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