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