Merge branch 'master' into respect-cmake-output-variables

pull/4338/head
Kim Kulling 2022-01-23 18:11:47 +01:00 committed by GitHub
commit 6cc469a5ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 1270 additions and 737 deletions

View File

@ -111,20 +111,9 @@ Discreet3DSImporter::~Discreet3DSImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
std::string extension = GetExtension(pFile); static const uint16_t token[] = { 0x4d4d, 0x3dc2 /*, 0x3daa */ };
if (extension == "3ds" || extension == "prj") { return CheckMagicToken(pIOHandler, pFile, token, AI_COUNT_OF(token), 0, sizeof token[0]);
return true;
}
if (!extension.length() || checkSig) {
uint16_t token[3];
token[0] = 0x4d4d;
token[1] = 0x3dc2;
//token[2] = 0x3daa;
return CheckMagicToken(pIOHandler, pFile, token, 2, 0, 2);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -90,24 +90,12 @@ D3MFImporter::~D3MFImporter() {
// empty // empty
} }
bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const { bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension(GetExtension(filename)); if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
if (extension == desc.mFileExtensions) { return false;
return true;
}
if (!extension.length() || checkSig) {
if (nullptr == pIOHandler) {
return false;
}
if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
return false;
}
D3MFOpcPackage opcPackage(pIOHandler, filename);
return opcPackage.validate();
} }
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
return false; return opcPackage.validate();
} }
void D3MFImporter::SetupProperties(const Importer*) { void D3MFImporter::SetupProperties(const Importer*) {

View File

@ -152,18 +152,9 @@ AC3DImporter::~AC3DImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
std::string extension = GetExtension(pFile); static const uint32_t tokens[] = { AI_MAKE_MAGIC("AC3D") };
return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
// fixme: are acc and ac3d *really* used? Some sources say they are
if (extension == "ac" || extension == "ac3d" || extension == "acc") {
return true;
}
if (!extension.length() || checkSig) {
uint32_t token = AI_MAKE_MAGIC("AC3D");
return CheckMagicToken(pIOHandler, pFile, &token, 1, 0);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -503,19 +503,9 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) {
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const { bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*pCheckSig*/) const {
const std::string extension = GetExtension(pFile); static const char *tokens[] = { "<amf" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "amf") {
return true;
}
if (extension.empty() || pCheckSig) {
static const char * const tokens[] = { "<amf" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
const aiImporterDesc *AMFImporter::GetInfo() const { const aiImporterDesc *AMFImporter::GetInfo() const {

View File

@ -95,19 +95,9 @@ ASEImporter::~ASEImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const { bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
// check file extension static const char *tokens[] = { "*3dsmax_asciiexport" };
const std::string extension = GetExtension(pFile); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "ase" || extension == "ask") {
return true;
}
if ((!extension.length() || cs) && pIOHandler) {
static const char * const tokens[] = { "*3dsmax_asciiexport" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -486,8 +486,9 @@ void Parser::ParseLV1MaterialListBlock() {
ParseLV4MeshLong(iIndex); ParseLV4MeshLong(iIndex);
if (iIndex >= iMaterialCount) { if (iIndex >= iMaterialCount) {
LogWarning("Out of range: material index is too large"); LogError("Out of range: material index is too large");
iIndex = iMaterialCount - 1; iIndex = iMaterialCount - 1;
return;
} }
// get a reference to the material // get a reference to the material

View File

@ -81,7 +81,7 @@ static const aiImporterDesc desc = {
//#define DEBUG_B3D //#define DEBUG_B3D
template <typename T> template<typename T>
void DeleteAllBarePointers(std::vector<T> &x) { void DeleteAllBarePointers(std::vector<T> &x) {
for (auto p : x) { for (auto p : x) {
delete p; delete p;
@ -89,11 +89,11 @@ void DeleteAllBarePointers(std::vector<T> &x) {
} }
B3DImporter::~B3DImporter() { B3DImporter::~B3DImporter() {
// empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
size_t pos = pFile.find_last_of('.'); size_t pos = pFile.find_last_of('.');
if (pos == string::npos) { if (pos == string::npos) {
return false; return false;

View File

@ -92,18 +92,9 @@ BVHLoader::~BVHLoader() {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const { bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
// check file extension static const char *tokens[] = { "HIERARCHY" };
const std::string extension = GetExtension(pFile); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "bvh")
return true;
if ((!extension.length() || cs) && pIOHandler) {
static const char * const tokens[] = { "HIERARCHY" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -114,22 +114,14 @@ BlenderImporter::~BlenderImporter() {
} }
static const char * const Tokens[] = { "BLENDER" }; static const char * const Tokens[] = { "BLENDER" };
static const char * const TokensForSearch[] = { "blender" };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string &extension = GetExtension(pFile); // note: this won't catch compressed files
if (extension == "blend") { static const char *tokens[] = { "<BLENDER", "blender" };
return true;
}
if ((!extension.length() || checkSig) && pIOHandler) { return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
// note: this won't catch compressed files
return SearchFileHeaderForToken(pIOHandler, pFile, TokensForSearch, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -106,14 +106,25 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { C4DImporter::C4DImporter()
: BaseImporter() {
// empty
}
// ------------------------------------------------------------------------------------------------
C4DImporter::~C4DImporter() {
// empty
}
// ------------------------------------------------------------------------------------------------
bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const {
const std::string& extension = GetExtension(pFile); const std::string& extension = GetExtension(pFile);
if (extension == "c4d") { if (extension == "c4d") {
return true; return true;
} else if ((!extension.length() || checkSig) && pIOHandler) { } else if ((!extension.length() || checkSig) && pIOHandler) {
// TODO // TODO
} }
return false; return false;
} }

View File

@ -103,17 +103,9 @@ COBImporter::~COBImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string &extension = GetExtension(pFile); static const char *tokens[] = { "Caligary" };
if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") { return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
return true;
}
else if ((!extension.length() || checkSig) && pIOHandler) {
static const char * const tokens[] = { "Caligary" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -90,19 +90,10 @@ CSMImporter::~CSMImporter()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
{ {
// check file extension static const char* tokens[] = {"$Filename"};
const std::string extension = GetExtension(pFile); return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
if( extension == "csm")
return true;
if ((checkSig || !extension.length()) && pIOHandler) {
static const char * const tokens[] = {"$Filename"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -116,37 +116,15 @@ ColladaLoader::~ColladaLoader() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
// check file extension // Look for a DAE file inside, but don't extract it
const std::string extension = GetExtension(pFile); ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
const bool readSig = checkSig && (pIOHandler != nullptr); if (zip_archive.isOpen()) {
if (!readSig) { return !ColladaParser::ReadZaeManifest(zip_archive).empty();
if (extension == "dae" || extension == "zae") {
return true;
}
} else {
// Look for a DAE file inside, but don't extract it
ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
if (zip_archive.isOpen()) {
return !ColladaParser::ReadZaeManifest(zip_archive).empty();
}
} }
// XML - too generic, we need to open the file and search for typical keywords static const char *tokens[] = { "<collada" };
if (extension == "xml" || !extension.length() || checkSig) { return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
// If CanRead() is called in order to check whether we
// support a specific file extension in general pIOHandler
// might be nullptr and it's our duty to return true here.
if (nullptr == pIOHandler) {
return true;
}
static const char * const tokens[] = {
"<collada"
};
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -331,7 +331,16 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
const std::string &currentName = currentNode.name(); const std::string &currentName = currentNode.name();
if (currentName == "unit") { if (currentName == "unit") {
mUnitSize = 1.f; mUnitSize = 1.f;
XmlParser::getRealAttribute(currentNode, "meter", mUnitSize); std::string tUnitSizeString;
if (XmlParser::getStdStrAttribute(currentNode, "meter", tUnitSizeString)) {
try {
fast_atoreal_move<ai_real>(tUnitSizeString.data(), mUnitSize);
} catch (const DeadlyImportError& die) {
std::string warning("Collada: Failed to parse meter parameter to real number. Exception:\n");
warning.append(die.what());
ASSIMP_LOG_WARN(warning.data());
}
}
} else if (currentName == "up_axis") { } else if (currentName == "up_axis") {
std::string v; std::string v;
if (!XmlParser::getValueAsString(currentNode, v)) { if (!XmlParser::getValueAsString(currentNode, v)) {
@ -2242,20 +2251,26 @@ void ColladaParser::ReadNodeGeometry(XmlNode &node, Node *pNode) {
if (currentName == "bind_material") { if (currentName == "bind_material") {
XmlNode techNode = currentNode.child("technique_common"); XmlNode techNode = currentNode.child("technique_common");
if (techNode) { if (techNode) {
XmlNode instanceMatNode = techNode.child("instance_material"); for (XmlNode instanceMatNode = techNode.child("instance_material"); instanceMatNode; instanceMatNode = instanceMatNode.next_sibling())
// read ID of the geometry subgroup and the target material {
std::string group; const std::string &instance_name = instanceMatNode.name();
XmlParser::getStdStrAttribute(instanceMatNode, "symbol", group); if (instance_name == "instance_material")
XmlParser::getStdStrAttribute(instanceMatNode, "target", url); {
const char *urlMat = url.c_str(); // read ID of the geometry subgroup and the target material
Collada::SemanticMappingTable s; std::string group;
if (urlMat[0] == '#') XmlParser::getStdStrAttribute(instanceMatNode, "symbol", group);
urlMat++; XmlParser::getStdStrAttribute(instanceMatNode, "target", url);
const char *urlMat = url.c_str();
Collada::SemanticMappingTable s;
if (urlMat[0] == '#')
urlMat++;
s.mMatName = urlMat; s.mMatName = urlMat;
// store the association // store the association
instance.mMaterials[group] = s; instance.mMaterials[group] = s;
ReadMaterialVertexInputBinding(instanceMatNode, s); ReadMaterialVertexInputBinding(instanceMatNode, s);
}
}
} }
} }
} }

View File

@ -123,18 +123,9 @@ DXFImporter::~DXFImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool checkSig ) const { bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
const std::string& extension = GetExtension( filename ); static const char *tokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
if ( extension == desc.mFileExtensions ) { return SearchFileHeaderForToken(pIOHandler, filename, tokens, AI_COUNT_OF(tokens), 32);
return true;
}
if ( extension.empty() || checkSig ) {
static const char * const pTokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
return SearchFileHeaderForToken(pIOHandler, filename, pTokens, 4, 32 );
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -100,18 +100,10 @@ FBXImporter::~FBXImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
const std::string &extension = GetExtension(pFile); // at least ASCII-FBX files usually have a 'FBX' somewhere in their head
if (extension == std::string(desc.mFileExtensions)) { static const char *tokens[] = { "fbx" };
return true; return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
}
else if ((!extension.length() || checkSig) && pIOHandler) {
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
static const char * const tokens[] = { "fbx" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -84,20 +84,13 @@ HMPImporter::~HMPImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool HMPImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const { bool HMPImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const uint32_t tokens[] = {
if (extension == "hmp") AI_HMP_MAGIC_NUMBER_LE_4,
return true; AI_HMP_MAGIC_NUMBER_LE_5,
AI_HMP_MAGIC_NUMBER_LE_7
// if check for extension is not enough, check for the magic tokens };
if (!extension.length() || cs) { return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
uint32_t tokens[3];
tokens[0] = AI_HMP_MAGIC_NUMBER_LE_4;
tokens[1] = AI_HMP_MAGIC_NUMBER_LE_5;
tokens[2] = AI_HMP_MAGIC_NUMBER_LE_7;
return CheckMagicToken(pIOHandler, pFile, tokens, 3, 0);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -699,7 +699,7 @@ void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedArea
continue; continue;
} }
GenerateOpenings(openings, std::vector<IfcVector3>(1, IfcVector3(1, 0, 0)), temp, false, true); GenerateOpenings(openings, temp, false, true);
result.Append(temp); result.Append(temp);
vit += pcount; vit += pcount;

View File

@ -190,7 +190,7 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m
std::copy(outer_vit, outer_vit+outer_polygon_size, std::copy(outer_vit, outer_vit+outer_polygon_size,
std::back_inserter(temp.mVerts)); std::back_inserter(temp.mVerts));
GenerateOpenings(fake_openings, normals, temp, false, false); GenerateOpenings(fake_openings, temp, false, false);
result.Append(temp); result.Append(temp);
} }
@ -529,6 +529,31 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
return m; return m;
} }
const auto closeDistance = 1e-6;
bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) {
if(pt1.Coordinates.size() != pt2.Coordinates.size())
{
IFCImporter::LogWarn("unable to compare differently-dimensioned points");
return false;
}
auto coord1 = pt1.Coordinates.begin();
auto coord2 = pt2.Coordinates.begin();
// we're just testing each dimension separately rather than doing euclidean distance, as we're
// looking for very close coordinates
for(; coord1 != pt1.Coordinates.end(); coord1++,coord2++)
{
if(std::fabs(*coord1 - *coord2) > closeDistance)
return false;
}
return true;
}
bool areClose(IfcVector3 pt1,IfcVector3 pt2) {
return (std::fabs(pt1.x - pt2.x) < closeDistance &&
std::fabs(pt1.y - pt2.y) < closeDistance &&
std::fabs(pt1.z - pt2.z) < closeDistance);
}
// Extrudes the given polygon along the direction, converts it into an opening or applies all openings as necessary. // Extrudes the given polygon along the direction, converts it into an opening or applies all openings as necessary.
void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const TempMesh& curve, void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const TempMesh& curve,
const IfcVector3& extrusionDir, TempMesh& result, ConversionData &conv, bool collect_openings) const IfcVector3& extrusionDir, TempMesh& result, ConversionData &conv, bool collect_openings)
@ -592,7 +617,21 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
nors.push_back(IfcVector3()); nors.push_back(IfcVector3());
continue; continue;
} }
nors.push_back(((bounds.mVerts[2] - bounds.mVerts[0]) ^ (bounds.mVerts[1] - bounds.mVerts[0])).Normalize()); auto nor = ((bounds.mVerts[2] - bounds.mVerts[0]) ^ (bounds.mVerts[1] - bounds.mVerts[0])).Normalize();
auto vI0 = bounds.mVertcnt[0];
for(size_t faceI = 0; faceI < bounds.mVertcnt.size(); faceI++)
{
if(bounds.mVertcnt[faceI] >= 3) {
// do a check that this is at least parallel to the base plane
auto nor2 = ((bounds.mVerts[vI0 + 2] - bounds.mVerts[vI0]) ^ (bounds.mVerts[vI0 + 1] - bounds.mVerts[vI0])).Normalize();
if(!areClose(nor,nor2)) {
std::stringstream msg;
msg << "Face " << faceI << " is not parallel with face 0 - opening on entity " << solid.GetID();
IFCImporter::LogWarn(msg.str().c_str());
}
}
}
nors.push_back(nor);
} }
} }
@ -613,7 +652,7 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
out.push_back(in[i] + 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, temp, true, true, dir) ) {
++sides_with_openings; ++sides_with_openings;
} }
@ -622,31 +661,33 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
} }
} }
if( openings ) { if(openings) {
for(TempOpening& opening : *conv.apply_openings) { for(TempOpening& opening : *conv.apply_openings) {
if( !opening.wallPoints.empty() ) { if(!opening.wallPoints.empty()) {
IFCImporter::LogError("failed to generate all window caps"); std::stringstream msg;
msg << "failed to generate all window caps on ID " << (int)solid.GetID();
IFCImporter::LogError(msg.str().c_str());
} }
opening.wallPoints.clear(); opening.wallPoints.clear();
} }
} }
size_t sides_with_v_openings = 0; size_t sides_with_v_openings = 0;
if( has_area ) { if(has_area) {
for( size_t n = 0; n < 2; ++n ) { for(size_t n = 0; n < 2; ++n) {
if( n > 0 ) { if(n > 0) {
for( size_t i = 0; i < in.size(); ++i ) for(size_t i = 0; i < in.size(); ++i)
out.push_back(in[i] + dir); out.push_back(in[i] + dir);
} }
else { else {
for( size_t i = in.size(); i--; ) for(size_t i = in.size(); i--; )
out.push_back(in[i]); out.push_back(in[i]);
} }
curmesh.mVertcnt.push_back(static_cast<unsigned int>(in.size())); curmesh.mVertcnt.push_back(static_cast<unsigned int>(in.size()));
if( openings && in.size() > 2 ) { if(openings && in.size() > 2) {
if( GenerateOpenings(*conv.apply_openings, nors, temp, true, true, dir) ) { if(GenerateOpenings(*conv.apply_openings,temp,true,true,dir)) {
++sides_with_v_openings; ++sides_with_v_openings;
} }
@ -656,8 +697,10 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
} }
} }
if( openings && (sides_with_openings == 1 || sides_with_v_openings == 2 ) ) { if (openings && (sides_with_openings == 1 || sides_with_v_openings == 2)) {
IFCImporter::LogWarn("failed to resolve all openings, presumably their topology is not supported by Assimp"); std::stringstream msg;
msg << "failed to resolve all openings, presumably their topology is not supported by Assimp - ID " << solid.GetID() << " sides_with_openings " << sides_with_openings << " sides_with_v_openings " << sides_with_v_openings;
IFCImporter::LogWarn(msg.str().c_str());
} }
IFCImporter::LogVerboseDebug("generate mesh procedurally by extrusion (IfcExtrudedAreaSolid)"); IFCImporter::LogVerboseDebug("generate mesh procedurally by extrusion (IfcExtrudedAreaSolid)");
@ -781,7 +824,9 @@ bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned
return false; return false;
} }
else { else {
IFCImporter::LogWarn("skipping unknown IfcGeometricRepresentationItem entity, type is ", geo.GetClassName()); std::stringstream toLog;
toLog << "skipping unknown IfcGeometricRepresentationItem entity, type is " << geo.GetClassName() << " id is " << geo.GetID();
IFCImporter::LogWarn(toLog.str().c_str());
return false; return false;
} }

View File

@ -129,18 +129,12 @@ IFCImporter::~IFCImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string &extension = GetExtension(pFile); // note: this is the common identification for STEP-encoded files, so
if (extension == "ifc" || extension == "ifczip") { // it is only unambiguous as long as we don't support any further
return true; // file formats with STEP as their encoding.
} else if ((!extension.length() || checkSig) && pIOHandler) { static const char *tokens[] = { "ISO-10303-21" };
// note: this is the common identification for STEP-encoded files, so return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
// it is only unambiguous as long as we don't support any further
// file formats with STEP as their encoding.
static const char * const tokens[] = { "ISO-10303-21" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -58,6 +58,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include <iterator> #include <iterator>
#include <forward_list>
#include <deque>
namespace Assimp { namespace Assimp {
namespace IFC { namespace IFC {
@ -73,7 +75,7 @@ namespace Assimp {
// fallback method to generate wall openings // fallback method to generate wall openings
bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std::vector<IfcVector3>& nors, bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,
TempMesh& curmesh); TempMesh& curmesh);
@ -1140,7 +1142,6 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool GenerateOpenings(std::vector<TempOpening>& openings, bool GenerateOpenings(std::vector<TempOpening>& openings,
const std::vector<IfcVector3>& nors,
TempMesh& curmesh, TempMesh& curmesh,
bool check_intersection, bool check_intersection,
bool generate_connection_geometry, bool generate_connection_geometry,
@ -1340,7 +1341,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
MergeWindowContours(temp_contour, other, poly); MergeWindowContours(temp_contour, other, poly);
if (poly.size() > 1) { if (poly.size() > 1) {
return TryAddOpenings_Poly2Tri(openings, nors, curmesh); return TryAddOpenings_Poly2Tri(openings, curmesh);
} }
else if (poly.size() == 0) { else if (poly.size() == 0) {
IFCImporter::LogWarn("ignoring duplicate opening"); IFCImporter::LogWarn("ignoring duplicate opening");
@ -1427,8 +1428,289 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
return true; return true;
} }
std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMatrix3 planeSpace,
IfcVector3 planeNor,IfcFloat planeOffset,
IfcVector3 extrusionDir,IfcVector3& wall_extrusion,bool& first,bool& ok) {
std::vector<IfcVector2> contour;
const auto outernor = ((mesh->mVerts[2] - mesh->mVerts[0]) ^ (mesh->mVerts[1] - mesh->mVerts[0])).Normalize();
const IfcFloat dot = planeNor * outernor;
if(std::fabs(dot) < 1.f - 1e-6f) {
std::stringstream msg;
msg << "Skipping: Unaligned opening (" << planeNor.x << ", " << planeNor.y << ", " << planeNor.z << ")";
msg << " . ( " << outernor.x << ", " << outernor.y << ", " << outernor.z << ") = " << dot;
IFCImporter::LogDebug(msg.str().c_str());
ok = false;
return contour;
}
const std::vector<IfcVector3>& va = mesh->mVerts;
if(va.size() <= 2) {
std::stringstream msg;
msg << "Skipping: Only " << va.size() << " verticies in opening mesh.";
IFCImporter::LogDebug(msg.str().c_str());
ok = false;
return contour;
}
for(const IfcVector3& xx : mesh->mVerts) {
IfcVector3 vv = planeSpace * xx,vv_extr = planeSpace * (xx + extrusionDir);
const bool is_extruded_side = std::fabs(vv.z - planeOffset) > std::fabs(vv_extr.z - planeOffset);
if(first) {
first = false;
if(dot > 0.f) {
wall_extrusion = extrusionDir;
if(is_extruded_side) {
wall_extrusion = -wall_extrusion;
}
}
}
// XXX should not be necessary - but it is. Why? For precision reasons?
vv = is_extruded_side ? vv_extr : vv;
contour.push_back(IfcVector2(vv.x,vv.y));
}
ok = true;
return contour;
}
const float close { 1e-6f };
static bool isClose(IfcVector2 first,IfcVector2 second) {
auto diff = (second - first);
return (std::fabs(diff.x) < close && std::fabs(diff.y) < close);
}
static void logSegment(std::pair<IfcVector2,IfcVector2> segment) {
std::stringstream msg2;
msg2 << " Segment: \n";
msg2 << " " << segment.first.x << " " << segment.first.y << " \n";
msg2 << " " << segment.second.x << " " << segment.second.y << " \n";
IFCImporter::LogInfo(msg2.str().c_str());
}
std::vector<std::vector<IfcVector2>> GetContoursInPlane3D(std::shared_ptr<TempMesh> mesh,IfcMatrix3 planeSpace,
IfcFloat planeOffset) {
{
std::stringstream msg;
msg << "GetContoursInPlane3D: planeSpace is \n";
msg << planeSpace.a1 << " " << planeSpace.a2 << " " << planeSpace.a3 << " " << "\n";
msg << planeSpace.b1 << " " << planeSpace.b2 << " " << planeSpace.b3 << " " << "\n";
msg << planeSpace.c1 << " " << planeSpace.c2 << " " << planeSpace.c3 << " " << "\n";
msg << "\n planeOffset is " << planeOffset;
IFCImporter::LogInfo(msg.str().c_str());
}
// we'll put our line segments in here, and then merge them together into contours later
std::deque<std::pair<IfcVector2,IfcVector2>> lineSegments;
// find the lines giving the intersection of the faces with the plane - we'll work in planeSpace throughout.
size_t vI0{ 0 }; // vertex index for first vertex in plane
for(auto nVertices : mesh->mVertcnt) { // iterate over faces
{
std::stringstream msg;
msg << "GetContoursInPlane3D: face (transformed) is \n";
for(auto vI = vI0; vI < vI0 + nVertices; vI++) {
auto v = planeSpace * mesh->mVerts[vI];
msg << " " << v.x << " " << v.y << " " << v.z << " " << "\n";
}
IFCImporter::LogInfo(msg.str().c_str());
}
if(nVertices <= 2) // not a plane, a point or line
{
std::stringstream msg;
msg << "GetContoursInPlane3D: found point or line when expecting plane (only " << nVertices << " vertices)";
IFCImporter::LogWarn(msg.str().c_str());
vI0 += nVertices;
continue;
}
auto v0 = planeSpace * mesh->mVerts[vI0];
// now calculate intersections between face and plane
IfcVector2 firstPoint;
bool gotFirstPoint(false);
if(std::fabs(v0.z - planeOffset) < close) {
// first point is on the plane
firstPoint.x = v0.x;
firstPoint.y = v0.y;
gotFirstPoint = true;
}
auto vn = v0;
for(auto vI = vI0 + 1; vI < vI0 + nVertices; vI++) {
auto vp = vn;
vn = planeSpace * mesh->mVerts[vI];
IfcVector3 intersection;
if(std::fabs(vn.z - planeOffset) < close) {
// on the plane
intersection = vn;
}
else if((vn.z > planeOffset) != (vp.z > planeOffset))
{
// passes through the plane
auto vdir = vn - vp;
auto scale = (planeOffset - vp.z) / vdir.z;
intersection = vp + scale * vdir;
}
else {
// nowhere near - move on
continue;
}
if(!gotFirstPoint) {
if(std::fabs(vp.z - planeOffset) < close) {
// just had a second line along the plane
firstPoint.x = vp.x;
firstPoint.y = vp.y;
IfcVector2 secondPoint(intersection.x,intersection.y);
auto s = std::pair<IfcVector2,IfcVector2>(firstPoint,secondPoint);
logSegment(s);
lineSegments.push_back(s);
// next firstpoint should be this one
}
else {
// store the first intersection point
firstPoint.x = intersection.x;
firstPoint.y = intersection.y;
gotFirstPoint = true;
}
}
else {
// now got the second point, so store the pair
IfcVector2 secondPoint(intersection.x,intersection.y);
auto s = std::pair<IfcVector2,IfcVector2>(firstPoint,secondPoint);
logSegment(s);
lineSegments.push_back(s);
// - note that we don't move onto the next face as a non-convex face can create two or more intersections with a plane
gotFirstPoint = false;
}
}
if(gotFirstPoint) {
IFCImporter::LogWarn("GetContoursInPlane3D: odd number of intersections with plane");
}
vI0 += nVertices;
}
{
std::stringstream msg;
msg << "GetContoursInPlane3D: found " << lineSegments.size() << " line segments:\n";
IFCImporter::LogInfo(msg.str().c_str());
for(auto& s : lineSegments) {
logSegment(s);
}
}
// now merge contours until we have the best-looking polygons we can
std::vector<Contour> contours;
while(!lineSegments.empty()) {
// start with a polygon and make the best closed contour we can
const auto& firstSeg = lineSegments.front();
std::deque<IfcVector2> contour{ firstSeg.first, firstSeg.second };
lineSegments.pop_front();
bool foundNextPoint{ true };
bool closedContour{ false };
while(foundNextPoint) {
foundNextPoint = false;
for(auto nextSeg = lineSegments.begin(); nextSeg != lineSegments.end(); nextSeg++) {
// see if we can match up both ends - in which case we've closed the contour
if((isClose(contour.front(),nextSeg->first) && isClose(contour.back(),nextSeg->second)) ||
(isClose(contour.back(),nextSeg->first) && isClose(contour.front(),nextSeg->second))
) {
lineSegments.erase(nextSeg);
closedContour = true;
break;
}
// otherwise, see if we can match up either end
foundNextPoint = true;
if(isClose(contour.front(),nextSeg->first)) {
contour.push_front(nextSeg->second);
}
else if(isClose(contour.front(),nextSeg->second)) {
contour.push_front(nextSeg->first);
}
else if(isClose(contour.back(),nextSeg->first)) {
contour.push_back(nextSeg->second);
}
else if(isClose(contour.back(),nextSeg->second)) {
contour.push_back(nextSeg->first);
}
else {
foundNextPoint = false;
}
if(foundNextPoint) {
lineSegments.erase(nextSeg);
break;
}
}
}
if(!closedContour) {
IFCImporter::LogWarn("GetContoursInPlane3D: did not close contour");
}
// now add the contour if we can
if(contour.size() <= 2) {
IFCImporter::LogWarn("GetContoursInPlane3D: discarding line/point contour");
continue;
}
Contour c{};
for(auto p : contour)
{
c.push_back(p);
}
contours.push_back(c);
}
{
std::stringstream msg;
msg << "GetContoursInPlane3D: found " << contours.size() << " contours:\n";
for(auto c : contours) {
msg << " Contour: \n";
for(auto p : c) {
msg << " " << p.x << " " << p.y << " \n";
}
}
IFCImporter::LogInfo(msg.str().c_str());
}
return contours;
}
std::vector<std::vector<IfcVector2>> GetContoursInPlane(std::shared_ptr<TempMesh> mesh,IfcMatrix3 planeSpace,
IfcVector3 planeNor,IfcFloat planeOffset,
IfcVector3 extrusionDir,IfcVector3& wall_extrusion,bool& first) {
if(mesh->mVertcnt.size() == 1)
{
bool ok;
auto contour = GetContourInPlane2D(mesh,planeSpace,planeNor,planeOffset,extrusionDir,wall_extrusion,first,ok);
if(ok)
return std::vector<std::vector<IfcVector2>> {contour};
else
return std::vector<std::vector<IfcVector2>> {};
}
else
{
return GetContoursInPlane3D(mesh,planeSpace,planeOffset);
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std::vector<IfcVector3>& nors, bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,
TempMesh& curmesh) TempMesh& curmesh)
{ {
IFCImporter::LogWarn("forced to use poly2tri fallback method to generate wall openings"); IFCImporter::LogWarn("forced to use poly2tri fallback method to generate wall openings");
@ -1498,61 +1780,41 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
try { try {
ClipperLib::Clipper clipper_holes; ClipperLib::Clipper clipper_holes;
size_t c = 0;
for(const TempOpening& t :openings) { for(const TempOpening& t : openings) {
const IfcVector3& outernor = nors[c++]; auto contours = GetContoursInPlane(t.profileMesh,m,nor,coord,t.extrusionDir,wall_extrusion,first);
const IfcFloat dot = nor * outernor;
if (std::fabs(dot)<1.f-1e-6f) {
continue;
}
const std::vector<IfcVector3>& va = t.profileMesh->mVerts; for(auto& contour : contours) {
if(va.size() <= 2) { // scale to clipping space
continue; ClipperLib::Polygon hole;
} for(IfcVector2& pip : contour) {
pip.x = (pip.x - vmin.x) / vmax.x;
pip.y = (pip.y - vmin.y) / vmax.y;
std::vector<IfcVector2> contour; hole.push_back(ClipperLib::IntPoint(to_int64(pip.x),to_int64(pip.y)));
for(const IfcVector3& xx : t.profileMesh->mVerts) {
IfcVector3 vv = m * xx, vv_extr = m * (xx + t.extrusionDir);
const bool is_extruded_side = std::fabs(vv.z - coord) > std::fabs(vv_extr.z - coord);
if (first) {
first = false;
if (dot > 0.f) {
wall_extrusion = t.extrusionDir;
if (is_extruded_side) {
wall_extrusion = - wall_extrusion;
}
}
} }
// XXX should not be necessary - but it is. Why? For precision reasons? if(!ClipperLib::Orientation(hole)) {
vv = is_extruded_side ? vv_extr : vv; std::reverse(hole.begin(),hole.end());
contour.push_back(IfcVector2(vv.x,vv.y)); // assert(ClipperLib::Orientation(hole));
}
/*ClipperLib::Polygons pol_temp(1), pol_temp2(1);
pol_temp[0] = hole;
ClipperLib::OffsetPolygons(pol_temp,pol_temp2,5.0);
hole = pol_temp2[0];*/
clipper_holes.AddPolygon(hole,ClipperLib::ptSubject);
{
std::stringstream msg;
msg << "- added polygon ";
for(auto elem : hole) {
msg << " (" << elem.X << ", " << elem.Y << ")";
}
IFCImporter::LogDebug(msg.str().c_str());
}
} }
ClipperLib::Polygon hole;
for(IfcVector2& pip : contour) {
pip.x = (pip.x - vmin.x) / vmax.x;
pip.y = (pip.y - vmin.y) / vmax.y;
hole.push_back(ClipperLib::IntPoint( to_int64(pip.x), to_int64(pip.y) ));
}
if (!ClipperLib::Orientation(hole)) {
std::reverse(hole.begin(), hole.end());
// assert(ClipperLib::Orientation(hole));
}
/*ClipperLib::Polygons pol_temp(1), pol_temp2(1);
pol_temp[0] = hole;
ClipperLib::OffsetPolygons(pol_temp,pol_temp2,5.0);
hole = pol_temp2[0];*/
clipper_holes.AddPolygon(hole,ClipperLib::ptSubject);
} }
clipper_holes.Execute(ClipperLib::ctUnion,holes_union, clipper_holes.Execute(ClipperLib::ctUnion,holes_union,

View File

@ -307,7 +307,6 @@ void ProcessBooleanExtrudedAreaSolidDifference(const Schema_2x3::IfcExtrudedArea
// IFCOpenings.cpp // IFCOpenings.cpp
bool GenerateOpenings(std::vector<TempOpening>& openings, bool GenerateOpenings(std::vector<TempOpening>& openings,
const std::vector<IfcVector3>& nors,
TempMesh& curmesh, TempMesh& curmesh,
bool check_intersection, bool check_intersection,
bool generate_connection_geometry, bool generate_connection_geometry,

View File

@ -0,0 +1,322 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2021, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
#include <assimp/DefaultIOSystem.h>
#include <assimp/IOStreamBuffer.h>
#include <assimp/ai_assert.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/ByteSwapper.h>
#include <memory>
#include <numeric>
#include "IQMImporter.h"
#include "iqm.h"
// RESOURCES:
// http://sauerbraten.org/iqm/
// https://github.com/lsalzman/iqm
inline void swap_block( uint32_t *block, size_t size ){
(void)block; // suppress 'unreferenced formal parameter' MSVC warning
size >>= 2;
for ( size_t i = 0; i < size; ++i )
AI_SWAP4( block[ i ] );
}
static const aiImporterDesc desc = {
"Inter-Quake Model Importer",
"",
"",
"",
aiImporterFlags_SupportBinaryFlavour,
0,
0,
0,
0,
"iqm"
};
namespace Assimp {
// ------------------------------------------------------------------------------------------------
// Default constructor
IQMImporter::IQMImporter() :
mScene(nullptr) {
// empty
}
// ------------------------------------------------------------------------------------------------
// Returns true, if file is a binary Inter-Quake Model file.
bool IQMImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
const std::string extension = GetExtension(pFile);
if (extension == "iqm")
return true;
else if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
/*
* don't use CheckMagicToken because that checks with swapped bytes too, leading to false
* positives. This magic is not uint32_t, but char[4], so memcmp is the best way
const char* tokens[] = {"3DMO", "3dmo"};
return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
*/
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
unsigned char data[15];
if (!pStream || 15 != pStream->Read(data, 1, 15)) {
return false;
}
return !memcmp(data, "INTERQUAKEMODEL", 15);
}
return false;
}
// ------------------------------------------------------------------------------------------------
const aiImporterDesc *IQMImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Model 3D import implementation
void IQMImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
// Read file into memory
std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
if (!pStream.get()) {
throw DeadlyImportError("Failed to open file ", file, ".");
}
// Get the file-size and validate it, throwing an exception when fails
const size_t fileSize = pStream->FileSize();
if (fileSize < sizeof( iqmheader )) {
throw DeadlyImportError("IQM-file ", file, " is too small.");
}
std::vector<unsigned char> buffer(fileSize);
unsigned char *data = buffer.data();
if (fileSize != pStream->Read(data, 1, fileSize)) {
throw DeadlyImportError("Failed to read the file ", file, ".");
}
// get header
iqmheader &hdr = reinterpret_cast<iqmheader&>( *data );
swap_block( &hdr.version, sizeof( iqmheader ) - sizeof( iqmheader::magic ) );
// extra check for header
if (memcmp(data, IQM_MAGIC, sizeof( IQM_MAGIC ) )
|| hdr.version != IQM_VERSION
|| hdr.filesize != fileSize) {
throw DeadlyImportError("Bad binary header in file ", file, ".");
}
ASSIMP_LOG_DEBUG("IQM: loading ", file);
// create the root node
pScene->mRootNode = new aiNode( "<IQMRoot>" );
// Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
pScene->mRootNode->mTransformation = aiMatrix4x4(
1.f, 0.f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
0.f, -1.f, 0.f, 0.f,
0.f, 0.f, 0.f, 1.f);
pScene->mRootNode->mNumMeshes = hdr.num_meshes;
pScene->mRootNode->mMeshes = new unsigned int[hdr.num_meshes];
std::iota( pScene->mRootNode->mMeshes, pScene->mRootNode->mMeshes + pScene->mRootNode->mNumMeshes, 0 );
mScene = pScene;
// Allocate output storage
pScene->mNumMeshes = 0;
pScene->mMeshes = new aiMesh *[hdr.num_meshes](); // Set arrays to zero to ensue proper destruction if an exception is raised
pScene->mNumMaterials = 0;
pScene->mMaterials = new aiMaterial *[hdr.num_meshes]();
// swap vertex arrays beforehand...
for( auto array = reinterpret_cast<iqmvertexarray*>( data + hdr.ofs_vertexarrays ), end = array + hdr.num_vertexarrays; array != end; ++array )
{
swap_block( &array->type, sizeof( iqmvertexarray ) );
}
// Read all surfaces from the file
for( auto imesh = reinterpret_cast<iqmmesh*>( data + hdr.ofs_meshes ), end_ = imesh + hdr.num_meshes; imesh != end_; ++imesh )
{
swap_block( &imesh->name, sizeof( iqmmesh ) );
// Allocate output mesh & material
auto mesh = pScene->mMeshes[pScene->mNumMeshes++] = new aiMesh();
mesh->mMaterialIndex = pScene->mNumMaterials;
auto mat = pScene->mMaterials[pScene->mNumMaterials++] = new aiMaterial();
{
auto text = reinterpret_cast<char*>( data + hdr.ofs_text );
aiString name( text + imesh->material );
mat->AddProperty( &name, AI_MATKEY_NAME );
mat->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE(0) );
}
// Fill mesh information
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
mesh->mNumFaces = 0;
mesh->mFaces = new aiFace[imesh->num_triangles];
// Fill in all triangles
for( auto tri = reinterpret_cast<iqmtriangle*>( data + hdr.ofs_triangles ) + imesh->first_triangle, end = tri + imesh->num_triangles; tri != end; ++tri )
{
swap_block( tri->vertex, sizeof( tri->vertex ) );
auto& face = mesh->mFaces[mesh->mNumFaces++];
face.mNumIndices = 3;
face.mIndices = new unsigned int[3]{ tri->vertex[0] - imesh->first_vertex,
tri->vertex[2] - imesh->first_vertex,
tri->vertex[1] - imesh->first_vertex };
}
// Fill in all vertices
for( auto array = reinterpret_cast<const iqmvertexarray*>( data + hdr.ofs_vertexarrays ), end__ = array + hdr.num_vertexarrays; array != end__; ++array )
{
const unsigned int nVerts = imesh->num_vertexes;
const unsigned int step = array->size;
switch ( array->type )
{
case IQM_POSITION:
if( array->format == IQM_FLOAT && step >= 3 ){
mesh->mNumVertices = nVerts;
auto v = mesh->mVertices = new aiVector3D[nVerts];
for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
end = f + nVerts * step; f != end; f += step, ++v )
{
*v = { AI_BE( f[0] ),
AI_BE( f[1] ),
AI_BE( f[2] ) };
}
}
break;
case IQM_TEXCOORD:
if( array->format == IQM_FLOAT && step >= 2)
{
auto v = mesh->mTextureCoords[0] = new aiVector3D[nVerts];
mesh->mNumUVComponents[0] = 2;
for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
end = f + nVerts * step; f != end; f += step, ++v )
{
*v = { AI_BE( f[0] ),
1 - AI_BE( f[1] ), 0 };
}
}
break;
case IQM_NORMAL:
if (array->format == IQM_FLOAT && step >= 3)
{
auto v = mesh->mNormals = new aiVector3D[nVerts];
for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
end = f + nVerts * step; f != end; f += step, ++v )
{
*v = { AI_BE( f[0] ),
AI_BE( f[1] ),
AI_BE( f[2] ) };
}
}
break;
case IQM_COLOR:
if (array->format == IQM_UBYTE && step >= 3)
{
auto v = mesh->mColors[0] = new aiColor4D[nVerts];
for( auto f = ( data + array->offset ) + imesh->first_vertex * step,
end = f + nVerts * step; f != end; f += step, ++v )
{
*v = { ( f[0] ) / 255.f,
( f[1] ) / 255.f,
( f[2] ) / 255.f,
step == 3? 1 : ( f[3] ) / 255.f };
}
}
else if (array->format == IQM_FLOAT && step >= 3)
{
auto v = mesh->mColors[0] = new aiColor4D[nVerts];
for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
end = f + nVerts * step; f != end; f += step, ++v )
{
*v = { AI_BE( f[0] ),
AI_BE( f[1] ),
AI_BE( f[2] ),
step == 3? 1 : AI_BE( f[3] ) };
}
}
break;
case IQM_TANGENT:
#if 0
if (array->format == IQM_FLOAT && step >= 3)
{
auto v = mesh->mTangents = new aiVector3D[nVerts];
for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
end = f + nVerts * step; f != end; f += step, ++v )
{
*v = { AI_BE( f[0] ),
AI_BE( f[1] ),
AI_BE( f[2] ) };
}
}
#endif
break;
case IQM_BLENDINDEXES:
case IQM_BLENDWEIGHTS:
case IQM_CUSTOM:
break; // these attributes are not relevant.
default:
break;
}
}
}
}
// ------------------------------------------------------------------------------------------------
} // Namespace Assimp
#endif // !! ASSIMP_BUILD_NO_IQM_IMPORTER

View File

@ -0,0 +1,78 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2021, 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 IQMImporter.h
* @brief Declares the importer class to read a scene from an Inter-Quake Model file
*/
#pragma once
#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
#include <assimp/BaseImporter.h>
#include <assimp/material.h>
namespace Assimp {
class IQMImporter : public BaseImporter {
public:
/// \brief Default constructor
IQMImporter();
~IQMImporter() override {}
/// \brief Returns whether the class can handle the format of the given file.
/// \remark See BaseImporter::CanRead() for details.
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected:
//! \brief Appends the supported extension.
const aiImporterDesc *GetInfo() const override;
//! \brief File import implementation.
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
private:
aiScene *mScene = nullptr; // the scene to import to
};
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_IQM_IMPORTER

View File

@ -0,0 +1,134 @@
#ifndef __IQM_H__
#define __IQM_H__
#define IQM_MAGIC "INTERQUAKEMODEL"
#define IQM_VERSION 2
struct iqmheader
{
char magic[16];
unsigned int version;
unsigned int filesize;
unsigned int flags;
unsigned int num_text, ofs_text;
unsigned int num_meshes, ofs_meshes;
unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
unsigned int num_triangles, ofs_triangles, ofs_adjacency;
unsigned int num_joints, ofs_joints;
unsigned int num_poses, ofs_poses;
unsigned int num_anims, ofs_anims;
unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
unsigned int num_comment, ofs_comment;
unsigned int num_extensions, ofs_extensions;
};
struct iqmmesh
{
unsigned int name;
unsigned int material;
unsigned int first_vertex, num_vertexes;
unsigned int first_triangle, num_triangles;
};
enum
{
IQM_POSITION = 0,
IQM_TEXCOORD = 1,
IQM_NORMAL = 2,
IQM_TANGENT = 3,
IQM_BLENDINDEXES = 4,
IQM_BLENDWEIGHTS = 5,
IQM_COLOR = 6,
IQM_CUSTOM = 0x10
};
enum
{
IQM_BYTE = 0,
IQM_UBYTE = 1,
IQM_SHORT = 2,
IQM_USHORT = 3,
IQM_INT = 4,
IQM_UINT = 5,
IQM_HALF = 6,
IQM_FLOAT = 7,
IQM_DOUBLE = 8
};
struct iqmtriangle
{
unsigned int vertex[3];
};
struct iqmadjacency
{
unsigned int triangle[3];
};
struct iqmjointv1
{
unsigned int name;
int parent;
float translate[3], rotate[3], scale[3];
};
struct iqmjoint
{
unsigned int name;
int parent;
float translate[3], rotate[4], scale[3];
};
struct iqmposev1
{
int parent;
unsigned int mask;
float channeloffset[9];
float channelscale[9];
};
struct iqmpose
{
int parent;
unsigned int mask;
float channeloffset[10];
float channelscale[10];
};
struct iqmanim
{
unsigned int name;
unsigned int first_frame, num_frames;
float framerate;
unsigned int flags;
};
enum
{
IQM_LOOP = 1<<0
};
struct iqmvertexarray
{
unsigned int type;
unsigned int flags;
unsigned int format;
unsigned int size;
unsigned int offset;
};
struct iqmbounds
{
float bbmin[3], bbmax[3];
float xyradius, radius;
};
struct iqmextension
{
unsigned int name;
unsigned int num_data, ofs_data;
unsigned int ofs_extensions; // pointer to next extension
};
#endif

View File

@ -94,23 +94,9 @@ IRRImporter::~IRRImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const char *tokens[] = { "irr_scene" };
if (extension == "irr") { return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
return true;
} else if (extension == "xml" || checkSig) {
/* If CanRead() is called in order to check whether we
* support a specific file extension in general pIOHandler
* might be nullptr and it's our duty to return true here.
*/
if (nullptr == pIOHandler) {
return true;
}
static const char * const tokens[] = { "irr_scene" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -85,26 +83,14 @@ IRRMeshImporter::~IRRMeshImporter() {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
/* NOTE: A simple check for the file extension is not enough /* NOTE: A simple check for the file extension is not enough
* here. Irrmesh and irr are easy, but xml is too generic * here. Irrmesh and irr are easy, but xml is too generic
* and could be collada, too. So we need to open the file and * and could be collada, too. So we need to open the file and
* search for typical tokens. * search for typical tokens.
*/ */
const std::string extension = GetExtension(pFile); static const char *tokens[] = { "irrmesh" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "irrmesh")
return true;
else if (extension == "xml" || checkSig) {
/* If CanRead() is called to check whether the loader
* supports a specific file extension in general we
* must return true here.
*/
if (!pIOHandler) return true;
static const char * const tokens[] = { "irrmesh" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -105,21 +105,13 @@ LWOImporter::~LWOImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool checkSig) const { bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(file); static const uint32_t tokens[] = {
if (extension == "lwo" || extension == "lxo") { AI_LWO_FOURCC_LWOB,
return true; AI_LWO_FOURCC_LWO2,
} AI_LWO_FOURCC_LXOB
};
// if check for extension is not enough, check for the magic tokens return CheckMagicToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens), 8);
if (!extension.length() || checkSig) {
uint32_t tokens[3];
tokens[0] = AI_LWO_FOURCC_LWOB;
tokens[1] = AI_LWO_FOURCC_LWO2;
tokens[2] = AI_LWO_FOURCC_LXOB;
return CheckMagicToken(pIOHandler, file, tokens, 3, 8);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -147,20 +147,12 @@ LWSImporter::~LWSImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const uint32_t tokens[] = {
if (extension == "lws" || extension == "mot") { AI_MAKE_MAGIC("LWSC"),
return true; AI_MAKE_MAGIC("LWMO")
} };
return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
// if check for extension is not enough, check for the magic tokens LWSC and LWMO
if (!extension.length() || checkSig) {
uint32_t tokens[2];
tokens[0] = AI_MAKE_MAGIC("LWSC");
tokens[1] = AI_MAKE_MAGIC("LWMO");
return CheckMagicToken(pIOHandler, pFile, tokens, 2);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -111,34 +111,19 @@ M3DImporter::M3DImporter() :
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if file is a binary or ASCII Model 3D file. // Returns true, if file is a binary or ASCII Model 3D file.
bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); // don't use CheckMagicToken because that checks with swapped bytes too, leading to false
// positives. This magic is not uint32_t, but char[4], so memcmp is the best way
if (extension == "m3d" std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
|| extension == "a3d" unsigned char data[4];
) if (4 != pStream->Read(data, 1, 4)) {
return true; return false;
else if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
/*
* don't use CheckMagicToken because that checks with swapped bytes too, leading to false
* positives. This magic is not uint32_t, but char[4], so memcmp is the best way
const char* tokens[] = {"3DMO", "3dmo"};
return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
*/
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
unsigned char data[4];
if (!pStream || 4 != pStream->Read(data, 1, 4)) {
return false;
}
return !memcmp(data, "3DMO", 4) /* bin */
|| !memcmp(data, "3dmo", 4) /* ASCII */
;
} }
return false; return !memcmp(data, "3DMO", 4) /* bin */
#ifdef M3D_ASCII
|| !memcmp(data, "3dmo", 4) /* ASCII */
#endif
;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -107,19 +107,10 @@ MD2Importer::~MD2Importer()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
{ {
const std::string extension = GetExtension(pFile); static const uint32_t tokens[] = { AI_MD2_MAGIC_NUMBER_LE };
if (extension == "md2") return CheckMagicToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
return true;
// if check for extension is not enough, check for the magic tokens
if (!extension.length() || checkSig) {
uint32_t tokens[1];
tokens[0] = AI_MD2_MAGIC_NUMBER_LE;
return CheckMagicToken(pIOHandler,pFile,tokens,1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -349,18 +349,9 @@ MD3Importer::~MD3Importer() {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MD3Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool MD3Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const uint32_t tokens[] = { AI_MD3_MAGIC_NUMBER_LE };
if (extension == "md3") return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
return true;
// if check for extension is not enough, check for the magic tokens
if (!extension.length() || checkSig) {
uint32_t tokens[1];
tokens[0] = AI_MD3_MAGIC_NUMBER_LE;
return CheckMagicToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -100,20 +100,9 @@ MD5Importer::~MD5Importer() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const char *tokens[] = { "MD5Version" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "md5anim" || extension == "md5mesh" || extension == "md5camera")
return true;
else if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
static const char * const tokens[] = { "MD5Version" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -111,19 +111,9 @@ MDCImporter::~MDCImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const uint32_t tokens[] = { AI_MDC_MAGIC_NUMBER_LE };
if (extension == "mdc") { return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
return true;
}
// if check for extension is not enough, check for the magic tokens
if (!extension.length() || checkSig) {
uint32_t tokens[1];
tokens[0] = AI_MDC_MAGIC_NUMBER_LE;
return CheckMagicToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -104,23 +104,18 @@ MDLImporter::~MDLImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const uint32_t tokens[] = {
AI_MDL_MAGIC_NUMBER_LE_HL2a,
// if check for extension is not enough, check for the magic tokens AI_MDL_MAGIC_NUMBER_LE_HL2b,
if (extension == "mdl" || !extension.length() || checkSig) { AI_MDL_MAGIC_NUMBER_LE_GS7,
uint32_t tokens[8]; AI_MDL_MAGIC_NUMBER_LE_GS5b,
tokens[0] = AI_MDL_MAGIC_NUMBER_LE_HL2a; AI_MDL_MAGIC_NUMBER_LE_GS5a,
tokens[1] = AI_MDL_MAGIC_NUMBER_LE_HL2b; AI_MDL_MAGIC_NUMBER_LE_GS4,
tokens[2] = AI_MDL_MAGIC_NUMBER_LE_GS7; AI_MDL_MAGIC_NUMBER_LE_GS3,
tokens[3] = AI_MDL_MAGIC_NUMBER_LE_GS5b; AI_MDL_MAGIC_NUMBER_LE
tokens[4] = AI_MDL_MAGIC_NUMBER_LE_GS5a; };
tokens[5] = AI_MDL_MAGIC_NUMBER_LE_GS4; return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
tokens[6] = AI_MDL_MAGIC_NUMBER_LE_GS3;
tokens[7] = AI_MDL_MAGIC_NUMBER_LE;
return CheckMagicToken(pIOHandler, pFile, tokens, 8, 0);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -89,14 +89,9 @@ MMDImporter::~MMDImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if file is an pmx file. // Returns true, if file is an pmx file.
bool MMDImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool MMDImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler,
bool checkSig) const { bool /*checkSig*/) const {
if (!checkSig) { static const char *tokens[] = { "PMX " };
return SimpleExtensionCheck(pFile, "pmx"); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
} else {
// Check file Header
static const char * const pTokens[] = { "PMX " };
return SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 1);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -88,26 +88,12 @@ MS3DImporter::MS3DImporter()
// Destructor, private as well // Destructor, private as well
MS3DImporter::~MS3DImporter() MS3DImporter::~MS3DImporter()
{} {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
{ {
// first call - simple extension check static const char* tokens[] = { "MS3D000000" };
const std::string extension = GetExtension(pFile); return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
if (extension == "ms3d") {
return true;
}
// second call - check for magic identifiers
else if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
static const char * const tokens[] = {"MS3D000000"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -82,19 +80,10 @@ NDOImporter::~NDOImporter()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool NDOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool NDOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
{ {
// check file extension static const char* tokens[] = {"nendo"};
const std::string extension = GetExtension(pFile); return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens),5);
if( extension == "ndo")
return true;
if ((checkSig || !extension.length()) && pIOHandler) {
static const char * const tokens[] = {"nendo"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,5);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -83,7 +81,7 @@ NFFImporter::~NFFImporter() {}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool NFFImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { bool NFFImporter::CanRead(const std::string & pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
return SimpleExtensionCheck(pFile, "nff", "enff"); return SimpleExtensionCheck(pFile, "nff", "enff");
} }

View File

@ -83,19 +83,10 @@ OFFImporter::~OFFImporter()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
{ {
const std::string extension = GetExtension(pFile); static const char* tokens[] = { "off" };
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens),3);
if (extension == "off")
return true;
else if (!extension.length() || checkSig)
{
if (!pIOHandler)return true;
static const char * const tokens[] = {"off"};
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,3);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -87,16 +87,10 @@ ObjFileImporter::~ObjFileImporter() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if file is an obj file. // Returns true if file is an obj file.
bool ObjFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool ObjFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
if (!checkSig) { static const char *tokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
//Check File Extension return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens), 200, false, true);
return SimpleExtensionCheck(pFile, "obj");
} else {
// Check file Header
static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9, 200, false, true);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -73,14 +73,10 @@ void OgreImporter::SetupProperties(const Importer *pImp) {
m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false); m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
} }
bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const { bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool /*checkSig*/) const {
if (!checkSig) {
return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false);
}
if (EndsWith(pFile, ".mesh.xml", false)) { if (EndsWith(pFile, ".mesh.xml", false)) {
static const char * const tokens[] = { "<mesh>" }; static const char *tokens[] = { "<mesh>" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
} }
/// @todo Read and validate first header chunk? /// @todo Read and validate first header chunk?

View File

@ -290,16 +290,9 @@ OpenGEXImporter::~OpenGEXImporter() {
} }
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------
bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool checkSig) const { bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
bool canRead(false); static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
if (!checkSig) { return SearchFileHeaderForToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens));
canRead = SimpleExtensionCheck(file, "ogex");
} else {
static const char * const token[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
canRead = SearchFileHeaderForToken(pIOHandler, file, token, 4);
}
return canRead;
} }
//------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------

View File

@ -100,24 +100,9 @@ PLYImporter::~PLYImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const char *tokens[] = { "ply" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "ply") {
return true;
}
if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
static const char * const tokens[] = {
"ply"
};
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -156,12 +156,11 @@ Q3BSPFileImporter::~Q3BSPFileImporter() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if the loader can read this. // Returns true if the loader can read this.
bool Q3BSPFileImporter::CanRead(const std::string &rFile, IOSystem * /*pIOHandler*/, bool checkSig) const { bool Q3BSPFileImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool checkSig) const {
if (!checkSig) { if (!checkSig) {
return SimpleExtensionCheck(rFile, "pk3", "bsp"); return SimpleExtensionCheck(filename, "pk3", "bsp");
} }
return false; return false;
} }

View File

@ -84,18 +84,9 @@ Q3DImporter::~Q3DImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Q3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool Q3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const char *tokens[] = { "quick3Do", "quick3Ds" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "q3s" || extension == "q3o")
return true;
else if (!extension.length() || checkSig) {
if (!pIOHandler)
return true;
static const char * const tokens[] = { "quick3Do", "quick3Ds" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -84,8 +84,8 @@ RAWImporter::~RAWImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool RAWImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { bool RAWImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
return SimpleExtensionCheck(pFile, "raw"); return SimpleExtensionCheck(filename, "raw");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -61,7 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef ASSIMP_USE_HUNTER #ifdef ASSIMP_USE_HUNTER
#include <utf8.h> #include <utf8.h>
#else #else
//# include "../contrib/ConvertUTF/ConvertUTF.h"
#include "../contrib/utf8cpp/source/utf8.h" #include "../contrib/utf8cpp/source/utf8.h"
#endif #endif
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
@ -217,8 +214,8 @@ SIBImporter::~SIBImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool SIBImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { bool SIBImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
return SimpleExtensionCheck(pFile, "sib"); return SimpleExtensionCheck(filename, "sib");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -81,15 +81,15 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
SMDImporter::SMDImporter() SMDImporter::SMDImporter() :
: configFrameID() configFrameID(),
, mBuffer() mBuffer(),
, pScene( nullptr ) pScene( nullptr ),
, iFileSize( 0 ) iFileSize( 0 ),
, iSmallestFrame( INT_MAX ) iSmallestFrame( INT_MAX ),
, dLengthOfAnim( 0.0 ) dLengthOfAnim( 0.0 ),
, bHasUVs(false ) bHasUVs(false ),
, iLineNumber((unsigned int)-1) { iLineNumber((unsigned int)-1) {
// empty // empty
} }
@ -101,9 +101,8 @@ SMDImporter::~SMDImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool SMDImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool) const { bool SMDImporter::CanRead( const std::string& filename, IOSystem* /*pIOHandler*/, bool) const {
// fixme: auto format detection return SimpleExtensionCheck(filename, "smd", "vta");
return SimpleExtensionCheck(pFile,"smd","vta");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -140,22 +140,9 @@ STLImporter::~STLImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
const std::string extension = GetExtension(pFile); static const char *tokens[] = { "STL", "solid" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "stl") {
return true;
}
if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
static const char * const tokens[] = { "STL", "solid" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -81,27 +81,9 @@ TerragenImporter::~TerragenImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool TerragenImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool TerragenImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
// check file extension static const char *tokens[] = { "terragen" };
std::string extension = GetExtension(pFile); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
if (extension == "ter")
return true;
if (!extension.length() || checkSig) {
/* If CanRead() is called in order to check whether we
* support a specific file extension in general pIOHandler
* might be nullptr and it's our duty to return true here.
*/
if (!pIOHandler) {
return true;
}
static const char * const tokens[] = { "terragen" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -74,7 +74,7 @@ namespace Unreal {
3 = Masked two-sided 3 = Masked two-sided
4 = Modulation blended two-sided 4 = Modulation blended two-sided
8 = Placeholder triangle for weapon positioning (invisible) 8 = Placeholder triangle for weapon positioning (invisible)
*/ */
enum MeshFlags { enum MeshFlags {
MF_NORMAL_OS = 0, MF_NORMAL_OS = 0,
MF_NORMAL_TS = 1, MF_NORMAL_TS = 1,
@ -168,16 +168,20 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
UnrealImporter::UnrealImporter() : UnrealImporter::UnrealImporter() :
mConfigFrameID(0), mConfigHandleFlags(true) {} mConfigFrameID(0), mConfigHandleFlags(true) {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
UnrealImporter::~UnrealImporter() {} UnrealImporter::~UnrealImporter() {
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool UnrealImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const { bool UnrealImporter::CanRead(const std::string & filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
return SimpleExtensionCheck(pFile, "3d", "uc"); return SimpleExtensionCheck(filename, "3d", "uc");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -88,17 +88,9 @@ XFileImporter::~XFileImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const {
std::string extension = GetExtension(pFile); static const uint32_t token[] = { AI_MAKE_MAGIC("xof ") };
if(extension == "x") { return CheckMagicToken(pIOHandler,pFile,token,AI_COUNT_OF(token));
return true;
}
if (!extension.length() || checkSig) {
uint32_t token[1];
token[0] = AI_MAKE_MAGIC("xof ");
return CheckMagicToken(pIOHandler,pFile,token,1,0);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -104,25 +104,9 @@ XGLImporter::~XGLImporter() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
/* NOTE: A simple check for the file extension is not enough static const char *tokens[] = { "<world>", "<World>", "<WORLD>" };
* here. XGL and ZGL are ok, but xml is too generic return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
* and might be collada as well. So open the file and
* look for typical signal tokens.
*/
const std::string extension = GetExtension(pFile);
if (extension == "xgl" || extension == "zgl") {
return true;
}
if (extension == "xml" || checkSig) {
ai_assert(pIOHandler != nullptr);
static const char * const tokens[] = { "<world>", "<World>", "<WORLD>" };
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 3);
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -93,24 +93,14 @@ const aiImporterDesc *glTFImporter::GetInfo() const {
} }
bool glTFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const { bool glTFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
const std::string &extension = GetExtension(pFile); glTF::Asset asset(pIOHandler);
try {
if (extension != "gltf" && extension != "glb") { asset.Load(pFile, GetExtension(pFile) == "glb");
std::string version = asset.asset.version;
return !version.empty() && version[0] == '1';
} catch (...) {
return false; return false;
} }
if (pIOHandler) {
glTF::Asset asset(pIOHandler);
try {
asset.Load(pFile, extension == "glb");
std::string version = asset.asset.version;
return !version.empty() && version[0] == '1';
} catch (...) {
return false;
}
}
return false;
} }
inline void SetMaterialColorProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/, glTF::TexProperty prop, aiMaterial *mat, inline void SetMaterialColorProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/, glTF::TexProperty prop, aiMaterial *mat,

View File

@ -98,7 +98,7 @@ static const aiImporterDesc desc = {
glTF2Importer::glTF2Importer() : glTF2Importer::glTF2Importer() :
BaseImporter(), BaseImporter(),
meshOffsets(), meshOffsets(),
embeddedTexIdxs(), mEmbeddedTexIdxs(),
mScene(nullptr) { mScene(nullptr) {
// empty // empty
} }
@ -111,21 +111,21 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
return &desc; return &desc;
} }
bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig ) const { bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig ) const {
const std::string &extension = GetExtension(pFile); const std::string extension = GetExtension(filename);
if (!checkSig && (extension != "gltf") && (extension != "glb")) {
return false;
}
if (!checkSig && (extension != "gltf") && (extension != "glb")) if (pIOHandler) {
return false; glTF2::Asset asset(pIOHandler);
return asset.CanRead(filename, extension == "glb");
if (pIOHandler) { }
glTF2::Asset asset(pIOHandler);
return asset.CanRead(pFile, extension == "glb");
}
return false; return false;
} }
static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) { static inline aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
switch (gltfWrapMode) { switch (gltfWrapMode) {
case SamplerWrap::Mirrored_Repeat: case SamplerWrap::Mirrored_Repeat:
return aiTextureMapMode_Mirror; return aiTextureMapMode_Mirror;
@ -140,21 +140,21 @@ static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
} }
} }
inline void SetMaterialColorProperty(Asset & /*r*/, vec4 &prop, aiMaterial *mat, static inline void SetMaterialColorProperty(Asset & /*r*/, vec4 &prop, aiMaterial *mat,
const char *pKey, unsigned int type, unsigned int idx) { const char *pKey, unsigned int type, unsigned int idx) {
aiColor4D col; aiColor4D col;
CopyValue(prop, col); CopyValue(prop, col);
mat->AddProperty(&col, 1, pKey, type, idx); mat->AddProperty(&col, 1, pKey, type, idx);
} }
inline void SetMaterialColorProperty(Asset & /*r*/, vec3 &prop, aiMaterial *mat, static inline void SetMaterialColorProperty(Asset & /*r*/, vec3 &prop, aiMaterial *mat,
const char *pKey, unsigned int type, unsigned int idx) { const char *pKey, unsigned int type, unsigned int idx) {
aiColor4D col; aiColor4D col;
glTFCommon::CopyValue(prop, col); glTFCommon::CopyValue(prop, col);
mat->AddProperty(&col, 1, pKey, type, idx); mat->AddProperty(&col, 1, pKey, type, idx);
} }
inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/, static void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/,
glTF2::TextureInfo prop, aiMaterial *mat, aiTextureType texType, glTF2::TextureInfo prop, aiMaterial *mat, aiTextureType texType,
unsigned int texSlot = 0) { unsigned int texSlot = 0) {
if (prop.texture && prop.texture->source) { if (prop.texture && prop.texture->source) {
@ -371,10 +371,10 @@ void glTF2Importer::ImportMaterials(Asset &r) {
mScene->mNumMaterials = numImportedMaterials + 1; mScene->mNumMaterials = numImportedMaterials + 1;
mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials]; mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
std::fill(mScene->mMaterials, mScene->mMaterials + mScene->mNumMaterials, nullptr); std::fill(mScene->mMaterials, mScene->mMaterials + mScene->mNumMaterials, nullptr);
mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial); mScene->mMaterials[numImportedMaterials] = ImportMaterial(mEmbeddedTexIdxs, r, defaultMaterial);
for (unsigned int i = 0; i < numImportedMaterials; ++i) { for (unsigned int i = 0; i < numImportedMaterials; ++i) {
mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]); mScene->mMaterials[i] = ImportMaterial(mEmbeddedTexIdxs, r, r.materials[i]);
} }
} }
@ -802,8 +802,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
if (actualNumFaces < nFaces) { if (actualNumFaces < nFaces) {
ASSIMP_LOG_WARN("Some faces had out-of-range indices. Those faces were dropped."); ASSIMP_LOG_WARN("Some faces had out-of-range indices. Those faces were dropped.");
} }
if (actualNumFaces == 0) if (actualNumFaces == 0) {
{
throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces"); throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces");
} }
aim->mNumFaces = actualNumFaces; aim->mNumFaces = actualNumFaces;
@ -843,7 +842,6 @@ void glTF2Importer::ImportCameras(glTF2::Asset &r) {
aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f); aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f);
if (cam.type == Camera::Perspective) { if (cam.type == Camera::Perspective) {
aicam->mAspect = cam.cameraProperties.perspective.aspectRatio; aicam->mAspect = cam.cameraProperties.perspective.aspectRatio;
aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect);
aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar;
@ -862,8 +860,9 @@ void glTF2Importer::ImportCameras(glTF2::Asset &r) {
} }
void glTF2Importer::ImportLights(glTF2::Asset &r) { void glTF2Importer::ImportLights(glTF2::Asset &r) {
if (!r.lights.Size()) if (!r.lights.Size()) {
return; return;
}
const unsigned int numLights = r.lights.Size(); const unsigned int numLights = r.lights.Size();
ASSIMP_LOG_DEBUG("Importing ", numLights, " lights"); ASSIMP_LOG_DEBUG("Importing ", numLights, " lights");
@ -1125,8 +1124,8 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
bone->mNumWeights = static_cast<uint32_t>(weights.size()); bone->mNumWeights = static_cast<uint32_t>(weights.size());
if (bone->mNumWeights > 0) { if (bone->mNumWeights > 0) {
bone->mWeights = new aiVertexWeight[bone->mNumWeights]; bone->mWeights = new aiVertexWeight[bone->mNumWeights];
memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
} else { } else {
// Assimp expects all bones to have at least 1 weight. // Assimp expects all bones to have at least 1 weight.
bone->mWeights = new aiVertexWeight[1]; bone->mWeights = new aiVertexWeight[1];
@ -1167,8 +1166,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
if (!ainode->mMetaData) { if (!ainode->mMetaData) {
ainode->mMetaData = aiMetadata::Alloc(1); ainode->mMetaData = aiMetadata::Alloc(1);
ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
} } else {
else {
ainode->mMetaData->Add("PBR_LightRange", node.light->range.value); ainode->mMetaData->Add("PBR_LightRange", node.light->range.value);
} }
} }
@ -1509,16 +1507,20 @@ void glTF2Importer::ImportAnimations(glTF2::Asset &r) {
} }
} }
void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) { static unsigned int countEmbeddedTextures(glTF2::Asset &r) {
embeddedTexIdxs.resize(r.images.Size(), -1); unsigned int numEmbeddedTexs = 0;
int numEmbeddedTexs = 0;
for (size_t i = 0; i < r.images.Size(); ++i) { for (size_t i = 0; i < r.images.Size(); ++i) {
if (r.images[i].HasData()) { if (r.images[i].HasData()) {
numEmbeddedTexs += 1; numEmbeddedTexs += 1;
} }
} }
return numEmbeddedTexs;
}
void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
mEmbeddedTexIdxs.resize(r.images.Size(), -1);
const unsigned int numEmbeddedTexs = countEmbeddedTextures(r);
if (numEmbeddedTexs == 0) { if (numEmbeddedTexs == 0) {
return; return;
} }
@ -1536,7 +1538,7 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
} }
int idx = mScene->mNumTextures++; int idx = mScene->mNumTextures++;
embeddedTexIdxs[i] = idx; mEmbeddedTexIdxs[i] = idx;
aiTexture *tex = mScene->mTextures[idx] = new aiTexture(); aiTexture *tex = mScene->mTextures[idx] = new aiTexture();
@ -1597,7 +1599,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
// clean all member arrays // clean all member arrays
meshOffsets.clear(); meshOffsets.clear();
embeddedTexIdxs.clear(); mEmbeddedTexIdxs.clear();
this->mScene = pScene; this->mScene = pScene;

View File

@ -79,7 +79,7 @@ private:
private: private:
std::vector<unsigned int> meshOffsets; std::vector<unsigned int> meshOffsets;
std::vector<int> embeddedTexIdxs; std::vector<int> mEmbeddedTexIdxs;
aiScene *mScene; aiScene *mScene;
/// An instance of rapidjson::IRemoteSchemaDocumentProvider /// An instance of rapidjson::IRemoteSchemaDocumentProvider

View File

@ -376,6 +376,12 @@ ADD_ASSIMP_IMPORTER( IRRMESH
AssetLib/Irr/IRRShared.h AssetLib/Irr/IRRShared.h
) )
ADD_ASSIMP_IMPORTER( IQM
AssetLib/IQM/IQMImporter.cpp
AssetLib/IQM/iqm.h
AssetLib/IQM/IQMImporter.h
)
ADD_ASSIMP_IMPORTER( IRR ADD_ASSIMP_IMPORTER( IRR
AssetLib/Irr/IRRLoader.cpp AssetLib/Irr/IRRLoader.cpp
AssetLib/Irr/IRRLoader.h AssetLib/Irr/IRRLoader.h

View File

@ -156,8 +156,8 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
/*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem *pIOHandler, /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem *pIOHandler,
const std::string &pFile, const std::string &pFile,
const char * const *tokens, const char **tokens,
unsigned int numTokens, std::size_t numTokens,
unsigned int searchBytes /* = 200 */, unsigned int searchBytes /* = 200 */,
bool tokensSol /* false */, bool tokensSol /* false */,
bool noAlphaBeforeTokens /* false */) { bool noAlphaBeforeTokens /* false */) {
@ -268,10 +268,11 @@ std::string BaseImporter::GetExtension(const std::string &file) {
return ret; return ret;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check for magic bytes at the beginning of the file. // Check for magic bytes at the beginning of the file.
/* static */ bool BaseImporter::CheckMagicToken(IOSystem *pIOHandler, const std::string &pFile, /* static */ bool BaseImporter::CheckMagicToken(IOSystem *pIOHandler, const std::string &pFile,
const void *_magic, unsigned int num, unsigned int offset, unsigned int size) { const void *_magic, std::size_t num, unsigned int offset, unsigned int size) {
ai_assert(size <= 16); ai_assert(size <= 16);
ai_assert(_magic); ai_assert(_magic);

View File

@ -388,15 +388,16 @@ void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev)
ai_assert(nullptr != message); ai_assert(nullptr != message);
// Check whether this is a repeated message // Check whether this is a repeated message
if (!::strncmp(message, lastMsg, lastLen - 1)) { auto thisLen = ::strlen(message);
if (thisLen == lastLen - 1 && !::strncmp(message, lastMsg, lastLen - 1)) {
if (!noRepeatMsg) { if (!noRepeatMsg) {
noRepeatMsg = true; noRepeatMsg = true;
message = "Skipping one or more lines with the same contents\n"; message = "Skipping one or more lines with the same contents\n";
} else }
return; return;
} else { } else {
// append a new-line character to the message to be printed // append a new-line character to the message to be printed
lastLen = ::strlen(message); lastLen = thisLen;
::memcpy(lastMsg, message, lastLen + 1); ::memcpy(lastMsg, message, lastLen + 1);
::strcat(lastMsg + lastLen, "\n"); ::strcat(lastMsg + lastLen, "\n");

View File

@ -617,29 +617,71 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
profiler->BeginRegion("total"); profiler->BeginRegion("total");
} }
// Find an worker class which can handle the file // Find an worker class which can handle the file extension.
BaseImporter* imp = nullptr; // Multiple importers may be able to handle the same extension (.xml!); gather them all.
SetPropertyInteger("importerIndex", -1); SetPropertyInteger("importerIndex", -1);
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { struct ImporterAndIndex {
BaseImporter * importer;
unsigned int index;
};
std::vector<ImporterAndIndex> possibleImporters;
for (unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
// Every importer has a list of supported extensions.
std::set<std::string> extensions;
pimpl->mImporter[a]->GetExtensionList(extensions);
// CAUTION: Do not just search for the extension!
// GetExtension() returns the part after the *last* dot, but some extensions have dots
// inside them, e.g. ogre.mesh.xml. Compare the entire end of the string.
for (std::set<std::string>::const_iterator it = extensions.cbegin(); it != extensions.cend(); ++it) {
// Yay for C++<20 not having std::string::ends_with()
std::string extension = "." + *it;
if (extension.length() <= pFile.length()) {
// Possible optimization: Fetch the lowercase filename!
if (0 == ASSIMP_stricmp(pFile.c_str() + pFile.length() - extension.length(), extension.c_str())) {
ImporterAndIndex candidate = { pimpl->mImporter[a], a };
possibleImporters.push_back(candidate);
break;
}
}
if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
imp = pimpl->mImporter[a];
SetPropertyInteger("importerIndex", a);
break;
} }
}
// If just one importer supports this extension, pick it and close the case.
BaseImporter* imp = nullptr;
if (1 == possibleImporters.size()) {
imp = possibleImporters[0].importer;
SetPropertyInteger("importerIndex", possibleImporters[0].index);
}
// If multiple importers claim this file extension, ask them to look at the actual file data to decide.
// This can happen e.g. with XML (COLLADA vs. Irrlicht).
else {
for (std::vector<ImporterAndIndex>::const_iterator it = possibleImporters.begin(); it < possibleImporters.end(); ++it) {
BaseImporter & importer = *it->importer;
ASSIMP_LOG_INFO("Found a possible importer: " + std::string(importer.GetInfo()->mName) + "; trying signature-based detection");
if (importer.CanRead( pFile, pimpl->mIOHandler, true)) {
imp = &importer;
SetPropertyInteger("importerIndex", it->index);
break;
}
}
} }
if (!imp) { if (!imp) {
// not so bad yet ... try format auto detection. // not so bad yet ... try format auto detection.
const std::string::size_type s = pFile.find_last_of('.'); ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
if (s != std::string::npos) { for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
ASSIMP_LOG_INFO("File extension not known, trying signature-based detection"); if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { imp = pimpl->mImporter[a];
if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) { SetPropertyInteger("importerIndex", a);
imp = pimpl->mImporter[a]; break;
SetPropertyInteger("importerIndex", a);
break;
}
} }
} }
// Put a proper error message if no suitable importer was found // Put a proper error message if no suitable importer was found

View File

@ -202,6 +202,9 @@ corresponding preprocessor flag to selectively disable formats.
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#include "AssetLib/M3D/M3DImporter.h" #include "AssetLib/M3D/M3DImporter.h"
#endif #endif
#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
#include "AssetLib/IQM/IQMImporter.h"
#endif
namespace Assimp { namespace Assimp {
@ -370,6 +373,9 @@ void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
#endif #endif
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
out.push_back(new MMDImporter()); out.push_back(new MMDImporter());
#endif
#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
out.push_back(new IQMImporter());
#endif #endif
//#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER //#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
// out.push_back(new StepFile::StepFileImporter()); // out.push_back(new StepFile::StepFileImporter());

View File

@ -95,20 +95,15 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
* *
* The implementation should be as quick as possible. A check for * The implementation is expected to perform a full check of the file
* the file extension is enough. If no suitable loader is found with * structure, possibly searching the first bytes of the file for magic
* this strategy, CanRead() is called again, the 'checkSig' parameter * identifiers or keywords.
* set to true this time. Now the implementation is expected to
* perform a full check of the file structure, possibly searching the
* first bytes of the file for magic identifiers or keywords.
* *
* @param pFile Path and file name of the file to be examined. * @param pFile Path and file name of the file to be examined.
* @param pIOHandler The IO handler to use for accessing any file. * @param pIOHandler The IO handler to use for accessing any file.
* @param checkSig Set to true if this method is called a second time. * @param checkSig Legacy; do not use.
* This time, the implementation may take more time to examine the * @return true if the class can read this file, false if not or if
* contents of the file to be loaded for magic bytes, keywords, etc * unsure.
* to be able to load files with unknown/not existent file extensions.
* @return true if the class can read this file, false if not.
*/ */
virtual bool CanRead( virtual bool CanRead(
const std::string &pFile, const std::string &pFile,
@ -259,8 +254,8 @@ public: // static utilities
static bool SearchFileHeaderForToken( static bool SearchFileHeaderForToken(
IOSystem *pIOSystem, IOSystem *pIOSystem,
const std::string &file, const std::string &file,
const char * const *tokens, const char **tokens,
unsigned int numTokens, std::size_t numTokens,
unsigned int searchBytes = 200, unsigned int searchBytes = 200,
bool tokensSol = false, bool tokensSol = false,
bool noAlphaBeforeTokens = false); bool noAlphaBeforeTokens = false);
@ -305,7 +300,7 @@ public: // static utilities
IOSystem *pIOHandler, IOSystem *pIOHandler,
const std::string &pFile, const std::string &pFile,
const void *magic, const void *magic,
unsigned int num, std::size_t num,
unsigned int offset = 0, unsigned int offset = 0,
unsigned int size = 4); unsigned int size = 4);

View File

@ -331,4 +331,6 @@ static const ai_real ai_epsilon = (ai_real)0.00001;
#define AI_DEBUG_INVALIDATE_PTR(x) #define AI_DEBUG_INVALIDATE_PTR(x)
#endif #endif
#define AI_COUNT_OF(X) (sizeof(X) / sizeof((X)[0]))
#endif // !! AI_DEFINES_H_INC #endif // !! AI_DEFINES_H_INC

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.