1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2012, assimp team
7 
8 All rights reserved.
9 
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:
13 
14 * Redistributions of source code must retain the above
15   copyright notice, this list of conditions and the
16   following disclaimer.
17 
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.
22 
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.
27 
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 */
41 
42 /** @file  ASEParser.cpp
43  *  @brief Implementation of the ASE parser class
44  */
45 
46 #include "AssimpPCH.h"
47 
48 // internal headers
49 #include "TextureTransform.h"
50 #include "ASELoader.h"
51 #include "MaterialSystem.h"
52 #include "fast_atof.h"
53 
54 using namespace Assimp;
55 using namespace Assimp::ASE;
56 
57 
58 // ------------------------------------------------------------------------------------------------
59 // Begin an ASE parsing function
60 
61 #define AI_ASE_PARSER_INIT() \
62 	int iDepth = 0;
63 
64 // ------------------------------------------------------------------------------------------------
65 // Handle a "top-level" section in the file. EOF is no error in this case.
66 
67 #define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \
68 	else if ('{' == *filePtr)iDepth++; \
69 	else if ('}' == *filePtr) \
70 	{ \
71 		if (0 == --iDepth) \
72 		{ \
73 			++filePtr; \
74 			SkipToNextToken(); \
75 			return; \
76 		} \
77 	} \
78 	else if ('\0' == *filePtr) \
79 	{ \
80 		return; \
81 	} \
82 	if(IsLineEnd(*filePtr) && !bLastWasEndLine) \
83 	{ \
84 		++iLineNumber; \
85 		bLastWasEndLine = true; \
86 	} else bLastWasEndLine = false; \
87 	++filePtr;
88 
89 // ------------------------------------------------------------------------------------------------
90 // Handle a nested section in the file. EOF is an error in this case
91 // @param level "Depth" of the section
92 // @param msg Full name of the section (including the asterisk)
93 
94 #define AI_ASE_HANDLE_SECTION(level, msg) \
95 	if ('{' == *filePtr)iDepth++; \
96 	else if ('}' == *filePtr) \
97 	{ \
98 		if (0 == --iDepth) \
99 		{ \
100 			++filePtr; \
101 			SkipToNextToken(); \
102 			return; \
103 		} \
104 	} \
105 	else if ('\0' == *filePtr) \
106 	{ \
107 		LogError("Encountered unexpected EOL while parsing a " msg \
108 		" chunk (Level " level ")"); \
109 	} \
110 	if(IsLineEnd(*filePtr) && !bLastWasEndLine) \
111 		{ \
112 		++iLineNumber; \
113 		bLastWasEndLine = true; \
114 	} else bLastWasEndLine = false; \
115 	++filePtr;
116 
117 // ------------------------------------------------------------------------------------------------
Parser(const char * szFile,unsigned int fileFormatDefault)118 Parser::Parser (const char* szFile, unsigned int fileFormatDefault)
119 {
120 	ai_assert(NULL != szFile);
121 	filePtr = szFile;
122 	iFileFormat = fileFormatDefault;
123 
124 	// make sure that the color values are invalid
125 	m_clrBackground.r = get_qnan();
126 	m_clrAmbient.r    = get_qnan();
127 
128 	// setup some default values
129 	iLineNumber = 0;
130 	iFirstFrame = 0;
131 	iLastFrame = 0;
132 	iFrameSpeed = 30;        // use 30 as default value for this property
133 	iTicksPerFrame = 1;      // use 1 as default value for this property
134 	bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping
135 }
136 
137 // ------------------------------------------------------------------------------------------------
LogWarning(const char * szWarn)138 void Parser::LogWarning(const char* szWarn)
139 {
140 	ai_assert(NULL != szWarn);
141 
142 	char szTemp[1024];
143 #if _MSC_VER >= 1400
144 	sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn);
145 #else
146 	snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn);
147 #endif
148 
149 	// output the warning to the logger ...
150 	DefaultLogger::get()->warn(szTemp);
151 }
152 
153 // ------------------------------------------------------------------------------------------------
LogInfo(const char * szWarn)154 void Parser::LogInfo(const char* szWarn)
155 {
156 	ai_assert(NULL != szWarn);
157 
158 	char szTemp[1024];
159 #if _MSC_VER >= 1400
160 	sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn);
161 #else
162 	snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn);
163 #endif
164 
165 	// output the information to the logger ...
166 	DefaultLogger::get()->info(szTemp);
167 }
168 
169 // ------------------------------------------------------------------------------------------------
LogError(const char * szWarn)170 void Parser::LogError(const char* szWarn)
171 {
172 	ai_assert(NULL != szWarn);
173 
174 	char szTemp[1024];
175 #if _MSC_VER >= 1400
176 	sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn);
177 #else
178 	snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn);
179 #endif
180 
181 	// throw an exception
182 	throw DeadlyImportError(szTemp);
183 }
184 
185 // ------------------------------------------------------------------------------------------------
SkipToNextToken()186 bool Parser::SkipToNextToken()
187 {
188 	while (true)
189 	{
190 		char me = *filePtr;
191 
192 		// increase the line number counter if necessary
193 		if (IsLineEnd(me) && !bLastWasEndLine)
194 		{
195 			++iLineNumber;
196 			bLastWasEndLine = true;
197 		}
198 		else bLastWasEndLine = false;
199 		if ('*' == me || '}' == me || '{' == me)return true;
200 		if ('\0' == me)return false;
201 
202 		++filePtr;
203 	}
204 }
205 
206 // ------------------------------------------------------------------------------------------------
SkipSection()207 bool Parser::SkipSection()
208 {
209 	// must handle subsections ...
210 	int iCnt = 0;
211 	while (true)
212 	{
213 		if ('}' == *filePtr)
214 		{
215 			--iCnt;
216 			if (0 == iCnt)
217 			{
218 				// go to the next valid token ...
219 				++filePtr;
220 				SkipToNextToken();
221 				return true;
222 			}
223 		}
224 		else if ('{' == *filePtr)
225 		{
226 			++iCnt;
227 		}
228 		else if ('\0' == *filePtr)
229 		{
230 			LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]");
231 			return false;
232 		}
233 		else if(IsLineEnd(*filePtr))++iLineNumber;
234 		++filePtr;
235 	}
236 }
237 
238 // ------------------------------------------------------------------------------------------------
Parse()239 void Parser::Parse()
240 {
241 	AI_ASE_PARSER_INIT();
242 	while (true)
243 	{
244 		if ('*' == *filePtr)
245 		{
246 			++filePtr;
247 
248 			// Version should be 200. Validate this ...
249 			if (TokenMatch(filePtr,"3DSMAX_ASCIIEXPORT",18))
250 			{
251 				unsigned int fmt;
252 				ParseLV4MeshLong(fmt);
253 
254 				if (fmt > 200)
255 				{
256 					LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \
257 							   be <= 200");
258 				}
259 				// *************************************************************
260 				// - fmt will be 0 if we're unable to read the version number
261 				// there are some faulty files without a version number ...
262 				// in this case we'll guess the exact file format by looking
263 				// at the file extension (ASE, ASK, ASC)
264 				// *************************************************************
265 
266 				if (fmt)iFileFormat = fmt;
267 				continue;
268 			}
269 			// main scene information
270 			if (TokenMatch(filePtr,"SCENE",5))
271 			{
272 				ParseLV1SceneBlock();
273 				continue;
274 			}
275 			// "group" - no implementation yet, in facte
276 			// we're just ignoring them for the moment
277 			if (TokenMatch(filePtr,"GROUP",5))
278 			{
279 				Parse();
280 				continue;
281 			}
282 			// material list
283 			if (TokenMatch(filePtr,"MATERIAL_LIST",13))
284 			{
285 				ParseLV1MaterialListBlock();
286 				continue;
287 			}
288 			// geometric object (mesh)
289 			if (TokenMatch(filePtr,"GEOMOBJECT",10))
290 
291 			{
292 				m_vMeshes.push_back(Mesh());
293 				ParseLV1ObjectBlock(m_vMeshes.back());
294 				continue;
295 			}
296 			// helper object = dummy in the hierarchy
297 			if (TokenMatch(filePtr,"HELPEROBJECT",12))
298 
299 			{
300 				m_vDummies.push_back(Dummy());
301 				ParseLV1ObjectBlock(m_vDummies.back());
302 				continue;
303 			}
304 			// light object
305 			if (TokenMatch(filePtr,"LIGHTOBJECT",11))
306 
307 			{
308 				m_vLights.push_back(Light());
309 				ParseLV1ObjectBlock(m_vLights.back());
310 				continue;
311 			}
312 			// camera object
313 			if (TokenMatch(filePtr,"CAMERAOBJECT",12))
314 			{
315 				m_vCameras.push_back(Camera());
316 				ParseLV1ObjectBlock(m_vCameras.back());
317 				continue;
318 			}
319 			// comment - print it on the console
320 			if (TokenMatch(filePtr,"COMMENT",7))
321 			{
322 				std::string out = "<unknown>";
323 				ParseString(out,"*COMMENT");
324 				LogInfo(("Comment: " + out).c_str());
325 				continue;
326 			}
327 			// ASC bone weights
328 			if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr,"MESH_SOFTSKINVERTS",18))
329 			{
330 				ParseLV1SoftSkinBlock();
331 			}
332 		}
333 		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
334 	}
335 	return;
336 }
337 
338 // ------------------------------------------------------------------------------------------------
ParseLV1SoftSkinBlock()339 void Parser::ParseLV1SoftSkinBlock()
340 {
341 	// TODO: fix line counting here
342 
343 	// **************************************************************
344 	// The soft skin block is formatted differently. There are no
345 	// nested sections supported and the single elements aren't
346 	// marked by keywords starting with an asterisk.
347 
348 	/**
349 	FORMAT BEGIN
350 
351 	*MESH_SOFTSKINVERTS {
352 	<nodename>
353 	<number of vertices>
354 
355 	[for <number of vertices> times:]
356 		<number of weights>	[for <number of weights> times:] <bone name> <weight>
357 	}
358 
359 	FORMAT END
360 	*/
361 	// **************************************************************
362 	while (true)
363 	{
364 		if (*filePtr == '}'      )	{++filePtr;return;}
365 		else if (*filePtr == '\0')	return;
366 		else if (*filePtr == '{' )	++filePtr;
367 
368 		else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr))
369 		{
370 			ASE::Mesh* curMesh		= NULL;
371 			unsigned int numVerts	= 0;
372 
373 			const char* sz = filePtr;
374 			while (!IsSpaceOrNewLine(*filePtr))++filePtr;
375 
376 			const unsigned int diff = (unsigned int)(filePtr-sz);
377 			if (diff)
378 			{
379 				std::string name = std::string(sz,diff);
380 				for (std::vector<ASE::Mesh>::iterator it = m_vMeshes.begin();
381 					it != m_vMeshes.end(); ++it)
382 				{
383 					if ((*it).mName == name)
384 					{
385 						curMesh = & (*it);
386 						break;
387 					}
388 				}
389 				if (!curMesh)
390 				{
391 					LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section");
392 
393 					// Skip the mesh data - until we find a new mesh
394 					// or the end of the *MESH_SOFTSKINVERTS section
395 					while (true)
396 					{
397 						SkipSpacesAndLineEnd(&filePtr);
398 						if (*filePtr == '}')
399 							{++filePtr;return;}
400 						else if (!IsNumeric(*filePtr))
401 							break;
402 
403 						SkipLine(&filePtr);
404 					}
405 				}
406 				else
407 				{
408 					SkipSpacesAndLineEnd(&filePtr);
409 					ParseLV4MeshLong(numVerts);
410 
411 					// Reserve enough storage
412 					curMesh->mBoneVertices.reserve(numVerts);
413 
414 					for (unsigned int i = 0; i < numVerts;++i)
415 					{
416 						SkipSpacesAndLineEnd(&filePtr);
417 						unsigned int numWeights;
418 						ParseLV4MeshLong(numWeights);
419 
420 						curMesh->mBoneVertices.push_back(ASE::BoneVertex());
421 						ASE::BoneVertex& vert = curMesh->mBoneVertices.back();
422 
423 						// Reserve enough storage
424 						vert.mBoneWeights.reserve(numWeights);
425 
426 						for (unsigned int w = 0; w < numWeights;++w)
427 						{
428 							std::string bone;
429 							ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
430 
431 							// Find the bone in the mesh's list
432 							std::pair<int,float> me;
433 							me.first = -1;
434 
435 							for (unsigned int n = 0; n < curMesh->mBones.size();++n)
436 							{
437 								if (curMesh->mBones[n].mName == bone)
438 								{
439 									me.first = n;
440 									break;
441 								}
442 							}
443 							if (-1 == me.first)
444 							{
445 								// We don't have this bone yet, so add it to the list
446 								me.first = (int)curMesh->mBones.size();
447 								curMesh->mBones.push_back(ASE::Bone(bone));
448 							}
449 							ParseLV4MeshFloat( me.second );
450 
451 							// Add the new bone weight to list
452 							vert.mBoneWeights.push_back(me);
453 						}
454 					}
455 				}
456 			}
457 		}
458 		++filePtr;
459 		SkipSpacesAndLineEnd(&filePtr);
460 	}
461 }
462 
463 // ------------------------------------------------------------------------------------------------
ParseLV1SceneBlock()464 void Parser::ParseLV1SceneBlock()
465 {
466 	AI_ASE_PARSER_INIT();
467 	while (true)
468 	{
469 		if ('*' == *filePtr)
470 		{
471 			++filePtr;
472 			if (TokenMatch(filePtr,"SCENE_BACKGROUND_STATIC",23))
473 
474 			{
475 				// parse a color triple and assume it is really the bg color
476 				ParseLV4MeshFloatTriple( &m_clrBackground.r );
477 				continue;
478 			}
479 			if (TokenMatch(filePtr,"SCENE_AMBIENT_STATIC",20))
480 
481 			{
482 				// parse a color triple and assume it is really the bg color
483 				ParseLV4MeshFloatTriple( &m_clrAmbient.r );
484 				continue;
485 			}
486 			if (TokenMatch(filePtr,"SCENE_FIRSTFRAME",16))
487 			{
488 				ParseLV4MeshLong(iFirstFrame);
489 				continue;
490 			}
491 			if (TokenMatch(filePtr,"SCENE_LASTFRAME",15))
492 			{
493 				ParseLV4MeshLong(iLastFrame);
494 				continue;
495 			}
496 			if (TokenMatch(filePtr,"SCENE_FRAMESPEED",16))
497 			{
498 				ParseLV4MeshLong(iFrameSpeed);
499 				continue;
500 			}
501 			if (TokenMatch(filePtr,"SCENE_TICKSPERFRAME",19))
502 			{
503 				ParseLV4MeshLong(iTicksPerFrame);
504 				continue;
505 			}
506 		}
507 		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
508 	}
509 }
510 
511 // ------------------------------------------------------------------------------------------------
ParseLV1MaterialListBlock()512 void Parser::ParseLV1MaterialListBlock()
513 {
514 	AI_ASE_PARSER_INIT();
515 
516 	unsigned int iMaterialCount = 0;
517 	unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size();
518 	while (true)
519 	{
520 		if ('*' == *filePtr)
521 		{
522 			++filePtr;
523 			if (TokenMatch(filePtr,"MATERIAL_COUNT",14))
524 			{
525 				ParseLV4MeshLong(iMaterialCount);
526 
527 				// now allocate enough storage to hold all materials
528 				m_vMaterials.resize(iOldMaterialCount+iMaterialCount);
529 				continue;
530 			}
531 			if (TokenMatch(filePtr,"MATERIAL",8))
532 			{
533 				unsigned int iIndex = 0;
534 				ParseLV4MeshLong(iIndex);
535 
536 				if (iIndex >= iMaterialCount)
537 				{
538 					LogWarning("Out of range: material index is too large");
539 					iIndex = iMaterialCount-1;
540 				}
541 
542 				// get a reference to the material
543 				Material& sMat = m_vMaterials[iIndex+iOldMaterialCount];
544 				// parse the material block
545 				ParseLV2MaterialBlock(sMat);
546 				continue;
547 			}
548 		}
549 		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
550 	}
551 }
552 
553 // ------------------------------------------------------------------------------------------------
ParseLV2MaterialBlock(ASE::Material & mat)554 void Parser::ParseLV2MaterialBlock(ASE::Material& mat)
555 {
556 	AI_ASE_PARSER_INIT();
557 
558 	unsigned int iNumSubMaterials = 0;
559 	while (true)
560 	{
561 		if ('*' == *filePtr)
562 		{
563 			++filePtr;
564 			if (TokenMatch(filePtr,"MATERIAL_NAME",13))
565 			{
566 				if (!ParseString(mat.mName,"*MATERIAL_NAME"))
567 					SkipToNextToken();
568 				continue;
569 			}
570 			// ambient material color
571 			if (TokenMatch(filePtr,"MATERIAL_AMBIENT",16))
572 			{
573 				ParseLV4MeshFloatTriple(&mat.mAmbient.r);
574 				continue;
575 			}
576 			// diffuse material color
577 			if (TokenMatch(filePtr,"MATERIAL_DIFFUSE",16) )
578 			{
579 				ParseLV4MeshFloatTriple(&mat.mDiffuse.r);
580 				continue;
581 			}
582 			// specular material color
583 			if (TokenMatch(filePtr,"MATERIAL_SPECULAR",17))
584 			{
585 				ParseLV4MeshFloatTriple(&mat.mSpecular.r);
586 				continue;
587 			}
588 			// material shading type
589 			if (TokenMatch(filePtr,"MATERIAL_SHADING",16))
590 			{
591 				if (TokenMatch(filePtr,"Blinn",5))
592 				{
593 					mat.mShading = Discreet3DS::Blinn;
594 				}
595 				else if (TokenMatch(filePtr,"Phong",5))
596 				{
597 					mat.mShading = Discreet3DS::Phong;
598 				}
599 				else if (TokenMatch(filePtr,"Flat",4))
600 				{
601 					mat.mShading = Discreet3DS::Flat;
602 				}
603 				else if (TokenMatch(filePtr,"Wire",4))
604 				{
605 					mat.mShading = Discreet3DS::Wire;
606 				}
607 				else
608 				{
609 					// assume gouraud shading
610 					mat.mShading = Discreet3DS::Gouraud;
611 					SkipToNextToken();
612 				}
613 				continue;
614 			}
615 			// material transparency
616 			if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21))
617 			{
618 				ParseLV4MeshFloat(mat.mTransparency);
619 				mat.mTransparency = 1.0f - mat.mTransparency;continue;
620 			}
621 			// material self illumination
622 			if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18))
623 			{
624 				float f = 0.0f;
625 				ParseLV4MeshFloat(f);
626 
627 				mat.mEmissive.r = f;
628 				mat.mEmissive.g = f;
629 				mat.mEmissive.b = f;
630 				continue;
631 			}
632 			// material shininess
633 			if (TokenMatch(filePtr,"MATERIAL_SHINE",14) )
634 			{
635 				ParseLV4MeshFloat(mat.mSpecularExponent);
636 				mat.mSpecularExponent *= 15;
637 				continue;
638 			}
639 			// two-sided material
640 			if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) )
641 			{
642 				mat.mTwoSided = true;
643 				continue;
644 			}
645 			// material shininess strength
646 			if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22))
647 			{
648 				ParseLV4MeshFloat(mat.mShininessStrength);
649 				continue;
650 			}
651 			// diffuse color map
652 			if (TokenMatch(filePtr,"MAP_DIFFUSE",11))
653 			{
654 				// parse the texture block
655 				ParseLV3MapBlock(mat.sTexDiffuse);
656 				continue;
657 			}
658 			// ambient color map
659 			if (TokenMatch(filePtr,"MAP_AMBIENT",11))
660 			{
661 				// parse the texture block
662 				ParseLV3MapBlock(mat.sTexAmbient);
663 				continue;
664 			}
665 			// specular color map
666 			if (TokenMatch(filePtr,"MAP_SPECULAR",12))
667 			{
668 				// parse the texture block
669 				ParseLV3MapBlock(mat.sTexSpecular);
670 				continue;
671 			}
672 			// opacity map
673 			if (TokenMatch(filePtr,"MAP_OPACITY",11))
674 			{
675 				// parse the texture block
676 				ParseLV3MapBlock(mat.sTexOpacity);
677 				continue;
678 			}
679 			// emissive map
680 			if (TokenMatch(filePtr,"MAP_SELFILLUM",13))
681 			{
682 				// parse the texture block
683 				ParseLV3MapBlock(mat.sTexEmissive);
684 				continue;
685 			}
686 			// bump map
687 			if (TokenMatch(filePtr,"MAP_BUMP",8))
688 			{
689 				// parse the texture block
690 				ParseLV3MapBlock(mat.sTexBump);
691 			}
692 			// specular/shininess map
693 			if (TokenMatch(filePtr,"MAP_SHINESTRENGTH",17))
694 			{
695 				// parse the texture block
696 				ParseLV3MapBlock(mat.sTexShininess);
697 				continue;
698 			}
699 			// number of submaterials
700 			if (TokenMatch(filePtr,"NUMSUBMTLS",10))
701 			{
702 				ParseLV4MeshLong(iNumSubMaterials);
703 
704 				// allocate enough storage
705 				mat.avSubMaterials.resize(iNumSubMaterials);
706 			}
707 			// submaterial chunks
708 			if (TokenMatch(filePtr,"SUBMATERIAL",11))
709 			{
710 
711 				unsigned int iIndex = 0;
712 				ParseLV4MeshLong(iIndex);
713 
714 				if (iIndex >= iNumSubMaterials)
715 				{
716 					LogWarning("Out of range: submaterial index is too large");
717 					iIndex = iNumSubMaterials-1;
718 				}
719 
720 				// get a reference to the material
721 				Material& sMat = mat.avSubMaterials[iIndex];
722 
723 				// parse the material block
724 				ParseLV2MaterialBlock(sMat);
725 				continue;
726 			}
727 		}
728 		AI_ASE_HANDLE_SECTION("2","*MATERIAL");
729 	}
730 }
731 
732 // ------------------------------------------------------------------------------------------------
ParseLV3MapBlock(Texture & map)733 void Parser::ParseLV3MapBlock(Texture& map)
734 {
735 	AI_ASE_PARSER_INIT();
736 
737 	// ***********************************************************
738 	// *BITMAP should not be there if *MAP_CLASS is not BITMAP,
739 	// but we need to expect that case ... if the path is
740 	// empty the texture won't be used later.
741 	// ***********************************************************
742 	bool parsePath = true;
743 	while (true)
744 	{
745 		if ('*' == *filePtr)
746 		{
747 			++filePtr;
748 			// type of map
749 			if (TokenMatch(filePtr,"MAP_CLASS" ,9))
750 			{
751 				std::string temp;
752 				if(!ParseString(temp,"*MAP_CLASS"))
753 					SkipToNextToken();
754 				if (temp != "Bitmap" && temp != "Normal Bump")
755 				{
756 					DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp);
757 					parsePath = false;
758 				}
759 				continue;
760 			}
761 			// path to the texture
762 			if (parsePath && TokenMatch(filePtr,"BITMAP" ,6))
763 			{
764 				if(!ParseString(map.mMapName,"*BITMAP"))
765 					SkipToNextToken();
766 
767 				if (map.mMapName == "None")
768 				{
769 					// Files with 'None' as map name are produced by
770 					// an Maja to ASE exporter which name I forgot ..
771 					DefaultLogger::get()->warn("ASE: Skipping invalid map entry");
772 					map.mMapName = "";
773 				}
774 
775 				continue;
776 			}
777 			// offset on the u axis
778 			if (TokenMatch(filePtr,"UVW_U_OFFSET" ,12))
779 			{
780 				ParseLV4MeshFloat(map.mOffsetU);
781 				continue;
782 			}
783 			// offset on the v axis
784 			if (TokenMatch(filePtr,"UVW_V_OFFSET" ,12))
785 			{
786 				ParseLV4MeshFloat(map.mOffsetV);
787 				continue;
788 			}
789 			// tiling on the u axis
790 			if (TokenMatch(filePtr,"UVW_U_TILING" ,12))
791 			{
792 				ParseLV4MeshFloat(map.mScaleU);
793 				continue;
794 			}
795 			// tiling on the v axis
796 			if (TokenMatch(filePtr,"UVW_V_TILING" ,12))
797 			{
798 				ParseLV4MeshFloat(map.mScaleV);
799 				continue;
800 			}
801 			// rotation around the z-axis
802 			if (TokenMatch(filePtr,"UVW_ANGLE" ,9))
803 			{
804 				ParseLV4MeshFloat(map.mRotation);
805 				continue;
806 			}
807 			// map blending factor
808 			if (TokenMatch(filePtr,"MAP_AMOUNT" ,10))
809 			{
810 				ParseLV4MeshFloat(map.mTextureBlend);
811 				continue;
812 			}
813 		}
814 		AI_ASE_HANDLE_SECTION("3","*MAP_XXXXXX");
815 	}
816 	return;
817 }
818 
819 // ------------------------------------------------------------------------------------------------
ParseString(std::string & out,const char * szName)820 bool Parser::ParseString(std::string& out,const char* szName)
821 {
822 	char szBuffer[1024];
823 	if (!SkipSpaces(&filePtr))
824 	{
825 
826 		sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName);
827 		LogWarning(szBuffer);
828 		return false;
829 	}
830 	// there must be '"'
831 	if ('\"' != *filePtr)
832 	{
833 
834 		sprintf(szBuffer,"Unable to parse %s block: Strings are expected "
835 			"to be enclosed in double quotation marks",szName);
836 		LogWarning(szBuffer);
837 		return false;
838 	}
839 	++filePtr;
840 	const char* sz = filePtr;
841 	while (true)
842 	{
843 		if ('\"' == *sz)break;
844 		else if ('\0' == *sz)
845 		{
846 			sprintf(szBuffer,"Unable to parse %s block: Strings are expected to "
847 				"be enclosed in double quotation marks but EOF was reached before "
848 				"a closing quotation mark was encountered",szName);
849 			LogWarning(szBuffer);
850 			return false;
851 		}
852 		sz++;
853 	}
854 	out = std::string(filePtr,(uintptr_t)sz-(uintptr_t)filePtr);
855 	filePtr = sz+1;
856 	return true;
857 }
858 
859 // ------------------------------------------------------------------------------------------------
ParseLV1ObjectBlock(ASE::BaseNode & node)860 void Parser::ParseLV1ObjectBlock(ASE::BaseNode& node)
861 {
862 	AI_ASE_PARSER_INIT();
863 	while (true)
864 	{
865 		if ('*' == *filePtr)
866 		{
867 			++filePtr;
868 
869 			// first process common tokens such as node name and transform
870 			// name of the mesh/node
871 			if (TokenMatch(filePtr,"NODE_NAME" ,9))
872 			{
873 				if(!ParseString(node.mName,"*NODE_NAME"))
874 					SkipToNextToken();
875 				continue;
876 			}
877 			// name of the parent of the node
878 			if (TokenMatch(filePtr,"NODE_PARENT" ,11) )
879 			{
880 				if(!ParseString(node.mParent,"*NODE_PARENT"))
881 					SkipToNextToken();
882 				continue;
883 			}
884 			// transformation matrix of the node
885 			if (TokenMatch(filePtr,"NODE_TM" ,7))
886 			{
887 				ParseLV2NodeTransformBlock(node);
888 				continue;
889 			}
890 			// animation data of the node
891 			if (TokenMatch(filePtr,"TM_ANIMATION" ,12))
892 			{
893 				ParseLV2AnimationBlock(node);
894 				continue;
895 			}
896 
897 			if (node.mType == BaseNode::Light)
898 			{
899 				// light settings
900 				if (TokenMatch(filePtr,"LIGHT_SETTINGS" ,14))
901 				{
902 					ParseLV2LightSettingsBlock((ASE::Light&)node);
903 					continue;
904 				}
905 				// type of the light source
906 				if (TokenMatch(filePtr,"LIGHT_TYPE" ,10))
907 				{
908 					if (!ASSIMP_strincmp("omni",filePtr,4))
909 					{
910 						((ASE::Light&)node).mLightType = ASE::Light::OMNI;
911 					}
912 					else if (!ASSIMP_strincmp("target",filePtr,6))
913 					{
914 						((ASE::Light&)node).mLightType = ASE::Light::TARGET;
915 					}
916 					else if (!ASSIMP_strincmp("free",filePtr,4))
917 					{
918 						((ASE::Light&)node).mLightType = ASE::Light::FREE;
919 					}
920 					else if (!ASSIMP_strincmp("directional",filePtr,11))
921 					{
922 						((ASE::Light&)node).mLightType = ASE::Light::DIRECTIONAL;
923 					}
924 					else
925 					{
926 						LogWarning("Unknown kind of light source");
927 					}
928 					continue;
929 				}
930 			}
931 			else if (node.mType == BaseNode::Camera)
932 			{
933 				// Camera settings
934 				if (TokenMatch(filePtr,"CAMERA_SETTINGS" ,15))
935 				{
936 					ParseLV2CameraSettingsBlock((ASE::Camera&)node);
937 					continue;
938 				}
939 				else if (TokenMatch(filePtr,"CAMERA_TYPE" ,11))
940 				{
941 					if (!ASSIMP_strincmp("target",filePtr,6))
942 					{
943 						((ASE::Camera&)node).mCameraType = ASE::Camera::TARGET;
944 					}
945 					else if (!ASSIMP_strincmp("free",filePtr,4))
946 					{
947 						((ASE::Camera&)node).mCameraType = ASE::Camera::FREE;
948 					}
949 					else
950 					{
951 						LogWarning("Unknown kind of camera");
952 					}
953 					continue;
954 				}
955 			}
956 			else if (node.mType == BaseNode::Mesh)
957 			{
958 				// mesh data
959 				// FIX: Older files use MESH_SOFTSKIN
960 				if (TokenMatch(filePtr,"MESH" ,4) ||
961 					TokenMatch(filePtr,"MESH_SOFTSKIN",13))
962 				{
963 					ParseLV2MeshBlock((ASE::Mesh&)node);
964 					continue;
965 				}
966 				// mesh material index
967 				if (TokenMatch(filePtr,"MATERIAL_REF" ,12))
968 				{
969 					ParseLV4MeshLong(((ASE::Mesh&)node).iMaterialIndex);
970 					continue;
971 				}
972 			}
973 		}
974 		AI_ASE_HANDLE_TOP_LEVEL_SECTION();
975 	}
976 	return;
977 }
978 
979 // ------------------------------------------------------------------------------------------------
ParseLV2CameraSettingsBlock(ASE::Camera & camera)980 void Parser::ParseLV2CameraSettingsBlock(ASE::Camera& camera)
981 {
982 	AI_ASE_PARSER_INIT();
983 	while (true)
984 	{
985 		if ('*' == *filePtr)
986 		{
987 			++filePtr;
988 			if (TokenMatch(filePtr,"CAMERA_NEAR" ,11))
989 			{
990 				ParseLV4MeshFloat(camera.mNear);
991 				continue;
992 			}
993 			if (TokenMatch(filePtr,"CAMERA_FAR" ,10))
994 			{
995 				ParseLV4MeshFloat(camera.mFar);
996 				continue;
997 			}
998 			if (TokenMatch(filePtr,"CAMERA_FOV" ,10))
999 			{
1000 				ParseLV4MeshFloat(camera.mFOV);
1001 				continue;
1002 			}
1003 		}
1004 		AI_ASE_HANDLE_SECTION("2","CAMERA_SETTINGS");
1005 	}
1006 	return;
1007 }
1008 
1009 // ------------------------------------------------------------------------------------------------
ParseLV2LightSettingsBlock(ASE::Light & light)1010 void Parser::ParseLV2LightSettingsBlock(ASE::Light& light)
1011 {
1012 	AI_ASE_PARSER_INIT();
1013 	while (true)
1014 	{
1015 		if ('*' == *filePtr)
1016 		{
1017 			++filePtr;
1018 			if (TokenMatch(filePtr,"LIGHT_COLOR" ,11))
1019 			{
1020 				ParseLV4MeshFloatTriple(&light.mColor.r);
1021 				continue;
1022 			}
1023 			if (TokenMatch(filePtr,"LIGHT_INTENS" ,12))
1024 			{
1025 				ParseLV4MeshFloat(light.mIntensity);
1026 				continue;
1027 			}
1028 			if (TokenMatch(filePtr,"LIGHT_HOTSPOT" ,13))
1029 			{
1030 				ParseLV4MeshFloat(light.mAngle);
1031 				continue;
1032 			}
1033 			if (TokenMatch(filePtr,"LIGHT_FALLOFF" ,13))
1034 			{
1035 				ParseLV4MeshFloat(light.mFalloff);
1036 				continue;
1037 			}
1038 		}
1039 		AI_ASE_HANDLE_SECTION("2","LIGHT_SETTINGS");
1040 	}
1041 	return;
1042 }
1043 
1044 // ------------------------------------------------------------------------------------------------
ParseLV2AnimationBlock(ASE::BaseNode & mesh)1045 void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
1046 {
1047 	AI_ASE_PARSER_INIT();
1048 
1049 	ASE::Animation* anim = &mesh.mAnim;
1050 	while (true)
1051 	{
1052 		if ('*' == *filePtr)
1053 		{
1054 			++filePtr;
1055 			if (TokenMatch(filePtr,"NODE_NAME" ,9))
1056 			{
1057 				std::string temp;
1058 				if(!ParseString(temp,"*NODE_NAME"))
1059 					SkipToNextToken();
1060 
1061 				// If the name of the node contains .target it
1062 				// represents an animated camera or spot light
1063 				// target.
1064 				if (std::string::npos != temp.find(".Target"))
1065 				{
1066 					if  ((mesh.mType != BaseNode::Camera || ((ASE::Camera&)mesh).mCameraType != ASE::Camera::TARGET)  &&
1067 						( mesh.mType != BaseNode::Light  || ((ASE::Light&)mesh).mLightType   != ASE::Light::TARGET))
1068 					{
1069 
1070 						DefaultLogger::get()->error("ASE: Found target animation channel "
1071 							"but the node is neither a camera nor a spot light");
1072 						anim = NULL;
1073 					}
1074 					else anim = &mesh.mTargetAnim;
1075 				}
1076 				continue;
1077 			}
1078 
1079 			// position keyframes
1080 			if (TokenMatch(filePtr,"CONTROL_POS_TRACK"  ,17)  ||
1081 				TokenMatch(filePtr,"CONTROL_POS_BEZIER" ,18)  ||
1082 				TokenMatch(filePtr,"CONTROL_POS_TCB"    ,15))
1083 			{
1084 				if (!anim)SkipSection();
1085 				else ParseLV3PosAnimationBlock(*anim);
1086 				continue;
1087 			}
1088 			// scaling keyframes
1089 			if (TokenMatch(filePtr,"CONTROL_SCALE_TRACK"  ,19) ||
1090 				TokenMatch(filePtr,"CONTROL_SCALE_BEZIER" ,20) ||
1091 				TokenMatch(filePtr,"CONTROL_SCALE_TCB"    ,17))
1092 			{
1093 				if (!anim || anim == &mesh.mTargetAnim)
1094 				{
1095 					// Target animation channels may have no rotation channels
1096 					DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation");
1097 					SkipSection();
1098 				}
1099 				else ParseLV3ScaleAnimationBlock(*anim);
1100 				continue;
1101 			}
1102 			// rotation keyframes
1103 			if (TokenMatch(filePtr,"CONTROL_ROT_TRACK"  ,17) ||
1104 				TokenMatch(filePtr,"CONTROL_ROT_BEZIER" ,18) ||
1105 				TokenMatch(filePtr,"CONTROL_ROT_TCB"    ,15))
1106 			{
1107 				if (!anim || anim == &mesh.mTargetAnim)
1108 				{
1109 					// Target animation channels may have no rotation channels
1110 					DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation");
1111 					SkipSection();
1112 				}
1113 				else ParseLV3RotAnimationBlock(*anim);
1114 				continue;
1115 			}
1116 		}
1117 		AI_ASE_HANDLE_SECTION("2","TM_ANIMATION");
1118 	}
1119 }
1120 // ------------------------------------------------------------------------------------------------
ParseLV3ScaleAnimationBlock(ASE::Animation & anim)1121 void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation& anim)
1122 {
1123 	AI_ASE_PARSER_INIT();
1124 	unsigned int iIndex;
1125 
1126 	while (true)
1127 	{
1128 		if ('*' == *filePtr)
1129 		{
1130 			++filePtr;
1131 
1132 			bool b = false;
1133 
1134 			// For the moment we're just reading the three floats -
1135 			// we ignore the �dditional information for bezier's and TCBs
1136 
1137 			// simple scaling keyframe
1138 			if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20))
1139 			{
1140 				b = true;
1141 				anim.mScalingType = ASE::Animation::TRACK;
1142 			}
1143 
1144 			// Bezier scaling keyframe
1145 			if (TokenMatch(filePtr,"CONTROL_BEZIER_SCALE_KEY" ,24))
1146 			{
1147 				b = true;
1148 				anim.mScalingType = ASE::Animation::BEZIER;
1149 			}
1150 			// TCB scaling keyframe
1151 			if (TokenMatch(filePtr,"CONTROL_TCB_SCALE_KEY" ,21))
1152 			{
1153 				b = true;
1154 				anim.mScalingType = ASE::Animation::TCB;
1155 			}
1156 			if (b)
1157 			{
1158 				anim.akeyScaling.push_back(aiVectorKey());
1159 				aiVectorKey& key = anim.akeyScaling.back();
1160 				ParseLV4MeshFloatTriple(&key.mValue.x,iIndex);
1161 				key.mTime = (double)iIndex;
1162 			}
1163 		}
1164 		AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK");
1165 	}
1166 }
1167 // ------------------------------------------------------------------------------------------------
ParseLV3PosAnimationBlock(ASE::Animation & anim)1168 void Parser::ParseLV3PosAnimationBlock(ASE::Animation& anim)
1169 {
1170 	AI_ASE_PARSER_INIT();
1171 	unsigned int iIndex;
1172 	while (true)
1173 	{
1174 		if ('*' == *filePtr)
1175 		{
1176 			++filePtr;
1177 
1178 			bool b = false;
1179 
1180 			// For the moment we're just reading the three floats -
1181 			// we ignore the �dditional information for bezier's and TCBs
1182 
1183 			// simple scaling keyframe
1184 			if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18))
1185 			{
1186 				b = true;
1187 				anim.mPositionType = ASE::Animation::TRACK;
1188 			}
1189 
1190 			// Bezier scaling keyframe
1191 			if (TokenMatch(filePtr,"CONTROL_BEZIER_POS_KEY" ,22))
1192 			{
1193 				b = true;
1194 				anim.mPositionType = ASE::Animation::BEZIER;
1195 			}
1196 			// TCB scaling keyframe
1197 			if (TokenMatch(filePtr,"CONTROL_TCB_POS_KEY" ,19))
1198 			{
1199 				b = true;
1200 				anim.mPositionType = ASE::Animation::TCB;
1201 			}
1202 			if (b)
1203 			{
1204 				anim.akeyPositions.push_back(aiVectorKey());
1205 				aiVectorKey& key = anim.akeyPositions.back();
1206 				ParseLV4MeshFloatTriple(&key.mValue.x,iIndex);
1207 				key.mTime = (double)iIndex;
1208 			}
1209 		}
1210 		AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK");
1211 	}
1212 }
1213 // ------------------------------------------------------------------------------------------------
ParseLV3RotAnimationBlock(ASE::Animation & anim)1214 void Parser::ParseLV3RotAnimationBlock(ASE::Animation& anim)
1215 {
1216 	AI_ASE_PARSER_INIT();
1217 	unsigned int iIndex;
1218 	while (true)
1219 	{
1220 		if ('*' == *filePtr)
1221 		{
1222 			++filePtr;
1223 
1224 			bool b = false;
1225 
1226 			// For the moment we're just reading the  floats -
1227 			// we ignore the �dditional information for bezier's and TCBs
1228 
1229 			// simple scaling keyframe
1230 			if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18))
1231 			{
1232 				b = true;
1233 				anim.mRotationType = ASE::Animation::TRACK;
1234 			}
1235 
1236 			// Bezier scaling keyframe
1237 			if (TokenMatch(filePtr,"CONTROL_BEZIER_ROT_KEY" ,22))
1238 			{
1239 				b = true;
1240 				anim.mRotationType = ASE::Animation::BEZIER;
1241 			}
1242 			// TCB scaling keyframe
1243 			if (TokenMatch(filePtr,"CONTROL_TCB_ROT_KEY" ,19))
1244 			{
1245 				b = true;
1246 				anim.mRotationType = ASE::Animation::TCB;
1247 			}
1248 			if (b)
1249 			{
1250 				anim.akeyRotations.push_back(aiQuatKey());
1251 				aiQuatKey& key = anim.akeyRotations.back();
1252 				aiVector3D v;float f;
1253 				ParseLV4MeshFloatTriple(&v.x,iIndex);
1254 				ParseLV4MeshFloat(f);
1255 				key.mTime = (double)iIndex;
1256 				key.mValue = aiQuaternion(v,f);
1257 			}
1258 		}
1259 		AI_ASE_HANDLE_SECTION("3","*CONTROL_ROT_TRACK");
1260 	}
1261 }
1262 // ------------------------------------------------------------------------------------------------
ParseLV2NodeTransformBlock(ASE::BaseNode & mesh)1263 void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode& mesh)
1264 {
1265 	AI_ASE_PARSER_INIT();
1266 	int mode   = 0;
1267 	while (true)
1268 	{
1269 		if ('*' == *filePtr)
1270 		{
1271 			++filePtr;
1272 			// name of the node
1273 			if (TokenMatch(filePtr,"NODE_NAME" ,9))
1274 			{
1275 				std::string temp;
1276 				if(!ParseString(temp,"*NODE_NAME"))
1277 					SkipToNextToken();
1278 
1279 				std::string::size_type s;
1280 				if (temp == mesh.mName)
1281 				{
1282 					mode = 1;
1283 				}
1284 				else if (std::string::npos != (s = temp.find(".Target")) &&
1285 					mesh.mName == temp.substr(0,s))
1286 				{
1287 					// This should be either a target light or a target camera
1288 					if ( (mesh.mType == BaseNode::Light &&  ((ASE::Light&)mesh) .mLightType  == ASE::Light::TARGET) ||
1289 						 (mesh.mType == BaseNode::Camera && ((ASE::Camera&)mesh).mCameraType == ASE::Camera::TARGET))
1290 					{
1291 						mode = 2;
1292 					}
1293 					else DefaultLogger::get()->error("ASE: Ignoring target transform, "
1294 						"this is no spot light or target camera");
1295 				}
1296 				else
1297 				{
1298 					DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp);
1299 					// mode = 0
1300 				}
1301 				continue;
1302 			}
1303 			if (mode)
1304 			{
1305 				// fourth row of the transformation matrix - and also the
1306 				// only information here that is interesting for targets
1307 				if (TokenMatch(filePtr,"TM_ROW3" ,7))
1308 				{
1309 					ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x));
1310 					continue;
1311 				}
1312 				if (mode == 1)
1313 				{
1314 					// first row of the transformation matrix
1315 					if (TokenMatch(filePtr,"TM_ROW0" ,7))
1316 					{
1317 						ParseLV4MeshFloatTriple(mesh.mTransform[0]);
1318 						continue;
1319 					}
1320 					// second row of the transformation matrix
1321 					if (TokenMatch(filePtr,"TM_ROW1" ,7))
1322 					{
1323 						ParseLV4MeshFloatTriple(mesh.mTransform[1]);
1324 						continue;
1325 					}
1326 					// third row of the transformation matrix
1327 					if (TokenMatch(filePtr,"TM_ROW2" ,7))
1328 					{
1329 						ParseLV4MeshFloatTriple(mesh.mTransform[2]);
1330 						continue;
1331 					}
1332 					// inherited position axes
1333 					if (TokenMatch(filePtr,"INHERIT_POS" ,11))
1334 					{
1335 						unsigned int aiVal[3];
1336 						ParseLV4MeshLongTriple(aiVal);
1337 
1338 						for (unsigned int i = 0; i < 3;++i)
1339 							mesh.inherit.abInheritPosition[i] = aiVal[i] != 0;
1340 						continue;
1341 					}
1342 					// inherited rotation axes
1343 					if (TokenMatch(filePtr,"INHERIT_ROT" ,11))
1344 					{
1345 						unsigned int aiVal[3];
1346 						ParseLV4MeshLongTriple(aiVal);
1347 
1348 						for (unsigned int i = 0; i < 3;++i)
1349 							mesh.inherit.abInheritRotation[i] = aiVal[i] != 0;
1350 						continue;
1351 					}
1352 					// inherited scaling axes
1353 					if (TokenMatch(filePtr,"INHERIT_SCL" ,11))
1354 					{
1355 						unsigned int aiVal[3];
1356 						ParseLV4MeshLongTriple(aiVal);
1357 
1358 						for (unsigned int i = 0; i < 3;++i)
1359 							mesh.inherit.abInheritScaling[i] = aiVal[i] != 0;
1360 						continue;
1361 					}
1362 				}
1363 			}
1364 		}
1365 		AI_ASE_HANDLE_SECTION("2","*NODE_TM");
1366 	}
1367 	return;
1368 }
1369 // ------------------------------------------------------------------------------------------------
ParseLV2MeshBlock(ASE::Mesh & mesh)1370 void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh)
1371 {
1372 	AI_ASE_PARSER_INIT();
1373 
1374 	unsigned int iNumVertices = 0;
1375 	unsigned int iNumFaces = 0;
1376 	unsigned int iNumTVertices = 0;
1377 	unsigned int iNumTFaces = 0;
1378 	unsigned int iNumCVertices = 0;
1379 	unsigned int iNumCFaces = 0;
1380 	while (true)
1381 	{
1382 		if ('*' == *filePtr)
1383 		{
1384 			++filePtr;
1385 			// Number of vertices in the mesh
1386 			if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14))
1387 			{
1388 				ParseLV4MeshLong(iNumVertices);
1389 				continue;
1390 			}
1391 			// Number of texture coordinates in the mesh
1392 			if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15))
1393 			{
1394 				ParseLV4MeshLong(iNumTVertices);
1395 				continue;
1396 			}
1397 			// Number of vertex colors in the mesh
1398 			if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15))
1399 			{
1400 				ParseLV4MeshLong(iNumCVertices);
1401 				continue;
1402 			}
1403 			// Number of regular faces in the mesh
1404 			if (TokenMatch(filePtr,"MESH_NUMFACES" ,13))
1405 			{
1406 				ParseLV4MeshLong(iNumFaces);
1407 				continue;
1408 			}
1409 			// Number of UVWed faces in the mesh
1410 			if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15))
1411 			{
1412 				ParseLV4MeshLong(iNumTFaces);
1413 				continue;
1414 			}
1415 			// Number of colored faces in the mesh
1416 			if (TokenMatch(filePtr,"MESH_NUMCVFACES" ,15))
1417 			{
1418 				ParseLV4MeshLong(iNumCFaces);
1419 				continue;
1420 			}
1421 			// mesh vertex list block
1422 			if (TokenMatch(filePtr,"MESH_VERTEX_LIST" ,16))
1423 			{
1424 				ParseLV3MeshVertexListBlock(iNumVertices,mesh);
1425 				continue;
1426 			}
1427 			// mesh face list block
1428 			if (TokenMatch(filePtr,"MESH_FACE_LIST" ,14))
1429 			{
1430 				ParseLV3MeshFaceListBlock(iNumFaces,mesh);
1431 				continue;
1432 			}
1433 			// mesh texture vertex list block
1434 			if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14))
1435 			{
1436 				ParseLV3MeshTListBlock(iNumTVertices,mesh);
1437 				continue;
1438 			}
1439 			// mesh texture face block
1440 			if (TokenMatch(filePtr,"MESH_TFACELIST" ,14))
1441 			{
1442 				ParseLV3MeshTFaceListBlock(iNumTFaces,mesh);
1443 				continue;
1444 			}
1445 			// mesh color vertex list block
1446 			if (TokenMatch(filePtr,"MESH_CVERTLIST" ,14))
1447 			{
1448 				ParseLV3MeshCListBlock(iNumCVertices,mesh);
1449 				continue;
1450 			}
1451 			// mesh color face block
1452 			if (TokenMatch(filePtr,"MESH_CFACELIST" ,14))
1453 			{
1454 				ParseLV3MeshCFaceListBlock(iNumCFaces,mesh);
1455 				continue;
1456 			}
1457 			// mesh normals
1458 			if (TokenMatch(filePtr,"MESH_NORMALS" ,12))
1459 			{
1460 				ParseLV3MeshNormalListBlock(mesh);
1461 				continue;
1462 			}
1463 			// another mesh UV channel ...
1464 			if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19))
1465 			{
1466 
1467 				unsigned int iIndex = 0;
1468 				ParseLV4MeshLong(iIndex);
1469 
1470 				if (iIndex < 2)
1471 				{
1472 					LogWarning("Mapping channel has an invalid index. Skipping UV channel");
1473 					// skip it ...
1474 					SkipSection();
1475 				}
1476 				if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS)
1477 				{
1478 					LogWarning("Too many UV channels specified. Skipping channel ..");
1479 					// skip it ...
1480 					SkipSection();
1481 				}
1482 				else
1483 				{
1484 					// parse the mapping channel
1485 					ParseLV3MappingChannel(iIndex-1,mesh);
1486 				}
1487 				continue;
1488 			}
1489 			// mesh animation keyframe. Not supported
1490 			if (TokenMatch(filePtr,"MESH_ANIMATION" ,14))
1491 			{
1492 
1493 				LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
1494 					"Keyframe animation is not supported by Assimp, this element "
1495 					"will be ignored");
1496 				//SkipSection();
1497 				continue;
1498 			}
1499 			if (TokenMatch(filePtr,"MESH_WEIGHTS" ,12))
1500 			{
1501 				ParseLV3MeshWeightsBlock(mesh);continue;
1502 			}
1503 		}
1504 		AI_ASE_HANDLE_SECTION("2","*MESH");
1505 	}
1506 	return;
1507 }
1508 // ------------------------------------------------------------------------------------------------
ParseLV3MeshWeightsBlock(ASE::Mesh & mesh)1509 void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh& mesh)
1510 {
1511 	AI_ASE_PARSER_INIT();
1512 
1513 	unsigned int iNumVertices = 0, iNumBones = 0;
1514 	while (true)
1515 	{
1516 		if ('*' == *filePtr)
1517 		{
1518 			++filePtr;
1519 
1520 			// Number of bone vertices ...
1521 			if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14))
1522 			{
1523 				ParseLV4MeshLong(iNumVertices);
1524 				continue;
1525 			}
1526 			// Number of bones
1527 			if (TokenMatch(filePtr,"MESH_NUMBONE" ,11))
1528 			{
1529 				ParseLV4MeshLong(iNumBones);
1530 				continue;
1531 			}
1532 			// parse the list of bones
1533 			if (TokenMatch(filePtr,"MESH_BONE_LIST" ,14))
1534 			{
1535 				ParseLV4MeshBones(iNumBones,mesh);
1536 				continue;
1537 			}
1538 			// parse the list of bones vertices
1539 			if (TokenMatch(filePtr,"MESH_BONE_VERTEX_LIST" ,21) )
1540 			{
1541 				ParseLV4MeshBonesVertices(iNumVertices,mesh);
1542 				continue;
1543 			}
1544 		}
1545 		AI_ASE_HANDLE_SECTION("3","*MESH_WEIGHTS");
1546 	}
1547 	return;
1548 }
1549 // ------------------------------------------------------------------------------------------------
ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh & mesh)1550 void Parser::ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh& mesh)
1551 {
1552 	AI_ASE_PARSER_INIT();
1553 	mesh.mBones.resize(iNumBones);
1554 	while (true)
1555 	{
1556 		if ('*' == *filePtr)
1557 		{
1558 			++filePtr;
1559 
1560 			// Mesh bone with name ...
1561 			if (TokenMatch(filePtr,"MESH_BONE_NAME" ,16))
1562 			{
1563 				// parse an index ...
1564 				if(SkipSpaces(&filePtr))
1565 				{
1566 					unsigned int iIndex = strtoul10(filePtr,&filePtr);
1567 					if (iIndex >= iNumBones)
1568 					{
1569 						continue;
1570 						LogWarning("Bone index is out of bounds");
1571 					}
1572 					if (!ParseString(mesh.mBones[iIndex].mName,"*MESH_BONE_NAME"))
1573 						SkipToNextToken();
1574 					continue;
1575 				}
1576 			}
1577 		}
1578 		AI_ASE_HANDLE_SECTION("3","*MESH_BONE_LIST");
1579 	}
1580 }
1581 // ------------------------------------------------------------------------------------------------
ParseLV4MeshBonesVertices(unsigned int iNumVertices,ASE::Mesh & mesh)1582 void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices,ASE::Mesh& mesh)
1583 {
1584 	AI_ASE_PARSER_INIT();
1585 	mesh.mBoneVertices.resize(iNumVertices);
1586 	while (true)
1587 	{
1588 		if ('*' == *filePtr)
1589 		{
1590 			++filePtr;
1591 
1592 			// Mesh bone vertex
1593 			if (TokenMatch(filePtr,"MESH_BONE_VERTEX" ,16))
1594 			{
1595 				// read the vertex index
1596 				unsigned int iIndex = strtoul10(filePtr,&filePtr);
1597 				if (iIndex >= mesh.mPositions.size())
1598 				{
1599 					iIndex = (unsigned int)mesh.mPositions.size()-1;
1600 					LogWarning("Bone vertex index is out of bounds. Using the largest valid "
1601 						"bone vertex index instead");
1602 				}
1603 
1604 				// --- ignored
1605 				float afVert[3];
1606 				ParseLV4MeshFloatTriple(afVert);
1607 
1608 				std::pair<int,float> pairOut;
1609 				while (true)
1610 				{
1611 					// first parse the bone index ...
1612 					if (!SkipSpaces(&filePtr))break;
1613 					pairOut.first = strtoul10(filePtr,&filePtr);
1614 
1615 					// then parse the vertex weight
1616 					if (!SkipSpaces(&filePtr))break;
1617 					filePtr = fast_atoreal_move<float>(filePtr,pairOut.second);
1618 
1619 					// -1 marks unused entries
1620 					if (-1 != pairOut.first)
1621 					{
1622 						mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut);
1623 					}
1624 				}
1625 				continue;
1626 			}
1627 		}
1628 		AI_ASE_HANDLE_SECTION("4","*MESH_BONE_VERTEX");
1629 	}
1630 	return;
1631 }
1632 // ------------------------------------------------------------------------------------------------
ParseLV3MeshVertexListBlock(unsigned int iNumVertices,ASE::Mesh & mesh)1633 void Parser::ParseLV3MeshVertexListBlock(
1634 	unsigned int iNumVertices, ASE::Mesh& mesh)
1635 {
1636 	AI_ASE_PARSER_INIT();
1637 
1638 	// allocate enough storage in the array
1639 	mesh.mPositions.resize(iNumVertices);
1640 	while (true)
1641 	{
1642 		if ('*' == *filePtr)
1643 		{
1644 			++filePtr;
1645 
1646 			// Vertex entry
1647 			if (TokenMatch(filePtr,"MESH_VERTEX" ,11))
1648 			{
1649 
1650 				aiVector3D vTemp;
1651 				unsigned int iIndex;
1652 				ParseLV4MeshFloatTriple(&vTemp.x,iIndex);
1653 
1654 				if (iIndex >= iNumVertices)
1655 				{
1656 					LogWarning("Invalid vertex index. It will be ignored");
1657 				}
1658 				else mesh.mPositions[iIndex] = vTemp;
1659 				continue;
1660 			}
1661 		}
1662 		AI_ASE_HANDLE_SECTION("3","*MESH_VERTEX_LIST");
1663 	}
1664 	return;
1665 }
1666 // ------------------------------------------------------------------------------------------------
ParseLV3MeshFaceListBlock(unsigned int iNumFaces,ASE::Mesh & mesh)1667 void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh)
1668 {
1669 	AI_ASE_PARSER_INIT();
1670 
1671 	// allocate enough storage in the face array
1672 	mesh.mFaces.resize(iNumFaces);
1673 	while (true)
1674 	{
1675 		if ('*' == *filePtr)
1676 		{
1677 			++filePtr;
1678 
1679 			// Face entry
1680 			if (TokenMatch(filePtr,"MESH_FACE" ,9))
1681 			{
1682 
1683 				ASE::Face mFace;
1684 				ParseLV4MeshFace(mFace);
1685 
1686 				if (mFace.iFace >= iNumFaces)
1687 				{
1688 					LogWarning("Face has an invalid index. It will be ignored");
1689 				}
1690 				else mesh.mFaces[mFace.iFace] = mFace;
1691 				continue;
1692 			}
1693 		}
1694 		AI_ASE_HANDLE_SECTION("3","*MESH_FACE_LIST");
1695 	}
1696 	return;
1697 }
1698 // ------------------------------------------------------------------------------------------------
ParseLV3MeshTListBlock(unsigned int iNumVertices,ASE::Mesh & mesh,unsigned int iChannel)1699 void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
1700 	ASE::Mesh& mesh, unsigned int iChannel)
1701 {
1702 	AI_ASE_PARSER_INIT();
1703 
1704 	// allocate enough storage in the array
1705 	mesh.amTexCoords[iChannel].resize(iNumVertices);
1706 	while (true)
1707 	{
1708 		if ('*' == *filePtr)
1709 		{
1710 			++filePtr;
1711 
1712 			// Vertex entry
1713 			if (TokenMatch(filePtr,"MESH_TVERT" ,10))
1714 			{
1715 				aiVector3D vTemp;
1716 				unsigned int iIndex;
1717 				ParseLV4MeshFloatTriple(&vTemp.x,iIndex);
1718 
1719 				if (iIndex >= iNumVertices)
1720 				{
1721 					LogWarning("Tvertex has an invalid index. It will be ignored");
1722 				}
1723 				else mesh.amTexCoords[iChannel][iIndex] = vTemp;
1724 
1725 				if (0.0f != vTemp.z)
1726 				{
1727 					// we need 3 coordinate channels
1728 					mesh.mNumUVComponents[iChannel] = 3;
1729 				}
1730 				continue;
1731 			}
1732 		}
1733 		AI_ASE_HANDLE_SECTION("3","*MESH_TVERT_LIST");
1734 	}
1735 	return;
1736 }
1737 // ------------------------------------------------------------------------------------------------
ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,ASE::Mesh & mesh,unsigned int iChannel)1738 void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
1739 	ASE::Mesh& mesh, unsigned int iChannel)
1740 {
1741 	AI_ASE_PARSER_INIT();
1742 	while (true)
1743 	{
1744 		if ('*' == *filePtr)
1745 		{
1746 			++filePtr;
1747 
1748 			// Face entry
1749 			if (TokenMatch(filePtr,"MESH_TFACE" ,10))
1750 			{
1751 				unsigned int aiValues[3];
1752 				unsigned int iIndex = 0;
1753 
1754 				ParseLV4MeshLongTriple(aiValues,iIndex);
1755 				if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size())
1756 				{
1757 					LogWarning("UV-Face has an invalid index. It will be ignored");
1758 				}
1759 				else
1760 				{
1761 					// copy UV indices
1762 					mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0];
1763 					mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1];
1764 					mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2];
1765 				}
1766 				continue;
1767 			}
1768 		}
1769 		AI_ASE_HANDLE_SECTION("3","*MESH_TFACE_LIST");
1770 	}
1771 	return;
1772 }
1773 // ------------------------------------------------------------------------------------------------
ParseLV3MappingChannel(unsigned int iChannel,ASE::Mesh & mesh)1774 void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh& mesh)
1775 {
1776 	AI_ASE_PARSER_INIT();
1777 
1778 	unsigned int iNumTVertices = 0;
1779 	unsigned int iNumTFaces = 0;
1780 	while (true)
1781 	{
1782 		if ('*' == *filePtr)
1783 		{
1784 			++filePtr;
1785 
1786 			// Number of texture coordinates in the mesh
1787 			if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15))
1788 			{
1789 				ParseLV4MeshLong(iNumTVertices);
1790 				continue;
1791 			}
1792 			// Number of UVWed faces in the mesh
1793 			if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15))
1794 			{
1795 				ParseLV4MeshLong(iNumTFaces);
1796 				continue;
1797 			}
1798 			// mesh texture vertex list block
1799 			if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14))
1800 			{
1801 				ParseLV3MeshTListBlock(iNumTVertices,mesh,iChannel);
1802 				continue;
1803 			}
1804 			// mesh texture face block
1805 			if (TokenMatch(filePtr,"MESH_TFACELIST" ,14))
1806 			{
1807 				ParseLV3MeshTFaceListBlock(iNumTFaces,mesh, iChannel);
1808 				continue;
1809 			}
1810 		}
1811 		AI_ASE_HANDLE_SECTION("3","*MESH_MAPPING_CHANNEL");
1812 	}
1813 	return;
1814 }
1815 // ------------------------------------------------------------------------------------------------
ParseLV3MeshCListBlock(unsigned int iNumVertices,ASE::Mesh & mesh)1816 void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh& mesh)
1817 {
1818 	AI_ASE_PARSER_INIT();
1819 
1820 	// allocate enough storage in the array
1821 	mesh.mVertexColors.resize(iNumVertices);
1822 	while (true)
1823 	{
1824 		if ('*' == *filePtr)
1825 		{
1826 			++filePtr;
1827 
1828 			// Vertex entry
1829 			if (TokenMatch(filePtr,"MESH_VERTCOL" ,12))
1830 			{
1831 				aiColor4D vTemp;
1832 				vTemp.a = 1.0f;
1833 				unsigned int iIndex;
1834 				ParseLV4MeshFloatTriple(&vTemp.r,iIndex);
1835 
1836 				if (iIndex >= iNumVertices)
1837 				{
1838 					LogWarning("Vertex color has an invalid index. It will be ignored");
1839 				}
1840 				else mesh.mVertexColors[iIndex] = vTemp;
1841 				continue;
1842 			}
1843 		}
1844 		AI_ASE_HANDLE_SECTION("3","*MESH_CVERTEX_LIST");
1845 	}
1846 	return;
1847 }
1848 // ------------------------------------------------------------------------------------------------
ParseLV3MeshCFaceListBlock(unsigned int iNumFaces,ASE::Mesh & mesh)1849 void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh)
1850 {
1851 	AI_ASE_PARSER_INIT();
1852 	while (true)
1853 	{
1854 		if ('*' == *filePtr)
1855 		{
1856 			++filePtr;
1857 
1858 			// Face entry
1859 			if (TokenMatch(filePtr,"MESH_CFACE" ,11))
1860 			{
1861 				unsigned int aiValues[3];
1862 				unsigned int iIndex = 0;
1863 
1864 				ParseLV4MeshLongTriple(aiValues,iIndex);
1865 				if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size())
1866 				{
1867 					LogWarning("UV-Face has an invalid index. It will be ignored");
1868 				}
1869 				else
1870 				{
1871 					// copy color indices
1872 					mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0];
1873 					mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1];
1874 					mesh.mFaces[iIndex].mColorIndices[2] = aiValues[2];
1875 				}
1876 				continue;
1877 			}
1878 		}
1879 		AI_ASE_HANDLE_SECTION("3","*MESH_CFACE_LIST");
1880 	}
1881 	return;
1882 }
1883 // ------------------------------------------------------------------------------------------------
ParseLV3MeshNormalListBlock(ASE::Mesh & sMesh)1884 void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
1885 {
1886 	AI_ASE_PARSER_INIT();
1887 
1888 	// Allocate enough storage for the normals
1889 	sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f ));
1890 	unsigned int index, faceIdx = UINT_MAX;
1891 
1892 	// FIXME: rewrite this and find out how to interpret the normals
1893 	// correctly. This is crap.
1894 
1895 	// Smooth the vertex and face normals together. The result
1896 	// will be edgy then, but otherwise everything would be soft ...
1897 	while (true)	{
1898 		if ('*' == *filePtr)	{
1899 			++filePtr;
1900 			if (faceIdx != UINT_MAX && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17))	{
1901 				aiVector3D vNormal;
1902 				ParseLV4MeshFloatTriple(&vNormal.x,index);
1903 				if (faceIdx >=  sMesh.mFaces.size())
1904 					continue;
1905 
1906 				// Make sure we assign it to the correct face
1907 				const ASE::Face& face = sMesh.mFaces[faceIdx];
1908 				if (index == face.mIndices[0])
1909 					index = 0;
1910 				else if (index == face.mIndices[1])
1911 					index = 1;
1912 				else if (index == face.mIndices[2])
1913 					index = 2;
1914 				else	{
1915 					DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
1916 					continue;
1917 				}
1918 				// We'll renormalize later
1919 				sMesh.mNormals[faceIdx*3+index] += vNormal;
1920 				continue;
1921 			}
1922 			if (TokenMatch(filePtr,"MESH_FACENORMAL",15))	{
1923 				aiVector3D vNormal;
1924 				ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
1925 
1926 				if (faceIdx >= sMesh.mFaces.size())	{
1927 					DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section");
1928 					continue;
1929 				}
1930 
1931 				// We'll renormalize later
1932 				sMesh.mNormals[faceIdx*3] += vNormal;
1933 				sMesh.mNormals[faceIdx*3+1] += vNormal;
1934 				sMesh.mNormals[faceIdx*3+2] += vNormal;
1935 				continue;
1936 			}
1937 		}
1938 		AI_ASE_HANDLE_SECTION("3","*MESH_NORMALS");
1939 	}
1940 	return;
1941 }
1942 // ------------------------------------------------------------------------------------------------
ParseLV4MeshFace(ASE::Face & out)1943 void Parser::ParseLV4MeshFace(ASE::Face& out)
1944 {
1945 	// skip spaces and tabs
1946 	if(!SkipSpaces(&filePtr))
1947 	{
1948 		LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
1949 		SkipToNextToken();
1950 		return;
1951 	}
1952 
1953 	// parse the face index
1954 	out.iFace = strtoul10(filePtr,&filePtr);
1955 
1956 	// next character should be ':'
1957 	if(!SkipSpaces(&filePtr))
1958 	{
1959 		// FIX: there are some ASE files which haven't got : here ....
1960 		LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
1961 		SkipToNextToken();
1962 		return;
1963 	}
1964 	// FIX: There are some ASE files which haven't got ':' here
1965 	if(':' == *filePtr)++filePtr;
1966 
1967 	// Parse all mesh indices
1968 	for (unsigned int i = 0; i < 3;++i)
1969 	{
1970 		unsigned int iIndex = 0;
1971 		if(!SkipSpaces(&filePtr))
1972 		{
1973 			LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
1974 			SkipToNextToken();
1975 			return;
1976 		}
1977 		switch (*filePtr)
1978 		{
1979 		case 'A':
1980 		case 'a':
1981 			break;
1982 		case 'B':
1983 		case 'b':
1984 			iIndex = 1;
1985 			break;
1986 		case 'C':
1987 		case 'c':
1988 			iIndex = 2;
1989 			break;
1990 		default:
1991 			LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
1992 				"A,B or C expected [#3]");
1993 			SkipToNextToken();
1994 			return;
1995 		};
1996 		++filePtr;
1997 
1998 		// next character should be ':'
1999 		if(!SkipSpaces(&filePtr) || ':' != *filePtr)
2000 		{
2001 			LogWarning("Unable to parse *MESH_FACE Element: "
2002 				"Unexpected EOL. \':\' expected [#2]");
2003 			SkipToNextToken();
2004 			return;
2005 		}
2006 
2007 		++filePtr;
2008 		if(!SkipSpaces(&filePtr))
2009 		{
2010 			LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
2011 				"Vertex index ecpected [#4]");
2012 			SkipToNextToken();
2013 			return;
2014 		}
2015 		out.mIndices[iIndex] = strtoul10(filePtr,&filePtr);
2016 	}
2017 
2018 	// now we need to skip the AB, BC, CA blocks.
2019 	while (true)
2020 	{
2021 		if ('*' == *filePtr)break;
2022 		if (IsLineEnd(*filePtr))
2023 		{
2024 			//iLineNumber++;
2025 			return;
2026 		}
2027 		filePtr++;
2028 	}
2029 
2030 	// parse the smoothing group of the face
2031 	if (TokenMatch(filePtr,"*MESH_SMOOTHING",15))
2032 	{
2033 		if(!SkipSpaces(&filePtr))
2034 		{
2035 			LogWarning("Unable to parse *MESH_SMOOTHING Element: "
2036 				"Unexpected EOL. Smoothing group(s) expected [#5]");
2037 			SkipToNextToken();
2038 			return;
2039 		}
2040 
2041 		// Parse smoothing groups until we don't anymore see commas
2042 		// FIX: There needn't always be a value, sad but true
2043 		while (true)
2044 		{
2045 			if (*filePtr < '9' && *filePtr >= '0')
2046 			{
2047 				out.iSmoothGroup |= (1 << strtoul10(filePtr,&filePtr));
2048 			}
2049 			SkipSpaces(&filePtr);
2050 			if (',' != *filePtr)
2051 			{
2052 				break;
2053 			}
2054 			++filePtr;
2055 			SkipSpaces(&filePtr);
2056 		}
2057 	}
2058 
2059 	// *MESH_MTLID  is optional, too
2060 	while (true)
2061 	{
2062 		if ('*' == *filePtr)break;
2063 		if (IsLineEnd(*filePtr))
2064 		{
2065 			return;
2066 		}
2067 		filePtr++;
2068 	}
2069 
2070 	if (TokenMatch(filePtr,"*MESH_MTLID",11))
2071 	{
2072 		if(!SkipSpaces(&filePtr))
2073 		{
2074 			LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
2075 				"Material index expected [#6]");
2076 			SkipToNextToken();
2077 			return;
2078 		}
2079 		out.iMaterial = strtoul10(filePtr,&filePtr);
2080 	}
2081 	return;
2082 }
2083 // ------------------------------------------------------------------------------------------------
ParseLV4MeshLongTriple(unsigned int * apOut)2084 void Parser::ParseLV4MeshLongTriple(unsigned int* apOut)
2085 {
2086 	ai_assert(NULL != apOut);
2087 
2088 	for (unsigned int i = 0; i < 3;++i)
2089 		ParseLV4MeshLong(apOut[i]);
2090 }
2091 // ------------------------------------------------------------------------------------------------
ParseLV4MeshLongTriple(unsigned int * apOut,unsigned int & rIndexOut)2092 void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut)
2093 {
2094 	ai_assert(NULL != apOut);
2095 
2096 	// parse the index
2097 	ParseLV4MeshLong(rIndexOut);
2098 
2099 	// parse the three others
2100 	ParseLV4MeshLongTriple(apOut);
2101 }
2102 // ------------------------------------------------------------------------------------------------
ParseLV4MeshFloatTriple(float * apOut,unsigned int & rIndexOut)2103 void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut)
2104 {
2105 	ai_assert(NULL != apOut);
2106 
2107 	// parse the index
2108 	ParseLV4MeshLong(rIndexOut);
2109 
2110 	// parse the three others
2111 	ParseLV4MeshFloatTriple(apOut);
2112 }
2113 // ------------------------------------------------------------------------------------------------
ParseLV4MeshFloatTriple(float * apOut)2114 void Parser::ParseLV4MeshFloatTriple(float* apOut)
2115 {
2116 	ai_assert(NULL != apOut);
2117 
2118 	for (unsigned int i = 0; i < 3;++i)
2119 		ParseLV4MeshFloat(apOut[i]);
2120 }
2121 // ------------------------------------------------------------------------------------------------
ParseLV4MeshFloat(float & fOut)2122 void Parser::ParseLV4MeshFloat(float& fOut)
2123 {
2124 	// skip spaces and tabs
2125 	if(!SkipSpaces(&filePtr))
2126 	{
2127 		// LOG
2128 		LogWarning("Unable to parse float: unexpected EOL [#1]");
2129 		fOut = 0.0f;
2130 		++iLineNumber;
2131 		return;
2132 	}
2133 	// parse the first float
2134 	filePtr = fast_atoreal_move<float>(filePtr,fOut);
2135 }
2136 // ------------------------------------------------------------------------------------------------
ParseLV4MeshLong(unsigned int & iOut)2137 void Parser::ParseLV4MeshLong(unsigned int& iOut)
2138 {
2139 	// Skip spaces and tabs
2140 	if(!SkipSpaces(&filePtr))
2141 	{
2142 		// LOG
2143 		LogWarning("Unable to parse long: unexpected EOL [#1]");
2144 		iOut = 0;
2145 		++iLineNumber;
2146 		return;
2147 	}
2148 	// parse the value
2149 	iOut = strtoul10(filePtr,&filePtr);
2150 }
2151