From f1fe73d1909a2448a004a88362a1a532d0d4f7c3 Mon Sep 17 00:00:00 2001 From: sanine Date: Sun, 12 Feb 2023 23:53:22 -0600 Subject: switch to tinyobj and nanovg from assimp and cairo --- .../code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp | 680 --------------------- 1 file changed, 680 deletions(-) delete mode 100644 libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp (limited to 'libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp') diff --git a/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp deleted file mode 100644 index db9a4a0..0000000 --- a/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp +++ /dev/null @@ -1,680 +0,0 @@ -/* -Open Asset Import Library (assimp) ---------------------------------------------------------------------------------------------------- - -Copyright (c) 2006-2022, 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_Q3BSP_IMPORTER - -#include "Q3BSPFileImporter.h" -#include "Q3BSPFileData.h" -#include "Q3BSPFileParser.h" - -#include - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -#include -#else -#include "../contrib/zlib/zlib.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const aiImporterDesc desc = { - "Quake III BSP Importer", - "", - "", - "", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 0, - 0, - "bsp pk3" -}; - -namespace Assimp { - -using namespace Q3BSP; - -// ------------------------------------------------------------------------------------------------ -// Local function to create a material key name. -static void createKey(int id1, int id2, std::string &key) { - std::ostringstream str; - str << id1 << "." << id2; - key = str.str(); -} - -// ------------------------------------------------------------------------------------------------ -// Local function to extract the texture ids from a material key-name. -static void extractIds(const std::string &key, int &id1, int &id2) { - id1 = -1; - id2 = -1; - if (key.empty()) { - return; - } - - const std::string::size_type pos = key.find('.'); - if (std::string::npos == pos) { - return; - } - - std::string tmp1 = key.substr(0, pos); - std::string tmp2 = key.substr(pos + 1, key.size() - pos - 1); - id1 = atoi(tmp1.c_str()); - id2 = atoi(tmp2.c_str()); -} - -// ------------------------------------------------------------------------------------------------ -// Local helper function to normalize filenames. -static void normalizePathName(const std::string &rPath, std::string &normalizedPath) { - normalizedPath = std::string(); - if (rPath.empty()) { - return; - } - -#ifdef _WIN32 - std::string sep = "\\"; -#else - std::string sep = "/"; -#endif - - static const unsigned int numDelimiters = 2; - const char delimiters[numDelimiters] = { '/', '\\' }; - normalizedPath = rPath; - for (const char delimiter : delimiters) { - for (size_t j = 0; j < normalizedPath.size(); ++j) { - if (normalizedPath[j] == delimiter) { - normalizedPath[j] = sep[0]; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Constructor. -Q3BSPFileImporter::Q3BSPFileImporter() : - m_pCurrentMesh(nullptr), m_pCurrentFace(nullptr), m_MaterialLookupMap(), mTextures() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor. -Q3BSPFileImporter::~Q3BSPFileImporter() { - // Clear face-to-material map - for (FaceMap::iterator it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it) { - const std::string &matName = it->first; - if (!matName.empty()) { - delete it->second; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Returns true if the loader can read this. -bool Q3BSPFileImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool checkSig) const { - if (!checkSig) { - return SimpleExtensionCheck(filename, "pk3", "bsp"); - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Adds extensions. -const aiImporterDesc *Q3BSPFileImporter::GetInfo() const { - return &desc; -} - -// ------------------------------------------------------------------------------------------------ -// Import method. -void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene *scene, IOSystem *ioHandler) { - ZipArchiveIOSystem Archive(ioHandler, rFile); - if (!Archive.isOpen()) { - throw DeadlyImportError("Failed to open file ", rFile, "."); - } - - std::string archiveName, mapName; - separateMapName(rFile, archiveName, mapName); - - if (mapName.empty()) { - if (!findFirstMapInArchive(Archive, mapName)) { - return; - } - } - - Q3BSPFileParser fileParser(mapName, &Archive); - Q3BSPModel *pBSPModel = fileParser.getModel(); - if (nullptr != pBSPModel) { - CreateDataFromImport(pBSPModel, scene, &Archive); - } -} - -// ------------------------------------------------------------------------------------------------ -// Separates the map name from the import name. -void Q3BSPFileImporter::separateMapName(const std::string &importName, std::string &archiveName, std::string &mapName) { - archiveName = std::string(); - mapName = std::string(); - if (importName.empty()) { - return; - } - - const std::string::size_type pos = importName.rfind(','); - if (std::string::npos == pos) { - archiveName = importName; - return; - } - - archiveName = importName.substr(0, pos); - mapName = importName.substr(pos, importName.size() - pos - 1); -} - -// ------------------------------------------------------------------------------------------------ -// Returns the first map in the map archive. -bool Q3BSPFileImporter::findFirstMapInArchive(ZipArchiveIOSystem &bspArchive, std::string &mapName) { - mapName = std::string(); - std::vector fileList; - bspArchive.getFileListExtension(fileList, "bsp"); - if (fileList.empty()) { - return false; - } - - std::vector::iterator it(fileList.begin()); - for (; it != fileList.end(); ++it) { - const std::string::size_type pos = (*it).find("maps/"); - if (std::string::npos != pos) { - std::string::size_type extPos = (*it).find(".bsp"); - if (std::string::npos != extPos) { - mapName = *it; - return true; - } - } - } - - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Creates the assimp specific data. -void Q3BSPFileImporter::CreateDataFromImport(const Q3BSP::Q3BSPModel *pModel, aiScene *pScene, - ZipArchiveIOSystem *pArchive) { - if (nullptr == pModel || nullptr == pScene) { - return; - } - - pScene->mRootNode = new aiNode; - if (!pModel->m_ModelName.empty()) { - pScene->mRootNode->mName.Set(pModel->m_ModelName); - } - - // Create the face to material relation map - createMaterialMap(pModel); - - // Create all nodes - CreateNodes(pModel, pScene, pScene->mRootNode); - - // Create the assigned materials - createMaterials(pModel, pScene, pArchive); -} - -// ------------------------------------------------------------------------------------------------ -// Creates all assimp nodes. -void Q3BSPFileImporter::CreateNodes(const Q3BSP::Q3BSPModel *pModel, aiScene *pScene, - aiNode *pParent) { - if (nullptr == pModel) { - return; - } - - unsigned int matIdx(0); - std::vector MeshArray; - std::vector NodeArray; - for (FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it) { - std::vector *pArray = (*it).second; - size_t numVerts = countData(*pArray); - if (0 != numVerts) { - aiMesh *pMesh(nullptr); - aiNode *pNode = CreateTopology(pModel, matIdx, *pArray, &pMesh); - if (nullptr != pNode) { - NodeArray.push_back(pNode); - MeshArray.push_back(pMesh); - } - } - matIdx++; - } - - pScene->mNumMeshes = static_cast(MeshArray.size()); - if (pScene->mNumMeshes > 0) { - pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; - for (size_t i = 0; i < MeshArray.size(); i++) { - aiMesh *pMesh = MeshArray[i]; - if (nullptr != pMesh) { - pScene->mMeshes[i] = pMesh; - } - } - } - - pParent->mNumChildren = static_cast(MeshArray.size()); - pParent->mChildren = new aiNode *[pScene->mRootNode->mNumChildren]; - for (size_t i = 0; i < NodeArray.size(); i++) { - aiNode *pNode = NodeArray[i]; - pNode->mParent = pParent; - pParent->mChildren[i] = pNode; - pParent->mChildren[i]->mMeshes[0] = static_cast(i); - } -} - -// ------------------------------------------------------------------------------------------------ -// Creates the topology. -aiNode *Q3BSPFileImporter::CreateTopology(const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx, - std::vector &rArray, aiMesh **pMesh) { - size_t numVerts = countData(rArray); - if (0 == numVerts) { - return nullptr; - } - - size_t numFaces = countFaces(rArray); - if (0 == numFaces) { - return nullptr; - } - - aiMesh *mesh = new aiMesh; - size_t numTriangles = countTriangles(rArray); - mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - - mesh->mFaces = new aiFace[numTriangles]; - mesh->mNumFaces = static_cast(numTriangles); - - mesh->mNumVertices = static_cast(numVerts); - mesh->mVertices = new aiVector3D[numVerts]; - mesh->mNormals = new aiVector3D[numVerts]; - mesh->mTextureCoords[0] = new aiVector3D[numVerts]; - mesh->mTextureCoords[1] = new aiVector3D[numVerts]; - mesh->mMaterialIndex = materialIdx; - - unsigned int faceIdx = 0; - unsigned int vertIdx = 0; - mesh->mNumUVComponents[0] = 2; - mesh->mNumUVComponents[1] = 2; - for (std::vector::const_iterator it = rArray.begin(); it != rArray.end(); ++it) { - Q3BSP::sQ3BSPFace *pQ3BSPFace = *it; - ai_assert(nullptr != pQ3BSPFace); - if (nullptr == pQ3BSPFace) { - continue; - } - - if (pQ3BSPFace->iNumOfFaceVerts > 0) { - if (pQ3BSPFace->iType == Polygon || pQ3BSPFace->iType == TriangleMesh) { - createTriangleTopology(pModel, pQ3BSPFace, mesh, faceIdx, vertIdx); - } - } - } - - aiNode *pNode = new aiNode; - pNode->mNumMeshes = 1; - pNode->mMeshes = new unsigned int[1]; - *pMesh = mesh; - - return pNode; -} - -// ------------------------------------------------------------------------------------------------ -// Creates the triangle topology from a face array. -void Q3BSPFileImporter::createTriangleTopology(const Q3BSP::Q3BSPModel *pModel, sQ3BSPFace *pQ3BSPFace, - aiMesh *pMesh, unsigned int &faceIdx, unsigned int &vertIdx) { - ai_assert(faceIdx < pMesh->mNumFaces); - - m_pCurrentFace = getNextFace(pMesh, faceIdx); - if (nullptr == m_pCurrentFace) { - return; - } - - m_pCurrentFace->mNumIndices = 3; - m_pCurrentFace->mIndices = new unsigned int[m_pCurrentFace->mNumIndices]; - - size_t idx(0); - for (size_t i = 0; i < (size_t)pQ3BSPFace->iNumOfFaceVerts; ++i) { - const size_t index = pQ3BSPFace->iVertexIndex + pModel->m_Indices[pQ3BSPFace->iFaceVertexIndex + i]; - if (index >= pModel->m_Vertices.size()) { - continue; - } - - sQ3BSPVertex *pVertex = pModel->m_Vertices[index]; - if (nullptr == pVertex) { - continue; - } - if (idx > 2) { - idx = 0; - m_pCurrentFace = getNextFace(pMesh, faceIdx); - if (nullptr != m_pCurrentFace) { - m_pCurrentFace->mNumIndices = 3; - m_pCurrentFace->mIndices = new unsigned int[3]; - m_pCurrentFace->mIndices[idx] = vertIdx; - } - } - - pMesh->mVertices[vertIdx].Set(pVertex->vPosition.x, pVertex->vPosition.y, pVertex->vPosition.z); - pMesh->mNormals[vertIdx].Set(pVertex->vNormal.x, pVertex->vNormal.y, pVertex->vNormal.z); - - pMesh->mTextureCoords[0][vertIdx].Set(pVertex->vTexCoord.x, pVertex->vTexCoord.y, 0.0f); - pMesh->mTextureCoords[1][vertIdx].Set(pVertex->vLightmap.x, pVertex->vLightmap.y, 0.0f); - - vertIdx++; - idx++; - } -} - -// ------------------------------------------------------------------------------------------------ -// Creates all referenced materials. -void Q3BSPFileImporter::createMaterials(const Q3BSP::Q3BSPModel *pModel, aiScene *pScene, - ZipArchiveIOSystem *pArchive) { - if (m_MaterialLookupMap.empty()) { - return; - } - - pScene->mMaterials = new aiMaterial *[m_MaterialLookupMap.size()]; - aiString aiMatName; - int textureId(-1), lightmapId(-1); - for (FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); - ++it) { - const std::string matName(it->first); - if (matName.empty()) { - continue; - } - - aiMatName.Set(matName); - aiMaterial *pMatHelper = new aiMaterial; - pMatHelper->AddProperty(&aiMatName, AI_MATKEY_NAME); - - extractIds(matName, textureId, lightmapId); - - // Adding the texture - if (-1 != textureId) { - sQ3BSPTexture *pTexture = pModel->m_Textures[textureId]; - if (nullptr != pTexture) { - std::string tmp("*"), texName; - tmp += pTexture->strName; - tmp += ".jpg"; - normalizePathName(tmp, texName); - - if (!importTextureFromArchive(pModel, pArchive, pScene, pMatHelper, textureId)) { - ASSIMP_LOG_ERROR("Cannot import texture from archive ", texName); - } - } - } - if (-1 != lightmapId) { - importLightmap(pModel, pScene, pMatHelper, lightmapId); - } - pScene->mMaterials[pScene->mNumMaterials] = pMatHelper; - pScene->mNumMaterials++; - } - pScene->mNumTextures = static_cast(mTextures.size()); - pScene->mTextures = new aiTexture *[pScene->mNumTextures]; - std::copy(mTextures.begin(), mTextures.end(), pScene->mTextures); -} - -// ------------------------------------------------------------------------------------------------ -// Counts the number of referenced vertices. -size_t Q3BSPFileImporter::countData(const std::vector &faceArray) const { - size_t numVerts(0); - for (std::vector::const_iterator it = faceArray.begin(); it != faceArray.end(); - ++it) { - sQ3BSPFace *pQ3BSPFace = *it; - if (pQ3BSPFace->iType == Polygon || pQ3BSPFace->iType == TriangleMesh) { - Q3BSP::sQ3BSPFace *face = *it; - if (nullptr != face) { - numVerts += face->iNumOfFaceVerts; - } - } - } - - return numVerts; -} - -// ------------------------------------------------------------------------------------------------ -// Counts the faces with vertices. -size_t Q3BSPFileImporter::countFaces(const std::vector &rArray) const { - size_t numFaces = 0; - for (std::vector::const_iterator it = rArray.begin(); it != rArray.end(); - ++it) { - Q3BSP::sQ3BSPFace *pQ3BSPFace = *it; - if (pQ3BSPFace->iNumOfFaceVerts > 0) { - numFaces++; - } - } - - return numFaces; -} - -// ------------------------------------------------------------------------------------------------ -// Counts the number of triangles in a Q3-face-array. -size_t Q3BSPFileImporter::countTriangles(const std::vector &rArray) const { - size_t numTriangles = 0; - for (std::vector::const_iterator it = rArray.begin(); it != rArray.end(); - ++it) { - const Q3BSP::sQ3BSPFace *pQ3BSPFace = *it; - if (nullptr != pQ3BSPFace) { - numTriangles += pQ3BSPFace->iNumOfFaceVerts / 3; - } - } - - return numTriangles; -} - -// ------------------------------------------------------------------------------------------------ -// Creates the faces-to-material map. -void Q3BSPFileImporter::createMaterialMap(const Q3BSP::Q3BSPModel *pModel) { - std::string key; - std::vector *pCurFaceArray = nullptr; - for (size_t idx = 0; idx < pModel->m_Faces.size(); idx++) { - Q3BSP::sQ3BSPFace *pQ3BSPFace = pModel->m_Faces[idx]; - const int texId = pQ3BSPFace->iTextureID; - const int lightMapId = pQ3BSPFace->iLightmapID; - createKey(texId, lightMapId, key); - FaceMapIt it = m_MaterialLookupMap.find(key); - if (m_MaterialLookupMap.end() == it) { - pCurFaceArray = new std::vector; - m_MaterialLookupMap[key] = pCurFaceArray; - } else { - pCurFaceArray = (*it).second; - } - ai_assert(nullptr != pCurFaceArray); - if (nullptr != pCurFaceArray) { - pCurFaceArray->push_back(pQ3BSPFace); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Returns the next face. -aiFace *Q3BSPFileImporter::getNextFace(aiMesh *mesh, unsigned int &faceIdx) { - aiFace *face(nullptr); - if (faceIdx < mesh->mNumFaces) { - face = &mesh->mFaces[faceIdx]; - ++faceIdx; - } - - return face; -} - -// ------------------------------------------------------------------------------------------------ -// Imports a texture file. -bool Q3BSPFileImporter::importTextureFromArchive(const Q3BSP::Q3BSPModel *model, - ZipArchiveIOSystem *archive, aiScene *, - aiMaterial *pMatHelper, int textureId) { - if (nullptr == archive || nullptr == pMatHelper) { - return false; - } - - if (textureId < 0 || textureId >= static_cast(model->m_Textures.size())) { - return false; - } - - bool res = true; - sQ3BSPTexture *pTexture = model->m_Textures[textureId]; - if (!pTexture) { - return false; - } - - std::vector supportedExtensions; - supportedExtensions.push_back(".jpg"); - supportedExtensions.push_back(".png"); - supportedExtensions.push_back(".tga"); - std::string textureName, ext; - if (expandFile(archive, pTexture->strName, supportedExtensions, textureName, ext)) { - IOStream *pTextureStream = archive->Open(textureName.c_str()); - if (pTextureStream) { - size_t texSize = pTextureStream->FileSize(); - aiTexture *curTexture = new aiTexture; - curTexture->mHeight = 0; - curTexture->mWidth = static_cast(texSize); - unsigned char *pData = new unsigned char[curTexture->mWidth]; - size_t readSize = pTextureStream->Read(pData, sizeof(unsigned char), curTexture->mWidth); - (void)readSize; - ai_assert(readSize == curTexture->mWidth); - curTexture->pcData = reinterpret_cast(pData); - curTexture->achFormatHint[0] = ext[1]; - curTexture->achFormatHint[1] = ext[2]; - curTexture->achFormatHint[2] = ext[3]; - curTexture->achFormatHint[3] = '\0'; - res = true; - - aiString name; - name.data[0] = '*'; - name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast(MAXLEN - 1), static_cast(mTextures.size())); - - archive->Close(pTextureStream); - - pMatHelper->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE(0)); - mTextures.push_back(curTexture); - } else { - // If it doesn't exist in the archive, it is probably just a reference to an external file. - // We'll leave it up to the user to figure out which extension the file has. - aiString name; - strncpy(name.data, pTexture->strName, sizeof name.data); - name.length = static_cast(strlen(name.data)); - pMatHelper->AddProperty(&name, AI_MATKEY_TEXTURE_DIFFUSE(0)); - } - } - - return res; -} - -// ------------------------------------------------------------------------------------------------ -// Imports a light map file. -bool Q3BSPFileImporter::importLightmap(const Q3BSP::Q3BSPModel *pModel, aiScene *pScene, - aiMaterial *pMatHelper, int lightmapId) { - if (nullptr == pModel || nullptr == pScene || nullptr == pMatHelper) { - return false; - } - - if (lightmapId < 0 || lightmapId >= static_cast(pModel->m_Lightmaps.size())) { - return false; - } - - sQ3BSPLightmap *pLightMap = pModel->m_Lightmaps[lightmapId]; - if (nullptr == pLightMap) { - return false; - } - - aiTexture *pTexture = new aiTexture; - - pTexture->mWidth = CE_BSP_LIGHTMAPWIDTH; - pTexture->mHeight = CE_BSP_LIGHTMAPHEIGHT; - pTexture->pcData = new aiTexel[CE_BSP_LIGHTMAPWIDTH * CE_BSP_LIGHTMAPHEIGHT]; - - ::memcpy(pTexture->pcData, pLightMap->bLMapData, pTexture->mWidth); - size_t p = 0; - for (size_t i = 0; i < CE_BSP_LIGHTMAPWIDTH * CE_BSP_LIGHTMAPHEIGHT; ++i) { - pTexture->pcData[i].r = pLightMap->bLMapData[p++]; - pTexture->pcData[i].g = pLightMap->bLMapData[p++]; - pTexture->pcData[i].b = pLightMap->bLMapData[p++]; - pTexture->pcData[i].a = 0xFF; - } - - aiString name; - name.data[0] = '*'; - name.length = 1 + ASSIMP_itoa10(name.data + 1, static_cast(MAXLEN - 1), static_cast(mTextures.size())); - - pMatHelper->AddProperty(&name, AI_MATKEY_TEXTURE_LIGHTMAP(1)); - mTextures.push_back(pTexture); - - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Will search for a supported extension. -bool Q3BSPFileImporter::expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename, - const std::vector &rExtList, std::string &rFile, - std::string &rExt) { - ai_assert(nullptr != pArchive); - ai_assert(!rFilename.empty()); - - if (rExtList.empty()) { - rFile = rFilename; - rExt = std::string(); - return true; - } - - bool found = false; - for (std::vector::const_iterator it = rExtList.begin(); it != rExtList.end(); ++it) { - const std::string textureName = rFilename + *it; - if (pArchive->Exists(textureName.c_str())) { - rExt = *it; - rFile = textureName; - found = true; - break; - } - } - - return found; -} - -// ------------------------------------------------------------------------------------------------ - -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER -- cgit v1.2.1