1 | /* |
2 | --------------------------------------------------------------------------- |
3 | Open Asset Import Library (assimp) |
4 | --------------------------------------------------------------------------- |
5 | |
6 | Copyright (c) 2006-2017, assimp team |
7 | |
8 | |
9 | All rights reserved. |
10 | |
11 | Redistribution and use of this software in source and binary forms, |
12 | with or without modification, are permitted provided that the following |
13 | conditions 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 |
31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
39 | OF 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 | |
57 | using namespace Assimp; |
58 | using 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 | // ------------------------------------------------------------------------------------------------ |
121 | Parser::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 | // ------------------------------------------------------------------------------------------------ |
141 | void 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 | // ------------------------------------------------------------------------------------------------ |
157 | void 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 | // ------------------------------------------------------------------------------------------------ |
173 | AI_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 | // ------------------------------------------------------------------------------------------------ |
189 | bool 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 | // ------------------------------------------------------------------------------------------------ |
210 | bool 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 | // ------------------------------------------------------------------------------------------------ |
242 | void 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 | // ------------------------------------------------------------------------------------------------ |
342 | void 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 | // ------------------------------------------------------------------------------------------------ |
467 | void 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 | // ------------------------------------------------------------------------------------------------ |
515 | void 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 | // ------------------------------------------------------------------------------------------------ |
557 | void 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 | // ------------------------------------------------------------------------------------------------ |
737 | void 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 | // ------------------------------------------------------------------------------------------------ |
824 | bool 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 | // ------------------------------------------------------------------------------------------------ |
864 | void 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 | // ------------------------------------------------------------------------------------------------ |
984 | void 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 | // ------------------------------------------------------------------------------------------------ |
1014 | void 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 | // ------------------------------------------------------------------------------------------------ |
1049 | void 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 | // ------------------------------------------------------------------------------------------------ |
1125 | void 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 | // ------------------------------------------------------------------------------------------------ |
1172 | void 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 | // ------------------------------------------------------------------------------------------------ |
1218 | void 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 | // ------------------------------------------------------------------------------------------------ |
1267 | void 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 | // ------------------------------------------------------------------------------------------------ |
1374 | void 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 | // ------------------------------------------------------------------------------------------------ |
1512 | void 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 | // ------------------------------------------------------------------------------------------------ |
1553 | void 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 | // ------------------------------------------------------------------------------------------------ |
1585 | void 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 | // ------------------------------------------------------------------------------------------------ |
1636 | void 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 | // ------------------------------------------------------------------------------------------------ |
1670 | void 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 | // ------------------------------------------------------------------------------------------------ |
1702 | void 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 | // ------------------------------------------------------------------------------------------------ |
1741 | void 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 | // ------------------------------------------------------------------------------------------------ |
1777 | void 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 | // ------------------------------------------------------------------------------------------------ |
1819 | void 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 | // ------------------------------------------------------------------------------------------------ |
1852 | void 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 | // ------------------------------------------------------------------------------------------------ |
1887 | void 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 | // ------------------------------------------------------------------------------------------------ |
1946 | void 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 | // ------------------------------------------------------------------------------------------------ |
2087 | void 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 | // ------------------------------------------------------------------------------------------------ |
2095 | void 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 | // ------------------------------------------------------------------------------------------------ |
2106 | void 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 | // ------------------------------------------------------------------------------------------------ |
2117 | void 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 | // ------------------------------------------------------------------------------------------------ |
2125 | void 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 | // ------------------------------------------------------------------------------------------------ |
2140 | void 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 | |