nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file ASEParser.cpp nuclear@0: * @brief Implementation of the ASE parser class nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER nuclear@0: nuclear@0: // internal headers nuclear@0: #include "TextureTransform.h" nuclear@0: #include "ASELoader.h" nuclear@0: #include "MaterialSystem.h" nuclear@0: #include "fast_atof.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: using namespace Assimp::ASE; nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Begin an ASE parsing function nuclear@0: nuclear@0: #define AI_ASE_PARSER_INIT() \ nuclear@0: int iDepth = 0; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Handle a "top-level" section in the file. EOF is no error in this case. nuclear@0: nuclear@0: #define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \ nuclear@0: else if ('{' == *filePtr)iDepth++; \ nuclear@0: else if ('}' == *filePtr) \ nuclear@0: { \ nuclear@0: if (0 == --iDepth) \ nuclear@0: { \ nuclear@0: ++filePtr; \ nuclear@0: SkipToNextToken(); \ nuclear@0: return; \ nuclear@0: } \ nuclear@0: } \ nuclear@0: else if ('\0' == *filePtr) \ nuclear@0: { \ nuclear@0: return; \ nuclear@0: } \ nuclear@0: if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ nuclear@0: { \ nuclear@0: ++iLineNumber; \ nuclear@0: bLastWasEndLine = true; \ nuclear@0: } else bLastWasEndLine = false; \ nuclear@0: ++filePtr; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Handle a nested section in the file. EOF is an error in this case nuclear@0: // @param level "Depth" of the section nuclear@0: // @param msg Full name of the section (including the asterisk) nuclear@0: nuclear@0: #define AI_ASE_HANDLE_SECTION(level, msg) \ nuclear@0: if ('{' == *filePtr)iDepth++; \ nuclear@0: else if ('}' == *filePtr) \ nuclear@0: { \ nuclear@0: if (0 == --iDepth) \ nuclear@0: { \ nuclear@0: ++filePtr; \ nuclear@0: SkipToNextToken(); \ nuclear@0: return; \ nuclear@0: } \ nuclear@0: } \ nuclear@0: else if ('\0' == *filePtr) \ nuclear@0: { \ nuclear@0: LogError("Encountered unexpected EOL while parsing a " msg \ nuclear@0: " chunk (Level " level ")"); \ nuclear@0: } \ nuclear@0: if(IsLineEnd(*filePtr) && !bLastWasEndLine) \ nuclear@0: { \ nuclear@0: ++iLineNumber; \ nuclear@0: bLastWasEndLine = true; \ nuclear@0: } else bLastWasEndLine = false; \ nuclear@0: ++filePtr; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: Parser::Parser (const char* szFile, unsigned int fileFormatDefault) nuclear@0: { nuclear@0: ai_assert(NULL != szFile); nuclear@0: filePtr = szFile; nuclear@0: iFileFormat = fileFormatDefault; nuclear@0: nuclear@0: // make sure that the color values are invalid nuclear@0: m_clrBackground.r = get_qnan(); nuclear@0: m_clrAmbient.r = get_qnan(); nuclear@0: nuclear@0: // setup some default values nuclear@0: iLineNumber = 0; nuclear@0: iFirstFrame = 0; nuclear@0: iLastFrame = 0; nuclear@0: iFrameSpeed = 30; // use 30 as default value for this property nuclear@0: iTicksPerFrame = 1; // use 1 as default value for this property nuclear@0: bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::LogWarning(const char* szWarn) nuclear@0: { nuclear@0: ai_assert(NULL != szWarn); nuclear@0: nuclear@0: char szTemp[1024]; nuclear@0: #if _MSC_VER >= 1400 nuclear@0: sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn); nuclear@0: #else nuclear@0: snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn); nuclear@0: #endif nuclear@0: nuclear@0: // output the warning to the logger ... nuclear@0: DefaultLogger::get()->warn(szTemp); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::LogInfo(const char* szWarn) nuclear@0: { nuclear@0: ai_assert(NULL != szWarn); nuclear@0: nuclear@0: char szTemp[1024]; nuclear@0: #if _MSC_VER >= 1400 nuclear@0: sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn); nuclear@0: #else nuclear@0: snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn); nuclear@0: #endif nuclear@0: nuclear@0: // output the information to the logger ... nuclear@0: DefaultLogger::get()->info(szTemp); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::LogError(const char* szWarn) nuclear@0: { nuclear@0: ai_assert(NULL != szWarn); nuclear@0: nuclear@0: char szTemp[1024]; nuclear@0: #if _MSC_VER >= 1400 nuclear@0: sprintf_s(szTemp,"Line %i: %s",iLineNumber,szWarn); nuclear@0: #else nuclear@0: snprintf(szTemp,1024,"Line %i: %s",iLineNumber,szWarn); nuclear@0: #endif nuclear@0: nuclear@0: // throw an exception nuclear@0: throw DeadlyImportError(szTemp); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool Parser::SkipToNextToken() nuclear@0: { nuclear@0: while (true) nuclear@0: { nuclear@0: char me = *filePtr; nuclear@0: nuclear@0: // increase the line number counter if necessary nuclear@0: if (IsLineEnd(me) && !bLastWasEndLine) nuclear@0: { nuclear@0: ++iLineNumber; nuclear@0: bLastWasEndLine = true; nuclear@0: } nuclear@0: else bLastWasEndLine = false; nuclear@0: if ('*' == me || '}' == me || '{' == me)return true; nuclear@0: if ('\0' == me)return false; nuclear@0: nuclear@0: ++filePtr; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool Parser::SkipSection() nuclear@0: { nuclear@0: // must handle subsections ... nuclear@0: int iCnt = 0; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('}' == *filePtr) nuclear@0: { nuclear@0: --iCnt; nuclear@0: if (0 == iCnt) nuclear@0: { nuclear@0: // go to the next valid token ... nuclear@0: ++filePtr; nuclear@0: SkipToNextToken(); nuclear@0: return true; nuclear@0: } nuclear@0: } nuclear@0: else if ('{' == *filePtr) nuclear@0: { nuclear@0: ++iCnt; nuclear@0: } nuclear@0: else if ('\0' == *filePtr) nuclear@0: { nuclear@0: LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]"); nuclear@0: return false; nuclear@0: } nuclear@0: else if(IsLineEnd(*filePtr))++iLineNumber; nuclear@0: ++filePtr; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::Parse() nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Version should be 200. Validate this ... nuclear@0: if (TokenMatch(filePtr,"3DSMAX_ASCIIEXPORT",18)) nuclear@0: { nuclear@0: unsigned int fmt; nuclear@0: ParseLV4MeshLong(fmt); nuclear@0: nuclear@0: if (fmt > 200) nuclear@0: { nuclear@0: LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \ nuclear@0: be <= 200"); nuclear@0: } nuclear@0: // ************************************************************* nuclear@0: // - fmt will be 0 if we're unable to read the version number nuclear@0: // there are some faulty files without a version number ... nuclear@0: // in this case we'll guess the exact file format by looking nuclear@0: // at the file extension (ASE, ASK, ASC) nuclear@0: // ************************************************************* nuclear@0: nuclear@0: if (fmt)iFileFormat = fmt; nuclear@0: continue; nuclear@0: } nuclear@0: // main scene information nuclear@0: if (TokenMatch(filePtr,"SCENE",5)) nuclear@0: { nuclear@0: ParseLV1SceneBlock(); nuclear@0: continue; nuclear@0: } nuclear@0: // "group" - no implementation yet, in facte nuclear@0: // we're just ignoring them for the moment nuclear@0: if (TokenMatch(filePtr,"GROUP",5)) nuclear@0: { nuclear@0: Parse(); nuclear@0: continue; nuclear@0: } nuclear@0: // material list nuclear@0: if (TokenMatch(filePtr,"MATERIAL_LIST",13)) nuclear@0: { nuclear@0: ParseLV1MaterialListBlock(); nuclear@0: continue; nuclear@0: } nuclear@0: // geometric object (mesh) nuclear@0: if (TokenMatch(filePtr,"GEOMOBJECT",10)) nuclear@0: nuclear@0: { nuclear@0: m_vMeshes.push_back(Mesh()); nuclear@0: ParseLV1ObjectBlock(m_vMeshes.back()); nuclear@0: continue; nuclear@0: } nuclear@0: // helper object = dummy in the hierarchy nuclear@0: if (TokenMatch(filePtr,"HELPEROBJECT",12)) nuclear@0: nuclear@0: { nuclear@0: m_vDummies.push_back(Dummy()); nuclear@0: ParseLV1ObjectBlock(m_vDummies.back()); nuclear@0: continue; nuclear@0: } nuclear@0: // light object nuclear@0: if (TokenMatch(filePtr,"LIGHTOBJECT",11)) nuclear@0: nuclear@0: { nuclear@0: m_vLights.push_back(Light()); nuclear@0: ParseLV1ObjectBlock(m_vLights.back()); nuclear@0: continue; nuclear@0: } nuclear@0: // camera object nuclear@0: if (TokenMatch(filePtr,"CAMERAOBJECT",12)) nuclear@0: { nuclear@0: m_vCameras.push_back(Camera()); nuclear@0: ParseLV1ObjectBlock(m_vCameras.back()); nuclear@0: continue; nuclear@0: } nuclear@0: // comment - print it on the console nuclear@0: if (TokenMatch(filePtr,"COMMENT",7)) nuclear@0: { nuclear@0: std::string out = ""; nuclear@0: ParseString(out,"*COMMENT"); nuclear@0: LogInfo(("Comment: " + out).c_str()); nuclear@0: continue; nuclear@0: } nuclear@0: // ASC bone weights nuclear@0: if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(filePtr,"MESH_SOFTSKINVERTS",18)) nuclear@0: { nuclear@0: ParseLV1SoftSkinBlock(); nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_TOP_LEVEL_SECTION(); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV1SoftSkinBlock() nuclear@0: { nuclear@0: // TODO: fix line counting here nuclear@0: nuclear@0: // ************************************************************** nuclear@0: // The soft skin block is formatted differently. There are no nuclear@0: // nested sections supported and the single elements aren't nuclear@0: // marked by keywords starting with an asterisk. nuclear@0: nuclear@0: /** nuclear@0: FORMAT BEGIN nuclear@0: nuclear@0: *MESH_SOFTSKINVERTS { nuclear@0: nuclear@0: nuclear@0: nuclear@0: [for times:] nuclear@0: [for times:] nuclear@0: } nuclear@0: nuclear@0: FORMAT END nuclear@0: */ nuclear@0: // ************************************************************** nuclear@0: while (true) nuclear@0: { nuclear@0: if (*filePtr == '}' ) {++filePtr;return;} nuclear@0: else if (*filePtr == '\0') return; nuclear@0: else if (*filePtr == '{' ) ++filePtr; nuclear@0: nuclear@0: else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr)) nuclear@0: { nuclear@0: ASE::Mesh* curMesh = NULL; nuclear@0: unsigned int numVerts = 0; nuclear@0: nuclear@0: const char* sz = filePtr; nuclear@0: while (!IsSpaceOrNewLine(*filePtr))++filePtr; nuclear@0: nuclear@0: const unsigned int diff = (unsigned int)(filePtr-sz); nuclear@0: if (diff) nuclear@0: { nuclear@0: std::string name = std::string(sz,diff); nuclear@0: for (std::vector::iterator it = m_vMeshes.begin(); nuclear@0: it != m_vMeshes.end(); ++it) nuclear@0: { nuclear@0: if ((*it).mName == name) nuclear@0: { nuclear@0: curMesh = & (*it); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: if (!curMesh) nuclear@0: { nuclear@0: LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section"); nuclear@0: nuclear@0: // Skip the mesh data - until we find a new mesh nuclear@0: // or the end of the *MESH_SOFTSKINVERTS section nuclear@0: while (true) nuclear@0: { nuclear@0: SkipSpacesAndLineEnd(&filePtr); nuclear@0: if (*filePtr == '}') nuclear@0: {++filePtr;return;} nuclear@0: else if (!IsNumeric(*filePtr)) nuclear@0: break; nuclear@0: nuclear@0: SkipLine(&filePtr); nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: SkipSpacesAndLineEnd(&filePtr); nuclear@0: ParseLV4MeshLong(numVerts); nuclear@0: nuclear@0: // Reserve enough storage nuclear@0: curMesh->mBoneVertices.reserve(numVerts); nuclear@0: nuclear@0: for (unsigned int i = 0; i < numVerts;++i) nuclear@0: { nuclear@0: SkipSpacesAndLineEnd(&filePtr); nuclear@0: unsigned int numWeights; nuclear@0: ParseLV4MeshLong(numWeights); nuclear@0: nuclear@0: curMesh->mBoneVertices.push_back(ASE::BoneVertex()); nuclear@0: ASE::BoneVertex& vert = curMesh->mBoneVertices.back(); nuclear@0: nuclear@0: // Reserve enough storage nuclear@0: vert.mBoneWeights.reserve(numWeights); nuclear@0: nuclear@0: for (unsigned int w = 0; w < numWeights;++w) nuclear@0: { nuclear@0: std::string bone; nuclear@0: ParseString(bone,"*MESH_SOFTSKINVERTS.Bone"); nuclear@0: nuclear@0: // Find the bone in the mesh's list nuclear@0: std::pair me; nuclear@0: me.first = -1; nuclear@0: nuclear@0: for (unsigned int n = 0; n < curMesh->mBones.size();++n) nuclear@0: { nuclear@0: if (curMesh->mBones[n].mName == bone) nuclear@0: { nuclear@0: me.first = n; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: if (-1 == me.first) nuclear@0: { nuclear@0: // We don't have this bone yet, so add it to the list nuclear@0: me.first = (int)curMesh->mBones.size(); nuclear@0: curMesh->mBones.push_back(ASE::Bone(bone)); nuclear@0: } nuclear@0: ParseLV4MeshFloat( me.second ); nuclear@0: nuclear@0: // Add the new bone weight to list nuclear@0: vert.mBoneWeights.push_back(me); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: ++filePtr; nuclear@0: SkipSpacesAndLineEnd(&filePtr); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV1SceneBlock() nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: if (TokenMatch(filePtr,"SCENE_BACKGROUND_STATIC",23)) nuclear@0: nuclear@0: { nuclear@0: // parse a color triple and assume it is really the bg color nuclear@0: ParseLV4MeshFloatTriple( &m_clrBackground.r ); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"SCENE_AMBIENT_STATIC",20)) nuclear@0: nuclear@0: { nuclear@0: // parse a color triple and assume it is really the bg color nuclear@0: ParseLV4MeshFloatTriple( &m_clrAmbient.r ); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"SCENE_FIRSTFRAME",16)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iFirstFrame); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"SCENE_LASTFRAME",15)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iLastFrame); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"SCENE_FRAMESPEED",16)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iFrameSpeed); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"SCENE_TICKSPERFRAME",19)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iTicksPerFrame); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_TOP_LEVEL_SECTION(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV1MaterialListBlock() nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: unsigned int iMaterialCount = 0; nuclear@0: unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: if (TokenMatch(filePtr,"MATERIAL_COUNT",14)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iMaterialCount); nuclear@0: nuclear@0: // now allocate enough storage to hold all materials nuclear@0: m_vMaterials.resize(iOldMaterialCount+iMaterialCount); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"MATERIAL",8)) nuclear@0: { nuclear@0: unsigned int iIndex = 0; nuclear@0: ParseLV4MeshLong(iIndex); nuclear@0: nuclear@0: if (iIndex >= iMaterialCount) nuclear@0: { nuclear@0: LogWarning("Out of range: material index is too large"); nuclear@0: iIndex = iMaterialCount-1; nuclear@0: } nuclear@0: nuclear@0: // get a reference to the material nuclear@0: Material& sMat = m_vMaterials[iIndex+iOldMaterialCount]; nuclear@0: // parse the material block nuclear@0: ParseLV2MaterialBlock(sMat); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_TOP_LEVEL_SECTION(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV2MaterialBlock(ASE::Material& mat) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: unsigned int iNumSubMaterials = 0; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: if (TokenMatch(filePtr,"MATERIAL_NAME",13)) nuclear@0: { nuclear@0: if (!ParseString(mat.mName,"*MATERIAL_NAME")) nuclear@0: SkipToNextToken(); nuclear@0: continue; nuclear@0: } nuclear@0: // ambient material color nuclear@0: if (TokenMatch(filePtr,"MATERIAL_AMBIENT",16)) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple(&mat.mAmbient.r); nuclear@0: continue; nuclear@0: } nuclear@0: // diffuse material color nuclear@0: if (TokenMatch(filePtr,"MATERIAL_DIFFUSE",16) ) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple(&mat.mDiffuse.r); nuclear@0: continue; nuclear@0: } nuclear@0: // specular material color nuclear@0: if (TokenMatch(filePtr,"MATERIAL_SPECULAR",17)) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple(&mat.mSpecular.r); nuclear@0: continue; nuclear@0: } nuclear@0: // material shading type nuclear@0: if (TokenMatch(filePtr,"MATERIAL_SHADING",16)) nuclear@0: { nuclear@0: if (TokenMatch(filePtr,"Blinn",5)) nuclear@0: { nuclear@0: mat.mShading = Discreet3DS::Blinn; nuclear@0: } nuclear@0: else if (TokenMatch(filePtr,"Phong",5)) nuclear@0: { nuclear@0: mat.mShading = Discreet3DS::Phong; nuclear@0: } nuclear@0: else if (TokenMatch(filePtr,"Flat",4)) nuclear@0: { nuclear@0: mat.mShading = Discreet3DS::Flat; nuclear@0: } nuclear@0: else if (TokenMatch(filePtr,"Wire",4)) nuclear@0: { nuclear@0: mat.mShading = Discreet3DS::Wire; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // assume gouraud shading nuclear@0: mat.mShading = Discreet3DS::Gouraud; nuclear@0: SkipToNextToken(); nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: // material transparency nuclear@0: if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(mat.mTransparency); nuclear@0: mat.mTransparency = 1.0f - mat.mTransparency;continue; nuclear@0: } nuclear@0: // material self illumination nuclear@0: if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18)) nuclear@0: { nuclear@0: float f = 0.0f; nuclear@0: ParseLV4MeshFloat(f); nuclear@0: nuclear@0: mat.mEmissive.r = f; nuclear@0: mat.mEmissive.g = f; nuclear@0: mat.mEmissive.b = f; nuclear@0: continue; nuclear@0: } nuclear@0: // material shininess nuclear@0: if (TokenMatch(filePtr,"MATERIAL_SHINE",14) ) nuclear@0: { nuclear@0: ParseLV4MeshFloat(mat.mSpecularExponent); nuclear@0: mat.mSpecularExponent *= 15; nuclear@0: continue; nuclear@0: } nuclear@0: // two-sided material nuclear@0: if (TokenMatch(filePtr,"MATERIAL_TWOSIDED",17) ) nuclear@0: { nuclear@0: mat.mTwoSided = true; nuclear@0: continue; nuclear@0: } nuclear@0: // material shininess strength nuclear@0: if (TokenMatch(filePtr,"MATERIAL_SHINESTRENGTH",22)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(mat.mShininessStrength); nuclear@0: continue; nuclear@0: } nuclear@0: // diffuse color map nuclear@0: if (TokenMatch(filePtr,"MAP_DIFFUSE",11)) nuclear@0: { nuclear@0: // parse the texture block nuclear@0: ParseLV3MapBlock(mat.sTexDiffuse); nuclear@0: continue; nuclear@0: } nuclear@0: // ambient color map nuclear@0: if (TokenMatch(filePtr,"MAP_AMBIENT",11)) nuclear@0: { nuclear@0: // parse the texture block nuclear@0: ParseLV3MapBlock(mat.sTexAmbient); nuclear@0: continue; nuclear@0: } nuclear@0: // specular color map nuclear@0: if (TokenMatch(filePtr,"MAP_SPECULAR",12)) nuclear@0: { nuclear@0: // parse the texture block nuclear@0: ParseLV3MapBlock(mat.sTexSpecular); nuclear@0: continue; nuclear@0: } nuclear@0: // opacity map nuclear@0: if (TokenMatch(filePtr,"MAP_OPACITY",11)) nuclear@0: { nuclear@0: // parse the texture block nuclear@0: ParseLV3MapBlock(mat.sTexOpacity); nuclear@0: continue; nuclear@0: } nuclear@0: // emissive map nuclear@0: if (TokenMatch(filePtr,"MAP_SELFILLUM",13)) nuclear@0: { nuclear@0: // parse the texture block nuclear@0: ParseLV3MapBlock(mat.sTexEmissive); nuclear@0: continue; nuclear@0: } nuclear@0: // bump map nuclear@0: if (TokenMatch(filePtr,"MAP_BUMP",8)) nuclear@0: { nuclear@0: // parse the texture block nuclear@0: ParseLV3MapBlock(mat.sTexBump); nuclear@0: } nuclear@0: // specular/shininess map nuclear@0: if (TokenMatch(filePtr,"MAP_SHINESTRENGTH",17)) nuclear@0: { nuclear@0: // parse the texture block nuclear@0: ParseLV3MapBlock(mat.sTexShininess); nuclear@0: continue; nuclear@0: } nuclear@0: // number of submaterials nuclear@0: if (TokenMatch(filePtr,"NUMSUBMTLS",10)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumSubMaterials); nuclear@0: nuclear@0: // allocate enough storage nuclear@0: mat.avSubMaterials.resize(iNumSubMaterials); nuclear@0: } nuclear@0: // submaterial chunks nuclear@0: if (TokenMatch(filePtr,"SUBMATERIAL",11)) nuclear@0: { nuclear@0: nuclear@0: unsigned int iIndex = 0; nuclear@0: ParseLV4MeshLong(iIndex); nuclear@0: nuclear@0: if (iIndex >= iNumSubMaterials) nuclear@0: { nuclear@0: LogWarning("Out of range: submaterial index is too large"); nuclear@0: iIndex = iNumSubMaterials-1; nuclear@0: } nuclear@0: nuclear@0: // get a reference to the material nuclear@0: Material& sMat = mat.avSubMaterials[iIndex]; nuclear@0: nuclear@0: // parse the material block nuclear@0: ParseLV2MaterialBlock(sMat); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("2","*MATERIAL"); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MapBlock(Texture& map) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: // *********************************************************** nuclear@0: // *BITMAP should not be there if *MAP_CLASS is not BITMAP, nuclear@0: // but we need to expect that case ... if the path is nuclear@0: // empty the texture won't be used later. nuclear@0: // *********************************************************** nuclear@0: bool parsePath = true; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: // type of map nuclear@0: if (TokenMatch(filePtr,"MAP_CLASS" ,9)) nuclear@0: { nuclear@0: std::string temp; nuclear@0: if(!ParseString(temp,"*MAP_CLASS")) nuclear@0: SkipToNextToken(); nuclear@0: if (temp != "Bitmap" && temp != "Normal Bump") nuclear@0: { nuclear@0: DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp); nuclear@0: parsePath = false; nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: // path to the texture nuclear@0: if (parsePath && TokenMatch(filePtr,"BITMAP" ,6)) nuclear@0: { nuclear@0: if(!ParseString(map.mMapName,"*BITMAP")) nuclear@0: SkipToNextToken(); nuclear@0: nuclear@0: if (map.mMapName == "None") nuclear@0: { nuclear@0: // Files with 'None' as map name are produced by nuclear@0: // an Maja to ASE exporter which name I forgot .. nuclear@0: DefaultLogger::get()->warn("ASE: Skipping invalid map entry"); nuclear@0: map.mMapName = ""; nuclear@0: } nuclear@0: nuclear@0: continue; nuclear@0: } nuclear@0: // offset on the u axis nuclear@0: if (TokenMatch(filePtr,"UVW_U_OFFSET" ,12)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(map.mOffsetU); nuclear@0: continue; nuclear@0: } nuclear@0: // offset on the v axis nuclear@0: if (TokenMatch(filePtr,"UVW_V_OFFSET" ,12)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(map.mOffsetV); nuclear@0: continue; nuclear@0: } nuclear@0: // tiling on the u axis nuclear@0: if (TokenMatch(filePtr,"UVW_U_TILING" ,12)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(map.mScaleU); nuclear@0: continue; nuclear@0: } nuclear@0: // tiling on the v axis nuclear@0: if (TokenMatch(filePtr,"UVW_V_TILING" ,12)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(map.mScaleV); nuclear@0: continue; nuclear@0: } nuclear@0: // rotation around the z-axis nuclear@0: if (TokenMatch(filePtr,"UVW_ANGLE" ,9)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(map.mRotation); nuclear@0: continue; nuclear@0: } nuclear@0: // map blending factor nuclear@0: if (TokenMatch(filePtr,"MAP_AMOUNT" ,10)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(map.mTextureBlend); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MAP_XXXXXX"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool Parser::ParseString(std::string& out,const char* szName) nuclear@0: { nuclear@0: char szBuffer[1024]; nuclear@0: if (!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: nuclear@0: sprintf(szBuffer,"Unable to parse %s block: Unexpected EOL",szName); nuclear@0: LogWarning(szBuffer); nuclear@0: return false; nuclear@0: } nuclear@0: // there must be '"' nuclear@0: if ('\"' != *filePtr) nuclear@0: { nuclear@0: nuclear@0: sprintf(szBuffer,"Unable to parse %s block: Strings are expected " nuclear@0: "to be enclosed in double quotation marks",szName); nuclear@0: LogWarning(szBuffer); nuclear@0: return false; nuclear@0: } nuclear@0: ++filePtr; nuclear@0: const char* sz = filePtr; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('\"' == *sz)break; nuclear@0: else if ('\0' == *sz) nuclear@0: { nuclear@0: sprintf(szBuffer,"Unable to parse %s block: Strings are expected to " nuclear@0: "be enclosed in double quotation marks but EOF was reached before " nuclear@0: "a closing quotation mark was encountered",szName); nuclear@0: LogWarning(szBuffer); nuclear@0: return false; nuclear@0: } nuclear@0: sz++; nuclear@0: } nuclear@0: out = std::string(filePtr,(uintptr_t)sz-(uintptr_t)filePtr); nuclear@0: filePtr = sz+1; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV1ObjectBlock(ASE::BaseNode& node) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // first process common tokens such as node name and transform nuclear@0: // name of the mesh/node nuclear@0: if (TokenMatch(filePtr,"NODE_NAME" ,9)) nuclear@0: { nuclear@0: if(!ParseString(node.mName,"*NODE_NAME")) nuclear@0: SkipToNextToken(); nuclear@0: continue; nuclear@0: } nuclear@0: // name of the parent of the node nuclear@0: if (TokenMatch(filePtr,"NODE_PARENT" ,11) ) nuclear@0: { nuclear@0: if(!ParseString(node.mParent,"*NODE_PARENT")) nuclear@0: SkipToNextToken(); nuclear@0: continue; nuclear@0: } nuclear@0: // transformation matrix of the node nuclear@0: if (TokenMatch(filePtr,"NODE_TM" ,7)) nuclear@0: { nuclear@0: ParseLV2NodeTransformBlock(node); nuclear@0: continue; nuclear@0: } nuclear@0: // animation data of the node nuclear@0: if (TokenMatch(filePtr,"TM_ANIMATION" ,12)) nuclear@0: { nuclear@0: ParseLV2AnimationBlock(node); nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: if (node.mType == BaseNode::Light) nuclear@0: { nuclear@0: // light settings nuclear@0: if (TokenMatch(filePtr,"LIGHT_SETTINGS" ,14)) nuclear@0: { nuclear@0: ParseLV2LightSettingsBlock((ASE::Light&)node); nuclear@0: continue; nuclear@0: } nuclear@0: // type of the light source nuclear@0: if (TokenMatch(filePtr,"LIGHT_TYPE" ,10)) nuclear@0: { nuclear@0: if (!ASSIMP_strincmp("omni",filePtr,4)) nuclear@0: { nuclear@0: ((ASE::Light&)node).mLightType = ASE::Light::OMNI; nuclear@0: } nuclear@0: else if (!ASSIMP_strincmp("target",filePtr,6)) nuclear@0: { nuclear@0: ((ASE::Light&)node).mLightType = ASE::Light::TARGET; nuclear@0: } nuclear@0: else if (!ASSIMP_strincmp("free",filePtr,4)) nuclear@0: { nuclear@0: ((ASE::Light&)node).mLightType = ASE::Light::FREE; nuclear@0: } nuclear@0: else if (!ASSIMP_strincmp("directional",filePtr,11)) nuclear@0: { nuclear@0: ((ASE::Light&)node).mLightType = ASE::Light::DIRECTIONAL; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: LogWarning("Unknown kind of light source"); nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: else if (node.mType == BaseNode::Camera) nuclear@0: { nuclear@0: // Camera settings nuclear@0: if (TokenMatch(filePtr,"CAMERA_SETTINGS" ,15)) nuclear@0: { nuclear@0: ParseLV2CameraSettingsBlock((ASE::Camera&)node); nuclear@0: continue; nuclear@0: } nuclear@0: else if (TokenMatch(filePtr,"CAMERA_TYPE" ,11)) nuclear@0: { nuclear@0: if (!ASSIMP_strincmp("target",filePtr,6)) nuclear@0: { nuclear@0: ((ASE::Camera&)node).mCameraType = ASE::Camera::TARGET; nuclear@0: } nuclear@0: else if (!ASSIMP_strincmp("free",filePtr,4)) nuclear@0: { nuclear@0: ((ASE::Camera&)node).mCameraType = ASE::Camera::FREE; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: LogWarning("Unknown kind of camera"); nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: else if (node.mType == BaseNode::Mesh) nuclear@0: { nuclear@0: // mesh data nuclear@0: // FIX: Older files use MESH_SOFTSKIN nuclear@0: if (TokenMatch(filePtr,"MESH" ,4) || nuclear@0: TokenMatch(filePtr,"MESH_SOFTSKIN",13)) nuclear@0: { nuclear@0: ParseLV2MeshBlock((ASE::Mesh&)node); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh material index nuclear@0: if (TokenMatch(filePtr,"MATERIAL_REF" ,12)) nuclear@0: { nuclear@0: ParseLV4MeshLong(((ASE::Mesh&)node).iMaterialIndex); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_TOP_LEVEL_SECTION(); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV2CameraSettingsBlock(ASE::Camera& camera) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: if (TokenMatch(filePtr,"CAMERA_NEAR" ,11)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(camera.mNear); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"CAMERA_FAR" ,10)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(camera.mFar); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"CAMERA_FOV" ,10)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(camera.mFOV); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("2","CAMERA_SETTINGS"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV2LightSettingsBlock(ASE::Light& light) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: if (TokenMatch(filePtr,"LIGHT_COLOR" ,11)) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple(&light.mColor.r); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"LIGHT_INTENS" ,12)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(light.mIntensity); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"LIGHT_HOTSPOT" ,13)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(light.mAngle); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"LIGHT_FALLOFF" ,13)) nuclear@0: { nuclear@0: ParseLV4MeshFloat(light.mFalloff); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("2","LIGHT_SETTINGS"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: ASE::Animation* anim = &mesh.mAnim; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: if (TokenMatch(filePtr,"NODE_NAME" ,9)) nuclear@0: { nuclear@0: std::string temp; nuclear@0: if(!ParseString(temp,"*NODE_NAME")) nuclear@0: SkipToNextToken(); nuclear@0: nuclear@0: // If the name of the node contains .target it nuclear@0: // represents an animated camera or spot light nuclear@0: // target. nuclear@0: if (std::string::npos != temp.find(".Target")) nuclear@0: { nuclear@0: if ((mesh.mType != BaseNode::Camera || ((ASE::Camera&)mesh).mCameraType != ASE::Camera::TARGET) && nuclear@0: ( mesh.mType != BaseNode::Light || ((ASE::Light&)mesh).mLightType != ASE::Light::TARGET)) nuclear@0: { nuclear@0: nuclear@0: DefaultLogger::get()->error("ASE: Found target animation channel " nuclear@0: "but the node is neither a camera nor a spot light"); nuclear@0: anim = NULL; nuclear@0: } nuclear@0: else anim = &mesh.mTargetAnim; nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: // position keyframes nuclear@0: if (TokenMatch(filePtr,"CONTROL_POS_TRACK" ,17) || nuclear@0: TokenMatch(filePtr,"CONTROL_POS_BEZIER" ,18) || nuclear@0: TokenMatch(filePtr,"CONTROL_POS_TCB" ,15)) nuclear@0: { nuclear@0: if (!anim)SkipSection(); nuclear@0: else ParseLV3PosAnimationBlock(*anim); nuclear@0: continue; nuclear@0: } nuclear@0: // scaling keyframes nuclear@0: if (TokenMatch(filePtr,"CONTROL_SCALE_TRACK" ,19) || nuclear@0: TokenMatch(filePtr,"CONTROL_SCALE_BEZIER" ,20) || nuclear@0: TokenMatch(filePtr,"CONTROL_SCALE_TCB" ,17)) nuclear@0: { nuclear@0: if (!anim || anim == &mesh.mTargetAnim) nuclear@0: { nuclear@0: // Target animation channels may have no rotation channels nuclear@0: DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation"); nuclear@0: SkipSection(); nuclear@0: } nuclear@0: else ParseLV3ScaleAnimationBlock(*anim); nuclear@0: continue; nuclear@0: } nuclear@0: // rotation keyframes nuclear@0: if (TokenMatch(filePtr,"CONTROL_ROT_TRACK" ,17) || nuclear@0: TokenMatch(filePtr,"CONTROL_ROT_BEZIER" ,18) || nuclear@0: TokenMatch(filePtr,"CONTROL_ROT_TCB" ,15)) nuclear@0: { nuclear@0: if (!anim || anim == &mesh.mTargetAnim) nuclear@0: { nuclear@0: // Target animation channels may have no rotation channels nuclear@0: DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation"); nuclear@0: SkipSection(); nuclear@0: } nuclear@0: else ParseLV3RotAnimationBlock(*anim); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("2","TM_ANIMATION"); nuclear@0: } nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation& anim) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: unsigned int iIndex; nuclear@0: nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: bool b = false; nuclear@0: nuclear@0: // For the moment we're just reading the three floats - nuclear@0: // we ignore the ádditional information for bezier's and TCBs nuclear@0: nuclear@0: // simple scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_SCALE_SAMPLE" ,20)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mScalingType = ASE::Animation::TRACK; nuclear@0: } nuclear@0: nuclear@0: // Bezier scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_BEZIER_SCALE_KEY" ,24)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mScalingType = ASE::Animation::BEZIER; nuclear@0: } nuclear@0: // TCB scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_TCB_SCALE_KEY" ,21)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mScalingType = ASE::Animation::TCB; nuclear@0: } nuclear@0: if (b) nuclear@0: { nuclear@0: anim.akeyScaling.push_back(aiVectorKey()); nuclear@0: aiVectorKey& key = anim.akeyScaling.back(); nuclear@0: ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); nuclear@0: key.mTime = (double)iIndex; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); nuclear@0: } nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3PosAnimationBlock(ASE::Animation& anim) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: unsigned int iIndex; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: bool b = false; nuclear@0: nuclear@0: // For the moment we're just reading the three floats - nuclear@0: // we ignore the ádditional information for bezier's and TCBs nuclear@0: nuclear@0: // simple scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_POS_SAMPLE" ,18)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mPositionType = ASE::Animation::TRACK; nuclear@0: } nuclear@0: nuclear@0: // Bezier scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_BEZIER_POS_KEY" ,22)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mPositionType = ASE::Animation::BEZIER; nuclear@0: } nuclear@0: // TCB scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_TCB_POS_KEY" ,19)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mPositionType = ASE::Animation::TCB; nuclear@0: } nuclear@0: if (b) nuclear@0: { nuclear@0: anim.akeyPositions.push_back(aiVectorKey()); nuclear@0: aiVectorKey& key = anim.akeyPositions.back(); nuclear@0: ParseLV4MeshFloatTriple(&key.mValue.x,iIndex); nuclear@0: key.mTime = (double)iIndex; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*CONTROL_POS_TRACK"); nuclear@0: } nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3RotAnimationBlock(ASE::Animation& anim) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: unsigned int iIndex; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: bool b = false; nuclear@0: nuclear@0: // For the moment we're just reading the floats - nuclear@0: // we ignore the ádditional information for bezier's and TCBs nuclear@0: nuclear@0: // simple scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_ROT_SAMPLE" ,18)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mRotationType = ASE::Animation::TRACK; nuclear@0: } nuclear@0: nuclear@0: // Bezier scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_BEZIER_ROT_KEY" ,22)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mRotationType = ASE::Animation::BEZIER; nuclear@0: } nuclear@0: // TCB scaling keyframe nuclear@0: if (TokenMatch(filePtr,"CONTROL_TCB_ROT_KEY" ,19)) nuclear@0: { nuclear@0: b = true; nuclear@0: anim.mRotationType = ASE::Animation::TCB; nuclear@0: } nuclear@0: if (b) nuclear@0: { nuclear@0: anim.akeyRotations.push_back(aiQuatKey()); nuclear@0: aiQuatKey& key = anim.akeyRotations.back(); nuclear@0: aiVector3D v;float f; nuclear@0: ParseLV4MeshFloatTriple(&v.x,iIndex); nuclear@0: ParseLV4MeshFloat(f); nuclear@0: key.mTime = (double)iIndex; nuclear@0: key.mValue = aiQuaternion(v,f); nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*CONTROL_ROT_TRACK"); nuclear@0: } nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: int mode = 0; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: // name of the node nuclear@0: if (TokenMatch(filePtr,"NODE_NAME" ,9)) nuclear@0: { nuclear@0: std::string temp; nuclear@0: if(!ParseString(temp,"*NODE_NAME")) nuclear@0: SkipToNextToken(); nuclear@0: nuclear@0: std::string::size_type s; nuclear@0: if (temp == mesh.mName) nuclear@0: { nuclear@0: mode = 1; nuclear@0: } nuclear@0: else if (std::string::npos != (s = temp.find(".Target")) && nuclear@0: mesh.mName == temp.substr(0,s)) nuclear@0: { nuclear@0: // This should be either a target light or a target camera nuclear@0: if ( (mesh.mType == BaseNode::Light && ((ASE::Light&)mesh) .mLightType == ASE::Light::TARGET) || nuclear@0: (mesh.mType == BaseNode::Camera && ((ASE::Camera&)mesh).mCameraType == ASE::Camera::TARGET)) nuclear@0: { nuclear@0: mode = 2; nuclear@0: } nuclear@0: else DefaultLogger::get()->error("ASE: Ignoring target transform, " nuclear@0: "this is no spot light or target camera"); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp); nuclear@0: // mode = 0 nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: if (mode) nuclear@0: { nuclear@0: // fourth row of the transformation matrix - and also the nuclear@0: // only information here that is interesting for targets nuclear@0: if (TokenMatch(filePtr,"TM_ROW3" ,7)) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x)); nuclear@0: continue; nuclear@0: } nuclear@0: if (mode == 1) nuclear@0: { nuclear@0: // first row of the transformation matrix nuclear@0: if (TokenMatch(filePtr,"TM_ROW0" ,7)) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple(mesh.mTransform[0]); nuclear@0: continue; nuclear@0: } nuclear@0: // second row of the transformation matrix nuclear@0: if (TokenMatch(filePtr,"TM_ROW1" ,7)) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple(mesh.mTransform[1]); nuclear@0: continue; nuclear@0: } nuclear@0: // third row of the transformation matrix nuclear@0: if (TokenMatch(filePtr,"TM_ROW2" ,7)) nuclear@0: { nuclear@0: ParseLV4MeshFloatTriple(mesh.mTransform[2]); nuclear@0: continue; nuclear@0: } nuclear@0: // inherited position axes nuclear@0: if (TokenMatch(filePtr,"INHERIT_POS" ,11)) nuclear@0: { nuclear@0: unsigned int aiVal[3]; nuclear@0: ParseLV4MeshLongTriple(aiVal); nuclear@0: nuclear@0: for (unsigned int i = 0; i < 3;++i) nuclear@0: mesh.inherit.abInheritPosition[i] = aiVal[i] != 0; nuclear@0: continue; nuclear@0: } nuclear@0: // inherited rotation axes nuclear@0: if (TokenMatch(filePtr,"INHERIT_ROT" ,11)) nuclear@0: { nuclear@0: unsigned int aiVal[3]; nuclear@0: ParseLV4MeshLongTriple(aiVal); nuclear@0: nuclear@0: for (unsigned int i = 0; i < 3;++i) nuclear@0: mesh.inherit.abInheritRotation[i] = aiVal[i] != 0; nuclear@0: continue; nuclear@0: } nuclear@0: // inherited scaling axes nuclear@0: if (TokenMatch(filePtr,"INHERIT_SCL" ,11)) nuclear@0: { nuclear@0: unsigned int aiVal[3]; nuclear@0: ParseLV4MeshLongTriple(aiVal); nuclear@0: nuclear@0: for (unsigned int i = 0; i < 3;++i) nuclear@0: mesh.inherit.abInheritScaling[i] = aiVal[i] != 0; nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("2","*NODE_TM"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV2MeshBlock(ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: unsigned int iNumVertices = 0; nuclear@0: unsigned int iNumFaces = 0; nuclear@0: unsigned int iNumTVertices = 0; nuclear@0: unsigned int iNumTFaces = 0; nuclear@0: unsigned int iNumCVertices = 0; nuclear@0: unsigned int iNumCFaces = 0; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: // Number of vertices in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumVertices); nuclear@0: continue; nuclear@0: } nuclear@0: // Number of texture coordinates in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumTVertices); nuclear@0: continue; nuclear@0: } nuclear@0: // Number of vertex colors in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMCVERTEX" ,15)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumCVertices); nuclear@0: continue; nuclear@0: } nuclear@0: // Number of regular faces in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMFACES" ,13)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumFaces); nuclear@0: continue; nuclear@0: } nuclear@0: // Number of UVWed faces in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumTFaces); nuclear@0: continue; nuclear@0: } nuclear@0: // Number of colored faces in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMCVFACES" ,15)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumCFaces); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh vertex list block nuclear@0: if (TokenMatch(filePtr,"MESH_VERTEX_LIST" ,16)) nuclear@0: { nuclear@0: ParseLV3MeshVertexListBlock(iNumVertices,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh face list block nuclear@0: if (TokenMatch(filePtr,"MESH_FACE_LIST" ,14)) nuclear@0: { nuclear@0: ParseLV3MeshFaceListBlock(iNumFaces,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh texture vertex list block nuclear@0: if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) nuclear@0: { nuclear@0: ParseLV3MeshTListBlock(iNumTVertices,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh texture face block nuclear@0: if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) nuclear@0: { nuclear@0: ParseLV3MeshTFaceListBlock(iNumTFaces,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh color vertex list block nuclear@0: if (TokenMatch(filePtr,"MESH_CVERTLIST" ,14)) nuclear@0: { nuclear@0: ParseLV3MeshCListBlock(iNumCVertices,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh color face block nuclear@0: if (TokenMatch(filePtr,"MESH_CFACELIST" ,14)) nuclear@0: { nuclear@0: ParseLV3MeshCFaceListBlock(iNumCFaces,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh normals nuclear@0: if (TokenMatch(filePtr,"MESH_NORMALS" ,12)) nuclear@0: { nuclear@0: ParseLV3MeshNormalListBlock(mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // another mesh UV channel ... nuclear@0: if (TokenMatch(filePtr,"MESH_MAPPINGCHANNEL" ,19)) nuclear@0: { nuclear@0: nuclear@0: unsigned int iIndex = 0; nuclear@0: ParseLV4MeshLong(iIndex); nuclear@0: nuclear@0: if (iIndex < 2) nuclear@0: { nuclear@0: LogWarning("Mapping channel has an invalid index. Skipping UV channel"); nuclear@0: // skip it ... nuclear@0: SkipSection(); nuclear@0: } nuclear@0: if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) nuclear@0: { nuclear@0: LogWarning("Too many UV channels specified. Skipping channel .."); nuclear@0: // skip it ... nuclear@0: SkipSection(); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // parse the mapping channel nuclear@0: ParseLV3MappingChannel(iIndex-1,mesh); nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: // mesh animation keyframe. Not supported nuclear@0: if (TokenMatch(filePtr,"MESH_ANIMATION" ,14)) nuclear@0: { nuclear@0: nuclear@0: LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. " nuclear@0: "Keyframe animation is not supported by Assimp, this element " nuclear@0: "will be ignored"); nuclear@0: //SkipSection(); nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"MESH_WEIGHTS" ,12)) nuclear@0: { nuclear@0: ParseLV3MeshWeightsBlock(mesh);continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("2","*MESH"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: unsigned int iNumVertices = 0, iNumBones = 0; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Number of bone vertices ... nuclear@0: if (TokenMatch(filePtr,"MESH_NUMVERTEX" ,14)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumVertices); nuclear@0: continue; nuclear@0: } nuclear@0: // Number of bones nuclear@0: if (TokenMatch(filePtr,"MESH_NUMBONE" ,11)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumBones); nuclear@0: continue; nuclear@0: } nuclear@0: // parse the list of bones nuclear@0: if (TokenMatch(filePtr,"MESH_BONE_LIST" ,14)) nuclear@0: { nuclear@0: ParseLV4MeshBones(iNumBones,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: // parse the list of bones vertices nuclear@0: if (TokenMatch(filePtr,"MESH_BONE_VERTEX_LIST" ,21) ) nuclear@0: { nuclear@0: ParseLV4MeshBonesVertices(iNumVertices,mesh); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_WEIGHTS"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: mesh.mBones.resize(iNumBones); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Mesh bone with name ... nuclear@0: if (TokenMatch(filePtr,"MESH_BONE_NAME" ,16)) nuclear@0: { nuclear@0: // parse an index ... nuclear@0: if(SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: unsigned int iIndex = strtoul10(filePtr,&filePtr); nuclear@0: if (iIndex >= iNumBones) nuclear@0: { nuclear@0: LogWarning("Bone index is out of bounds"); nuclear@0: continue; nuclear@0: } nuclear@0: if (!ParseString(mesh.mBones[iIndex].mName,"*MESH_BONE_NAME")) nuclear@0: SkipToNextToken(); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_BONE_LIST"); nuclear@0: } nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices,ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: mesh.mBoneVertices.resize(iNumVertices); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Mesh bone vertex nuclear@0: if (TokenMatch(filePtr,"MESH_BONE_VERTEX" ,16)) nuclear@0: { nuclear@0: // read the vertex index nuclear@0: unsigned int iIndex = strtoul10(filePtr,&filePtr); nuclear@0: if (iIndex >= mesh.mPositions.size()) nuclear@0: { nuclear@0: iIndex = (unsigned int)mesh.mPositions.size()-1; nuclear@0: LogWarning("Bone vertex index is out of bounds. Using the largest valid " nuclear@0: "bone vertex index instead"); nuclear@0: } nuclear@0: nuclear@0: // --- ignored nuclear@0: float afVert[3]; nuclear@0: ParseLV4MeshFloatTriple(afVert); nuclear@0: nuclear@0: std::pair pairOut; nuclear@0: while (true) nuclear@0: { nuclear@0: // first parse the bone index ... nuclear@0: if (!SkipSpaces(&filePtr))break; nuclear@0: pairOut.first = strtoul10(filePtr,&filePtr); nuclear@0: nuclear@0: // then parse the vertex weight nuclear@0: if (!SkipSpaces(&filePtr))break; nuclear@0: filePtr = fast_atoreal_move(filePtr,pairOut.second); nuclear@0: nuclear@0: // -1 marks unused entries nuclear@0: if (-1 != pairOut.first) nuclear@0: { nuclear@0: mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut); nuclear@0: } nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("4","*MESH_BONE_VERTEX"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshVertexListBlock( nuclear@0: unsigned int iNumVertices, ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: // allocate enough storage in the array nuclear@0: mesh.mPositions.resize(iNumVertices); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Vertex entry nuclear@0: if (TokenMatch(filePtr,"MESH_VERTEX" ,11)) nuclear@0: { nuclear@0: nuclear@0: aiVector3D vTemp; nuclear@0: unsigned int iIndex; nuclear@0: ParseLV4MeshFloatTriple(&vTemp.x,iIndex); nuclear@0: nuclear@0: if (iIndex >= iNumVertices) nuclear@0: { nuclear@0: LogWarning("Invalid vertex index. It will be ignored"); nuclear@0: } nuclear@0: else mesh.mPositions[iIndex] = vTemp; nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_VERTEX_LIST"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: // allocate enough storage in the face array nuclear@0: mesh.mFaces.resize(iNumFaces); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Face entry nuclear@0: if (TokenMatch(filePtr,"MESH_FACE" ,9)) nuclear@0: { nuclear@0: nuclear@0: ASE::Face mFace; nuclear@0: ParseLV4MeshFace(mFace); nuclear@0: nuclear@0: if (mFace.iFace >= iNumFaces) nuclear@0: { nuclear@0: LogWarning("Face has an invalid index. It will be ignored"); nuclear@0: } nuclear@0: else mesh.mFaces[mFace.iFace] = mFace; nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_FACE_LIST"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices, nuclear@0: ASE::Mesh& mesh, unsigned int iChannel) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: // allocate enough storage in the array nuclear@0: mesh.amTexCoords[iChannel].resize(iNumVertices); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Vertex entry nuclear@0: if (TokenMatch(filePtr,"MESH_TVERT" ,10)) nuclear@0: { nuclear@0: aiVector3D vTemp; nuclear@0: unsigned int iIndex; nuclear@0: ParseLV4MeshFloatTriple(&vTemp.x,iIndex); nuclear@0: nuclear@0: if (iIndex >= iNumVertices) nuclear@0: { nuclear@0: LogWarning("Tvertex has an invalid index. It will be ignored"); nuclear@0: } nuclear@0: else mesh.amTexCoords[iChannel][iIndex] = vTemp; nuclear@0: nuclear@0: if (0.0f != vTemp.z) nuclear@0: { nuclear@0: // we need 3 coordinate channels nuclear@0: mesh.mNumUVComponents[iChannel] = 3; nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_TVERT_LIST"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces, nuclear@0: ASE::Mesh& mesh, unsigned int iChannel) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Face entry nuclear@0: if (TokenMatch(filePtr,"MESH_TFACE" ,10)) nuclear@0: { nuclear@0: unsigned int aiValues[3]; nuclear@0: unsigned int iIndex = 0; nuclear@0: nuclear@0: ParseLV4MeshLongTriple(aiValues,iIndex); nuclear@0: if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) nuclear@0: { nuclear@0: LogWarning("UV-Face has an invalid index. It will be ignored"); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // copy UV indices nuclear@0: mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0]; nuclear@0: mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1]; nuclear@0: mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2]; nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_TFACE_LIST"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: unsigned int iNumTVertices = 0; nuclear@0: unsigned int iNumTFaces = 0; nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Number of texture coordinates in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMTVERTEX" ,15)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumTVertices); nuclear@0: continue; nuclear@0: } nuclear@0: // Number of UVWed faces in the mesh nuclear@0: if (TokenMatch(filePtr,"MESH_NUMTVFACES" ,15)) nuclear@0: { nuclear@0: ParseLV4MeshLong(iNumTFaces); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh texture vertex list block nuclear@0: if (TokenMatch(filePtr,"MESH_TVERTLIST" ,14)) nuclear@0: { nuclear@0: ParseLV3MeshTListBlock(iNumTVertices,mesh,iChannel); nuclear@0: continue; nuclear@0: } nuclear@0: // mesh texture face block nuclear@0: if (TokenMatch(filePtr,"MESH_TFACELIST" ,14)) nuclear@0: { nuclear@0: ParseLV3MeshTFaceListBlock(iNumTFaces,mesh, iChannel); nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_MAPPING_CHANNEL"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: // allocate enough storage in the array nuclear@0: mesh.mVertexColors.resize(iNumVertices); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Vertex entry nuclear@0: if (TokenMatch(filePtr,"MESH_VERTCOL" ,12)) nuclear@0: { nuclear@0: aiColor4D vTemp; nuclear@0: vTemp.a = 1.0f; nuclear@0: unsigned int iIndex; nuclear@0: ParseLV4MeshFloatTriple(&vTemp.r,iIndex); nuclear@0: nuclear@0: if (iIndex >= iNumVertices) nuclear@0: { nuclear@0: LogWarning("Vertex color has an invalid index. It will be ignored"); nuclear@0: } nuclear@0: else mesh.mVertexColors[iIndex] = vTemp; nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_CVERTEX_LIST"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh& mesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr) nuclear@0: { nuclear@0: ++filePtr; nuclear@0: nuclear@0: // Face entry nuclear@0: if (TokenMatch(filePtr,"MESH_CFACE" ,11)) nuclear@0: { nuclear@0: unsigned int aiValues[3]; nuclear@0: unsigned int iIndex = 0; nuclear@0: nuclear@0: ParseLV4MeshLongTriple(aiValues,iIndex); nuclear@0: if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) nuclear@0: { nuclear@0: LogWarning("UV-Face has an invalid index. It will be ignored"); nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // copy color indices nuclear@0: mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0]; nuclear@0: mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1]; nuclear@0: mesh.mFaces[iIndex].mColorIndices[2] = aiValues[2]; nuclear@0: } nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_CFACE_LIST"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh) nuclear@0: { nuclear@0: AI_ASE_PARSER_INIT(); nuclear@0: nuclear@0: // Allocate enough storage for the normals nuclear@0: sMesh.mNormals.resize(sMesh.mFaces.size()*3,aiVector3D( 0.f, 0.f, 0.f )); nuclear@0: unsigned int index, faceIdx = UINT_MAX; nuclear@0: nuclear@0: // FIXME: rewrite this and find out how to interpret the normals nuclear@0: // correctly. This is crap. nuclear@0: nuclear@0: // Smooth the vertex and face normals together. The result nuclear@0: // will be edgy then, but otherwise everything would be soft ... nuclear@0: while (true) { nuclear@0: if ('*' == *filePtr) { nuclear@0: ++filePtr; nuclear@0: if (faceIdx != UINT_MAX && TokenMatch(filePtr,"MESH_VERTEXNORMAL",17)) { nuclear@0: aiVector3D vNormal; nuclear@0: ParseLV4MeshFloatTriple(&vNormal.x,index); nuclear@0: if (faceIdx >= sMesh.mFaces.size()) nuclear@0: continue; nuclear@0: nuclear@0: // Make sure we assign it to the correct face nuclear@0: const ASE::Face& face = sMesh.mFaces[faceIdx]; nuclear@0: if (index == face.mIndices[0]) nuclear@0: index = 0; nuclear@0: else if (index == face.mIndices[1]) nuclear@0: index = 1; nuclear@0: else if (index == face.mIndices[2]) nuclear@0: index = 2; nuclear@0: else { nuclear@0: DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); nuclear@0: continue; nuclear@0: } nuclear@0: // We'll renormalize later nuclear@0: sMesh.mNormals[faceIdx*3+index] += vNormal; nuclear@0: continue; nuclear@0: } nuclear@0: if (TokenMatch(filePtr,"MESH_FACENORMAL",15)) { nuclear@0: aiVector3D vNormal; nuclear@0: ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); nuclear@0: nuclear@0: if (faceIdx >= sMesh.mFaces.size()) { nuclear@0: DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section"); nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: // We'll renormalize later nuclear@0: sMesh.mNormals[faceIdx*3] += vNormal; nuclear@0: sMesh.mNormals[faceIdx*3+1] += vNormal; nuclear@0: sMesh.mNormals[faceIdx*3+2] += vNormal; nuclear@0: continue; nuclear@0: } nuclear@0: } nuclear@0: AI_ASE_HANDLE_SECTION("3","*MESH_NORMALS"); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshFace(ASE::Face& out) nuclear@0: { nuclear@0: // skip spaces and tabs nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // parse the face index nuclear@0: out.iFace = strtoul10(filePtr,&filePtr); nuclear@0: nuclear@0: // next character should be ':' nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: // FIX: there are some ASE files which haven't got : here .... nuclear@0: LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: } nuclear@0: // FIX: There are some ASE files which haven't got ':' here nuclear@0: if(':' == *filePtr)++filePtr; nuclear@0: nuclear@0: // Parse all mesh indices nuclear@0: for (unsigned int i = 0; i < 3;++i) nuclear@0: { nuclear@0: unsigned int iIndex = 0; nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: } nuclear@0: switch (*filePtr) nuclear@0: { nuclear@0: case 'A': nuclear@0: case 'a': nuclear@0: break; nuclear@0: case 'B': nuclear@0: case 'b': nuclear@0: iIndex = 1; nuclear@0: break; nuclear@0: case 'C': nuclear@0: case 'c': nuclear@0: iIndex = 2; nuclear@0: break; nuclear@0: default: nuclear@0: LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " nuclear@0: "A,B or C expected [#3]"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: }; nuclear@0: ++filePtr; nuclear@0: nuclear@0: // next character should be ':' nuclear@0: if(!SkipSpaces(&filePtr) || ':' != *filePtr) nuclear@0: { nuclear@0: LogWarning("Unable to parse *MESH_FACE Element: " nuclear@0: "Unexpected EOL. \':\' expected [#2]"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: ++filePtr; nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. " nuclear@0: "Vertex index ecpected [#4]"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: } nuclear@0: out.mIndices[iIndex] = strtoul10(filePtr,&filePtr); nuclear@0: } nuclear@0: nuclear@0: // now we need to skip the AB, BC, CA blocks. nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr)break; nuclear@0: if (IsLineEnd(*filePtr)) nuclear@0: { nuclear@0: //iLineNumber++; nuclear@0: return; nuclear@0: } nuclear@0: filePtr++; nuclear@0: } nuclear@0: nuclear@0: // parse the smoothing group of the face nuclear@0: if (TokenMatch(filePtr,"*MESH_SMOOTHING",15)) nuclear@0: { nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: LogWarning("Unable to parse *MESH_SMOOTHING Element: " nuclear@0: "Unexpected EOL. Smoothing group(s) expected [#5]"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // Parse smoothing groups until we don't anymore see commas nuclear@0: // FIX: There needn't always be a value, sad but true nuclear@0: while (true) nuclear@0: { nuclear@0: if (*filePtr < '9' && *filePtr >= '0') nuclear@0: { nuclear@0: out.iSmoothGroup |= (1 << strtoul10(filePtr,&filePtr)); nuclear@0: } nuclear@0: SkipSpaces(&filePtr); nuclear@0: if (',' != *filePtr) nuclear@0: { nuclear@0: break; nuclear@0: } nuclear@0: ++filePtr; nuclear@0: SkipSpaces(&filePtr); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // *MESH_MTLID is optional, too nuclear@0: while (true) nuclear@0: { nuclear@0: if ('*' == *filePtr)break; nuclear@0: if (IsLineEnd(*filePtr)) nuclear@0: { nuclear@0: return; nuclear@0: } nuclear@0: filePtr++; nuclear@0: } nuclear@0: nuclear@0: if (TokenMatch(filePtr,"*MESH_MTLID",11)) nuclear@0: { nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. " nuclear@0: "Material index expected [#6]"); nuclear@0: SkipToNextToken(); nuclear@0: return; nuclear@0: } nuclear@0: out.iMaterial = strtoul10(filePtr,&filePtr); nuclear@0: } nuclear@0: return; nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshLongTriple(unsigned int* apOut) nuclear@0: { nuclear@0: ai_assert(NULL != apOut); nuclear@0: nuclear@0: for (unsigned int i = 0; i < 3;++i) nuclear@0: ParseLV4MeshLong(apOut[i]); nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut) nuclear@0: { nuclear@0: ai_assert(NULL != apOut); nuclear@0: nuclear@0: // parse the index nuclear@0: ParseLV4MeshLong(rIndexOut); nuclear@0: nuclear@0: // parse the three others nuclear@0: ParseLV4MeshLongTriple(apOut); nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut) nuclear@0: { nuclear@0: ai_assert(NULL != apOut); nuclear@0: nuclear@0: // parse the index nuclear@0: ParseLV4MeshLong(rIndexOut); nuclear@0: nuclear@0: // parse the three others nuclear@0: ParseLV4MeshFloatTriple(apOut); nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshFloatTriple(float* apOut) nuclear@0: { nuclear@0: ai_assert(NULL != apOut); nuclear@0: nuclear@0: for (unsigned int i = 0; i < 3;++i) nuclear@0: ParseLV4MeshFloat(apOut[i]); nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshFloat(float& fOut) nuclear@0: { nuclear@0: // skip spaces and tabs nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: // LOG nuclear@0: LogWarning("Unable to parse float: unexpected EOL [#1]"); nuclear@0: fOut = 0.0f; nuclear@0: ++iLineNumber; nuclear@0: return; nuclear@0: } nuclear@0: // parse the first float nuclear@0: filePtr = fast_atoreal_move(filePtr,fOut); nuclear@0: } nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void Parser::ParseLV4MeshLong(unsigned int& iOut) nuclear@0: { nuclear@0: // Skip spaces and tabs nuclear@0: if(!SkipSpaces(&filePtr)) nuclear@0: { nuclear@0: // LOG nuclear@0: LogWarning("Unable to parse long: unexpected EOL [#1]"); nuclear@0: iOut = 0; nuclear@0: ++iLineNumber; nuclear@0: return; nuclear@0: } nuclear@0: // parse the value nuclear@0: iOut = strtoul10(filePtr,&filePtr); nuclear@0: } nuclear@0: nuclear@0: #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER