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 Implementation of the PLY parser class */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER nuclear@0: nuclear@0: #include "PlyLoader.h" nuclear@0: #include "fast_atof.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: PLY::EDataType PLY::Property::ParseDataType(const char* pCur,const char** pCurOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: PLY::EDataType eOut = PLY::EDT_INVALID; nuclear@0: nuclear@0: if (TokenMatch(pCur,"char",4) || nuclear@0: TokenMatch(pCur,"int8",4)) nuclear@0: { nuclear@0: eOut = PLY::EDT_Char; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"uchar",5) || nuclear@0: TokenMatch(pCur,"uint8",5)) nuclear@0: { nuclear@0: eOut = PLY::EDT_UChar; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"short",5) || nuclear@0: TokenMatch(pCur,"int16",5)) nuclear@0: { nuclear@0: eOut = PLY::EDT_Short; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"ushort",6) || nuclear@0: TokenMatch(pCur,"uint16",6)) nuclear@0: { nuclear@0: eOut = PLY::EDT_UShort; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"int32",5) || TokenMatch(pCur,"int",3)) nuclear@0: { nuclear@0: eOut = PLY::EDT_Int; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"uint32",6) || TokenMatch(pCur,"uint",4)) nuclear@0: { nuclear@0: eOut = PLY::EDT_UInt; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"float",5) || TokenMatch(pCur,"float32",7)) nuclear@0: { nuclear@0: eOut = PLY::EDT_Float; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"double64",8) || TokenMatch(pCur,"double",6) || nuclear@0: TokenMatch(pCur,"float64",7)) nuclear@0: { nuclear@0: eOut = PLY::EDT_Double; nuclear@0: } nuclear@0: if (PLY::EDT_INVALID == eOut) nuclear@0: { nuclear@0: DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK"); nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return eOut; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: nuclear@0: PLY::ESemantic eOut = PLY::EST_INVALID; nuclear@0: if (TokenMatch(pCur,"red",3)) nuclear@0: { nuclear@0: eOut = PLY::EST_Red; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"green",5)) nuclear@0: { nuclear@0: eOut = PLY::EST_Green; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"blue",4)) nuclear@0: { nuclear@0: eOut = PLY::EST_Blue; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"alpha",5)) nuclear@0: { nuclear@0: eOut = PLY::EST_Alpha; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"vertex_index",12) || TokenMatch(pCur,"vertex_indices",14)) nuclear@0: { nuclear@0: eOut = PLY::EST_VertexIndex; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"material_index",14)) nuclear@0: { nuclear@0: eOut = PLY::EST_MaterialIndex; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"ambient_red",11)) nuclear@0: { nuclear@0: eOut = PLY::EST_AmbientRed; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"ambient_green",13)) nuclear@0: { nuclear@0: eOut = PLY::EST_AmbientGreen; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"ambient_blue",12)) nuclear@0: { nuclear@0: eOut = PLY::EST_AmbientBlue; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"ambient_alpha",13)) nuclear@0: { nuclear@0: eOut = PLY::EST_AmbientAlpha; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"diffuse_red",11)) nuclear@0: { nuclear@0: eOut = PLY::EST_DiffuseRed; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"diffuse_green",13)) nuclear@0: { nuclear@0: eOut = PLY::EST_DiffuseGreen; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"diffuse_blue",12)) nuclear@0: { nuclear@0: eOut = PLY::EST_DiffuseBlue; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"diffuse_alpha",13)) nuclear@0: { nuclear@0: eOut = PLY::EST_DiffuseAlpha; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"specular_red",12)) nuclear@0: { nuclear@0: eOut = PLY::EST_SpecularRed; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"specular_green",14)) nuclear@0: { nuclear@0: eOut = PLY::EST_SpecularGreen; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"specular_blue",13)) nuclear@0: { nuclear@0: eOut = PLY::EST_SpecularBlue; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"specular_alpha",14)) nuclear@0: { nuclear@0: eOut = PLY::EST_SpecularAlpha; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"opacity",7)) nuclear@0: { nuclear@0: eOut = PLY::EST_Opacity; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"specular_power",6)) nuclear@0: { nuclear@0: eOut = PLY::EST_PhongPower; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"r",1)) nuclear@0: { nuclear@0: eOut = PLY::EST_Red; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"g",1)) nuclear@0: { nuclear@0: eOut = PLY::EST_Green; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"b",1)) nuclear@0: { nuclear@0: eOut = PLY::EST_Blue; nuclear@0: } nuclear@0: // NOTE: Blender3D exports texture coordinates as s,t tuples nuclear@0: else if (TokenMatch(pCur,"u",1) || TokenMatch(pCur,"s",1) || TokenMatch(pCur,"tx",2)) nuclear@0: { nuclear@0: eOut = PLY::EST_UTextureCoord; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"v",1) || TokenMatch(pCur,"t",1) || TokenMatch(pCur,"ty",2)) nuclear@0: { nuclear@0: eOut = PLY::EST_VTextureCoord; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"x",1)) nuclear@0: { nuclear@0: eOut = PLY::EST_XCoord; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"y",1)) nuclear@0: { nuclear@0: eOut = PLY::EST_YCoord; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"z",1)) nuclear@0: { nuclear@0: eOut = PLY::EST_ZCoord; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"nx",2)) nuclear@0: { nuclear@0: eOut = PLY::EST_XNormal; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"ny",2)) nuclear@0: { nuclear@0: eOut = PLY::EST_YNormal; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"nz",2)) nuclear@0: { nuclear@0: eOut = PLY::EST_ZNormal; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: DefaultLogger::get()->info("Found unknown property semantic in file. This is ok"); nuclear@0: SkipLine(&pCur); nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return eOut; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::Property::ParseProperty (const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: PLY::Property* pOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: nuclear@0: // Forms supported: nuclear@0: // "property float x" nuclear@0: // "property list uchar int vertex_index" nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: // skip leading spaces nuclear@0: if (!SkipSpaces(pCur,&pCur))return false; nuclear@0: nuclear@0: // skip the "property" string at the beginning nuclear@0: if (!TokenMatch(pCur,"property",8)) nuclear@0: { nuclear@0: // seems not to be a valid property entry nuclear@0: return false; nuclear@0: } nuclear@0: // get next word nuclear@0: if (!SkipSpaces(pCur,&pCur))return false; nuclear@0: if (TokenMatch(pCur,"list",4)) nuclear@0: { nuclear@0: pOut->bIsList = true; nuclear@0: nuclear@0: // seems to be a list. nuclear@0: if(EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(pCur, &pCur))) nuclear@0: { nuclear@0: // unable to parse list size data type nuclear@0: SkipLine(pCur,&pCur); nuclear@0: *pCurOut = pCur; nuclear@0: return false; nuclear@0: } nuclear@0: if (!SkipSpaces(pCur,&pCur))return false; nuclear@0: if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur))) nuclear@0: { nuclear@0: // unable to parse list data type nuclear@0: SkipLine(pCur,&pCur); nuclear@0: *pCurOut = pCur; nuclear@0: return false; nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur))) nuclear@0: { nuclear@0: // unable to parse data type. Skip the property nuclear@0: SkipLine(pCur,&pCur); nuclear@0: *pCurOut = pCur; nuclear@0: return false; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (!SkipSpaces(pCur,&pCur))return false; nuclear@0: const char* szCur = pCur; nuclear@0: pOut->Semantic = PLY::Property::ParseSemantic(pCur, &pCur); nuclear@0: nuclear@0: if (PLY::EST_INVALID == pOut->Semantic) nuclear@0: { nuclear@0: // store the name of the semantic nuclear@0: uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; nuclear@0: nuclear@0: DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK"); nuclear@0: pOut->szName = std::string(szCur,iDiff); nuclear@0: } nuclear@0: nuclear@0: SkipSpacesAndLineEnd(pCur,&pCur); nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: PLY::EElementSemantic PLY::Element::ParseSemantic(const char* pCur, nuclear@0: const char** pCurOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: PLY::EElementSemantic eOut = PLY::EEST_INVALID; nuclear@0: if (TokenMatch(pCur,"vertex",6)) nuclear@0: { nuclear@0: eOut = PLY::EEST_Vertex; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"face",4)) nuclear@0: { nuclear@0: eOut = PLY::EEST_Face; nuclear@0: } nuclear@0: #if 0 nuclear@0: // TODO: maybe implement this? nuclear@0: else if (TokenMatch(pCur,"range_grid",10)) nuclear@0: { nuclear@0: eOut = PLY::EEST_Face; nuclear@0: } nuclear@0: #endif nuclear@0: else if (TokenMatch(pCur,"tristrips",9)) nuclear@0: { nuclear@0: eOut = PLY::EEST_TriStrip; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"edge",4)) nuclear@0: { nuclear@0: eOut = PLY::EEST_Edge; nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"material",8)) nuclear@0: { nuclear@0: eOut = PLY::EEST_Material; nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return eOut; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::Element::ParseElement (const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: PLY::Element* pOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != pOut); nuclear@0: nuclear@0: // Example format: "element vertex 8" nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: // skip leading spaces nuclear@0: if (!SkipSpaces(&pCur))return false; nuclear@0: nuclear@0: // skip the "element" string at the beginning nuclear@0: if (!TokenMatch(pCur,"element",7)) nuclear@0: { nuclear@0: // seems not to be a valid property entry nuclear@0: return false; nuclear@0: } nuclear@0: // get next word nuclear@0: if (!SkipSpaces(&pCur))return false; nuclear@0: nuclear@0: // parse the semantic of the element nuclear@0: const char* szCur = pCur; nuclear@0: pOut->eSemantic = PLY::Element::ParseSemantic(pCur,&pCur); nuclear@0: if (PLY::EEST_INVALID == pOut->eSemantic) nuclear@0: { nuclear@0: // if the exact semantic can't be determined, just store nuclear@0: // the original string identifier nuclear@0: uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; nuclear@0: pOut->szName = std::string(szCur,iDiff); nuclear@0: } nuclear@0: nuclear@0: if (!SkipSpaces(&pCur))return false; nuclear@0: nuclear@0: //parse the number of occurences of this element nuclear@0: pOut->NumOccur = strtoul10(pCur,&pCur); nuclear@0: nuclear@0: // go to the next line nuclear@0: SkipSpacesAndLineEnd(pCur,&pCur); nuclear@0: nuclear@0: // now parse all properties of the element nuclear@0: while(true) nuclear@0: { nuclear@0: // skip all comments nuclear@0: PLY::DOM::SkipComments(pCur,&pCur); nuclear@0: nuclear@0: PLY::Property prop; nuclear@0: if(!PLY::Property::ParseProperty(pCur,&pCur,&prop))break; nuclear@0: pOut->alProperties.push_back(prop); nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::DOM::SkipComments (const char* pCur, nuclear@0: const char** pCurOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: // skip spaces nuclear@0: if (!SkipSpaces(pCur,&pCur))return false; nuclear@0: nuclear@0: if (TokenMatch(pCur,"comment",7)) nuclear@0: { nuclear@0: SkipLine(pCur,&pCur); nuclear@0: SkipComments(pCur,&pCur); nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin"); nuclear@0: nuclear@0: // after ply and format line nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: // parse all elements nuclear@0: while (true) nuclear@0: { nuclear@0: // skip all comments nuclear@0: PLY::DOM::SkipComments(pCur,&pCur); nuclear@0: nuclear@0: PLY::Element out; nuclear@0: if(PLY::Element::ParseElement(pCur,&pCur,&out)) nuclear@0: { nuclear@0: // add the element to the list of elements nuclear@0: alElements.push_back(out); nuclear@0: } nuclear@0: else if (TokenMatch(pCur,"end_header",10)) nuclear@0: { nuclear@0: // we have reached the end of the header nuclear@0: break; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // ignore unknown header elements nuclear@0: SkipLine(&pCur); nuclear@0: } nuclear@0: } nuclear@0: SkipSpacesAndLineEnd(pCur,&pCur); nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded"); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::DOM::ParseElementInstanceLists ( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin"); nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: alElementData.resize(alElements.size()); nuclear@0: nuclear@0: std::vector::const_iterator i = alElements.begin(); nuclear@0: std::vector::iterator a = alElementData.begin(); nuclear@0: nuclear@0: // parse all element instances nuclear@0: for (;i != alElements.end();++i,++a) nuclear@0: { nuclear@0: (*a).alInstances.resize((*i).NumOccur); nuclear@0: PLY::ElementInstanceList::ParseInstanceList(pCur,&pCur,&(*i),&(*a)); nuclear@0: } nuclear@0: nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded"); nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::DOM::ParseElementInstanceListsBinary ( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: bool p_bBE) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut); nuclear@0: nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin"); nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: alElementData.resize(alElements.size()); nuclear@0: nuclear@0: std::vector::const_iterator i = alElements.begin(); nuclear@0: std::vector::iterator a = alElementData.begin(); nuclear@0: nuclear@0: // parse all element instances nuclear@0: for (;i != alElements.end();++i,++a) nuclear@0: { nuclear@0: (*a).alInstances.resize((*i).NumOccur); nuclear@0: PLY::ElementInstanceList::ParseInstanceListBinary(pCur,&pCur,&(*i),&(*a),p_bBE); nuclear@0: } nuclear@0: nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded"); nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != p_pcOut); nuclear@0: nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); nuclear@0: nuclear@0: if(!p_pcOut->ParseHeader(pCur,&pCur)) nuclear@0: { nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); nuclear@0: return false; nuclear@0: } nuclear@0: if(!p_pcOut->ParseElementInstanceListsBinary(pCur,&pCur,p_bBE)) nuclear@0: { nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); nuclear@0: return false; nuclear@0: } nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded"); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::DOM::ParseInstance (const char* pCur,DOM* p_pcOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur); nuclear@0: ai_assert(NULL != p_pcOut); nuclear@0: nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); nuclear@0: nuclear@0: nuclear@0: if(!p_pcOut->ParseHeader(pCur,&pCur)) nuclear@0: { nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); nuclear@0: return false; nuclear@0: } nuclear@0: if(!p_pcOut->ParseElementInstanceLists(pCur,&pCur)) nuclear@0: { nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); nuclear@0: return false; nuclear@0: } nuclear@0: DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded"); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::ElementInstanceList::ParseInstanceList ( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: const PLY::Element* pcElement, nuclear@0: PLY::ElementInstanceList* p_pcOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != pcElement && NULL != p_pcOut); nuclear@0: nuclear@0: if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty()) nuclear@0: { nuclear@0: // if the element has an unknown semantic we can skip all lines nuclear@0: // However, there could be comments nuclear@0: for (unsigned int i = 0; i < pcElement->NumOccur;++i) nuclear@0: { nuclear@0: PLY::DOM::SkipComments(pCur,&pCur); nuclear@0: SkipLine(pCur,&pCur); nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // be sure to have enough storage nuclear@0: for (unsigned int i = 0; i < pcElement->NumOccur;++i) nuclear@0: { nuclear@0: PLY::DOM::SkipComments(pCur,&pCur); nuclear@0: PLY::ElementInstance::ParseInstance(pCur, &pCur,pcElement, nuclear@0: &p_pcOut->alInstances[i]); nuclear@0: } nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::ElementInstanceList::ParseInstanceListBinary ( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: const PLY::Element* pcElement, nuclear@0: PLY::ElementInstanceList* p_pcOut, nuclear@0: bool p_bBE /* = false */) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != pcElement && NULL != p_pcOut); nuclear@0: nuclear@0: // we can add special handling code for unknown element semantics since nuclear@0: // we can't skip it as a whole block (we don't know its exact size nuclear@0: // due to the fact that lists could be contained in the property list nuclear@0: // of the unknown element) nuclear@0: for (unsigned int i = 0; i < pcElement->NumOccur;++i) nuclear@0: { nuclear@0: PLY::ElementInstance::ParseInstanceBinary(pCur, &pCur,pcElement, nuclear@0: &p_pcOut->alInstances[i], p_bBE); nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::ElementInstance::ParseInstance ( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: const PLY::Element* pcElement, nuclear@0: PLY::ElementInstance* p_pcOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != pcElement && NULL != p_pcOut); nuclear@0: nuclear@0: if (!SkipSpaces(pCur, &pCur))return false; nuclear@0: nuclear@0: // allocate enough storage nuclear@0: p_pcOut->alProperties.resize(pcElement->alProperties.size()); nuclear@0: nuclear@0: std::vector::iterator i = p_pcOut->alProperties.begin(); nuclear@0: std::vector::const_iterator a = pcElement->alProperties.begin(); nuclear@0: for (;i != p_pcOut->alProperties.end();++i,++a) nuclear@0: { nuclear@0: if(!(PLY::PropertyInstance::ParseInstance(pCur, &pCur,&(*a),&(*i)))) nuclear@0: { nuclear@0: DefaultLogger::get()->warn("Unable to parse property instance. " nuclear@0: "Skipping this element instance"); nuclear@0: nuclear@0: // skip the rest of the instance nuclear@0: SkipLine(pCur, &pCur); nuclear@0: nuclear@0: PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType); nuclear@0: (*i).avList.push_back(v); nuclear@0: } nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::ElementInstance::ParseInstanceBinary ( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: const PLY::Element* pcElement, nuclear@0: PLY::ElementInstance* p_pcOut, nuclear@0: bool p_bBE /* = false */) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != pcElement && NULL != p_pcOut); nuclear@0: nuclear@0: // allocate enough storage nuclear@0: p_pcOut->alProperties.resize(pcElement->alProperties.size()); nuclear@0: nuclear@0: std::vector::iterator i = p_pcOut->alProperties.begin(); nuclear@0: std::vector::const_iterator a = pcElement->alProperties.begin(); nuclear@0: for (;i != p_pcOut->alProperties.end();++i,++a) nuclear@0: { nuclear@0: if(!(PLY::PropertyInstance::ParseInstanceBinary(pCur, &pCur,&(*a),&(*i),p_bBE))) nuclear@0: { nuclear@0: DefaultLogger::get()->warn("Unable to parse binary property instance. " nuclear@0: "Skipping this element instance"); nuclear@0: nuclear@0: (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType)); nuclear@0: } nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::PropertyInstance::ParseInstance (const char* pCur,const char** pCurOut, nuclear@0: const PLY::Property* prop, PLY::PropertyInstance* p_pcOut) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != prop && NULL != p_pcOut); nuclear@0: nuclear@0: *pCurOut = pCur; nuclear@0: nuclear@0: // skip spaces at the beginning nuclear@0: if (!SkipSpaces(pCur, &pCur))return false; nuclear@0: nuclear@0: if (prop->bIsList) nuclear@0: { nuclear@0: // parse the number of elements in the list nuclear@0: PLY::PropertyInstance::ValueUnion v; nuclear@0: PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eFirstType,&v); nuclear@0: nuclear@0: // convert to unsigned int nuclear@0: unsigned int iNum = PLY::PropertyInstance::ConvertTo(v,prop->eFirstType); nuclear@0: nuclear@0: // parse all list elements nuclear@0: p_pcOut->avList.resize(iNum); nuclear@0: for (unsigned int i = 0; i < iNum;++i) nuclear@0: { nuclear@0: if (!SkipSpaces(pCur, &pCur))return false; nuclear@0: PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&p_pcOut->avList[i]); nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // parse the property nuclear@0: PLY::PropertyInstance::ValueUnion v; nuclear@0: nuclear@0: PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&v); nuclear@0: p_pcOut->avList.push_back(v); nuclear@0: } nuclear@0: SkipSpacesAndLineEnd(pCur, &pCur); nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::PropertyInstance::ParseInstanceBinary ( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: const PLY::Property* prop, nuclear@0: PLY::PropertyInstance* p_pcOut, nuclear@0: bool p_bBE) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != prop && NULL != p_pcOut); nuclear@0: nuclear@0: if (prop->bIsList) nuclear@0: { nuclear@0: // parse the number of elements in the list nuclear@0: PLY::PropertyInstance::ValueUnion v; nuclear@0: PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eFirstType,&v,p_bBE); nuclear@0: nuclear@0: // convert to unsigned int nuclear@0: unsigned int iNum = PLY::PropertyInstance::ConvertTo(v,prop->eFirstType); nuclear@0: nuclear@0: // parse all list elements nuclear@0: p_pcOut->avList.resize(iNum); nuclear@0: for (unsigned int i = 0; i < iNum;++i){ nuclear@0: PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&p_pcOut->avList[i],p_bBE); nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // parse the property nuclear@0: PLY::PropertyInstance::ValueUnion v; nuclear@0: PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&v,p_bBE); nuclear@0: p_pcOut->avList.push_back(v); nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue( nuclear@0: PLY::EDataType eType) nuclear@0: { nuclear@0: PLY::PropertyInstance::ValueUnion out; nuclear@0: nuclear@0: switch (eType) nuclear@0: { nuclear@0: case EDT_Float: nuclear@0: out.fFloat = 0.f; nuclear@0: return out; nuclear@0: nuclear@0: case EDT_Double: nuclear@0: out.fDouble = 0.; nuclear@0: return out; nuclear@0: nuclear@0: default: ; nuclear@0: }; nuclear@0: out.iUInt = 0; nuclear@0: return out; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::PropertyInstance::ParseValue( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: PLY::EDataType eType, nuclear@0: PLY::PropertyInstance::ValueUnion* out) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != out); nuclear@0: nuclear@0: register bool ret = true; nuclear@0: *pCurOut = pCur; nuclear@0: switch (eType) nuclear@0: { nuclear@0: case EDT_UInt: nuclear@0: case EDT_UShort: nuclear@0: case EDT_UChar: nuclear@0: nuclear@0: out->iUInt = (uint32_t)strtoul10(pCur, &pCur); nuclear@0: break; nuclear@0: nuclear@0: case EDT_Int: nuclear@0: case EDT_Short: nuclear@0: case EDT_Char: nuclear@0: nuclear@0: out->iInt = (int32_t)strtol10(pCur, &pCur); nuclear@0: break; nuclear@0: nuclear@0: case EDT_Float: nuclear@0: nuclear@0: pCur = fast_atoreal_move(pCur,out->fFloat); nuclear@0: break; nuclear@0: nuclear@0: case EDT_Double: nuclear@0: nuclear@0: float f; nuclear@0: pCur = fast_atoreal_move(pCur,f); nuclear@0: out->fDouble = (double)f; nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: ret = false; nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: bool PLY::PropertyInstance::ParseValueBinary( nuclear@0: const char* pCur, nuclear@0: const char** pCurOut, nuclear@0: PLY::EDataType eType, nuclear@0: PLY::PropertyInstance::ValueUnion* out, nuclear@0: bool p_bBE) nuclear@0: { nuclear@0: ai_assert(NULL != pCur && NULL != pCurOut && NULL != out); nuclear@0: nuclear@0: register bool ret = true; nuclear@0: switch (eType) nuclear@0: { nuclear@0: case EDT_UInt: nuclear@0: out->iUInt = (uint32_t)*((uint32_t*)pCur); nuclear@0: pCur += 4; nuclear@0: nuclear@0: // Swap endianess nuclear@0: if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt); nuclear@0: break; nuclear@0: nuclear@0: case EDT_UShort: nuclear@0: { nuclear@0: int16_t i = *((uint16_t*)pCur); nuclear@0: nuclear@0: // Swap endianess nuclear@0: if (p_bBE)ByteSwap::Swap(&i); nuclear@0: out->iUInt = (uint32_t)i; nuclear@0: pCur += 2; nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: case EDT_UChar: nuclear@0: { nuclear@0: out->iUInt = (uint32_t)(*((uint8_t*)pCur)); nuclear@0: pCur ++; nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: case EDT_Int: nuclear@0: out->iInt = *((int32_t*)pCur); nuclear@0: pCur += 4; nuclear@0: nuclear@0: // Swap endianess nuclear@0: if (p_bBE)ByteSwap::Swap(&out->iInt); nuclear@0: break; nuclear@0: nuclear@0: case EDT_Short: nuclear@0: { nuclear@0: int16_t i = *((int16_t*)pCur); nuclear@0: nuclear@0: // Swap endianess nuclear@0: if (p_bBE)ByteSwap::Swap(&i); nuclear@0: out->iInt = (int32_t)i; nuclear@0: pCur += 2; nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: case EDT_Char: nuclear@0: out->iInt = (int32_t)*((int8_t*)pCur); nuclear@0: pCur ++; nuclear@0: break; nuclear@0: nuclear@0: case EDT_Float: nuclear@0: { nuclear@0: out->fFloat = *((float*)pCur); nuclear@0: nuclear@0: // Swap endianess nuclear@0: if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat); nuclear@0: pCur += 4; nuclear@0: break; nuclear@0: } nuclear@0: case EDT_Double: nuclear@0: { nuclear@0: out->fDouble = *((double*)pCur); nuclear@0: nuclear@0: // Swap endianess nuclear@0: if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble); nuclear@0: pCur += 8; nuclear@0: break; nuclear@0: } nuclear@0: default: nuclear@0: ret = false; nuclear@0: } nuclear@0: *pCurOut = pCur; nuclear@0: return ret; nuclear@0: } nuclear@0: nuclear@0: #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER