/src/assimp/code/AssetLib/Q3BSP/Q3BSPFileParser.cpp
Line | Count | Source |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | |
43 | | #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER |
44 | | |
45 | | #include "Q3BSPFileParser.h" |
46 | | #include "Q3BSPFileData.h" |
47 | | #include <vector> |
48 | | #include <assimp/DefaultIOSystem.h> |
49 | | #include <assimp/ZipArchiveIOSystem.h> |
50 | | #include <assimp/ai_assert.h> |
51 | | |
52 | | namespace Assimp { |
53 | | |
54 | | using namespace Q3BSP; |
55 | | |
56 | | // ------------------------------------------------------------------------------------------------ |
57 | | Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, ZipArchiveIOSystem *pZipArchive ) : |
58 | 0 | m_sOffset( 0 ), |
59 | 0 | m_Data(), |
60 | 0 | m_pModel(nullptr), |
61 | 0 | m_pZipArchive( pZipArchive ) |
62 | 0 | { |
63 | 0 | ai_assert(nullptr != m_pZipArchive ); |
64 | 0 | ai_assert( !mapName.empty() ); |
65 | |
|
66 | 0 | if ( !readData( mapName ) ) |
67 | 0 | return; |
68 | | |
69 | 0 | m_pModel = new Q3BSPModel; |
70 | 0 | m_pModel->m_ModelName = mapName; |
71 | 0 | if ( !parseFile() ) { |
72 | 0 | delete m_pModel; |
73 | 0 | m_pModel = nullptr; |
74 | 0 | } |
75 | 0 | } |
76 | | |
77 | | // ------------------------------------------------------------------------------------------------ |
78 | 0 | Q3BSPFileParser::~Q3BSPFileParser() { |
79 | 0 | delete m_pModel; |
80 | 0 | } |
81 | | |
82 | | // ------------------------------------------------------------------------------------------------ |
83 | 0 | Q3BSP::Q3BSPModel *Q3BSPFileParser::getModel() const { |
84 | 0 | return m_pModel; |
85 | 0 | } |
86 | | |
87 | | // ------------------------------------------------------------------------------------------------ |
88 | 0 | bool Q3BSPFileParser::readData( const std::string &rMapName ) { |
89 | 0 | if ( !m_pZipArchive->Exists( rMapName.c_str() ) ) |
90 | 0 | return false; |
91 | | |
92 | 0 | IOStream *pMapFile = m_pZipArchive->Open( rMapName.c_str() ); |
93 | 0 | if ( nullptr == pMapFile ) |
94 | 0 | return false; |
95 | | |
96 | 0 | const size_t size = pMapFile->FileSize(); |
97 | 0 | m_Data.resize( size ); |
98 | |
|
99 | 0 | const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size ); |
100 | 0 | if ( readSize != size ) { |
101 | 0 | m_Data.clear(); |
102 | 0 | m_pZipArchive->Close(pMapFile); |
103 | 0 | return false; |
104 | 0 | } |
105 | 0 | m_pZipArchive->Close( pMapFile ); |
106 | |
|
107 | 0 | return true; |
108 | 0 | } |
109 | | |
110 | | // ------------------------------------------------------------------------------------------------ |
111 | 0 | bool Q3BSPFileParser::parseFile() { |
112 | 0 | if ( m_Data.empty() ) { |
113 | 0 | return false; |
114 | 0 | } |
115 | | |
116 | 0 | if ( !validateFormat() ) |
117 | 0 | { |
118 | 0 | return false; |
119 | 0 | } |
120 | | |
121 | | // Imports the dictionary of the level |
122 | 0 | getLumps(); |
123 | | |
124 | | // Count data and prepare model data |
125 | 0 | countLumps(); |
126 | | |
127 | | // Read in Vertices |
128 | 0 | getVertices(); |
129 | | |
130 | | // Read in Indices |
131 | 0 | getIndices(); |
132 | | |
133 | | // Read Faces |
134 | 0 | getFaces(); |
135 | | |
136 | | // Read Textures |
137 | 0 | getTextures(); |
138 | | |
139 | | // Read Lightmaps |
140 | 0 | getLightMaps(); |
141 | | |
142 | | // Load the entities |
143 | 0 | getEntities(); |
144 | |
|
145 | 0 | return true; |
146 | 0 | } |
147 | | |
148 | | // ------------------------------------------------------------------------------------------------ |
149 | | bool Q3BSPFileParser::validateFormat() |
150 | 0 | { |
151 | 0 | sQ3BSPHeader *pHeader = (sQ3BSPHeader*) &m_Data[ 0 ]; |
152 | 0 | m_sOffset += sizeof( sQ3BSPHeader ); |
153 | | |
154 | | // Version and identify string validation |
155 | 0 | if (pHeader->strID[ 0 ] != 'I' || pHeader->strID[ 1 ] != 'B' || pHeader->strID[ 2 ] != 'S' |
156 | 0 | || pHeader->strID[ 3 ] != 'P') |
157 | 0 | { |
158 | 0 | return false; |
159 | 0 | } |
160 | | |
161 | 0 | return true; |
162 | 0 | } |
163 | | |
164 | | // ------------------------------------------------------------------------------------------------ |
165 | | void Q3BSPFileParser::getLumps() |
166 | 0 | { |
167 | 0 | size_t Offset = m_sOffset; |
168 | 0 | m_pModel->m_Lumps.resize( kMaxLumps ); |
169 | 0 | for ( size_t idx=0; idx < kMaxLumps; idx++ ) |
170 | 0 | { |
171 | 0 | sQ3BSPLump *pLump = new sQ3BSPLump; |
172 | 0 | memcpy( pLump, &m_Data[ Offset ], sizeof( sQ3BSPLump ) ); |
173 | 0 | Offset += sizeof( sQ3BSPLump ); |
174 | 0 | m_pModel->m_Lumps[ idx ] = pLump; |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | | // ------------------------------------------------------------------------------------------------ |
179 | | void Q3BSPFileParser::countLumps() |
180 | 0 | { |
181 | 0 | m_pModel->m_Vertices.resize( m_pModel->m_Lumps[ kVertices ]->iSize / sizeof( sQ3BSPVertex ) ); |
182 | 0 | m_pModel->m_Indices.resize( m_pModel->m_Lumps[ kMeshVerts ]->iSize / sizeof( int ) ); |
183 | 0 | m_pModel->m_Faces.resize( m_pModel->m_Lumps[ kFaces ]->iSize / sizeof( sQ3BSPFace ) ); |
184 | 0 | m_pModel->m_Textures.resize( m_pModel->m_Lumps[ kTextures ]->iSize / sizeof( sQ3BSPTexture ) ); |
185 | 0 | m_pModel->m_Lightmaps.resize( m_pModel->m_Lumps[ kLightmaps ]->iSize / sizeof( sQ3BSPLightmap ) ); |
186 | 0 | } |
187 | | |
188 | | // ------------------------------------------------------------------------------------------------ |
189 | | void Q3BSPFileParser::getVertices() |
190 | 0 | { |
191 | 0 | size_t Offset = m_pModel->m_Lumps[ kVertices ]->iOffset; |
192 | 0 | for ( size_t idx = 0; idx < m_pModel->m_Vertices.size(); idx++ ) |
193 | 0 | { |
194 | 0 | sQ3BSPVertex *pVertex = new sQ3BSPVertex; |
195 | 0 | memcpy( pVertex, &m_Data[ Offset ], sizeof( sQ3BSPVertex ) ); |
196 | 0 | Offset += sizeof( sQ3BSPVertex ); |
197 | 0 | m_pModel->m_Vertices[ idx ] = pVertex; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | // ------------------------------------------------------------------------------------------------ |
202 | | void Q3BSPFileParser::getIndices() |
203 | 0 | { |
204 | 0 | ai_assert(nullptr != m_pModel ); |
205 | |
|
206 | 0 | sQ3BSPLump *lump = m_pModel->m_Lumps[ kMeshVerts ]; |
207 | 0 | size_t Offset = (size_t) lump->iOffset; |
208 | 0 | const size_t nIndices = lump->iSize / sizeof( int ); |
209 | 0 | m_pModel->m_Indices.resize( nIndices ); |
210 | 0 | memcpy( &m_pModel->m_Indices[ 0 ], &m_Data[ Offset ], lump->iSize ); |
211 | 0 | } |
212 | | |
213 | | // ------------------------------------------------------------------------------------------------ |
214 | | void Q3BSPFileParser::getFaces() |
215 | 0 | { |
216 | 0 | ai_assert(nullptr != m_pModel ); |
217 | |
|
218 | 0 | size_t Offset = m_pModel->m_Lumps[ kFaces ]->iOffset; |
219 | 0 | for ( size_t idx = 0; idx < m_pModel->m_Faces.size(); idx++ ) |
220 | 0 | { |
221 | 0 | sQ3BSPFace *pFace = new sQ3BSPFace; |
222 | 0 | memcpy( pFace, &m_Data[ Offset ], sizeof( sQ3BSPFace ) ); |
223 | 0 | m_pModel->m_Faces[ idx ] = pFace; |
224 | 0 | Offset += sizeof( sQ3BSPFace ); |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | | // ------------------------------------------------------------------------------------------------ |
229 | | void Q3BSPFileParser::getTextures() |
230 | 0 | { |
231 | 0 | ai_assert(nullptr != m_pModel ); |
232 | |
|
233 | 0 | size_t Offset = m_pModel->m_Lumps[ kTextures ]->iOffset; |
234 | 0 | for ( size_t idx=0; idx < m_pModel->m_Textures.size(); idx++ ) |
235 | 0 | { |
236 | 0 | sQ3BSPTexture *pTexture = new sQ3BSPTexture; |
237 | 0 | memcpy( pTexture, &m_Data[ Offset ], sizeof(sQ3BSPTexture) ); |
238 | 0 | m_pModel->m_Textures[ idx ] = pTexture; |
239 | 0 | Offset += sizeof(sQ3BSPTexture); |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | | // ------------------------------------------------------------------------------------------------ |
244 | | void Q3BSPFileParser::getLightMaps() |
245 | 0 | { |
246 | 0 | ai_assert(nullptr != m_pModel ); |
247 | |
|
248 | 0 | size_t Offset = m_pModel->m_Lumps[kLightmaps]->iOffset; |
249 | 0 | for ( size_t idx=0; idx < m_pModel->m_Lightmaps.size(); idx++ ) |
250 | 0 | { |
251 | 0 | sQ3BSPLightmap *pLightmap = new sQ3BSPLightmap; |
252 | 0 | memcpy( pLightmap, &m_Data[ Offset ], sizeof( sQ3BSPLightmap ) ); |
253 | 0 | Offset += sizeof( sQ3BSPLightmap ); |
254 | 0 | m_pModel->m_Lightmaps[ idx ] = pLightmap; |
255 | 0 | } |
256 | 0 | } |
257 | | |
258 | | // ------------------------------------------------------------------------------------------------ |
259 | 0 | void Q3BSPFileParser::getEntities() { |
260 | 0 | const int size = m_pModel->m_Lumps[ kEntities ]->iSize; |
261 | 0 | m_pModel->m_EntityData.resize( size ); |
262 | 0 | if ( size > 0 ) { |
263 | 0 | size_t Offset = m_pModel->m_Lumps[ kEntities ]->iOffset; |
264 | 0 | memcpy( &m_pModel->m_EntityData[ 0 ], &m_Data[ Offset ], sizeof( char ) * size ); |
265 | 0 | } |
266 | 0 | } |
267 | | |
268 | | // ------------------------------------------------------------------------------------------------ |
269 | | |
270 | | } // Namespace Assimp |
271 | | |
272 | | #endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER |