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