vrshoot

view libs/assimp/MD5Parser.cpp @ 1:e7ca128b8713

looks nice :)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Feb 2014 00:35:22 +0200
parents
children
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
42 /** @file MD5Parser.cpp
43 * @brief Implementation of the MD5 parser class
44 */
45 #include "AssimpPCH.h"
47 // internal headers
48 #include "MD5Loader.h"
49 #include "MaterialSystem.h"
50 #include "fast_atof.h"
51 #include "ParsingUtils.h"
52 #include "StringComparison.h"
54 using namespace Assimp;
55 using namespace Assimp::MD5;
57 // ------------------------------------------------------------------------------------------------
58 // Parse the segment structure fo a MD5 file
59 MD5Parser::MD5Parser(char* _buffer, unsigned int _fileSize )
60 {
61 ai_assert(NULL != _buffer && 0 != _fileSize);
63 buffer = _buffer;
64 fileSize = _fileSize;
65 lineNumber = 0;
67 DefaultLogger::get()->debug("MD5Parser begin");
69 // parse the file header
70 ParseHeader();
72 // and read all sections until we're finished
73 bool running = true;
74 while (running) {
75 mSections.push_back(Section());
76 Section& sec = mSections.back();
77 if(!ParseSection(sec)) {
78 break;
79 }
80 }
82 if ( !DefaultLogger::isNullLogger()) {
83 char szBuffer[128]; // should be sufficiently large
84 ::sprintf(szBuffer,"MD5Parser end. Parsed %i sections",(int)mSections.size());
85 DefaultLogger::get()->debug(szBuffer);
86 }
87 }
89 // ------------------------------------------------------------------------------------------------
90 // Report error to the log stream
91 /*static*/ void MD5Parser::ReportError (const char* error, unsigned int line)
92 {
93 char szBuffer[1024];
94 ::sprintf(szBuffer,"[MD5] Line %i: %s",line,error);
95 throw DeadlyImportError(szBuffer);
96 }
98 // ------------------------------------------------------------------------------------------------
99 // Report warning to the log stream
100 /*static*/ void MD5Parser::ReportWarning (const char* warn, unsigned int line)
101 {
102 char szBuffer[1024];
103 ::sprintf(szBuffer,"[MD5] Line %i: %s",line,warn);
104 DefaultLogger::get()->warn(szBuffer);
105 }
107 // ------------------------------------------------------------------------------------------------
108 // Parse and validate the MD5 header
109 void MD5Parser::ParseHeader()
110 {
111 // parse and validate the file version
112 SkipSpaces();
113 if (!TokenMatch(buffer,"MD5Version",10)) {
114 ReportError("Invalid MD5 file: MD5Version tag has not been found");
115 }
116 SkipSpaces();
117 unsigned int iVer = ::strtoul10(buffer,(const char**)&buffer);
118 if (10 != iVer) {
119 ReportError("MD5 version tag is unknown (10 is expected)");
120 }
121 SkipLine();
123 // print the command line options to the console
124 // FIX: can break the log length limit, so we need to be careful
125 char* sz = buffer;
126 while (!IsLineEnd( *buffer++));
127 DefaultLogger::get()->info(std::string(sz,std::min((uintptr_t)MAX_LOG_MESSAGE_LENGTH, (uintptr_t)(buffer-sz))));
128 SkipSpacesAndLineEnd();
129 }
131 // ------------------------------------------------------------------------------------------------
132 // Recursive MD5 parsing function
133 bool MD5Parser::ParseSection(Section& out)
134 {
135 // store the current line number for use in error messages
136 out.iLineNumber = lineNumber;
138 // first parse the name of the section
139 char* sz = buffer;
140 while (!IsSpaceOrNewLine( *buffer))buffer++;
141 out.mName = std::string(sz,(uintptr_t)(buffer-sz));
142 SkipSpaces();
144 bool running = true;
145 while (running) {
146 if ('{' == *buffer) {
147 // it is a normal section so read all lines
148 buffer++;
149 bool run = true;
150 while (run)
151 {
152 if (!SkipSpacesAndLineEnd()) {
153 return false; // seems this was the last section
154 }
155 if ('}' == *buffer) {
156 buffer++;
157 break;
158 }
160 out.mElements.push_back(Element());
161 Element& elem = out.mElements.back();
163 elem.iLineNumber = lineNumber;
164 elem.szStart = buffer;
166 // terminate the line with zero
167 while (!IsLineEnd( *buffer))buffer++;
168 if (*buffer) {
169 ++lineNumber;
170 *buffer++ = '\0';
171 }
172 }
173 break;
174 }
175 else if (!IsSpaceOrNewLine(*buffer)) {
176 // it is an element at global scope. Parse its value and go on
177 sz = buffer;
178 while (!IsSpaceOrNewLine( *buffer++));
179 out.mGlobalValue = std::string(sz,(uintptr_t)(buffer-sz));
180 continue;
181 }
182 break;
183 }
184 return SkipSpacesAndLineEnd();
185 }
187 // ------------------------------------------------------------------------------------------------
188 // Some dirty macros just because they're so funny and easy to debug
190 // skip all spaces ... handle EOL correctly
191 #define AI_MD5_SKIP_SPACES() if(!SkipSpaces(&sz)) \
192 MD5Parser::ReportWarning("Unexpected end of line",(*eit).iLineNumber);
194 // read a triple float in brackets: (1.0 1.0 1.0)
195 #define AI_MD5_READ_TRIPLE(vec) \
196 AI_MD5_SKIP_SPACES(); \
197 if ('(' != *sz++) \
198 MD5Parser::ReportWarning("Unexpected token: ( was expected",(*eit).iLineNumber); \
199 AI_MD5_SKIP_SPACES(); \
200 sz = fast_atoreal_move<float>(sz,(float&)vec.x); \
201 AI_MD5_SKIP_SPACES(); \
202 sz = fast_atoreal_move<float>(sz,(float&)vec.y); \
203 AI_MD5_SKIP_SPACES(); \
204 sz = fast_atoreal_move<float>(sz,(float&)vec.z); \
205 AI_MD5_SKIP_SPACES(); \
206 if (')' != *sz++) \
207 MD5Parser::ReportWarning("Unexpected token: ) was expected",(*eit).iLineNumber);
209 // parse a string, enclosed in quotation marks or not
210 #define AI_MD5_PARSE_STRING(out) \
211 bool bQuota = (*sz == '\"'); \
212 const char* szStart = sz; \
213 while (!IsSpaceOrNewLine(*sz))++sz; \
214 const char* szEnd = sz; \
215 if (bQuota) { \
216 szStart++; \
217 if ('\"' != *(szEnd-=1)) { \
218 MD5Parser::ReportWarning("Expected closing quotation marks in string", \
219 (*eit).iLineNumber); \
220 continue; \
221 } \
222 } \
223 out.length = (size_t)(szEnd - szStart); \
224 ::memcpy(out.data,szStart,out.length); \
225 out.data[out.length] = '\0';
227 // ------------------------------------------------------------------------------------------------
228 // .MD5MESH parsing function
229 MD5MeshParser::MD5MeshParser(SectionList& mSections)
230 {
231 DefaultLogger::get()->debug("MD5MeshParser begin");
233 // now parse all sections
234 for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end();iter != iterEnd;++iter){
235 if ( (*iter).mName == "numMeshes") {
236 mMeshes.reserve(::strtoul10((*iter).mGlobalValue.c_str()));
237 }
238 else if ( (*iter).mName == "numJoints") {
239 mJoints.reserve(::strtoul10((*iter).mGlobalValue.c_str()));
240 }
241 else if ((*iter).mName == "joints") {
242 // "origin" -1 ( -0.000000 0.016430 -0.006044 ) ( 0.707107 0.000000 0.707107 )
243 for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();eit != eitEnd; ++eit){
244 mJoints.push_back(BoneDesc());
245 BoneDesc& desc = mJoints.back();
247 const char* sz = (*eit).szStart;
248 AI_MD5_PARSE_STRING(desc.mName);
249 AI_MD5_SKIP_SPACES();
251 // negative values, at least -1, is allowed here
252 desc.mParentIndex = (int)strtol10(sz,&sz);
254 AI_MD5_READ_TRIPLE(desc.mPositionXYZ);
255 AI_MD5_READ_TRIPLE(desc.mRotationQuat); // normalized quaternion, so w is not there
256 }
257 }
258 else if ((*iter).mName == "mesh") {
259 mMeshes.push_back(MeshDesc());
260 MeshDesc& desc = mMeshes.back();
262 for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();eit != eitEnd; ++eit){
263 const char* sz = (*eit).szStart;
265 // shader attribute
266 if (TokenMatch(sz,"shader",6)) {
267 AI_MD5_SKIP_SPACES();
268 AI_MD5_PARSE_STRING(desc.mShader);
269 }
270 // numverts attribute
271 else if (TokenMatch(sz,"numverts",8)) {
272 AI_MD5_SKIP_SPACES();
273 desc.mVertices.resize(strtoul10(sz));
274 }
275 // numtris attribute
276 else if (TokenMatch(sz,"numtris",7)) {
277 AI_MD5_SKIP_SPACES();
278 desc.mFaces.resize(strtoul10(sz));
279 }
280 // numweights attribute
281 else if (TokenMatch(sz,"numweights",10)) {
282 AI_MD5_SKIP_SPACES();
283 desc.mWeights.resize(strtoul10(sz));
284 }
285 // vert attribute
286 // "vert 0 ( 0.394531 0.513672 ) 0 1"
287 else if (TokenMatch(sz,"vert",4)) {
288 AI_MD5_SKIP_SPACES();
289 const unsigned int idx = ::strtoul10(sz,&sz);
290 AI_MD5_SKIP_SPACES();
291 if (idx >= desc.mVertices.size())
292 desc.mVertices.resize(idx+1);
294 VertexDesc& vert = desc.mVertices[idx];
295 if ('(' != *sz++)
296 MD5Parser::ReportWarning("Unexpected token: ( was expected",(*eit).iLineNumber);
297 AI_MD5_SKIP_SPACES();
298 sz = fast_atoreal_move<float>(sz,(float&)vert.mUV.x);
299 AI_MD5_SKIP_SPACES();
300 sz = fast_atoreal_move<float>(sz,(float&)vert.mUV.y);
301 AI_MD5_SKIP_SPACES();
302 if (')' != *sz++)
303 MD5Parser::ReportWarning("Unexpected token: ) was expected",(*eit).iLineNumber);
304 AI_MD5_SKIP_SPACES();
305 vert.mFirstWeight = ::strtoul10(sz,&sz);
306 AI_MD5_SKIP_SPACES();
307 vert.mNumWeights = ::strtoul10(sz,&sz);
308 }
309 // tri attribute
310 // "tri 0 15 13 12"
311 else if (TokenMatch(sz,"tri",3)) {
312 AI_MD5_SKIP_SPACES();
313 const unsigned int idx = strtoul10(sz,&sz);
314 if (idx >= desc.mFaces.size())
315 desc.mFaces.resize(idx+1);
317 aiFace& face = desc.mFaces[idx];
318 face.mIndices = new unsigned int[face.mNumIndices = 3];
319 for (unsigned int i = 0; i < 3;++i) {
320 AI_MD5_SKIP_SPACES();
321 face.mIndices[i] = strtoul10(sz,&sz);
322 }
323 }
324 // weight attribute
325 // "weight 362 5 0.500000 ( -3.553583 11.893474 9.719339 )"
326 else if (TokenMatch(sz,"weight",6)) {
327 AI_MD5_SKIP_SPACES();
328 const unsigned int idx = strtoul10(sz,&sz);
329 AI_MD5_SKIP_SPACES();
330 if (idx >= desc.mWeights.size())
331 desc.mWeights.resize(idx+1);
333 WeightDesc& weight = desc.mWeights[idx];
334 weight.mBone = strtoul10(sz,&sz);
335 AI_MD5_SKIP_SPACES();
336 sz = fast_atoreal_move<float>(sz,weight.mWeight);
337 AI_MD5_READ_TRIPLE(weight.vOffsetPosition);
338 }
339 }
340 }
341 }
342 DefaultLogger::get()->debug("MD5MeshParser end");
343 }
345 // ------------------------------------------------------------------------------------------------
346 // .MD5ANIM parsing function
347 MD5AnimParser::MD5AnimParser(SectionList& mSections)
348 {
349 DefaultLogger::get()->debug("MD5AnimParser begin");
351 fFrameRate = 24.0f;
352 mNumAnimatedComponents = UINT_MAX;
353 for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end();iter != iterEnd;++iter) {
354 if ((*iter).mName == "hierarchy") {
355 // "sheath" 0 63 6
356 for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end();eit != eitEnd; ++eit) {
357 mAnimatedBones.push_back ( AnimBoneDesc () );
358 AnimBoneDesc& desc = mAnimatedBones.back();
360 const char* sz = (*eit).szStart;
361 AI_MD5_PARSE_STRING(desc.mName);
362 AI_MD5_SKIP_SPACES();
364 // parent index - negative values are allowed (at least -1)
365 desc.mParentIndex = ::strtol10(sz,&sz);
367 // flags (highest is 2^6-1)
368 AI_MD5_SKIP_SPACES();
369 if(63 < (desc.iFlags = ::strtoul10(sz,&sz))){
370 MD5Parser::ReportWarning("Invalid flag combination in hierarchy section",(*eit).iLineNumber);
371 }
372 AI_MD5_SKIP_SPACES();
374 // index of the first animation keyframe component for this joint
375 desc.iFirstKeyIndex = ::strtoul10(sz,&sz);
376 }
377 }
378 else if((*iter).mName == "baseframe") {
379 // ( -0.000000 0.016430 -0.006044 ) ( 0.707107 0.000242 0.707107 )
380 for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end(); eit != eitEnd; ++eit) {
381 const char* sz = (*eit).szStart;
383 mBaseFrames.push_back ( BaseFrameDesc () );
384 BaseFrameDesc& desc = mBaseFrames.back();
386 AI_MD5_READ_TRIPLE(desc.vPositionXYZ);
387 AI_MD5_READ_TRIPLE(desc.vRotationQuat);
388 }
389 }
390 else if((*iter).mName == "frame") {
391 if (!(*iter).mGlobalValue.length()) {
392 MD5Parser::ReportWarning("A frame section must have a frame index",(*iter).iLineNumber);
393 continue;
394 }
396 mFrames.push_back ( FrameDesc () );
397 FrameDesc& desc = mFrames.back();
398 desc.iIndex = strtoul10((*iter).mGlobalValue.c_str());
400 // we do already know how much storage we will presumably need
401 if (UINT_MAX != mNumAnimatedComponents) {
402 desc.mValues.reserve(mNumAnimatedComponents);
403 }
405 // now read all elements (continous list of floats)
406 for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end(); eit != eitEnd; ++eit){
407 const char* sz = (*eit).szStart;
408 while (SkipSpacesAndLineEnd(&sz)) {
409 float f;sz = fast_atoreal_move<float>(sz,f);
410 desc.mValues.push_back(f);
411 }
412 }
413 }
414 else if((*iter).mName == "numFrames") {
415 mFrames.reserve(strtoul10((*iter).mGlobalValue.c_str()));
416 }
417 else if((*iter).mName == "numJoints") {
418 const unsigned int num = strtoul10((*iter).mGlobalValue.c_str());
419 mAnimatedBones.reserve(num);
421 // try to guess the number of animated components if that element is not given
422 if (UINT_MAX == mNumAnimatedComponents) {
423 mNumAnimatedComponents = num * 6;
424 }
425 }
426 else if((*iter).mName == "numAnimatedComponents") {
427 mAnimatedBones.reserve( strtoul10((*iter).mGlobalValue.c_str()));
428 }
429 else if((*iter).mName == "frameRate") {
430 fast_atoreal_move<float>((*iter).mGlobalValue.c_str(),fFrameRate);
431 }
432 }
433 DefaultLogger::get()->debug("MD5AnimParser end");
434 }
436 // ------------------------------------------------------------------------------------------------
437 // .MD5CAMERA parsing function
438 MD5CameraParser::MD5CameraParser(SectionList& mSections)
439 {
440 DefaultLogger::get()->debug("MD5CameraParser begin");
441 fFrameRate = 24.0f;
443 for (SectionList::const_iterator iter = mSections.begin(), iterEnd = mSections.end();iter != iterEnd;++iter) {
444 if ((*iter).mName == "numFrames") {
445 frames.reserve(strtoul10((*iter).mGlobalValue.c_str()));
446 }
447 else if ((*iter).mName == "frameRate") {
448 fFrameRate = fast_atof ((*iter).mGlobalValue.c_str());
449 }
450 else if ((*iter).mName == "numCuts") {
451 cuts.reserve(strtoul10((*iter).mGlobalValue.c_str()));
452 }
453 else if ((*iter).mName == "cuts") {
454 for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end(); eit != eitEnd; ++eit){
455 cuts.push_back(strtoul10((*eit).szStart)+1);
456 }
457 }
458 else if ((*iter).mName == "camera") {
459 for (ElementList::const_iterator eit = (*iter).mElements.begin(), eitEnd = (*iter).mElements.end(); eit != eitEnd; ++eit){
460 const char* sz = (*eit).szStart;
462 frames.push_back(CameraAnimFrameDesc());
463 CameraAnimFrameDesc& cur = frames.back();
464 AI_MD5_READ_TRIPLE(cur.vPositionXYZ);
465 AI_MD5_READ_TRIPLE(cur.vRotationQuat);
466 AI_MD5_SKIP_SPACES();
467 cur.fFOV = fast_atof(sz);
468 }
469 }
470 }
471 DefaultLogger::get()->debug("MD5CameraParser end");
472 }