Merge branch 'master' of github.com:assimp/assimp

Conflicts:
	code/ColladaLoader.cpp
pull/502/head
Alexander Gessler 2015-03-15 00:18:39 +01:00
commit c59878e427
96 changed files with 3067 additions and 985 deletions

View File

@ -183,6 +183,52 @@ ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "")
MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER ) MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
SET ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER OFF CACHE BOOL
"Build the C4D importer, which relies on the non-free Melange SDK."
)
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
IF ( MSVC )
SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/_melange/includes")
# pick the correct prebuilt library
IF(MSVC11)
SET(C4D_LIB_POSTFIX "_2012md")
ELSEIF(MSVC10)
SET(C4D_LIB_POSTFIX "_2010md")
ELSEIF(MSVC90)
SET(C4D_LIB_POSTFIX "_2008md")
ELSE()
MESSAGE( FATAL_ERROR
"C4D is currently only supported with MSVC 9, 10, 11"
)
ENDIF()
IF(CMAKE_CL_64)
SET(C4D_LIB_ARCH_POSTFIX "_x64")
ELSE()
SET(C4D_LIB_ARCH_POSTFIX "")
ENDIF()
SET(C4D_LIB_BASE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/_melange/lib/WIN")
SET(C4D_DEBUG_LIBRARY "${C4D_LIB_BASE_PATH}/debug/_melange_lib${C4D_LIB_ARCH_POSTFIX}${C4D_LIB_POSTFIX}.lib")
SET(C4D_RELEASE_LIBRARY "${C4D_LIB_BASE_PATH}/release/_melange_lib${C4D_LIB_ARCH_POSTFIX}${C4D_LIB_POSTFIX}.lib")
# winsock and winmm are necessary dependencies of melange (this is undocumented, but true.)
SET(C4D_EXTRA_LIBRARIES WSock32.lib Winmm.lib)
ELSE ()
MESSAGE( FATAL_ERROR
"C4D is currently only available on Windows with melange SDK installed in contrib/Melange"
)
ENDIF ( MSVC )
else (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
ADD_SUBDIRECTORY( code/ ) ADD_SUBDIRECTORY( code/ )
option ( ASSIMP_BUILD_ASSIMP_TOOLS option ( ASSIMP_BUILD_ASSIMP_TOOLS
"If the supplementary tools for Assimp are built in addition to the library." "If the supplementary tools for Assimp are built in addition to the library."

View File

@ -396,7 +396,7 @@ void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut)
} }
for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q)
{ {
register unsigned int index = aiSplit[p][q]; unsigned int index = aiSplit[p][q];
aiFace& face = meshOut->mFaces[q]; aiFace& face = meshOut->mFaces[q];
face.mIndices = new unsigned int[3]; face.mIndices = new unsigned int[3];

View File

@ -294,7 +294,7 @@ void Discreet3DSExporter::WriteMaterials()
WriteColor(color); WriteColor(color);
} }
aiShadingMode shading_mode; aiShadingMode shading_mode = aiShadingMode_Flat;
if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) {
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING); ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);

View File

@ -489,7 +489,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
for (it = object.surfaces.begin(); it != end; ++it) for (it = object.surfaces.begin(); it != end; ++it)
{ {
register unsigned int idx = (*it).mat; unsigned int idx = (*it).mat;
if (idx >= needMat.size()) if (idx >= needMat.size())
{ {
DefaultLogger::get()->error("AC3D: material index is out of range"); DefaultLogger::get()->error("AC3D: material index is out of range");
@ -617,7 +617,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
it2 = (*it).entries.begin(); it2 = (*it).entries.begin();
// either a closed or an unclosed line // either a closed or an unclosed line
register unsigned int tmp = (unsigned int)(*it).entries.size(); unsigned int tmp = (unsigned int)(*it).entries.size();
if (0x2 == type)--tmp; if (0x2 == type)--tmp;
for (unsigned int m = 0; m < tmp;++m) for (unsigned int m = 0; m < tmp;++m)
{ {

View File

@ -168,7 +168,7 @@ void Parser::LogInfo(const char* szWarn)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::LogError(const char* szWarn) AI_WONT_RETURN void Parser::LogError(const char* szWarn)
{ {
ai_assert(NULL != szWarn); ai_assert(NULL != szWarn);

View File

@ -602,7 +602,7 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Output an error to the logger //! Output an error to the logger
//! \param szWarn Error message //! \param szWarn Error message
void LogError(const char* szWarn); AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Parse a string, enclosed in double quotation marks //! Parse a string, enclosed in double quotation marks

View File

@ -273,13 +273,13 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
if (buffer) delete[] buffer; if (buffer) delete[] buffer;
} }
void * GetBufferPointer() { return buffer; }; void * GetBufferPointer() { return buffer; }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; }; virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; }
virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; }; virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; }
virtual size_t Tell() const { return cursor; }; virtual size_t Tell() const { return cursor; }
virtual void Flush() { }; virtual void Flush() { }
virtual size_t FileSize() const virtual size_t FileSize() const
{ {

View File

@ -127,12 +127,12 @@ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void B3DImporter::Oops(){ AI_WONT_RETURN void B3DImporter::Oops(){
throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" ); throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void B3DImporter::Fail( string str ){ AI_WONT_RETURN void B3DImporter::Fail( string str ){
#ifdef DEBUG_B3D #ifdef DEBUG_B3D
cout<<"Error in B3D file data: "<<str<<endl; cout<<"Error in B3D file data: "<<str<<endl;
#endif #endif

View File

@ -87,8 +87,8 @@ private:
float weights[4]; float weights[4];
}; };
void Oops(); AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
void Fail( std::string str ); AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX;
void ReadTEXS(); void ReadTEXS();
void ReadBRUS(); void ReadBRUS();

View File

@ -413,7 +413,7 @@ float BVHLoader::GetNextTokenAsFloat()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception // Aborts the file reading with an exception
void BVHLoader::ThrowException( const std::string& pError) AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError)
{ {
throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError)); throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
} }

View File

@ -134,7 +134,7 @@ protected:
float GetNextTokenAsFloat(); float GetNextTokenAsFloat();
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
void ThrowException( const std::string& pError); AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
/** Constructs an animation for the motion data and stores it in the given scene */ /** Constructs an animation for the motion data and stores it in the given scene */
void CreateAnimation( aiScene* pScene); void CreateAnimation( aiScene* pScene);

View File

@ -0,0 +1,641 @@
/*
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 C4DImporter.cpp
* @brief Implementation of the Cinema4D importer class.
*/
#include "AssimpPCH.h"
// no #ifdefing here, Cinema4D support is carried out in a branch of assimp
// where it is turned on in the CMake settings.
#ifndef _MSC_VER
# error C4D support is currently MSVC only
#endif
#include "C4DImporter.h"
#include "TinyFormatter.h"
#if defined(_M_X64) || defined(__amd64__)
# define __C4D_64BIT
#endif
#define __PC
#include "c4d_file.h"
#include "default_alien_overloads.h"
using namespace _melange_;
// overload this function and fill in your own unique data
void GetWriterInfo(LONG &id, String &appname)
{
id = 2424226;
appname = "Open Asset Import Library";
}
using namespace Assimp;
using namespace Assimp::Formatter;
namespace Assimp {
template<> const std::string LogFunctions<C4DImporter>::log_prefix = "C4D: ";
}
static const aiImporterDesc desc = {
"Cinema4D Importer",
"",
"",
"",
aiImporterFlags_SupportBinaryFlavour,
0,
0,
0,
0,
"c4d"
};
// ------------------------------------------------------------------------------------------------
C4DImporter::C4DImporter()
{}
// ------------------------------------------------------------------------------------------------
C4DImporter::~C4DImporter()
{}
// ------------------------------------------------------------------------------------------------
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
{
const std::string& extension = GetExtension(pFile);
if (extension == "c4d") {
return true;
}
else if ((!extension.length() || checkSig) && pIOHandler) {
// TODO
}
return false;
}
// ------------------------------------------------------------------------------------------------
const aiImporterDesc* C4DImporter::GetInfo () const
{
return &desc;
}
// ------------------------------------------------------------------------------------------------
void C4DImporter::SetupProperties(const Importer* /*pImp*/)
{
// nothing to be done for the moment
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void C4DImporter::InternReadFile( const std::string& pFile,
aiScene* pScene, IOSystem* pIOHandler)
{
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
if( file.get() == NULL) {
ThrowException("failed to open file " + pFile);
}
const size_t file_size = file->FileSize();
std::vector<uint8_t> mBuffer(file_size);
file->Read(&mBuffer[0], 1, file_size);
Filename f;
f.SetMemoryReadMode(&mBuffer[0], file_size);
// open document first
BaseDocument* doc = LoadDocument(f, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS);
if(doc == NULL) {
ThrowException("failed to read document " + pFile);
}
pScene->mRootNode = new aiNode("<C4DRoot>");
// first convert all materials
ReadMaterials(doc->GetFirstMaterial());
// process C4D scenegraph recursively
try {
RecurseHierarchy(doc->GetFirstObject(), pScene->mRootNode);
}
catch(...) {
BOOST_FOREACH(aiMesh* mesh, meshes) {
delete mesh;
}
BaseDocument::Free(doc);
throw;
}
BaseDocument::Free(doc);
// copy meshes over
pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]();
std::copy(meshes.begin(), meshes.end(), pScene->mMeshes);
// copy materials over, adding a default material if necessary
unsigned int mat_count = static_cast<unsigned int>(materials.size());
BOOST_FOREACH(aiMesh* mesh, meshes) {
ai_assert(mesh->mMaterialIndex <= mat_count);
if(mesh->mMaterialIndex >= mat_count) {
++mat_count;
ScopeGuard<aiMaterial> def_material(new aiMaterial());
const aiString name(AI_DEFAULT_MATERIAL_NAME);
def_material->AddProperty(&name, AI_MATKEY_NAME);
materials.push_back(def_material.dismiss());
break;
}
}
pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]();
std::copy(materials.begin(), materials.end(), pScene->mMaterials);
}
// ------------------------------------------------------------------------------------------------
bool C4DImporter::ReadShader(aiMaterial* out, _melange_::BaseShader* shader)
{
// based on Melange sample code (C4DImportExport.cpp)
while(shader) {
if(shader->GetType() == Xlayer) {
BaseContainer* container = shader->GetDataInstance();
GeData blend = container->GetData(SLA_LAYER_BLEND);
iBlendDataType* blend_list = reinterpret_cast<iBlendDataType*>(blend.GetCustomDataType(CUSTOMDATA_BLEND_LIST));
if (!blend_list)
{
LogWarn("ignoring XLayer shader: no blend list given");
continue;
}
LayerShaderLayer *lsl = dynamic_cast<LayerShaderLayer*>(blend_list->m_BlendLayers.GetObject(0));
// Ignore the actual layer blending - models for real-time rendering should not
// use them in a non-trivial way. Just try to find textures that we can apply
// to the model.
while (lsl)
{
if (lsl->GetType() == TypeFolder)
{
BlendFolder* const folder = dynamic_cast<BlendFolder*>(lsl);
LayerShaderLayer *subLsl = dynamic_cast<LayerShaderLayer*>(folder->m_Children.GetObject(0));
while (subLsl)
{
if (subLsl->GetType() == TypeShader) {
BlendShader* const shader = dynamic_cast<BlendShader*>(subLsl);
if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
return true;
}
}
subLsl = subLsl->GetNext();
}
}
else if (lsl->GetType() == TypeShader) {
BlendShader* const shader = dynamic_cast<BlendShader*>(lsl);
if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
return true;
}
}
lsl = lsl->GetNext();
}
}
else if ( shader->GetType() == Xbitmap )
{
aiString path;
shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1);
path.length = ::strlen(path.data);
out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
return true;
}
else {
LogWarn("ignoring shader type: " + std::string(GetObjectTypeName(shader->GetType())));
}
shader = shader->GetNext();
}
return false;
}
// ------------------------------------------------------------------------------------------------
void C4DImporter::ReadMaterials(_melange_::BaseMaterial* mat)
{
// based on Melange sample code
while (mat)
{
const String& name = mat->GetName();
if (mat->GetType() == Mmaterial)
{
aiMaterial* out = new aiMaterial();
material_mapping[mat] = static_cast<unsigned int>(materials.size());
materials.push_back(out);
aiString ai_name;
name.GetCString(ai_name.data, MAXLEN-1);
ai_name.length = ::strlen(ai_name.data);
out->AddProperty(&ai_name, AI_MATKEY_NAME);
Material& m = dynamic_cast<Material&>(*mat);
if (m.GetChannelState(CHANNEL_COLOR))
{
GeData data;
mat->GetParameter(MATERIAL_COLOR_COLOR, data);
Vector color = data.GetVector();
mat->GetParameter(MATERIAL_COLOR_BRIGHTNESS, data);
const Real brightness = data.GetReal();
color *= brightness;
aiVector3D v;
v.x = color.x;
v.y = color.y;
v.z = color.z;
out->AddProperty(&v, 1, AI_MATKEY_COLOR_DIFFUSE);
}
BaseShader* const shader = m.GetShader(MATERIAL_COLOR_SHADER);
if(shader) {
ReadShader(out, shader);
}
}
else
{
LogWarn("ignoring plugin material: " + std::string(GetObjectTypeName(mat->GetType())));
}
mat = mat->GetNext();
}
}
// ------------------------------------------------------------------------------------------------
void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent)
{
ai_assert(parent != NULL);
std::vector<aiNode*> nodes;
// based on Melange sample code
while (object)
{
const String& name = object->GetName();
const LONG type = object->GetType();
const Matrix& ml = object->GetMl();
aiString string;
name.GetCString(string.data, MAXLEN-1);
string.length = ::strlen(string.data);
aiNode* const nd = new aiNode();
nd->mParent = parent;
nd->mName = string;
nd->mTransformation.a1 = ml.v1.x;
nd->mTransformation.b1 = ml.v1.y;
nd->mTransformation.c1 = ml.v1.z;
nd->mTransformation.a2 = ml.v2.x;
nd->mTransformation.b2 = ml.v2.y;
nd->mTransformation.c2 = ml.v2.z;
nd->mTransformation.a3 = ml.v3.x;
nd->mTransformation.b3 = ml.v3.y;
nd->mTransformation.c3 = ml.v3.z;
nd->mTransformation.a4 = ml.off.x;
nd->mTransformation.b4 = ml.off.y;
nd->mTransformation.c4 = ml.off.z;
nodes.push_back(nd);
GeData data;
if (type == Ocamera)
{
object->GetParameter(CAMERAOBJECT_FOV, data);
// TODO: read camera
}
else if (type == Olight)
{
// TODO: read light
}
else if (type == Opolygon)
{
aiMesh* const mesh = ReadMesh(object);
if(mesh != NULL) {
nd->mNumMeshes = 1;
nd->mMeshes = new unsigned int[1];
nd->mMeshes[0] = static_cast<unsigned int>(meshes.size());
meshes.push_back(mesh);
}
}
else {
LogWarn("ignoring object: " + std::string(GetObjectTypeName(type)));
}
RecurseHierarchy(object->GetDown(), nd);
object = object->GetNext();
}
// copy nodes over to parent
parent->mNumChildren = static_cast<unsigned int>(nodes.size());
parent->mChildren = new aiNode*[parent->mNumChildren]();
std::copy(nodes.begin(), nodes.end(), parent->mChildren);
}
// ------------------------------------------------------------------------------------------------
aiMesh* C4DImporter::ReadMesh(BaseObject* object)
{
assert(object != NULL && object->GetType() == Opolygon);
// based on Melange sample code
PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
ai_assert(polyObject != NULL);
const LONG pointCount = polyObject->GetPointCount();
const LONG polyCount = polyObject->GetPolygonCount();
if(!polyObject || !pointCount) {
LogWarn("ignoring mesh with zero vertices or faces");
return NULL;
}
const Vector* points = polyObject->GetPointR();
ai_assert(points != NULL);
const CPolygon* polys = polyObject->GetPolygonR();
ai_assert(polys != NULL);
ScopeGuard<aiMesh> mesh(new aiMesh());
mesh->mNumFaces = static_cast<unsigned int>(polyCount);
aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
mesh->mMaterialIndex = 0;
unsigned int vcount = 0;
// first count vertices
for (LONG i = 0; i < polyCount; i++)
{
vcount += 3;
// TODO: do we also need to handle lines or points with similar checks?
if (polys[i].c != polys[i].d)
{
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
++vcount;
}
}
ai_assert(vcount > 0);
mesh->mNumVertices = vcount;
aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
aiVector3D* normals, *uvs, *tangents, *bitangents;
unsigned int n = 0;
// check if there are normals, tangents or UVW coordinates
BaseTag* tag = object->GetTag(Tnormal);
NormalTag* normals_src = NULL;
if(tag) {
normals_src = dynamic_cast<NormalTag*>(tag);
normals = mesh->mNormals = new aiVector3D[mesh->mNumVertices]();
}
tag = object->GetTag(Ttangent);
TangentTag* tangents_src = NULL;
if(tag) {
tangents_src = dynamic_cast<TangentTag*>(tag);
tangents = mesh->mTangents = new aiVector3D[mesh->mNumVertices]();
bitangents = mesh->mBitangents = new aiVector3D[mesh->mNumVertices]();
}
tag = object->GetTag(Tuvw);
UVWTag* uvs_src = NULL;
if(tag) {
uvs_src = dynamic_cast<UVWTag*>(tag);
uvs = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]();
}
// copy vertices and extra channels over and populate faces
for (LONG i = 0; i < polyCount; ++i, ++face)
{
ai_assert(polys[i].a < pointCount && polys[i].a >= 0);
const Vector& pointA = points[polys[i].a];
verts->x = pointA.x;
verts->y = pointA.y;
verts->z = pointA.z;
++verts;
ai_assert(polys[i].b < pointCount && polys[i].b >= 0);
const Vector& pointB = points[polys[i].b];
verts->x = pointB.x;
verts->y = pointB.y;
verts->z = pointB.z;
++verts;
ai_assert(polys[i].c < pointCount && polys[i].c >= 0);
const Vector& pointC = points[polys[i].c];
verts->x = pointC.x;
verts->y = pointC.y;
verts->z = pointC.z;
++verts;
// TODO: do we also need to handle lines or points with similar checks?
if (polys[i].c != polys[i].d)
{
ai_assert(polys[i].d < pointCount && polys[i].d >= 0);
face->mNumIndices = 4;
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
const Vector& pointD = points[polys[i].d];
verts->x = pointD.x;
verts->y = pointD.y;
verts->z = pointD.z;
++verts;
}
else {
face->mNumIndices = 3;
}
face->mIndices = new unsigned int[face->mNumIndices];
for(unsigned int j = 0; j < face->mNumIndices; ++j) {
face->mIndices[j] = n++;
}
// copy normals
if (normals_src) {
if(i >= normals_src->GetNormalCount()) {
LogError("unexpected number of normals, ignoring");
}
else {
const NormalStruct& nor = normals_src->GetNormals(i);
normals->x = nor.a.x;
normals->y = nor.a.y;
normals->z = nor.a.z;
++normals;
normals->x = nor.b.x;
normals->y = nor.b.y;
normals->z = nor.b.z;
++normals;
normals->x = nor.c.x;
normals->y = nor.c.y;
normals->z = nor.c.z;
++normals;
if(face->mNumIndices == 4) {
normals->x = nor.d.x;
normals->y = nor.d.y;
normals->z = nor.d.z;
++normals;
}
}
}
// copy tangents and bitangents
if (tangents_src) {
for(unsigned int k = 0; k < face->mNumIndices; ++k) {
LONG l;
switch(k) {
case 0:
l = polys[i].a;
break;
case 1:
l = polys[i].b;
break;
case 2:
l = polys[i].c;
break;
case 3:
l = polys[i].d;
break;
default:
ai_assert(false);
}
if(l >= tangents_src->GetDataCount()) {
LogError("unexpected number of tangents, ignoring");
break;
}
Tangent tan = tangents_src->GetDataR()[l];
tangents->x = tan.vl.x;
tangents->y = tan.vl.y;
tangents->z = tan.vl.z;
++tangents;
bitangents->x = tan.vr.x;
bitangents->y = tan.vr.y;
bitangents->z = tan.vr.z;
++bitangents;
}
}
// copy UVs
if (uvs_src) {
if(i >= uvs_src->GetDataCount()) {
LogError("unexpected number of UV coordinates, ignoring");
}
else {
UVWStruct uvw;
uvs_src->Get(uvs_src->GetDataAddressR(),i,uvw);
uvs->x = uvw.a.x;
uvs->y = 1.0f-uvw.a.y;
uvs->z = uvw.a.z;
++uvs;
uvs->x = uvw.b.x;
uvs->y = 1.0f-uvw.b.y;
uvs->z = uvw.b.z;
++uvs;
uvs->x = uvw.c.x;
uvs->y = 1.0f-uvw.c.y;
uvs->z = uvw.c.z;
++uvs;
if(face->mNumIndices == 4) {
uvs->x = uvw.d.x;
uvs->y = 1.0f-uvw.d.y;
uvs->z = uvw.d.z;
++uvs;
}
}
}
}
mesh->mMaterialIndex = ResolveMaterial(polyObject);
return mesh.dismiss();
}
// ------------------------------------------------------------------------------------------------
unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj)
{
ai_assert(obj != NULL);
const unsigned int mat_count = static_cast<unsigned int>(materials.size());
BaseTag* tag = obj->GetTag(Ttexture);
if(tag == NULL) {
return mat_count;
}
TextureTag& ttag = dynamic_cast<TextureTag&>(*tag);
BaseMaterial* const mat = ttag.GetMaterial();
assert(mat != NULL);
const MaterialMap::const_iterator it = material_mapping.find(mat);
if(it == material_mapping.end()) {
return mat_count;
}
ai_assert((*it).second < mat_count);
return (*it).second;
}

120
code/C4DImporter.h 100644
View File

@ -0,0 +1,120 @@
/*
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 C4DImporter.h
* @brief Declaration of the Cinema4D (*.c4d) importer class.
*/
#ifndef INCLUDED_AI_CINEMA_4D_LOADER_H
#define INCLUDED_AI_CINEMA_4D_LOADER_H
#include "BaseImporter.h"
#include "LogAux.h"
#include <set>
struct aiImporterDesc;
namespace _melange_ {
class BaseObject; // c4d_file.h
class PolygonObject;
class BaseMaterial;
class BaseShader;
}
namespace Assimp {
// TinyFormatter.h
namespace Formatter {
template <typename T,typename TR, typename A> class basic_formatter;
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
}
// -------------------------------------------------------------------------------------------
/** Importer class to load Cinema4D files using the Melange library to be obtained from
* www.plugincafe.com
*
* Note that Melange is not free software. */
// -------------------------------------------------------------------------------------------
class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter>
{
public:
C4DImporter();
~C4DImporter();
public:
// --------------------
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const;
protected:
// --------------------
const aiImporterDesc* GetInfo () const;
// --------------------
void SetupProperties(const Importer* pImp);
// --------------------
void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler);
private:
void ReadMaterials(_melange_::BaseMaterial* mat);
void RecurseHierarchy(_melange_::BaseObject* object, aiNode* parent);
aiMesh* ReadMesh(_melange_::BaseObject* object);
unsigned int ResolveMaterial(_melange_::PolygonObject* obj);
bool ReadShader(aiMaterial* out, _melange_::BaseShader* shader);
std::vector<aiMesh*> meshes;
std::vector<aiMaterial*> materials;
typedef std::map<_melange_::BaseMaterial*, unsigned int> MaterialMap;
MaterialMap material_mapping;
}; // !class C4DImporter
} // end of namespace Assimp
#endif // INCLUDED_AI_CINEMA_4D_LOADER_H

View File

@ -148,6 +148,14 @@ SET( Common_SRCS
) )
SOURCE_GROUP(Common FILES ${Common_SRCS}) SOURCE_GROUP(Common FILES ${Common_SRCS})
IF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
SET( C4D_SRCS
C4DImporter.cpp
C4DImporter.h
)
SOURCE_GROUP( C4D FILES ${C4D_SRCS})
ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
SET( 3DS_SRCS SET( 3DS_SRCS
3DSConverter.cpp 3DSConverter.cpp
3DSHelper.h 3DSHelper.h
@ -718,6 +726,11 @@ SET( assimp_src
AssimpPCH.cpp AssimpPCH.cpp
) )
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
SET( assimp_src ${assimp_src} ${C4D_SRCS})
INCLUDE_DIRECTORIES(${C4D_INCLUDES})
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
#ADD_MSVC_PRECOMPILED_HEADER("AssimpPCH.h" "AssimpPCH.cpp" assimp_src) #ADD_MSVC_PRECOMPILED_HEADER("AssimpPCH.h" "AssimpPCH.cpp" assimp_src)
ADD_LIBRARY( assimp ${assimp_src} ) ADD_LIBRARY( assimp ${assimp_src} )
@ -730,6 +743,12 @@ if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
target_link_libraries(assimp android_jniiosystem) target_link_libraries(assimp android_jniiosystem)
endif(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) endif(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
TARGET_LINK_LIBRARIES(assimp optimized ${C4D_RELEASE_LIBRARY})
TARGET_LINK_LIBRARIES(assimp debug ${C4D_DEBUG_LIBRARY})
TARGET_LINK_LIBRARIES(assimp ${C4D_EXTRA_LIBRARIES})
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
if( MSVC ) if( MSVC )
# in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix
if( MSVC70 OR MSVC71 ) if( MSVC70 OR MSVC71 )

View File

@ -127,7 +127,7 @@ void COBImporter::SetupProperties(const Importer* /*pImp*/)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
/*static*/ void COBImporter::ThrowException(const std::string& msg) /*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string& msg)
{ {
throw DeadlyImportError("COB: "+msg); throw DeadlyImportError("COB: "+msg);
} }

View File

@ -95,7 +95,7 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Prepend 'COB: ' and throw msg.*/ /** Prepend 'COB: ' and throw msg.*/
static void ThrowException(const std::string& msg); AI_WONT_RETURN static void ThrowException(const std::string& msg) AI_WONT_RETURN_SUFFIX;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** @brief Read from an ascii scene/object file /** @brief Read from an ascii scene/object file

View File

@ -167,7 +167,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// their tangent vectors are set to qnan. // their tangent vectors are set to qnan.
for (unsigned int i = 0; i < face.mNumIndices;++i) for (unsigned int i = 0; i < face.mNumIndices;++i)
{ {
register unsigned int idx = face.mIndices[i]; unsigned int idx = face.mIndices[i];
vertexDone [idx] = true; vertexDone [idx] = true;
meshTang [idx] = aiVector3D(qnan); meshTang [idx] = aiVector3D(qnan);
meshBitang [idx] = aiVector3D(qnan); meshBitang [idx] = aiVector3D(qnan);

View File

@ -452,7 +452,7 @@ void ColladaExporter::WriteMaterials()
} }
} }
aiShadingMode shading; aiShadingMode shading = aiShadingMode_Flat;
materials[a].shading_model = "phong"; materials[a].shading_model = "phong";
if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) { if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) {
if(shading == aiShadingMode_Phong) { if(shading == aiShadingMode_Phong) {

View File

@ -395,6 +395,7 @@ struct Controller
/** A collada material. Pretty much the only member is a reference to an effect. */ /** A collada material. Pretty much the only member is a reference to an effect. */
struct Material struct Material
{ {
std::string mName;
std::string mEffect; std::string mEffect;
}; };

View File

@ -73,7 +73,7 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
ColladaLoader::ColladaLoader() ColladaLoader::ColladaLoader()
: noSkeletonMesh(), ignoreUpDirection(false), mNodeNameCounter() : noSkeletonMesh(), ignoreUpDirection(false), mNodeNameCounter()
{} {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -87,16 +87,16 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
{ {
// check file extension // check file extension
std::string extension = GetExtension(pFile); std::string extension = GetExtension(pFile);
if( extension == "dae") if( extension == "dae")
return true; return true;
// XML - too generic, we need to open the file and search for typical keywords // XML - too generic, we need to open the file and search for typical keywords
if( extension == "xml" || !extension.length() || checkSig) { if( extension == "xml" || !extension.length() || checkSig) {
/* If CanRead() is called in order to check whether we /* If CanRead() is called in order to check whether we
* support a specific file extension in general pIOHandler * support a specific file extension in general pIOHandler
* might be NULL and it's our duty to return true here. * might be NULL and it's our duty to return true here.
*/ */
if (!pIOHandler)return true; if (!pIOHandler)return true;
const char* tokens[] = {"collada"}; const char* tokens[] = {"collada"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
@ -157,26 +157,26 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// ... then fill the materials with the now adjusted settings // ... then fill the materials with the now adjusted settings
FillMaterials(parser, pScene); FillMaterials(parser, pScene);
// Apply unitsize scale calculation // Apply unitsize scale calculation
pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0, pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0,
0, parser.mUnitSize, 0, 0, 0, parser.mUnitSize, 0, 0,
0, 0, parser.mUnitSize, 0, 0, 0, parser.mUnitSize, 0,
0, 0, 0, 1); 0, 0, 0, 1);
if( !ignoreUpDirection ) { if( !ignoreUpDirection ) {
// Convert to Y_UP, if different orientation // Convert to Y_UP, if different orientation
if( parser.mUpDirection == ColladaParser::UP_X) if( parser.mUpDirection == ColladaParser::UP_X)
pScene->mRootNode->mTransformation *= aiMatrix4x4( pScene->mRootNode->mTransformation *= aiMatrix4x4(
0, -1, 0, 0, 0, -1, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1); 0, 0, 0, 1);
else if( parser.mUpDirection == ColladaParser::UP_Z) else if( parser.mUpDirection == ColladaParser::UP_Z)
pScene->mRootNode->mTransformation *= aiMatrix4x4( pScene->mRootNode->mTransformation *= aiMatrix4x4(
1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, -1, 0, 0, 0, -1, 0, 0,
0, 0, 0, 1); 0, 0, 0, 1);
} }
// store all meshes // store all meshes
StoreSceneMeshes( pScene); StoreSceneMeshes( pScene);
@ -195,7 +195,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
// If no meshes have been loaded, it's probably just an animated skeleton. // If no meshes have been loaded, it's probably just an animated skeleton.
if (!pScene->mNumMeshes) { if (!pScene->mNumMeshes) {
if (!noSkeletonMesh) { if (!noSkeletonMesh) {
SkeletonMeshBuilder hero(pScene); SkeletonMeshBuilder hero(pScene);
} }
@ -251,14 +251,14 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Resolve node instances // Resolve node instances
void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode, void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
std::vector<const Collada::Node*>& resolved) std::vector<const Collada::Node*>& resolved)
{ {
// reserve enough storage // reserve enough storage
resolved.reserve(pNode->mNodeInstances.size()); resolved.reserve(pNode->mNodeInstances.size());
// ... and iterate through all nodes to be instanced as children of pNode // ... and iterate through all nodes to be instanced as children of pNode
for (std::vector<Collada::NodeInstance>::const_iterator it = pNode->mNodeInstances.begin(), for (std::vector<Collada::NodeInstance>::const_iterator it = pNode->mNodeInstances.begin(),
end = pNode->mNodeInstances.end(); it != end; ++it) end = pNode->mNodeInstances.end(); it != end; ++it)
{ {
// find the corresponding node in the library // find the corresponding node in the library
const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find((*it).mNode); const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find((*it).mNode);
@ -272,7 +272,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
} }
if (!nd) if (!nd)
DefaultLogger::get()->error("Collada: Unable to resolve reference to instanced node " + (*it).mNode); DefaultLogger::get()->error("Collada: Unable to resolve reference to instanced node " + (*it).mNode);
else { else {
// attach this node to the list of children // attach this node to the list of children
resolved.push_back(nd); resolved.push_back(nd);
@ -283,7 +283,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Resolve UV channels // Resolve UV channels
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler, void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
const Collada::SemanticMappingTable& table) const Collada::SemanticMappingTable& table)
{ {
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel); std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it != table.mMap.end()) { if (it != table.mMap.end()) {
@ -308,7 +308,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
continue; continue;
} }
const Collada::Light* srcLight = &srcLightIt->second; const Collada::Light* srcLight = &srcLightIt->second;
// now fill our ai data structure // now fill our ai data structure
aiLight* out = new aiLight(); aiLight* out = new aiLight();
out->mName = pTarget->mName; out->mName = pTarget->mName;
@ -326,7 +326,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
// convert falloff angle and falloff exponent in our representation, if given // convert falloff angle and falloff exponent in our representation, if given
if (out->mType == aiLightSource_SPOT) { if (out->mType == aiLightSource_SPOT) {
out->mAngleInnerCone = AI_DEG_TO_RAD( srcLight->mFalloffAngle ); out->mAngleInnerCone = AI_DEG_TO_RAD( srcLight->mFalloffAngle );
// ... some extension magic. // ... some extension magic.
@ -387,7 +387,7 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
// ... but for the rest some values are optional // ... but for the rest some values are optional
// and we need to compute the others in any combination. // and we need to compute the others in any combination.
if (srcCamera->mAspect != 10e10f) if (srcCamera->mAspect != 10e10f)
out->mAspect = srcCamera->mAspect; out->mAspect = srcCamera->mAspect;
if (srcCamera->mHorFov != 10e10f) { if (srcCamera->mHorFov != 10e10f) {
@ -395,12 +395,12 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
if (srcCamera->mVerFov != 10e10f && srcCamera->mAspect == 10e10f) { if (srcCamera->mVerFov != 10e10f && srcCamera->mAspect == 10e10f) {
out->mAspect = tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) / out->mAspect = tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) /
tan(AI_DEG_TO_RAD(srcCamera->mVerFov)); tan(AI_DEG_TO_RAD(srcCamera->mVerFov));
} }
} }
else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(atan(srcCamera->mAspect * out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(atan(srcCamera->mAspect *
tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f))); tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f)));
} }
// Collada uses degrees, we use radians // Collada uses degrees, we use radians
@ -518,11 +518,11 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
// assign the material index // assign the material index
dstMesh->mMaterialIndex = matIdx; dstMesh->mMaterialIndex = matIdx;
if(dstMesh->mName.length == 0) if(dstMesh->mName.length == 0)
{ {
dstMesh->mName = mid.mMeshOrController; dstMesh->mName = mid.mMeshOrController;
} }
} }
} }
} }
@ -538,11 +538,11 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh // Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace) const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace)
{ {
aiMesh* dstMesh = new aiMesh; aiMesh* dstMesh = new aiMesh;
dstMesh->mName = pSrcMesh->mName; dstMesh->mName = pSrcMesh->mName;
// count the vertices addressed by its faces // count the vertices addressed by its faces
const size_t numVertices = std::accumulate( pSrcMesh->mFaceSize.begin() + pStartFace, const size_t numVertices = std::accumulate( pSrcMesh->mFaceSize.begin() + pStartFace,
@ -589,7 +589,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
dstMesh->mTextureCoords[real] = new aiVector3D[numVertices]; dstMesh->mTextureCoords[real] = new aiVector3D[numVertices];
for( size_t b = 0; b < numVertices; ++b) for( size_t b = 0; b < numVertices; ++b)
dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex+b]; dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex+b];
dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a]; dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a];
++real; ++real;
} }
@ -624,8 +624,8 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
if( pSrcController) if( pSrcController)
{ {
// refuse if the vertex count does not match // refuse if the vertex count does not match
// if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices) // if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices)
// throw DeadlyImportError( "Joint Controller vertex count does not match mesh vertex count"); // throw DeadlyImportError( "Joint Controller vertex count does not match mesh vertex count");
// resolve references - joint names // resolve references - joint names
const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource); const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource);
@ -937,7 +937,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
// find the collada node corresponding to the aiNode // find the collada node corresponding to the aiNode
const Collada::Node* srcNode = FindNode( pParser.mRootNode, nodeName); const Collada::Node* srcNode = FindNode( pParser.mRootNode, nodeName);
// ai_assert( srcNode != NULL); // ai_assert( srcNode != NULL);
if( !srcNode) if( !srcNode)
continue; continue;
@ -990,7 +990,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
{ {
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1); entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
std::string subElement = srcChannel.mTarget.substr(bracketPos); std::string subElement = srcChannel.mTarget.substr(bracketPos);
if (subElement == "(0)(0)") if (subElement == "(0)(0)")
entry.mSubElement = 0; entry.mSubElement = 0;
else if (subElement == "(1)(0)") else if (subElement == "(1)(0)")
@ -1058,154 +1058,134 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
if( e.mTimeAccessor->mCount != e.mValueAccessor->mCount) if( e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
throw DeadlyImportError( boost::str( boost::format( "Time count / value count mismatch in animation channel \"%s\".") % e.mChannel->mTarget)); throw DeadlyImportError( boost::str( boost::format( "Time count / value count mismatch in animation channel \"%s\".") % e.mChannel->mTarget));
if( e.mTimeAccessor->mCount > 0 ) if( e.mTimeAccessor->mCount > 0 )
{ {
// find bounding times // find bounding times
startTime = std::min( startTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, 0, 0)); startTime = std::min( startTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, 0, 0));
endTime = std::max( endTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount-1, 0)); endTime = std::max( endTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount-1, 0));
} }
} }
std::vector<aiMatrix4x4> resultTrafos; std::vector<aiMatrix4x4> resultTrafos;
if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 ) if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 )
{ {
// create a local transformation chain of the node's transforms // create a local transformation chain of the node's transforms
std::vector<Collada::Transform> transforms = srcNode->mTransforms; std::vector<Collada::Transform> transforms = srcNode->mTransforms;
// now for every unique point in time, find or interpolate the key values for that time // now for every unique point in time, find or interpolate the key values for that time
// and apply them to the transform chain. Then the node's present transformation can be calculated. // and apply them to the transform chain. Then the node's present transformation can be calculated.
float time = startTime; float time = startTime;
while( 1) while( 1)
{ {
for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
{ {
Collada::ChannelEntry& e = *it; Collada::ChannelEntry& e = *it;
// find the keyframe behind the current point in time // find the keyframe behind the current point in time
size_t pos = 0; size_t pos = 0;
float postTime = 0.f; float postTime = 0.f;
while( 1) while( 1)
{ {
if( pos >= e.mTimeAccessor->mCount) if( pos >= e.mTimeAccessor->mCount)
break; break;
postTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0); postTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0);
if( postTime >= time) if( postTime >= time)
break; break;
++pos; ++pos;
} }
pos = std::min( pos, e.mTimeAccessor->mCount-1); pos = std::min( pos, e.mTimeAccessor->mCount-1);
// read values from there // read values from there
float temp[16]; float temp[16];
for( size_t c = 0; c < e.mValueAccessor->mSize; ++c) for( size_t c = 0; c < e.mValueAccessor->mSize; ++c)
temp[c] = ReadFloat( *e.mValueAccessor, *e.mValueData, pos, c); temp[c] = ReadFloat( *e.mValueAccessor, *e.mValueData, pos, c);
// if not exactly at the key time, interpolate with previous value set // if not exactly at the key time, interpolate with previous value set
if( postTime > time && pos > 0) if( postTime > time && pos > 0)
{ {
float preTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos-1, 0); float preTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos-1, 0);
float factor = (time - postTime) / (preTime - postTime); float factor = (time - postTime) / (preTime - postTime);
for( size_t c = 0; c < e.mValueAccessor->mSize; ++c) for( size_t c = 0; c < e.mValueAccessor->mSize; ++c)
{ {
float v = ReadFloat( *e.mValueAccessor, *e.mValueData, pos-1, c); float v = ReadFloat( *e.mValueAccessor, *e.mValueData, pos-1, c);
temp[c] += (v - temp[c]) * factor; temp[c] += (v - temp[c]) * factor;
} }
} }
// Apply values to current transformation // Apply values to current transformation
std::copy( temp, temp + e.mValueAccessor->mSize, transforms[e.mTransformIndex].f + e.mSubElement); std::copy( temp, temp + e.mValueAccessor->mSize, transforms[e.mTransformIndex].f + e.mSubElement);
} }
// Calculate resulting transformation // Calculate resulting transformation
aiMatrix4x4 mat = pParser.CalculateResultTransform( transforms); aiMatrix4x4 mat = pParser.CalculateResultTransform( transforms);
// out of lazyness: we store the time in matrix.d4 // out of lazyness: we store the time in matrix.d4
mat.d4 = time; mat.d4 = time;
resultTrafos.push_back( mat); resultTrafos.push_back( mat);
// find next point in time to evaluate. That's the closest frame larger than the current in any channel // find next point in time to evaluate. That's the closest frame larger than the current in any channel
float nextTime = 1e20f; float nextTime = 1e20f;
for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
{ {
Collada::ChannelEntry& e = *it; Collada::ChannelEntry& e = *it;
// find the next time value larger than the current // find the next time value larger than the current
size_t pos = 0; size_t pos = 0;
while( pos < e.mTimeAccessor->mCount) while( pos < e.mTimeAccessor->mCount)
{ {
float t = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0); float t = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0);
if( t > time) if( t > time)
{ {
nextTime = std::min( nextTime, t); nextTime = std::min( nextTime, t);
break; break;
} }
++pos; ++pos;
} }
}
// https://github.com/assimp/assimp/issues/458 // no more keys on any channel after the current time -> we're done
// Sub-sample axis-angle channels if the delta between two consecutive if( nextTime > 1e19)
// key-frame angles is >= 180 degrees. break;
if (transforms[e.mTransformIndex].mType == Collada::TF_ROTATE && e.mSubElement == 3 && pos > 0 && pos < e.mTimeAccessor->mCount) {
float cur_key_angle = ReadFloat( *e.mValueAccessor, *e.mValueData, pos, 0);
float last_key_angle = ReadFloat( *e.mValueAccessor, *e.mValueData, pos - 1, 0);
float cur_key_time = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0);
float last_key_time = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos - 1, 0);
float last_eval_angle = last_key_angle + (cur_key_angle - last_key_angle) * (time - last_key_time) / (cur_key_time - last_key_time); // else construct next keyframe at this following time point
float delta = std::fabs(cur_key_angle-last_eval_angle); time = nextTime;
if (delta >= 180.0f) { }
int subSampleCount = static_cast<int>(std::floorf(delta / 90.0f)); }
if (cur_key_time != time) {
float nextSampleTime = time + (cur_key_time - time) / subSampleCount;
nextTime = std::min( nextTime, nextSampleTime);
}
}
}
}
// no more keys on any channel after the current time -> we're done
if( nextTime > 1e19)
break;
// else construct next keyframe at this following time point
time = nextTime;
}
}
// there should be some keyframes, but we aren't that fixated on valid input data // there should be some keyframes, but we aren't that fixated on valid input data
// ai_assert( resultTrafos.size() > 0); // ai_assert( resultTrafos.size() > 0);
// build an animation channel for the given node out of these trafo keys // build an animation channel for the given node out of these trafo keys
if( !resultTrafos.empty() ) if( !resultTrafos.empty() )
{ {
aiNodeAnim* dstAnim = new aiNodeAnim; aiNodeAnim* dstAnim = new aiNodeAnim;
dstAnim->mNodeName = nodeName; dstAnim->mNodeName = nodeName;
dstAnim->mNumPositionKeys = resultTrafos.size(); dstAnim->mNumPositionKeys = resultTrafos.size();
dstAnim->mNumRotationKeys= resultTrafos.size(); dstAnim->mNumRotationKeys= resultTrafos.size();
dstAnim->mNumScalingKeys = resultTrafos.size(); dstAnim->mNumScalingKeys = resultTrafos.size();
dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()]; dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()]; dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()]; dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
for( size_t a = 0; a < resultTrafos.size(); ++a) for( size_t a = 0; a < resultTrafos.size(); ++a)
{ {
aiMatrix4x4 mat = resultTrafos[a]; aiMatrix4x4 mat = resultTrafos[a];
double time = double( mat.d4); // remember? time is stored in mat.d4 double time = double( mat.d4); // remember? time is stored in mat.d4
mat.d4 = 1.0f; mat.d4 = 1.0f;
dstAnim->mPositionKeys[a].mTime = time; dstAnim->mPositionKeys[a].mTime = time;
dstAnim->mRotationKeys[a].mTime = time; dstAnim->mRotationKeys[a].mTime = time;
dstAnim->mScalingKeys[a].mTime = time; dstAnim->mScalingKeys[a].mTime = time;
mat.Decompose( dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue); mat.Decompose( dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
} }
anims.push_back( dstAnim); anims.push_back( dstAnim);
} else } else
{ {
DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter."); DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
} }
} }
if( !anims.empty()) if( !anims.empty())
@ -1230,9 +1210,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Add a texture to a material structure // Add a texture to a material structure
void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser, void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
const Collada::Effect& effect, const Collada::Effect& effect,
const Collada::Sampler& sampler, const Collada::Sampler& sampler,
aiTextureType type, unsigned int idx) aiTextureType type, unsigned int idx)
{ {
// first of all, basic file name // first of all, basic file name
const aiString name = FindFilenameForEffectTexture( pParser, effect, sampler.mName ); const aiString name = FindFilenameForEffectTexture( pParser, effect, sampler.mName );
@ -1359,8 +1339,8 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
// add textures, if given // add textures, if given
if( !effect.mTexAmbient.mName.empty()) if( !effect.mTexAmbient.mName.empty())
/* It is merely a lightmap */ /* It is merely a lightmap */
AddTexture( mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP); AddTexture( mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP);
if( !effect.mTexEmissive.mName.empty()) if( !effect.mTexEmissive.mName.empty())
AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE); AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE);
@ -1399,7 +1379,7 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/)
// create material // create material
aiMaterial* mat = new aiMaterial; aiMaterial* mat = new aiMaterial;
aiString name( matIt->first); aiString name( material.mName.empty() ? matIt->first : material.mName );
mat->AddProperty(&name,AI_MATKEY_NAME); mat->AddProperty(&name,AI_MATKEY_NAME);
// store the material // store the material
@ -1431,7 +1411,7 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Resolves the texture name for the given effect texture entry // Resolves the texture name for the given effect texture entry
aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser, aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser,
const Collada::Effect& pEffect, const std::string& pName) const Collada::Effect& pEffect, const std::string& pName)
{ {
// recurse through the param references until we end up at an image // recurse through the param references until we end up at an image
std::string name = pName; std::string name = pName;
@ -1508,35 +1488,35 @@ void ColladaLoader::ConvertPath (aiString& ss)
ss.data[ss.length] = '\0'; ss.data[ss.length] = '\0';
} }
// Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes... // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
// I need to filter it without destroying linux paths starting with "/somewhere" // I need to filter it without destroying linux paths starting with "/somewhere"
if( ss.data[0] == '/' && isalpha( ss.data[1]) && ss.data[2] == ':' ) if( ss.data[0] == '/' && isalpha( ss.data[1]) && ss.data[2] == ':' )
{ {
ss.length--; ss.length--;
memmove( ss.data, ss.data+1, ss.length); memmove( ss.data, ss.data+1, ss.length);
ss.data[ss.length] = 0; ss.data[ss.length] = 0;
} }
// find and convert all %xy special chars // find and convert all %xy special chars
char* out = ss.data; char* out = ss.data;
for( const char* it = ss.data; it != ss.data + ss.length; /**/ ) for( const char* it = ss.data; it != ss.data + ss.length; /**/ )
{ {
if( *it == '%' && (it + 3) < ss.data + ss.length ) if( *it == '%' && (it + 3) < ss.data + ss.length )
{ {
// separate the number to avoid dragging in chars from behind into the parsing // separate the number to avoid dragging in chars from behind into the parsing
char mychar[3] = { it[1], it[2], 0 }; char mychar[3] = { it[1], it[2], 0 };
size_t nbr = strtoul16( mychar); size_t nbr = strtoul16( mychar);
it += 3; it += 3;
*out++ = (char)(nbr & 0xFF); *out++ = (char)(nbr & 0xFF);
} else } else
{ {
*out++ = *it++; *out++ = *it++;
} }
} }
// adjust length and terminator of the shortened string // adjust length and terminator of the shortened string
*out = 0; *out = 0;
ss.length = (ptrdiff_t) (out - ss.data); ss.length = (ptrdiff_t) (out - ss.data);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1589,17 +1569,17 @@ const Collada::Node* ColladaLoader::FindNode( const Collada::Node* pNode, const
// Finds a node in the collada scene by the given SID // Finds a node in the collada scene by the given SID
const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const
{ {
if( pNode->mSID == pSID) if( pNode->mSID == pSID)
return pNode; return pNode;
for( size_t a = 0; a < pNode->mChildren.size(); ++a) for( size_t a = 0; a < pNode->mChildren.size(); ++a)
{ {
const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID); const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID);
if( node) if( node)
return node; return node;
} }
return NULL; return NULL;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1613,12 +1593,12 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
else if (!pNode->mID.empty()) else if (!pNode->mID.empty())
return pNode->mID; return pNode->mID;
else if (!pNode->mSID.empty()) else if (!pNode->mSID.empty())
return pNode->mSID; return pNode->mSID;
else else
{ {
// No need to worry. Unnamed nodes are no problem at all, except // No need to worry. Unnamed nodes are no problem at all, except
// if cameras or lights need to be assigned to them. // if cameras or lights need to be assigned to them.
return boost::str( boost::format( "$ColladaAutoName$_%d") % mNodeNameCounter++); return boost::str( boost::format( "$ColladaAutoName$_%d") % mNodeNameCounter++);
} }
} }

View File

@ -60,7 +60,7 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
{ {
mRootNode = NULL; mRootNode = NULL;
mUnitSize = 1.0f; mUnitSize = 1.0f;
mUpDirection = UP_Z; mUpDirection = UP_Y;
// We assume the newest file format by default // We assume the newest file format by default
mFormat = FV_1_5_n; mFormat = FV_1_5_n;
@ -225,10 +225,10 @@ void ColladaParser::ReadAssetInfo()
const char* content = GetTextContent(); const char* content = GetTextContent();
if( strncmp( content, "X_UP", 4) == 0) if( strncmp( content, "X_UP", 4) == 0)
mUpDirection = UP_X; mUpDirection = UP_X;
else if( strncmp( content, "Y_UP", 4) == 0) else if( strncmp( content, "Z_UP", 4) == 0)
mUpDirection = UP_Y;
else
mUpDirection = UP_Z; mUpDirection = UP_Z;
else
mUpDirection = UP_Y;
// check element end // check element end
TestClosing( "up_axis"); TestClosing( "up_axis");
@ -817,6 +817,7 @@ void ColladaParser::ReadMaterialLibrary()
if( mReader->isEmptyElement()) if( mReader->isEmptyElement())
return; return;
std::map<std::string, int> names;
while( mReader->read()) while( mReader->read())
{ {
if( mReader->getNodeType() == irr::io::EXN_ELEMENT) if( mReader->getNodeType() == irr::io::EXN_ELEMENT)
@ -827,8 +828,32 @@ void ColladaParser::ReadMaterialLibrary()
int attrID = GetAttribute( "id"); int attrID = GetAttribute( "id");
std::string id = mReader->getAttributeValue( attrID); std::string id = mReader->getAttributeValue( attrID);
std::string name;
int attrName = TestAttribute("name");
if (attrName >= 0)
name = mReader->getAttributeValue( attrName);
// create an entry and store it in the library under its ID // create an entry and store it in the library under its ID
ReadMaterial(mMaterialLibrary[id] = Material()); mMaterialLibrary[id] = Material();
if( !name.empty())
{
std::map<std::string, int>::iterator it = names.find( name);
if( it != names.end())
{
std::ostringstream strStream;
strStream << ++it->second;
name.append( " " + strStream.str());
}
else
{
names[name] = 0;
}
mMaterialLibrary[id].mName = name;
}
ReadMaterial( mMaterialLibrary[id]);
} else } else
{ {
// ignore the rest // ignore the rest
@ -1385,6 +1410,9 @@ void ColladaParser::ReadEffectColor( aiColor4D& pColor, Sampler& pSampler)
if( attrTex >= 0 ) if( attrTex >= 0 )
pSampler.mUVChannel = mReader->getAttributeValue( attrTex); pSampler.mUVChannel = mReader->getAttributeValue( attrTex);
//SkipElement(); //SkipElement();
// as we've read texture, the color needs to be 1,1,1,1
pColor = aiColor4D(1.f, 1.f, 1.f, 1.f);
} }
else if( IsElement( "technique")) else if( IsElement( "technique"))
{ {
@ -1936,6 +1964,10 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
// now here the actual fun starts - these are the indices to construct the mesh data from // now here the actual fun starts - these are the indices to construct the mesh data from
actualPrimitives += ReadPrimitives(pMesh, perIndexData, numPrimitives, vcount, primType); actualPrimitives += ReadPrimitives(pMesh, perIndexData, numPrimitives, vcount, primType);
} }
}
else if (IsElement("extra"))
{
SkipElement("extra");
} else } else
{ {
ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <%s>") % mReader->getNodeName() % elementName)); ThrowException( boost::str( boost::format( "Unexpected sub element <%s> in tag <%s>") % mReader->getNodeName() % elementName));
@ -2661,7 +2693,7 @@ void ColladaParser::ReadScene()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception // Aborts the file reading with an exception
void ColladaParser::ThrowException( const std::string& pError) const AI_WONT_RETURN void ColladaParser::ThrowException( const std::string& pError) const
{ {
throw DeadlyImportError( boost::str( boost::format( "Collada: %s - %s") % mFileName % pError)); throw DeadlyImportError( boost::str( boost::format( "Collada: %s - %s") % mFileName % pError));
} }

View File

@ -212,7 +212,7 @@ protected:
protected: protected:
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
void ThrowException( const std::string& pError) const; AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
/** Skips all data until the end node of the current element */ /** Skips all data until the end node of the current element */
void SkipElement(); void SkipElement();

View File

@ -454,7 +454,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
for (unsigned int m = 0; m < pScene->mNumMeshes;++m) for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
{ {
aiMesh* mesh = pScene->mMeshes[m]; aiMesh* mesh = pScene->mMeshes[m];
unsigned int outIdx; unsigned int outIdx = 0;
if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX || if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
!mesh->mNumVertices) !mesh->mNumVertices)
{ {

View File

@ -78,7 +78,8 @@ namespace {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError. // signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
void TokenizeError(const std::string& message, unsigned int offset) AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset)
{ {
throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset)); throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
} }

View File

@ -1256,8 +1256,11 @@ private:
// taking notes so we don't need to do it twice. // taking notes so we don't need to do it twice.
BOOST_FOREACH(WeightIndexArray::value_type index, indices) { BOOST_FOREACH(WeightIndexArray::value_type index, indices) {
unsigned int count; unsigned int count = 0;
const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count); const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count);
// ToOutputVertexIndex only returns NULL if index is out of bounds
// which should never happen
ai_assert(out_idx != NULL);
index_out_indices.push_back(no_index_sentinel); index_out_indices.push_back(no_index_sentinel);
count_out_indices.push_back(0); count_out_indices.push_back(0);

View File

@ -242,20 +242,20 @@ public:
public: public:
fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0)); fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0)); fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
fbx_simple_property(InterestPosition, aiVector3D, aiVector3D(0,0,0)); fbx_simple_property(InterestPosition, aiVector3D, aiVector3D(0,0,0))
fbx_simple_property(AspectWidth, float, 1.0f); fbx_simple_property(AspectWidth, float, 1.0f)
fbx_simple_property(AspectHeight, float, 1.0f); fbx_simple_property(AspectHeight, float, 1.0f)
fbx_simple_property(FilmWidth, float, 1.0f); fbx_simple_property(FilmWidth, float, 1.0f)
fbx_simple_property(FilmHeight, float, 1.0f); fbx_simple_property(FilmHeight, float, 1.0f)
fbx_simple_property(FilmAspectRatio, float, 1.0f); fbx_simple_property(FilmAspectRatio, float, 1.0f)
fbx_simple_property(ApertureMode, int, 0); fbx_simple_property(ApertureMode, int, 0)
fbx_simple_property(FieldOfView, float, 1.0f); fbx_simple_property(FieldOfView, float, 1.0f)
fbx_simple_property(FocalLength, float, 1.0f); fbx_simple_property(FocalLength, float, 1.0f)
private: private:
}; };
@ -314,37 +314,37 @@ public:
public: public:
fbx_simple_property(Color, aiVector3D, aiVector3D(1,1,1)); fbx_simple_property(Color, aiVector3D, aiVector3D(1,1,1))
fbx_simple_enum_property(LightType, Type, 0); fbx_simple_enum_property(LightType, Type, 0)
fbx_simple_property(CastLightOnObject, bool, false); fbx_simple_property(CastLightOnObject, bool, false)
fbx_simple_property(DrawVolumetricLight, bool, true); fbx_simple_property(DrawVolumetricLight, bool, true)
fbx_simple_property(DrawGroundProjection, bool, true); fbx_simple_property(DrawGroundProjection, bool, true)
fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false); fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false)
fbx_simple_property(Intensity, float, 1.0f); fbx_simple_property(Intensity, float, 1.0f)
fbx_simple_property(InnerAngle, float, 0.0f); fbx_simple_property(InnerAngle, float, 0.0f)
fbx_simple_property(OuterAngle, float, 45.0f); fbx_simple_property(OuterAngle, float, 45.0f)
fbx_simple_property(Fog, int, 50); fbx_simple_property(Fog, int, 50)
fbx_simple_enum_property(DecayType, Decay, 0); fbx_simple_enum_property(DecayType, Decay, 0)
fbx_simple_property(DecayStart, int, 0); fbx_simple_property(DecayStart, int, 0)
fbx_simple_property(FileName, std::string, ""); fbx_simple_property(FileName, std::string, "")
fbx_simple_property(EnableNearAttenuation, bool, false); fbx_simple_property(EnableNearAttenuation, bool, false)
fbx_simple_property(NearAttenuationStart, float, 0.0f); fbx_simple_property(NearAttenuationStart, float, 0.0f)
fbx_simple_property(NearAttenuationEnd, float, 0.0f); fbx_simple_property(NearAttenuationEnd, float, 0.0f)
fbx_simple_property(EnableFarAttenuation, bool, false); fbx_simple_property(EnableFarAttenuation, bool, false)
fbx_simple_property(FarAttenuationStart, float, 0.0f); fbx_simple_property(FarAttenuationStart, float, 0.0f)
fbx_simple_property(FarAttenuationEnd, float, 0.0f); fbx_simple_property(FarAttenuationEnd, float, 0.0f)
fbx_simple_property(CastShadows, bool, true); fbx_simple_property(CastShadows, bool, true)
fbx_simple_property(ShadowColor, aiVector3D, aiVector3D(0,0,0)); fbx_simple_property(ShadowColor, aiVector3D, aiVector3D(0,0,0))
fbx_simple_property(AreaLightShape, int, 0); fbx_simple_property(AreaLightShape, int, 0)
fbx_simple_property(LeftBarnDoor, float, 20.0f); fbx_simple_property(LeftBarnDoor, float, 20.0f)
fbx_simple_property(RightBarnDoor, float, 20.0f); fbx_simple_property(RightBarnDoor, float, 20.0f)
fbx_simple_property(TopBarnDoor, float, 20.0f); fbx_simple_property(TopBarnDoor, float, 20.0f)
fbx_simple_property(BottomBarnDoor, float, 20.0f); fbx_simple_property(BottomBarnDoor, float, 20.0f)
fbx_simple_property(EnableBarnDoor, bool, true); fbx_simple_property(EnableBarnDoor, bool, true)
private: private:
@ -387,81 +387,81 @@ public:
public: public:
fbx_simple_property(QuaternionInterpolate, int, 0); fbx_simple_property(QuaternionInterpolate, int, 0)
fbx_simple_property(RotationOffset, aiVector3D, aiVector3D()); fbx_simple_property(RotationOffset, aiVector3D, aiVector3D())
fbx_simple_property(RotationPivot, aiVector3D, aiVector3D()); fbx_simple_property(RotationPivot, aiVector3D, aiVector3D())
fbx_simple_property(ScalingOffset, aiVector3D, aiVector3D()); fbx_simple_property(ScalingOffset, aiVector3D, aiVector3D())
fbx_simple_property(ScalingPivot, aiVector3D, aiVector3D()); fbx_simple_property(ScalingPivot, aiVector3D, aiVector3D())
fbx_simple_property(TranslationActive, bool, false); fbx_simple_property(TranslationActive, bool, false)
fbx_simple_property(TranslationMin, aiVector3D, aiVector3D()); fbx_simple_property(TranslationMin, aiVector3D, aiVector3D())
fbx_simple_property(TranslationMax, aiVector3D, aiVector3D()); fbx_simple_property(TranslationMax, aiVector3D, aiVector3D())
fbx_simple_property(TranslationMinX, bool, false); fbx_simple_property(TranslationMinX, bool, false)
fbx_simple_property(TranslationMaxX, bool, false); fbx_simple_property(TranslationMaxX, bool, false)
fbx_simple_property(TranslationMinY, bool, false); fbx_simple_property(TranslationMinY, bool, false)
fbx_simple_property(TranslationMaxY, bool, false); fbx_simple_property(TranslationMaxY, bool, false)
fbx_simple_property(TranslationMinZ, bool, false); fbx_simple_property(TranslationMinZ, bool, false)
fbx_simple_property(TranslationMaxZ, bool, false); fbx_simple_property(TranslationMaxZ, bool, false)
fbx_simple_enum_property(RotationOrder, RotOrder, 0); fbx_simple_enum_property(RotationOrder, RotOrder, 0)
fbx_simple_property(RotationSpaceForLimitOnly, bool, false); fbx_simple_property(RotationSpaceForLimitOnly, bool, false)
fbx_simple_property(RotationStiffnessX, float, 0.0f); fbx_simple_property(RotationStiffnessX, float, 0.0f)
fbx_simple_property(RotationStiffnessY, float, 0.0f); fbx_simple_property(RotationStiffnessY, float, 0.0f)
fbx_simple_property(RotationStiffnessZ, float, 0.0f); fbx_simple_property(RotationStiffnessZ, float, 0.0f)
fbx_simple_property(AxisLen, float, 0.0f); fbx_simple_property(AxisLen, float, 0.0f)
fbx_simple_property(PreRotation, aiVector3D, aiVector3D()); fbx_simple_property(PreRotation, aiVector3D, aiVector3D())
fbx_simple_property(PostRotation, aiVector3D, aiVector3D()); fbx_simple_property(PostRotation, aiVector3D, aiVector3D())
fbx_simple_property(RotationActive, bool, false); fbx_simple_property(RotationActive, bool, false)
fbx_simple_property(RotationMin, aiVector3D, aiVector3D()); fbx_simple_property(RotationMin, aiVector3D, aiVector3D())
fbx_simple_property(RotationMax, aiVector3D, aiVector3D()); fbx_simple_property(RotationMax, aiVector3D, aiVector3D())
fbx_simple_property(RotationMinX, bool, false); fbx_simple_property(RotationMinX, bool, false)
fbx_simple_property(RotationMaxX, bool, false); fbx_simple_property(RotationMaxX, bool, false)
fbx_simple_property(RotationMinY, bool, false); fbx_simple_property(RotationMinY, bool, false)
fbx_simple_property(RotationMaxY, bool, false); fbx_simple_property(RotationMaxY, bool, false)
fbx_simple_property(RotationMinZ, bool, false); fbx_simple_property(RotationMinZ, bool, false)
fbx_simple_property(RotationMaxZ, bool, false); fbx_simple_property(RotationMaxZ, bool, false)
fbx_simple_enum_property(InheritType, TransformInheritance, 0); fbx_simple_enum_property(InheritType, TransformInheritance, 0)
fbx_simple_property(ScalingActive, bool, false); fbx_simple_property(ScalingActive, bool, false)
fbx_simple_property(ScalingMin, aiVector3D, aiVector3D()); fbx_simple_property(ScalingMin, aiVector3D, aiVector3D())
fbx_simple_property(ScalingMax, aiVector3D, aiVector3D(1.f,1.f,1.f)); fbx_simple_property(ScalingMax, aiVector3D, aiVector3D(1.f,1.f,1.f))
fbx_simple_property(ScalingMinX, bool, false); fbx_simple_property(ScalingMinX, bool, false)
fbx_simple_property(ScalingMaxX, bool, false); fbx_simple_property(ScalingMaxX, bool, false)
fbx_simple_property(ScalingMinY, bool, false); fbx_simple_property(ScalingMinY, bool, false)
fbx_simple_property(ScalingMaxY, bool, false); fbx_simple_property(ScalingMaxY, bool, false)
fbx_simple_property(ScalingMinZ, bool, false); fbx_simple_property(ScalingMinZ, bool, false)
fbx_simple_property(ScalingMaxZ, bool, false); fbx_simple_property(ScalingMaxZ, bool, false)
fbx_simple_property(GeometricTranslation, aiVector3D, aiVector3D()); fbx_simple_property(GeometricTranslation, aiVector3D, aiVector3D())
fbx_simple_property(GeometricRotation, aiVector3D, aiVector3D()); fbx_simple_property(GeometricRotation, aiVector3D, aiVector3D())
fbx_simple_property(GeometricScaling, aiVector3D, aiVector3D(1.f, 1.f, 1.f)); fbx_simple_property(GeometricScaling, aiVector3D, aiVector3D(1.f, 1.f, 1.f))
fbx_simple_property(MinDampRangeX, float, 0.0f); fbx_simple_property(MinDampRangeX, float, 0.0f)
fbx_simple_property(MinDampRangeY, float, 0.0f); fbx_simple_property(MinDampRangeY, float, 0.0f)
fbx_simple_property(MinDampRangeZ, float, 0.0f); fbx_simple_property(MinDampRangeZ, float, 0.0f)
fbx_simple_property(MaxDampRangeX, float, 0.0f); fbx_simple_property(MaxDampRangeX, float, 0.0f)
fbx_simple_property(MaxDampRangeY, float, 0.0f); fbx_simple_property(MaxDampRangeY, float, 0.0f)
fbx_simple_property(MaxDampRangeZ, float, 0.0f); fbx_simple_property(MaxDampRangeZ, float, 0.0f)
fbx_simple_property(MinDampStrengthX, float, 0.0f); fbx_simple_property(MinDampStrengthX, float, 0.0f)
fbx_simple_property(MinDampStrengthY, float, 0.0f); fbx_simple_property(MinDampStrengthY, float, 0.0f)
fbx_simple_property(MinDampStrengthZ, float, 0.0f); fbx_simple_property(MinDampStrengthZ, float, 0.0f)
fbx_simple_property(MaxDampStrengthX, float, 0.0f); fbx_simple_property(MaxDampStrengthX, float, 0.0f)
fbx_simple_property(MaxDampStrengthY, float, 0.0f); fbx_simple_property(MaxDampStrengthY, float, 0.0f)
fbx_simple_property(MaxDampStrengthZ, float, 0.0f); fbx_simple_property(MaxDampStrengthZ, float, 0.0f)
fbx_simple_property(PreferredAngleX, float, 0.0f); fbx_simple_property(PreferredAngleX, float, 0.0f)
fbx_simple_property(PreferredAngleY, float, 0.0f); fbx_simple_property(PreferredAngleY, float, 0.0f)
fbx_simple_property(PreferredAngleZ, float, 0.0f); fbx_simple_property(PreferredAngleZ, float, 0.0f)
fbx_simple_property(Show, bool, true); fbx_simple_property(Show, bool, true)
fbx_simple_property(LODBox, bool, false); fbx_simple_property(LODBox, bool, false)
fbx_simple_property(Freeze, bool, false); fbx_simple_property(Freeze, bool, false)
public: public:
@ -1015,10 +1015,10 @@ public:
public: public:
fbx_simple_property(LocalStart, uint64_t, 0L); fbx_simple_property(LocalStart, uint64_t, 0L)
fbx_simple_property(LocalStop, uint64_t, 0L); fbx_simple_property(LocalStop, uint64_t, 0L)
fbx_simple_property(ReferenceStart, uint64_t, 0L); fbx_simple_property(ReferenceStart, uint64_t, 0L)
fbx_simple_property(ReferenceStop, uint64_t, 0L); fbx_simple_property(ReferenceStop, uint64_t, 0L)
@ -1227,18 +1227,18 @@ public:
} }
fbx_simple_property(UpAxis, int, 1); fbx_simple_property(UpAxis, int, 1)
fbx_simple_property(UpAxisSign, int, 1); fbx_simple_property(UpAxisSign, int, 1)
fbx_simple_property(FrontAxis, int, 2); fbx_simple_property(FrontAxis, int, 2)
fbx_simple_property(FrontAxisSign, int, 1); fbx_simple_property(FrontAxisSign, int, 1)
fbx_simple_property(CoordAxis, int, 0); fbx_simple_property(CoordAxis, int, 0)
fbx_simple_property(CoordAxisSign, int, 1); fbx_simple_property(CoordAxisSign, int, 1)
fbx_simple_property(OriginalUpAxis, int, 0); fbx_simple_property(OriginalUpAxis, int, 0)
fbx_simple_property(OriginalUpAxisSign, int, 1); fbx_simple_property(OriginalUpAxisSign, int, 1)
fbx_simple_property(UnitScaleFactor, double, 1); fbx_simple_property(UnitScaleFactor, double, 1)
fbx_simple_property(OriginalUnitScaleFactor, double, 1); fbx_simple_property(OriginalUnitScaleFactor, double, 1)
fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0)); fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0))
fbx_simple_property(DefaultCamera, std::string, ""); fbx_simple_property(DefaultCamera, std::string, "")
enum FrameRate { enum FrameRate {
@ -1261,10 +1261,10 @@ public:
FrameRate_MAX// end-of-enum sentinel FrameRate_MAX// end-of-enum sentinel
}; };
fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT); fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT)
fbx_simple_property(TimeSpanStart, uint64_t, 0L); fbx_simple_property(TimeSpanStart, uint64_t, 0L)
fbx_simple_property(TimeSpanStop, uint64_t, 0L); fbx_simple_property(TimeSpanStop, uint64_t, 0L)
fbx_simple_property(CustomFrameRate, float, -1.0f); fbx_simple_property(CustomFrameRate, float, -1.0f)
private: private:

View File

@ -68,13 +68,15 @@ namespace {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// signal parse error, this is always unrecoverable. Throws DeadlyImportError. // signal parse error, this is always unrecoverable. Throws DeadlyImportError.
void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ParseError(const std::string& message, const Token& token)
{ {
throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token)); throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ParseError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN void ParseError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ParseError(const std::string& message, const Element* element)
{ {
if(element) { if(element) {
ParseError(message,element->KeyToken()); ParseError(message,element->KeyToken());

View File

@ -86,7 +86,8 @@ namespace {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError. // signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column)
{ {
throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column)); throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column));
} }

View File

@ -107,7 +107,7 @@ void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh)
bool first = true; bool first = true;
// check whether the face contains degenerated entries // check whether the face contains degenerated entries
for (register unsigned int i = 0; i < face.mNumIndices; ++i) for (unsigned int i = 0; i < face.mNumIndices; ++i)
{ {
// Polygons with more than 4 points are allowed to have double points, that is // Polygons with more than 4 points are allowed to have double points, that is
// simulating polygons with holes just with concave polygons. However, // simulating polygons with holes just with concave polygons. However,
@ -116,7 +116,7 @@ void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh)
if (face.mNumIndices > 4) if (face.mNumIndices > 4)
limit = std::min(limit,i+2); limit = std::min(limit,i+2);
for (register unsigned int t = i+1; t < limit; ++t) for (unsigned int t = i+1; t < limit; ++t)
{ {
if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]])
{ {

View File

@ -89,7 +89,7 @@ void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMap
unsigned int out = 0; unsigned int out = 0;
for (unsigned int a = 0; a < node->mNumMeshes;++a) { for (unsigned int a = 0; a < node->mNumMeshes;++a) {
register unsigned int ref = node->mMeshes[a]; unsigned int ref = node->mMeshes[a];
if (UINT_MAX != (ref = meshMapping[ref])) { if (UINT_MAX != (ref = meshMapping[ref])) {
node->mMeshes[out++] = ref; node->mMeshes[out++] = ref;
} }

View File

@ -195,7 +195,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
// Write the smoothed normal back to all affected normals // Write the smoothed normal back to all affected normals
for (unsigned int a = 0; a < verticesFound.size(); ++a) for (unsigned int a = 0; a < verticesFound.size(); ++a)
{ {
register unsigned int vidx = verticesFound[a]; unsigned int vidx = verticesFound[a];
pcNew[vidx] = pcNor; pcNew[vidx] = pcNor;
abHad[vidx] = true; abHad[vidx] = true;
} }

View File

@ -50,42 +50,97 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include <iterator> #include <iterator>
#include <boost/tuple/tuple.hpp>
namespace Assimp { namespace Assimp {
namespace IFC { namespace IFC {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
enum Intersect { // Calculates intersection between line segment and plane. To catch corner cases, specify which side you prefer.
Intersect_No, // The function then generates a hit only if the end is beyond a certain margin in that direction, filtering out
Intersect_LiesOnPlane, // "very close to plane" ghost hits as long as start and end stay directly on or within the given plane side.
Intersect_Yes bool IntersectSegmentPlane(const IfcVector3& p,const IfcVector3& n, const IfcVector3& e0,
}; const IfcVector3& e1, bool assumeStartOnWhiteSide, IfcVector3& out)
// ------------------------------------------------------------------------------------------------
Intersect IntersectSegmentPlane(const IfcVector3& p,const IfcVector3& n, const IfcVector3& e0,
const IfcVector3& e1,
IfcVector3& out)
{ {
const IfcVector3 pdelta = e0 - p, seg = e1-e0; const IfcVector3 pdelta = e0 - p, seg = e1 - e0;
const IfcFloat dotOne = n*seg, dotTwo = -(n*pdelta); const IfcFloat dotOne = n*seg, dotTwo = -(n*pdelta);
if (std::fabs(dotOne) < 1e-6) { // if segment ends on plane, do not report a hit. We stay on that side until a following segment starting at this
return std::fabs(dotTwo) < 1e-6f ? Intersect_LiesOnPlane : Intersect_No; // point leaves the plane through the other side
if( std::abs(dotOne + dotTwo) < 1e-6 )
return false;
// if segment starts on the plane, report a hit only if the end lies on the *other* side
if( std::abs(dotTwo) < 1e-6 )
{
if( (assumeStartOnWhiteSide && dotOne + dotTwo < 1e-6) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -1e-6) )
{
out = e0;
return true;
}
else
{
return false;
}
} }
const IfcFloat t = dotTwo/dotOne; // ignore if segment is parallel to plane and far away from it on either side
// Warning: if there's a few thousand of such segments which slowly accumulate beyond the epsilon, no hit would be registered
if( std::abs(dotOne) < 1e-6 )
return false;
// t must be in [0..1] if the intersection point is within the given segment // t must be in [0..1] if the intersection point is within the given segment
if (t > 1.f || t < 0.f) { const IfcFloat t = dotTwo / dotOne;
return Intersect_No; if( t > 1.0 || t < 0.0 )
} return false;
out = e0+t*seg;
return Intersect_Yes; out = e0 + t*seg;
return true;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& result, void FilterPolygon(std::vector<IfcVector3>& resultpoly)
const TempMesh& first_operand, {
ConversionData& /*conv*/) if( resultpoly.size() < 3 )
{
resultpoly.clear();
return;
}
IfcVector3 vmin, vmax;
ArrayBounds(resultpoly.data(), resultpoly.size(), vmin, vmax);
// filter our IfcFloat points - those may happen if a point lies
// directly on the intersection line or directly on the clipping plane
const IfcFloat epsilon = (vmax - vmin).SquareLength() / 1e6f;
FuzzyVectorCompare fz(epsilon);
std::vector<IfcVector3>::iterator e = std::unique(resultpoly.begin(), resultpoly.end(), fz);
if( e != resultpoly.end() )
resultpoly.erase(e, resultpoly.end());
if( !resultpoly.empty() && fz(resultpoly.front(), resultpoly.back()) )
resultpoly.pop_back();
}
// ------------------------------------------------------------------------------------------------
void WritePolygon(std::vector<IfcVector3>& resultpoly, TempMesh& result)
{
FilterPolygon(resultpoly);
if( resultpoly.size() > 2 )
{
result.verts.insert(result.verts.end(), resultpoly.begin(), resultpoly.end());
result.vertcnt.push_back(resultpoly.size());
}
}
// ------------------------------------------------------------------------------------------------
void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& result,
const TempMesh& first_operand,
ConversionData& /*conv*/)
{ {
ai_assert(hs != NULL); ai_assert(hs != NULL);
@ -120,20 +175,14 @@ void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& re
for(iit = begin; iit != end; vidx += *iit++) { for(iit = begin; iit != end; vidx += *iit++) {
unsigned int newcount = 0; unsigned int newcount = 0;
for(unsigned int i = 0; i < *iit; ++i) { bool isAtWhiteSide = (in[vidx] - p) * n > -1e-6;
const IfcVector3& e0 = in[vidx+i], e1 = in[vidx+(i+1)%*iit]; for( unsigned int i = 0; i < *iit; ++i ) {
const IfcVector3& e0 = in[vidx + i], e1 = in[vidx + (i + 1) % *iit];
// does the next segment intersect the plane? // does the next segment intersect the plane?
IfcVector3 isectpos; IfcVector3 isectpos;
const Intersect isect = IntersectSegmentPlane(p,n,e0,e1,isectpos); if( IntersectSegmentPlane(p, n, e0, e1, isAtWhiteSide, isectpos) ) {
if (isect == Intersect_No || isect == Intersect_LiesOnPlane) { if( isAtWhiteSide ) {
if ( (e0-p).Normalize()*n > 0 ) {
outvert.push_back(e0);
++newcount;
}
}
else if (isect == Intersect_Yes) {
if ( (e0-p).Normalize()*n > 0 ) {
// e0 is on the right side, so keep it // e0 is on the right side, so keep it
outvert.push_back(e0); outvert.push_back(e0);
outvert.push_back(isectpos); outvert.push_back(isectpos);
@ -144,8 +193,16 @@ void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& re
outvert.push_back(isectpos); outvert.push_back(isectpos);
++newcount; ++newcount;
} }
isAtWhiteSide = !isAtWhiteSide;
} }
} else
{
if( isAtWhiteSide ) {
outvert.push_back(e0);
++newcount;
}
}
}
if (!newcount) { if (!newcount) {
continue; continue;
@ -185,76 +242,114 @@ void ProcessBooleanHalfSpaceDifference(const IfcHalfSpaceSolid* hs, TempMesh& re
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check if e0-e1 intersects a sub-segment of the given boundary line. // Check if e0-e1 intersects a sub-segment of the given boundary line.
// note: this functions works on 3D vectors, but performs its intersection checks solely in xy. // note: this functions works on 3D vectors, but performs its intersection checks solely in xy.
bool IntersectsBoundaryProfile( const IfcVector3& e0, const IfcVector3& e1, const std::vector<IfcVector3>& boundary, // New version takes the supposed inside/outside state as a parameter and treats corner cases as if
std::vector<size_t>& intersected_boundary_segments, // the line stays on that side. This should make corner cases more stable.
std::vector<IfcVector3>& intersected_boundary_points, // Two million assumptions! Boundary should have all z at 0.0, will be treated as closed, should not have
bool half_open = false, // segments with length <1e-6, self-intersecting might break the corner case handling... just don't go there, ok?
bool* e0_hits_border = NULL) bool IntersectsBoundaryProfile(const IfcVector3& e0, const IfcVector3& e1, const std::vector<IfcVector3>& boundary,
const bool isStartAssumedInside, std::vector<std::pair<size_t, IfcVector3> >& intersect_results,
const bool halfOpen = false)
{ {
ai_assert(intersected_boundary_segments.empty()); ai_assert(intersect_results.empty());
ai_assert(intersected_boundary_points.empty());
if(e0_hits_border) { // determine winding order - necessary to detect segments going "inwards" or "outwards" from a point directly on the border
*e0_hits_border = false; // positive sum of angles means clockwise order when looking down the -Z axis
IfcFloat windingOrder = 0.0;
for( size_t i = 0, bcount = boundary.size(); i < bcount; ++i ) {
IfcVector3 b01 = boundary[(i + 1) % bcount] - boundary[i];
IfcVector3 b12 = boundary[(i + 2) % bcount] - boundary[(i + 1) % bcount];
IfcVector3 b1_side = IfcVector3(b01.y, -b01.x, 0.0); // rotated 90° clockwise in Z plane
// Warning: rough estimate only. A concave poly with lots of small segments each featuring a small counter rotation
// could fool the accumulation. Correct implementation would be sum( acos( b01 * b2) * sign( b12 * b1_side))
windingOrder += (b1_side.x*b12.x + b1_side.y*b12.y);
} }
windingOrder = windingOrder > 0.0 ? 1.0 : -1.0;
const IfcVector3& e = e1 - e0; const IfcVector3 e = e1 - e0;
for (size_t i = 0, bcount = boundary.size(); i < bcount; ++i) { for( size_t i = 0, bcount = boundary.size(); i < bcount; ++i ) {
// boundary segment i: b0-b1 // boundary segment i: b0-b1
const IfcVector3& b0 = boundary[i]; const IfcVector3& b0 = boundary[i];
const IfcVector3& b1 = boundary[(i+1) % bcount]; const IfcVector3& b1 = boundary[(i + 1) % bcount];
IfcVector3 b = b1 - b0;
const IfcVector3& b = b1 - b0; IfcFloat b_sqlen_inv = 1.0 / b.SquareLength();
// segment-segment intersection // segment-segment intersection
// solve b0 + b*s = e0 + e*t for (s,t) // solve b0 + b*s = e0 + e*t for (s,t)
const IfcFloat det = (-b.x * e.y + e.x * b.y); const IfcFloat det = (-b.x * e.y + e.x * b.y);
if(std::fabs(det) < 1e-6) { if( std::abs(det) < 1e-6 ) {
// no solutions (parallel lines) // no solutions (parallel lines)
continue; continue;
} }
const IfcFloat x = b0.x - e0.x; const IfcFloat x = b0.x - e0.x;
const IfcFloat y = b0.y - e0.y; const IfcFloat y = b0.y - e0.y;
const IfcFloat s = (x*e.y - e.x*y) / det; // scale along boundary edge
const IfcFloat s = (x*e.y - e.x*y)/det; const IfcFloat t = (x*b.y - b.x*y) / det; // scale along given segment
const IfcFloat t = (x*b.y - b.x*y)/det; const IfcVector3 p = e0 + e*t;
#ifdef ASSIMP_BUILD_DEBUG #ifdef ASSIMP_BUILD_DEBUG
const IfcVector3 check = b0 + b*s - (e0 + e*t); const IfcVector3 check = b0 + b*s - p;
ai_assert((IfcVector2(check.x,check.y)).SquareLength() < 1e-5); ai_assert((IfcVector2(check.x, check.y)).SquareLength() < 1e-5);
#endif #endif
// for a valid intersection, s-t should be in range [0,1]. // also calculate the distance of e0 and e1 to the segment. We need to detect the "starts directly on segment"
// note that for t (i.e. the segment point) we only use a // and "ends directly at segment" cases
// half-sided epsilon because the next segment should catch bool startsAtSegment, endsAtSegment;
// this case. {
const IfcFloat epsilon = 1e-6; // calculate closest point to each end on the segment, clamp that point to the segment's length, then check
if (t >= -epsilon && (t <= 1.0+epsilon || half_open) && s >= -epsilon && s <= 1.0) { // distance to that point. This approach is like testing if e0 is inside a capped cylinder.
IfcFloat et0 = (b.x*(e0.x - b0.x) + b.y*(e0.y - b0.y)) * b_sqlen_inv;
IfcVector3 closestPosToE0OnBoundary = b0 + std::max(IfcFloat(0.0), std::min(IfcFloat(1.0), et0)) * b;
startsAtSegment = (closestPosToE0OnBoundary - IfcVector3(e0.x, e0.y, 0.0)).SquareLength() < 1e-12;
IfcFloat et1 = (b.x*(e1.x - b0.x) + b.y*(e1.y - b0.y)) * b_sqlen_inv;
IfcVector3 closestPosToE1OnBoundary = b0 + std::max(IfcFloat(0.0), std::min(IfcFloat(1.0), et1)) * b;
endsAtSegment = (closestPosToE1OnBoundary - IfcVector3(e1.x, e1.y, 0.0)).SquareLength() < 1e-12;
}
if (e0_hits_border && !*e0_hits_border) { // Line segment ends at boundary -> ignore any hit, it will be handled by possibly following segments
*e0_hits_border = std::fabs(t) < 1e-5f; if( endsAtSegment && !halfOpen )
} continue;
const IfcVector3& p = e0 + e*t;
// only insert the point into the list if it is sufficiently // Line segment starts at boundary -> generate a hit only if following that line would change the INSIDE/OUTSIDE
// far away from the previous intersection point. This way, // state. This should catch the case where a connected set of segments has a point directly on the boundary,
// we avoid duplicate detection if the intersection is // one segment not hitting it because it ends there and the next segment not hitting it because it starts there
// directly on the vertex between two segments. // Should NOT generate a hit if the segment only touches the boundary but turns around and stays inside.
if (!intersected_boundary_points.empty() && intersected_boundary_segments.back()==i-1 ) { if( startsAtSegment )
const IfcVector3 diff = intersected_boundary_points.back() - p; {
if(IfcVector2(diff.x, diff.y).SquareLength() < 1e-7) { IfcVector3 inside_dir = IfcVector3(b.y, -b.x, 0.0) * windingOrder;
bool isGoingInside = (inside_dir * e) > 0.0;
if( isGoingInside == isStartAssumedInside )
continue;
// only insert the point into the list if it is sufficiently far away from the previous intersection point.
// This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments.
if( !intersect_results.empty() && intersect_results.back().first == i - 1 )
{
const IfcVector3 diff = intersect_results.back().second - e0;
if( IfcVector2(diff.x, diff.y).SquareLength() < 1e-10 )
continue; continue;
}
} }
intersected_boundary_segments.push_back(i); intersect_results.push_back(std::make_pair(i, e0));
intersected_boundary_points.push_back(p); continue;
}
// for a valid intersection, s and t should be in range [0,1]. Including a bit of epsilon on s, potential double
// hits on two consecutive boundary segments are filtered
if( s >= -1e-6 * b_sqlen_inv && s <= 1.0 + 1e-6*b_sqlen_inv && t >= 0.0 && (t <= 1.0 || halfOpen) )
{
// only insert the point into the list if it is sufficiently far away from the previous intersection point.
// This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments.
if( !intersect_results.empty() && intersect_results.back().first == i - 1 )
{
const IfcVector3 diff = intersect_results.back().second - p;
if( IfcVector2(diff.x, diff.y).SquareLength() < 1e-10 )
continue;
}
intersect_results.push_back(std::make_pair(i, p));
} }
} }
return !intersected_boundary_segments.empty(); return !intersect_results.empty();
} }
@ -272,47 +367,21 @@ bool PointInPoly(const IfcVector3& p, const std::vector<IfcVector3>& boundary)
// the border of the polygon. If any of our attempts produces this result, // the border of the polygon. If any of our attempts produces this result,
// we return false immediately. // we return false immediately.
std::vector<size_t> intersected_boundary_segments; std::vector<std::pair<size_t, IfcVector3> > intersected_boundary;
std::vector<IfcVector3> intersected_boundary_points;
size_t votes = 0; size_t votes = 0;
bool is_border; IntersectsBoundaryProfile(p, p + IfcVector3(1.0, 0, 0), boundary, true, intersected_boundary, true);
IntersectsBoundaryProfile(p, p + IfcVector3(1.0,0,0), boundary, votes += intersected_boundary.size() % 2;
intersected_boundary_segments,
intersected_boundary_points, true, &is_border);
if(is_border) { intersected_boundary.clear();
return false; IntersectsBoundaryProfile(p, p + IfcVector3(0, 1.0, 0), boundary, true, intersected_boundary, true);
} votes += intersected_boundary.size() % 2;
votes += intersected_boundary_segments.size() % 2; intersected_boundary.clear();
IntersectsBoundaryProfile(p, p + IfcVector3(0.6, -0.6, 0.0), boundary, true, intersected_boundary, true);
votes += intersected_boundary.size() % 2;
intersected_boundary_segments.clear(); // ai_assert(votes == 3 || votes == 0);
intersected_boundary_points.clear();
IntersectsBoundaryProfile(p, p + IfcVector3(0,1.0,0), boundary,
intersected_boundary_segments,
intersected_boundary_points, true, &is_border);
if(is_border) {
return false;
}
votes += intersected_boundary_segments.size() % 2;
intersected_boundary_segments.clear();
intersected_boundary_points.clear();
IntersectsBoundaryProfile(p, p + IfcVector3(0.6,-0.6,0.0), boundary,
intersected_boundary_segments,
intersected_boundary_points, true, &is_border);
if(is_border) {
return false;
}
votes += intersected_boundary_segments.size() % 2;
//ai_assert(votes == 3 || votes == 0);
return votes > 1; return votes > 1;
} }
@ -350,6 +419,9 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
return; return;
} }
// determine winding order by calculating the normal.
IfcVector3 profileNormal = TempMesh::ComputePolygonNormal(profile->verts.data(), profile->verts.size());
IfcMatrix4 proj_inv; IfcMatrix4 proj_inv;
ConvertAxisPlacement(proj_inv,hs->Position); ConvertAxisPlacement(proj_inv,hs->Position);
@ -361,256 +433,287 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
// clip the current contents of `meshout` against the plane we obtained from the second operand // clip the current contents of `meshout` against the plane we obtained from the second operand
const std::vector<IfcVector3>& in = first_operand.verts; const std::vector<IfcVector3>& in = first_operand.verts;
std::vector<IfcVector3>& outvert = result.verts; std::vector<IfcVector3>& outvert = result.verts;
std::vector<unsigned int>& outvertcnt = result.vertcnt;
std::vector<unsigned int>::const_iterator begin = first_operand.vertcnt.begin(),
end = first_operand.vertcnt.end(), iit;
outvert.reserve(in.size()); outvert.reserve(in.size());
result.vertcnt.reserve(first_operand.vertcnt.size()); outvertcnt.reserve(first_operand.vertcnt.size());
std::vector<size_t> intersected_boundary_segments;
std::vector<IfcVector3> intersected_boundary_points;
// TODO: the following algorithm doesn't handle all cases.
unsigned int vidx = 0; unsigned int vidx = 0;
for(iit = begin; iit != end; vidx += *iit++) { std::vector<unsigned int>::const_iterator begin = first_operand.vertcnt.begin();
if (!*iit) { std::vector<unsigned int>::const_iterator end = first_operand.vertcnt.end();
continue; std::vector<unsigned int>::const_iterator iit;
for( iit = begin; iit != end; vidx += *iit++ )
{
// Our new approach: we cut the poly along the plane, then we intersect the part on the black side of the plane
// against the bounding polygon. All the white parts, and the black part outside the boundary polygon, are kept.
std::vector<IfcVector3> whiteside, blackside;
{
const IfcVector3* srcVertices = &in[vidx];
const size_t srcVtxCount = *iit;
if( srcVtxCount == 0 )
continue;
IfcVector3 polyNormal = TempMesh::ComputePolygonNormal(srcVertices, srcVtxCount, true);
// if the poly is parallel to the plane, put it completely on the black or white side
if( std::abs(polyNormal * n) > 0.9999 )
{
bool isOnWhiteSide = (srcVertices[0] - p) * n > -1e-6;
std::vector<IfcVector3>& targetSide = isOnWhiteSide ? whiteside : blackside;
targetSide.insert(targetSide.end(), srcVertices, srcVertices + srcVtxCount);
}
else
{
// otherwise start building one polygon for each side. Whenever the current line segment intersects the plane
// we put a point there as an end of the current segment. Then we switch to the other side, put a point there, too,
// as a beginning of the current segment, and simply continue accumulating vertices.
bool isCurrentlyOnWhiteSide = ((srcVertices[0]) - p) * n > -1e-6;
for( size_t a = 0; a < srcVtxCount; ++a )
{
IfcVector3 e0 = srcVertices[a];
IfcVector3 e1 = srcVertices[(a + 1) % srcVtxCount];
IfcVector3 ei;
// put starting point to the current mesh
std::vector<IfcVector3>& trgt = isCurrentlyOnWhiteSide ? whiteside : blackside;
trgt.push_back(srcVertices[a]);
// if there's an intersection, put an end vertex there, switch to the other side's mesh,
// and add a starting vertex there, too
bool isPlaneHit = IntersectSegmentPlane(p, n, e0, e1, isCurrentlyOnWhiteSide, ei);
if( isPlaneHit )
{
if( trgt.empty() || (trgt.back() - ei).SquareLength() > 1e-12 )
trgt.push_back(ei);
isCurrentlyOnWhiteSide = !isCurrentlyOnWhiteSide;
std::vector<IfcVector3>& newtrgt = isCurrentlyOnWhiteSide ? whiteside : blackside;
newtrgt.push_back(ei);
}
}
}
} }
unsigned int newcount = 0; // the part on the white side can be written into the target mesh right away
bool was_outside_boundary = !PointInPoly(proj * in[vidx], profile->verts); WritePolygon(whiteside, result);
// used any more? // The black part is the piece we need to get rid of, but only the part of it within the boundary polygon.
//size_t last_intersected_boundary_segment; // So we now need to construct all the polygons that result from BlackSidePoly minus BoundaryPoly.
IfcVector3 last_intersected_boundary_point; FilterPolygon(blackside);
bool extra_point_flag = false; // Complicated, II. We run along the polygon. a) When we're inside the boundary, we run on until we hit an
IfcVector3 extra_point; // intersection, which means we're leaving it. We then start a new out poly there. b) When we're outside the
// boundary, we start collecting vertices until we hit an intersection, then we run along the boundary until we hit
// an intersection, then we switch back to the poly and run on on this one again, and so on until we got a closed
// loop. Then we continue with the path we left to catch potential additional polys on the other side of the
// boundary as described in a)
if( !blackside.empty() )
{
// poly edge index, intersection point, edge index in boundary poly
std::vector<boost::tuple<size_t, IfcVector3, size_t> > intersections;
bool startedInside = PointInPoly(proj * blackside.front(), profile->verts);
bool isCurrentlyInside = startedInside;
IfcVector3 enter_volume; std::vector<std::pair<size_t, IfcVector3> > intersected_boundary;
bool entered_volume_flag = false;
for(unsigned int i = 0; i < *iit; ++i) { for( size_t a = 0; a < blackside.size(); ++a )
// current segment: [i,i+1 mod size] or [*extra_point,i] if extra_point_flag is set {
const IfcVector3& e0 = extra_point_flag ? extra_point : in[vidx+i]; const IfcVector3 e0 = proj * blackside[a];
const IfcVector3& e1 = extra_point_flag ? in[vidx+i] : in[vidx+(i+1)%*iit]; const IfcVector3 e1 = proj * blackside[(a + 1) % blackside.size()];
// does the current segment intersect the polygonal boundary? intersected_boundary.clear();
const IfcVector3& e0_plane = proj * e0; IntersectsBoundaryProfile(e0, e1, profile->verts, isCurrentlyInside, intersected_boundary);
const IfcVector3& e1_plane = proj * e1; // sort the hits by distance from e0 to get the correct in/out/in sequence. Manually :-( I miss you, C++11.
if( intersected_boundary.size() > 1 )
intersected_boundary_segments.clear(); {
intersected_boundary_points.clear(); bool keepSorting = true;
while( keepSorting )
const bool is_outside_boundary = !PointInPoly(e1_plane, profile->verts); {
const bool is_boundary_intersection = is_outside_boundary != was_outside_boundary; keepSorting = false;
for( size_t b = 0; b < intersected_boundary.size() - 1; ++b )
IntersectsBoundaryProfile(e0_plane, e1_plane, profile->verts, {
intersected_boundary_segments, if( (intersected_boundary[b + 1].second - e0).SquareLength() < (intersected_boundary[b].second - e0).SquareLength() )
intersected_boundary_points); {
keepSorting = true;
ai_assert(!is_boundary_intersection || !intersected_boundary_segments.empty()); std::swap(intersected_boundary[b + 1], intersected_boundary[b]);
}
// does the current segment intersect the plane? }
// (no extra check if this is an extra point)
IfcVector3 isectpos;
const Intersect isect = extra_point_flag ? Intersect_No : IntersectSegmentPlane(p,n,e0,e1,isectpos);
#ifdef ASSIMP_BUILD_DEBUG
if (isect == Intersect_Yes) {
const IfcFloat f = std::fabs((isectpos - p)*n);
ai_assert(f < 1e-5);
}
#endif
const bool is_white_side = (e0-p)*n >= -1e-6;
// e0 on good side of plane? (i.e. we should keep all geometry on this side)
if (is_white_side) {
// but is there an intersection in e0-e1 and is e1 in the clipping
// boundary? In this case, generate a line that only goes to the
// intersection point.
if (isect == Intersect_Yes && !is_outside_boundary) {
outvert.push_back(e0);
++newcount;
outvert.push_back(isectpos);
++newcount;
/*
// this is, however, only a line that goes to the plane, but not
// necessarily to the point where the bounding volume on the
// black side of the plane is hit. So basically, we need another
// check for [isectpos-e1], which should yield an intersection
// point.
extra_point_flag = true;
extra_point = isectpos;
was_outside_boundary = true;
continue; */
// [isectpos, enter_volume] potentially needs extra points.
// For this, we determine the intersection point with the
// bounding volume and project it onto the plane.
/*
const IfcVector3& enter_volume_proj = proj * enter_volume;
const IfcVector3& enter_isectpos = proj * isectpos;
intersected_boundary_segments.clear();
intersected_boundary_points.clear();
IntersectsBoundaryProfile(enter_volume_proj, enter_isectpos, profile->verts,
intersected_boundary_segments,
intersected_boundary_points);
if(!intersected_boundary_segments.empty()) {
vec = vec + ((p - vec) * n) * n;
} }
*/
//entered_volume_flag = true;
} }
else { // now add them to the list of intersections
outvert.push_back(e0); for( size_t b = 0; b < intersected_boundary.size(); ++b )
++newcount; intersections.push_back(boost::make_tuple(a, proj_inv * intersected_boundary[b].second, intersected_boundary[b].first));
// and calculate our new inside/outside state
if( intersected_boundary.size() & 1 )
isCurrentlyInside = !isCurrentlyInside;
}
// we got a list of in-out-combinations of intersections. That should be an even number of intersections, or
// we're fucked.
if( (intersections.size() & 1) != 0 )
{
IFCImporter::LogWarn("Odd number of intersections, can't work with that. Omitting half space boundary check.");
continue;
}
if( intersections.size() > 1 )
{
// If we started outside, the first intersection is a out->in intersection. Cycle them so that it
// starts with an intersection leaving the boundary
if( !startedInside )
for( size_t b = 0; b < intersections.size() - 1; ++b )
std::swap(intersections[b], intersections[(b + intersections.size() - 1) % intersections.size()]);
// Filter pairs of out->in->out that lie too close to each other.
for( size_t a = 0; intersections.size() > 0 && a < intersections.size() - 1; /**/ )
{
if( (intersections[a].get<1>() - intersections[(a + 1) % intersections.size()].get<1>()).SquareLength() < 1e-10 )
intersections.erase(intersections.begin() + a, intersections.begin() + a + 2);
else
a++;
}
if( intersections.size() > 1 && (intersections.back().get<1>() - intersections.front().get<1>()).SquareLength() < 1e-10 )
{
intersections.pop_back(); intersections.erase(intersections.begin());
} }
} }
// e0 on bad side of plane, e1 on good (i.e. we should remove geometry on this side,
// but only if it is within the bounding volume).
else if (isect == Intersect_Yes) {
// is e0 within the clipping volume? Insert the intersection point
// of [e0,e1] and the plane instead of e0.
if(was_outside_boundary) {
outvert.push_back(e0);
}
else {
if(entered_volume_flag) {
const IfcVector3& fix_point = enter_volume + ((p - enter_volume) * n) * n;
outvert.push_back(fix_point);
++newcount;
}
outvert.push_back(isectpos);
// no intersections at all: either completely inside the boundary, so everything gets discarded, or completely outside.
// in the latter case we're implementional lost. I'm simply going to ignore this, so a large poly will not get any
// holes if the boundary is smaller and does not touch it anywhere.
if( intersections.empty() )
{
// starting point was outside -> everything is outside the boundary -> nothing is clipped -> add black side
// to result mesh unchanged
if( !startedInside )
{
outvertcnt.push_back(blackside.size());
outvert.insert(outvert.end(), blackside.begin(), blackside.end());
continue;
}
else
{
// starting point was inside the boundary -> everything is inside the boundary -> nothing is spared from the
// clipping -> nothing left to add to the result mesh
continue;
} }
entered_volume_flag = false;
++newcount;
} }
else { // no intersection with plane or parallel; e0,e1 are on the bad side
// did we just pass the boundary line to the poly bounding?
if (is_boundary_intersection) {
// and are now outside the clipping boundary? // determine the direction in which we're marching along the boundary polygon. If the src poly is faced upwards
if (is_outside_boundary) { // and the boundary is also winded this way, we need to march *backwards* on the boundary.
// in this case, get the point where the clipping boundary const IfcVector3 polyNormal = IfcMatrix3(proj) * TempMesh::ComputePolygonNormal(blackside.data(), blackside.size());
// was entered first. Then, get the point where the clipping bool marchBackwardsOnBoundary = (profileNormal * polyNormal) >= 0.0;
// boundary volume was left! These two points with the plane
// normal form another plane that intersects the clipping
// volume. There are two ways to get from the first to the
// second point along the intersection curve, try to pick the
// one that lies within the current polygon.
// TODO this approach doesn't handle all cases // Build closed loops from these intersections. Starting from an intersection leaving the boundary we
// walk along the polygon to the next intersection (which should be an IS entering the boundary poly).
// From there we walk along the boundary until we hit another intersection leaving the boundary,
// walk along the poly to the next IS and so on until we're back at the starting point.
// We remove every intersection we "used up", so any remaining intersection is the start of a new loop.
while( !intersections.empty() )
{
std::vector<IfcVector3> resultpoly;
size_t currentIntersecIdx = 0;
// ... while( true )
{
ai_assert(intersections.size() > currentIntersecIdx + 1);
boost::tuple<size_t, IfcVector3, size_t> currintsec = intersections[currentIntersecIdx + 0];
boost::tuple<size_t, IfcVector3, size_t> nextintsec = intersections[currentIntersecIdx + 1];
intersections.erase(intersections.begin() + currentIntersecIdx, intersections.begin() + currentIntersecIdx + 2);
IfcFloat d = 1e20; // we start with an in->out intersection
IfcVector3 vclosest; resultpoly.push_back(currintsec.get<1>());
BOOST_FOREACH(const IfcVector3& v, intersected_boundary_points) { // climb along the polygon to the next intersection, which should be an out->in
const IfcFloat dn = (v-e1_plane).SquareLength(); size_t numPolyPoints = (currintsec.get<0>() > nextintsec.get<0>() ? blackside.size() : 0)
if (dn < d) { + nextintsec.get<0>() - currintsec.get<0>();
d = dn; for( size_t a = 1; a <= numPolyPoints; ++a )
vclosest = v; resultpoly.push_back(blackside[(currintsec.get<0>() + a) % blackside.size()]);
// put the out->in intersection
resultpoly.push_back(nextintsec.get<1>());
// generate segments along the boundary polygon that lie in the poly's plane until we hit another intersection
IfcVector3 startingPoint = proj * nextintsec.get<1>();
size_t currentBoundaryEdgeIdx = (nextintsec.get<2>() + (marchBackwardsOnBoundary ? 1 : 0)) % profile->verts.size();
size_t nextIntsecIdx = SIZE_MAX;
while( nextIntsecIdx == SIZE_MAX )
{
IfcFloat t = 1e10;
size_t nextBoundaryEdgeIdx = marchBackwardsOnBoundary ? (currentBoundaryEdgeIdx + profile->verts.size() - 1) : currentBoundaryEdgeIdx + 1;
nextBoundaryEdgeIdx %= profile->verts.size();
// vertices of the current boundary segments
IfcVector3 currBoundaryPoint = profile->verts[currentBoundaryEdgeIdx];
IfcVector3 nextBoundaryPoint = profile->verts[nextBoundaryEdgeIdx];
// project the two onto the polygon
if( std::abs(polyNormal.z) > 1e-5 )
{
currBoundaryPoint.z = startingPoint.z + (currBoundaryPoint.x - startingPoint.x) * polyNormal.x/polyNormal.z + (currBoundaryPoint.y - startingPoint.y) * polyNormal.y/polyNormal.z;
nextBoundaryPoint.z = startingPoint.z + (nextBoundaryPoint.x - startingPoint.x) * polyNormal.x/polyNormal.z + (nextBoundaryPoint.y - startingPoint.y) * polyNormal.y/polyNormal.z;
}
// build a direction that goes along the boundary border but lies in the poly plane
IfcVector3 boundaryPlaneNormal = ((nextBoundaryPoint - currBoundaryPoint) ^ profileNormal).Normalize();
IfcVector3 dirAtPolyPlane = (boundaryPlaneNormal ^ polyNormal).Normalize() * (marchBackwardsOnBoundary ? -1.0 : 1.0);
// if we can project the direction to the plane, we can calculate a maximum marching distance along that dir
// until we finish that boundary segment and continue on the next
if( std::abs(polyNormal.z) > 1e-5 )
{
t = std::min(t, (nextBoundaryPoint - startingPoint).Length());
}
// check if the direction hits the loop start - if yes, we got a poly to output
IfcVector3 dirToThatPoint = proj * resultpoly.front() - startingPoint;
IfcFloat tpt = dirToThatPoint * dirAtPolyPlane;
if( tpt > -1e-6 && tpt <= t && (dirToThatPoint - tpt * dirAtPolyPlane).SquareLength() < 1e-10 )
{
nextIntsecIdx = intersections.size(); // dirty hack to end marching along the boundary and signal the end of the loop
t = tpt;
}
// also check if the direction hits any in->out intersections earlier. If we hit one, we can switch back
// to marching along the poly border from that intersection point
for( size_t a = 0; a < intersections.size(); a += 2 )
{
dirToThatPoint = proj * intersections[a].get<1>() - startingPoint;
tpt = dirToThatPoint * dirAtPolyPlane;
if( tpt > -1e-6 && tpt <= t && (dirToThatPoint - tpt * dirAtPolyPlane).SquareLength() < 1e-10 )
{
nextIntsecIdx = a; // switch back to poly and march on from this in->out intersection
t = tpt;
} }
} }
vclosest = proj_inv * vclosest; // if we keep marching on the boundary, put the segment end point to the result poly and well... keep marching
if(entered_volume_flag) { if( nextIntsecIdx == SIZE_MAX )
const IfcVector3& fix_point = vclosest + ((p - vclosest) * n) * n; {
outvert.push_back(fix_point); resultpoly.push_back(proj_inv * nextBoundaryPoint);
++newcount; currentBoundaryEdgeIdx = nextBoundaryEdgeIdx;
startingPoint = nextBoundaryPoint;
entered_volume_flag = false;
} }
outvert.push_back(vclosest); // quick endless loop check
++newcount; if( resultpoly.size() > blackside.size() + profile->verts.size() )
{
//outvert.push_back(e1); IFCImporter::LogError("Encountered endless loop while clipping polygon against poly-bounded half space.");
//++newcount; break;
}
else {
entered_volume_flag = true;
// we just entered the clipping boundary. Record the point
// and the segment where we entered and also generate this point.
//last_intersected_boundary_segment = intersected_boundary_segments.front();
//last_intersected_boundary_point = intersected_boundary_points.front();
outvert.push_back(e0);
++newcount;
IfcFloat d = 1e20;
IfcVector3 vclosest;
BOOST_FOREACH(const IfcVector3& v, intersected_boundary_points) {
const IfcFloat dn = (v-e0_plane).SquareLength();
if (dn < d) {
d = dn;
vclosest = v;
}
} }
enter_volume = proj_inv * vclosest;
outvert.push_back(enter_volume);
++newcount;
} }
}
// if not, we just keep the vertex
else if (is_outside_boundary) {
outvert.push_back(e0);
++newcount;
entered_volume_flag = false; // we're back on the poly - if this is the intersection we started from, we got a closed loop.
if( nextIntsecIdx >= intersections.size() )
{
break;
}
// otherwise it's another intersection. Continue marching from there.
currentIntersecIdx = nextIntsecIdx;
} }
WritePolygon(resultpoly, result);
} }
was_outside_boundary = is_outside_boundary;
extra_point_flag = false;
} }
if (!newcount) {
continue;
}
IfcVector3 vmin,vmax;
ArrayBounds(&*(outvert.end()-newcount),newcount,vmin,vmax);
// filter our IfcFloat points - those may happen if a point lies
// directly on the intersection line. However, due to IfcFloat
// precision a bitwise comparison is not feasible to detect
// this case.
const IfcFloat epsilon = (vmax-vmin).SquareLength() / 1e6f;
FuzzyVectorCompare fz(epsilon);
std::vector<IfcVector3>::iterator e = std::unique( outvert.end()-newcount, outvert.end(), fz );
if (e != outvert.end()) {
newcount -= static_cast<unsigned int>(std::distance(e,outvert.end()));
outvert.erase(e,outvert.end());
}
if (fz(*( outvert.end()-newcount),outvert.back())) {
outvert.pop_back();
--newcount;
}
if(newcount > 2) {
result.vertcnt.push_back(newcount);
}
else while(newcount-->0) {
result.verts.pop_back();
}
} }
IFCImporter::LogDebug("generating CSG geometry by plane clipping with polygonal bounding (IfcBooleanClippingResult)"); IFCImporter::LogDebug("generating CSG geometry by plane clipping with polygonal bounding (IfcBooleanClippingResult)");
} }

View File

@ -579,6 +579,11 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
IfcVector3 min = in[0]; IfcVector3 min = in[0];
dir *= IfcMatrix3(trafo); dir *= IfcMatrix3(trafo);
// reverse profile polygon if it's winded in the wrong direction in relation to the extrusion direction
IfcVector3 profileNormal = TempMesh::ComputePolygonNormal( in.data(), in.size());
if( profileNormal * dir < 0.0 )
std::reverse( in.begin(), in.end());
std::vector<IfcVector3> nors; std::vector<IfcVector3> nors;
const bool openings = !!conv.apply_openings && conv.apply_openings->size(); const bool openings = !!conv.apply_openings && conv.apply_openings->size();
@ -619,9 +624,9 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
curmesh.vertcnt.push_back(4); curmesh.vertcnt.push_back(4);
out.push_back(in[i]); out.push_back(in[i]);
out.push_back(in[i]+dir);
out.push_back(in[next]+dir);
out.push_back(in[next]); out.push_back(in[next]);
out.push_back(in[next]+dir);
out.push_back(in[i]+dir);
if(openings) { if(openings) {
if((in[i]-in[next]).Length() > diag * 0.1 && GenerateOpenings(*conv.apply_openings,nors,temp,true, true, dir)) { if((in[i]-in[next]).Length() > diag * 0.1 && GenerateOpenings(*conv.apply_openings,nors,temp,true, true, dir)) {
@ -646,8 +651,12 @@ void ProcessExtrudedAreaSolid(const IfcExtrudedAreaSolid& solid, TempMesh& resul
if(has_area) { if(has_area) {
for(size_t n = 0; n < 2; ++n) { for(size_t n = 0; n < 2; ++n) {
for(size_t i = size; i--; ) { if( n > 0 ) {
out.push_back(in[i]+(n?dir:IfcVector3())); for(size_t i = 0; i < size; ++i )
out.push_back(in[i]+dir);
} else {
for(size_t i = size; i--; )
out.push_back(in[i]);
} }
curmesh.vertcnt.push_back(size); curmesh.vertcnt.push_back(size);
@ -699,10 +708,10 @@ void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessGeometricItem(const IfcRepresentationItem& geo, std::vector<unsigned int>& mesh_indices, bool ProcessGeometricItem(const IfcRepresentationItem& geo, unsigned int matid, std::vector<unsigned int>& mesh_indices,
ConversionData& conv) ConversionData& conv)
{ {
bool fix_orientation = true; bool fix_orientation = false;
boost::shared_ptr< TempMesh > meshtmp = boost::make_shared<TempMesh>(); boost::shared_ptr< TempMesh > meshtmp = boost::make_shared<TempMesh>();
if(const IfcShellBasedSurfaceModel* shellmod = geo.ToPtr<IfcShellBasedSurfaceModel>()) { if(const IfcShellBasedSurfaceModel* shellmod = geo.ToPtr<IfcShellBasedSurfaceModel>()) {
BOOST_FOREACH(boost::shared_ptr<const IfcShell> shell,shellmod->SbsmBoundary) { BOOST_FOREACH(boost::shared_ptr<const IfcShell> shell,shellmod->SbsmBoundary) {
@ -716,24 +725,27 @@ bool ProcessGeometricItem(const IfcRepresentationItem& geo, std::vector<unsigned
IFCImporter::LogWarn("unexpected type error, IfcShell ought to inherit from IfcConnectedFaceSet"); IFCImporter::LogWarn("unexpected type error, IfcShell ought to inherit from IfcConnectedFaceSet");
} }
} }
fix_orientation = true;
} }
else if(const IfcConnectedFaceSet* fset = geo.ToPtr<IfcConnectedFaceSet>()) { else if(const IfcConnectedFaceSet* fset = geo.ToPtr<IfcConnectedFaceSet>()) {
ProcessConnectedFaceSet(*fset,*meshtmp.get(),conv); ProcessConnectedFaceSet(*fset,*meshtmp.get(),conv);
fix_orientation = true;
} }
else if(const IfcSweptAreaSolid* swept = geo.ToPtr<IfcSweptAreaSolid>()) { else if(const IfcSweptAreaSolid* swept = geo.ToPtr<IfcSweptAreaSolid>()) {
ProcessSweptAreaSolid(*swept,*meshtmp.get(),conv); ProcessSweptAreaSolid(*swept,*meshtmp.get(),conv);
} }
else if(const IfcSweptDiskSolid* disk = geo.ToPtr<IfcSweptDiskSolid>()) { else if(const IfcSweptDiskSolid* disk = geo.ToPtr<IfcSweptDiskSolid>()) {
ProcessSweptDiskSolid(*disk,*meshtmp.get(),conv); ProcessSweptDiskSolid(*disk,*meshtmp.get(),conv);
fix_orientation = false;
} }
else if(const IfcManifoldSolidBrep* brep = geo.ToPtr<IfcManifoldSolidBrep>()) { else if(const IfcManifoldSolidBrep* brep = geo.ToPtr<IfcManifoldSolidBrep>()) {
ProcessConnectedFaceSet(brep->Outer,*meshtmp.get(),conv); ProcessConnectedFaceSet(brep->Outer,*meshtmp.get(),conv);
fix_orientation = true;
} }
else if(const IfcFaceBasedSurfaceModel* surf = geo.ToPtr<IfcFaceBasedSurfaceModel>()) { else if(const IfcFaceBasedSurfaceModel* surf = geo.ToPtr<IfcFaceBasedSurfaceModel>()) {
BOOST_FOREACH(const IfcConnectedFaceSet& fc, surf->FbsmFaces) { BOOST_FOREACH(const IfcConnectedFaceSet& fc, surf->FbsmFaces) {
ProcessConnectedFaceSet(fc,*meshtmp.get(),conv); ProcessConnectedFaceSet(fc,*meshtmp.get(),conv);
} }
fix_orientation = true;
} }
else if(const IfcBooleanResult* boolean = geo.ToPtr<IfcBooleanResult>()) { else if(const IfcBooleanResult* boolean = geo.ToPtr<IfcBooleanResult>()) {
ProcessBoolean(*boolean,*meshtmp.get(),conv); ProcessBoolean(*boolean,*meshtmp.get(),conv);
@ -777,7 +789,7 @@ bool ProcessGeometricItem(const IfcRepresentationItem& geo, std::vector<unsigned
aiMesh* const mesh = meshtmp->ToMesh(); aiMesh* const mesh = meshtmp->ToMesh();
if(mesh) { if(mesh) {
mesh->mMaterialIndex = ProcessMaterials(geo,conv); mesh->mMaterialIndex = matid;
mesh_indices.push_back(conv.meshes.size()); mesh_indices.push_back(conv.meshes.size());
conv.meshes.push_back(mesh); conv.meshes.push_back(mesh);
return true; return true;
@ -807,10 +819,11 @@ void AssignAddedMeshes(std::vector<unsigned int>& mesh_indices,aiNode* nd,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool TryQueryMeshCache(const IfcRepresentationItem& item, bool TryQueryMeshCache(const IfcRepresentationItem& item,
std::vector<unsigned int>& mesh_indices, std::vector<unsigned int>& mesh_indices, unsigned int mat_index,
ConversionData& conv) ConversionData& conv)
{ {
ConversionData::MeshCache::const_iterator it = conv.cached_meshes.find(&item); ConversionData::MeshCacheIndex idx(&item, mat_index);
ConversionData::MeshCache::const_iterator it = conv.cached_meshes.find(idx);
if (it != conv.cached_meshes.end()) { if (it != conv.cached_meshes.end()) {
std::copy((*it).second.begin(),(*it).second.end(),std::back_inserter(mesh_indices)); std::copy((*it).second.begin(),(*it).second.end(),std::back_inserter(mesh_indices));
return true; return true;
@ -820,21 +833,25 @@ bool TryQueryMeshCache(const IfcRepresentationItem& item,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void PopulateMeshCache(const IfcRepresentationItem& item, void PopulateMeshCache(const IfcRepresentationItem& item,
const std::vector<unsigned int>& mesh_indices, const std::vector<unsigned int>& mesh_indices, unsigned int mat_index,
ConversionData& conv) ConversionData& conv)
{ {
conv.cached_meshes[&item] = mesh_indices; ConversionData::MeshCacheIndex idx(&item, mat_index);
conv.cached_meshes[idx] = mesh_indices;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessRepresentationItem(const IfcRepresentationItem& item, bool ProcessRepresentationItem(const IfcRepresentationItem& item, unsigned int matid,
std::vector<unsigned int>& mesh_indices, std::vector<unsigned int>& mesh_indices,
ConversionData& conv) ConversionData& conv)
{ {
if (!TryQueryMeshCache(item,mesh_indices,conv)) { // determine material
if(ProcessGeometricItem(item,mesh_indices,conv)) { unsigned int localmatid = ProcessMaterials(item.GetID(), matid, conv, true);
if (!TryQueryMeshCache(item,mesh_indices,localmatid,conv)) {
if(ProcessGeometricItem(item,localmatid,mesh_indices,conv)) {
if(mesh_indices.size()) { if(mesh_indices.size()) {
PopulateMeshCache(item,mesh_indices,conv); PopulateMeshCache(item,mesh_indices,localmatid,conv);
} }
} }
else return false; else return false;

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
#include <iterator> #include <iterator>
#include <limits>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
#ifndef ASSIMP_BUILD_NO_COMPRESSED_IFC #ifndef ASSIMP_BUILD_NO_COMPRESSED_IFC
@ -428,7 +429,7 @@ void GetAbsTransform(aiMatrix4x4& out, const aiNode* nd, ConversionData& conv)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessMappedItem(const IfcMappedItem& mapped, aiNode* nd_src, std::vector< aiNode* >& subnodes_src, ConversionData& conv) bool ProcessMappedItem(const IfcMappedItem& mapped, aiNode* nd_src, std::vector< aiNode* >& subnodes_src, unsigned int matid, ConversionData& conv)
{ {
// insert a custom node here, the cartesian transform operator is simply a conventional transformation matrix // insert a custom node here, the cartesian transform operator is simply a conventional transformation matrix
std::auto_ptr<aiNode> nd(new aiNode()); std::auto_ptr<aiNode> nd(new aiNode());
@ -453,11 +454,12 @@ bool ProcessMappedItem(const IfcMappedItem& mapped, aiNode* nd_src, std::vector<
} }
} }
unsigned int localmatid = ProcessMaterials(mapped.GetID(),matid,conv,false);
const IfcRepresentation& repr = mapped.MappingSource->MappedRepresentation; const IfcRepresentation& repr = mapped.MappingSource->MappedRepresentation;
bool got = false; bool got = false;
BOOST_FOREACH(const IfcRepresentationItem& item, repr.Items) { BOOST_FOREACH(const IfcRepresentationItem& item, repr.Items) {
if(!ProcessRepresentationItem(item,meshes,conv)) { if(!ProcessRepresentationItem(item,localmatid,meshes,conv)) {
IFCImporter::LogWarn("skipping mapped entity of type " + item.GetClassName() + ", no representations could be generated"); IFCImporter::LogWarn("skipping mapped entity of type " + item.GetClassName() + ", no representations could be generated");
} }
else got = true; else got = true;
@ -557,7 +559,11 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
if(!el.Representation) { if(!el.Representation) {
return; return;
} }
// extract Color from metadata, if present
unsigned int matid = ProcessMaterials( el.GetID(), std::numeric_limits<uint32_t>::max(), conv, false);
std::vector<unsigned int> meshes; std::vector<unsigned int> meshes;
// we want only one representation type, so bring them in a suitable order (i.e try those // we want only one representation type, so bring them in a suitable order (i.e try those
// that look as if we could read them quickly at first). This way of reading // that look as if we could read them quickly at first). This way of reading
// representation is relatively generic and allows the concrete implementations // representation is relatively generic and allows the concrete implementations
@ -571,10 +577,10 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
bool res = false; bool res = false;
BOOST_FOREACH(const IfcRepresentationItem& item, repr->Items) { BOOST_FOREACH(const IfcRepresentationItem& item, repr->Items) {
if(const IfcMappedItem* const geo = item.ToPtr<IfcMappedItem>()) { if(const IfcMappedItem* const geo = item.ToPtr<IfcMappedItem>()) {
res = ProcessMappedItem(*geo,nd,subnodes,conv) || res; res = ProcessMappedItem(*geo,nd,subnodes,matid,conv) || res;
} }
else { else {
res = ProcessRepresentationItem(item,meshes,conv) || res; res = ProcessRepresentationItem(item,matid,meshes,conv) || res;
} }
} }
// if we got something meaningful at this point, skip any further representations // if we got something meaningful at this point, skip any further representations
@ -671,10 +677,11 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
const STEP::DB::RefMap& refs = conv.db.GetRefs(); const STEP::DB::RefMap& refs = conv.db.GetRefs();
// skip over space and annotation nodes - usually, these have no meaning in Assimp's context // skip over space and annotation nodes - usually, these have no meaning in Assimp's context
bool skipGeometry = false;
if(conv.settings.skipSpaceRepresentations) { if(conv.settings.skipSpaceRepresentations) {
if(const IfcSpace* const space = el.ToPtr<IfcSpace>()) { if(const IfcSpace* const space = el.ToPtr<IfcSpace>()) {
IFCImporter::LogDebug("skipping IfcSpace entity due to importer settings"); IFCImporter::LogDebug("skipping IfcSpace entity due to importer settings");
return NULL; skipGeometry = true;
} }
} }
@ -844,8 +851,10 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
conv.apply_openings = &openings; conv.apply_openings = &openings;
} }
ProcessProductRepresentation(el,nd.get(),subnodes,conv); if (!skipGeometry) {
conv.apply_openings = conv.collect_openings = NULL; ProcessProductRepresentation(el,nd.get(),subnodes,conv);
conv.apply_openings = conv.collect_openings = NULL;
}
if (subnodes.size()) { if (subnodes.size()) {
nd->mChildren = new aiNode*[subnodes.size()](); nd->mChildren = new aiNode*[subnodes.size()]();

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
#include "IFCUtil.h" #include "IFCUtil.h"
#include <limits>
namespace Assimp { namespace Assimp {
namespace IFC { namespace IFC {
@ -132,45 +133,70 @@ void FillMaterial(aiMaterial* mat,const IFC::IfcSurfaceStyle* surf,ConversionDat
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ProcessMaterials(const IFC::IfcRepresentationItem& item, ConversionData& conv) unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat)
{ {
if (conv.materials.empty()) { STEP::DB::RefMapRange range = conv.db.GetRefs().equal_range(id);
aiString name;
std::auto_ptr<aiMaterial> mat(new aiMaterial());
name.Set("<IFCDefault>");
mat->AddProperty(&name,AI_MATKEY_NAME);
const aiColor4D col = aiColor4D(0.6f,0.6f,0.6f,1.0f);
mat->AddProperty(&col,1, AI_MATKEY_COLOR_DIFFUSE);
conv.materials.push_back(mat.release());
}
STEP::DB::RefMapRange range = conv.db.GetRefs().equal_range(item.GetID());
for(;range.first != range.second; ++range.first) { for(;range.first != range.second; ++range.first) {
if(const IFC::IfcStyledItem* const styled = conv.db.GetObject((*range.first).second)->ToPtr<IFC::IfcStyledItem>()) { if(const IFC::IfcStyledItem* const styled = conv.db.GetObject((*range.first).second)->ToPtr<IFC::IfcStyledItem>()) {
BOOST_FOREACH(const IFC::IfcPresentationStyleAssignment& as, styled->Styles) { BOOST_FOREACH(const IFC::IfcPresentationStyleAssignment& as, styled->Styles) {
BOOST_FOREACH(boost::shared_ptr<const IFC::IfcPresentationStyleSelect> sel, as.Styles) { BOOST_FOREACH(boost::shared_ptr<const IFC::IfcPresentationStyleSelect> sel, as.Styles) {
if (const IFC::IfcSurfaceStyle* const surf = sel->ResolveSelectPtr<IFC::IfcSurfaceStyle>(conv.db)) { if( const IFC::IfcSurfaceStyle* const surf = sel->ResolveSelectPtr<IFC::IfcSurfaceStyle>(conv.db) ) {
// try to satisfy from cache
ConversionData::MaterialCache::iterator mit = conv.cached_materials.find(surf);
if( mit != conv.cached_materials.end() )
return mit->second;
// not found, create new material
const std::string side = static_cast<std::string>(surf->Side); const std::string side = static_cast<std::string>(surf->Side);
if (side != "BOTH") { if( side != "BOTH" ) {
IFCImporter::LogWarn("ignoring surface side marker on IFC::IfcSurfaceStyle: " + side); IFCImporter::LogWarn("ignoring surface side marker on IFC::IfcSurfaceStyle: " + side);
} }
std::auto_ptr<aiMaterial> mat(new aiMaterial()); std::auto_ptr<aiMaterial> mat(new aiMaterial());
FillMaterial(mat.get(),surf,conv); FillMaterial(mat.get(), surf, conv);
conv.materials.push_back(mat.release()); conv.materials.push_back(mat.release());
return conv.materials.size()-1; unsigned int matindex = conv.materials.size() - 1;
} conv.cached_materials[surf] = matindex;
} return matindex;
} }
} }
} }
return 0; }
}
// no local material defined. If there's global one, use that instead
if( prevMatId != std::numeric_limits<uint32_t>::max() )
return prevMatId;
// we're still here - create an default material if required, or simply fail otherwise
if( !forceDefaultMat )
return std::numeric_limits<uint32_t>::max();
aiString name;
name.Set("<IFCDefault>");
// ConvertColorToString( color, name);
// look if there's already a default material with this base color
for( size_t a = 0; a < conv.materials.size(); ++a )
{
aiString mname;
conv.materials[a]->Get(AI_MATKEY_NAME, mname);
if( name == mname )
return (unsigned int)a;
}
// we're here, yet - no default material with suitable color available. Generate one
std::auto_ptr<aiMaterial> mat(new aiMaterial());
mat->AddProperty(&name,AI_MATKEY_NAME);
const aiColor4D col = aiColor4D( 0.6f, 0.6f, 0.6f, 1.0f); // aiColor4D( color.r, color.g, color.b, 1.0f);
mat->AddProperty(&col,1, AI_MATKEY_COLOR_DIFFUSE);
conv.materials.push_back(mat.release());
return (unsigned int) conv.materials.size() - 1;
} }
} // ! IFC } // ! IFC

View File

@ -902,6 +902,14 @@ size_t CloseWindows(ContourVector& contours,
curmesh.verts.reserve(curmesh.verts.size() + (*it).contour.size() * 4); curmesh.verts.reserve(curmesh.verts.size() + (*it).contour.size() * 4);
curmesh.vertcnt.reserve(curmesh.vertcnt.size() + (*it).contour.size()); curmesh.vertcnt.reserve(curmesh.vertcnt.size() + (*it).contour.size());
// compare base poly normal and contour normal to detect if we need to reverse the face winding
IfcVector3 basePolyNormal = TempMesh::ComputePolygonNormal( curmesh.verts.data(), curmesh.vertcnt.front());
std::vector<IfcVector3> worldSpaceContourVtx( it->contour.size());
for( size_t a = 0; a < it->contour.size(); ++a )
worldSpaceContourVtx[a] = minv * IfcVector3( it->contour[a].x, it->contour[a].y, 0.0);
IfcVector3 contourNormal = TempMesh::ComputePolygonNormal( worldSpaceContourVtx.data(), worldSpaceContourVtx.size());
bool reverseCountourFaces = (contourNormal * basePolyNormal) > 0.0;
// XXX this algorithm is really a bit inefficient - both in terms // XXX this algorithm is really a bit inefficient - both in terms
// of constant factor and of asymptotic runtime. // of constant factor and of asymptotic runtime.
std::vector<bool>::const_iterator skipit = skipbegin; std::vector<bool>::const_iterator skipit = skipbegin;
@ -909,9 +917,6 @@ size_t CloseWindows(ContourVector& contours,
IfcVector3 start0; IfcVector3 start0;
IfcVector3 start1; IfcVector3 start1;
IfcVector2 last_proj;
//const IfcVector2& first_proj;
const Contour::const_iterator cbegin = (*it).contour.begin(), cend = (*it).contour.end(); const Contour::const_iterator cbegin = (*it).contour.begin(), cend = (*it).contour.end();
bool drop_this_edge = false; bool drop_this_edge = false;
@ -923,18 +928,8 @@ size_t CloseWindows(ContourVector& contours,
IfcFloat best = static_cast<IfcFloat>(1e10); IfcFloat best = static_cast<IfcFloat>(1e10);
IfcVector3 bestv; IfcVector3 bestv;
/* debug code to check for unwanted diagonal lines in window contours
if (cit != cbegin) {
const IfcVector2& vdelta = proj_point - last_proj;
if (std::fabs(vdelta.x-vdelta.y) < 0.5 * std::max(vdelta.x, vdelta.y)) {
//continue;
}
} */
const IfcVector3& world_point = minv * IfcVector3(proj_point.x,proj_point.y,0.0f); const IfcVector3& world_point = minv * IfcVector3(proj_point.x,proj_point.y,0.0f);
last_proj = proj_point;
BOOST_FOREACH(const TempOpening* opening, refs) { BOOST_FOREACH(const TempOpening* opening, refs) {
BOOST_FOREACH(const IfcVector3& other, opening->wallPoints) { BOOST_FOREACH(const IfcVector3& other, opening->wallPoints) {
const IfcFloat sqdist = (world_point - other).SquareLength(); const IfcFloat sqdist = (world_point - other).SquareLength();
@ -956,8 +951,8 @@ size_t CloseWindows(ContourVector& contours,
curmesh.verts.pop_back(); curmesh.verts.pop_back();
} }
else { else {
curmesh.verts.push_back(cit == cbegin ? world_point : bestv); curmesh.verts.push_back(((cit == cbegin) != reverseCountourFaces) ? world_point : bestv);
curmesh.verts.push_back(cit == cbegin ? bestv : world_point); curmesh.verts.push_back(((cit == cbegin) != reverseCountourFaces) ? bestv : world_point);
curmesh.vertcnt.push_back(4); curmesh.vertcnt.push_back(4);
++closed; ++closed;
@ -969,8 +964,8 @@ size_t CloseWindows(ContourVector& contours,
continue; continue;
} }
curmesh.verts.push_back(world_point); curmesh.verts.push_back(reverseCountourFaces ? bestv : world_point);
curmesh.verts.push_back(bestv); curmesh.verts.push_back(reverseCountourFaces ? world_point : bestv);
if (cit == cend - 1) { if (cit == cend - 1) {
drop_this_edge = *skipit; drop_this_edge = *skipit;
@ -984,16 +979,11 @@ size_t CloseWindows(ContourVector& contours,
curmesh.verts.pop_back(); curmesh.verts.pop_back();
} }
else { else {
curmesh.verts.push_back(start1); curmesh.verts.push_back(reverseCountourFaces ? start0 : start1);
curmesh.verts.push_back(start0); curmesh.verts.push_back(reverseCountourFaces ? start1 : start0);
} }
} }
} }
/*
BOOST_FOREACH(TempOpening* opening, refs) {
//opening->wallPoints.clear();
}*/
} }
else { else {
@ -1194,16 +1184,13 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
profile_data = opening.profileMesh2D.get(); profile_data = opening.profileMesh2D.get();
is_2d_source = true; is_2d_source = true;
} }
else {
//continue;
}
} }
else { else {
// vertical extrusion // vertical extrusion
if (std::fabs(norm_extrusion_dir * nor) > 0.9) { if (std::fabs(norm_extrusion_dir * nor) > 0.9) {
continue; profile_data = opening.profileMesh2D.get();
} is_2d_source = true;
continue; }
} }
} }
std::vector<IfcVector3> profile_verts = profile_data->verts; std::vector<IfcVector3> profile_verts = profile_data->verts;

View File

@ -149,7 +149,7 @@ void TempMesh::RemoveDegenerates()
for (std::vector<unsigned int>::iterator it = vertcnt.begin(); it != vertcnt.end(); ++inor) { for (std::vector<unsigned int>::iterator it = vertcnt.begin(); it != vertcnt.end(); ++inor) {
const unsigned int pcount = *it; const unsigned int pcount = *it;
if (normals[inor].SquareLength() < 1e-5f) { if (normals[inor].SquareLength() < 1e-10f) {
it = vertcnt.erase(it); it = vertcnt.erase(it);
vit = verts.erase(vit, vit + pcount); vit = verts.erase(vit, vit + pcount);
@ -166,6 +166,23 @@ void TempMesh::RemoveDegenerates()
} }
} }
// ------------------------------------------------------------------------------------------------
IfcVector3 TempMesh::ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize)
{
std::vector<IfcFloat> temp((cnt+2)*3);
for( size_t vofs = 0, i = 0; vofs < cnt; ++vofs )
{
const IfcVector3& v = vtcs[vofs];
temp[i++] = v.x;
temp[i++] = v.y;
temp[i++] = v.z;
}
IfcVector3 nor;
NewellNormal<3, 3, 3>(nor, cnt, &temp[0], &temp[1], &temp[2]);
return normalize ? nor.Normalize() : nor;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals, void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
bool normalize, bool normalize,
@ -214,37 +231,148 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
// Compute the normal of the last polygon in the given mesh // Compute the normal of the last polygon in the given mesh
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
{ {
size_t total = vertcnt.back(), vidx = verts.size() - total; return ComputePolygonNormal(&verts[verts.size() - vertcnt.back()], vertcnt.back(), normalize);
std::vector<IfcFloat> temp((total+2)*3);
for(size_t vofs = 0, cnt = 0; vofs < total; ++vofs) {
const IfcVector3& v = verts[vidx+vofs];
temp[cnt++] = v.x;
temp[cnt++] = v.y;
temp[cnt++] = v.z;
}
IfcVector3 nor;
NewellNormal<3,3,3>(nor,total,&temp[0],&temp[1],&temp[2]);
return normalize ? nor.Normalize() : nor;
} }
struct CompareVector
{
bool operator () (const IfcVector3& a, const IfcVector3& b) const
{
IfcVector3 d = a - b;
IfcFloat eps = 1e-6;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
}
};
struct FindVector
{
IfcVector3 v;
FindVector(const IfcVector3& p) : v(p) { }
bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); }
};
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TempMesh::FixupFaceOrientation() void TempMesh::FixupFaceOrientation()
{ {
const IfcVector3 vavg = Center(); const IfcVector3 vavg = Center();
std::vector<IfcVector3> normals; // create a list of start indices for all faces to allow random access to faces
ComputePolygonNormals(normals); std::vector<size_t> faceStartIndices(vertcnt.size());
for( size_t i = 0, a = 0; a < vertcnt.size(); i += vertcnt[a], ++a )
faceStartIndices[a] = i;
size_t c = 0, ofs = 0; // list all faces on a vertex
BOOST_FOREACH(unsigned int cnt, vertcnt) { std::map<IfcVector3, std::vector<size_t>, CompareVector> facesByVertex;
if (cnt>2){ for( size_t a = 0; a < vertcnt.size(); ++a )
const IfcVector3& thisvert = verts[c]; {
if (normals[ofs]*(thisvert-vavg) < 0) { for( size_t b = 0; b < vertcnt[a]; ++b )
std::reverse(verts.begin()+c,verts.begin()+cnt+c); facesByVertex[verts[faceStartIndices[a] + b]].push_back(a);
}
// determine neighbourhood for all polys
std::vector<size_t> neighbour(verts.size(), SIZE_MAX);
std::vector<size_t> tempIntersect(10);
for( size_t a = 0; a < vertcnt.size(); ++a )
{
for( size_t b = 0; b < vertcnt[a]; ++b )
{
size_t ib = faceStartIndices[a] + b, nib = faceStartIndices[a] + (b + 1) % vertcnt[a];
const std::vector<size_t>& facesOnB = facesByVertex[verts[ib]];
const std::vector<size_t>& facesOnNB = facesByVertex[verts[nib]];
// there should be exactly one or two faces which appear in both lists. Our face and the other side
std::vector<size_t>::iterator sectstart = tempIntersect.begin();
std::vector<size_t>::iterator sectend = std::set_intersection(
facesOnB.begin(), facesOnB.end(), facesOnNB.begin(), facesOnNB.end(), sectstart);
if( std::distance(sectstart, sectend) != 2 )
continue;
if( *sectstart == a )
++sectstart;
neighbour[ib] = *sectstart;
}
}
// now we're getting started. We take the face which is the farthest away from the center. This face is most probably
// facing outwards. So we reverse this face to point outwards in relation to the center. Then we adapt neighbouring
// faces to have the same winding until all faces have been tested.
std::vector<bool> faceDone(vertcnt.size(), false);
while( std::count(faceDone.begin(), faceDone.end(), false) != 0 )
{
// find the farthest of the remaining faces
size_t farthestIndex = SIZE_MAX;
IfcFloat farthestDistance = -1.0;
for( size_t a = 0; a < vertcnt.size(); ++a )
{
if( faceDone[a] )
continue;
IfcVector3 faceCenter = std::accumulate(verts.begin() + faceStartIndices[a],
verts.begin() + faceStartIndices[a] + vertcnt[a], IfcVector3(0.0)) / IfcFloat(vertcnt[a]);
IfcFloat dst = (faceCenter - vavg).SquareLength();
if( dst > farthestDistance ) { farthestDistance = dst; farthestIndex = a; }
}
// calculate its normal and reverse the poly if its facing towards the mesh center
IfcVector3 farthestNormal = ComputePolygonNormal(verts.data() + faceStartIndices[farthestIndex], vertcnt[farthestIndex]);
IfcVector3 farthestCenter = std::accumulate(verts.begin() + faceStartIndices[farthestIndex],
verts.begin() + faceStartIndices[farthestIndex] + vertcnt[farthestIndex], IfcVector3(0.0))
/ IfcFloat(vertcnt[farthestIndex]);
// We accapt a bit of negative orientation without reversing. In case of doubt, prefer the orientation given in
// the file.
if( (farthestNormal * (farthestCenter - vavg).Normalize()) < -0.4 )
{
size_t fsi = faceStartIndices[farthestIndex], fvc = vertcnt[farthestIndex];
std::reverse(verts.begin() + fsi, verts.begin() + fsi + fvc);
std::reverse(neighbour.begin() + fsi, neighbour.begin() + fsi + fvc);
// because of the neighbour index belonging to the edge starting with the point at the same index, we need to
// cycle the neighbours through to match the edges again.
// Before: points A - B - C - D with edge neighbour p - q - r - s
// After: points D - C - B - A, reversed neighbours are s - r - q - p, but the should be
// r q p s
for( size_t a = 0; a < fvc - 1; ++a )
std::swap(neighbour[fsi + a], neighbour[fsi + a + 1]);
}
faceDone[farthestIndex] = true;
std::vector<size_t> todo;
todo.push_back(farthestIndex);
// go over its neighbour faces recursively and adapt their winding order to match the farthest face
while( !todo.empty() )
{
size_t tdf = todo.back();
size_t vsi = faceStartIndices[tdf], vc = vertcnt[tdf];
todo.pop_back();
// check its neighbours
for( size_t a = 0; a < vc; ++a )
{
// ignore neighbours if we already checked them
size_t nbi = neighbour[vsi + a];
if( nbi == SIZE_MAX || faceDone[nbi] )
continue;
const IfcVector3& vp = verts[vsi + a];
size_t nbvsi = faceStartIndices[nbi], nbvc = vertcnt[nbi];
std::vector<IfcVector3>::iterator it = std::find_if(verts.begin() + nbvsi, verts.begin() + nbvsi + nbvc, FindVector(vp));
ai_assert(it != verts.begin() + nbvsi + nbvc);
size_t nb_vidx = std::distance(verts.begin() + nbvsi, it);
// two faces winded in the same direction should have a crossed edge, where one face has p0->p1 and the other
// has p1'->p0'. If the next point on the neighbouring face is also the next on the current face, we need
// to reverse the neighbour
nb_vidx = (nb_vidx + 1) % nbvc;
size_t oursideidx = (a + 1) % vc;
if( FuzzyVectorCompare(1e-6)(verts[vsi + oursideidx], verts[nbvsi + nb_vidx]) )
{
std::reverse(verts.begin() + nbvsi, verts.begin() + nbvsi + nbvc);
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
for( size_t a = 0; a < nbvc - 1; ++a )
std::swap(neighbour[nbvsi + a], neighbour[nbvsi + a + 1]);
}
// either way we're done with the neighbour. Mark it as done and continue checking from there recursively
faceDone[nbi] = true;
todo.push_back(nbi);
} }
} }
c += cnt;
++ofs; // no more faces reachable from this part of the surface, start over with a disjunct part and its farthest face
} }
} }

View File

@ -97,10 +97,10 @@ struct TempMesh
void RemoveDegenerates(); void RemoveDegenerates();
void FixupFaceOrientation(); void FixupFaceOrientation();
static IfcVector3 ComputePolygonNormal(const IfcVector3* vtcs, size_t cnt, bool normalize = true);
IfcVector3 ComputeLastPolygonNormal(bool normalize = true) const; IfcVector3 ComputeLastPolygonNormal(bool normalize = true) const;
void ComputePolygonNormals(std::vector<IfcVector3>& normals, void ComputePolygonNormals(std::vector<IfcVector3>& normals, bool normalize = true, size_t ofs = 0) const;
bool normalize = true,
size_t ofs = 0) const;
void Swap(TempMesh& other); void Swap(TempMesh& other);
}; };
@ -195,9 +195,19 @@ struct ConversionData
std::vector<aiMesh*> meshes; std::vector<aiMesh*> meshes;
std::vector<aiMaterial*> materials; std::vector<aiMaterial*> materials;
typedef std::map<const IFC::IfcRepresentationItem*, std::vector<unsigned int> > MeshCache; struct MeshCacheIndex {
const IFC::IfcRepresentationItem* item; unsigned int matindex;
MeshCacheIndex() : item(NULL), matindex(0) { }
MeshCacheIndex(const IFC::IfcRepresentationItem* i, unsigned int mi) : item(i), matindex(mi) { }
bool operator == (const MeshCacheIndex& o) const { return item == o.item && matindex == o.matindex; }
bool operator < (const MeshCacheIndex& o) const { return item < o.item || (item == o.item && matindex < o.matindex); }
};
typedef std::map<MeshCacheIndex, std::vector<unsigned int> > MeshCache;
MeshCache cached_meshes; MeshCache cached_meshes;
typedef std::map<const IFC::IfcSurfaceStyle*, unsigned int> MaterialCache;
MaterialCache cached_materials;
const IFCImporter::Settings& settings; const IFCImporter::Settings& settings;
// Intermediate arrays used to resolve openings in walls: only one of them // Intermediate arrays used to resolve openings in walls: only one of them
@ -220,7 +230,7 @@ struct FuzzyVectorCompare {
FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {} FuzzyVectorCompare(IfcFloat epsilon) : epsilon(epsilon) {}
bool operator()(const IfcVector3& a, const IfcVector3& b) { bool operator()(const IfcVector3& a, const IfcVector3& b) {
return std::fabs((a-b).SquareLength()) < epsilon; return std::abs((a-b).SquareLength()) < epsilon;
} }
const IfcFloat epsilon; const IfcFloat epsilon;
@ -263,11 +273,11 @@ IfcFloat ConvertSIPrefix(const std::string& prefix);
bool ProcessProfile(const IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv); bool ProcessProfile(const IfcProfileDef& prof, TempMesh& meshout, ConversionData& conv);
// IFCMaterial.cpp // IFCMaterial.cpp
unsigned int ProcessMaterials(const IFC::IfcRepresentationItem& item, ConversionData& conv); unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat);
// IFCGeometry.cpp // IFCGeometry.cpp
IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut); IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVector3& norOut);
bool ProcessRepresentationItem(const IfcRepresentationItem& item, std::vector<unsigned int>& mesh_indices, ConversionData& conv); bool ProcessRepresentationItem(const IfcRepresentationItem& item, unsigned int matid, std::vector<unsigned int>& mesh_indices, ConversionData& conv);
void AssignAddedMeshes(std::vector<unsigned int>& mesh_indices,aiNode* nd,ConversionData& /*conv*/); void AssignAddedMeshes(std::vector<unsigned int>& mesh_indices,aiNode* nd,ConversionData& /*conv*/);
void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout, void ProcessSweptAreaSolid(const IfcSweptAreaSolid& swept, TempMesh& meshout,

View File

@ -170,6 +170,10 @@ corresponding preprocessor flag to selectively disable formats.
# include "AssbinLoader.h" # include "AssbinLoader.h"
#endif #endif
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
# include "C4DImporter.h"
#endif
namespace Assimp { namespace Assimp {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -297,6 +301,10 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER ) #if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER )
out.push_back( new AssbinImporter() ); out.push_back( new AssbinImporter() );
#endif #endif
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
out.push_back( new C4DImporter() );
#endif
} }
} }

View File

@ -303,7 +303,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh
ivdx = -1; ivdx = -1;
int max_priority = -1; int max_priority = -1;
for (unsigned int* piCur = piCandidates;piCur != piCurCandidate;++piCur) { for (unsigned int* piCur = piCandidates;piCur != piCurCandidate;++piCur) {
register const unsigned int dp = *piCur; const unsigned int dp = *piCur;
// must have live triangles // must have live triangles
if (piNumTriPtr[dp] > 0) { if (piNumTriPtr[dp] > 0) {

View File

@ -346,7 +346,7 @@ struct VColorChannel : public VMapEntry
if (!rawData.empty()) if (!rawData.empty())
return; // return if already allocated return; // return if already allocated
register unsigned int m = num*dims; unsigned int m = num*dims;
rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs
rawData.resize(m); rawData.resize(m);

View File

@ -344,7 +344,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
// copy all vertices // copy all vertices
for (unsigned int q = 0; q < face.mNumIndices;++q,++vert) { for (unsigned int q = 0; q < face.mNumIndices;++q,++vert) {
register unsigned int idx = face.mIndices[q]; unsigned int idx = face.mIndices[q];
*pv++ = layer.mTempPoints[idx] /*- layer.mPivot*/; *pv++ = layer.mTempPoints[idx] /*- layer.mPivot*/;
// process UV coordinates // process UV coordinates
@ -491,7 +491,7 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>&
aiFace& face = *begin; aiFace& face = *begin;
for (unsigned int i = 0; i < face.mNumIndices;++i) for (unsigned int i = 0; i < face.mNumIndices;++i)
{ {
register unsigned int tt = face.mIndices[i]; unsigned int tt = face.mIndices[i];
sSort.Add(mesh->mVertices[tt],tt,*it); sSort.Add(mesh->mVertices[tt],tt,*it);
} }
} }
@ -510,7 +510,7 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>&
unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices; unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
for (; beginIdx != endIdx; ++beginIdx) for (; beginIdx != endIdx; ++beginIdx)
{ {
register unsigned int idx = *beginIdx; unsigned int idx = *beginIdx;
sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true); sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
std::vector<unsigned int>::const_iterator a, end = poResult.end(); std::vector<unsigned int>::const_iterator a, end = poResult.end();
@ -533,7 +533,7 @@ void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>&
unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices; unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
for (; beginIdx != endIdx; ++beginIdx) for (; beginIdx != endIdx; ++beginIdx)
{ {
register unsigned int idx = *beginIdx; unsigned int idx = *beginIdx;
if (vertexDone[idx]) if (vertexDone[idx])
continue; continue;
sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true); sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
@ -735,7 +735,7 @@ void LWOImporter::LoadLWOPoints(unsigned int length)
{ {
throw DeadlyImportError( "LWO2: Points chunk length is not multiple of vertexLen (12)"); throw DeadlyImportError( "LWO2: Points chunk length is not multiple of vertexLen (12)");
} }
register unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12; unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
if (mIsLWO2) if (mIsLWO2)
{ {
mCurLayer->mTempPoints.reserve ( regularSize + (regularSize>>2u) ); mCurLayer->mTempPoints.reserve ( regularSize + (regularSize>>2u) );

View File

@ -377,7 +377,7 @@ void MD2Importer::InternReadFile( const std::string& pFile,
for (unsigned int c = 0; c < 3;++c,++iCurrent) { for (unsigned int c = 0; c < 3;++c,++iCurrent) {
// validate vertex indices // validate vertex indices
register unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c]; unsigned int iIndex = (unsigned int)pcTriangles[i].vertexIndices[c];
if (iIndex >= m_pcHeader->numVertices) { if (iIndex >= m_pcHeader->numVertices) {
DefaultLogger::get()->error("MD2: Vertex index is outside the allowed range"); DefaultLogger::get()->error("MD2: Vertex index is outside the allowed range");
iIndex = m_pcHeader->numVertices-1; iIndex = m_pcHeader->numVertices-1;

View File

@ -88,7 +88,7 @@ MD5Parser::MD5Parser(char* _buffer, unsigned int _fileSize )
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Report error to the log stream // Report error to the log stream
/*static*/ void MD5Parser::ReportError (const char* error, unsigned int line) /*static*/ AI_WONT_RETURN void MD5Parser::ReportError (const char* error, unsigned int line)
{ {
char szBuffer[1024]; char szBuffer[1024];
::sprintf(szBuffer,"[MD5] Line %i: %s",line,error); ::sprintf(szBuffer,"[MD5] Line %i: %s",line,error);

View File

@ -367,7 +367,7 @@ public:
* @param error Error message to be reported * @param error Error message to be reported
* @param line Index of the line where the error occured * @param line Index of the line where the error occured
*/ */
static void ReportError (const char* error, unsigned int line); AI_WONT_RETURN static void ReportError (const char* error, unsigned int line) AI_WONT_RETURN_SUFFIX;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Report a specific warning /** Report a specific warning

View File

@ -400,7 +400,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
if (TokenMatch(sz,"0x",2)) if (TokenMatch(sz,"0x",2))
{ {
hasColor = true; hasColor = true;
register unsigned int numIdx = ::strtoul16(sz,&sz); unsigned int numIdx = ::strtoul16(sz,&sz);
aiColor4D clr; aiColor4D clr;
clr.a = 1.f; clr.a = 1.f;

View File

@ -54,7 +54,8 @@ namespace Assimp
namespace Ogre namespace Ogre
{ {
void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error)
{ {
if (!error.empty()) if (!error.empty())
{ {

View File

@ -170,7 +170,7 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode)
// Find meshes to merge with us // Find meshes to merge with us
for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) { for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) {
register unsigned int am = pNode->mMeshes[a]; unsigned int am = pNode->mMeshes[a];
if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) { if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) {
merge_list.push_back(mScene->mMeshes[am]); merge_list.push_back(mScene->mMeshes[am]);

View File

@ -201,7 +201,12 @@ template <class char_t>
AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len) AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len)
{ {
if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) { if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) {
in += len+1; if (in[len] != '\0') {
in += len+1;
} else {
// If EOF after the token make sure we don't go past end of buffer
in += len;
}
return true; return true;
} }

View File

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

View File

@ -794,7 +794,7 @@ bool PLY::PropertyInstance::ParseValue(
{ {
ai_assert(NULL != pCur && NULL != pCurOut && NULL != out); ai_assert(NULL != pCur && NULL != pCurOut && NULL != out);
register bool ret = true; bool ret = true;
*pCurOut = pCur; *pCurOut = pCur;
switch (eType) switch (eType)
{ {
@ -841,7 +841,7 @@ bool PLY::PropertyInstance::ParseValueBinary(
{ {
ai_assert(NULL != pCur && NULL != pCurOut && NULL != out); ai_assert(NULL != pCur && NULL != pCurOut && NULL != out);
register bool ret = true; bool ret = true;
switch (eType) switch (eType)
{ {
case EDT_UInt: case EDT_UInt:

View File

@ -314,7 +314,7 @@ void Q3DImporter::InternReadFile( const std::string& pFile,
if (!tex->mWidth || !tex->mHeight) if (!tex->mWidth || !tex->mHeight)
throw DeadlyImportError("Quick3D: Invalid texture. Width or height is zero"); throw DeadlyImportError("Quick3D: Invalid texture. Width or height is zero");
register unsigned int mul = tex->mWidth * tex->mHeight; unsigned int mul = tex->mWidth * tex->mHeight;
aiTexel* begin = tex->pcData = new aiTexel[mul]; aiTexel* begin = tex->pcData = new aiTexel[mul];
aiTexel* const end = & begin [mul]; aiTexel* const end = & begin [mul];

View File

@ -84,7 +84,7 @@ inline void ArrayDelete(T**& in, unsigned int& num)
// "don't remove" flag not set. Nodes with meshes are never deleted. // "don't remove" flag not set. Nodes with meshes are never deleted.
bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root) bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root)
{ {
register bool b = false; bool b = false;
std::list<aiNode*> mine; std::list<aiNode*> mine;
for (unsigned int i = 0; i < node->mNumChildren;++i) for (unsigned int i = 0; i < node->mNumChildren;++i)
@ -271,7 +271,7 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh)
} }
// handle texture coordinates // handle texture coordinates
register bool b = (0 != (configDeleteFlags & aiComponent_TEXCOORDS)); bool b = (0 != (configDeleteFlags & aiComponent_TEXCOORDS));
for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++real) for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++real)
{ {
if (!pMesh->mTextureCoords[i])break; if (!pMesh->mTextureCoords[i])break;

View File

@ -106,7 +106,7 @@ void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
std::vector<unsigned int> poResult; std::vector<unsigned int> poResult;
for (unsigned int c = 0; c < 3;++c) for (unsigned int c = 0; c < 3;++c)
{ {
register unsigned int idx = (*i).mIndices[c]; unsigned int idx = (*i).mIndices[c];
if (vertexDone[idx])continue; if (vertexDone[idx])continue;
sSort.FindPositions(sMesh.mPositions[idx],(*i).iSmoothGroup, sSort.FindPositions(sMesh.mPositions[idx],(*i).iSmoothGroup,

View File

@ -289,7 +289,7 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
for (unsigned int q = 0; q < in.mNumIndices; ++q) for (unsigned int q = 0; q < in.mNumIndices; ++q)
{ {
register unsigned int idx = in.mIndices[q]; unsigned int idx = in.mIndices[q];
// process all bones of this index // process all bones of this index
if (avw) if (avw)

View File

@ -137,7 +137,7 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2)
return ::strcasecmp(s1,s2); return ::strcasecmp(s1,s2);
#else #else
register char c1, c2; char c1, c2;
do { do {
c1 = tolower(*s1++); c1 = tolower(*s1++);
c2 = tolower(*s2++); c2 = tolower(*s2++);
@ -156,7 +156,7 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2)
*/ */
inline int ASSIMP_stricmp(const std::string& a, const std::string& b) inline int ASSIMP_stricmp(const std::string& a, const std::string& b)
{ {
register int i = (int)b.length()-(int)a.length(); int i = (int)b.length()-(int)a.length();
return (i ? i : ASSIMP_stricmp(a.c_str(),b.c_str())); return (i ? i : ASSIMP_stricmp(a.c_str(),b.c_str()));
} }
@ -186,7 +186,7 @@ inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n)
return ::strncasecmp(s1,s2, n); return ::strncasecmp(s1,s2, n);
#else #else
register char c1, c2; char c1, c2;
unsigned int p = 0; unsigned int p = 0;
do do
{ {

View File

@ -290,6 +290,8 @@ void CatmullClarkSubdivider::InternSubdivide (
} }
} }
{
// we want edges to go away before the recursive calls so begin a new scope
EdgeMap edges; EdgeMap edges;
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -572,6 +574,7 @@ void CatmullClarkSubdivider::InternSubdivide (
} }
} }
} }
} // end of scope for edges, freeing its memory
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// 7. Apply the next subdivision step. // 7. Apply the next subdivision step.

View File

@ -225,7 +225,7 @@ void TerragenImporter::InternReadFile( const std::string& pFile,
// make verts // make verts
const float fy = (float)yy, fx = (float)xx; const float fy = (float)yy, fx = (float)xx;
register unsigned tmp,tmp2; unsigned tmp,tmp2;
*pv++ = aiVector3D(fx,fy, (float)data[(tmp2=x*yy) + xx] * hscale + bheight); *pv++ = aiVector3D(fx,fy, (float)data[(tmp2=x*yy) + xx] * hscale + bheight);
*pv++ = aiVector3D(fx,fy+1, (float)data[(tmp=x*(yy+1)) + xx] * hscale + bheight); *pv++ = aiVector3D(fx,fy+1, (float)data[(tmp=x*(yy+1)) + xx] * hscale + bheight);
*pv++ = aiVector3D(fx+1,fy+1,(float)data[tmp + xx+1] * hscale + bheight); *pv++ = aiVector3D(fx+1,fy+1,(float)data[tmp + xx+1] * hscale + bheight);

View File

@ -120,7 +120,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
* offset 2 and 3) * offset 2 and 3)
*/ */
if ((rounded = (int)info.mTranslation.x)) { if ((rounded = (int)info.mTranslation.x)) {
float out; float out = 0.0f;
szTemp[0] = 0; szTemp[0] = 0;
if (aiTextureMapMode_Wrap == info.mapU) { if (aiTextureMapMode_Wrap == info.mapU) {
// Wrap - simple take the fraction of the field // Wrap - simple take the fraction of the field
@ -153,7 +153,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
* offset 2 and 3) * offset 2 and 3)
*/ */
if ((rounded = (int)info.mTranslation.y)) { if ((rounded = (int)info.mTranslation.y)) {
float out; float out = 0.0f;
szTemp[0] = 0; szTemp[0] = 0;
if (aiTextureMapMode_Wrap == info.mapV) { if (aiTextureMapMode_Wrap == info.mapV) {
// Wrap - simple take the fraction of the field // Wrap - simple take the fraction of the field

View File

@ -1432,7 +1432,7 @@ aiColor3D XFileParser::ReadRGB()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Throws an exception with a line number and the given text. // Throws an exception with a line number and the given text.
void XFileParser::ThrowException( const std::string& pText) AI_WONT_RETURN void XFileParser::ThrowException( const std::string& pText)
{ {
if( mIsBinaryFormat) if( mIsBinaryFormat)
throw DeadlyImportError( pText); throw DeadlyImportError( pText);

View File

@ -134,7 +134,7 @@ protected:
aiColor4D ReadRGBA(); aiColor4D ReadRGBA();
/** Throws an exception with a line number and the given text. */ /** Throws an exception with a line number and the given text. */
void ThrowException( const std::string& pText); AI_WONT_RETURN void ThrowException( const std::string& pText) AI_WONT_RETURN_SUFFIX;
/** Filters the imported hierarchy for some degenerated cases that some exporters produce. /** Filters the imported hierarchy for some degenerated cases that some exporters produce.
* @param pData The sub-hierarchy to filter * @param pData The sub-hierarchy to filter

View File

@ -102,7 +102,7 @@ public:
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
//! Virtual destructor //! Virtual destructor
virtual ~CIrrXML_IOStreamReader() {}; virtual ~CIrrXML_IOStreamReader() {}
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
//! Reads an amount of bytes from the file. //! Reads an amount of bytes from the file.

View File

@ -37,7 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file DefaultLogger.h /** @file DefaultLogger.hpp
*/ */
#ifndef INCLUDED_AI_DEFAULTLOGGER #ifndef INCLUDED_AI_DEFAULTLOGGER

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file export.hpp /** @file Exporter.hpp
* @brief Defines the CPP-API for the Assimp export interface * @brief Defines the CPP-API for the Assimp export interface
*/ */
#ifndef AI_EXPORT_HPP_INC #ifndef AI_EXPORT_HPP_INC
@ -181,7 +181,7 @@ public:
* about the output data flow of the export process. * about the output data flow of the export process.
* @param pBlob A data blob obtained from a previous call to #aiExportScene. Must not be NULL. * @param pBlob A data blob obtained from a previous call to #aiExportScene. Must not be NULL.
* @param pPath Full target file name. Target must be accessible. * @param pPath Full target file name. Target must be accessible.
* @param pPreprocessing Accepts any choice of the #aiPostProcessing enumerated * @param pPreprocessing Accepts any choice of the #aiPostProcessSteps enumerated
* flags, but in reality only a subset of them makes sense here. Specifying * flags, but in reality only a subset of them makes sense here. Specifying
* 'preprocessing' flags is useful if the input scene does not conform to * 'preprocessing' flags is useful if the input scene does not conform to
* Assimp's default conventions as specified in the @link data Data Structures Page @endlink. * Assimp's default conventions as specified in the @link data Data Structures Page @endlink.

View File

@ -38,7 +38,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file IOStream.h /** @file IOStream.hpp
* @brief File I/O wrappers for C++. * @brief File I/O wrappers for C++.
*/ */

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file IOSystem.h /** @file IOSystem.hpp
* @brief File system wrapper for C++. Inherit this class to supply * @brief File system wrapper for C++. Inherit this class to supply
* custom file handling logic to the Import library. * custom file handling logic to the Import library.
*/ */

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file assimp.hpp /** @file Importer.hpp
* @brief Defines the C++-API to the Open Asset Import Library. * @brief Defines the C++-API to the Open Asset Import Library.
*/ */
#ifndef INCLUDED_AI_ASSIMP_HPP #ifndef INCLUDED_AI_ASSIMP_HPP
@ -624,8 +624,8 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Private, do not use. */ /** Private, do not use. */
ImporterPimpl* Pimpl() { return pimpl; }; ImporterPimpl* Pimpl() { return pimpl; }
const ImporterPimpl* Pimpl() const { return pimpl; }; const ImporterPimpl* Pimpl() const { return pimpl; }
protected: protected:

View File

@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file LogStream.h /** @file LogStream.hpp
* @brief Abstract base class 'LogStream', representing an output log stream. * @brief Abstract base class 'LogStream', representing an output log stream.
*/ */
#ifndef INCLUDED_AI_LOGSTREAM_H #ifndef INCLUDED_AI_LOGSTREAM_H

View File

@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file NullLogger.h /** @file NullLogger.hpp
* @brief Dummy logger * @brief Dummy logger
*/ */

View File

@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** @file ProgressHandler.h /** @file ProgressHandler.hpp
* @brief Abstract base class 'ProgressHandler'. * @brief Abstract base class 'ProgressHandler'.
*/ */
#ifndef INCLUDED_AI_PROGRESSHANDLER_H #ifndef INCLUDED_AI_PROGRESSHANDLER_H
@ -99,7 +99,7 @@ public:
virtual void UpdateFileRead(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) { virtual void UpdateFileRead(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) {
float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f; float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f;
Update( f * 0.5f ); Update( f * 0.5f );
}; }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** @brief Progress callback for post-processing steps /** @brief Progress callback for post-processing steps
@ -113,7 +113,7 @@ public:
virtual void UpdatePostProcess(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) { virtual void UpdatePostProcess(int currentStep /*= 0*/, int numberOfSteps /*= 0*/) {
float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f; float f = numberOfSteps ? currentStep / (float)numberOfSteps : 1.0f;
Update( f * 0.5f + 0.5f ); Update( f * 0.5f + 0.5f );
}; }
}; // !class ProgressHandler }; // !class ProgressHandler
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/** @file assert.h /** @file ai_assert.h
*/ */
#ifndef AI_DEBUG_H_INC #ifndef AI_DEBUG_H_INC
#define AI_DEBUG_H_INC #define AI_DEBUG_H_INC

View File

@ -122,10 +122,7 @@ ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn);
* @param pFormatId ID string to specify to which format you want to export to. Use * @param pFormatId ID string to specify to which format you want to export to. Use
* aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available. * aiGetExportFormatCount() / aiGetExportFormatDescription() to learn which export formats are available.
* @param pFileName Output file to write * @param pFileName Output file to write
* @param pIO custom IO implementation to be used. Use this if you use your own storage methods. * @param pPreprocessing Accepts any choice of the #aiPostProcessSteps enumerated
* If none is supplied, a default implementation using standard file IO is used. Note that
* #aiExportSceneToBlob is provided as convenience function to export to memory buffers.
* @param pPreprocessing Accepts any choice of the #aiPostProcessing enumerated
* flags, but in reality only a subset of them makes sense here. Specifying * flags, but in reality only a subset of them makes sense here. Specifying
* 'preprocessing' flags is useful if the input scene does not conform to * 'preprocessing' flags is useful if the input scene does not conform to
* Assimp's default conventions as specified in the @link data Data Structures Page @endlink. * Assimp's default conventions as specified in the @link data Data Structures Page @endlink.
@ -183,7 +180,7 @@ ASSIMP_API aiReturn aiExportSceneEx( const C_STRUCT aiScene* pScene,
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
/** Describes a blob of exported scene data. Use #aiExportSceneToBlob() to create a blob containing an /** Describes a blob of exported scene data. Use #aiExportSceneToBlob() to create a blob containing an
* exported scene. The memory referred by this structure is owned by Assimp. Use #aiReleaseExportedFile() * exported scene. The memory referred by this structure is owned by Assimp.
* to free its resources. Don't try to free the memory on your side - it will crash for most build configurations * to free its resources. Don't try to free the memory on your side - it will crash for most build configurations
* due to conflicting heaps. * due to conflicting heaps.
* *

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiFileIO.h /** @file cfileio.h
* @brief Defines generic C routines to access memory-mapped files * @brief Defines generic C routines to access memory-mapped files
*/ */
#ifndef AI_FILEIO_H_INC #ifndef AI_FILEIO_H_INC

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file assimp.h /** @file cimport.h
* @brief Defines the C-API to the Open Asset Import Library. * @brief Defines the C-API to the Open Asset Import Library.
*/ */
#ifndef AI_ASSIMP_H_INC #ifndef AI_ASSIMP_H_INC
@ -139,7 +139,17 @@ ASSIMP_API const C_STRUCT aiScene* aiImportFileEx(
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
/** Same as #aiImportFileEx, but adds an extra parameter containing importer settings. /** Same as #aiImportFileEx, but adds an extra parameter containing importer settings.
* *
* @param pFile Path and filename of the file to be imported,
* expected to be a null-terminated c-string. NULL is not a valid value.
* @param pFlags Optional post processing steps to be executed after
* a successful import. Provide a bitwise combination of the
* #aiPostProcessSteps flags.
* @param pFS aiFileIO structure. Will be used to open the model file itself
* and any other files the loader needs to open. Pass NULL to use the default
* implementation.
* @param pProps #aiPropertyStore instance containing import settings. * @param pProps #aiPropertyStore instance containing import settings.
* @return Pointer to the imported data or NULL if the import failed.
* @note Include <aiFileIO.h> for the definition of #aiFileIO.
* @see aiImportFileEx * @see aiImportFileEx
*/ */
ASSIMP_API const C_STRUCT aiScene* aiImportFileExWithProperties( ASSIMP_API const C_STRUCT aiScene* aiImportFileExWithProperties(
@ -188,7 +198,29 @@ ASSIMP_API const C_STRUCT aiScene* aiImportFileFromMemory(
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
/** Same as #aiImportFileFromMemory, but adds an extra parameter containing importer settings. /** Same as #aiImportFileFromMemory, but adds an extra parameter containing importer settings.
* *
* @param pBuffer Pointer to the file data
* @param pLength Length of pBuffer, in bytes
* @param pFlags Optional post processing steps to be executed after
* a successful import. Provide a bitwise combination of the
* #aiPostProcessSteps flags. If you wish to inspect the imported
* scene first in order to fine-tune your post-processing setup,
* consider to use #aiApplyPostProcessing().
* @param pHint An additional hint to the library. If this is a non empty string,
* the library looks for a loader to support the file extension specified by pHint
* and passes the file to the first matching loader. If this loader is unable to
* completely the request, the library continues and tries to determine the file
* format on its own, a task that may or may not be successful.
* Check the return value, and you'll know ...
* @param pProps #aiPropertyStore instance containing import settings. * @param pProps #aiPropertyStore instance containing import settings.
* @return A pointer to the imported data, NULL if the import failed.
*
* @note This is a straightforward way to decode models from memory
* buffers, but it doesn't handle model formats that spread their
* data across multiple files or even directories. Examples include
* OBJ or MD3, which outsource parts of their material info into
* external scripts. If you need full functionality, provide
* a custom IOSystem to make Assimp find these files and use
* the regular aiImportFileEx()/aiImportFileExWithProperties() API.
* @see aiImportFileFromMemory * @see aiImportFileFromMemory
*/ */
ASSIMP_API const C_STRUCT aiScene* aiImportFileFromMemoryWithProperties( ASSIMP_API const C_STRUCT aiScene* aiImportFileFromMemoryWithProperties(
@ -210,7 +242,7 @@ ASSIMP_API const C_STRUCT aiScene* aiImportFileFromMemoryWithProperties(
* meaning this is still the same #aiScene which you passed for pScene. However, * meaning this is still the same #aiScene which you passed for pScene. However,
* _if_ post-processing failed, the scene could now be NULL. That's quite a rare * _if_ post-processing failed, the scene could now be NULL. That's quite a rare
* case, post processing steps are not really designed to 'fail'. To be exact, * case, post processing steps are not really designed to 'fail'. To be exact,
* the #aiProcess_ValidateDS flag is currently the only post processing step * the #aiProcess_ValidateDataStructure flag is currently the only post processing step
* which can actually cause the scene to be reset to NULL. * which can actually cause the scene to be reset to NULL.
*/ */
ASSIMP_API const C_STRUCT aiScene* aiApplyPostProcessing( ASSIMP_API const C_STRUCT aiScene* aiApplyPostProcessing(
@ -266,7 +298,7 @@ ASSIMP_API void aiEnableVerboseLogging(aiBool d);
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
/** Detach a custom log stream from the libraries' logging system. /** Detach a custom log stream from the libraries' logging system.
* *
* This is the counterpart of #aiAttachPredefinedLogStream. If you attached a stream, * This is the counterpart of #aiAttachLogStream. If you attached a stream,
* don't forget to detach it again. * don't forget to detach it again.
* @param stream The log stream to be detached. * @param stream The log stream to be detached.
* @return AI_SUCCESS if the log stream has been detached successfully. * @return AI_SUCCESS if the log stream has been detached successfully.
@ -356,8 +388,9 @@ ASSIMP_API void aiReleasePropertyStore(C_STRUCT aiPropertyStore* p);
* interface, properties are always shared by all imports. It is not possible to * interface, properties are always shared by all imports. It is not possible to
* specify them per import. * specify them per import.
* *
* @param store Store to modify. Use #aiCreatePropertyStore to obtain a store.
* @param szName Name of the configuration property to be set. All supported * @param szName Name of the configuration property to be set. All supported
* public properties are defined in the config.h header file (#AI_CONFIG_XXX). * public properties are defined in the config.h header file (AI_CONFIG_XXX).
* @param value New value for the property * @param value New value for the property
*/ */
ASSIMP_API void aiSetImportPropertyInteger( ASSIMP_API void aiSetImportPropertyInteger(
@ -372,8 +405,9 @@ ASSIMP_API void aiSetImportPropertyInteger(
* interface, properties are always shared by all imports. It is not possible to * interface, properties are always shared by all imports. It is not possible to
* specify them per import. * specify them per import.
* *
* @param store Store to modify. Use #aiCreatePropertyStore to obtain a store.
* @param szName Name of the configuration property to be set. All supported * @param szName Name of the configuration property to be set. All supported
* public properties are defined in the config.h header file (#AI_CONFIG_XXX). * public properties are defined in the config.h header file (AI_CONFIG_XXX).
* @param value New value for the property * @param value New value for the property
*/ */
ASSIMP_API void aiSetImportPropertyFloat( ASSIMP_API void aiSetImportPropertyFloat(
@ -388,10 +422,10 @@ ASSIMP_API void aiSetImportPropertyFloat(
* interface, properties are always shared by all imports. It is not possible to * interface, properties are always shared by all imports. It is not possible to
* specify them per import. * specify them per import.
* *
* @param property store to modify. Use #aiCreatePropertyStore to obtain a store. * @param store Store to modify. Use #aiCreatePropertyStore to obtain a store.
* @param szName Name of the configuration property to be set. All supported * @param szName Name of the configuration property to be set. All supported
* public properties are defined in the config.h header file (#AI_CONFIG_XXX). * public properties are defined in the config.h header file (AI_CONFIG_XXX).
* @param value New value for the property * @param st New value for the property
*/ */
ASSIMP_API void aiSetImportPropertyString( ASSIMP_API void aiSetImportPropertyString(
C_STRUCT aiPropertyStore* store, C_STRUCT aiPropertyStore* store,
@ -405,10 +439,10 @@ ASSIMP_API void aiSetImportPropertyString(
* interface, properties are always shared by all imports. It is not possible to * interface, properties are always shared by all imports. It is not possible to
* specify them per import. * specify them per import.
* *
* @param property store to modify. Use #aiCreatePropertyStore to obtain a store. * @param store Store to modify. Use #aiCreatePropertyStore to obtain a store.
* @param szName Name of the configuration property to be set. All supported * @param szName Name of the configuration property to be set. All supported
* public properties are defined in the config.h header file (#AI_CONFIG_XXX). * public properties are defined in the config.h header file (AI_CONFIG_XXX).
* @param value New value for the property * @param mat New value for the property
*/ */
ASSIMP_API void aiSetImportPropertyMatrix( ASSIMP_API void aiSetImportPropertyMatrix(
C_STRUCT aiPropertyStore* store, C_STRUCT aiPropertyStore* store,

View File

@ -38,7 +38,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiColor4D.h /** @file color4.h
* @brief RGBA color structure, including operators when compiling in C++ * @brief RGBA color structure, including operators when compiling in C++
*/ */
#ifndef AI_COLOR4D_H_INC #ifndef AI_COLOR4D_H_INC

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiColor4D.inl /** @file color4.inl
* @brief Inline implementation of aiColor4t<TReal> operators * @brief Inline implementation of aiColor4t<TReal> operators
*/ */
#ifndef AI_COLOR4D_INL_INC #ifndef AI_COLOR4D_INL_INC

View File

@ -209,7 +209,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"PP_RRM_EXCLUDE_LIST" "PP_RRM_EXCLUDE_LIST"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Configures the #aiProcess_PretransformVertices step to /** @brief Configures the #aiProcess_PreTransformVertices step to
* keep the scene hierarchy. Meshes are moved to worldspace, but * keep the scene hierarchy. Meshes are moved to worldspace, but
* no optimization is performed (read: meshes with equal materials are not * no optimization is performed (read: meshes with equal materials are not
* joined. The total number of meshes won't change). * joined. The total number of meshes won't change).
@ -224,7 +224,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"PP_PTV_KEEP_HIERARCHY" "PP_PTV_KEEP_HIERARCHY"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Configures the #aiProcess_PretransformVertices step to normalize /** @brief Configures the #aiProcess_PreTransformVertices step to normalize
* all vertex components into the [-1,1] range. That is, a bounding box * all vertex components into the [-1,1] range. That is, a bounding box
* for the whole scene is computed, the maximum component is taken and all * for the whole scene is computed, the maximum component is taken and all
* meshes are scaled appropriately (uniformly of course!). * meshes are scaled appropriately (uniformly of course!).
@ -234,7 +234,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"PP_PTV_NORMALIZE" "PP_PTV_NORMALIZE"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Configures the #aiProcess_PretransformVertices step to use /** @brief Configures the #aiProcess_PreTransformVertices step to use
* a users defined matrix as the scene root node transformation before * a users defined matrix as the scene root node transformation before
* transforming vertices. * transforming vertices.
* Property type: bool. Default value: false. * Property type: bool. Default value: false.
@ -243,7 +243,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"PP_PTV_ADD_ROOT_TRANSFORMATION" "PP_PTV_ADD_ROOT_TRANSFORMATION"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Configures the #aiProcess_PretransformVertices step to use /** @brief Configures the #aiProcess_PreTransformVertices step to use
* a users defined matrix as the scene root node transformation before * a users defined matrix as the scene root node transformation before
* transforming vertices. This property correspond to the 'a1' component * transforming vertices. This property correspond to the 'a1' component
* of the transformation matrix. * of the transformation matrix.
@ -376,7 +376,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Enumerates components of the aiScene and aiMesh data structures /** @brief Enumerates components of the aiScene and aiMesh data structures
* that can be excluded from the import using the #aiPrpcess_RemoveComponent step. * that can be excluded from the import using the #aiProcess_RemoveComponent step.
* *
* See the documentation to #aiProcess_RemoveComponent for more details. * See the documentation to #aiProcess_RemoveComponent for more details.
*/ */
@ -715,7 +715,7 @@ enum aiComponent
/** @brief Tells the MD3 loader which skin files to load. /** @brief Tells the MD3 loader which skin files to load.
* *
* When loading MD3 files, Assimp checks whether a file * When loading MD3 files, Assimp checks whether a file
* <md3_file_name>_<skin_name>.skin is existing. These files are used by * [md3_file_name]_[skin_name].skin is existing. These files are used by
* Quake III to be able to assign different skins (e.g. red and blue team) * Quake III to be able to assign different skins (e.g. red and blue team)
* to models. 'default', 'red', 'blue' are typical skin names. * to models. 'default', 'red', 'blue' are typical skin names.
* Property type: String. Default value: "default". * Property type: String. Default value: "default".
@ -728,14 +728,14 @@ enum aiComponent
* MD3 file. This can also be a search path. * MD3 file. This can also be a search path.
* *
* By default Assimp's behaviour is as follows: If a MD3 file * By default Assimp's behaviour is as follows: If a MD3 file
* <tt><any_path>/models/<any_q3_subdir>/<model_name>/<file_name>.md3</tt> is * <tt>any_path/models/any_q3_subdir/model_name/file_name.md3</tt> is
* loaded, the library tries to locate the corresponding shader file in * loaded, the library tries to locate the corresponding shader file in
* <tt><any_path>/scripts/<model_name>.shader</tt>. This property overrides this * <tt>any_path/scripts/model_name.shader</tt>. This property overrides this
* behaviour. It can either specify a full path to the shader to be loaded * behaviour. It can either specify a full path to the shader to be loaded
* or alternatively the path (relative or absolute) to the directory where * or alternatively the path (relative or absolute) to the directory where
* the shaders for all MD3s to be loaded reside. Assimp attempts to open * the shaders for all MD3s to be loaded reside. Assimp attempts to open
* <tt><dir>/<model_name>.shader</tt> first, <tt><dir>/<file_name>.shader</tt> * <tt>IMPORT_MD3_SHADER_SRC/model_name.shader</tt> first, <tt>IMPORT_MD3_SHADER_SRC/file_name.shader</tt>
* is the fallback file. Note that <dir> should have a terminal (back)slash. * is the fallback file. Note that IMPORT_MD3_SHADER_SRC should have a terminal (back)slash.
* Property type: String. Default value: n/a. * Property type: String. Default value: n/a.
*/ */
#define AI_CONFIG_IMPORT_MD3_SHADER_SRC \ #define AI_CONFIG_IMPORT_MD3_SHADER_SRC \
@ -818,12 +818,13 @@ enum aiComponent
/** @brief Ogre Importer detect the texture usage from its filename. /** @brief Ogre Importer detect the texture usage from its filename.
* *
* Ogre material texture units do not define texture type, the textures usage * Ogre material texture units do not define texture type, the textures usage
* depends on the used shader or Ogres fixed pipeline. If this config property * depends on the used shader or Ogre's fixed pipeline. If this config property
* is true Assimp will try to detect the type from the textures filename postfix: * is true Assimp will try to detect the type from the textures filename postfix:
* _n, _nrm, _nrml, _normal, _normals and _normalmap for normal map, _s, _spec, * _n, _nrm, _nrml, _normal, _normals and _normalmap for normal map, _s, _spec,
* _specular and _specularmap for specular map, _l, _light, _lightmap, _occ * _specular and _specularmap for specular map, _l, _light, _lightmap, _occ
* and _occlusion for light map, _disp and _displacement for displacement map. * and _occlusion for light map, _disp and _displacement for displacement map.
* The matching is case insensitive. Post fix is taken between last "_" and last ".". * The matching is case insensitive. Post fix is taken between the last
* underscore and the last period.
* Default behavior is to detect type from lower cased texture unit name by * Default behavior is to detect type from lower cased texture unit name by
* matching against: normalmap, specularmap, lightmap and displacementmap. * matching against: normalmap, specularmap, lightmap and displacementmap.
* For both cases if no match is found aiTextureType_DIFFUSE is used. * For both cases if no match is found aiTextureType_DIFFUSE is used.

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiDefines.h /** @file defs.h
* @brief Assimp build configuration setup. See the notes in the comment * @brief Assimp build configuration setup. See the notes in the comment
* blocks to find out how to customize _your_ Assimp build. * blocks to find out how to customize _your_ Assimp build.
*/ */
@ -162,8 +162,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# define AI_FORCE_INLINE inline # define AI_FORCE_INLINE inline
#endif // (defined _MSC_VER) #endif // (defined _MSC_VER)
#ifdef __clang__ #ifdef __GNUC__
# define AI_WONT_RETURN_SUFFIX __attribute__((analyzer_noreturn)) # define AI_WONT_RETURN_SUFFIX __attribute__((noreturn))
#else #else
# define AI_WONT_RETURN_SUFFIX # define AI_WONT_RETURN_SUFFIX
#endif // (defined __clang__) #endif // (defined __clang__)

View File

@ -98,8 +98,7 @@ struct aiImporterDesc
/** Implementation comments, i.e. unimplemented features*/ /** Implementation comments, i.e. unimplemented features*/
const char* mComments; const char* mComments;
/** Any combination of the #aiLoaderFlags enumerated values. /** These flags indicate some characteristics common to many
These flags indicate some characteristics common to many
importers. */ importers. */
unsigned int mFlags; unsigned int mFlags;

View File

@ -95,14 +95,9 @@ enum aiTextureOp
aiTextureOp_SignedAdd = 0x5, aiTextureOp_SignedAdd = 0x5,
/** @cond never
* This value is not used. It forces the compiler to use at least
* 32 Bit integers to represent this enum.
*/
#ifndef SWIG #ifndef SWIG
_aiTextureOp_Force32Bit = INT_MAX _aiTextureOp_Force32Bit = INT_MAX
#endif #endif
//! @endcond
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -131,14 +126,9 @@ enum aiTextureMapMode
*/ */
aiTextureMapMode_Mirror = 0x2, aiTextureMapMode_Mirror = 0x2,
/** @cond never
* This value is not used. It forces the compiler to use at least
* 32 Bit integers to represent this enum.
*/
#ifndef SWIG #ifndef SWIG
_aiTextureMapMode_Force32Bit = INT_MAX _aiTextureMapMode_Force32Bit = INT_MAX
#endif #endif
//! @endcond
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -176,14 +166,9 @@ enum aiTextureMapping
aiTextureMapping_OTHER = 0x5, aiTextureMapping_OTHER = 0x5,
/** @cond never
* This value is not used. It forces the compiler to use at least
* 32 Bit integers to represent this enum.
*/
#ifndef SWIG #ifndef SWIG
_aiTextureMapping_Force32Bit = INT_MAX _aiTextureMapping_Force32Bit = INT_MAX
#endif #endif
//! @endcond
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -296,14 +281,9 @@ enum aiTextureType
aiTextureType_UNKNOWN = 0xC, aiTextureType_UNKNOWN = 0xC,
/** @cond never
* This value is not used. It forces the compiler to use at least
* 32 Bit integers to represent this enum.
*/
#ifndef SWIG #ifndef SWIG
_aiTextureType_Force32Bit = INT_MAX _aiTextureType_Force32Bit = INT_MAX
#endif #endif
//! @endcond
}; };
#define AI_TEXTURE_TYPE_MAX aiTextureType_UNKNOWN #define AI_TEXTURE_TYPE_MAX aiTextureType_UNKNOWN
@ -374,14 +354,9 @@ enum aiShadingMode
aiShadingMode_Fresnel = 0xa, aiShadingMode_Fresnel = 0xa,
/** @cond never
* This value is not used. It forces the compiler to use at least
* 32 Bit integers to represent this enum.
*/
#ifndef SWIG #ifndef SWIG
_aiShadingMode_Force32Bit = INT_MAX _aiShadingMode_Force32Bit = INT_MAX
#endif #endif
//! @endcond
}; };
@ -420,14 +395,9 @@ enum aiTextureFlags
*/ */
aiTextureFlags_IgnoreAlpha = 0x4, aiTextureFlags_IgnoreAlpha = 0x4,
/** @cond never
* This value is not used. It forces the compiler to use at least
* 32 Bit integers to represent this enum.
*/
#ifndef SWIG #ifndef SWIG
_aiTextureFlags_Force32Bit = INT_MAX _aiTextureFlags_Force32Bit = INT_MAX
#endif #endif
//! @endcond
}; };
@ -442,8 +412,8 @@ enum aiTextureFlags
* @code * @code
* SourceColor * SourceBlend + DestColor * DestBlend * SourceColor * SourceBlend + DestColor * DestBlend
* @endcode * @endcode
* where <DestColor> is the previous color in the framebuffer at this * where DestColor is the previous color in the framebuffer at this
* position and <SourceColor> is the material colro before the transparency * position and SourceColor is the material colro before the transparency
* calculation.<br> * calculation.<br>
* This corresponds to the #AI_MATKEY_BLEND_FUNC property. * This corresponds to the #AI_MATKEY_BLEND_FUNC property.
*/ */
@ -469,14 +439,9 @@ enum aiBlendMode
// we don't need more for the moment, but we might need them // we don't need more for the moment, but we might need them
// in future versions ... // in future versions ...
/** @cond never
* This value is not used. It forces the compiler to use at least
* 32 Bit integers to represent this enum.
*/
#ifndef SWIG #ifndef SWIG
_aiBlendMode_Force32Bit = INT_MAX _aiBlendMode_Force32Bit = INT_MAX
#endif #endif
//! @endcond
}; };
@ -862,7 +827,9 @@ public:
/** @brief Remove a given key from the list. /** @brief Remove a given key from the list.
* *
* The function fails if the key isn't found * The function fails if the key isn't found
* @param pKey Key to be deleted */ * @param pKey Key to be deleted
* @param type Set by the AI_MATKEY_XXX macro
* @param index Set by the AI_MATKEY_XXX macro */
aiReturn RemoveProperty (const char* pKey, aiReturn RemoveProperty (const char* pKey,
unsigned int type = 0, unsigned int type = 0,
unsigned int index = 0); unsigned int index = 0);
@ -1330,6 +1297,8 @@ extern "C" {
#define AI_MATKEY_TEXFLAGS_UNKNOWN(N) \ #define AI_MATKEY_TEXFLAGS_UNKNOWN(N) \
AI_MATKEY_TEXFLAGS(aiTextureType_UNKNOWN,N) AI_MATKEY_TEXFLAGS(aiTextureType_UNKNOWN,N)
//! @endcond
//!
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Retrieve a material property with a specific key from the material /** @brief Retrieve a material property with a specific key from the material
* *
@ -1537,6 +1506,7 @@ ASSIMP_API unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMa
* Pass NULL if you're not interested in this information. Otherwise, * Pass NULL if you're not interested in this information. Otherwise,
* pass a pointer to an array of two aiTextureMapMode's (one for each * pass a pointer to an array of two aiTextureMapMode's (one for each
* axis, UV order). * axis, UV order).
* @param[out] flags Receives the the texture flags.
* @return AI_SUCCESS on success, otherwise something else. Have fun.*/ * @return AI_SUCCESS on success, otherwise something else. Have fun.*/
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiMaterial.inl /** @file material.inl
* @brief Defines the C++ getters for the material system * @brief Defines the C++ getters for the material system
*/ */

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiMatrix3x3.inl /** @file matrix3x3.inl
* @brief Inline implementation of the 3x3 matrix operators * @brief Inline implementation of the 3x3 matrix operators
*/ */
#ifndef AI_MATRIX3x3_INL_INC #ifndef AI_MATRIX3x3_INL_INC

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiMatrix4x4t<TReal>.inl /** @file matrix4x4.inl
* @brief Inline implementation of the 4x4 matrix operators * @brief Inline implementation of the 4x4 matrix operators
*/ */
#ifndef AI_MATRIX4x4_INL_INC #ifndef AI_MATRIX4x4_INL_INC
@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "quaternion.h" #include "quaternion.h"
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
#include <cmath> #include <cmath>
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------

View File

@ -668,8 +668,7 @@ struct aiMesh
} }
//! Check whether the mesh contains positions. Provided no special //! Check whether the mesh contains positions. Provided no special
//! scene flags are set (such as #AI_SCENE_FLAGS_ANIM_SKELETON_ONLY), //! scene flags are set, this will always be true
//! this will always be true
bool HasPositions() const bool HasPositions() const
{ return mVertices != NULL && mNumVertices > 0; } { return mVertices != NULL && mNumVertices > 0; }

View File

@ -282,7 +282,7 @@ enum aiPostProcessSteps
/** <hr>Searches for redundant/unreferenced materials and removes them. /** <hr>Searches for redundant/unreferenced materials and removes them.
* *
* This is especially useful in combination with the * This is especially useful in combination with the
* #aiProcess_PretransformVertices and #aiProcess_OptimizeMeshes flags. * #aiProcess_PreTransformVertices and #aiProcess_OptimizeMeshes flags.
* Both join small meshes with equal characteristics, but they can't do * Both join small meshes with equal characteristics, but they can't do
* their work if two meshes have different materials. Because several * their work if two meshes have different materials. Because several
* material settings are lost during Assimp's import filters, * material settings are lost during Assimp's import filters,
@ -335,7 +335,7 @@ enum aiPostProcessSteps
* To have the degenerate stuff not only detected and collapsed but * To have the degenerate stuff not only detected and collapsed but
* removed, try one of the following procedures: * removed, try one of the following procedures:
* <br><b>1.</b> (if you support lines and points for rendering but don't * <br><b>1.</b> (if you support lines and points for rendering but don't
* want the degenerates)</br> * want the degenerates)<br>
* <ul> * <ul>
* <li>Specify the #aiProcess_FindDegenerates flag. * <li>Specify the #aiProcess_FindDegenerates flag.
* </li> * </li>
@ -345,7 +345,7 @@ enum aiPostProcessSteps
* pipeline steps. * pipeline steps.
* </li> * </li>
* </ul> * </ul>
* <br><b>2.</b>(if you don't support lines and points at all)</br> * <br><b>2.</b>(if you don't support lines and points at all)<br>
* <ul> * <ul>
* <li>Specify the #aiProcess_FindDegenerates flag. * <li>Specify the #aiProcess_FindDegenerates flag.
* </li> * </li>
@ -550,7 +550,7 @@ enum aiPostProcessSteps
// --------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------
/** @def aiProcessPreset_TargetRealtimeUse_Fast /** @def aiProcessPreset_TargetRealtime_Fast
* @brief Default postprocess configuration optimizing the data for real-time rendering. * @brief Default postprocess configuration optimizing the data for real-time rendering.
* *
* Applications would want to use this preset to load models on end-user PCs, * Applications would want to use this preset to load models on end-user PCs,

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiQuaterniont.inl /** @file quaternion.inl
* @brief Inline implementation of aiQuaterniont<TReal> operators * @brief Inline implementation of aiQuaterniont<TReal> operators
*/ */
#ifndef AI_QUATERNION_INL_INC #ifndef AI_QUATERNION_INL_INC

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiScene.h /** @file scene.h
* @brief Defines the data structures in which the imported scene is returned. * @brief Defines the data structures in which the imported scene is returned.
*/ */
#ifndef __AI_SCENE_H_INC__ #ifndef __AI_SCENE_H_INC__
@ -182,8 +182,6 @@ struct aiNode
} }
/** @override
*/
inline const aiNode* FindNode(const char* name) const inline const aiNode* FindNode(const char* name) const
{ {
if (!::strcmp( mName.data,name))return this; if (!::strcmp( mName.data,name))return this;
@ -217,7 +215,7 @@ struct aiNode
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
/** @def AI_SCENE_FLAGS_INCOMPLETE /**
* Specifies that the scene data structure that was imported is not complete. * Specifies that the scene data structure that was imported is not complete.
* This flag bypasses some internal validations and allows the import * This flag bypasses some internal validations and allows the import
* of animation skeletons, material libraries or camera animation paths * of animation skeletons, material libraries or camera animation paths
@ -225,14 +223,14 @@ struct aiNode
*/ */
#define AI_SCENE_FLAGS_INCOMPLETE 0x1 #define AI_SCENE_FLAGS_INCOMPLETE 0x1
/** @def AI_SCENE_FLAGS_VALIDATED /**
* This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS) * This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS)
* if the validation is successful. In a validated scene you can be sure that * if the validation is successful. In a validated scene you can be sure that
* any cross references in the data structure (e.g. vertex indices) are valid. * any cross references in the data structure (e.g. vertex indices) are valid.
*/ */
#define AI_SCENE_FLAGS_VALIDATED 0x2 #define AI_SCENE_FLAGS_VALIDATED 0x2
/** @def AI_SCENE_FLAGS_VALIDATION_WARNING /**
* This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS) * This flag is set by the validation postprocess-step (aiPostProcess_ValidateDS)
* if the validation is successful but some issues have been found. * if the validation is successful but some issues have been found.
* This can for example mean that a texture that does not exist is referenced * This can for example mean that a texture that does not exist is referenced
@ -242,7 +240,7 @@ struct aiNode
*/ */
#define AI_SCENE_FLAGS_VALIDATION_WARNING 0x4 #define AI_SCENE_FLAGS_VALIDATION_WARNING 0x4
/** @def AI_SCENE_FLAGS_NON_VERBOSE_FORMAT /**
* This flag is currently only set by the aiProcess_JoinIdenticalVertices step. * This flag is currently only set by the aiProcess_JoinIdenticalVertices step.
* It indicates that the vertices of the output meshes aren't in the internal * It indicates that the vertices of the output meshes aren't in the internal
* verbose format anymore. In the verbose format all vertices are unique, * verbose format anymore. In the verbose format all vertices are unique,
@ -250,7 +248,7 @@ struct aiNode
*/ */
#define AI_SCENE_FLAGS_NON_VERBOSE_FORMAT 0x8 #define AI_SCENE_FLAGS_NON_VERBOSE_FORMAT 0x8
/** @def AI_SCENE_FLAGS_TERRAIN /**
* Denotes pure height-map terrain data. Pure terrains usually consist of quads, * Denotes pure height-map terrain data. Pure terrains usually consist of quads,
* sometimes triangles, in a regular grid. The x,y coordinates of all vertex * sometimes triangles, in a regular grid. The x,y coordinates of all vertex
* positions refer to the x,y coordinates on the terrain height map, the z-axis * positions refer to the x,y coordinates on the terrain height map, the z-axis

View File

@ -241,7 +241,7 @@ struct aiColor3D
* For most applications, it will be absolutely sufficient to interpret the * For most applications, it will be absolutely sufficient to interpret the
* aiString as ASCII data and work with it as one would work with a plain char*. * aiString as ASCII data and work with it as one would work with a plain char*.
* Windows users in need of proper support for i.e asian characters can use the * Windows users in need of proper support for i.e asian characters can use the
* #MultiByteToWideChar(), #WideCharToMultiByte() WinAPI functionality to convert the * MultiByteToWideChar(), WideCharToMultiByte() WinAPI functionality to convert the
* UTF-8 strings to their working character set (i.e. MBCS, WideChar). * UTF-8 strings to their working character set (i.e. MBCS, WideChar).
* *
* We use this representation instead of std::string to be C-compatible. The * We use this representation instead of std::string to be C-compatible. The
@ -388,6 +388,8 @@ typedef enum aiReturn
* Force 32-bit size enum * Force 32-bit size enum
*/ */
_AI_ENFORCE_ENUM_SIZE = 0x7fffffff _AI_ENFORCE_ENUM_SIZE = 0x7fffffff
/// @endcond
} aiReturn; // !enum aiReturn } aiReturn; // !enum aiReturn
// just for backwards compatibility, don't use these constants anymore // just for backwards compatibility, don't use these constants anymore
@ -414,13 +416,14 @@ enum aiOrigin
* Force 32-bit size enum * Force 32-bit size enum
*/ */
_AI_ORIGIN_ENFORCE_ENUM_SIZE = 0x7fffffff _AI_ORIGIN_ENFORCE_ENUM_SIZE = 0x7fffffff
/// @endcond
}; // !enum aiOrigin }; // !enum aiOrigin
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
/** @brief Enumerates predefined log streaming destinations. /** @brief Enumerates predefined log streaming destinations.
* Logging to these streams can be enabled with a single call to * Logging to these streams can be enabled with a single call to
* #LogStream::createDefaultStream or #aiAttachPredefinedLogStream(), * #LogStream::createDefaultStream.
* respectively.
*/ */
enum aiDefaultLogStream enum aiDefaultLogStream
{ {
@ -442,6 +445,7 @@ enum aiDefaultLogStream
* Force 32-bit size enum * Force 32-bit size enum
*/ */
_AI_DLS_ENFORCE_ENUM_SIZE = 0x7fffffff _AI_DLS_ENFORCE_ENUM_SIZE = 0x7fffffff
/// @endcond
}; // !enum aiDefaultLogStream }; // !enum aiDefaultLogStream
// just for backwards compatibility, don't use these constants anymore // just for backwards compatibility, don't use these constants anymore

View File

@ -38,18 +38,18 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiVector2t.h /** @file vector2.h
* @brief 2D vector structure, including operators when compiling in C++ * @brief 2D vector structure, including operators when compiling in C++
*/ */
#ifndef AI_VECTOR2D_H_INC #ifndef AI_VECTOR2D_H_INC
#define AI_VECTOR2D_H_INC #define AI_VECTOR2D_H_INC
#ifdef __cplusplus #ifdef __cplusplus
# include <cmath> # include <cmath>
#else #else
# include <math.h> # include <math.h>
#endif #endif
#include "./Compiler/pushpack1.h" #include "./Compiler/pushpack1.h"
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiVector2D.inl /** @file vector2.inl
* @brief Inline implementation of aiVector2t<TReal> operators * @brief Inline implementation of aiVector2t<TReal> operators
*/ */
#ifndef AI_VECTOR2D_INL_INC #ifndef AI_VECTOR2D_INL_INC

View File

@ -38,18 +38,18 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiVector3D.h /** @file vector3.h
* @brief 3D vector structure, including operators when compiling in C++ * @brief 3D vector structure, including operators when compiling in C++
*/ */
#ifndef AI_VECTOR3D_H_INC #ifndef AI_VECTOR3D_H_INC
#define AI_VECTOR3D_H_INC #define AI_VECTOR3D_H_INC
#ifdef __cplusplus #ifdef __cplusplus
# include <cmath> # include <cmath>
#else #else
# include <math.h> # include <math.h>
#endif #endif
#include "./Compiler/pushpack1.h" #include "./Compiler/pushpack1.h"
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiVector3D.inl /** @file vector3.inl
* @brief Inline implementation of aiVector3t<TReal> operators * @brief Inline implementation of aiVector3t<TReal> operators
*/ */
#ifndef AI_VECTOR3D_INL_INC #ifndef AI_VECTOR3D_INL_INC

View File

@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file aiVersion.h /** @file version.h
* @brief Functions to query the version of the Assimp runtime, check * @brief Functions to query the version of the Assimp runtime, check
* compile flags, ... * compile flags, ...
*/ */

View File

@ -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

View File

@ -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.

View File

@ -221,7 +221,7 @@ public:
private: private:
/* Report failure */ /* Report failure */
void failure(const std::string& err, const std::string& name) { AI_WONT_RETURN void failure(const std::string& err, const std::string& name) AI_WONT_RETURN_SUFFIX {
std::stringstream ss; std::stringstream ss;
throw compare_fails_exception((ss throw compare_fails_exception((ss
<< "Files are different at " << "Files are different at "