summaryrefslogtreecommitdiff
path: root/libs/assimp/code/AssetLib/Q3BSP
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-04-16 11:55:09 -0500
committersanine <sanine.not@pm.me>2022-04-16 11:55:09 -0500
commitdb81b925d776103326128bf629cbdda576a223e7 (patch)
tree58bea8155c686733310009f6bed7363f91fbeb9d /libs/assimp/code/AssetLib/Q3BSP
parent55860037b14fb3893ba21cf2654c83d349cc1082 (diff)
move 3rd-party librarys into libs/ and add built-in honeysuckle
Diffstat (limited to 'libs/assimp/code/AssetLib/Q3BSP')
-rw-r--r--libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileData.h214
-rw-r--r--libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp680
-rw-r--r--libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.h118
-rw-r--r--libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp272
-rw-r--r--libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.h89
5 files changed, 1373 insertions, 0 deletions
diff --git a/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileData.h b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileData.h
new file mode 100644
index 0000000..8ccee0b
--- /dev/null
+++ b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileData.h
@@ -0,0 +1,214 @@
+/*
+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_Q3BSPFILEDATA_H_INC
+#define ASSIMP_Q3BSPFILEDATA_H_INC
+
+#include <vector>
+#include <string.h>
+#include <string>
+
+namespace Assimp {
+namespace Q3BSP {
+
+static const unsigned int CE_BSP_LIGHTMAPWIDTH = 128;
+static const unsigned int CE_BSP_LIGHTMAPHEIGHT = 128;
+
+static const unsigned int CE_BSP_LIGHTMAPSIZE = 128*128*3; ///< = 128( width ) * 128 ( height ) * 3 ( channels / RGB ).
+static const int VERION_Q3LEVEL = 46; ///< Supported version.
+
+/// Geometric type enumeration
+enum Q3BSPGeoType {
+ Polygon = 1,
+ Patch,
+ TriangleMesh,
+ Billboard
+};
+
+/// Integer vector.
+struct ceVec3i {
+ int x, y, z;
+ ceVec3i(): x( 0 ), y( 0 ), z( 0 ) { /* empty */ }
+ ceVec3i( int iX, int iY=0, int iZ=0) : x( iX ), y( iY ), z( iZ ) { /* empty */ }
+};
+
+/// the file header
+struct sQ3BSPHeader {
+ char strID[ 4 ]; ///< Should be "IBSP"
+ int iVersion; ///< 46 for standard levels
+};
+
+/// Describes an entry.
+struct sQ3BSPLump {
+ int iOffset; ///< Offset from start pointer of file
+ int iSize; ///< Size of part
+};
+
+struct vec2f {
+ float x,y;
+};
+
+struct vec3f {
+ float x, y, z;
+};
+
+/// Vertex of a Q3 level
+struct sQ3BSPVertex {
+ vec3f vPosition; ///< Position of vertex
+ vec2f vTexCoord; ///< (u,v) Texturecoordinate of detailtexture
+ vec2f vLightmap; ///< (u,v) Texturecoordinate of lightmap
+ vec3f vNormal; ///< vertex normal
+ unsigned char bColor[ 4 ]; ///< Color in RGBA
+};
+
+/// A face in bsp format info
+struct sQ3BSPFace {
+ int iTextureID; ///< Index in texture array
+ int iEffect; ///< Index in effect array (-1 = no effect)
+ int iType; ///< 1=Polygon, 2=Patch, 3=Mesh, 4=Billboard
+ int iVertexIndex; ///< Start index of polygon
+ int iNumOfVerts; ///< Number of vertices
+ int iFaceVertexIndex; ///< Index of first mesh vertex
+ int iNumOfFaceVerts; ///< number of mesh vertices
+ int iLightmapID; ///< Index to the light-map array
+ int iLMapCorner[ 2 ]; ///< edge of the light-map in texture
+ int iLMapSize[ 2 ]; ///< Size of the light-map stored on the texture
+ vec3f vLMapPos; ///< 3D origin of the light-map
+ vec3f vLMapVecs[ 2 ]; ///< 3D-s-t-vectors
+ vec3f vNormal; ///< Polygon normals
+ int patchWidth, patchHeight; ///< bezier patch
+};
+
+/// A quake3 texture name.
+struct sQ3BSPTexture {
+ char strName[ 64 ]; ///< Name of the texture without extension
+ int iFlags; ///< Not used
+ int iContents; ///< Not used
+};
+
+/// A light-map of the level, size 128 x 128, RGB components.
+struct sQ3BSPLightmap {
+ unsigned char bLMapData[ CE_BSP_LIGHTMAPSIZE ];
+ sQ3BSPLightmap() {
+ ::memset(bLMapData, 0, CE_BSP_LIGHTMAPSIZE );
+ }
+};
+
+struct SubPatch {
+ std::vector<size_t> indices;
+ int lightmapID;
+};
+
+enum eLumps {
+ kEntities = 0,
+ kTextures,
+ kPlanes,
+ kNodes,
+ kLeafs,
+ kLeafFaces,
+ kLeafBrushes,
+ kModels,
+ kBrushes,
+ kBrushSides,
+ kVertices,
+ kMeshVerts,
+ kShaders,
+ kFaces,
+ kLightmaps,
+ kLightVolumes,
+ kVisData,
+ kMaxLumps
+};
+
+struct Q3BSPModel {
+ std::vector<unsigned char> m_Data;
+ std::vector<sQ3BSPLump*> m_Lumps;
+ std::vector<sQ3BSPVertex*> m_Vertices;
+ std::vector<sQ3BSPFace*> m_Faces;
+ std::vector<int> m_Indices;
+ std::vector<sQ3BSPTexture*> m_Textures;
+ std::vector<sQ3BSPLightmap*> m_Lightmaps;
+ std::vector<char> m_EntityData;
+ std::string m_ModelName;
+
+ Q3BSPModel() :
+ m_Data(),
+ m_Lumps(),
+ m_Vertices(),
+ m_Faces(),
+ m_Indices(),
+ m_Textures(),
+ m_Lightmaps(),
+ m_EntityData(),
+ m_ModelName()
+ {
+ // empty
+ }
+
+ ~Q3BSPModel() {
+ for ( unsigned int i=0; i<m_Lumps.size(); i++ ) {
+ delete m_Lumps[ i ];
+ }
+ for ( unsigned int i=0; i<m_Vertices.size(); i++ ) {
+ delete m_Vertices[ i ];
+ }
+ for ( unsigned int i=0; i<m_Faces.size(); i++ ) {
+ delete m_Faces[ i ];
+ }
+ for ( unsigned int i=0; i<m_Textures.size(); i++ ) {
+ delete m_Textures[ i ];
+ }
+ for ( unsigned int i=0; i<m_Lightmaps.size(); i++ ) {
+ delete m_Lightmaps[ i ];
+ }
+
+ m_Lumps.clear();
+ m_Vertices.clear();
+ m_Faces.clear();
+ m_Textures.clear();
+ m_Lightmaps.clear();
+ }
+};
+
+} // Namespace Q3BSP
+} // Namespace Assimp
+
+#endif // ASSIMP_Q3BSPFILEDATA_H_INC
diff --git a/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp
new file mode 100644
index 0000000..db9a4a0
--- /dev/null
+++ b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp
@@ -0,0 +1,680 @@
+/*
+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 <assimp/DefaultLogger.hpp>
+
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#include <zlib.h>
+#else
+#include "../contrib/zlib/zlib.h"
+#endif
+
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/StringComparison.h>
+#include <assimp/ZipArchiveIOSystem.h>
+#include <assimp/ai_assert.h>
+#include <assimp/importerdesc.h>
+#include <assimp/mesh.h>
+#include <assimp/scene.h>
+#include <assimp/types.h>
+#include <sstream>
+#include <vector>
+
+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<std::string> fileList;
+ bspArchive.getFileListExtension(fileList, "bsp");
+ if (fileList.empty()) {
+ return false;
+ }
+
+ std::vector<std::string>::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<aiMesh *> MeshArray;
+ std::vector<aiNode *> NodeArray;
+ for (FaceMapIt it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it) {
+ std::vector<Q3BSP::sQ3BSPFace *> *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<unsigned int>(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<unsigned int>(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<unsigned int>(i);
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Creates the topology.
+aiNode *Q3BSPFileImporter::CreateTopology(const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx,
+ std::vector<sQ3BSPFace *> &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<unsigned int>(numTriangles);
+
+ mesh->mNumVertices = static_cast<unsigned int>(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<sQ3BSPFace *>::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<unsigned int>(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<sQ3BSPFace *> &faceArray) const {
+ size_t numVerts(0);
+ for (std::vector<sQ3BSPFace *>::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<Q3BSP::sQ3BSPFace *> &rArray) const {
+ size_t numFaces = 0;
+ for (std::vector<sQ3BSPFace *>::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<Q3BSP::sQ3BSPFace *> &rArray) const {
+ size_t numTriangles = 0;
+ for (std::vector<Q3BSP::sQ3BSPFace *>::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<sQ3BSPFace *> *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<Q3BSP::sQ3BSPFace *>;
+ 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<int>(model->m_Textures.size())) {
+ return false;
+ }
+
+ bool res = true;
+ sQ3BSPTexture *pTexture = model->m_Textures[textureId];
+ if (!pTexture) {
+ return false;
+ }
+
+ std::vector<std::string> 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<unsigned int>(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<aiTexel *>(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<unsigned int>(MAXLEN - 1), static_cast<int32_t>(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<ai_uint32>(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<int>(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<unsigned int>(MAXLEN - 1), static_cast<int32_t>(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<std::string> &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<std::string>::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
diff --git a/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.h b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.h
new file mode 100644
index 0000000..fdcfff8
--- /dev/null
+++ b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileImporter.h
@@ -0,0 +1,118 @@
+/*
+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_Q3BSPFILEIMPORTER_H_INC
+#define ASSIMP_Q3BSPFILEIMPORTER_H_INC
+
+#include <assimp/BaseImporter.h>
+
+#include <map>
+#include <string>
+
+struct aiMesh;
+struct aiNode;
+struct aiFace;
+struct aiMaterial;
+struct aiTexture;
+
+namespace Assimp {
+ class ZipArchiveIOSystem;
+
+namespace Q3BSP {
+ struct Q3BSPModel;
+ struct sQ3BSPFace;
+}
+
+// ------------------------------------------------------------------------------------------------
+/** Loader to import BSP-levels from a PK3 archive or from a unpacked BSP-level.
+ */
+// ------------------------------------------------------------------------------------------------
+class Q3BSPFileImporter : public BaseImporter {
+public:
+ /// @brief Default constructor.
+ Q3BSPFileImporter();
+
+ /// @brief Destructor.
+ ~Q3BSPFileImporter() 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:
+ using FaceMap = std::map<std::string, std::vector<Q3BSP::sQ3BSPFace*>*>;
+ using FaceMapIt = std::map<std::string, std::vector<Q3BSP::sQ3BSPFace*>* >::iterator;
+ using FaceMapConstIt = std::map<std::string, std::vector<Q3BSP::sQ3BSPFace*>*>::const_iterator;
+
+ const aiImporterDesc* GetInfo () const override;
+ void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
+ void separateMapName( const std::string &rImportName, std::string &rArchiveName, std::string &rMapName );
+ bool findFirstMapInArchive(ZipArchiveIOSystem &rArchive, std::string &rMapName );
+ void CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive );
+ void CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiNode *pParent );
+ aiNode *CreateTopology( const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx,
+ std::vector<Q3BSP::sQ3BSPFace*> &rArray, aiMesh **pMesh );
+ void createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, Q3BSP::sQ3BSPFace *pQ3BSPFace, aiMesh* pMesh, unsigned int &rFaceIdx,
+ unsigned int &rVertIdx );
+ void createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive );
+ size_t countData( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
+ size_t countFaces( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
+ size_t countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
+ void createMaterialMap( const Q3BSP::Q3BSPModel *pModel);
+ aiFace *getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx );
+ bool importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, ZipArchiveIOSystem *pArchive, aiScene* pScene,
+ aiMaterial *pMatHelper, int textureId );
+ bool importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiMaterial *pMatHelper, int lightmapId );
+ bool importEntities( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene );
+ bool expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename, const std::vector<std::string> &rExtList,
+ std::string &rFile, std::string &rExt );
+
+private:
+ aiMesh *m_pCurrentMesh;
+ aiFace *m_pCurrentFace;
+ FaceMap m_MaterialLookupMap;
+ std::vector<aiTexture*> mTextures;
+};
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif // ASSIMP_Q3BSPFILEIMPORTER_H_INC
diff --git a/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp
new file mode 100644
index 0000000..910da5b
--- /dev/null
+++ b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp
@@ -0,0 +1,272 @@
+/*
+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 "Q3BSPFileParser.h"
+#include "Q3BSPFileData.h"
+#include <vector>
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/ZipArchiveIOSystem.h>
+#include <assimp/ai_assert.h>
+
+namespace Assimp {
+
+using namespace Q3BSP;
+
+// ------------------------------------------------------------------------------------------------
+Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, ZipArchiveIOSystem *pZipArchive ) :
+ m_sOffset( 0 ),
+ m_Data(),
+ m_pModel(nullptr),
+ m_pZipArchive( pZipArchive )
+{
+ ai_assert(nullptr != m_pZipArchive );
+ ai_assert( !mapName.empty() );
+
+ if ( !readData( mapName ) )
+ return;
+
+ m_pModel = new Q3BSPModel;
+ m_pModel->m_ModelName = mapName;
+ if ( !parseFile() ) {
+ delete m_pModel;
+ m_pModel = nullptr;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+Q3BSPFileParser::~Q3BSPFileParser() {
+ delete m_pModel;
+}
+
+// ------------------------------------------------------------------------------------------------
+Q3BSP::Q3BSPModel *Q3BSPFileParser::getModel() const {
+ return m_pModel;
+}
+
+// ------------------------------------------------------------------------------------------------
+bool Q3BSPFileParser::readData( const std::string &rMapName ) {
+ if ( !m_pZipArchive->Exists( rMapName.c_str() ) )
+ return false;
+
+ IOStream *pMapFile = m_pZipArchive->Open( rMapName.c_str() );
+ if ( nullptr == pMapFile )
+ return false;
+
+ const size_t size = pMapFile->FileSize();
+ m_Data.resize( size );
+
+ const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size );
+ if ( readSize != size ) {
+ m_Data.clear();
+ m_pZipArchive->Close(pMapFile);
+ return false;
+ }
+ m_pZipArchive->Close( pMapFile );
+
+ return true;
+}
+
+// ------------------------------------------------------------------------------------------------
+bool Q3BSPFileParser::parseFile() {
+ if ( m_Data.empty() ) {
+ return false;
+ }
+
+ if ( !validateFormat() )
+ {
+ return false;
+ }
+
+ // Imports the dictionary of the level
+ getLumps();
+
+ // Count data and prepare model data
+ countLumps();
+
+ // Read in Vertices
+ getVertices();
+
+ // Read in Indices
+ getIndices();
+
+ // Read Faces
+ getFaces();
+
+ // Read Textures
+ getTextures();
+
+ // Read Lightmaps
+ getLightMaps();
+
+ // Load the entities
+ getEntities();
+
+ return true;
+}
+
+// ------------------------------------------------------------------------------------------------
+bool Q3BSPFileParser::validateFormat()
+{
+ sQ3BSPHeader *pHeader = (sQ3BSPHeader*) &m_Data[ 0 ];
+ m_sOffset += sizeof( sQ3BSPHeader );
+
+ // Version and identify string validation
+ if (pHeader->strID[ 0 ] != 'I' || pHeader->strID[ 1 ] != 'B' || pHeader->strID[ 2 ] != 'S'
+ || pHeader->strID[ 3 ] != 'P')
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::getLumps()
+{
+ size_t Offset = m_sOffset;
+ m_pModel->m_Lumps.resize( kMaxLumps );
+ for ( size_t idx=0; idx < kMaxLumps; idx++ )
+ {
+ sQ3BSPLump *pLump = new sQ3BSPLump;
+ memcpy( pLump, &m_Data[ Offset ], sizeof( sQ3BSPLump ) );
+ Offset += sizeof( sQ3BSPLump );
+ m_pModel->m_Lumps[ idx ] = pLump;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::countLumps()
+{
+ m_pModel->m_Vertices.resize( m_pModel->m_Lumps[ kVertices ]->iSize / sizeof( sQ3BSPVertex ) );
+ m_pModel->m_Indices.resize( m_pModel->m_Lumps[ kMeshVerts ]->iSize / sizeof( int ) );
+ m_pModel->m_Faces.resize( m_pModel->m_Lumps[ kFaces ]->iSize / sizeof( sQ3BSPFace ) );
+ m_pModel->m_Textures.resize( m_pModel->m_Lumps[ kTextures ]->iSize / sizeof( sQ3BSPTexture ) );
+ m_pModel->m_Lightmaps.resize( m_pModel->m_Lumps[ kLightmaps ]->iSize / sizeof( sQ3BSPLightmap ) );
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::getVertices()
+{
+ size_t Offset = m_pModel->m_Lumps[ kVertices ]->iOffset;
+ for ( size_t idx = 0; idx < m_pModel->m_Vertices.size(); idx++ )
+ {
+ sQ3BSPVertex *pVertex = new sQ3BSPVertex;
+ memcpy( pVertex, &m_Data[ Offset ], sizeof( sQ3BSPVertex ) );
+ Offset += sizeof( sQ3BSPVertex );
+ m_pModel->m_Vertices[ idx ] = pVertex;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::getIndices()
+{
+ ai_assert(nullptr != m_pModel );
+
+ sQ3BSPLump *lump = m_pModel->m_Lumps[ kMeshVerts ];
+ size_t Offset = (size_t) lump->iOffset;
+ const size_t nIndices = lump->iSize / sizeof( int );
+ m_pModel->m_Indices.resize( nIndices );
+ memcpy( &m_pModel->m_Indices[ 0 ], &m_Data[ Offset ], lump->iSize );
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::getFaces()
+{
+ ai_assert(nullptr != m_pModel );
+
+ size_t Offset = m_pModel->m_Lumps[ kFaces ]->iOffset;
+ for ( size_t idx = 0; idx < m_pModel->m_Faces.size(); idx++ )
+ {
+ sQ3BSPFace *pFace = new sQ3BSPFace;
+ memcpy( pFace, &m_Data[ Offset ], sizeof( sQ3BSPFace ) );
+ m_pModel->m_Faces[ idx ] = pFace;
+ Offset += sizeof( sQ3BSPFace );
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::getTextures()
+{
+ ai_assert(nullptr != m_pModel );
+
+ size_t Offset = m_pModel->m_Lumps[ kTextures ]->iOffset;
+ for ( size_t idx=0; idx < m_pModel->m_Textures.size(); idx++ )
+ {
+ sQ3BSPTexture *pTexture = new sQ3BSPTexture;
+ memcpy( pTexture, &m_Data[ Offset ], sizeof(sQ3BSPTexture) );
+ m_pModel->m_Textures[ idx ] = pTexture;
+ Offset += sizeof(sQ3BSPTexture);
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::getLightMaps()
+{
+ ai_assert(nullptr != m_pModel );
+
+ size_t Offset = m_pModel->m_Lumps[kLightmaps]->iOffset;
+ for ( size_t idx=0; idx < m_pModel->m_Lightmaps.size(); idx++ )
+ {
+ sQ3BSPLightmap *pLightmap = new sQ3BSPLightmap;
+ memcpy( pLightmap, &m_Data[ Offset ], sizeof( sQ3BSPLightmap ) );
+ Offset += sizeof( sQ3BSPLightmap );
+ m_pModel->m_Lightmaps[ idx ] = pLightmap;
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+void Q3BSPFileParser::getEntities() {
+ const int size = m_pModel->m_Lumps[ kEntities ]->iSize;
+ m_pModel->m_EntityData.resize( size );
+ if ( size > 0 ) {
+ size_t Offset = m_pModel->m_Lumps[ kEntities ]->iOffset;
+ memcpy( &m_pModel->m_EntityData[ 0 ], &m_Data[ Offset ], sizeof( char ) * size );
+ }
+}
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER
diff --git a/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.h b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.h
new file mode 100644
index 0000000..15cc751
--- /dev/null
+++ b/libs/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.h
@@ -0,0 +1,89 @@
+/*
+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_Q3BSPFILEPARSER_H_INC
+#define ASSIMP_Q3BSPFILEPARSER_H_INC
+
+#include <assimp/BaseImporter.h>
+#include <string>
+
+namespace Assimp
+{
+ class ZipArchiveIOSystem;
+
+namespace Q3BSP
+{
+ struct Q3BSPModel;
+ class ZipFile;
+}
+
+// -------------------------------------------------------------------
+/// @brief This class implements th Q3DSP file parsing.
+// -------------------------------------------------------------------
+class Q3BSPFileParser {
+public:
+ Q3BSPFileParser( const std::string &rMapName, ZipArchiveIOSystem *pZipArchive );
+ ~Q3BSPFileParser();
+ Q3BSP::Q3BSPModel *getModel() const;
+
+protected:
+ bool readData(const std::string &rMapName);
+ bool parseFile();
+ bool validateFormat();
+ void getLumps();
+ void countLumps();
+ void getVertices();
+ void getIndices();
+ void getFaces();
+ void getTextures();
+ void getLightMaps();
+ void getEntities();
+
+private:
+ size_t m_sOffset;
+ std::vector<char> m_Data;
+ Q3BSP::Q3BSPModel *m_pModel;
+ ZipArchiveIOSystem *m_pZipArchive;
+};
+
+} // Namespace Assimp
+
+#endif // ASSIMP_Q3BSPFILEPARSER_H_INC