Merge branch 'master' into respect-cmake-output-variables
commit
6cc469a5ae
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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*) {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -331,7 +331,16 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
|
||||||
const std::string ¤tName = currentNode.name();
|
const std::string ¤tName = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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.
Loading…
Reference in New Issue