rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file Implementation of the XFile parser helper class */
|
nuclear@0
|
43
|
nuclear@0
|
44 #include "AssimpPCH.h"
|
nuclear@0
|
45 #ifndef ASSIMP_BUILD_NO_X_IMPORTER
|
nuclear@0
|
46
|
nuclear@0
|
47 #include "XFileParser.h"
|
nuclear@0
|
48 #include "XFileHelper.h"
|
nuclear@0
|
49 #include "fast_atof.h"
|
nuclear@0
|
50
|
nuclear@0
|
51 using namespace Assimp;
|
nuclear@0
|
52 using namespace Assimp::XFile;
|
nuclear@0
|
53
|
nuclear@0
|
54 #ifndef ASSIMP_BUILD_NO_COMPRESSED_X
|
nuclear@0
|
55
|
nuclear@0
|
56 # ifdef ASSIMP_BUILD_NO_OWN_ZLIB
|
nuclear@0
|
57 # include <zlib.h>
|
nuclear@0
|
58 # else
|
nuclear@0
|
59 # include "../contrib/zlib/zlib.h"
|
nuclear@0
|
60 # endif
|
nuclear@0
|
61
|
nuclear@0
|
62 // Magic identifier for MSZIP compressed data
|
nuclear@0
|
63 #define MSZIP_MAGIC 0x4B43
|
nuclear@0
|
64 #define MSZIP_BLOCK 32786
|
nuclear@0
|
65
|
nuclear@0
|
66 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
67 // Dummy memory wrappers for use with zlib
|
nuclear@0
|
68 static void* dummy_alloc (void* /*opaque*/, unsigned int items, unsigned int size) {
|
nuclear@0
|
69 return ::operator new(items*size);
|
nuclear@0
|
70 }
|
nuclear@0
|
71
|
nuclear@0
|
72 static void dummy_free (void* /*opaque*/, void* address) {
|
nuclear@0
|
73 return ::operator delete(address);
|
nuclear@0
|
74 }
|
nuclear@0
|
75
|
nuclear@0
|
76 #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
|
nuclear@0
|
77
|
nuclear@0
|
78 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
79 // Constructor. Creates a data structure out of the XFile given in the memory block.
|
nuclear@0
|
80 XFileParser::XFileParser( const std::vector<char>& pBuffer)
|
nuclear@0
|
81 {
|
nuclear@0
|
82 mMajorVersion = mMinorVersion = 0;
|
nuclear@0
|
83 mIsBinaryFormat = false;
|
nuclear@0
|
84 mBinaryNumCount = 0;
|
nuclear@0
|
85 P = End = NULL;
|
nuclear@0
|
86 mLineNumber = 0;
|
nuclear@0
|
87 mScene = NULL;
|
nuclear@0
|
88
|
nuclear@0
|
89 // vector to store uncompressed file for INFLATE'd X files
|
nuclear@0
|
90 std::vector<char> uncompressed;
|
nuclear@0
|
91
|
nuclear@0
|
92 // set up memory pointers
|
nuclear@0
|
93 P = &pBuffer.front();
|
nuclear@0
|
94 End = P + pBuffer.size() - 1;
|
nuclear@0
|
95
|
nuclear@0
|
96 // check header
|
nuclear@0
|
97 if( strncmp( P, "xof ", 4) != 0)
|
nuclear@0
|
98 throw DeadlyImportError( "Header mismatch, file is not an XFile.");
|
nuclear@0
|
99
|
nuclear@0
|
100 // read version. It comes in a four byte format such as "0302"
|
nuclear@0
|
101 mMajorVersion = (unsigned int)(P[4] - 48) * 10 + (unsigned int)(P[5] - 48);
|
nuclear@0
|
102 mMinorVersion = (unsigned int)(P[6] - 48) * 10 + (unsigned int)(P[7] - 48);
|
nuclear@0
|
103
|
nuclear@0
|
104 bool compressed = false;
|
nuclear@0
|
105
|
nuclear@0
|
106 // txt - pure ASCII text format
|
nuclear@0
|
107 if( strncmp( P + 8, "txt ", 4) == 0)
|
nuclear@0
|
108 mIsBinaryFormat = false;
|
nuclear@0
|
109
|
nuclear@0
|
110 // bin - Binary format
|
nuclear@0
|
111 else if( strncmp( P + 8, "bin ", 4) == 0)
|
nuclear@0
|
112 mIsBinaryFormat = true;
|
nuclear@0
|
113
|
nuclear@0
|
114 // tzip - Inflate compressed text format
|
nuclear@0
|
115 else if( strncmp( P + 8, "tzip", 4) == 0)
|
nuclear@0
|
116 {
|
nuclear@0
|
117 mIsBinaryFormat = false;
|
nuclear@0
|
118 compressed = true;
|
nuclear@0
|
119 }
|
nuclear@0
|
120 // bzip - Inflate compressed binary format
|
nuclear@0
|
121 else if( strncmp( P + 8, "bzip", 4) == 0)
|
nuclear@0
|
122 {
|
nuclear@0
|
123 mIsBinaryFormat = true;
|
nuclear@0
|
124 compressed = true;
|
nuclear@0
|
125 }
|
nuclear@0
|
126 else ThrowException( boost::str(boost::format("Unsupported xfile format '%c%c%c%c'")
|
nuclear@0
|
127 % P[8] % P[9] % P[10] % P[11]));
|
nuclear@0
|
128
|
nuclear@0
|
129 // float size
|
nuclear@0
|
130 mBinaryFloatSize = (unsigned int)(P[12] - 48) * 1000
|
nuclear@0
|
131 + (unsigned int)(P[13] - 48) * 100
|
nuclear@0
|
132 + (unsigned int)(P[14] - 48) * 10
|
nuclear@0
|
133 + (unsigned int)(P[15] - 48);
|
nuclear@0
|
134
|
nuclear@0
|
135 if( mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
|
nuclear@0
|
136 ThrowException( boost::str( boost::format( "Unknown float size %1% specified in xfile header.")
|
nuclear@0
|
137 % mBinaryFloatSize));
|
nuclear@0
|
138
|
nuclear@0
|
139 P += 16;
|
nuclear@0
|
140
|
nuclear@0
|
141 // If this is a compressed X file, apply the inflate algorithm to it
|
nuclear@0
|
142 if (compressed)
|
nuclear@0
|
143 {
|
nuclear@0
|
144 #ifdef ASSIMP_BUILD_NO_COMPRESSED_X
|
nuclear@0
|
145 throw DeadlyImportError("Assimp was built without compressed X support");
|
nuclear@0
|
146 #else
|
nuclear@0
|
147 /* ///////////////////////////////////////////////////////////////////////
|
nuclear@0
|
148 * COMPRESSED X FILE FORMAT
|
nuclear@0
|
149 * ///////////////////////////////////////////////////////////////////////
|
nuclear@0
|
150 * [xhead]
|
nuclear@0
|
151 * 2 major
|
nuclear@0
|
152 * 2 minor
|
nuclear@0
|
153 * 4 type // bzip,tzip
|
nuclear@0
|
154 * [mszip_master_head]
|
nuclear@0
|
155 * 4 unkn // checksum?
|
nuclear@0
|
156 * 2 unkn // flags? (seems to be constant)
|
nuclear@0
|
157 * [mszip_head]
|
nuclear@0
|
158 * 2 ofs // offset to next section
|
nuclear@0
|
159 * 2 magic // 'CK'
|
nuclear@0
|
160 * ... ofs bytes of data
|
nuclear@0
|
161 * ... next mszip_head
|
nuclear@0
|
162 *
|
nuclear@0
|
163 * http://www.kdedevelopers.org/node/3181 has been very helpful.
|
nuclear@0
|
164 * ///////////////////////////////////////////////////////////////////////
|
nuclear@0
|
165 */
|
nuclear@0
|
166
|
nuclear@0
|
167 // build a zlib stream
|
nuclear@0
|
168 z_stream stream;
|
nuclear@0
|
169 stream.opaque = NULL;
|
nuclear@0
|
170 stream.zalloc = &dummy_alloc;
|
nuclear@0
|
171 stream.zfree = &dummy_free;
|
nuclear@0
|
172 stream.data_type = (mIsBinaryFormat ? Z_BINARY : Z_ASCII);
|
nuclear@0
|
173
|
nuclear@0
|
174 // initialize the inflation algorithm
|
nuclear@0
|
175 ::inflateInit2(&stream, -MAX_WBITS);
|
nuclear@0
|
176
|
nuclear@0
|
177 // skip unknown data (checksum, flags?)
|
nuclear@0
|
178 P += 6;
|
nuclear@0
|
179
|
nuclear@0
|
180 // First find out how much storage we'll need. Count sections.
|
nuclear@0
|
181 const char* P1 = P;
|
nuclear@0
|
182 unsigned int est_out = 0;
|
nuclear@0
|
183
|
nuclear@0
|
184 while (P1 + 3 < End)
|
nuclear@0
|
185 {
|
nuclear@0
|
186 // read next offset
|
nuclear@0
|
187 uint16_t ofs = *((uint16_t*)P1);
|
nuclear@0
|
188 AI_SWAP2(ofs); P1 += 2;
|
nuclear@0
|
189
|
nuclear@0
|
190 if (ofs >= MSZIP_BLOCK)
|
nuclear@0
|
191 throw DeadlyImportError("X: Invalid offset to next MSZIP compressed block");
|
nuclear@0
|
192
|
nuclear@0
|
193 // check magic word
|
nuclear@0
|
194 uint16_t magic = *((uint16_t*)P1);
|
nuclear@0
|
195 AI_SWAP2(magic); P1 += 2;
|
nuclear@0
|
196
|
nuclear@0
|
197 if (magic != MSZIP_MAGIC)
|
nuclear@0
|
198 throw DeadlyImportError("X: Unsupported compressed format, expected MSZIP header");
|
nuclear@0
|
199
|
nuclear@0
|
200 // and advance to the next offset
|
nuclear@0
|
201 P1 += ofs;
|
nuclear@0
|
202 est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 // Allocate storage and terminating zero and do the actual uncompressing
|
nuclear@0
|
206 uncompressed.resize(est_out + 1);
|
nuclear@0
|
207 char* out = &uncompressed.front();
|
nuclear@0
|
208 while (P + 3 < End)
|
nuclear@0
|
209 {
|
nuclear@0
|
210 uint16_t ofs = *((uint16_t*)P);
|
nuclear@0
|
211 AI_SWAP2(ofs);
|
nuclear@0
|
212 P += 4;
|
nuclear@0
|
213
|
nuclear@0
|
214 // push data to the stream
|
nuclear@0
|
215 stream.next_in = (Bytef*)P;
|
nuclear@0
|
216 stream.avail_in = ofs;
|
nuclear@0
|
217 stream.next_out = (Bytef*)out;
|
nuclear@0
|
218 stream.avail_out = MSZIP_BLOCK;
|
nuclear@0
|
219
|
nuclear@0
|
220 // and decompress the data ....
|
nuclear@0
|
221 int ret = ::inflate( &stream, Z_SYNC_FLUSH );
|
nuclear@0
|
222 if (ret != Z_OK && ret != Z_STREAM_END)
|
nuclear@0
|
223 throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
|
nuclear@0
|
224
|
nuclear@0
|
225 ::inflateReset( &stream );
|
nuclear@0
|
226 ::inflateSetDictionary( &stream, (const Bytef*)out , MSZIP_BLOCK - stream.avail_out );
|
nuclear@0
|
227
|
nuclear@0
|
228 // and advance to the next offset
|
nuclear@0
|
229 out += MSZIP_BLOCK - stream.avail_out;
|
nuclear@0
|
230 P += ofs;
|
nuclear@0
|
231 }
|
nuclear@0
|
232
|
nuclear@0
|
233 // terminate zlib
|
nuclear@0
|
234 ::inflateEnd(&stream);
|
nuclear@0
|
235
|
nuclear@0
|
236 // ok, update pointers to point to the uncompressed file data
|
nuclear@0
|
237 P = &uncompressed[0];
|
nuclear@0
|
238 End = out;
|
nuclear@0
|
239
|
nuclear@0
|
240 // FIXME: we don't need the compressed data anymore, could release
|
nuclear@0
|
241 // it already for better memory usage. Consider breaking const-co.
|
nuclear@0
|
242 DefaultLogger::get()->info("Successfully decompressed MSZIP-compressed file");
|
nuclear@0
|
243 #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
|
nuclear@0
|
244 }
|
nuclear@0
|
245 else
|
nuclear@0
|
246 {
|
nuclear@0
|
247 // start reading here
|
nuclear@0
|
248 ReadUntilEndOfLine();
|
nuclear@0
|
249 }
|
nuclear@0
|
250
|
nuclear@0
|
251 mScene = new Scene;
|
nuclear@0
|
252 ParseFile();
|
nuclear@0
|
253
|
nuclear@0
|
254 // filter the imported hierarchy for some degenerated cases
|
nuclear@0
|
255 if( mScene->mRootNode) {
|
nuclear@0
|
256 FilterHierarchy( mScene->mRootNode);
|
nuclear@0
|
257 }
|
nuclear@0
|
258 }
|
nuclear@0
|
259
|
nuclear@0
|
260 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
261 // Destructor. Destroys all imported data along with it
|
nuclear@0
|
262 XFileParser::~XFileParser()
|
nuclear@0
|
263 {
|
nuclear@0
|
264 // kill everything we created
|
nuclear@0
|
265 delete mScene;
|
nuclear@0
|
266 }
|
nuclear@0
|
267
|
nuclear@0
|
268 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
269 void XFileParser::ParseFile()
|
nuclear@0
|
270 {
|
nuclear@0
|
271 bool running = true;
|
nuclear@0
|
272 while( running )
|
nuclear@0
|
273 {
|
nuclear@0
|
274 // read name of next object
|
nuclear@0
|
275 std::string objectName = GetNextToken();
|
nuclear@0
|
276 if (objectName.length() == 0)
|
nuclear@0
|
277 break;
|
nuclear@0
|
278
|
nuclear@0
|
279 // parse specific object
|
nuclear@0
|
280 if( objectName == "template")
|
nuclear@0
|
281 ParseDataObjectTemplate();
|
nuclear@0
|
282 else
|
nuclear@0
|
283 if( objectName == "Frame")
|
nuclear@0
|
284 ParseDataObjectFrame( NULL);
|
nuclear@0
|
285 else
|
nuclear@0
|
286 if( objectName == "Mesh")
|
nuclear@0
|
287 {
|
nuclear@0
|
288 // some meshes have no frames at all
|
nuclear@0
|
289 Mesh* mesh = new Mesh;
|
nuclear@0
|
290 ParseDataObjectMesh( mesh);
|
nuclear@0
|
291 mScene->mGlobalMeshes.push_back( mesh);
|
nuclear@0
|
292 } else
|
nuclear@0
|
293 if( objectName == "AnimTicksPerSecond")
|
nuclear@0
|
294 ParseDataObjectAnimTicksPerSecond();
|
nuclear@0
|
295 else
|
nuclear@0
|
296 if( objectName == "AnimationSet")
|
nuclear@0
|
297 ParseDataObjectAnimationSet();
|
nuclear@0
|
298 else
|
nuclear@0
|
299 if( objectName == "Material")
|
nuclear@0
|
300 {
|
nuclear@0
|
301 // Material outside of a mesh or node
|
nuclear@0
|
302 Material material;
|
nuclear@0
|
303 ParseDataObjectMaterial( &material);
|
nuclear@0
|
304 mScene->mGlobalMaterials.push_back( material);
|
nuclear@0
|
305 } else
|
nuclear@0
|
306 if( objectName == "}")
|
nuclear@0
|
307 {
|
nuclear@0
|
308 // whatever?
|
nuclear@0
|
309 DefaultLogger::get()->warn("} found in dataObject");
|
nuclear@0
|
310 } else
|
nuclear@0
|
311 {
|
nuclear@0
|
312 // unknown format
|
nuclear@0
|
313 DefaultLogger::get()->warn("Unknown data object in animation of .x file");
|
nuclear@0
|
314 ParseUnknownDataObject();
|
nuclear@0
|
315 }
|
nuclear@0
|
316 }
|
nuclear@0
|
317 }
|
nuclear@0
|
318
|
nuclear@0
|
319 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
320 void XFileParser::ParseDataObjectTemplate()
|
nuclear@0
|
321 {
|
nuclear@0
|
322 // parse a template data object. Currently not stored.
|
nuclear@0
|
323 std::string name;
|
nuclear@0
|
324 readHeadOfDataObject( &name);
|
nuclear@0
|
325
|
nuclear@0
|
326 // read GUID
|
nuclear@0
|
327 std::string guid = GetNextToken();
|
nuclear@0
|
328
|
nuclear@0
|
329 // read and ignore data members
|
nuclear@0
|
330 bool running = true;
|
nuclear@0
|
331 while ( running )
|
nuclear@0
|
332 {
|
nuclear@0
|
333 std::string s = GetNextToken();
|
nuclear@0
|
334
|
nuclear@0
|
335 if( s == "}")
|
nuclear@0
|
336 break;
|
nuclear@0
|
337
|
nuclear@0
|
338 if( s.length() == 0)
|
nuclear@0
|
339 ThrowException( "Unexpected end of file reached while parsing template definition");
|
nuclear@0
|
340 }
|
nuclear@0
|
341 }
|
nuclear@0
|
342
|
nuclear@0
|
343 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
344 void XFileParser::ParseDataObjectFrame( Node* pParent)
|
nuclear@0
|
345 {
|
nuclear@0
|
346 // A coordinate frame, or "frame of reference." The Frame template
|
nuclear@0
|
347 // is open and can contain any object. The Direct3D extensions (D3DX)
|
nuclear@0
|
348 // mesh-loading functions recognize Mesh, FrameTransformMatrix, and
|
nuclear@0
|
349 // Frame template instances as child objects when loading a Frame
|
nuclear@0
|
350 // instance.
|
nuclear@0
|
351 std::string name;
|
nuclear@0
|
352 readHeadOfDataObject(&name);
|
nuclear@0
|
353
|
nuclear@0
|
354 // create a named node and place it at its parent, if given
|
nuclear@0
|
355 Node* node = new Node( pParent);
|
nuclear@0
|
356 node->mName = name;
|
nuclear@0
|
357 if( pParent)
|
nuclear@0
|
358 {
|
nuclear@0
|
359 pParent->mChildren.push_back( node);
|
nuclear@0
|
360 } else
|
nuclear@0
|
361 {
|
nuclear@0
|
362 // there might be multiple root nodes
|
nuclear@0
|
363 if( mScene->mRootNode != NULL)
|
nuclear@0
|
364 {
|
nuclear@0
|
365 // place a dummy root if not there
|
nuclear@0
|
366 if( mScene->mRootNode->mName != "$dummy_root")
|
nuclear@0
|
367 {
|
nuclear@0
|
368 Node* exroot = mScene->mRootNode;
|
nuclear@0
|
369 mScene->mRootNode = new Node( NULL);
|
nuclear@0
|
370 mScene->mRootNode->mName = "$dummy_root";
|
nuclear@0
|
371 mScene->mRootNode->mChildren.push_back( exroot);
|
nuclear@0
|
372 exroot->mParent = mScene->mRootNode;
|
nuclear@0
|
373 }
|
nuclear@0
|
374 // put the new node as its child instead
|
nuclear@0
|
375 mScene->mRootNode->mChildren.push_back( node);
|
nuclear@0
|
376 node->mParent = mScene->mRootNode;
|
nuclear@0
|
377 } else
|
nuclear@0
|
378 {
|
nuclear@0
|
379 // it's the first node imported. place it as root
|
nuclear@0
|
380 mScene->mRootNode = node;
|
nuclear@0
|
381 }
|
nuclear@0
|
382 }
|
nuclear@0
|
383
|
nuclear@0
|
384 // Now inside a frame.
|
nuclear@0
|
385 // read tokens until closing brace is reached.
|
nuclear@0
|
386 bool running = true;
|
nuclear@0
|
387 while ( running )
|
nuclear@0
|
388 {
|
nuclear@0
|
389 std::string objectName = GetNextToken();
|
nuclear@0
|
390 if (objectName.size() == 0)
|
nuclear@0
|
391 ThrowException( "Unexpected end of file reached while parsing frame");
|
nuclear@0
|
392
|
nuclear@0
|
393 if( objectName == "}")
|
nuclear@0
|
394 break; // frame finished
|
nuclear@0
|
395 else
|
nuclear@0
|
396 if( objectName == "Frame")
|
nuclear@0
|
397 ParseDataObjectFrame( node); // child frame
|
nuclear@0
|
398 else
|
nuclear@0
|
399 if( objectName == "FrameTransformMatrix")
|
nuclear@0
|
400 ParseDataObjectTransformationMatrix( node->mTrafoMatrix);
|
nuclear@0
|
401 else
|
nuclear@0
|
402 if( objectName == "Mesh")
|
nuclear@0
|
403 {
|
nuclear@0
|
404 Mesh* mesh = new Mesh;
|
nuclear@0
|
405 node->mMeshes.push_back( mesh);
|
nuclear@0
|
406 ParseDataObjectMesh( mesh);
|
nuclear@0
|
407 } else
|
nuclear@0
|
408 {
|
nuclear@0
|
409 DefaultLogger::get()->warn("Unknown data object in frame in x file");
|
nuclear@0
|
410 ParseUnknownDataObject();
|
nuclear@0
|
411 }
|
nuclear@0
|
412 }
|
nuclear@0
|
413 }
|
nuclear@0
|
414
|
nuclear@0
|
415 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
416 void XFileParser::ParseDataObjectTransformationMatrix( aiMatrix4x4& pMatrix)
|
nuclear@0
|
417 {
|
nuclear@0
|
418 // read header, we're not interested if it has a name
|
nuclear@0
|
419 readHeadOfDataObject();
|
nuclear@0
|
420
|
nuclear@0
|
421 // read its components
|
nuclear@0
|
422 pMatrix.a1 = ReadFloat(); pMatrix.b1 = ReadFloat();
|
nuclear@0
|
423 pMatrix.c1 = ReadFloat(); pMatrix.d1 = ReadFloat();
|
nuclear@0
|
424 pMatrix.a2 = ReadFloat(); pMatrix.b2 = ReadFloat();
|
nuclear@0
|
425 pMatrix.c2 = ReadFloat(); pMatrix.d2 = ReadFloat();
|
nuclear@0
|
426 pMatrix.a3 = ReadFloat(); pMatrix.b3 = ReadFloat();
|
nuclear@0
|
427 pMatrix.c3 = ReadFloat(); pMatrix.d3 = ReadFloat();
|
nuclear@0
|
428 pMatrix.a4 = ReadFloat(); pMatrix.b4 = ReadFloat();
|
nuclear@0
|
429 pMatrix.c4 = ReadFloat(); pMatrix.d4 = ReadFloat();
|
nuclear@0
|
430
|
nuclear@0
|
431 // trailing symbols
|
nuclear@0
|
432 CheckForSemicolon();
|
nuclear@0
|
433 CheckForClosingBrace();
|
nuclear@0
|
434 }
|
nuclear@0
|
435
|
nuclear@0
|
436 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
437 void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
|
nuclear@0
|
438 {
|
nuclear@0
|
439 std::string name;
|
nuclear@0
|
440 readHeadOfDataObject( &name);
|
nuclear@0
|
441
|
nuclear@0
|
442 // read vertex count
|
nuclear@0
|
443 unsigned int numVertices = ReadInt();
|
nuclear@0
|
444 pMesh->mPositions.resize( numVertices);
|
nuclear@0
|
445
|
nuclear@0
|
446 // read vertices
|
nuclear@0
|
447 for( unsigned int a = 0; a < numVertices; a++)
|
nuclear@0
|
448 pMesh->mPositions[a] = ReadVector3();
|
nuclear@0
|
449
|
nuclear@0
|
450 // read position faces
|
nuclear@0
|
451 unsigned int numPosFaces = ReadInt();
|
nuclear@0
|
452 pMesh->mPosFaces.resize( numPosFaces);
|
nuclear@0
|
453 for( unsigned int a = 0; a < numPosFaces; a++)
|
nuclear@0
|
454 {
|
nuclear@0
|
455 unsigned int numIndices = ReadInt();
|
nuclear@0
|
456 if( numIndices < 3)
|
nuclear@0
|
457 ThrowException( boost::str( boost::format( "Invalid index count %1% for face %2%.") % numIndices % a));
|
nuclear@0
|
458
|
nuclear@0
|
459 // read indices
|
nuclear@0
|
460 Face& face = pMesh->mPosFaces[a];
|
nuclear@0
|
461 for( unsigned int b = 0; b < numIndices; b++)
|
nuclear@0
|
462 face.mIndices.push_back( ReadInt());
|
nuclear@0
|
463 TestForSeparator();
|
nuclear@0
|
464 }
|
nuclear@0
|
465
|
nuclear@0
|
466 // here, other data objects may follow
|
nuclear@0
|
467 bool running = true;
|
nuclear@0
|
468 while ( running )
|
nuclear@0
|
469 {
|
nuclear@0
|
470 std::string objectName = GetNextToken();
|
nuclear@0
|
471
|
nuclear@0
|
472 if( objectName.size() == 0)
|
nuclear@0
|
473 ThrowException( "Unexpected end of file while parsing mesh structure");
|
nuclear@0
|
474 else
|
nuclear@0
|
475 if( objectName == "}")
|
nuclear@0
|
476 break; // mesh finished
|
nuclear@0
|
477 else
|
nuclear@0
|
478 if( objectName == "MeshNormals")
|
nuclear@0
|
479 ParseDataObjectMeshNormals( pMesh);
|
nuclear@0
|
480 else
|
nuclear@0
|
481 if( objectName == "MeshTextureCoords")
|
nuclear@0
|
482 ParseDataObjectMeshTextureCoords( pMesh);
|
nuclear@0
|
483 else
|
nuclear@0
|
484 if( objectName == "MeshVertexColors")
|
nuclear@0
|
485 ParseDataObjectMeshVertexColors( pMesh);
|
nuclear@0
|
486 else
|
nuclear@0
|
487 if( objectName == "MeshMaterialList")
|
nuclear@0
|
488 ParseDataObjectMeshMaterialList( pMesh);
|
nuclear@0
|
489 else
|
nuclear@0
|
490 if( objectName == "VertexDuplicationIndices")
|
nuclear@0
|
491 ParseUnknownDataObject(); // we'll ignore vertex duplication indices
|
nuclear@0
|
492 else
|
nuclear@0
|
493 if( objectName == "XSkinMeshHeader")
|
nuclear@0
|
494 ParseDataObjectSkinMeshHeader( pMesh);
|
nuclear@0
|
495 else
|
nuclear@0
|
496 if( objectName == "SkinWeights")
|
nuclear@0
|
497 ParseDataObjectSkinWeights( pMesh);
|
nuclear@0
|
498 else
|
nuclear@0
|
499 {
|
nuclear@0
|
500 DefaultLogger::get()->warn("Unknown data object in mesh in x file");
|
nuclear@0
|
501 ParseUnknownDataObject();
|
nuclear@0
|
502 }
|
nuclear@0
|
503 }
|
nuclear@0
|
504 }
|
nuclear@0
|
505
|
nuclear@0
|
506 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
507 void XFileParser::ParseDataObjectSkinWeights( Mesh *pMesh)
|
nuclear@0
|
508 {
|
nuclear@0
|
509 readHeadOfDataObject();
|
nuclear@0
|
510
|
nuclear@0
|
511 std::string transformNodeName;
|
nuclear@0
|
512 GetNextTokenAsString( transformNodeName);
|
nuclear@0
|
513
|
nuclear@0
|
514 pMesh->mBones.push_back( Bone());
|
nuclear@0
|
515 Bone& bone = pMesh->mBones.back();
|
nuclear@0
|
516 bone.mName = transformNodeName;
|
nuclear@0
|
517
|
nuclear@0
|
518 // read vertex weights
|
nuclear@0
|
519 unsigned int numWeights = ReadInt();
|
nuclear@0
|
520 bone.mWeights.reserve( numWeights);
|
nuclear@0
|
521
|
nuclear@0
|
522 for( unsigned int a = 0; a < numWeights; a++)
|
nuclear@0
|
523 {
|
nuclear@0
|
524 BoneWeight weight;
|
nuclear@0
|
525 weight.mVertex = ReadInt();
|
nuclear@0
|
526 bone.mWeights.push_back( weight);
|
nuclear@0
|
527 }
|
nuclear@0
|
528
|
nuclear@0
|
529 // read vertex weights
|
nuclear@0
|
530 for( unsigned int a = 0; a < numWeights; a++)
|
nuclear@0
|
531 bone.mWeights[a].mWeight = ReadFloat();
|
nuclear@0
|
532
|
nuclear@0
|
533 // read matrix offset
|
nuclear@0
|
534 bone.mOffsetMatrix.a1 = ReadFloat(); bone.mOffsetMatrix.b1 = ReadFloat();
|
nuclear@0
|
535 bone.mOffsetMatrix.c1 = ReadFloat(); bone.mOffsetMatrix.d1 = ReadFloat();
|
nuclear@0
|
536 bone.mOffsetMatrix.a2 = ReadFloat(); bone.mOffsetMatrix.b2 = ReadFloat();
|
nuclear@0
|
537 bone.mOffsetMatrix.c2 = ReadFloat(); bone.mOffsetMatrix.d2 = ReadFloat();
|
nuclear@0
|
538 bone.mOffsetMatrix.a3 = ReadFloat(); bone.mOffsetMatrix.b3 = ReadFloat();
|
nuclear@0
|
539 bone.mOffsetMatrix.c3 = ReadFloat(); bone.mOffsetMatrix.d3 = ReadFloat();
|
nuclear@0
|
540 bone.mOffsetMatrix.a4 = ReadFloat(); bone.mOffsetMatrix.b4 = ReadFloat();
|
nuclear@0
|
541 bone.mOffsetMatrix.c4 = ReadFloat(); bone.mOffsetMatrix.d4 = ReadFloat();
|
nuclear@0
|
542
|
nuclear@0
|
543 CheckForSemicolon();
|
nuclear@0
|
544 CheckForClosingBrace();
|
nuclear@0
|
545 }
|
nuclear@0
|
546
|
nuclear@0
|
547 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
548 void XFileParser::ParseDataObjectSkinMeshHeader( Mesh* /*pMesh*/ )
|
nuclear@0
|
549 {
|
nuclear@0
|
550 readHeadOfDataObject();
|
nuclear@0
|
551
|
nuclear@0
|
552 /*unsigned int maxSkinWeightsPerVertex =*/ ReadInt();
|
nuclear@0
|
553 /*unsigned int maxSkinWeightsPerFace =*/ ReadInt();
|
nuclear@0
|
554 /*unsigned int numBonesInMesh = */ReadInt();
|
nuclear@0
|
555
|
nuclear@0
|
556 CheckForClosingBrace();
|
nuclear@0
|
557 }
|
nuclear@0
|
558
|
nuclear@0
|
559 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
560 void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh)
|
nuclear@0
|
561 {
|
nuclear@0
|
562 readHeadOfDataObject();
|
nuclear@0
|
563
|
nuclear@0
|
564 // read count
|
nuclear@0
|
565 unsigned int numNormals = ReadInt();
|
nuclear@0
|
566 pMesh->mNormals.resize( numNormals);
|
nuclear@0
|
567
|
nuclear@0
|
568 // read normal vectors
|
nuclear@0
|
569 for( unsigned int a = 0; a < numNormals; a++)
|
nuclear@0
|
570 pMesh->mNormals[a] = ReadVector3();
|
nuclear@0
|
571
|
nuclear@0
|
572 // read normal indices
|
nuclear@0
|
573 unsigned int numFaces = ReadInt();
|
nuclear@0
|
574 if( numFaces != pMesh->mPosFaces.size())
|
nuclear@0
|
575 ThrowException( "Normal face count does not match vertex face count.");
|
nuclear@0
|
576
|
nuclear@0
|
577 for( unsigned int a = 0; a < numFaces; a++)
|
nuclear@0
|
578 {
|
nuclear@0
|
579 unsigned int numIndices = ReadInt();
|
nuclear@0
|
580 pMesh->mNormFaces.push_back( Face());
|
nuclear@0
|
581 Face& face = pMesh->mNormFaces.back();
|
nuclear@0
|
582
|
nuclear@0
|
583 for( unsigned int b = 0; b < numIndices; b++)
|
nuclear@0
|
584 face.mIndices.push_back( ReadInt());
|
nuclear@0
|
585
|
nuclear@0
|
586 TestForSeparator();
|
nuclear@0
|
587 }
|
nuclear@0
|
588
|
nuclear@0
|
589 CheckForClosingBrace();
|
nuclear@0
|
590 }
|
nuclear@0
|
591
|
nuclear@0
|
592 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
593 void XFileParser::ParseDataObjectMeshTextureCoords( Mesh* pMesh)
|
nuclear@0
|
594 {
|
nuclear@0
|
595 readHeadOfDataObject();
|
nuclear@0
|
596 if( pMesh->mNumTextures + 1 > AI_MAX_NUMBER_OF_TEXTURECOORDS)
|
nuclear@0
|
597 ThrowException( "Too many sets of texture coordinates");
|
nuclear@0
|
598
|
nuclear@0
|
599 std::vector<aiVector2D>& coords = pMesh->mTexCoords[pMesh->mNumTextures++];
|
nuclear@0
|
600
|
nuclear@0
|
601 unsigned int numCoords = ReadInt();
|
nuclear@0
|
602 if( numCoords != pMesh->mPositions.size())
|
nuclear@0
|
603 ThrowException( "Texture coord count does not match vertex count");
|
nuclear@0
|
604
|
nuclear@0
|
605 coords.resize( numCoords);
|
nuclear@0
|
606 for( unsigned int a = 0; a < numCoords; a++)
|
nuclear@0
|
607 coords[a] = ReadVector2();
|
nuclear@0
|
608
|
nuclear@0
|
609 CheckForClosingBrace();
|
nuclear@0
|
610 }
|
nuclear@0
|
611
|
nuclear@0
|
612 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
613 void XFileParser::ParseDataObjectMeshVertexColors( Mesh* pMesh)
|
nuclear@0
|
614 {
|
nuclear@0
|
615 readHeadOfDataObject();
|
nuclear@0
|
616 if( pMesh->mNumColorSets + 1 > AI_MAX_NUMBER_OF_COLOR_SETS)
|
nuclear@0
|
617 ThrowException( "Too many colorsets");
|
nuclear@0
|
618 std::vector<aiColor4D>& colors = pMesh->mColors[pMesh->mNumColorSets++];
|
nuclear@0
|
619
|
nuclear@0
|
620 unsigned int numColors = ReadInt();
|
nuclear@0
|
621 if( numColors != pMesh->mPositions.size())
|
nuclear@0
|
622 ThrowException( "Vertex color count does not match vertex count");
|
nuclear@0
|
623
|
nuclear@0
|
624 colors.resize( numColors, aiColor4D( 0, 0, 0, 1));
|
nuclear@0
|
625 for( unsigned int a = 0; a < numColors; a++)
|
nuclear@0
|
626 {
|
nuclear@0
|
627 unsigned int index = ReadInt();
|
nuclear@0
|
628 if( index >= pMesh->mPositions.size())
|
nuclear@0
|
629 ThrowException( "Vertex color index out of bounds");
|
nuclear@0
|
630
|
nuclear@0
|
631 colors[index] = ReadRGBA();
|
nuclear@0
|
632 // HACK: (thom) Maxon Cinema XPort plugin puts a third separator here, kwxPort puts a comma.
|
nuclear@0
|
633 // Ignore gracefully.
|
nuclear@0
|
634 if( !mIsBinaryFormat)
|
nuclear@0
|
635 {
|
nuclear@0
|
636 FindNextNoneWhiteSpace();
|
nuclear@0
|
637 if( *P == ';' || *P == ',')
|
nuclear@0
|
638 P++;
|
nuclear@0
|
639 }
|
nuclear@0
|
640 }
|
nuclear@0
|
641
|
nuclear@0
|
642 CheckForClosingBrace();
|
nuclear@0
|
643 }
|
nuclear@0
|
644
|
nuclear@0
|
645 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
646 void XFileParser::ParseDataObjectMeshMaterialList( Mesh* pMesh)
|
nuclear@0
|
647 {
|
nuclear@0
|
648 readHeadOfDataObject();
|
nuclear@0
|
649
|
nuclear@0
|
650 // read material count
|
nuclear@0
|
651 /*unsigned int numMaterials =*/ ReadInt();
|
nuclear@0
|
652 // read non triangulated face material index count
|
nuclear@0
|
653 unsigned int numMatIndices = ReadInt();
|
nuclear@0
|
654
|
nuclear@0
|
655 // some models have a material index count of 1... to be able to read them we
|
nuclear@0
|
656 // replicate this single material index on every face
|
nuclear@0
|
657 if( numMatIndices != pMesh->mPosFaces.size() && numMatIndices != 1)
|
nuclear@0
|
658 ThrowException( "Per-Face material index count does not match face count.");
|
nuclear@0
|
659
|
nuclear@0
|
660 // read per-face material indices
|
nuclear@0
|
661 for( unsigned int a = 0; a < numMatIndices; a++)
|
nuclear@0
|
662 pMesh->mFaceMaterials.push_back( ReadInt());
|
nuclear@0
|
663
|
nuclear@0
|
664 // in version 03.02, the face indices end with two semicolons.
|
nuclear@0
|
665 // commented out version check, as version 03.03 exported from blender also has 2 semicolons
|
nuclear@0
|
666 if( !mIsBinaryFormat) // && MajorVersion == 3 && MinorVersion <= 2)
|
nuclear@0
|
667 {
|
nuclear@0
|
668 if(P < End && *P == ';')
|
nuclear@0
|
669 ++P;
|
nuclear@0
|
670 }
|
nuclear@0
|
671
|
nuclear@0
|
672 // if there was only a single material index, replicate it on all faces
|
nuclear@0
|
673 while( pMesh->mFaceMaterials.size() < pMesh->mPosFaces.size())
|
nuclear@0
|
674 pMesh->mFaceMaterials.push_back( pMesh->mFaceMaterials.front());
|
nuclear@0
|
675
|
nuclear@0
|
676 // read following data objects
|
nuclear@0
|
677 bool running = true;
|
nuclear@0
|
678 while ( running )
|
nuclear@0
|
679 {
|
nuclear@0
|
680 std::string objectName = GetNextToken();
|
nuclear@0
|
681 if( objectName.size() == 0)
|
nuclear@0
|
682 ThrowException( "Unexpected end of file while parsing mesh material list.");
|
nuclear@0
|
683 else
|
nuclear@0
|
684 if( objectName == "}")
|
nuclear@0
|
685 break; // material list finished
|
nuclear@0
|
686 else
|
nuclear@0
|
687 if( objectName == "{")
|
nuclear@0
|
688 {
|
nuclear@0
|
689 // template materials
|
nuclear@0
|
690 std::string matName = GetNextToken();
|
nuclear@0
|
691 Material material;
|
nuclear@0
|
692 material.mIsReference = true;
|
nuclear@0
|
693 material.mName = matName;
|
nuclear@0
|
694 pMesh->mMaterials.push_back( material);
|
nuclear@0
|
695
|
nuclear@0
|
696 CheckForClosingBrace(); // skip }
|
nuclear@0
|
697 } else
|
nuclear@0
|
698 if( objectName == "Material")
|
nuclear@0
|
699 {
|
nuclear@0
|
700 pMesh->mMaterials.push_back( Material());
|
nuclear@0
|
701 ParseDataObjectMaterial( &pMesh->mMaterials.back());
|
nuclear@0
|
702 } else
|
nuclear@0
|
703 if( objectName == ";")
|
nuclear@0
|
704 {
|
nuclear@0
|
705 // ignore
|
nuclear@0
|
706 } else
|
nuclear@0
|
707 {
|
nuclear@0
|
708 DefaultLogger::get()->warn("Unknown data object in material list in x file");
|
nuclear@0
|
709 ParseUnknownDataObject();
|
nuclear@0
|
710 }
|
nuclear@0
|
711 }
|
nuclear@0
|
712 }
|
nuclear@0
|
713
|
nuclear@0
|
714 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
715 void XFileParser::ParseDataObjectMaterial( Material* pMaterial)
|
nuclear@0
|
716 {
|
nuclear@0
|
717 std::string matName;
|
nuclear@0
|
718 readHeadOfDataObject( &matName);
|
nuclear@0
|
719 if( matName.empty())
|
nuclear@0
|
720 matName = std::string( "material") + boost::lexical_cast<std::string>( mLineNumber);
|
nuclear@0
|
721 pMaterial->mName = matName;
|
nuclear@0
|
722 pMaterial->mIsReference = false;
|
nuclear@0
|
723
|
nuclear@0
|
724 // read material values
|
nuclear@0
|
725 pMaterial->mDiffuse = ReadRGBA();
|
nuclear@0
|
726 pMaterial->mSpecularExponent = ReadFloat();
|
nuclear@0
|
727 pMaterial->mSpecular = ReadRGB();
|
nuclear@0
|
728 pMaterial->mEmissive = ReadRGB();
|
nuclear@0
|
729
|
nuclear@0
|
730 // read other data objects
|
nuclear@0
|
731 bool running = true;
|
nuclear@0
|
732 while ( running )
|
nuclear@0
|
733 {
|
nuclear@0
|
734 std::string objectName = GetNextToken();
|
nuclear@0
|
735 if( objectName.size() == 0)
|
nuclear@0
|
736 ThrowException( "Unexpected end of file while parsing mesh material");
|
nuclear@0
|
737 else
|
nuclear@0
|
738 if( objectName == "}")
|
nuclear@0
|
739 break; // material finished
|
nuclear@0
|
740 else
|
nuclear@0
|
741 if( objectName == "TextureFilename" || objectName == "TextureFileName")
|
nuclear@0
|
742 {
|
nuclear@0
|
743 // some exporters write "TextureFileName" instead.
|
nuclear@0
|
744 std::string texname;
|
nuclear@0
|
745 ParseDataObjectTextureFilename( texname);
|
nuclear@0
|
746 pMaterial->mTextures.push_back( TexEntry( texname));
|
nuclear@0
|
747 } else
|
nuclear@0
|
748 if( objectName == "NormalmapFilename" || objectName == "NormalmapFileName")
|
nuclear@0
|
749 {
|
nuclear@0
|
750 // one exporter writes out the normal map in a separate filename tag
|
nuclear@0
|
751 std::string texname;
|
nuclear@0
|
752 ParseDataObjectTextureFilename( texname);
|
nuclear@0
|
753 pMaterial->mTextures.push_back( TexEntry( texname, true));
|
nuclear@0
|
754 } else
|
nuclear@0
|
755 {
|
nuclear@0
|
756 DefaultLogger::get()->warn("Unknown data object in material in x file");
|
nuclear@0
|
757 ParseUnknownDataObject();
|
nuclear@0
|
758 }
|
nuclear@0
|
759 }
|
nuclear@0
|
760 }
|
nuclear@0
|
761
|
nuclear@0
|
762 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
763 void XFileParser::ParseDataObjectAnimTicksPerSecond()
|
nuclear@0
|
764 {
|
nuclear@0
|
765 readHeadOfDataObject();
|
nuclear@0
|
766 mScene->mAnimTicksPerSecond = ReadInt();
|
nuclear@0
|
767 CheckForClosingBrace();
|
nuclear@0
|
768 }
|
nuclear@0
|
769
|
nuclear@0
|
770 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
771 void XFileParser::ParseDataObjectAnimationSet()
|
nuclear@0
|
772 {
|
nuclear@0
|
773 std::string animName;
|
nuclear@0
|
774 readHeadOfDataObject( &animName);
|
nuclear@0
|
775
|
nuclear@0
|
776 Animation* anim = new Animation;
|
nuclear@0
|
777 mScene->mAnims.push_back( anim);
|
nuclear@0
|
778 anim->mName = animName;
|
nuclear@0
|
779
|
nuclear@0
|
780 bool running = true;
|
nuclear@0
|
781 while ( running )
|
nuclear@0
|
782 {
|
nuclear@0
|
783 std::string objectName = GetNextToken();
|
nuclear@0
|
784 if( objectName.length() == 0)
|
nuclear@0
|
785 ThrowException( "Unexpected end of file while parsing animation set.");
|
nuclear@0
|
786 else
|
nuclear@0
|
787 if( objectName == "}")
|
nuclear@0
|
788 break; // animation set finished
|
nuclear@0
|
789 else
|
nuclear@0
|
790 if( objectName == "Animation")
|
nuclear@0
|
791 ParseDataObjectAnimation( anim);
|
nuclear@0
|
792 else
|
nuclear@0
|
793 {
|
nuclear@0
|
794 DefaultLogger::get()->warn("Unknown data object in animation set in x file");
|
nuclear@0
|
795 ParseUnknownDataObject();
|
nuclear@0
|
796 }
|
nuclear@0
|
797 }
|
nuclear@0
|
798 }
|
nuclear@0
|
799
|
nuclear@0
|
800 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
801 void XFileParser::ParseDataObjectAnimation( Animation* pAnim)
|
nuclear@0
|
802 {
|
nuclear@0
|
803 readHeadOfDataObject();
|
nuclear@0
|
804 AnimBone* banim = new AnimBone;
|
nuclear@0
|
805 pAnim->mAnims.push_back( banim);
|
nuclear@0
|
806
|
nuclear@0
|
807 bool running = true;
|
nuclear@0
|
808 while( running )
|
nuclear@0
|
809 {
|
nuclear@0
|
810 std::string objectName = GetNextToken();
|
nuclear@0
|
811
|
nuclear@0
|
812 if( objectName.length() == 0)
|
nuclear@0
|
813 ThrowException( "Unexpected end of file while parsing animation.");
|
nuclear@0
|
814 else
|
nuclear@0
|
815 if( objectName == "}")
|
nuclear@0
|
816 break; // animation finished
|
nuclear@0
|
817 else
|
nuclear@0
|
818 if( objectName == "AnimationKey")
|
nuclear@0
|
819 ParseDataObjectAnimationKey( banim);
|
nuclear@0
|
820 else
|
nuclear@0
|
821 if( objectName == "AnimationOptions")
|
nuclear@0
|
822 ParseUnknownDataObject(); // not interested
|
nuclear@0
|
823 else
|
nuclear@0
|
824 if( objectName == "{")
|
nuclear@0
|
825 {
|
nuclear@0
|
826 // read frame name
|
nuclear@0
|
827 banim->mBoneName = GetNextToken();
|
nuclear@0
|
828 CheckForClosingBrace();
|
nuclear@0
|
829 } else
|
nuclear@0
|
830 {
|
nuclear@0
|
831 DefaultLogger::get()->warn("Unknown data object in animation in x file");
|
nuclear@0
|
832 ParseUnknownDataObject();
|
nuclear@0
|
833 }
|
nuclear@0
|
834 }
|
nuclear@0
|
835 }
|
nuclear@0
|
836
|
nuclear@0
|
837 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
838 void XFileParser::ParseDataObjectAnimationKey( AnimBone* pAnimBone)
|
nuclear@0
|
839 {
|
nuclear@0
|
840 readHeadOfDataObject();
|
nuclear@0
|
841
|
nuclear@0
|
842 // read key type
|
nuclear@0
|
843 unsigned int keyType = ReadInt();
|
nuclear@0
|
844
|
nuclear@0
|
845 // read number of keys
|
nuclear@0
|
846 unsigned int numKeys = ReadInt();
|
nuclear@0
|
847
|
nuclear@0
|
848 for( unsigned int a = 0; a < numKeys; a++)
|
nuclear@0
|
849 {
|
nuclear@0
|
850 // read time
|
nuclear@0
|
851 unsigned int time = ReadInt();
|
nuclear@0
|
852
|
nuclear@0
|
853 // read keys
|
nuclear@0
|
854 switch( keyType)
|
nuclear@0
|
855 {
|
nuclear@0
|
856 case 0: // rotation quaternion
|
nuclear@0
|
857 {
|
nuclear@0
|
858 // read count
|
nuclear@0
|
859 if( ReadInt() != 4)
|
nuclear@0
|
860 ThrowException( "Invalid number of arguments for quaternion key in animation");
|
nuclear@0
|
861
|
nuclear@0
|
862 aiQuatKey key;
|
nuclear@0
|
863 key.mTime = double( time);
|
nuclear@0
|
864 key.mValue.w = ReadFloat();
|
nuclear@0
|
865 key.mValue.x = ReadFloat();
|
nuclear@0
|
866 key.mValue.y = ReadFloat();
|
nuclear@0
|
867 key.mValue.z = ReadFloat();
|
nuclear@0
|
868 pAnimBone->mRotKeys.push_back( key);
|
nuclear@0
|
869
|
nuclear@0
|
870 CheckForSemicolon();
|
nuclear@0
|
871 break;
|
nuclear@0
|
872 }
|
nuclear@0
|
873
|
nuclear@0
|
874 case 1: // scale vector
|
nuclear@0
|
875 case 2: // position vector
|
nuclear@0
|
876 {
|
nuclear@0
|
877 // read count
|
nuclear@0
|
878 if( ReadInt() != 3)
|
nuclear@0
|
879 ThrowException( "Invalid number of arguments for vector key in animation");
|
nuclear@0
|
880
|
nuclear@0
|
881 aiVectorKey key;
|
nuclear@0
|
882 key.mTime = double( time);
|
nuclear@0
|
883 key.mValue = ReadVector3();
|
nuclear@0
|
884
|
nuclear@0
|
885 if( keyType == 2)
|
nuclear@0
|
886 pAnimBone->mPosKeys.push_back( key);
|
nuclear@0
|
887 else
|
nuclear@0
|
888 pAnimBone->mScaleKeys.push_back( key);
|
nuclear@0
|
889
|
nuclear@0
|
890 break;
|
nuclear@0
|
891 }
|
nuclear@0
|
892
|
nuclear@0
|
893 case 3: // combined transformation matrix
|
nuclear@0
|
894 case 4: // denoted both as 3 or as 4
|
nuclear@0
|
895 {
|
nuclear@0
|
896 // read count
|
nuclear@0
|
897 if( ReadInt() != 16)
|
nuclear@0
|
898 ThrowException( "Invalid number of arguments for matrix key in animation");
|
nuclear@0
|
899
|
nuclear@0
|
900 // read matrix
|
nuclear@0
|
901 MatrixKey key;
|
nuclear@0
|
902 key.mTime = double( time);
|
nuclear@0
|
903 key.mMatrix.a1 = ReadFloat(); key.mMatrix.b1 = ReadFloat();
|
nuclear@0
|
904 key.mMatrix.c1 = ReadFloat(); key.mMatrix.d1 = ReadFloat();
|
nuclear@0
|
905 key.mMatrix.a2 = ReadFloat(); key.mMatrix.b2 = ReadFloat();
|
nuclear@0
|
906 key.mMatrix.c2 = ReadFloat(); key.mMatrix.d2 = ReadFloat();
|
nuclear@0
|
907 key.mMatrix.a3 = ReadFloat(); key.mMatrix.b3 = ReadFloat();
|
nuclear@0
|
908 key.mMatrix.c3 = ReadFloat(); key.mMatrix.d3 = ReadFloat();
|
nuclear@0
|
909 key.mMatrix.a4 = ReadFloat(); key.mMatrix.b4 = ReadFloat();
|
nuclear@0
|
910 key.mMatrix.c4 = ReadFloat(); key.mMatrix.d4 = ReadFloat();
|
nuclear@0
|
911 pAnimBone->mTrafoKeys.push_back( key);
|
nuclear@0
|
912
|
nuclear@0
|
913 CheckForSemicolon();
|
nuclear@0
|
914 break;
|
nuclear@0
|
915 }
|
nuclear@0
|
916
|
nuclear@0
|
917 default:
|
nuclear@0
|
918 ThrowException( boost::str( boost::format( "Unknown key type %1% in animation.") % keyType));
|
nuclear@0
|
919 break;
|
nuclear@0
|
920 } // end switch
|
nuclear@0
|
921
|
nuclear@0
|
922 // key separator
|
nuclear@0
|
923 CheckForSeparator();
|
nuclear@0
|
924 }
|
nuclear@0
|
925
|
nuclear@0
|
926 CheckForClosingBrace();
|
nuclear@0
|
927 }
|
nuclear@0
|
928
|
nuclear@0
|
929 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
930 void XFileParser::ParseDataObjectTextureFilename( std::string& pName)
|
nuclear@0
|
931 {
|
nuclear@0
|
932 readHeadOfDataObject();
|
nuclear@0
|
933 GetNextTokenAsString( pName);
|
nuclear@0
|
934 CheckForClosingBrace();
|
nuclear@0
|
935
|
nuclear@0
|
936 // FIX: some files (e.g. AnimationTest.x) have "" as texture file name
|
nuclear@0
|
937 if (!pName.length())
|
nuclear@0
|
938 {
|
nuclear@0
|
939 DefaultLogger::get()->warn("Length of texture file name is zero. Skipping this texture.");
|
nuclear@0
|
940 }
|
nuclear@0
|
941
|
nuclear@0
|
942 // some exporters write double backslash paths out. We simply replace them if we find them
|
nuclear@0
|
943 while( pName.find( "\\\\") != std::string::npos)
|
nuclear@0
|
944 pName.replace( pName.find( "\\\\"), 2, "\\");
|
nuclear@0
|
945 }
|
nuclear@0
|
946
|
nuclear@0
|
947 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
948 void XFileParser::ParseUnknownDataObject()
|
nuclear@0
|
949 {
|
nuclear@0
|
950 // find opening delimiter
|
nuclear@0
|
951 bool running = true;
|
nuclear@0
|
952 while( running )
|
nuclear@0
|
953 {
|
nuclear@0
|
954 std::string t = GetNextToken();
|
nuclear@0
|
955 if( t.length() == 0)
|
nuclear@0
|
956 ThrowException( "Unexpected end of file while parsing unknown segment.");
|
nuclear@0
|
957
|
nuclear@0
|
958 if( t == "{")
|
nuclear@0
|
959 break;
|
nuclear@0
|
960 }
|
nuclear@0
|
961
|
nuclear@0
|
962 unsigned int counter = 1;
|
nuclear@0
|
963
|
nuclear@0
|
964 // parse until closing delimiter
|
nuclear@0
|
965 while( counter > 0)
|
nuclear@0
|
966 {
|
nuclear@0
|
967 std::string t = GetNextToken();
|
nuclear@0
|
968
|
nuclear@0
|
969 if( t.length() == 0)
|
nuclear@0
|
970 ThrowException( "Unexpected end of file while parsing unknown segment.");
|
nuclear@0
|
971
|
nuclear@0
|
972 if( t == "{")
|
nuclear@0
|
973 ++counter;
|
nuclear@0
|
974 else
|
nuclear@0
|
975 if( t == "}")
|
nuclear@0
|
976 --counter;
|
nuclear@0
|
977 }
|
nuclear@0
|
978 }
|
nuclear@0
|
979
|
nuclear@0
|
980 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
981 //! checks for closing curly brace
|
nuclear@0
|
982 void XFileParser::CheckForClosingBrace()
|
nuclear@0
|
983 {
|
nuclear@0
|
984 if( GetNextToken() != "}")
|
nuclear@0
|
985 ThrowException( "Closing brace expected.");
|
nuclear@0
|
986 }
|
nuclear@0
|
987
|
nuclear@0
|
988 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
989 //! checks for one following semicolon
|
nuclear@0
|
990 void XFileParser::CheckForSemicolon()
|
nuclear@0
|
991 {
|
nuclear@0
|
992 if( mIsBinaryFormat)
|
nuclear@0
|
993 return;
|
nuclear@0
|
994
|
nuclear@0
|
995 if( GetNextToken() != ";")
|
nuclear@0
|
996 ThrowException( "Semicolon expected.");
|
nuclear@0
|
997 }
|
nuclear@0
|
998
|
nuclear@0
|
999 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1000 //! checks for a separator char, either a ',' or a ';'
|
nuclear@0
|
1001 void XFileParser::CheckForSeparator()
|
nuclear@0
|
1002 {
|
nuclear@0
|
1003 if( mIsBinaryFormat)
|
nuclear@0
|
1004 return;
|
nuclear@0
|
1005
|
nuclear@0
|
1006 std::string token = GetNextToken();
|
nuclear@0
|
1007 if( token != "," && token != ";")
|
nuclear@0
|
1008 ThrowException( "Separator character (';' or ',') expected.");
|
nuclear@0
|
1009 }
|
nuclear@0
|
1010
|
nuclear@0
|
1011 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1012 // tests and possibly consumes a separator char, but does nothing if there was no separator
|
nuclear@0
|
1013 void XFileParser::TestForSeparator()
|
nuclear@0
|
1014 {
|
nuclear@0
|
1015 if( mIsBinaryFormat)
|
nuclear@0
|
1016 return;
|
nuclear@0
|
1017
|
nuclear@0
|
1018 FindNextNoneWhiteSpace();
|
nuclear@0
|
1019 if( P >= End)
|
nuclear@0
|
1020 return;
|
nuclear@0
|
1021
|
nuclear@0
|
1022 // test and skip
|
nuclear@0
|
1023 if( *P == ';' || *P == ',')
|
nuclear@0
|
1024 P++;
|
nuclear@0
|
1025 }
|
nuclear@0
|
1026
|
nuclear@0
|
1027 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1028 void XFileParser::readHeadOfDataObject( std::string* poName)
|
nuclear@0
|
1029 {
|
nuclear@0
|
1030 std::string nameOrBrace = GetNextToken();
|
nuclear@0
|
1031 if( nameOrBrace != "{")
|
nuclear@0
|
1032 {
|
nuclear@0
|
1033 if( poName)
|
nuclear@0
|
1034 *poName = nameOrBrace;
|
nuclear@0
|
1035
|
nuclear@0
|
1036 if( GetNextToken() != "{")
|
nuclear@0
|
1037 ThrowException( "Opening brace expected.");
|
nuclear@0
|
1038 }
|
nuclear@0
|
1039 }
|
nuclear@0
|
1040
|
nuclear@0
|
1041 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1042 std::string XFileParser::GetNextToken()
|
nuclear@0
|
1043 {
|
nuclear@0
|
1044 std::string s;
|
nuclear@0
|
1045
|
nuclear@0
|
1046 // process binary-formatted file
|
nuclear@0
|
1047 if( mIsBinaryFormat)
|
nuclear@0
|
1048 {
|
nuclear@0
|
1049 // in binary mode it will only return NAME and STRING token
|
nuclear@0
|
1050 // and (correctly) skip over other tokens.
|
nuclear@0
|
1051
|
nuclear@0
|
1052 if( End - P < 2) return s;
|
nuclear@0
|
1053 unsigned int tok = ReadBinWord();
|
nuclear@0
|
1054 unsigned int len;
|
nuclear@0
|
1055
|
nuclear@0
|
1056 // standalone tokens
|
nuclear@0
|
1057 switch( tok)
|
nuclear@0
|
1058 {
|
nuclear@0
|
1059 case 1:
|
nuclear@0
|
1060 // name token
|
nuclear@0
|
1061 if( End - P < 4) return s;
|
nuclear@0
|
1062 len = ReadBinDWord();
|
nuclear@0
|
1063 if( End - P < int(len)) return s;
|
nuclear@0
|
1064 s = std::string(P, len);
|
nuclear@0
|
1065 P += len;
|
nuclear@0
|
1066 return s;
|
nuclear@0
|
1067 case 2:
|
nuclear@0
|
1068 // string token
|
nuclear@0
|
1069 if( End - P < 4) return s;
|
nuclear@0
|
1070 len = ReadBinDWord();
|
nuclear@0
|
1071 if( End - P < int(len)) return s;
|
nuclear@0
|
1072 s = std::string(P, len);
|
nuclear@0
|
1073 P += (len + 2);
|
nuclear@0
|
1074 return s;
|
nuclear@0
|
1075 case 3:
|
nuclear@0
|
1076 // integer token
|
nuclear@0
|
1077 P += 4;
|
nuclear@0
|
1078 return "<integer>";
|
nuclear@0
|
1079 case 5:
|
nuclear@0
|
1080 // GUID token
|
nuclear@0
|
1081 P += 16;
|
nuclear@0
|
1082 return "<guid>";
|
nuclear@0
|
1083 case 6:
|
nuclear@0
|
1084 if( End - P < 4) return s;
|
nuclear@0
|
1085 len = ReadBinDWord();
|
nuclear@0
|
1086 P += (len * 4);
|
nuclear@0
|
1087 return "<int_list>";
|
nuclear@0
|
1088 case 7:
|
nuclear@0
|
1089 if( End - P < 4) return s;
|
nuclear@0
|
1090 len = ReadBinDWord();
|
nuclear@0
|
1091 P += (len * mBinaryFloatSize);
|
nuclear@0
|
1092 return "<flt_list>";
|
nuclear@0
|
1093 case 0x0a:
|
nuclear@0
|
1094 return "{";
|
nuclear@0
|
1095 case 0x0b:
|
nuclear@0
|
1096 return "}";
|
nuclear@0
|
1097 case 0x0c:
|
nuclear@0
|
1098 return "(";
|
nuclear@0
|
1099 case 0x0d:
|
nuclear@0
|
1100 return ")";
|
nuclear@0
|
1101 case 0x0e:
|
nuclear@0
|
1102 return "[";
|
nuclear@0
|
1103 case 0x0f:
|
nuclear@0
|
1104 return "]";
|
nuclear@0
|
1105 case 0x10:
|
nuclear@0
|
1106 return "<";
|
nuclear@0
|
1107 case 0x11:
|
nuclear@0
|
1108 return ">";
|
nuclear@0
|
1109 case 0x12:
|
nuclear@0
|
1110 return ".";
|
nuclear@0
|
1111 case 0x13:
|
nuclear@0
|
1112 return ",";
|
nuclear@0
|
1113 case 0x14:
|
nuclear@0
|
1114 return ";";
|
nuclear@0
|
1115 case 0x1f:
|
nuclear@0
|
1116 return "template";
|
nuclear@0
|
1117 case 0x28:
|
nuclear@0
|
1118 return "WORD";
|
nuclear@0
|
1119 case 0x29:
|
nuclear@0
|
1120 return "DWORD";
|
nuclear@0
|
1121 case 0x2a:
|
nuclear@0
|
1122 return "FLOAT";
|
nuclear@0
|
1123 case 0x2b:
|
nuclear@0
|
1124 return "DOUBLE";
|
nuclear@0
|
1125 case 0x2c:
|
nuclear@0
|
1126 return "CHAR";
|
nuclear@0
|
1127 case 0x2d:
|
nuclear@0
|
1128 return "UCHAR";
|
nuclear@0
|
1129 case 0x2e:
|
nuclear@0
|
1130 return "SWORD";
|
nuclear@0
|
1131 case 0x2f:
|
nuclear@0
|
1132 return "SDWORD";
|
nuclear@0
|
1133 case 0x30:
|
nuclear@0
|
1134 return "void";
|
nuclear@0
|
1135 case 0x31:
|
nuclear@0
|
1136 return "string";
|
nuclear@0
|
1137 case 0x32:
|
nuclear@0
|
1138 return "unicode";
|
nuclear@0
|
1139 case 0x33:
|
nuclear@0
|
1140 return "cstring";
|
nuclear@0
|
1141 case 0x34:
|
nuclear@0
|
1142 return "array";
|
nuclear@0
|
1143 }
|
nuclear@0
|
1144 }
|
nuclear@0
|
1145 // process text-formatted file
|
nuclear@0
|
1146 else
|
nuclear@0
|
1147 {
|
nuclear@0
|
1148 FindNextNoneWhiteSpace();
|
nuclear@0
|
1149 if( P >= End)
|
nuclear@0
|
1150 return s;
|
nuclear@0
|
1151
|
nuclear@0
|
1152 while( (P < End) && !isspace( (unsigned char) *P))
|
nuclear@0
|
1153 {
|
nuclear@0
|
1154 // either keep token delimiters when already holding a token, or return if first valid char
|
nuclear@0
|
1155 if( *P == ';' || *P == '}' || *P == '{' || *P == ',')
|
nuclear@0
|
1156 {
|
nuclear@0
|
1157 if( !s.size())
|
nuclear@0
|
1158 s.append( P++, 1);
|
nuclear@0
|
1159 break; // stop for delimiter
|
nuclear@0
|
1160 }
|
nuclear@0
|
1161 s.append( P++, 1);
|
nuclear@0
|
1162 }
|
nuclear@0
|
1163 }
|
nuclear@0
|
1164 return s;
|
nuclear@0
|
1165 }
|
nuclear@0
|
1166
|
nuclear@0
|
1167 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1168 void XFileParser::FindNextNoneWhiteSpace()
|
nuclear@0
|
1169 {
|
nuclear@0
|
1170 if( mIsBinaryFormat)
|
nuclear@0
|
1171 return;
|
nuclear@0
|
1172
|
nuclear@0
|
1173 bool running = true;
|
nuclear@0
|
1174 while( running )
|
nuclear@0
|
1175 {
|
nuclear@0
|
1176 while( P < End && isspace( (unsigned char) *P))
|
nuclear@0
|
1177 {
|
nuclear@0
|
1178 if( *P == '\n')
|
nuclear@0
|
1179 mLineNumber++;
|
nuclear@0
|
1180 ++P;
|
nuclear@0
|
1181 }
|
nuclear@0
|
1182
|
nuclear@0
|
1183 if( P >= End)
|
nuclear@0
|
1184 return;
|
nuclear@0
|
1185
|
nuclear@0
|
1186 // check if this is a comment
|
nuclear@0
|
1187 if( (P[0] == '/' && P[1] == '/') || P[0] == '#')
|
nuclear@0
|
1188 ReadUntilEndOfLine();
|
nuclear@0
|
1189 else
|
nuclear@0
|
1190 break;
|
nuclear@0
|
1191 }
|
nuclear@0
|
1192 }
|
nuclear@0
|
1193
|
nuclear@0
|
1194 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1195 void XFileParser::GetNextTokenAsString( std::string& poString)
|
nuclear@0
|
1196 {
|
nuclear@0
|
1197 if( mIsBinaryFormat)
|
nuclear@0
|
1198 {
|
nuclear@0
|
1199 poString = GetNextToken();
|
nuclear@0
|
1200 return;
|
nuclear@0
|
1201 }
|
nuclear@0
|
1202
|
nuclear@0
|
1203 FindNextNoneWhiteSpace();
|
nuclear@0
|
1204 if( P >= End)
|
nuclear@0
|
1205 ThrowException( "Unexpected end of file while parsing string");
|
nuclear@0
|
1206
|
nuclear@0
|
1207 if( *P != '"')
|
nuclear@0
|
1208 ThrowException( "Expected quotation mark.");
|
nuclear@0
|
1209 ++P;
|
nuclear@0
|
1210
|
nuclear@0
|
1211 while( P < End && *P != '"')
|
nuclear@0
|
1212 poString.append( P++, 1);
|
nuclear@0
|
1213
|
nuclear@0
|
1214 if( P >= End-1)
|
nuclear@0
|
1215 ThrowException( "Unexpected end of file while parsing string");
|
nuclear@0
|
1216
|
nuclear@0
|
1217 if( P[1] != ';' || P[0] != '"')
|
nuclear@0
|
1218 ThrowException( "Expected quotation mark and semicolon at the end of a string.");
|
nuclear@0
|
1219 P+=2;
|
nuclear@0
|
1220 }
|
nuclear@0
|
1221
|
nuclear@0
|
1222 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1223 void XFileParser::ReadUntilEndOfLine()
|
nuclear@0
|
1224 {
|
nuclear@0
|
1225 if( mIsBinaryFormat)
|
nuclear@0
|
1226 return;
|
nuclear@0
|
1227
|
nuclear@0
|
1228 while( P < End)
|
nuclear@0
|
1229 {
|
nuclear@0
|
1230 if( *P == '\n' || *P == '\r')
|
nuclear@0
|
1231 {
|
nuclear@0
|
1232 ++P; mLineNumber++;
|
nuclear@0
|
1233 return;
|
nuclear@0
|
1234 }
|
nuclear@0
|
1235
|
nuclear@0
|
1236 ++P;
|
nuclear@0
|
1237 }
|
nuclear@0
|
1238 }
|
nuclear@0
|
1239
|
nuclear@0
|
1240 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1241 unsigned short XFileParser::ReadBinWord()
|
nuclear@0
|
1242 {
|
nuclear@0
|
1243 ai_assert(End - P >= 2);
|
nuclear@0
|
1244 const unsigned char* q = (const unsigned char*) P;
|
nuclear@0
|
1245 unsigned short tmp = q[0] | (q[1] << 8);
|
nuclear@0
|
1246 P += 2;
|
nuclear@0
|
1247 return tmp;
|
nuclear@0
|
1248 }
|
nuclear@0
|
1249
|
nuclear@0
|
1250 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1251 unsigned int XFileParser::ReadBinDWord()
|
nuclear@0
|
1252 {
|
nuclear@0
|
1253 ai_assert(End - P >= 4);
|
nuclear@0
|
1254 const unsigned char* q = (const unsigned char*) P;
|
nuclear@0
|
1255 unsigned int tmp = q[0] | (q[1] << 8) | (q[2] << 16) | (q[3] << 24);
|
nuclear@0
|
1256 P += 4;
|
nuclear@0
|
1257 return tmp;
|
nuclear@0
|
1258 }
|
nuclear@0
|
1259
|
nuclear@0
|
1260 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1261 unsigned int XFileParser::ReadInt()
|
nuclear@0
|
1262 {
|
nuclear@0
|
1263 if( mIsBinaryFormat)
|
nuclear@0
|
1264 {
|
nuclear@0
|
1265 if( mBinaryNumCount == 0 && End - P >= 2)
|
nuclear@0
|
1266 {
|
nuclear@0
|
1267 unsigned short tmp = ReadBinWord(); // 0x06 or 0x03
|
nuclear@0
|
1268 if( tmp == 0x06 && End - P >= 4) // array of ints follows
|
nuclear@0
|
1269 mBinaryNumCount = ReadBinDWord();
|
nuclear@0
|
1270 else // single int follows
|
nuclear@0
|
1271 mBinaryNumCount = 1;
|
nuclear@0
|
1272 }
|
nuclear@0
|
1273
|
nuclear@0
|
1274 --mBinaryNumCount;
|
nuclear@0
|
1275 if ( End - P >= 4) {
|
nuclear@0
|
1276 return ReadBinDWord();
|
nuclear@0
|
1277 } else {
|
nuclear@0
|
1278 P = End;
|
nuclear@0
|
1279 return 0;
|
nuclear@0
|
1280 }
|
nuclear@0
|
1281 } else
|
nuclear@0
|
1282 {
|
nuclear@0
|
1283 FindNextNoneWhiteSpace();
|
nuclear@0
|
1284
|
nuclear@0
|
1285 // TODO: consider using strtol10 instead???
|
nuclear@0
|
1286
|
nuclear@0
|
1287 // check preceeding minus sign
|
nuclear@0
|
1288 bool isNegative = false;
|
nuclear@0
|
1289 if( *P == '-')
|
nuclear@0
|
1290 {
|
nuclear@0
|
1291 isNegative = true;
|
nuclear@0
|
1292 P++;
|
nuclear@0
|
1293 }
|
nuclear@0
|
1294
|
nuclear@0
|
1295 // at least one digit expected
|
nuclear@0
|
1296 if( !isdigit( *P))
|
nuclear@0
|
1297 ThrowException( "Number expected.");
|
nuclear@0
|
1298
|
nuclear@0
|
1299 // read digits
|
nuclear@0
|
1300 unsigned int number = 0;
|
nuclear@0
|
1301 while( P < End)
|
nuclear@0
|
1302 {
|
nuclear@0
|
1303 if( !isdigit( *P))
|
nuclear@0
|
1304 break;
|
nuclear@0
|
1305 number = number * 10 + (*P - 48);
|
nuclear@0
|
1306 P++;
|
nuclear@0
|
1307 }
|
nuclear@0
|
1308
|
nuclear@0
|
1309 CheckForSeparator();
|
nuclear@0
|
1310 return isNegative ? ((unsigned int) -int( number)) : number;
|
nuclear@0
|
1311 }
|
nuclear@0
|
1312 }
|
nuclear@0
|
1313
|
nuclear@0
|
1314 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1315 float XFileParser::ReadFloat()
|
nuclear@0
|
1316 {
|
nuclear@0
|
1317 if( mIsBinaryFormat)
|
nuclear@0
|
1318 {
|
nuclear@0
|
1319 if( mBinaryNumCount == 0 && End - P >= 2)
|
nuclear@0
|
1320 {
|
nuclear@0
|
1321 unsigned short tmp = ReadBinWord(); // 0x07 or 0x42
|
nuclear@0
|
1322 if( tmp == 0x07 && End - P >= 4) // array of floats following
|
nuclear@0
|
1323 mBinaryNumCount = ReadBinDWord();
|
nuclear@0
|
1324 else // single float following
|
nuclear@0
|
1325 mBinaryNumCount = 1;
|
nuclear@0
|
1326 }
|
nuclear@0
|
1327
|
nuclear@0
|
1328 --mBinaryNumCount;
|
nuclear@0
|
1329 if( mBinaryFloatSize == 8)
|
nuclear@0
|
1330 {
|
nuclear@0
|
1331 if( End - P >= 8) {
|
nuclear@0
|
1332 float result = (float) (*(double*) P);
|
nuclear@0
|
1333 P += 8;
|
nuclear@0
|
1334 return result;
|
nuclear@0
|
1335 } else {
|
nuclear@0
|
1336 P = End;
|
nuclear@0
|
1337 return 0;
|
nuclear@0
|
1338 }
|
nuclear@0
|
1339 } else
|
nuclear@0
|
1340 {
|
nuclear@0
|
1341 if( End - P >= 4) {
|
nuclear@0
|
1342 float result = *(float*) P;
|
nuclear@0
|
1343 P += 4;
|
nuclear@0
|
1344 return result;
|
nuclear@0
|
1345 } else {
|
nuclear@0
|
1346 P = End;
|
nuclear@0
|
1347 return 0;
|
nuclear@0
|
1348 }
|
nuclear@0
|
1349 }
|
nuclear@0
|
1350 }
|
nuclear@0
|
1351
|
nuclear@0
|
1352 // text version
|
nuclear@0
|
1353 FindNextNoneWhiteSpace();
|
nuclear@0
|
1354 // check for various special strings to allow reading files from faulty exporters
|
nuclear@0
|
1355 // I mean you, Blender!
|
nuclear@0
|
1356 // Reading is safe because of the terminating zero
|
nuclear@0
|
1357 if( strncmp( P, "-1.#IND00", 9) == 0 || strncmp( P, "1.#IND00", 8) == 0)
|
nuclear@0
|
1358 {
|
nuclear@0
|
1359 P += 9;
|
nuclear@0
|
1360 CheckForSeparator();
|
nuclear@0
|
1361 return 0.0f;
|
nuclear@0
|
1362 } else
|
nuclear@0
|
1363 if( strncmp( P, "1.#QNAN0", 8) == 0)
|
nuclear@0
|
1364 {
|
nuclear@0
|
1365 P += 8;
|
nuclear@0
|
1366 CheckForSeparator();
|
nuclear@0
|
1367 return 0.0f;
|
nuclear@0
|
1368 }
|
nuclear@0
|
1369
|
nuclear@0
|
1370 float result = 0.0f;
|
nuclear@0
|
1371 P = fast_atoreal_move<float>( P, result);
|
nuclear@0
|
1372
|
nuclear@0
|
1373 CheckForSeparator();
|
nuclear@0
|
1374
|
nuclear@0
|
1375 return result;
|
nuclear@0
|
1376 }
|
nuclear@0
|
1377
|
nuclear@0
|
1378 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1379 aiVector2D XFileParser::ReadVector2()
|
nuclear@0
|
1380 {
|
nuclear@0
|
1381 aiVector2D vector;
|
nuclear@0
|
1382 vector.x = ReadFloat();
|
nuclear@0
|
1383 vector.y = ReadFloat();
|
nuclear@0
|
1384 TestForSeparator();
|
nuclear@0
|
1385
|
nuclear@0
|
1386 return vector;
|
nuclear@0
|
1387 }
|
nuclear@0
|
1388
|
nuclear@0
|
1389 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1390 aiVector3D XFileParser::ReadVector3()
|
nuclear@0
|
1391 {
|
nuclear@0
|
1392 aiVector3D vector;
|
nuclear@0
|
1393 vector.x = ReadFloat();
|
nuclear@0
|
1394 vector.y = ReadFloat();
|
nuclear@0
|
1395 vector.z = ReadFloat();
|
nuclear@0
|
1396 TestForSeparator();
|
nuclear@0
|
1397
|
nuclear@0
|
1398 return vector;
|
nuclear@0
|
1399 }
|
nuclear@0
|
1400
|
nuclear@0
|
1401 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1402 aiColor4D XFileParser::ReadRGBA()
|
nuclear@0
|
1403 {
|
nuclear@0
|
1404 aiColor4D color;
|
nuclear@0
|
1405 color.r = ReadFloat();
|
nuclear@0
|
1406 color.g = ReadFloat();
|
nuclear@0
|
1407 color.b = ReadFloat();
|
nuclear@0
|
1408 color.a = ReadFloat();
|
nuclear@0
|
1409 TestForSeparator();
|
nuclear@0
|
1410
|
nuclear@0
|
1411 return color;
|
nuclear@0
|
1412 }
|
nuclear@0
|
1413
|
nuclear@0
|
1414 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1415 aiColor3D XFileParser::ReadRGB()
|
nuclear@0
|
1416 {
|
nuclear@0
|
1417 aiColor3D color;
|
nuclear@0
|
1418 color.r = ReadFloat();
|
nuclear@0
|
1419 color.g = ReadFloat();
|
nuclear@0
|
1420 color.b = ReadFloat();
|
nuclear@0
|
1421 TestForSeparator();
|
nuclear@0
|
1422
|
nuclear@0
|
1423 return color;
|
nuclear@0
|
1424 }
|
nuclear@0
|
1425
|
nuclear@0
|
1426 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1427 // Throws an exception with a line number and the given text.
|
nuclear@0
|
1428 void XFileParser::ThrowException( const std::string& pText)
|
nuclear@0
|
1429 {
|
nuclear@0
|
1430 if( mIsBinaryFormat)
|
nuclear@0
|
1431 throw DeadlyImportError( pText);
|
nuclear@0
|
1432 else
|
nuclear@0
|
1433 throw DeadlyImportError( boost::str( boost::format( "Line %d: %s") % mLineNumber % pText));
|
nuclear@0
|
1434 }
|
nuclear@0
|
1435
|
nuclear@0
|
1436
|
nuclear@0
|
1437 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1438 // Filters the imported hierarchy for some degenerated cases that some exporters produce.
|
nuclear@0
|
1439 void XFileParser::FilterHierarchy( XFile::Node* pNode)
|
nuclear@0
|
1440 {
|
nuclear@0
|
1441 // if the node has just a single unnamed child containing a mesh, remove
|
nuclear@0
|
1442 // the anonymous node inbetween. The 3DSMax kwXport plugin seems to produce this
|
nuclear@0
|
1443 // mess in some cases
|
nuclear@0
|
1444 if( pNode->mChildren.size() == 1 && pNode->mMeshes.empty() )
|
nuclear@0
|
1445 {
|
nuclear@0
|
1446 XFile::Node* child = pNode->mChildren.front();
|
nuclear@0
|
1447 if( child->mName.length() == 0 && child->mMeshes.size() > 0)
|
nuclear@0
|
1448 {
|
nuclear@0
|
1449 // transfer its meshes to us
|
nuclear@0
|
1450 for( unsigned int a = 0; a < child->mMeshes.size(); a++)
|
nuclear@0
|
1451 pNode->mMeshes.push_back( child->mMeshes[a]);
|
nuclear@0
|
1452 child->mMeshes.clear();
|
nuclear@0
|
1453
|
nuclear@0
|
1454 // transfer the transform as well
|
nuclear@0
|
1455 pNode->mTrafoMatrix = pNode->mTrafoMatrix * child->mTrafoMatrix;
|
nuclear@0
|
1456
|
nuclear@0
|
1457 // then kill it
|
nuclear@0
|
1458 delete child;
|
nuclear@0
|
1459 pNode->mChildren.clear();
|
nuclear@0
|
1460 }
|
nuclear@0
|
1461 }
|
nuclear@0
|
1462
|
nuclear@0
|
1463 // recurse
|
nuclear@0
|
1464 for( unsigned int a = 0; a < pNode->mChildren.size(); a++)
|
nuclear@0
|
1465 FilterHierarchy( pNode->mChildren[a]);
|
nuclear@0
|
1466 }
|
nuclear@0
|
1467
|
nuclear@0
|
1468 #endif // !! ASSIMP_BUILD_NO_X_IMPORTER
|