diff --git a/INSTALL b/INSTALL index 20ef87f09..d09844921 100644 --- a/INSTALL +++ b/INSTALL @@ -1,7 +1,32 @@ - Open Asset Import Library (Assimp) Install - ----------------------------------------- -To take a look into the ASSIMP library just get the code, go to the -workspaces-directory and open your prefered build enviroment. Now just build -the engine, start the ASSIMP-Viewer application and select one of our basic test-files. - -You need boost-1.35 to build the Asset Import Library. + + +Open Asset Import Library (Assimp) Install +------------------------------------------------ + +Please see the doxygen documentation to learn how to build & use Assimp. +A CHM file is included in the SVN repos: ./doc/lib_htmp/AssimpDoc.chm. +At least Windows should be able to read it. + +To build the doxygen doc on your own follow these steps: + +a) download & install latest doxygen +b) ensure doxygen is in the executable search path +c) navigate to ./doc +d) and run 'doxygen' + +Open the generated HTML (lib_htmp/index.html) in the browser of your choice. +Windows only: To generate the CHM doc install the 'Microsoft HTML Workshop' +and configure the path to it in the DOXYFILE. Run doxygen again. + + +You can also find a copy of the doc on our web site: +http://assimp.sourceforge.net/lib_html/index.html + +Beware, it could be outdated. If you're in serious doubt it might be, +rebuilding the doc is probably a wise choice. + + + + + + diff --git a/clean.bat b/clean.bat deleted file mode 100644 index f6e74ed03..000000000 --- a/clean.bat +++ /dev/null @@ -1,6 +0,0 @@ -cd code -mingw32-make -f makefile.mingw clean - -cd .. -del /Q /S obj bin lib - diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index 3d5acfdc2..5ff756469 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -54,14 +54,13 @@ using namespace Assimp; // Setup final material indices, generae a default material if necessary void Discreet3DSImporter::ReplaceDefaultMaterial() { - ////////////////////////////////////////////////////////////////////////// + // Try to find an existing material that matches the // typical default material setting: // - no textures // - diffuse color (in grey!) // NOTE: This is here to workaround the fact that some // exporters are writing a default material, too. - ////////////////////////////////////////////////////////////////////////// unsigned int idx = 0xcdcdcdcd; for (unsigned int i = 0; i < mScene->mMaterials.size();++i) { @@ -438,57 +437,65 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, iArray.reserve(3); aiMatrix4x4 abs; - /*if (pcIn->mName == "$$$DUMMY") { - // FIX: Append the "real" name of the dummy to the string - pcIn->mName = "Dummy." + pcIn->mDummyName; + + // Find all meshes with the same name as the node + for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) + { + const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; + ai_assert(NULL != pcMesh); + + if (pcIn->mName == pcMesh->mName) + iArray.push_back(a); } - else*/ // if (pcIn->mName != "$$$DUMMY") - { - // Find all meshes with the same name as the node - for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) - { - const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; - ai_assert(NULL != pcMesh); + if (!iArray.empty()) + { + // The matrix should be identical for all meshes with the + // same name. It HAS to be identical for all meshes ..... + D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); - if (pcIn->mName == pcMesh->mName) - iArray.push_back(a); - } - if (!iArray.empty()) - { - // The matrix should be identical for all meshes with the - // same name. It HAS to be identical for all meshes ..... - aiMatrix4x4 mInv = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0])->mMat; - mInv.Inverse(); - const aiVector3D& pivot = pcIn->vPivot; + // Compute the inverse of the transformation matrix to move the + // vertices back to their relative and local space + aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; + mInv.Inverse();mInvTransposed.Transpose(); + aiVector3D pivot = pcIn->vPivot; - pcOut->mNumMeshes = (unsigned int)iArray.size(); - pcOut->mMeshes = new unsigned int[iArray.size()]; - for (unsigned int i = 0;i < iArray.size();++i) - { - const unsigned int iIndex = iArray[i]; - aiMesh* const mesh = pcSOut->mMeshes[iIndex]; + pcOut->mNumMeshes = (unsigned int)iArray.size(); + pcOut->mMeshes = new unsigned int[iArray.size()]; + for (unsigned int i = 0;i < iArray.size();++i) { + const unsigned int iIndex = iArray[i]; + aiMesh* const mesh = pcSOut->mMeshes[iIndex]; - // Pivot point adjustment - // See: http://www.zfx.info/DisplayThread.php?MID=235690#235690 - const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices; - aiVector3D* pvCurrent = mesh->mVertices; + // Transform the vertices back into their local space + // fixme: consider computing normals after this, so we don't need to transform them + const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices; + aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; - if(pivot.x || pivot.y || pivot.z) - { - for (;pvCurrent != pvEnd;++pvCurrent) - { - *pvCurrent = mInv * (*pvCurrent); - *pvCurrent -= pivot; - } - } - else - { - for (;pvCurrent != pvEnd;++pvCurrent) - *pvCurrent = mInv * (*pvCurrent); - } - // Setup the mesh index - pcOut->mMeshes[i] = iIndex; + for (;pvCurrent != pvEnd;++pvCurrent,++t2) { + *pvCurrent = mInv * (*pvCurrent); + *t2 = mInvTransposed * (*t2); } + + // Handle negative transformation matrix determinant -> invert vertex x + if (imesh->mMat.Determinant() < 0.0f) + { + /* we *must* have normals */ + for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) { + pvCurrent->x *= -1.f; + t2->x *= -1.f; + } + DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); + } + + // Handle pivot point + if(pivot.x || pivot.y || pivot.z) + { + for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent) { + *pvCurrent -= pivot; + } + } + + // Setup the mesh index + pcOut->mMeshes[i] = iIndex; } } @@ -526,7 +533,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, } // Generate animation channels for the node - if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || + if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || pcIn->aTargetPositionKeys.size() > 1) { diff --git a/code/3DSHelper.h b/code/3DSHelper.h index 40ea8ab79..4c591ee50 100644 --- a/code/3DSHelper.h +++ b/code/3DSHelper.h @@ -124,11 +124,10 @@ public: CHUNK_PERCENTF = 0x0031, // float4 percentage // ******************************************************************** - // Unknown and ignored. Possibly a chunk used by PROJ ( - // Discreet 3DS max Project File)? + // Prj master chunk CHUNK_PRJ = 0xC23D, - // Unknown. Possibly a reference to an external .mli file? + // MDLI master chunk CHUNK_MLI = 0x3DAA, // Primary main chunk of the .3ds file @@ -178,7 +177,6 @@ public: CHUNK_MESHCOLOR = 0x4165, CHUNK_TXTINFO = 0x4170, CHUNK_LIGHT = 0x4600, - CHUNK_SPOTLIGHT = 0x4610, CHUNK_CAMERA = 0x4700, CHUNK_HIERARCHY = 0x4F00, @@ -330,7 +328,7 @@ struct Texture , mMapMode (aiTextureMapMode_Wrap) , iUVSrc (0) { - mTextureBlend = std::numeric_limits::quiet_NaN(); + mTextureBlend = get_qnan(); } //! Specifies the blend factor for the texture diff --git a/code/3DSLoader.cpp b/code/3DSLoader.cpp index 64f3fd8d6..37f2d8c08 100644 --- a/code/3DSLoader.cpp +++ b/code/3DSLoader.cpp @@ -39,7 +39,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the 3ds importer class */ +/** @file 3DSLoader.cpp + * @brief Implementation of the 3ds importer class + * + * http://www.the-labs.com/Blender/3DS-details.html + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER @@ -53,12 +57,14 @@ using namespace Assimp; // Begins a new parsing block // - Reads the current chunk and validates it // - computes its length -#define ASSIMP_3DS_BEGIN_CHUNK() \ - Discreet3DS::Chunk chunk; \ - ReadChunk(&chunk); \ - int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ - const int oldReadLimit = stream->GetReadLimit(); \ - stream->SetReadLimit(stream->GetCurrentPos() + chunkSize); +#define ASSIMP_3DS_BEGIN_CHUNK() \ + if (stream->GetRemainingSizeToLimit() < sizeof(Discreet3DS::Chunk)) \ + return; \ + Discreet3DS::Chunk chunk; \ + ReadChunk(&chunk); \ + int chunkSize = chunk.Size-sizeof(Discreet3DS::Chunk); \ + const int oldReadLimit = stream->GetReadLimit(); \ + stream->SetReadLimit(stream->GetCurrentPos() + chunkSize); // ------------------------------------------------------------------------------------------------ @@ -82,18 +88,27 @@ Discreet3DSImporter::~Discreet3DSImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); - for (std::string::iterator i = extension.begin(); i != extension.end();++i) - *i = ::tolower(*i); + std::string extension = GetExtension(pFile); + if(extension == "3ds" || extension == "prj" ) { + return true; + } + if (!extension.length() || checkSig) { + uint16_t token[3]; + token[0] = 0x4d4d; + token[1] = 0x3dc2; + //token[2] = 0x3daa; + return CheckMagicToken(pIOHandler,pFile,token,2,0,2); + } + return false; +} - return (extension == ".3ds"); +// ------------------------------------------------------------------------------------------------ +// Get list of all extension supported by this loader +void Discreet3DSImporter::GetExtensionList(std::string& append) +{ + append.append("*.3ds;*.prj"); } // ------------------------------------------------------------------------------------------------ @@ -128,6 +143,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile, mMasterScale = 1.0f; mBackgroundImage = ""; bHasBG = false; + bIsPrj = false; // Parse the file ParseMainChunk(); @@ -138,8 +154,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile, // vectors from the smoothing groups we read from the // file. for (std::vector::iterator i = mScene->mMeshes.begin(), - end = mScene->mMeshes.end(); i != end;++i) - { + end = mScene->mMeshes.end(); i != end;++i) { CheckIndices(*i); MakeUnique (*i); ComputeNormalsWithSmoothingsGroups(*i); @@ -226,6 +241,9 @@ void Discreet3DSImporter::ParseMainChunk() // get chunk type switch (chunk.Flag) { + + case Discreet3DS::CHUNK_PRJ: + bIsPrj = true; case Discreet3DS::CHUNK_MAIN: ParseEditorChunk(); break; @@ -371,9 +389,9 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) light->mColorDiffuse = aiColor3D(1.f,1.f,1.f); - // Now check for further subchunks (excluding color) - int8_t* p = stream->GetPtr(); - ParseLightChunk(); + // Now check for further subchunks + if (!bIsPrj) /* fixme */ + ParseLightChunk(); // The specular light color is identical the the diffuse light // color. The ambient light color is equal to the ambient base @@ -424,6 +442,10 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num) if (camera->mHorizontalFOV < 0.001f) camera->mHorizontalFOV = AI_DEG_TO_RAD(45.f); } + + // Now check for further subchunks + if (!bIsPrj) /* fixme */ + ParseCameraChunk(); break; }; ASSIMP_3DS_END_CHUNK(); @@ -440,7 +462,7 @@ void Discreet3DSImporter::ParseLightChunk() // get chunk type switch (chunk.Flag) { - case Discreet3DS::CHUNK_SPOTLIGHT: + case Discreet3DS::CHUNK_DL_SPOTLIGHT: // Now we can be sure that the light is a spot light light->mType = aiLightSource_SPOT; @@ -511,7 +533,7 @@ void Discreet3DSImporter::ParseKeyframeChunk() switch (chunk.Flag) { case Discreet3DS::CHUNK_TRACKCAMTGT: - case Discreet3DS::CHUNK_SPOTLIGHT: + case Discreet3DS::CHUNK_TRACKSPOTL: case Discreet3DS::CHUNK_TRACKCAMERA: case Discreet3DS::CHUNK_TRACKINFO: case Discreet3DS::CHUNK_TRACKLIGHT: @@ -574,14 +596,11 @@ void Discreet3DSImporter::SkipTCBInfo() { unsigned int flags = stream->GetI2(); - if (!flags) - { - ////////////////////////////////////////////////////////////////////////// + if (!flags) { // Currently we can't do anything with these values. They occur // quite rare, so it wouldn't be worth the effort implementing // them. 3DS ist not really suitable for complex animations, // so full support is not required. - ////////////////////////////////////////////////////////////////////////// DefaultLogger::get()->warn("3DS: Skipping TCB animation info"); } @@ -1015,35 +1034,7 @@ void Discreet3DSImporter::ParseMeshChunk() mMesh.mMat.a4 = stream->GetF4(); mMesh.mMat.b4 = stream->GetF4(); mMesh.mMat.c4 = stream->GetF4(); - - // Now check whether the matrix has got a negative determinant - // If yes, we need to flip all vertices' Z axis .... - // This code has been taken from lib3ds - if (mMesh.mMat.Determinant() < 0.0f) { - // Compute the inverse of the matrix - aiMatrix4x4 mInv = mMesh.mMat; - mInv.Inverse(); - - aiMatrix4x4 mMe = mMesh.mMat; - mMe.c1 *= -1.0f; - mMe.c2 *= -1.0f; - mMe.c3 *= -1.0f; - mMe.c4 *= -1.0f; - mInv = mInv * mMe; - - // Now transform all vertices - for (unsigned int i = 0; i < (unsigned int)mMesh.mPositions.size();++i) - { - aiVector3D a,c; - a = mMesh.mPositions[i]; - c[0]= mInv[0][0]*a[0] + mInv[1][0]*a[1] + mInv[2][0]*a[2] + mInv[3][0]; - c[1]= mInv[0][1]*a[0] + mInv[1][1]*a[1] + mInv[2][1]*a[2] + mInv[3][1]; - c[2]= mInv[0][2]*a[0] + mInv[1][2]*a[1] + mInv[2][2]*a[2] + mInv[3][2]; - mMesh.mPositions[i] = c; - } - - DefaultLogger::get()->info("3DS: Flipping mesh Z-Axis"); - }} + } break; case Discreet3DS::CHUNK_MAPLIST: @@ -1353,7 +1344,7 @@ float Discreet3DSImporter::ParsePercentageChunk() return stream->GetF4(); else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) return (float)((uint16_t)stream->GetI2()) / (float)0xFFFF; - return std::numeric_limits::quiet_NaN(); + return get_qnan(); } // ------------------------------------------------------------------------------------------------ @@ -1364,7 +1355,7 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D* out, ai_assert(out != NULL); // error return value - const float qnan = std::numeric_limits::quiet_NaN(); + const float qnan = get_qnan(); static const aiColor3D clrError = aiColor3D(qnan,qnan,qnan); Discreet3DS::Chunk chunk; diff --git a/code/3DSLoader.h b/code/3DSLoader.h index 74cc5917c..2e8625aca 100644 --- a/code/3DSLoader.h +++ b/code/3DSLoader.h @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Definition of the .3ds importer class. */ +/** @file 3DSLoader.h + * @brief 3DS File format loader + */ #ifndef AI_3DSIMPORTER_H_INC #define AI_3DSIMPORTER_H_INC @@ -49,16 +51,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiNode; #include "3DSHelper.h" -namespace Assimp -{ +namespace Assimp { class MaterialHelper; using namespace D3DS; -// --------------------------------------------------------------------------- -/** The Discreet3DSImporter is a worker class capable of importing a scene from a -* 3ds Max 4/5 Files (.3ds) -*/ +// --------------------------------------------------------------------------------- +/** Importer class for 3D Studio r3 and r4 3DS files + */ class Discreet3DSImporter : public BaseImporter { friend class Importer; @@ -74,14 +74,16 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; // ------------------------------------------------------------------- /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - */ + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + */ void SetupProperties(const Importer* pImp); protected: @@ -90,21 +92,18 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.3ds"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ + * See BaseImporter::InternReadFile() for details + */ void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); // ------------------------------------------------------------------- /** Converts a temporary material to the outer representation - */ + */ void ConvertMaterial(D3DS::Material& p_cMat, MaterialHelper& p_pcOut); @@ -112,7 +111,7 @@ protected: /** Read a chunk * * @param pcOut Receives the current chunk - */ + */ void ReadChunk(Discreet3DS::Chunk* pcOut); // ------------------------------------------------------------------- @@ -271,6 +270,9 @@ protected: /** Path to the background image of the scene */ std::string mBackgroundImage; bool bHasBG; + + /** true if PRJ file */ + bool bIsPrj; }; } // end of namespace Assimp diff --git a/code/ACLoader.cpp b/code/ACLoader.cpp index 70dbffc9a..62bcac519 100644 --- a/code/ACLoader.cpp +++ b/code/ACLoader.cpp @@ -108,28 +108,38 @@ using namespace Assimp; // Constructor to be privately used by Importer AC3DImporter::AC3DImporter() { + // nothing to be done here } // ------------------------------------------------------------------------------------------------ // Destructor, private as well AC3DImporter::~AC3DImporter() { + // nothing to be done here } // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); + std::string extension = GetExtension(pFile); - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); + // fixme: are acc and ac3d *really* used? Some sources say they are + if(extension == "ac" || extension == "ac3d" || extension == "acc") { + return true; + } + if (!extension.length() || checkSig) { + uint32_t token = AI_MAKE_MAGIC("AC3D"); + return CheckMagicToken(pIOHandler,pFile,&token,1,0); + } + return false; +} - return( extension == ".ac3d" || extension == ".ac"); +// ------------------------------------------------------------------------------------------------ +// Get list of file extensions handled by this loader +void AC3DImporter::GetExtensionList(std::string& append) +{ + append.append("*.ac;*.acc;*.ac3d"); } // ------------------------------------------------------------------------------------------------ @@ -140,7 +150,6 @@ bool AC3DImporter::GetNextLine( ) return SkipSpaces(&buffer); } - // ------------------------------------------------------------------------------------------------ // Parse an object section in an AC file void AC3DImporter::LoadObjectSection(std::vector& objects) diff --git a/code/ACLoader.h b/code/ACLoader.h index 4309a4eca..fdf6bfdc5 100644 --- a/code/ACLoader.h +++ b/code/ACLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the .ac importer class. */ +/** @file ACLoader.h + * @brief Declaration of the .ac importer class. + */ #ifndef AI_AC3DLOADER_H_INCLUDED #define AI_AC3DLOADER_H_INCLUDED @@ -166,8 +168,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -175,10 +179,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.ac;*.acc"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index 7564fd74a..c3d25959b 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the ASE importer class */ +/** @file ASELoader.cpp + * @brief Implementation of the ASE importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER @@ -69,23 +71,25 @@ ASEImporter::~ASEImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; + // check file extension + const std::string extension = GetExtension(pFile); + + if( extension == "ase" || extension == "ask") + return true; - std::string extension = pFile.substr( pos); + if ((!extension.length() || cs) && pIOHandler) { + const char* tokens[] = {"*3dsmax_asciiexport"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; +} - // Either ASE, ASC or ASK - return !(extension.length() < 4 || extension[0] != '.' || - extension[1] != 'a' && extension[1] != 'A' || - extension[2] != 's' && extension[2] != 'S' || - extension[3] != 'e' && extension[3] != 'E' && - extension[3] != 'k' && extension[3] != 'K' && - extension[3] != 'c' && extension[3] != 'C'); +// ------------------------------------------------------------------------------------------------ +void ASEImporter::GetExtensionList(std::string& append) +{ + append.append("*.ase;*.ask"); } // ------------------------------------------------------------------------------------------------ @@ -108,6 +112,8 @@ void ASEImporter::InternReadFile( const std::string& pFile, throw new ImportErrorException( "Failed to open ASE file " + pFile + "."); size_t fileSize = file->FileSize(); + if (!fileSize) + throw new ImportErrorException( "ASE: File is empty"); // Allocate storage and copy the contents of the file to a memory buffer // (terminate it with zero) @@ -778,8 +784,7 @@ void ASEImporter::BuildNodes() delete pc; } // The root node should not have at least one child or the file is invalid - else if (!pcScene->mRootNode->mNumChildren) - { + else if (!pcScene->mRootNode->mNumChildren) { throw new ImportErrorException("No nodes loaded. The ASE/ASK file is either empty or corrupt"); } return; diff --git a/code/ASELoader.h b/code/ASELoader.h index 8b7f0a8fe..efae439f4 100644 --- a/code/ASELoader.h +++ b/code/ASELoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Definition of the .ASE importer class. */ +/** @file ASELoader.h + * @brief Definition of the .ASE importer class. + */ #ifndef AI_ASELOADER_H_INCLUDED #define AI_ASELOADER_H_INCLUDED @@ -48,15 +50,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiNode; #include "ASEParser.h" -namespace Assimp -{ +namespace Assimp { class MaterialHelper; using namespace ASE; -// --------------------------------------------------------------------------- -/** Used to load ASE files -*/ +// -------------------------------------------------------------------------------- +/** Importer class for the 3DS ASE ASCII format + * + * fixme: consider code cleanup + */ class ASEImporter : public BaseImporter { friend class Importer; @@ -72,8 +75,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -81,10 +86,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.ase;*.ask;*.asc"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index 5af9c9e84..bbc036f8b 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the ASE parser class */ +/** @file ASEParser.cpp + * @brief Implementation of the ASE parser class + */ #include "AssimpPCH.h" @@ -120,8 +122,8 @@ Parser::Parser (const char* szFile, unsigned int fileFormatDefault) iFileFormat = fileFormatDefault; // make sure that the color values are invalid - m_clrBackground.r = std::numeric_limits::quiet_NaN(); - m_clrAmbient.r = std::numeric_limits::quiet_NaN(); + m_clrBackground.r = get_qnan(); + m_clrAmbient.r = get_qnan(); // setup some default values iLineNumber = 0; diff --git a/code/ASEParser.h b/code/ASEParser.h index be7254d1e..749a2fa6d 100644 --- a/code/ASEParser.h +++ b/code/ASEParser.h @@ -227,7 +227,7 @@ struct BaseNode mName = szTemp; // Set mTargetPosition to qnan - const float qnan = std::numeric_limits::quiet_NaN(); + const float qnan = get_qnan(); mTargetPosition.x = qnan; } diff --git a/code/AssimpPCH.cpp b/code/AssimpPCH.cpp index 34dfd656c..57eb35e3d 100644 --- a/code/AssimpPCH.cpp +++ b/code/AssimpPCH.cpp @@ -1,5 +1,5 @@ -// Actually just a dummyy, used by the compiler to build the precompiled header. +// Actually just a dummy, used by the compiler to build the precompiled header. #include "AssimpPCH.h" #include "./../include/aiVersion.h" @@ -12,7 +12,7 @@ static const char* LEGAL_INFORMATION = "A free C/C++ library to import various 3D file formats into applications\n\n" "(c) ASSIMP Development Team, 2008-2009\n" -"License: BSD\n" +"License: 3-clause BSD license\n" "Website: http://assimp.sourceforge.net\n" ; @@ -59,10 +59,12 @@ ASSIMP_API unsigned int aiGetCompileFlags () { return flags; } +// include current build revision +#include "../mkutil/revision.h" + // ------------------------------------------------------------------------------------------------ ASSIMP_API unsigned int aiGetVersionRevision () { - // TODO: find a way to update the revision number automatically - return 306; + return SVNRevision; } diff --git a/code/AssimpPCH.h b/code/AssimpPCH.h index f60793fad..fe4e5c83f 100644 --- a/code/AssimpPCH.h +++ b/code/AssimpPCH.h @@ -67,6 +67,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 #endif +// size_t to unsigned int, possible loss of data. +// Yes, the compiler is right with his warning, but this loss of data +// won't be a problem for us. So shut up little boy. +#ifdef _MSC_VER +# pragma warning (disable : 4267) +#endif + // Actually that's not required for MSVC (it is included somewhere in // the STL ..) but it is necessary for build with STLport. #include @@ -75,6 +82,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include diff --git a/code/B3DImporter.cpp b/code/B3DImporter.cpp index deee0ad15..cbc95e49a 100644 --- a/code/B3DImporter.cpp +++ b/code/B3DImporter.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the b3d importer class */ +/** @file B3DImporter.cpp + * @brief Implementation of the b3d importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER @@ -52,7 +54,7 @@ using namespace Assimp; using namespace std; // ------------------------------------------------------------------------------------------------ -bool B3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const{ +bool B3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const{ int pos=pFile.find_last_of( '.' ); if( pos==string::npos ) return false; diff --git a/code/B3DImporter.h b/code/B3DImporter.h index 60235b759..71f0114cf 100644 --- a/code/B3DImporter.h +++ b/code/B3DImporter.h @@ -56,7 +56,7 @@ namespace Assimp{ class B3DImporter : public BaseImporter{ public: - virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; protected: diff --git a/code/BVHLoader.cpp b/code/BVHLoader.cpp index cb2d626c2..cf1231f57 100644 --- a/code/BVHLoader.cpp +++ b/code/BVHLoader.cpp @@ -61,18 +61,19 @@ BVHLoader::~BVHLoader() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { // check file extension - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); + const std::string extension = GetExtension(pFile); + + if( extension == "bvh") + return true; - return ( extension == ".bvh"); + if ((!extension.length() || cs) && pIOHandler) { + const char* tokens[] = {"HIERARCHY"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; } // ------------------------------------------------------------------------------------------------ diff --git a/code/BVHLoader.h b/code/BVHLoader.h index 77ea0261d..dc1c3644d 100644 --- a/code/BVHLoader.h +++ b/code/BVHLoader.h @@ -40,6 +40,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +/** @file BVHLoader.h + * @brief Biovision BVH import + */ + #ifndef AI_BVHLOADER_H_INC #define AI_BVHLOADER_H_INC @@ -48,9 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -/** Loader class to read Motion Capturing data from a .bvh file. This format only contains a -* hierarchy of joints and a series of keyframes for the hierarchy. It contains no actual mesh data, -* but we generate a dummy mesh inside the loader just to be able to see something. +// -------------------------------------------------------------------------------- +/** Loader class to read Motion Capturing data from a .bvh file. + * + * This format only contains a hierarchy of joints and a series of keyframes for + * the hierarchy. It contains no actual mesh data, but we generate a dummy mesh + * inside the loader just to be able to see something. */ class BVHLoader : public BaseImporter { @@ -88,7 +95,7 @@ protected: public: /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const; protected: /** Called by Importer::GetExtensionList() for each loaded importer. diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index 8c7ce5db1..bd1b6b48c 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -39,12 +39,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of BaseImporter */ +/** @file BaseImporter.cpp + * @brief Implementation of BaseImporter + */ #include "AssimpPCH.h" #include "BaseImporter.h" - using namespace Assimp; @@ -98,7 +99,7 @@ void BaseImporter::SetupProperties(const Importer* pImp) } // ------------------------------------------------------------------------------------------------ -bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler, +/*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler, const std::string& pFile, const char** tokens, unsigned int numTokens, @@ -142,17 +143,105 @@ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler, return false; } +// ------------------------------------------------------------------------------------------------ +// Simple check for file extension +/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile, + const char* ext0, + const char* ext1, + const char* ext2) +{ + std::string::size_type pos = pFile.find_last_of('.'); + + // no file extension - can't read + if( pos == std::string::npos) + return false; + + const char* ext_real = & pFile[ pos+1 ]; + if( !ASSIMP_stricmp(ext_real,ext0) ) + return true; + + // check for other, optional, file extensions + if (ext1 && !ASSIMP_stricmp(ext_real,ext1)) + return true; + + if (ext2 && !ASSIMP_stricmp(ext_real,ext2)) + return true; + + return false; +} + +// ------------------------------------------------------------------------------------------------ +// Get file extension from path +/*static*/ std::string BaseImporter::GetExtension (const std::string& pFile) +{ + std::string::size_type pos = pFile.find_last_of('.'); + + // no file extension at all + if( pos == std::string::npos) + return ""; + + std::string ret = pFile.substr(pos+1); + std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint + return ret; +} + +// ------------------------------------------------------------------------------------------------ +// Check for magic bytes at the beginning of the file. +/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, + const void* _magic, unsigned int num, unsigned int offset, unsigned int size) +{ + ai_assert(size <= 16 && _magic && num && pIOHandler); + + const char* magic = (const char*)_magic; + boost::scoped_ptr pStream (pIOHandler->Open(pFile)); + if (pStream.get() ) + { + // skip to offset + pStream->Seek(offset,aiOrigin_SET); + + // read 'size' characters from the file + char data[16]; + if(size != pStream->Read(data,1,size)) + return false; + + for (unsigned int i = 0; i < num; ++i) { + // also check against big endian versions of tokens with size 2,4 + // that's just for convinience, the chance that we cause conflicts + // is quite low and it can save some lines and prevent nasty bugs + if (2 == size) { + int16_t rev = *((int16_t*)magic); + ByteSwap::Swap(&rev); + if (*((int16_t*)data) == ((int16_t*)magic)[i] || *((int16_t*)data) == rev) + return true; + } + else if (4 == size) { + int32_t rev = *((int32_t*)magic); + ByteSwap::Swap(&rev); + if (*((int32_t*)data) == ((int32_t*)magic)[i] || *((int32_t*)data) == rev) + return true; + } + else { + // any length ... just compare + if(!::memcmp(magic,data,size)) + return true; + } + magic += size; + } + } + return false; +} // ------------------------------------------------------------------------------------------------ // Represents an import request struct LoadRequest { - LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map) + LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id) : file (_file) , flags (_flags) , refCnt (1) , scene (NULL) , loaded (false) + , id (_id) { if (_map) map = *_map; @@ -164,6 +253,7 @@ struct LoadRequest aiScene* scene; bool loaded; BatchLoader::PropertyMap map; + unsigned int id; bool operator== (const std::string& f) { return file == f; @@ -174,6 +264,10 @@ struct LoadRequest // BatchLoader::pimpl data structure struct Assimp::BatchData { + BatchData() + : next_id(0xffff) + {} + // IO system to be used for all imports IOSystem* pIOSystem; @@ -185,6 +279,9 @@ struct Assimp::BatchData // Base path std::string pathBase; + + // Id for next item + unsigned int next_id; }; // ------------------------------------------------------------------------------------------------ @@ -219,13 +316,15 @@ void BatchLoader::SetBasePath (const std::string& pBase) std::string::size_type ss,ss2; if (std::string::npos != (ss = data->pathBase.find_first_of('.'))) { - if (std::string::npos != (ss2 = data->pathBase.find_last_of('\\')) || - std::string::npos != (ss2 = data->pathBase.find_last_of('/'))) + if (std::string::npos != (ss2 = data->pathBase.find_last_of("\\/"))) { if (ss > ss2) data->pathBase.erase(ss2,data->pathBase.length()-ss2); } - else return; + else { + data->pathBase = ""; + return; + } } // make sure the directory is terminated properly @@ -235,7 +334,7 @@ void BatchLoader::SetBasePath (const std::string& pBase) } // ------------------------------------------------------------------------------------------------ -void BatchLoader::AddLoadRequest (const std::string& file, +unsigned int BatchLoader::AddLoadRequest (const std::string& file, unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/) { ai_assert(!file.empty()); @@ -245,8 +344,7 @@ void BatchLoader::AddLoadRequest (const std::string& file, // build a full path if this is a relative path and // we have a new base directory given - if (file.length() > 2 && file[1] != ':' && data->pathBase.length()) - { + if (file.length() > 2 && file[1] != ':' && data->pathBase.length()) { real = data->pathBase + file; } else real = file; @@ -258,32 +356,29 @@ void BatchLoader::AddLoadRequest (const std::string& file, // Call IOSystem's path comparison function here if (data->pIOSystem->ComparePaths((*it).file,real)) { + if (map) { + if (!((*it).map == *map)) + continue; + } + else if (!(*it).map.empty()) + continue; + (*it).refCnt++; - return; + return (*it).id; } } // no, we don't have it. So add it to the queue ... - data->requests.push_back(LoadRequest(real,steps,map)); + data->requests.push_back(LoadRequest(real,steps,map,data->next_id)); + return data->next_id++; } // ------------------------------------------------------------------------------------------------ -aiScene* BatchLoader::GetImport (const std::string& file) +aiScene* BatchLoader::GetImport (unsigned int which) { - // no threaded implementation for the moment - std::string real; - - // build a full path if this is a relative path and - // we have a new base directory given - if (file.length() > 2 && file[1] != ':' && data->pathBase.length()) - { - real = data->pathBase + file; - } - else real = file; for (std::list::iterator it = data->requests.begin();it != data->requests.end(); ++it) { - // Call IOSystem's path comparison function here - if (data->pIOSystem->ComparePaths((*it).file,real) && (*it).loaded) + if ((*it).id == which && (*it).loaded) { aiScene* sc = (*it).scene; if (!(--(*it).refCnt)) diff --git a/code/BaseImporter.h b/code/BaseImporter.h index e557faca6..f8359615e 100644 --- a/code/BaseImporter.h +++ b/code/BaseImporter.h @@ -52,6 +52,10 @@ namespace Assimp { class IOSystem; class Importer; +// utility to do char4 to uint32 in a portable manner +#define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \ + (string[1] << 16) + (string[2] << 8) + string[3])) + // --------------------------------------------------------------------------- /** Simple exception class to be thrown if an error occurs while importing. */ class ASSIMP_API ImportErrorException @@ -97,36 +101,48 @@ protected: public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * @param pFile Path and file name of the file to be examined. - * @param pIOHandler The IO handler to use for accessing any file. - * @return true if the class can read this file, false if not. - * - * @note Sometimes ASSIMP uses this method to determine whether a - * a given file extension is generally supported. In this case the - * file extension is passed in the pFile parameter, pIOHandler is NULL - */ + * + * The implementation should be as quick as possible. A check for + * the file extension is enough. If no suitable loader is found with + * this strategy, CanRead() is called again, the 'checkSig' parameter + * set to true this time. Now the implementation is expected to + * perform a full check of the file format, possibly searching the + * first bytes of the file for magic identifiers or keywords. + * + * @param pFile Path and file name of the file to be examined. + * @param pIOHandler The IO handler to use for accessing any file. + * @param checkSig Set to true if this method is called a second time. + * This time, the implementation may take more time to examine the + * contents of the file to be loaded for magic bytes, keywords, etc + * to be able to load files with unknown/not existent file extensions. + * @return true if the class can read this file, false if not. + * + * @note Sometimes ASSIMP uses this method to determine whether a + * a given file extension is generally supported. In this case the + * file extension is passed in the pFile parameter, pIOHandler is NULL + */ virtual bool CanRead( const std::string& pFile, - IOSystem* pIOHandler) const = 0; + IOSystem* pIOHandler, bool checkSig) const = 0; // ------------------------------------------------------------------- /** Imports the given file and returns the imported data. - * If the import succeeds, ownership of the data is transferred to - * the caller. If the import fails, NULL is returned. The function - * takes care that any partially constructed data is destroyed - * beforehand. - * - * @param pFile Path of the file to be imported. - * @param pIOHandler IO-Handler used to open this and possible other files. - * @return The imported data or NULL if failed. If it failed a - * human-readable error description can be retrieved by calling - * GetErrorText() - * - * @note This function is not intended to be overridden. Implement - * InternReadFile() to do the import. If an exception is thrown somewhere - * in InternReadFile(), this function will catch it and transform it into - * a suitable response to the caller. - */ + * If the import succeeds, ownership of the data is transferred to + * the caller. If the import fails, NULL is returned. The function + * takes care that any partially constructed data is destroyed + * beforehand. + * + * @param pFile Path of the file to be imported. + * @param pIOHandler IO-Handler used to open this and possible other files. + * @return The imported data or NULL if failed. If it failed a + * human-readable error description can be retrieved by calling + * GetErrorText() + * + * @note This function is not intended to be overridden. Implement + * InternReadFile() to do the import. If an exception is thrown somewhere + * in InternReadFile(), this function will catch it and transform it into + * a suitable response to the caller. + */ aiScene* ReadFile( const std::string& pFile, IOSystem* pIOHandler); @@ -135,19 +151,20 @@ public: * @return A description of the last error that occured. An empty * string if there was no error. */ - inline const std::string& GetErrorText() const - { return mErrorText; } + const std::string& GetErrorText() const { + return mErrorText; + } // ------------------------------------------------------------------- /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - * @param pImp Importer instance - * @param ppFlags Post-processing steps to be executed on the data - * returned by the loaders. This value is provided to allow some - * internal optimizations. - */ + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + * @param pImp Importer instance + * @param ppFlags Post-processing steps to be executed on the data + * returned by the loaders. This value is provided to allow some + * internal optimizations. + */ virtual void SetupProperties(const Importer* pImp /*, unsigned int ppFlags*/); @@ -157,7 +174,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * Importer implementations should append all file extensions * which they supported to the passed string. - * Example: "*.blabb;*.quak;*.gug;*.foo" (no comma after the last!) + * Example: "*.blabb;*.quak;*.gug;*.foo" (no delimiter after the last!) * @param append Output string */ virtual void GetExtensionList(std::string& append) = 0; @@ -169,23 +186,36 @@ protected: * expected to be correct. Override this function to implement the * actual importing. *
- * The output scene must meet the following requirements:
- * - at least a root node must be there
- * - aiMesh::mPrimitiveTypes may be 0. The types of primitives - * in the mesh are determined automatically in this case.
- * - the vertex data is stored in a pseudo-indexed "verbose" format. + * The output scene must meet the following requirements:
+ *
    + *
  • At least a root node must be there, even if its only purpose + * is to reference one mesh.
  • + *
  • aiMesh::mPrimitiveTypes may be 0. The types of primitives + * in the mesh are determined automatically in this case.
  • + *
  • the vertex data is stored in a pseudo-indexed "verbose" format. * In fact this means that every vertex that is referenced by * a face is unique. Or the other way round: a vertex index may - * not occur twice in a single aiMesh. - * - aiAnimation::mDuration may be -1. Assimp determines the length + * not occur twice in a single aiMesh.
  • + *
  • aiAnimation::mDuration may be -1. Assimp determines the length * of the animation automatically in this case as the length of - * the longest animation channel. - * - * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
    - * - at least one mesh must be there
    - * - at least one material must be there
    - * - there may be no meshes with 0 vertices or faces
    - * This won't be checked (except by the validation step), Assimp will + * the longest animation channel.
  • + *
  • aiMesh::mBitangents may be NULL if tangents and normals are + * given. In this case bitangents are computed as the cross product + * between normal and tangent.
  • + *
  • There needn't be a material. If none is there a default material + * is generated. However, it is recommended practice for loaders + * to generate a default material for yourself that matches the + * default material setting for the file format better than Assimp's + * generic default material. Note that default materials *should* + * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded + * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy) + * texture.
  • + *
+ * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
    + *
  • at least one mesh must be there
  • + *
  • there may be no meshes with 0 vertices or faces
  • + *
+ * This won't be checked (except by the validation step): Assimp will * crash if one of the conditions is not met! * * @param pFile Path of the file to be imported. @@ -218,12 +248,53 @@ protected: unsigned int numTokens, unsigned int searchBytes = 200); + + // ------------------------------------------------------------------- + /** @brief Check whether a file has a specific file extension + * @param pFile Input file + * @param ext0 Extension to check for. Lowercase characters only, no dot! + * @param ext1 Optional second extension + * @param ext2 Optional third extension + * @note Case-insensitive + */ + static bool SimpleExtensionCheck (const std::string& pFile, + const char* ext0, + const char* ext1 = NULL, + const char* ext2 = NULL); + + // ------------------------------------------------------------------- + /** @brief Extract file extension from a string + * @param pFile Input file + * @return Extension without trailing dot, all lowercase + */ + static std::string GetExtension (const std::string& pFile); + + // ------------------------------------------------------------------- + /** @brief Check whether a file starts with one or more magic tokens + * @param pFile Input file + * @param pIOHandler IO system to be used + * @param magic n magic tokens + * @params num Size of magic + * @param offset Offset from file start where tokens are located + * @param Size of one token, in bytes. Maximally 16 bytes. + * @return true if one of the given tokens was found + * + * @note For convinence, the check is also performed for the + * byte-swapped variant of all tokens (big endian). Only for + * tokens of size 2,4. + */ + static bool CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, + const void* magic, + unsigned int num, + unsigned int offset = 0, + unsigned int size = 4); + #if 0 /** TODO **/ // ------------------------------------------------------------------- /** An utility for all text file loaders. It converts a file to our - * ASCII/UTF8 character set. Special unicode characters are lost. - * - * @param buffer Input buffer. Needn't be terminated with zero. + * ASCII/UTF8 character set. Special unicode characters are lost. + * + * @param buffer Input buffer. Needn't be terminated with zero. * @param length Length of the input buffer, in bytes. Receives the * number of output characters, excluding the terminal char. * @return true if the source format did not match our internal @@ -266,10 +337,18 @@ public: Importer::IntPropertyMap ints; Importer::FloatPropertyMap floats; Importer::StringPropertyMap strings; + + bool operator == (const PropertyMap& prop) const { + return ints == prop.ints && floats == prop.floats && strings == prop.strings; + } + + bool empty () const { + return ints.empty() && floats.empty() && strings.empty(); + } }; - public: + /** Construct a batch loader from a given IO system */ @@ -293,8 +372,10 @@ public: * @param file File to be loaded * @param steps Steps to be executed on the file * @param map Optional configuration properties + * @return 'Load request channel' - an unique ID that can later + * be used to access the imported file data. */ - void AddLoadRequest (const std::string& file, + unsigned int AddLoadRequest (const std::string& file, unsigned int steps = 0, const PropertyMap* map = NULL); @@ -304,11 +385,11 @@ public: * If an import is requested several times, this function * can be called several times, too. * - * @param file File name of the scene + * @param which LRWC returned by AddLoadRequest(). * @return NULL if there is no scene with this file name * in the queue of the scene hasn't been loaded yet. */ - aiScene* GetImport (const std::string& file); + aiScene* GetImport (unsigned int which); /** Waits until all scenes have been loaded. @@ -321,7 +402,6 @@ private: BatchData* data; }; - } // end of namespace Assimp #endif // AI_BASEIMPORTER_H_INC diff --git a/code/BaseProcess.cpp b/code/BaseProcess.cpp index 0ae4d9ab5..ed639fef4 100644 --- a/code/BaseProcess.cpp +++ b/code/BaseProcess.cpp @@ -69,7 +69,7 @@ void BaseProcess::ExecuteOnScene( Importer* pImp) // catch exceptions thrown inside the PostProcess-Step try { - this->Execute(pImp->mScene); + Execute(pImp->mScene); } catch( ImportErrorException* exception) { diff --git a/code/CalcTangentsProcess.cpp b/code/CalcTangentsProcess.cpp index 21bc6a61f..d0204fd20 100644 --- a/code/CalcTangentsProcess.cpp +++ b/code/CalcTangentsProcess.cpp @@ -126,7 +126,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) const float angleEpsilon = 0.9999f; std::vector vertexDone( pMesh->mNumVertices, false); - const float qnan = std::numeric_limits::quiet_NaN(); + const float qnan = get_qnan(); // create space for the tangents and bitangents pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; @@ -149,8 +149,10 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // their tangent vectors are set to qnan. for (unsigned int i = 0; i < face.mNumIndices;++i) { - vertexDone[face.mIndices[i]] = true; - meshTang [face.mIndices[i]] = qnan; + register unsigned int idx = face.mIndices[i]; + vertexDone [idx] = true; + meshTang [idx] = qnan; + meshBitang [idx] = qnan; } continue; @@ -218,10 +220,10 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) vertexFinder = &_vertexFinder; posEpsilon = ComputePositionEpsilon(pMesh); } - std::vector verticesFound; const float fLimit = cosf(this->configMaxAngle); + std::vector closeVertices; // in the second pass we now smooth out all tangents and bitangents at the same local position // if they are not too far off. @@ -234,12 +236,14 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) const aiVector3D& origNorm = pMesh->mNormals[a]; const aiVector3D& origTang = pMesh->mTangents[a]; const aiVector3D& origBitang = pMesh->mBitangents[a]; - std::vector closeVertices; - closeVertices.push_back( a); + closeVertices.clear(); // find all vertices close to that position vertexFinder->FindPositions( origPos, posEpsilon, verticesFound); + closeVertices.reserve (verticesFound.size()+5); + closeVertices.push_back( a); + // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent for( unsigned int b = 0; b < verticesFound.size(); b++) { diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index 5189455c0..a892a7f68 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -67,22 +67,16 @@ ColladaLoader::~ColladaLoader() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { // check file extension - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); - - if( extension == ".dae") + std::string extension = GetExtension(pFile); + + if( extension == "dae") return true; // XML - too generic, we need to open the file and search for typical keywords - if( extension == ".xml") { + if( extension == "xml" || !extension.length() || checkSig) { /* If CanRead() is called in order to check whether we * support a specific file extension in general pIOHandler * might be NULL and it's our duty to return true here. @@ -94,6 +88,13 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler) con return false; } +// ------------------------------------------------------------------------------------------------ +// Get file extension list +void ColladaLoader::GetExtensionList( std::string& append) +{ + append.append("*.dae"); +} + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) @@ -166,7 +167,8 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla aiNode* node = new aiNode(); // now setup the name of the node. We take the name if not empty, otherwise the collada ID - if (!pNode->mName.empty()) + // FIX: Workaround for XSI calling the instanced visual scene 'untitled' by default. + if (!pNode->mName.empty() && pNode->mName != "untitled") node->mName.Set(pNode->mName); else if (!pNode->mID.empty()) node->mName.Set(pNode->mID); @@ -632,7 +634,7 @@ void ColladaLoader::AddTexture ( Assimp::MaterialHelper& mat, const ColladaParse _AI_MATKEY_TEXTURE_BASE,type,idx); // mapping mode - int map = map = aiTextureMapMode_Clamp; + int map = aiTextureMapMode_Clamp; if (sampler.mWrapU) map = aiTextureMapMode_Wrap; if (sampler.mWrapU && sampler.mMirrorU) @@ -896,4 +898,4 @@ void ColladaLoader::ConvertPath (aiString& ss) } } -#endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER \ No newline at end of file +#endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER diff --git a/code/ColladaLoader.h b/code/ColladaLoader.h index 845667621..52362b89d 100644 --- a/code/ColladaLoader.h +++ b/code/ColladaLoader.h @@ -90,16 +90,13 @@ protected: public: /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList( std::string& append) - { - append.append("*.dae"); - } + void GetExtensionList( std::string& append); /** Imports the given file into the given scene structure. * See BaseImporter::InternReadFile() for details diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index d83d653b3..85a3deb4d 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -1618,8 +1618,8 @@ void ColladaParser::ReadSceneLibrary() } else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_visual_scenes") != 0) - ThrowException( "Expected end of \"library_visual_scenes\" element."); + if( strcmp( mReader->getNodeName(), "library_visual_scenes") == 0) + //ThrowException( "Expected end of \"library_visual_scenes\" element."); break; } @@ -2106,4 +2106,4 @@ Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemant return IT_Invalid; } -#endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER \ No newline at end of file +#endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER diff --git a/code/ColladaParser.h b/code/ColladaParser.h index c26360f41..37b5876b8 100644 --- a/code/ColladaParser.h +++ b/code/ColladaParser.h @@ -202,7 +202,7 @@ protected: /** Reads the text contents of an element, returns NULL if not given. Skips leading whitespace. */ - const char* ColladaParser::TestTextContent(); + const char* TestTextContent(); /** Reads a single bool from current text content */ bool ReadBoolFromTextContent(); diff --git a/code/DXFLoader.cpp b/code/DXFLoader.cpp index bfe029122..c7fe9b803 100644 --- a/code/DXFLoader.cpp +++ b/code/DXFLoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the DXF importer class */ +/** @file DXFLoader.cpp + * @brief Implementation of the DXF importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_DXF_IMPORTER @@ -77,7 +79,7 @@ static aiColor4D g_aclrDxfIndexColors[] = #define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0])) // invalid/unassigned color value -aiColor4D g_clrInvalid = aiColor4D(std::numeric_limits::quiet_NaN(),0.f,0.f,1.f); +aiColor4D g_clrInvalid = aiColor4D(get_qnan(),0.f,0.f,1.f); // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer @@ -95,19 +97,15 @@ DXFImporter::~DXFImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); + return SimpleExtensionCheck(pFile,"dxf"); +} - return !(extension.length() != 4 || extension[0] != '.' || - extension[1] != 'd' && extension[1] != 'D' || - extension[2] != 'x' && extension[2] != 'X' || - extension[3] != 'f' && extension[3] != 'F'); +// ------------------------------------------------------------------------------------------------ +void DXFImporter::GetExtensionList(std::string& append) +{ + append.append("*.dxf"); } // ------------------------------------------------------------------------------------------------ diff --git a/code/DXFLoader.h b/code/DXFLoader.h index 996ddd4b4..f7c8f0ab7 100644 --- a/code/DXFLoader.h +++ b/code/DXFLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the .dxf importer class. */ +/** @file DXFLoader.h + * @brief Declaration of the .dxf importer class. + */ #ifndef AI_DXFLOADER_H_INCLUDED #define AI_DXFLOADER_H_INCLUDED @@ -85,7 +87,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -93,10 +96,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.dxf"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/DefaultLogger.cpp b/code/DefaultLogger.cpp index 6d6df287d..099b0f2e6 100644 --- a/code/DefaultLogger.cpp +++ b/code/DefaultLogger.cpp @@ -51,6 +51,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StdOStreamLogStream.h" #include "FileLogStream.h" +#ifndef ASSIMP_BUILD_SINGLETHREADED +# include +# include + +boost::mutex loggerMutex; +#endif + namespace Assimp { // ---------------------------------------------------------------------------------- @@ -119,6 +126,11 @@ Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/, unsigned int defStreams /*= DLS_DEBUGGER | DLS_FILE*/, IOSystem* io /*= NULL*/) { + // enter the mutex here to avoid concurrency problems +#ifndef ASSIMP_BUILD_SINGLETHREADED + boost::mutex::scoped_lock lock(loggerMutex); +#endif + if (m_pLogger && !isNullLogger() ) delete m_pLogger; @@ -146,31 +158,56 @@ Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/, // ---------------------------------------------------------------------------------- void Logger::debug(const std::string &message) { - ai_assert(message.length()<=Logger::MAX_LOG_MESSAGE_LENGTH); + + // SECURITY FIX: otherwise it's easy to produce overruns ... + if (message.length()>MAX_LOG_MESSAGE_LENGTH) { + ai_assert(false); + return; + } return OnDebug(message.c_str()); } // ---------------------------------------------------------------------------------- void Logger::info(const std::string &message) { - ai_assert(message.length()<=Logger::MAX_LOG_MESSAGE_LENGTH); + + // SECURITY FIX: otherwise it's easy to produce overruns ... + if (message.length()>MAX_LOG_MESSAGE_LENGTH) { + ai_assert(false); + return; + } return OnInfo(message.c_str()); } // ---------------------------------------------------------------------------------- void Logger::warn(const std::string &message) { - ai_assert(message.length()<=Logger::MAX_LOG_MESSAGE_LENGTH); + + // SECURITY FIX: otherwise it's easy to produce overruns ... + if (message.length()>MAX_LOG_MESSAGE_LENGTH) { + ai_assert(false); + return; + } return OnWarn(message.c_str()); } // ---------------------------------------------------------------------------------- void Logger::error(const std::string &message) { - ai_assert(message.length()<=Logger::MAX_LOG_MESSAGE_LENGTH); + + // SECURITY FIX: otherwise it's easy to produce overruns ... + if (message.length()>MAX_LOG_MESSAGE_LENGTH) { + ai_assert(false); + return; + } return OnError(message.c_str()); } // ---------------------------------------------------------------------------------- void DefaultLogger::set( Logger *logger ) { + // enter the mutex here to avoid concurrency problems +#ifndef ASSIMP_BUILD_SINGLETHREADED + boost::mutex::scoped_lock lock(loggerMutex); +#endif + if (!logger)logger = &s_pNullLogger; if (m_pLogger && !isNullLogger() ) delete m_pLogger; @@ -195,6 +232,11 @@ Logger *DefaultLogger::get() // Kills the only instance void DefaultLogger::kill() { + // enter the mutex here to avoid concurrency problems +#ifndef ASSIMP_BUILD_SINGLETHREADED + boost::mutex::scoped_lock lock(loggerMutex); +#endif + if (m_pLogger != &s_pNullLogger)return; delete m_pLogger; m_pLogger = &s_pNullLogger; @@ -243,23 +285,14 @@ void DefaultLogger::OnError( const char* message ) WriteToStreams( msg, Logger::ERR ); } -// ---------------------------------------------------------------------------------- -// Severity setter -void DefaultLogger::setLogSeverity( LogSeverity log_severity ) -{ - m_Severity = log_severity; -} - // ---------------------------------------------------------------------------------- // Attachs a new stream -void DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) +bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) { if (!pStream) - return; + return false; - // fix (Aramis) - if (0 == severity) - { + if (0 == severity) { severity = Logger::INFO | Logger::ERR | Logger::WARN | Logger::DEBUGGING; } @@ -270,24 +303,23 @@ void DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) if ( (*it)->m_pStream == pStream ) { (*it)->m_uiErrorSeverity |= severity; - return; + return true; } } LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream ); m_StreamArray.push_back( pInfo ); + return true; } // ---------------------------------------------------------------------------------- // Detatch a stream -void DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) +bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) { if (!pStream) - return; + return false; - // fix (Aramis) - if (0 == severity) - { + if (0 == severity) { severity = Logger::INFO | Logger::ERR | Logger::WARN | Logger::DEBUGGING; } @@ -303,15 +335,17 @@ void DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) m_StreamArray.erase( it ); break; } + return true; } } + return false; } // ---------------------------------------------------------------------------------- // Constructor DefaultLogger::DefaultLogger(LogSeverity severity) - : m_Severity ( severity ) + : Logger ( severity ) , noRepeatMsg (false) , lastLen( 0 ) { diff --git a/code/FindDegenerates.cpp b/code/FindDegenerates.cpp index 3ab4b1b19..c1d7f134b 100644 --- a/code/FindDegenerates.cpp +++ b/code/FindDegenerates.cpp @@ -39,8 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the DeterminePTypeHelperProcess and - * SortByPTypeProcess post-process steps. +/** @file FindDegenerates.cpp + * @brief Implementation of the FindDegenerates post-process step. */ #include "AssimpPCH.h" @@ -54,8 +54,8 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer FindDegeneratesProcess::FindDegeneratesProcess() -{ -} +: configRemoveDegenerates (false) +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well @@ -71,83 +71,144 @@ bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const return 0 != (pFlags & aiProcess_FindDegenerates); } +// ------------------------------------------------------------------------------------------------ +// Setup import configuration +void FindDegeneratesProcess::SetupProperties(const Importer* pImp) +{ + // Get the current value of AI_CONFIG_PP_FD_REMOVE + configRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0)); +} + // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void FindDegeneratesProcess::Execute( aiScene* pScene) { DefaultLogger::get()->debug("FindDegeneratesProcess begin"); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - aiMesh* mesh = pScene->mMeshes[i]; - mesh->mPrimitiveTypes = 0; - - unsigned int deg = 0; - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) - { - aiFace& face = mesh->mFaces[a]; - bool first = true; - - // check whether the face contains degenerated entries - for (register unsigned int i = 0; i < face.mNumIndices; ++i) - { - for (register unsigned int a = i+1; a < face.mNumIndices; ++a) - { - if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[a]]) - { - // we have found a matching vertex position - // remove the corresponding index from the array - for (unsigned int m = a; m < face.mNumIndices-1; ++m) - { - face.mIndices[m] = face.mIndices[m+1]; - } - --a; - --face.mNumIndices; - - // NOTE: we set the removed vertex index to an unique value - // to make sure the developer gets notified when his - // application attemps to access this data. - face.mIndices[face.mNumIndices] = 0xdeadbeef; - - - if(first) - { - ++deg; - first = false; - } - } - } - } - - // We need to update the primitive flags array of the mesh. - // Unfortunately it is not possible to execute - // FindDegenerates before DeterminePType. The latter does - // nothing if the primitive flags have already been set by - // the loader - our changes would be ignored. Although - // we could use some tricks regarding - i.e setting - // mPrimitiveTypes to 0 in every case - but this is the cleanest - // way and causes no additional dependencies in the pipeline. - switch (face.mNumIndices) - { - case 1u: - mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2u: - mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3u: - mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - }; - } - if (deg && !DefaultLogger::isNullLogger()) - { - char s[64]; - ASSIMP_itoa10(s,deg); - DefaultLogger::get()->warn(std::string("Found ") + s + " degenerated primitives"); - } + for (unsigned int i = 0; i < pScene->mNumMeshes;++i){ + ExecuteOnMesh( pScene->mMeshes[i]); } DefaultLogger::get()->debug("FindDegeneratesProcess finished"); } + +// ------------------------------------------------------------------------------------------------ +// Executes the post processing step on the given imported mesh +void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) +{ + mesh->mPrimitiveTypes = 0; + + std::vector remove_me; + if (configRemoveDegenerates) + remove_me.resize(mesh->mNumFaces,false); + + unsigned int deg = 0; + for (unsigned int a = 0; a < mesh->mNumFaces; ++a) + { + aiFace& face = mesh->mFaces[a]; + bool first = true; + + // check whether the face contains degenerated entries + for (register unsigned int i = 0; i < face.mNumIndices; ++i) + { + for (register unsigned int t = i+1; t < face.mNumIndices; ++t) + { + if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) + { + // we have found a matching vertex position + // remove the corresponding index from the array + --face.mNumIndices; + for (unsigned int m = t; m < face.mNumIndices; ++m) + { + face.mIndices[m] = face.mIndices[m+1]; + } + --t; + + // NOTE: we set the removed vertex index to an unique value + // to make sure the developer gets notified when his + // application attemps to access this data. + face.mIndices[face.mNumIndices] = 0xdeadbeef; + + if(first) + { + ++deg; + first = false; + } + + if (configRemoveDegenerates) { + remove_me[a] = true; + goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby! + } + } + } + } + + // We need to update the primitive flags array of the mesh. + // Unfortunately it is not possible to execute + // FindDegenerates before DeterminePType. The latter does + // nothing if the primitive flags have already been set by + // the loader - our changes would be ignored. Although + // we could use some tricks regarding - i.e setting + // mPrimitiveTypes to 0 in every case - but this is the cleanest + // way and causes no additional dependencies in the pipeline. + switch (face.mNumIndices) + { + case 1u: + mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 2u: + mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 3u: + mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + break; + }; +evil_jump_outside: + continue; + } + + // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import + if (configRemoveDegenerates && deg) { + unsigned int n = 0; + for (unsigned int a = 0; a < mesh->mNumFaces; ++a) + { + aiFace& face_src = mesh->mFaces[a]; + if (!remove_me[a]) { + aiFace& face_dest = mesh->mFaces[n++]; + + // Do a manual copy, keep the index array + face_dest.mNumIndices = face_src.mNumIndices; + face_dest.mIndices = face_src.mIndices; + + // clear source + face_src.mNumIndices = 0; + face_src.mIndices = NULL; + } + else { + // Otherwise delete it if we don't need this face + delete[] face_src.mIndices; + face_src.mIndices = NULL; + face_src.mNumIndices = 0; + } + } + // Just leave the rest of the array unreferenced, we don't care for now + mesh->mNumFaces = n; + if (!mesh->mNumFaces) { + // WTF!? + // OK ... for completeness and because I'm not yet tired, + // let's write code that willl hopefully never be called + // (famous last words) + + // OK ... bad idea. + throw new ImportErrorException("Mesh is empty after removal of degenerated primitives ... WTF!?"); + } + } + + if (deg && !DefaultLogger::isNullLogger()) + { + char s[64]; + ASSIMP_itoa10(s,deg); + DefaultLogger::get()->warn(std::string("Found ") + s + " degenerated primitives"); + } +} diff --git a/code/FindDegenerates.h b/code/FindDegenerates.h index 15abb3af5..e582f1525 100644 --- a/code/FindDegenerates.h +++ b/code/FindDegenerates.h @@ -66,14 +66,44 @@ protected: ~FindDegeneratesProcess(); public: + // ------------------------------------------------------------------- + // Check whether step is active bool IsActive( unsigned int pFlags) const; // ------------------------------------------------------------------- + // Execute step on a given scene void Execute( aiScene* pScene); + // ------------------------------------------------------------------- + // Setup import settings + void SetupProperties(const Importer* pImp); + + // ------------------------------------------------------------------- + // Execute step on a given mesh + void ExecuteOnMesh( aiMesh* mesh); + + + // ------------------------------------------------------------------- + /** @brief Enable the instant removal of degenerated primitives + * @param d hm ... difficult to guess what this means, hu!? + */ + void EnableInstantRemoval(bool d) { + configRemoveDegenerates = d; + } + + // ------------------------------------------------------------------- + /** @brief Check whether instant removal is currently enabled + * @return ... + */ + bool IsInstantRemoval() const { + return configRemoveDegenerates; + } + private: + //! Configuration option: remove degenerates faces immediately + bool configRemoveDegenerates; }; } diff --git a/code/GenFaceNormalsProcess.cpp b/code/GenFaceNormalsProcess.cpp index d00086358..8299aafe8 100644 --- a/code/GenFaceNormalsProcess.cpp +++ b/code/GenFaceNormalsProcess.cpp @@ -111,7 +111,7 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh) // allocate an array to hold the output normals pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - const float qnan = std::numeric_limits::quiet_NaN(); + const float qnan = get_qnan(); // iterate through all faces and compute per-face normals but store // them per-vertex. diff --git a/code/HMPFileData.h b/code/HMPFileData.h index b236bc376..5e14a3538 100644 --- a/code/HMPFileData.h +++ b/code/HMPFileData.h @@ -46,17 +46,15 @@ namespace HMP { #include "./../include/Compiler/pushpack1.h" -// to make it easier for ourselfes, we test the magic word against both "endianesses" -#define HMP_MAKE(string) ((uint32_t)((string[0] << 24) + (string[1] << 16) + (string[2] << 8) + string[3])) +// to make it easier for us, we test the magic word against both "endianesses" +#define AI_HMP_MAGIC_NUMBER_BE_4 AI_MAKE_MAGIC("HMP4") +#define AI_HMP_MAGIC_NUMBER_LE_4 AI_MAKE_MAGIC("4PMH") -#define AI_HMP_MAGIC_NUMBER_BE_4 HMP_MAKE("HMP4") -#define AI_HMP_MAGIC_NUMBER_LE_4 HMP_MAKE("4PMH") +#define AI_HMP_MAGIC_NUMBER_BE_5 AI_MAKE_MAGIC("HMP5") +#define AI_HMP_MAGIC_NUMBER_LE_5 AI_MAKE_MAGIC("5PMH") -#define AI_HMP_MAGIC_NUMBER_BE_5 HMP_MAKE("HMP5") -#define AI_HMP_MAGIC_NUMBER_LE_5 HMP_MAKE("5PMH") - -#define AI_HMP_MAGIC_NUMBER_BE_7 HMP_MAKE("HMP7") -#define AI_HMP_MAGIC_NUMBER_LE_7 HMP_MAKE("7PMH") +#define AI_HMP_MAGIC_NUMBER_BE_7 AI_MAKE_MAGIC("HMP7") +#define AI_HMP_MAGIC_NUMBER_LE_7 AI_MAKE_MAGIC("7PMH") // --------------------------------------------------------------------------- /** Data structure for the header of a HMP5 file. diff --git a/code/HMPLoader.cpp b/code/HMPLoader.cpp index f62f6779f..7d54b6bce 100644 --- a/code/HMPLoader.cpp +++ b/code/HMPLoader.cpp @@ -67,25 +67,34 @@ HMPImporter::~HMPImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool HMPImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool HMPImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { - (void)pIOHandler; //this avoids the compiler warning of unused element - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); + const std::string extension = GetExtension(pFile); + if (extension == "hmp" ) + return true; - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); + // if check for extension is not enough, check for the magic tokens + if (!extension.length() || cs) { + uint32_t tokens[3]; + tokens[0] = AI_HMP_MAGIC_NUMBER_LE_4; + tokens[1] = AI_HMP_MAGIC_NUMBER_LE_5; + tokens[2] = AI_HMP_MAGIC_NUMBER_LE_7; + return CheckMagicToken(pIOHandler,pFile,tokens,3,0); + } + return false; +} - return extension == ".hmp"; +// ------------------------------------------------------------------------------------------------ +// Get list of all file extensions that are handled by this loader +void HMPImporter::GetExtensionList(std::string& append) +{ + append.append("*.hmp"); } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void HMPImporter::InternReadFile( const std::string& pFile, - aiScene* _pScene, IOSystem* _pIOHandler) + aiScene* _pScene, IOSystem* _pIOHandler) { pScene = _pScene; pIOHandler = _pIOHandler; @@ -225,7 +234,8 @@ void HMPImporter::InternReadFile_HMP5( ) } // generate texture coordinates if necessary - if (pcHeader->numskins)GenerateTextureCoords(width,height); + if (pcHeader->numskins) + GenerateTextureCoords(width,height); // now build a list of faces CreateOutputFaceList(width,height); @@ -477,7 +487,7 @@ void HMPImporter::GenerateTextureCoords( for (unsigned int y = 0; y < height;++y) { for (unsigned int x = 0; x < width;++x,++uv) { - uv->y = 1.0f-fY*y; + uv->y = fY*y; uv->x = fX*x; uv->z = 0.0f; } diff --git a/code/HMPLoader.h b/code/HMPLoader.h index 441d113c2..2344f364b 100644 --- a/code/HMPLoader.h +++ b/code/HMPLoader.h @@ -37,9 +37,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -//! -//! @file Declaration of the HMP importer class -//! +/** @file HMPLoader.h + * @brief Declaration of the HMP importer class + */ #ifndef AI_HMPLOADER_H_INCLUDED #define AI_HMPLOADER_H_INCLUDED @@ -75,8 +75,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -85,10 +87,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.hmp"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/HalfLifeFileData.h b/code/HalfLifeFileData.h index 28c1ed983..e239f1998 100644 --- a/code/HalfLifeFileData.h +++ b/code/HalfLifeFileData.h @@ -57,10 +57,10 @@ namespace Assimp { namespace MDL { // magic bytes used in Half Life 2 MDL models -#define AI_MDL_MAGIC_NUMBER_BE_HL2a MDL_MAKE("IDST") -#define AI_MDL_MAGIC_NUMBER_LE_HL2a MDL_MAKE("TSDI") -#define AI_MDL_MAGIC_NUMBER_BE_HL2b MDL_MAKE("IDSQ") -#define AI_MDL_MAGIC_NUMBER_LE_HL2b MDL_MAKE("QSDI") +#define AI_MDL_MAGIC_NUMBER_BE_HL2a AI_MAKE_MAGIC("IDST") +#define AI_MDL_MAGIC_NUMBER_LE_HL2a AI_MAKE_MAGIC("TSDI") +#define AI_MDL_MAGIC_NUMBER_BE_HL2b AI_MAKE_MAGIC("IDSQ") +#define AI_MDL_MAGIC_NUMBER_LE_HL2b AI_MAKE_MAGIC("QSDI") // --------------------------------------------------------------------------- /** \struct Header_HL2 diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index f3622badd..266ad1ffb 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the Irr importer class */ +/** @file IRRLoader.cpp + * @brief Implementation of the Irr importer class + */ #include "AssimpPCH.h" @@ -81,26 +83,17 @@ IRRImporter::~IRRImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { /* NOTE: A simple check for the file extension is not enough * here. Irrmesh and irr are easy, but xml is too generic * and could be collada, too. So we need to open the file and * search for typical tokens. */ - - std::string::size_type pos = pFile.find_last_of('.'); - - // no file extension - can't read - if( pos == std::string::npos) - return false; - - std::string extension = pFile.substr( pos); - for (std::string::iterator i = extension.begin(); i != extension.end();++i) - *i = ::tolower(*i); - - if (extension == ".irr")return true; - else if (extension == ".xml") + const std::string extension = GetExtension(pFile); + + if (extension == "irr")return true; + else if (extension == "xml" || checkSig) { /* If CanRead() is called in order to check whether we * support a specific file extension in general pIOHandler @@ -128,11 +121,13 @@ void IRRImporter::SetupProperties(const Importer* pImp) { // read the output frame rate of all node animation channels fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS,100); - if (!fps) - { + if (fps < 10.) { DefaultLogger::get()->error("IRR: Invalid FPS configuration"); fps = 100; } + + // AI_CONFIG_FAVOUR_SPEED + configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0)); } // ------------------------------------------------------------------------------------------------ @@ -595,7 +590,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector mat->mNumAllocated) { delete[] mat->mProperties; - mat->mProperties = new aiMaterialProperty*[p.size()]; + mat->mProperties = new aiMaterialProperty*[p.size()*2]; + + mat->mNumAllocated = p.size()*2; } mat->mNumProperties = (unsigned int)p.size(); ::memcpy(mat->mProperties,&p[0],sizeof(void*)*mat->mNumProperties); @@ -680,7 +677,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // Get the loaded mesh from the scene and add it to // the list of all scenes to be attached to the // graph we're currently building - aiScene* scene = batch.GetImport(root->meshPath); + aiScene* scene = batch.GetImport(root->id); if (!scene) { DefaultLogger::get()->error("IRR: Unable to load external file: " @@ -688,6 +685,8 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, break; } attach.push_back(AttachmentInfo(scene,rootOut)); + +#if 0 meshTrafoAssign = 1; // If the root node of the scene is animated - and *this* node @@ -721,8 +720,9 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, } } } - if (1 == meshTrafoAssign) - scene->mRootNode->mTransformation *= AI_TO_IRR_MATRIX; +#endif + // if (1 == meshTrafoAssign) + // scene->mRootNode->mTransformation = AI_TO_IRR_MATRIX * scene->mRootNode->mTransformation; // Now combine the material we've loaded for this mesh @@ -748,7 +748,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // NOTE: Each mesh should have exactly one material assigned, // but we do it in a separate loop if this behaviour changes - // in the future. + // in future. for (unsigned int i = 0; i < scene->mNumMeshes;++i) { // Process material flags @@ -901,8 +901,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize; rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes]; - for (unsigned int a = 0; a < rootOut->mNumMeshes;++a) - { + for (unsigned int a = 0; a < rootOut->mNumMeshes;++a) { rootOut->mMeshes[a] = oldMeshSize+a; } } @@ -913,6 +912,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, // Now compute the final local transformation matrix of the // node from the given translation, rotation and scaling values. // (the rotation is given in Euler angles, XYZ order) + std::swap((float&)root->rotation.z,(float&)root->rotation.y); rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation) ); // apply scaling @@ -920,20 +920,20 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene, mat.a1 *= root->scaling.x; mat.b1 *= root->scaling.x; mat.c1 *= root->scaling.x; - mat.a2 *= root->scaling.y; - mat.b2 *= root->scaling.y; - mat.c2 *= root->scaling.y; - mat.a3 *= root->scaling.z; - mat.b3 *= root->scaling.z; - mat.c3 *= root->scaling.z; + mat.a2 *= root->scaling.z; + mat.b2 *= root->scaling.z; + mat.c2 *= root->scaling.z; + mat.a3 *= root->scaling.y; + mat.b3 *= root->scaling.y; + mat.c3 *= root->scaling.y; // apply translation mat.a4 += root->position.x; - mat.b4 += root->position.y; - mat.c4 += root->position.z; + mat.b4 += root->position.z; + mat.c4 += root->position.y; - if (meshTrafoAssign == 2) - mat *= AI_TO_IRR_MATRIX; + //if (meshTrafoAssign == 2) + // mat *= AI_TO_IRR_MATRIX; // now compute animations for the node ComputeAnimations(root,rootOut, anims); @@ -1446,7 +1446,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, } else { - batch.AddLoadRequest(prop.value,pp,&map); + curNode->id = batch.AddLoadRequest(prop.value,pp,&map); curNode->meshPath = prop.value; } } @@ -1528,8 +1528,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Now iterate through all cameras and compute their final (horizontal) FOV */ for (std::vector::iterator it = cameras.begin(), end = cameras.end(); - it != end; ++it) - { + it != end; ++it) { aiCamera* cam = *it; if (cam->mAspect) // screen aspect could be missing { @@ -1625,8 +1624,8 @@ void IRRImporter::InternReadFile( const std::string& pFile, * attachment points in the scenegraph. */ SceneCombiner::MergeScenes(&pScene,tempScene,attach, - AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES | - AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES); + AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( + AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : 0)); /* If we have no meshes | no materials now set the INCOMPLETE @@ -1639,11 +1638,6 @@ void IRRImporter::InternReadFile( const std::string& pFile, pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; } - - // transformation matrix to convert from IRRMESH to ASSIMP coordinates - pScene->mRootNode->mTransformation *= AI_TO_IRR_MATRIX; - - /* Finished ... everything destructs automatically and all * temporary scenes have already been deleted by MergeScenes() */ diff --git a/code/IRRLoader.h b/code/IRRLoader.h index bf7678321..d8d796de2 100644 --- a/code/IRRLoader.h +++ b/code/IRRLoader.h @@ -39,8 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** @file Declaration of the .irrMesh (Irrlight Engine Mesh Format) - importer class. +/** @file IRRLoader.h + * @brief Declaration of the .irrMesh (Irrlight Engine Mesh Format) + * importer class. */ #ifndef AI_IRRLOADER_H_INCLUDED #define AI_IRRLOADER_H_INCLUDED @@ -75,7 +76,8 @@ public: /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -203,6 +205,7 @@ private: // Meshes: path to the mesh to be loaded std::string meshPath; + unsigned int id; // Meshes: List of materials to be assigned // along with their corresponding material flags @@ -297,8 +300,11 @@ private: private: + /** Configuration option: desired output FPS */ double fps; + /** Configuration option: speed flag was set? */ + bool configSpeedFlag; }; } // end of namespace Assimp diff --git a/code/IRRMeshLoader.cpp b/code/IRRMeshLoader.cpp index 6dab0d319..b2df463c5 100644 --- a/code/IRRMeshLoader.cpp +++ b/code/IRRMeshLoader.cpp @@ -67,26 +67,17 @@ IRRMeshImporter::~IRRMeshImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool IRRMeshImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool IRRMeshImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { /* NOTE: A simple check for the file extension is not enough * here. Irrmesh and irr are easy, but xml is too generic * and could be collada, too. So we need to open the file and * search for typical tokens. */ + const std::string extension = GetExtension(pFile); - std::string::size_type pos = pFile.find_last_of('.'); - - // no file extension - can't read - if( pos == std::string::npos) - return false; - - std::string extension = pFile.substr( pos); - for (std::string::iterator i = extension.begin(); i != extension.end();++i) - *i = ::tolower(*i); - - if (extension == ".irrmesh")return true; - else if (extension == ".xml") + if (extension == "irrmesh")return true; + else if (extension == "xml" || checkSig) { /* If CanRead() is called to check whether the loader * supports a specific file extension in general we @@ -99,6 +90,14 @@ bool IRRMeshImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) c return false; } +// ------------------------------------------------------------------------------------------------ +// Get a list of all file extensions which are handled by this class +void IRRMeshImporter::GetExtensionList(std::string& append) +{ + // fixme: consider cleaner handling of xml extension + append.append("*.xml;*.irrmesh"); +} + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void IRRMeshImporter::InternReadFile( const std::string& pFile, diff --git a/code/IRRMeshLoader.h b/code/IRRMeshLoader.h index ab5137fc3..6d9b71173 100644 --- a/code/IRRMeshLoader.h +++ b/code/IRRMeshLoader.h @@ -38,8 +38,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the .irrMesh (Irrlight Engine Mesh Format) - importer class. */ +/** @file IRRMeshLoader.h + * @brief Declaration of the .irrMesh (Irrlight Engine Mesh Format) + * importer class. + */ #ifndef AI_IRRMESHLOADER_H_INCLUDED #define AI_IRRMESHLOADER_H_INCLUDED @@ -72,7 +74,8 @@ public: /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -80,16 +83,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - - /* NOTE: The file extenxsion .xml is too generic. We'll - * need to open the file in CanRead() and check whether it is - * a real irrlicht file - */ - - append.append("*.xml;*.irrmesh"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/IRRShared.cpp b/code/IRRShared.cpp index bc09d0404..8f2b53474 100644 --- a/code/IRRShared.cpp +++ b/code/IRRShared.cpp @@ -294,7 +294,11 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) // material type (shader) if (prop.name == "Type") { - if (prop.value == "trans_vertex_alpha") + if (prop.value == "solid") + { + // default material ... + } + else if (prop.value == "trans_vertex_alpha") { matFlags = AI_IRRMESH_MAT_trans_vertex_alpha; } diff --git a/code/Importer.cpp b/code/Importer.cpp index 3cbcf7573..87502b453 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -43,6 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssimpPCH.h" +/* Uncomment this line to prevent Assimp from catching unknown exceptions. + * + * Note that any Exception except ImportErrorException may lead to + * undefined behaviour -> loaders could remain in an unusable state and + * further imports with the same Importer instance could fail/crash/burn ... + */ +#define ASSIMP_CATCH_GLOBAL_EXCEPTIONS + // ======================================================================================= // Internal headers // ======================================================================================= @@ -135,6 +143,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_BUILD_NO_TERRAGEN_IMPORTER # include "TerragenLoader.h" #endif +//#ifndef AI_BUILD_NO_CSM_IMPORTER +//# include "CSMLoader.h" +//#endif +#ifndef AI_BUILD_NO_3D_IMPORTER +# include "UnrealLoader.h" +#endif + + + + +#ifndef AI_BUILD_NO_LWS_IMPORTER +# include "LWSLoader.h" +#endif + // ======================================================================================= // PostProcess-Steps @@ -325,6 +347,18 @@ Importer::Importer() #if (!defined AI_BUILD_NO_TERRAGEN_IMPORTER) mImporter.push_back( new TerragenImporter()); #endif +//#if (!defined AI_BUILD_NO_CSM_IMPORTER) +// mImporter.push_back( new CSMImporter()); +//#endif +#if (!defined AI_BUILD_NO_3D_IMPORTER) + mImporter.push_back( new UnrealImporter()); +#endif + + + +#if (!defined AI_BUILD_NO_LWS_IMPORTER) + mImporter.push_back( new LWSImporter()); +#endif // ====================================================================== // Add an instance of each post processing step here in the order @@ -333,10 +367,6 @@ Importer::Importer() // ====================================================================== mPostProcessingSteps.reserve(25); -#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS) - mPostProcessingSteps.push_back( new ValidateDSProcess()); -#endif - #if (!defined AI_BUILD_NO_REMOVEVC_PROCESS) mPostProcessingSteps.push_back( new RemoveVCProcess()); #endif @@ -548,10 +578,9 @@ bool Importer::IsDefaultIOHandler() return mIsDefaultHandler; } -#ifdef _DEBUG // ------------------------------------------------------------------------------------------------ // Validate post process step flags -bool ValidateFlags(unsigned int pFlags) +bool _ValidateFlags(unsigned int pFlags) { if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) @@ -562,7 +591,6 @@ bool ValidateFlags(unsigned int pFlags) } return true; } -#endif // ! DEBUG // ------------------------------------------------------------------------------------------------ // Free the current scene @@ -602,12 +630,50 @@ aiScene* Importer::GetOrphanedScene() return s; } +// ------------------------------------------------------------------------------------------------ +// Validate post-processing flags +bool Importer::ValidateFlags(unsigned int pFlags) +{ + // run basic checks for mutually exclusive flags + if(!_ValidateFlags(pFlags)) + return false; + + // ValidateDS does not anymore occur in the pp list, it plays + // an awesome extra role ... +#ifdef AI_BUILD_NO_VALIDATEDS_PROCESS + if (pFlags & aiProcess_ValidateDataStructure) + return false; +#endif + pFlags &= ~aiProcess_ValidateDataStructure; + + // Now iterate through all bits which are set in + // the flags and check whether we find at least + // one pp plugin which handles it. + for (unsigned int mask = 1; mask < (1 << (sizeof(unsigned int)*8-1));mask <<= 1) { + + if (pFlags & mask) { + + bool have = false; + for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) { + if (mPostProcessingSteps[a]-> IsActive(mask) ) { + + have = true; + break; + } + } + if (!have) + return false; + } + } + return true; +} + // ------------------------------------------------------------------------------------------------ // Reads the given file and returns its contents if successful. const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { - // Validate the flags - ai_assert(ValidateFlags(pFlags)); + // In debug builds, run a basic flag validation + ai_assert(_ValidateFlags(pFlags)); const std::string pFile(_pFile); @@ -616,7 +682,9 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // that might be thrown by STL containers or by new(). // ImportErrorException's are throw by ourselves and caught elsewhere. // ====================================================================== +#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS try +#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS { // Check whether this Importer instance has already loaded // a scene. In this case we need to delete the old one @@ -636,21 +704,35 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // Find an worker class which can handle the file BaseImporter* imp = NULL; - for( unsigned int a = 0; a < mImporter.size(); a++) - { - if( mImporter[a]->CanRead( pFile, mIOHandler)) - { + for( unsigned int a = 0; a < mImporter.size(); a++) { + + if( mImporter[a]->CanRead( pFile, mIOHandler, false)) { imp = mImporter[a]; break; } } - // Put a proper error message if no suitable importer was found - if( !imp) + if (!imp) { - mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; - DefaultLogger::get()->error(mErrorString); - return NULL; + // not so bad yet ... try format auto detection. + std::string::size_type s = pFile.find_last_of('.'); + if (s != std::string::npos) { + DefaultLogger::get()->info("File extension now known, trying signature-based detection"); + for( unsigned int a = 0; a < mImporter.size(); a++) { + + if( mImporter[a]->CanRead( pFile, mIOHandler, true)) { + imp = mImporter[a]; + break; + } + } + } + // Put a proper error message if no suitable importer was found + if( !imp) + { + mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; + DefaultLogger::get()->error(mErrorString); + return NULL; + } } // Dispatch the reading to the worker class for this format @@ -661,7 +743,19 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // If successful, apply all active post processing steps to the imported data if( mScene) { - // FIRST of all - preprocess the scene +#ifndef AI_BUILD_NO_VALIDATEDS_PROCESS + // The ValidateDS process is an exception. It is executed first, + // even before ScenePreprocessor is called. + if (pFlags & aiProcess_ValidateDataStructure) + { + ValidateDSProcess ds; + ds.ExecuteOnScene (this); + if (!mScene) + return NULL; + } +#endif // no validation + + // Preprocess the scene ScenePreprocessor pre(mScene); pre.ProcessScene(); @@ -669,11 +763,11 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) #ifdef _DEBUG if (bExtraVerbose) { -#if (!defined AI_BUILD_NO_VALIDATEDS_PROCESS) +#ifndef AI_BUILD_NO_VALIDATEDS_PROCESS DefaultLogger::get()->error("Extra verbose mode not available, library" " wasn't build with the ValidateDS-Step"); -#endif +#endif // no validation pFlags |= aiProcess_ValidateDataStructure; @@ -694,14 +788,16 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) #ifndef AI_BUILD_NO_VALIDATEDS_PROCESS continue; -#endif +#endif // no validation - // if the extra verbose mode is active execute the + // If the extra verbose mode is active execute the // VaidateDataStructureStep again after each step - if (bExtraVerbose && a) + if (bExtraVerbose) { DefaultLogger::get()->debug("Extra verbose: revalidating data structures"); - ((ValidateDSProcess*)mPostProcessingSteps[0])->ExecuteOnScene (this); + + ValidateDSProcess ds; + ds.ExecuteOnScene (this); if( !mScene) { DefaultLogger::get()->error("Extra verbose: failed to revalidate data structures"); @@ -712,11 +808,13 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } } // if failed, extract the error string - else if( !mScene)mErrorString = imp->GetErrorText(); + else if( !mScene) + mErrorString = imp->GetErrorText(); // clear any data allocated by post-process steps mPPShared->Clean(); } +#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS catch (std::exception &e) { #if (defined _MSC_VER) && (defined _CPPRTTI) @@ -729,6 +827,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) DefaultLogger::get()->error(mErrorString); delete mScene;mScene = NULL; } +#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS // either successful or failure - the pointer expresses it anyways return mScene; @@ -750,7 +849,7 @@ BaseImporter* Importer::FindLoader (const char* _szExtension) i != mImporter.end();++i) { // pass the file extension to the CanRead(..,NULL)-method - if ((*i)->CanRead(szExtension,NULL))return *i; + if ((*i)->CanRead(szExtension,NULL,false))return *i; } return NULL; } @@ -765,8 +864,10 @@ void Importer::GetExtensionList(aiString& szOut) i = mImporter.begin(); i != mImporter.end();++i,++iNum) { - // insert a comma as delimiter character - if (0 != iNum) + // Insert a comma as delimiter character + // FIX: to take lazy loader implementations into account, we are + // slightly more tolerant here than we'd need to be. + if (0 != iNum && ';' != *(tmp.end()-1)) tmp.append(";"); (*i)->GetExtensionList(tmp); diff --git a/code/ImproveCacheLocality.cpp b/code/ImproveCacheLocality.cpp index 0016fd7bf..698af7816 100644 --- a/code/ImproveCacheLocality.cpp +++ b/code/ImproveCacheLocality.cpp @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* The algorithm is roughly basing on this paper: * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf + * ... TODO: implement overdraw reduction */ #include "AssimpPCH.h" @@ -54,16 +55,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -#if _MSC_VER >= 1400 -# define sprintf sprintf_s -#endif - // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() -{ - // nothing to do here - configCacheDepth = 12; // hardcoded to 12 at the moment +ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() { + configCacheDepth = PP_ICL_PTCACHE_SIZE; } // ------------------------------------------------------------------------------------------------ @@ -80,28 +75,48 @@ bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const return (pFlags & aiProcess_ImproveCacheLocality) != 0; } +// ------------------------------------------------------------------------------------------------ +// Setup configuration +void ImproveCacheLocalityProcess::SetupProperties(const Importer* pImp) +{ + // AI_CONFIG_PP_ICL_PTCACHE_SIZE + configCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE,PP_ICL_PTCACHE_SIZE); +} + // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void ImproveCacheLocalityProcess::Execute( aiScene* pScene) { - if (!pScene->mNumMeshes) - { + if (!pScene->mNumMeshes) { DefaultLogger::get()->debug("ImproveCacheLocalityProcess skipped; there are no meshes"); return; } DefaultLogger::get()->debug("ImproveCacheLocalityProcess begin"); - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - this->ProcessMesh( pScene->mMeshes[a],a); + float out = 0.f; + unsigned int numf = 0, numm = 0; + for( unsigned int a = 0; a < pScene->mNumMeshes; a++){ + const float res = ProcessMesh( pScene->mMeshes[a],a); + if (res) { + numf += pScene->mMeshes[a]->mNumFaces; + out += res; + ++numm; + } + } + if (!DefaultLogger::isNullLogger()) { + char szBuff[128]; // should be sufficiently large in every case + ::sprintf(szBuff,"Cache relevant are %i meshes (%i faces). Average output ACMR is %f", + numm,numf,out/numf); + + DefaultLogger::get()->info(szBuff); + DefaultLogger::get()->debug("ImproveCacheLocalityProcess finished. "); } - DefaultLogger::get()->debug("ImproveCacheLocalityProcess finished. "); } // ------------------------------------------------------------------------------------------------ // Improves the cache coherency of a specific mesh -void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshNum) +float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshNum) { ai_assert(NULL != pMesh); @@ -109,52 +124,50 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN // - there must be vertices and faces (haha) // - all faces must be triangulated if (!pMesh->HasFaces() || !pMesh->HasPositions()) - return; + return 0.f; - if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) - { + if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) { DefaultLogger::get()->error("This algorithm works on triangle meshes only"); - return; + return 0.f; } - // find the input ACMR ... - unsigned int* piFIFOStack = new unsigned int[this->configCacheDepth]; - ::memset(piFIFOStack,0xff,this->configCacheDepth*sizeof(unsigned int)); - unsigned int* piCur = piFIFOStack; - const unsigned int* const piCurEnd = piFIFOStack + this->configCacheDepth; - - // count the number of cache misses - unsigned int iCacheMisses = 0; - + float fACMR = 3.f; const aiFace* const pcEnd = pMesh->mFaces+pMesh->mNumFaces; - for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace) + + // Input ACMR is for logging purposes only + if (!DefaultLogger::isNullLogger()) { - for (unsigned int qq = 0; qq < 3;++qq) + unsigned int* piFIFOStack = new unsigned int[configCacheDepth]; + ::memset(piFIFOStack,0xff,configCacheDepth*sizeof(unsigned int)); + unsigned int* piCur = piFIFOStack; + const unsigned int* const piCurEnd = piFIFOStack + configCacheDepth; + + // count the number of cache misses + unsigned int iCacheMisses = 0; + for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace) { - bool bInCache = false; - for (unsigned int* pp = piFIFOStack;pp < piCurEnd;++pp) + for (unsigned int qq = 0; qq < 3;++qq) { - if (*pp == pcFace->mIndices[qq]) + bool bInCache = false; + for (unsigned int* pp = piFIFOStack;pp < piCurEnd;++pp) { - // the vertex is in cache - bInCache = true; - break; + if (*pp == pcFace->mIndices[qq]) { + // the vertex is in cache + bInCache = true; + break; + } + } + if (!bInCache) + { + ++iCacheMisses; + if (piCurEnd == piCur)piCur = piFIFOStack; + *piCur++ = pcFace->mIndices[qq]; } } - if (!bInCache) - { - ++iCacheMisses; - if (piCurEnd == piCur)piCur = piFIFOStack; - *piCur++ = pcFace->mIndices[qq]; - } } - } - delete[] piFIFOStack; - float fACMR = (float)iCacheMisses / pMesh->mNumFaces; - if (3.0 == fACMR) - { - if (!DefaultLogger::isNullLogger()) - { + delete[] piFIFOStack; + fACMR = (float)iCacheMisses / pMesh->mNumFaces; + if (3.0 == fACMR) { char szBuff[128]; // should be sufficiently large in every case // the JoinIdenticalVertices process has not been executed on this @@ -162,8 +175,8 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN // smaller than 3.0 ... ::sprintf(szBuff,"Mesh %i: Not suitable for vcache optimization",meshNum); DefaultLogger::get()->warn(szBuff); + return 0.f; } - return; } // first we need to build a vertex-triangle adjacency list @@ -204,7 +217,7 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN iMaxRefTris = std::max(iMaxRefTris,*piCur); } unsigned int* piCandidates = new unsigned int[iMaxRefTris*3]; - iCacheMisses = 0; + unsigned int iCacheMisses = 0; /** PSEUDOCODE for the algorithm @@ -236,7 +249,7 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN int ivdx = 0; int ics = 1; - int iStampCnt = this->configCacheDepth+1; + int iStampCnt = configCacheDepth+1; while (ivdx >= 0) { unsigned int icnt = piNumTriPtrNoModify[ivdx]; @@ -274,7 +287,7 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN *piCSIter++ = dp; // if the vertex is not yet in cache, set its cache count - if (iStampCnt-piCachingStamps[dp] > this->configCacheDepth) + if (iStampCnt-piCachingStamps[dp] > configCacheDepth) { piCachingStamps[dp] = iStampCnt++; ++iCacheMisses; @@ -302,7 +315,7 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN // will the vertex be in cache, even after fanning occurs? unsigned int tmp; - if ((tmp = iStampCnt-piCachingStamps[dp]) + 2*piNumTriPtr[dp] <= this->configCacheDepth) + if ((tmp = iStampCnt-piCachingStamps[dp]) + 2*piNumTriPtr[dp] <= configCacheDepth) priority = tmp; // keep best candidate if (priority > max_priority) @@ -344,18 +357,24 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN } } } + float fACMR2 = 0.0f; if (!DefaultLogger::isNullLogger()) { - char szBuff[128]; // should be sufficiently large in every case - float fACMR2 = (float)iCacheMisses / pMesh->mNumFaces; + fACMR2 = (float)iCacheMisses / pMesh->mNumFaces; - ::sprintf(szBuff,"Mesh %i | ACMR in: %f out: %f | ~%.1f%%",meshNum,fACMR,fACMR2, - ((fACMR - fACMR2) / fACMR) * 100.f); - DefaultLogger::get()->info(szBuff); + // very intense verbose logging ... prepare for much text if there are many meshes + if ( DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) { + char szBuff[128]; // should be sufficiently large in every case + + ::sprintf(szBuff,"Mesh %i | ACMR in: %f out: %f | ~%.1f%%",meshNum,fACMR,fACMR2, + ((fACMR - fACMR2) / fACMR) * 100.f); + DefaultLogger::get()->debug(szBuff); + } + + fACMR2 *= pMesh->mNumFaces; } // sort the output index buffer back to the input array piCSIter = piIBOutput; - for (aiFace* pcFace = pMesh->mFaces; pcFace != pcEnd;++pcFace) { pcFace->mIndices[0] = *piCSIter++; @@ -368,4 +387,5 @@ void ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshN delete[] piIBOutput; delete[] piCandidates; delete[] piNumTriPtrNoModify; + return fACMR2; } diff --git a/code/ImproveCacheLocality.h b/code/ImproveCacheLocality.h index 6d884e527..fd4024633 100644 --- a/code/ImproveCacheLocality.h +++ b/code/ImproveCacheLocality.h @@ -70,30 +70,28 @@ protected: ~ImproveCacheLocalityProcess(); public: + // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ + // Check whether the pp step is active bool IsActive( unsigned int pFlags) const; // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ + // Executes the pp step on a given scene void Execute( aiScene* pScene); + // ------------------------------------------------------------------- + // Configures the pp step + void SetupProperties(const Importer* pImp); + protected: // ------------------------------------------------------------------- /** Executes the postprocessing step on the given mesh * @param pMesh The mesh to process. * @param meshNum Index of the mesh to process */ - void ProcessMesh( aiMesh* pMesh, unsigned int meshNum); - + float ProcessMesh( aiMesh* pMesh, unsigned int meshNum); +private: //! Configuration parameter: specifies the size of the cache to //! optimize the vertex data for. unsigned int configCacheDepth; diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index 39aac209a..ead42446d 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -51,9 +51,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -#if _MSC_VER >= 1400 -# define sprintf sprintf_s -#endif +// Data structure to keep a vertex in an interlaced format +struct Vertex +{ + aiVector3D mPosition; + aiVector3D mNormal; + aiVector3D mTangent, mBitangent; + aiColor4D mColors [AI_MAX_NUMBER_OF_COLOR_SETS]; + aiVector3D mTexCoords [AI_MAX_NUMBER_OF_TEXTURECOORDS]; +}; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer @@ -75,7 +81,6 @@ bool JoinVerticesProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_JoinIdenticalVertices) != 0; } - // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void JoinVerticesProcess::Execute( aiScene* pScene) @@ -84,18 +89,19 @@ void JoinVerticesProcess::Execute( aiScene* pScene) // get the total number of vertices BEFORE the step is executed int iNumOldVertices = 0; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - iNumOldVertices += pScene->mMeshes[a]->mNumVertices; + if (!DefaultLogger::isNullLogger()) { + for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { + iNumOldVertices += pScene->mMeshes[a]->mNumVertices; + } } // execute the step int iNumVertices = 0; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - iNumVertices += this->ProcessMesh( pScene->mMeshes[a],a); + for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { + iNumVertices += ProcessMesh( pScene->mMeshes[a],a); } - // if logging is active, print detailled statistics + + // if logging is active, print detailed statistics if (!DefaultLogger::isNullLogger()) { if (iNumOldVertices == iNumVertices)DefaultLogger::get()->debug("JoinVerticesProcess finished "); @@ -117,81 +123,103 @@ void JoinVerticesProcess::Execute( aiScene* pScene) // Unites identical vertices in the given mesh int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) { - // helper structure to hold all the data a single vertex can possibly have - typedef struct Vertex vertex; + BOOST_STATIC_ASSERT( AI_MAX_NUMBER_OF_COLOR_SETS == 4); + BOOST_STATIC_ASSERT( AI_MAX_NUMBER_OF_TEXTURECOORDS == 4); + // Return early if we don't have any positions if (!pMesh->HasPositions() || !pMesh->HasFaces()) return 0; - - struct Vertex - { - aiVector3D mPosition; - aiVector3D mNormal; - aiVector3D mTangent, mBitangent; - aiColor4D mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; - aiVector3D mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - }; + + // We'll never have more vertices afterwards. std::vector uniqueVertices; uniqueVertices.reserve( pMesh->mNumVertices); - //unsigned int iOldVerts = pMesh->mNumVertices; - // For each vertex the index of the vertex it was replaced by. std::vector replaceIndex( pMesh->mNumVertices, 0xffffffff); // for each vertex whether it was replaced by an existing unique vertex (true) or a new vertex was created for it (false) std::vector isVertexUnique( pMesh->mNumVertices, false); - // a little helper to find locally close vertices faster + // A little helper to find locally close vertices faster // FIX: check whether we can reuse the SpatialSort of a previous step - const float epsilon = 1e-5f; - float posEpsilon; - SpatialSort* vertexFinder = NULL; + const static float epsilon = 1e-5f; + float posEpsilonSqr; + SpatialSort* vertexFinder = NULL; SpatialSort _vertexFinder; if (shared) { std::vector >* avf; shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) - { + if (avf) { std::pair& blubb = avf->operator [] (meshIndex); - vertexFinder = &blubb.first; - posEpsilon = blubb.second; + vertexFinder = &blubb.first; + posEpsilonSqr = blubb.second; } } - if (!vertexFinder) - { + if (!vertexFinder) { _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); vertexFinder = &_vertexFinder; - posEpsilon = ComputePositionEpsilon(pMesh); + posEpsilonSqr = ComputePositionEpsilon(pMesh); } // squared because we check against squared length of the vector difference - const float squareEpsilon = epsilon * epsilon; - std::vector verticesFound; + static const float squareEpsilon = epsilon * epsilon; - // now check each vertex if it brings something new to the table + // again, better waste some bytes than a realloc ... + std::vector verticesFound; + verticesFound.reserve(10); + + // run an optimized code path if we don't have multiple UVs or vertex colors + const bool complex = ( + pMesh->mTextureCoords[1] || + pMesh->mTextureCoords[2] || + pMesh->mTextureCoords[3] || + pMesh->mColors[0] || + pMesh->mColors[1] || + pMesh->mColors[2] || + pMesh->mColors[3] ); + + // Now check each vertex if it brings something new to the table for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { // collect the vertex data Vertex v; v.mPosition = pMesh->mVertices[a]; - v.mNormal = (pMesh->mNormals != NULL) ? pMesh->mNormals[a] : aiVector3D( 0, 0, 0); - v.mTangent = (pMesh->mTangents != NULL) ? pMesh->mTangents[a] : aiVector3D( 0, 0, 0); - v.mBitangent = (pMesh->mBitangents != NULL) ? pMesh->mBitangents[a] : aiVector3D( 0, 0, 0); - for( unsigned int b = 0; b < AI_MAX_NUMBER_OF_COLOR_SETS; b++) - v.mColors[b] = (pMesh->mColors[b] != NULL) ? pMesh->mColors[b][a] : aiColor4D( 0, 0, 0, 0); - for( unsigned int b = 0; b < AI_MAX_NUMBER_OF_TEXTURECOORDS; b++) - v.mTexCoords[b] = (pMesh->mTextureCoords[b] != NULL) ? pMesh->mTextureCoords[b][a] : aiVector3D( 0, 0, 0); + + if (pMesh->mNormals) + v.mNormal = pMesh->mNormals[a]; + if (pMesh->mTangents) + v.mTangent = pMesh->mTangents[a]; + if (pMesh->mBitangents) + v.mBitangent = pMesh->mBitangents[a]; + + if (pMesh->mColors[0]) { // manually unrolled here + v.mColors[0] = pMesh->mColors[0][a]; + if (pMesh->mColors[1]) { + v.mColors[1] = pMesh->mColors[1][a]; + if (pMesh->mColors[2]) { + v.mColors[2] = pMesh->mColors[2][a]; + if (pMesh->mColors[3]) { + v.mColors[3] = pMesh->mColors[3][a]; + }}}} + if (pMesh->mTextureCoords[0]) { // manually unrolled here + v.mTexCoords[0] = pMesh->mTextureCoords[0][a]; + if (pMesh->mTextureCoords[1]) { + v.mTexCoords[1] = pMesh->mTextureCoords[1][a]; + if (pMesh->mTextureCoords[2]) { + v.mTexCoords[2] = pMesh->mTextureCoords[2][a]; + if (pMesh->mTextureCoords[3]) { + v.mTexCoords[3] = pMesh->mTextureCoords[3][a]; + }}}} // collect all vertices that are close enough to the given position - vertexFinder->FindPositions( v.mPosition, posEpsilon, verticesFound); + vertexFinder->FindPositions( v.mPosition, posEpsilonSqr, verticesFound); unsigned int matchIndex = 0xffffffff; // check all unique vertices close to the position if this vertex is already present among them for( unsigned int b = 0; b < verticesFound.size(); b++) { - unsigned int vidx = verticesFound[b]; - unsigned int uidx = replaceIndex[ vidx]; + const unsigned int vidx = verticesFound[b]; + const unsigned int uidx = replaceIndex[ vidx]; if( uidx == 0xffffffff || !isVertexUnique[ vidx]) continue; @@ -201,33 +229,38 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) // We just test the other attributes even if they're not present in the mesh. // In this case they're initialized to 0 so the comparision succeeds. // By this method the non-present attributes are effectively ignored in the comparision. - if( (uv.mNormal - v.mNormal).SquareLength() > squareEpsilon) continue; if( (uv.mTangent - v.mTangent).SquareLength() > squareEpsilon) continue; if( (uv.mBitangent - v.mBitangent).SquareLength() > squareEpsilon) continue; - // manually unrolled because continue wouldn't work as desired in an inner loop - BOOST_STATIC_ASSERT(4 == AI_MAX_NUMBER_OF_COLOR_SETS); - if( GetColorDifference( uv.mColors[0], v.mColors[0]) > squareEpsilon) - continue; - if( GetColorDifference( uv.mColors[1], v.mColors[1]) > squareEpsilon) - continue; - if( GetColorDifference( uv.mColors[2], v.mColors[2]) > squareEpsilon) - continue; - if( GetColorDifference( uv.mColors[3], v.mColors[3]) > squareEpsilon) - continue; - // texture coord matching manually unrolled as well - BOOST_STATIC_ASSERT(4 == AI_MAX_NUMBER_OF_TEXTURECOORDS); + if( (uv.mTexCoords[0] - v.mTexCoords[0]).SquareLength() > squareEpsilon) continue; - if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon) - continue; - if( (uv.mTexCoords[2] - v.mTexCoords[2]).SquareLength() > squareEpsilon) - continue; - if( (uv.mTexCoords[3] - v.mTexCoords[3]).SquareLength() > squareEpsilon) - continue; + + // Usually we won't have vertex colors or multiple UVs, so we can skip from here + // Actually this increases runtime performance slightly. + if (complex) + { + // manually unrolled because continue wouldn't work as desired in an inner loop + if( GetColorDifference( uv.mColors[0], v.mColors[0]) > squareEpsilon) + continue; + if( GetColorDifference( uv.mColors[1], v.mColors[1]) > squareEpsilon) + continue; + if( GetColorDifference( uv.mColors[2], v.mColors[2]) > squareEpsilon) + continue; + if( GetColorDifference( uv.mColors[3], v.mColors[3]) > squareEpsilon) + continue; + + // texture coord matching manually unrolled as well + if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon) + continue; + if( (uv.mTexCoords[2] - v.mTexCoords[2]).SquareLength() > squareEpsilon) + continue; + if( (uv.mTexCoords[3] - v.mTexCoords[3]).SquareLength() > squareEpsilon) + continue; + } // we're still here -> this vertex perfectly matches our given vertex matchIndex = uidx; @@ -250,24 +283,26 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) } } - if (!DefaultLogger::isNullLogger()) + if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) { char szBuff[128]; // should be sufficiently large in every case - sprintf(szBuff,"Mesh %i | Verts in: %i out: %i | ~%.1f%%", + ::sprintf(szBuff,"Mesh %i | Verts in: %i out: %i | ~%.1f%%", meshIndex, pMesh->mNumVertices, (int)uniqueVertices.size(), ((pMesh->mNumVertices - uniqueVertices.size()) / (float)pMesh->mNumVertices) * 100.f); - DefaultLogger::get()->info(szBuff); + DefaultLogger::get()->debug(szBuff); } // replace vertex data with the unique data sets pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); + // Position delete [] pMesh->mVertices; pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; for( unsigned int a = 0; a < pMesh->mNumVertices; a++) pMesh->mVertices[a] = uniqueVertices[a].mPosition; + // Normals, if present if( pMesh->mNormals) { @@ -296,7 +331,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { if( !pMesh->mColors[a]) - continue; + break; delete [] pMesh->mColors[a]; pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; @@ -307,7 +342,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { if( !pMesh->mTextureCoords[a]) - continue; + break; delete [] pMesh->mTextureCoords[a]; pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; @@ -319,10 +354,8 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { aiFace& face = pMesh->mFaces[a]; - for( unsigned int b = 0; b < face.mNumIndices; b++) - { - const size_t index = face.mIndices[b]; - face.mIndices[b] = replaceIndex[index]; + for( unsigned int b = 0; b < face.mNumIndices; b++) { + face.mIndices[b] = replaceIndex[face.mIndices[b]]; } } diff --git a/code/JoinVerticesProcess.h b/code/JoinVerticesProcess.h index ce0b195a2..5bb73babe 100644 --- a/code/JoinVerticesProcess.h +++ b/code/JoinVerticesProcess.h @@ -95,6 +95,8 @@ protected: * @param meshIndex Index of the mesh to process */ int ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); + +private: }; } // end of namespace Assimp diff --git a/code/LWOAnimation.cpp b/code/LWOAnimation.cpp new file mode 100644 index 000000000..f73470435 --- /dev/null +++ b/code/LWOAnimation.cpp @@ -0,0 +1,567 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file LWOAnimation.cpp + * @brief LWOAnimationResolver utility class + * + * It's a very generic implementation of LightWave's system of + * componentwise-animated stuff. The one and only fully free + * implementation of LightWave envelopes of which I know. +*/ + +#include "AssimpPCH.h" +#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER) && (!defined ASSIMP_BUILD_NO_LWS_IMPORTER) + +// internal headers +#include "LWOFileData.h" + +using namespace Assimp; +using namespace Assimp::LWO; + +// ------------------------------------------------------------------------------------------------ +// Construct an animation resolver from a given list of envelopes +AnimResolver::AnimResolver(std::list& _envelopes,double tick) + : envelopes (_envelopes) + , sample_rate (0.) +{ + trans_x = trans_y = trans_z = NULL; + rotat_x = rotat_y = rotat_z = NULL; + scale_x = scale_y = scale_z = NULL; + + first = last = 150392.; + + // find transformation envelopes + for (std::list::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { + + (*it).old_first = 0; + (*it).old_last = (*it).keys.size()-1; + + if ((*it).keys.empty()) continue; + switch ((*it).type) { + + // translation + case LWO::EnvelopeType_Position_X: + trans_x = &*it;break; + case LWO::EnvelopeType_Position_Y: + trans_y = &*it;break; + case LWO::EnvelopeType_Position_Z: + trans_z = &*it;break; + + // rotation + case LWO::EnvelopeType_Rotation_Heading: + rotat_x = &*it;break; + case LWO::EnvelopeType_Rotation_Pitch: + rotat_y = &*it;break; + case LWO::EnvelopeType_Rotation_Bank: + rotat_z = &*it;break; + + // scaling + case LWO::EnvelopeType_Scaling_X: + scale_x = &*it;break; + case LWO::EnvelopeType_Scaling_Y: + scale_y = &*it;break; + case LWO::EnvelopeType_Scaling_Z: + scale_z = &*it;break; + default: + continue; + }; + + // convert from seconds to ticks + for (std::vector::iterator d = (*it).keys.begin(); d != (*it).keys.end(); ++d) + (*d).time *= tick; + + // set default animation range (minimum and maximum time value for which we have a keyframe) + first = std::min(first, (*it).keys.front().time ); + last = std::max(last, (*it).keys.back().time ); + } + + // deferred setup of animation range to increase performance. + // typically the application will want to specify its own. + need_to_setup = true; +} + +// ------------------------------------------------------------------------------------------------ +// Reset all envelopes to their original contents +void AnimResolver::ClearAnimRangeSetup() +{ + for (std::list::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { + + (*it).keys.erase((*it).keys.begin(),(*it).keys.begin()+(*it).old_first); + (*it).keys.erase((*it).keys.begin()+(*it).old_last+1,(*it).keys.end()); + } +} + +// ------------------------------------------------------------------------------------------------ +// Insert additional keys to match LWO's pre& post behaviours. +void AnimResolver::UpdateAnimRangeSetup() +{ + for (std::list::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { + if ((*it).keys.empty()) continue; + + const double my_first = (*it).keys.front().time; + const double my_last = (*it).keys.back().time; + + const double delta = my_last-my_first; + const size_t old_size = (*it).keys.size(); + + const float value_delta = (*it).keys.back().value - (*it).keys.front().value; + + // NOTE: We won't handle reset, linear and constant here. + // See DoInterpolation() for their implementation. + + // process pre behaviour + switch ((*it).pre) { + case LWO::PrePostBehaviour_OffsetRepeat: + case LWO::PrePostBehaviour_Repeat: + case LWO::PrePostBehaviour_Oscillate: + + const double start_time = delta - fmod(my_first-first,delta); + std::vector::iterator n = std::find_if((*it).keys.begin(),(*it).keys.end(), + std::bind1st(std::greater(),start_time)),m; + + size_t ofs = 0; + if (n != (*it).keys.end()) { + // copy from here - don't use iterators, insert() would invalidate them + ofs = (*it).keys.end()-n; + (*it).keys.insert((*it).keys.begin(),ofs,LWO::Key()); + + std::copy((*it).keys.end()-ofs,(*it).keys.end(),(*it).keys.begin()); + } + + // do full copies. again, no iterators + const unsigned int num = (unsigned int)((my_first-first) / delta); + (*it).keys.resize((*it).keys.size() + num*old_size); + + n = (*it).keys.begin()+ofs; + bool reverse = false; + for (unsigned int i = 0; i < num; ++i) { + m = n+old_size*(i+1); + std::copy(n,n+old_size,m); + + if ((*it).pre == LWO::PrePostBehaviour_Oscillate && (reverse = !reverse)) + std::reverse(m,m+old_size-1); + } + + // update time values + n = (*it).keys.end() - (old_size+1); + double cur_minus = delta; + unsigned int tt = 1; + for (const double tmp = delta*(num+1);cur_minus <= tmp;cur_minus += delta,++tt) { + m = (delta == tmp ? (*it).keys.begin() : n - (old_size+1)); + for (;m != n; --n) { + (*n).time -= cur_minus; + + // offset repeat? add delta offset to key value + if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) { + (*n).value += tt * value_delta; + } + } + } + break; + } + + // process post behaviour + switch ((*it).post) { + + case LWO::PrePostBehaviour_OffsetRepeat: + case LWO::PrePostBehaviour_Repeat: + case LWO::PrePostBehaviour_Oscillate: + + break; + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Extract bind pose matrix +void AnimResolver::ExtractBindPose(aiMatrix4x4& out) +{ + // If we have no envelopes, return identity + if (envelopes.empty()) { + out = aiMatrix4x4(); + return; + } + aiVector3D angles, scaling(1.f,1.f,1.f), translation; + + if (trans_x) translation.x = trans_x->keys[0].value; + if (trans_y) translation.y = trans_y->keys[0].value; + if (trans_z) translation.z = trans_z->keys[0].value; + + if (rotat_x) angles.x = rotat_x->keys[0].value; + if (rotat_y) angles.y = rotat_y->keys[0].value; + if (rotat_z) angles.z = rotat_z->keys[0].value; + + if (scale_x) scaling.x = scale_x->keys[0].value; + if (scale_y) scaling.y = scale_y->keys[0].value; + if (scale_z) scaling.z = scale_z->keys[0].value; + + // build the final matrix + aiMatrix4x4 s,r,t; + + r.FromEulerAnglesXYZ(angles); + //aiMatrix4x4::RotationY(angles.y,r); + // fixme: make FromEulerAngles static, too + aiMatrix4x4::Translation(translation,t); + aiMatrix4x4::Scaling(scaling,s); + out = s*r*t; +} + +// ------------------------------------------------------------------------------------------------ +// Do a single interpolation on a channel +void AnimResolver::DoInterpolation(std::vector::const_iterator cur, + LWO::Envelope* envl,double time, float& fill) +{ + if (envl->keys.size() == 1) { + fill = envl->keys[0].value; + return; + } + + // check whether we're at the beginning of the animation track + if (cur == envl->keys.begin()) { + + // ok ... this depends on pre behaviour now + // we don't need to handle repeat&offset repeat&oszillate here, see UpdateAnimRangeSetup() + switch (envl->pre) + { + case LWO::PrePostBehaviour_Linear: + DoInterpolation2(cur,cur+1,time,fill); + return; + + case LWO::PrePostBehaviour_Reset: + fill = 0.f; + return; + + default : //case LWO::PrePostBehaviour_Constant: + fill = (*cur).value; + return; + } + } + // check whether we're at the end of the animation track + else if (cur == envl->keys.end()-1 && time > envl->keys.rbegin()->time) { + // ok ... this depends on post behaviour now + switch (envl->post) + { + case LWO::PrePostBehaviour_Linear: + DoInterpolation2(cur,cur-1,time,fill); + return; + + case LWO::PrePostBehaviour_Reset: + fill = 0.f; + return; + + default : //case LWO::PrePostBehaviour_Constant: + fill = (*cur).value; + return; + } + } + + // Otherwise do a simple interpolation + DoInterpolation2(cur-1,cur,time,fill); +} + +// ------------------------------------------------------------------------------------------------ +// Almost the same, except we won't handle pre/post conditions here +void AnimResolver::DoInterpolation2(std::vector::const_iterator beg, + std::vector::const_iterator end,double time, float& fill) +{ + switch ((*end).inter) { + + case LWO::IT_STEP: + // no interpolation at all - take the value of the last key + fill = (*beg).value; + return; + + } + // linear interpolation - default + fill = (*beg).value + ((*end).value - (*beg).value)*(float)(((time - (*beg).time) / ((*end).time - (*beg).time))); +} + +// ------------------------------------------------------------------------------------------------ +// Subsample animation track by given key values +void AnimResolver::SubsampleAnimTrack(std::vector& out, + double time,double sample_delta) +{ + ai_assert(!out.empty() && sample_delta); + + const double time_start = out.back().mTime; +// for () +} + +// ------------------------------------------------------------------------------------------------ +// Track interpolation +void AnimResolver::InterpolateTrack(std::vector& out,aiVectorKey& fill,double time) +{ + // subsample animation track? + if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { + SubsampleAnimTrack(out,time, sample_delta); + } + + fill.mTime = time; + + // get x + if ((*cur_x).time == time) { + fill.mValue.x = (*cur_x).value; + + if (cur_x != envl_x->keys.end()-1) /* increment x */ + ++cur_x; + else end_x = true; + } + else DoInterpolation(cur_x,envl_x,time,(float&)fill.mValue.x); + + // get y + if ((*cur_y).time == time) { + fill.mValue.y = (*cur_y).value; + + if (cur_y != envl_y->keys.end()-1) /* increment y */ + ++cur_y; + else end_y = true; + } + else DoInterpolation(cur_y,envl_y,time,(float&)fill.mValue.y); + + // get z + if ((*cur_z).time == time) { + fill.mValue.z = (*cur_z).value; + + if (cur_z != envl_z->keys.end()-1) /* increment z */ + ++cur_z; + else end_x = true; + } + else DoInterpolation(cur_z,envl_z,time,(float&)fill.mValue.z); +} + +// ------------------------------------------------------------------------------------------------ +// Build linearly subsampled keys from three single envelopes, one for each component (x,y,z) +void AnimResolver::GetKeys(std::vector& out, + LWO::Envelope* _envl_x, + LWO::Envelope* _envl_y, + LWO::Envelope* _envl_z, + unsigned int _flags) +{ + envl_x = _envl_x; + envl_y = _envl_y; + envl_z = _envl_z; + flags = _flags; + + // generate default channels if none are given + LWO::Envelope def_x, def_y, def_z; + LWO::Key key_dummy; + key_dummy.time = 0.f; + if (envl_x && envl_x->type == LWO::EnvelopeType_Scaling_X || + envl_y && envl_y->type == LWO::EnvelopeType_Scaling_Y || + envl_z && envl_z->type == LWO::EnvelopeType_Scaling_Z) { + key_dummy.value = 1.f; + } + else key_dummy.value = 0.f; + + if (!envl_x) { + envl_x = &def_x; + envl_x->keys.push_back(key_dummy); + } + if (!envl_y) { + envl_y = &def_y; + envl_y->keys.push_back(key_dummy); + } + if (!envl_z) { + envl_z = &def_z; + envl_z->keys.push_back(key_dummy); + } + + // guess how many keys we'll get + size_t reserve; + double sr = 1.; + if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { + if (!sample_rate) + sr = 100.f; + else sr = sample_rate; + sample_delta = 1.f / sr; + + reserve = (size_t)( + std::max( envl_x->keys.end()->time, + std::max( envl_y->keys.end()->time, envl_z->keys.end()->time )) * sr); + } + else reserve = std::max(envl_x->keys.size(),std::max(envl_x->keys.size(),envl_z->keys.size())); + out.reserve(reserve+(reserve>>1)); + + // Iterate through all three arrays at once - it's tricky, but + // rather interesting to implement. + double lasttime = std::min(envl_x->keys[0].time,std::min(envl_y->keys[0].time,envl_z->keys[0].time)); + + cur_x = envl_x->keys.begin(); + cur_y = envl_y->keys.begin(); + cur_z = envl_z->keys.begin(); + + end_x = end_y = end_z = false; + while (1) { + + aiVectorKey fill; + + if ((*cur_x).time == (*cur_y).time && (*cur_x).time == (*cur_z).time ) { + + // we have a keyframe for all of them defined .. great, + // we don't need to fucking interpolate here ... + fill.mTime = (*cur_x).time; + + fill.mValue.x = (*cur_x).value; + fill.mValue.y = (*cur_y).value; + fill.mValue.z = (*cur_z).value; + + // subsample animation track + if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { + //SubsampleAnimTrack(out,cur_x, cur_y, cur_z, d, sample_delta); + } + + if (cur_x != envl_x->keys.end()-1) + ++cur_x; + else end_x = true; + if (cur_y != envl_y->keys.end()-1) + ++cur_y; + else end_y = true; + if (cur_z != envl_z->keys.end()-1) + ++cur_z; + else end_z = true; + } + + // Find key with lowest time value + else if ((*cur_x).time <= (*cur_y).time && !end_x) { + + if ((*cur_z).time <= (*cur_x).time && !end_z) { + InterpolateTrack(out,fill,(*cur_z).time); + } + else { + InterpolateTrack(out,fill,(*cur_x).time); + } + } + else if ((*cur_z).time <= (*cur_y).time && !end_z) { + InterpolateTrack(out,fill,(*cur_z).time); + } + else if (!end_y) { + // welcome on the server, y + InterpolateTrack(out,fill,(*cur_y).time); + } + else { + // we have reached the end of at least 2 channels, + // only one is remaining. Extrapolate the 2. + if (end_y) { + InterpolateTrack(out,fill,(end_x ? (*cur_z) : (*cur_x)).time); + } + else if (end_x) { + InterpolateTrack(out,fill,(end_z ? (*cur_y) : (*cur_z)).time); + } + else { // if (end_z) + InterpolateTrack(out,fill,(end_y ? (*cur_x) : (*cur_y)).time); + } + } + lasttime = fill.mTime; + out.push_back(fill); + + if( end_x && end_y && end_z ) /* finished? */ + break; + } + + if (flags & AI_LWO_ANIM_FLAG_START_AT_ZERO) { + for (std::vector::iterator it = out.begin(); it != out.end(); ++it) + (*it).mTime -= first; + } +} + +// ------------------------------------------------------------------------------------------------ +// Extract animation channel +void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0*/) +{ + *out = NULL; + + // If we have no envelopes, return NULL + if (envelopes.empty()) { + return; + } + + // We won't spawn an animation channel if we don't have at least one + // envelope with more than one keyframe defined. + const bool trans = (trans_x && trans_x->keys.size() > 1 || trans_y && trans_y->keys.size() > 1 || trans_z && trans_z->keys.size() > 1); + const bool rotat = (rotat_x && rotat_x->keys.size() > 1 || rotat_y && rotat_y->keys.size() > 1 || rotat_z && rotat_z->keys.size() > 1); + const bool scale = (scale_x && scale_x->keys.size() > 1 || scale_y && scale_y->keys.size() > 1 || scale_z && scale_z->keys.size() > 1); + if (!trans && !rotat && !scale) + return; + + // Allocate the output animation + aiNodeAnim* anim = *out = new aiNodeAnim(); + + // Setup default animation setup if necessary + if (need_to_setup) { + UpdateAnimRangeSetup(); + need_to_setup = false; + } + + // copy translation keys + if (trans) { + std::vector keys; + GetKeys(keys,trans_x,trans_y,trans_z,flags); + + anim->mPositionKeys = new aiVectorKey[ anim->mNumPositionKeys = keys.size() ]; + std::copy(keys.begin(),keys.end(),anim->mPositionKeys); + } + + // copy rotation keys + if (rotat) { + std::vector keys; + GetKeys(keys,rotat_x,rotat_y,rotat_z,flags); + + anim->mRotationKeys = new aiQuatKey[ anim->mNumRotationKeys = keys.size() ]; + + // convert heading, pitch, bank to quaternion + for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { + aiQuatKey& qk = anim->mRotationKeys[i]; + qk.mTime = keys[i].mTime; + qk.mValue = aiQuaternion( keys[i].mValue.x ,keys[i].mValue.y ,keys[i].mValue.z ); + } + } + + // copy scaling keys + if (scale) { + std::vector keys; + GetKeys(keys,scale_x,scale_y,scale_z,flags); + + anim->mScalingKeys = new aiVectorKey[ anim->mNumScalingKeys = keys.size() ]; + std::copy(keys.begin(),keys.end(),anim->mScalingKeys); + } +} + + +#endif // no lwo or no lws diff --git a/code/LWOAnimation.h b/code/LWOAnimation.h new file mode 100644 index 000000000..f89d6823a --- /dev/null +++ b/code/LWOAnimation.h @@ -0,0 +1,336 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file LWOAnimation.h + * @brief LWOAnimationResolver utility class + * + * This is for all lightwave-related file format, not only LWO. + * LWS isthe main purpose. +*/ +#ifndef AI_LWO_ANIMATION_INCLUDED +#define AI_LWO_ANIMATION_INCLUDED + +namespace Assimp { +namespace LWO { + +// --------------------------------------------------------------------------- +/** \brief List of recognized LWO envelopes + */ +enum EnvelopeType +{ + EnvelopeType_Position_X = 0x1, + EnvelopeType_Position_Y = 0x2, + EnvelopeType_Position_Z = 0x3, + + EnvelopeType_Rotation_Heading = 0x4, + EnvelopeType_Rotation_Pitch = 0x5, + EnvelopeType_Rotation_Bank = 0x6, + + EnvelopeType_Scaling_X = 0x7, + EnvelopeType_Scaling_Y = 0x8, + EnvelopeType_Scaling_Z = 0x9, + + // -- currently not yet handled + EnvelopeType_Color_R = 0xa, + EnvelopeType_Color_G = 0xb, + EnvelopeType_Color_B = 0xc, + + EnvelopeType_Falloff_X = 0xd, + EnvelopeType_Falloff_Y = 0xe, + EnvelopeType_Falloff_Z = 0xf, + + EnvelopeType_Unknown +}; + +// --------------------------------------------------------------------------- +/** \brief List of recognized LWO interpolation modes + */ +enum InterpolationType +{ + IT_STEP, IT_LINE, IT_TCB, IT_HERM, IT_BEZI, IT_BEZ2 +}; + + +// --------------------------------------------------------------------------- +/** \brief List of recognized LWO pre or post range behaviours + */ +enum PrePostBehaviour +{ + PrePostBehaviour_Reset = 0x0, + PrePostBehaviour_Constant = 0x1, + PrePostBehaviour_Repeat = 0x2, + PrePostBehaviour_Oscillate = 0x3, + PrePostBehaviour_OffsetRepeat = 0x4, + PrePostBehaviour_Linear = 0x5 +}; + +// --------------------------------------------------------------------------- +/** \brief Data structure for a LWO animation keyframe + */ +struct Key +{ + Key() + : inter (IT_LINE) + {} + + //! Current time + double time; + + //! Current value + float value; + + //! How to interpolate this key with previous key? + InterpolationType inter; + + //! Interpolation parameters + float params[5]; + + + // for std::find() + operator double () { + return time; + } +}; + +// --------------------------------------------------------------------------- +/** \brief Data structure for a LWO animation envelope + */ +struct Envelope +{ + Envelope() + : type (EnvelopeType_Unknown) + , pre (PrePostBehaviour_Constant) + , post (PrePostBehaviour_Constant) + + , old_first (0) + , old_last (0) + {} + + //! Index of this envelope + unsigned int index; + + //! Type of envelope + EnvelopeType type; + + //! Pre and post-behaviour + PrePostBehaviour pre,post; + + //! Keyframes for this envelope + std::vector keys; + + + // temporary data for AnimResolver + size_t old_first,old_last; +}; + +// --------------------------------------------------------------------------- +//! @def AI_LWO_ANIM_FLAG_SAMPLE_ANIMS +//! Flag for AnimResolver, subsamples the input data with the rate specified +//! by AnimResolver::SetSampleRate(). +#define AI_LWO_ANIM_FLAG_SAMPLE_ANIMS 0x1 + + +// --------------------------------------------------------------------------- +//! @def AI_LWO_ANIM_FLAG_START_AT_ZERO +//! Flag for AnimResolver, ensures that the animations starts at zero. +#define AI_LWO_ANIM_FLAG_START_AT_ZERO 0x2 + +// --------------------------------------------------------------------------- +/** @brief Utility class to build Assimp animations from LWO envelopes. + * + * Used for both LWO and LWS (MOT also). + */ +class AnimResolver +{ +public: + + // ------------------------------------------------------------------ + /** @brief Construct an AnimResolver from a given list of envelopes + * @param envelopes Input envelopes. May be empty. + * @param Output tick rate, per second + * @note The input envelopes are possibly modified. + */ + AnimResolver(std::list& envelopes, + double tick); + +public: + + // ------------------------------------------------------------------ + /** @brief Extract the bind-pose transformation matrix. + * @param out Receives bind-pose transformation matrix + */ + void ExtractBindPose(aiMatrix4x4& out); + + // ------------------------------------------------------------------ + /** @brief Extract a node animation channel + * @param out Receives a pointer to a newly allocated node anim. + * If there's just one keyframe defined, *out is set to NULL and + * no animation channel is computed. + * @param flags Any combination of the AI_LWO_ANIM_FLAG_XXX flags. + */ + void ExtractAnimChannel(aiNodeAnim** out, unsigned int flags = 0); + + + // ------------------------------------------------------------------ + /** @brief Set the sampling rate for ExtractAnimChannel(). + * + * Non-linear interpolations are subsampled with this rate (keys + * per second). Closer sampling positions, if existent, are kept. + * The sampling rate defaults to 0, if this value is not changed and + * AI_LWO_ANIM_FLAG_SAMPLE_ANIMS is specified for ExtractAnimChannel(), + * the class finds a suitable sample rate by itself. + */ + void SetSampleRate(double sr) { + sample_rate = sr; + } + + // ------------------------------------------------------------------ + /** @brief Getter for SetSampleRate() + */ + double GetSampleRate() const { + return sample_rate; + } + + // ------------------------------------------------------------------ + /** @brief Set the animation time range + * + * @param first Time where the animation starts, in ticks + * @param last Time where the animation ends, in ticks + */ + void SetAnimationRange(double _first, double _last) { + first = _first; + last = _last; + + ClearAnimRangeSetup(); + UpdateAnimRangeSetup(); + } + +protected: + + // ------------------------------------------------------------------ + /** @brief Build linearly subsampled keys from 3 single envelopes + * @param out Receives output keys + * @param envl_x X-component envelope + * @param envl_y Y-component envelope + * @param envl_z Z-component envelope + * @param flags Any combination of the AI_LWO_ANIM_FLAG_XXX flags. + * @note Up to two input envelopes may be NULL + */ + void GetKeys(std::vector& out, + LWO::Envelope* envl_x, + LWO::Envelope* envl_y, + LWO::Envelope* envl_z, + unsigned int flags); + + // ------------------------------------------------------------------ + /** @brief Resolve a single animation key by applying the right + * interpolation to it. + * @param cur Current key + * @param envl Envelope working on + * @param time time to be interpolated + * @param fill Receives the interpolated output value. + */ + void DoInterpolation(std::vector::const_iterator cur, + LWO::Envelope* envl,double time, float& fill); + + // ------------------------------------------------------------------ + /** @brief Almost the same, except we won't handle pre/post + * conditions here. + * @see DoInterpolation + */ + void DoInterpolation2(std::vector::const_iterator beg, + std::vector::const_iterator end,double time, float& fill); + + // ------------------------------------------------------------------ + /** @brief Interpolate 2 tracks if one is given + * + * @param out Receives extra output keys + * @param key_out Primary output key + * @param time Time to interpolate for + */ + void InterpolateTrack(std::vector& out, + aiVectorKey& key_out,double time); + + // ------------------------------------------------------------------ + /** @brief Subsample an animation track by a given sampling rate + * + * @param out Receives output keys. Last key at input defines the + * time where subsampling starts. + * @param time Time to end subsampling at + * @param sample_delta Time delta between two samples + */ + void SubsampleAnimTrack(std::vector& out, + double time,double sample_delta); + + // ------------------------------------------------------------------ + /** @brief Delete all keys which we inserted to match anim setup + */ + void ClearAnimRangeSetup(); + + // ------------------------------------------------------------------ + /** @brief Insert extra keys to match LWO's pre and post behaviours + * in a given time range [first...last] + */ + void UpdateAnimRangeSetup(); + +private: + std::list& envelopes; + double sample_rate; + + LWO::Envelope* trans_x, *trans_y, *trans_z; + LWO::Envelope* rotat_x, *rotat_y, *rotat_z; + LWO::Envelope* scale_x, *scale_y, *scale_z; + + double first, last; + bool need_to_setup; + + // temporary storage + LWO::Envelope* envl_x, * envl_y, * envl_z; + std::vector::const_iterator cur_x,cur_y,cur_z; + bool end_x, end_y, end_z; + + unsigned int flags; + double sample_delta; +}; + +} // end namespace LWO +} // end namespace Assimp + +#endif // !! AI_LWO_ANIMATION_INCLUDED diff --git a/code/LWOBLoader.cpp b/code/LWOBLoader.cpp index a295a26e5..48a6e41ec 100644 --- a/code/LWOBLoader.cpp +++ b/code/LWOBLoader.cpp @@ -178,8 +178,8 @@ void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it, { surface = -surface; - // there are detail polygons - uint16_t numPolygons = *cursor++; + // there are detail polygons. + const uint16_t numPolygons = *cursor++; if (cursor < end)CopyFaceIndicesLWOB(it,cursor,end,numPolygons); } face.surfaceIndex = surface-1; @@ -194,6 +194,27 @@ LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned i std::string type; GetS0(type,size); + const char* s = type.c_str(); + + if(strstr(s, "Image Map")) + { + // Determine mapping type + if(strstr(s, "Planar")) + tex->mapMode = LWO::Texture::Planar; + else if(strstr(s, "Cylindrical")) + tex->mapMode = LWO::Texture::Cylindrical; + else if(strstr(s, "Spherical")) + tex->mapMode = LWO::Texture::Spherical; + else if(strstr(s, "Cubic")) + tex->mapMode = LWO::Texture::Cubic; + else if(strstr(s, "Front")) + tex->mapMode = LWO::Texture::FrontProjection; + } + else + { + // procedural or gradient, not supported + DefaultLogger::get()->error("LWOB: Unsupported legacy texture: " + type); + } return tex; } @@ -271,7 +292,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) case AI_LWO_SMAN: { AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4); - surf.mMaximumSmoothAngle = GetF4(); + surf.mMaximumSmoothAngle = fabs( GetF4() ); break; } // glossiness @@ -323,8 +344,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) { GetS0(pTex->mFileName,head->length); } - else DefaultLogger::get()->warn("LWOB: TIMG tag was encuntered although " - "there was no xTEX tag before"); + else DefaultLogger::get()->warn("LWOB: Unexpected TIMG chunk"); break; } // texture strength @@ -332,8 +352,28 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) { AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TVAL,1); if (pTex)pTex->mStrength = (float)GetU1()/ 255.f; - else DefaultLogger::get()->warn("LWOB: TVAL tag was encuntered " - "although there was no xTEX tag before"); + else DefaultLogger::get()->warn("LWOB: Unexpected TVAL chunk"); + break; + } + // texture flags + case AI_LWO_TFLG: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TFLG,2); + + if (pTex) + { + const uint16_t s = GetU2(); + if (s & 1) + pTex->majorAxis = LWO::Texture::AXIS_X; + else if (s & 2) + pTex->majorAxis = LWO::Texture::AXIS_Y; + else if (s & 4) + pTex->majorAxis = LWO::Texture::AXIS_Z; + + if (s & 16) + DefaultLogger::get()->warn("LWOB: Ignoring \'negate\' flag on texture"); + } + else DefaultLogger::get()->warn("LWOB: Unexpected TFLG chunk"); break; } } diff --git a/code/LWOFileData.h b/code/LWOFileData.h index f018bfc23..b0a2e9ba3 100644 --- a/code/LWOFileData.h +++ b/code/LWOFileData.h @@ -38,10 +38,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines chunk constants used by the LWO file format +/** @file LWOFileData.h + * @brief Defines chunk constants used by the LWO file format The chunks are taken from the official LightWave SDK headers. -Original copyright notice: "Ernie Wright 17 Sep 00" */ #ifndef AI_LWO_FILEDATA_INCLUDED @@ -56,6 +56,7 @@ Original copyright notice: "Ernie Wright 17 Sep 00" // internal headers #include "IFF.h" +#include "LWOAnimation.h" namespace Assimp { namespace LWO { @@ -254,29 +255,45 @@ namespace LWO { */ struct Face : public aiFace { + //! Default construction Face() : surfaceIndex (0) , smoothGroup (0) + , type (AI_LWO_FACE) {} - Face(const Face& f) - { + //! Construction from given type + Face(uint32_t _type) + : surfaceIndex (0) + , smoothGroup (0) + , type (_type) + {} + + //! Copy construction + Face(const Face& f) { *this = f; } + //! Zero-based index into tags chunk unsigned int surfaceIndex; + + //! Smooth group this face is assigned to unsigned int smoothGroup; - Face& operator=(const LWO::Face& f) - { + //! Type of face + uint32_t type; + + + //! Assignment operator + Face& operator=(const LWO::Face& f) { aiFace::operator =(f); surfaceIndex = f.surfaceIndex; smoothGroup = f.smoothGroup; + type = f.type; return *this; } }; - // --------------------------------------------------------------------------- /** \brief Base structure for all vertex map representations */ @@ -473,8 +490,9 @@ struct Clip } type; Clip() - : type (UNSUPPORTED) - , idx (0) + : type (UNSUPPORTED) + , idx (0) + , negate (false) {} //! path to the base texture - @@ -485,6 +503,9 @@ struct Clip //! index of the clip unsigned int idx; + + //! Negate the clip? + bool negate; }; @@ -529,6 +550,7 @@ struct Surface , mIOR (1.f) // vakuum , mBumpIntensity (1.f) , mWireframe (false) + , mAdditiveTransparency (10e10f) {} //! Name of the surface @@ -571,6 +593,9 @@ struct Surface //! Wireframe flag bool mWireframe; + + //! Intensity of additive blending + float mAdditiveTransparency; }; // --------------------------------------------------------------------------- @@ -592,7 +617,7 @@ typedef std::vector < WeightChannel > WeightChannelList; typedef std::vector < VColorChannel > VColorChannelList; typedef std::vector < UVChannel > UVChannelList; typedef std::vector < Clip > ClipList; - +typedef std::vector < Envelope > EnvelopeList; // --------------------------------------------------------------------------- /** \brief Represents a layer in the file diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index ff72d82a7..95a38642e 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -68,21 +68,21 @@ LWOImporter::~LWOImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); + const std::string extension = GetExtension(pFile); + if (extension == "lwo" || extension == "lxo") + return true; - if (extension.length() < 4)return false; - if (extension[0] != '.')return false; - - return ! (extension[1] != 'l' && extension[1] != 'L' || - extension[2] != 'w' && extension[2] != 'W' && - extension[2] != 'x' && extension[2] != 'X' || - extension[3] != 'o' && extension[3] != 'O'); + // if check for extension is not enough, check for the magic tokens + if (!extension.length() || checkSig) { + uint32_t tokens[3]; + tokens[0] = AI_LWO_FOURCC_LWOB; + tokens[1] = AI_LWO_FOURCC_LWO2; + tokens[2] = AI_LWO_FOURCC_LXOB; + return CheckMagicToken(pIOHandler,pFile,tokens,3,8); + } + return false; } // ------------------------------------------------------------------------------------------------ @@ -109,21 +109,23 @@ void LWOImporter::InternReadFile( const std::string& pFile, if((this->fileSize = (unsigned int)file->FileSize()) < 12) throw new ImportErrorException("LWO: The file is too small to contain the IFF header"); - // allocate storage and copy the contents of the file to a memory buffer + // Allocate storage and copy the contents of the file to a memory buffer std::vector< uint8_t > mBuffer(fileSize); file->Read( &mBuffer[0], 1, fileSize); this->pScene = pScene; - // determine the type of the file + // Determine the type of the file uint32_t fileType; const char* sz = IFF::ReadHeader(&mBuffer[0],fileType); if (sz)throw new ImportErrorException(sz); mFileBuffer = &mBuffer[0] + 12; fileSize -= 12; - hasNamedLayer = false; - // create temporary storage on the stack but store pointers to it in the class + // Initialize some members with their default values + hasNamedLayer = false; + + // Create temporary storage on the stack but store pointers to it in the class // instance. Therefore everything will be destructed properly if an exception // is thrown and we needn't take care of that. LayerList _mLayers; @@ -218,6 +220,11 @@ void LWOImporter::InternReadFile( const std::string& pFile, for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end(); it != end;++it,++i) { + // Check whether we support this face's type + if ((*it).type != AI_LWO_FACE && (*it).type != AI_LWO_PTCH) { + continue; + } + unsigned int idx = (*it).surfaceIndex; if (idx >= mTags->size()) { @@ -282,7 +289,7 @@ void LWOImporter::InternReadFile( const std::string& pFile, if (0xffffffff == vUVChannelIndices[mui])break; pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices]; - // LightWave doesn't support more than 2 UV components + // LightWave doesn't support more than 2 UV components (?) // so we can directly setup this value mesh->mNumUVComponents[0] = 2; } @@ -318,6 +325,7 @@ void LWOImporter::InternReadFile( const std::string& pFile, register unsigned int idx = face.mIndices[q]; *pv = layer.mTempPoints[idx] + layer.mPivot; pv->z *= -1.0f; // DX to OGL + //std::swap(pv->z,pv->y); pv++; // process UV coordinates @@ -585,7 +593,8 @@ void LWOImporter::GenerateNodeGraph(std::vector& apcNodes) pScene->mRootNode->mChildren = apcNewNodes; pScene->mRootNode->mNumChildren = newSize; } - if (!pScene->mRootNode->mNumChildren)throw new ImportErrorException("LWO: Unable to build a valid node graph"); + if (!pScene->mRootNode->mNumChildren) + throw new ImportErrorException("LWO: Unable to build a valid node graph"); // remove a single root node // TODO: implement directly in the above loop, no need to deallocate here @@ -717,31 +726,44 @@ void LWOImporter::LoadLWOPoints(unsigned int length) void LWOImporter::LoadLWO2Polygons(unsigned int length) { LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length); - uint32_t type = GetU4(); + const uint32_t type = GetU4(); // Determine the type of the polygons switch (type) { + // read unsupported stuff too (although we wont process it) + case AI_LWO_BONE: + DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (BONE)"); + break; + case AI_LWO_MBAL: + DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (METABALL)"); + break; + case AI_LWO_CURV: + DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (SPLINE)");; + break; + + // These are ok with no restrictions case AI_LWO_PTCH: case AI_LWO_FACE: - break; default: - DefaultLogger::get()->warn("LWO2: Unsupported polygon type (PTCH and FACE are supported)"); + + // hm!? wtf is this? ok ... + DefaultLogger::get()->error("LWO2: Encountered unknown polygon type"); + break; } // first find out how many faces and vertices we'll finally need - uint16_t* cursor = (uint16_t*)mFileBuffer; + uint16_t* cursor= (uint16_t*)mFileBuffer; unsigned int iNumFaces = 0,iNumVertices = 0; CountVertsAndFacesLWO2(iNumVertices,iNumFaces,cursor,end); // allocate the output array and copy face indices - if (iNumFaces) - { + if (iNumFaces) { cursor = (uint16_t*)mFileBuffer; - mCurLayer->mFaces.resize(iNumFaces); + mCurLayer->mFaces.resize(iNumFaces,LWO::Face(type)); FaceList::iterator it = mCurLayer->mFaces.begin(); CopyFaceIndicesLWO2(it,cursor,end); } @@ -898,6 +920,7 @@ inline void AddToSingleLinkedList(ReferrerList& refList, unsigned int srcIdx, un } // ------------------------------------------------------------------------------------------------ +// Load LWO2 vertex map void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) { LE_NCONST uint8_t* const end = mFileBuffer+length; @@ -915,24 +938,24 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) switch (type) { case AI_LWO_TXUV: - if (dims != 2) - { + if (dims != 2) { DefaultLogger::get()->warn("LWO2: Found UV channel with != 2 components"); + return; } base = FindEntry(mCurLayer->mUVChannels,name,perPoly); break; case AI_LWO_WGHT: - if (dims != 1) - { + if (dims != 1) { DefaultLogger::get()->warn("LWO2: found vertex weight map with != 1 components"); + return; } base = FindEntry(mCurLayer->mWeightChannels,name,perPoly); break; case AI_LWO_RGB: case AI_LWO_RGBA: - if (dims != 3 && dims != 4) - { + if (dims != 3 && dims != 4) { DefaultLogger::get()->warn("LWO2: found vertex color map with != 3&4 components"); + return; } base = FindEntry(mCurLayer->mVColorChannels,name,perPoly); break; @@ -1028,6 +1051,7 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) } // ------------------------------------------------------------------------------------------------ +// Load LWO2 clip void LWOImporter::LoadLWO2Clip(unsigned int length) { AI_LWO_VALIDATE_CHUNK_LENGTH(length,CLIP,10); @@ -1042,6 +1066,7 @@ void LWOImporter::LoadLWO2Clip(unsigned int length) switch (head->type) { case AI_LWO_STIL: + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,STIL,1); // "Normal" texture GetS0(clip.path,head->length); @@ -1049,7 +1074,7 @@ void LWOImporter::LoadLWO2Clip(unsigned int length) break; case AI_LWO_ISEQ: - + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ISEQ,16); // Image sequence. We'll later take the first. { uint8_t digits = GetU1(); mFileBuffer++; @@ -1078,18 +1103,124 @@ void LWOImporter::LoadLWO2Clip(unsigned int length) break; case AI_LWO_XREF: + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,XREF,4); // Just a cross-reference to another CLIp clip.type = Clip::REF; clip.clipRef = GetU4(); break; + case AI_LWO_NEGA: + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,NEGA,2); + clip.negate = (0 != GetU2()); + break; + default: DefaultLogger::get()->warn("LWO2: Encountered unknown CLIP subchunk"); } } // ------------------------------------------------------------------------------------------------ +// Load envelope description +void LWOImporter::LoadLWO2Envelope(unsigned int length) +{ + LE_NCONST uint8_t* const end = mFileBuffer + length; + AI_LWO_VALIDATE_CHUNK_LENGTH(length,ENVL,4); + + mEnvelopes.push_back(LWO::Envelope()); + LWO::Envelope& envelope = mEnvelopes.back(); + + // Get the index of the envelope + envelope.index = ReadVSizedIntLWO2(mFileBuffer); + + // ... and read all subchunks + while (true) + { + if (mFileBuffer + 6 >= end)break; + LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer); + + if (mFileBuffer + head->length > end) + throw new ImportErrorException("LWO2: Invalid envelope chunk length"); + + uint8_t* const next = mFileBuffer+head->length; + switch (head->type) + { + // Type & representation of the envelope + case AI_LWO_TYPE: + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TYPE,2); + mFileBuffer++; // skip user format + + // Determine type of envelope + envelope.type = (LWO::EnvelopeType)*mFileBuffer; + ++mFileBuffer; + break; + + // precondition + case AI_LWO_PRE: + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,PRE,2); + envelope.pre = (LWO::PrePostBehaviour)GetU2(); + break; + + // postcondition + case AI_LWO_POST: + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,POST,2); + envelope.post = (LWO::PrePostBehaviour)GetU2(); + break; + + // keyframe + case AI_LWO_KEY: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,KEY,8); + + envelope.keys.push_back(LWO::Key()); + LWO::Key& key = envelope.keys.back(); + + key.time = GetF4(); + key.value = GetF4(); + break; + } + + // interval interpolation + case AI_LWO_SPAN: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPAN,4); + if (envelope.keys.size()<2) + DefaultLogger::get()->warn("LWO2: Unexpected SPAN chunk"); + else { + LWO::Key& key = envelope.keys.back(); + switch (GetU4()) + { + case AI_LWO_STEP: + key.inter = LWO::IT_STEP;break; + case AI_LWO_LINE: + key.inter = LWO::IT_LINE;break; + case AI_LWO_TCB: + key.inter = LWO::IT_TCB;break; + case AI_LWO_HERM: + key.inter = LWO::IT_HERM;break; + case AI_LWO_BEZI: + key.inter = LWO::IT_BEZI;break; + case AI_LWO_BEZ2: + key.inter = LWO::IT_BEZ2;break; + default: + DefaultLogger::get()->warn("LWO2: Unknown interval interpolation mode"); + }; + + // todo ... read params + } + break; + } + + default: + DefaultLogger::get()->warn("LWO2: Encountered unknown ENVL subchunk"); + } + // regardless how much we did actually read, go to the next chunk + mFileBuffer = next; + } +} + +// ------------------------------------------------------------------------------------------------ +// Load file - master function void LWOImporter::LoadLWO2File() { bool skip = false; @@ -1121,8 +1252,7 @@ void LWOImporter::LoadLWO2File() // load this layer or ignore it? Check the layer index property // NOTE: The first layer is the default layer, so the layer // index is one-based now - if (0xffffffff != configLayerIndex && configLayerIndex != mLayers->size()) - { + if (0xffffffff != configLayerIndex && configLayerIndex != mLayers->size()-1) { skip = true; } else skip = false; @@ -1138,16 +1268,14 @@ void LWOImporter::LoadLWO2File() GetS0(layer.mName,head->length-16); // if the name is empty, generate a default name - if (layer.mName.empty()) - { + if (layer.mName.empty()) { char buffer[128]; // should be sufficiently large ::sprintf(buffer,"Layer_%i", iUnnamed++); layer.mName = buffer; } // load this layer or ignore it? Check the layer name property - if (configLayerName.length() && configLayerName != layer.mName) - { + if (configLayerName.length() && configLayerName != layer.mName) { skip = true; } else hasNamedLayer = true; @@ -1161,7 +1289,8 @@ void LWOImporter::LoadLWO2File() // vertex list case AI_LWO_PNTS: { - if (skip)break; + if (skip) + break; unsigned int old = (unsigned int)mCurLayer->mTempPoints.size(); LoadLWOPoints(head->length); @@ -1178,7 +1307,8 @@ void LWOImporter::LoadLWO2File() // --- intentionally no break here case AI_LWO_VMAP: { - if (skip)break; + if (skip) + break; if (mCurLayer->mTempPoints.empty()) DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk"); @@ -1188,7 +1318,8 @@ void LWOImporter::LoadLWO2File() // face list case AI_LWO_POLS: { - if (skip)break; + if (skip) + break; unsigned int old = (unsigned int)mCurLayer->mFaces.size(); LoadLWO2Polygons(head->length); @@ -1198,7 +1329,8 @@ void LWOImporter::LoadLWO2File() // polygon tags case AI_LWO_PTAG: { - if (skip)break; + if (skip) + break; if (mCurLayer->mFaces.empty()) DefaultLogger::get()->warn("LWO2: Unexpected PTAG"); @@ -1227,9 +1359,16 @@ void LWOImporter::LoadLWO2File() LoadLWO2Clip(head->length); break; } + + // envelope chunk + case AI_LWO_ENVL: + { + LoadLWO2Envelope(head->length); + break; + } } mFileBuffer = next; } } -#endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER \ No newline at end of file +#endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER diff --git a/code/LWOLoader.h b/code/LWOLoader.h index cf05ed9f6..9e308599e 100644 --- a/code/LWOLoader.h +++ b/code/LWOLoader.h @@ -62,7 +62,7 @@ using namespace LWO; * Methods named "xxxLWOB[xxx]" are used with the older LWOB format. * Methods named "xxxLWO[xxx]" are used with both formats. * Methods named "xxx" are used to preprocess the loaded data - - * they aren't specific to one format version, either + * they aren't specific to one format version */ // --------------------------------------------------------------------------- class LWOImporter : public BaseImporter @@ -81,8 +81,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; // ------------------------------------------------------------------- @@ -211,6 +213,11 @@ private: */ void LoadLWO2Clip(unsigned int length); + // ------------------------------------------------------------------- + /** Load an envelope from an EVL chunk + * @param length Size of the chunk + */ + void LoadLWO2Envelope(unsigned int length); // ------------------------------------------------------------------- /** Count vertices and faces in a LWOB/LWO2 file @@ -372,6 +379,9 @@ protected: /** Temporary clip list from the file */ ClipList mClips; + /** Temporary envelope list from the file */ + EnvelopeList mEnvelopes; + /** file buffer */ uint8_t* mFileBuffer; @@ -381,9 +391,16 @@ protected: /** Output scene */ aiScene* pScene; + /** Configuration option: speed flag set? */ bool configSpeedFlag; + + /** Configuration option: index of layer to be loaded */ unsigned int configLayerIndex; + + /** Configuration option: name of layer to be loaded */ std::string configLayerName; + + /** True if we have a named layer */ bool hasNamedLayer; }; diff --git a/code/LWOMaterial.cpp b/code/LWOMaterial.cpp index 8afdeb8a9..1a82ab1b8 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWOMaterial.cpp @@ -183,13 +183,30 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a if (mClips.end() == clip) { DefaultLogger::get()->error("LWO2: Clip index is out of bounds"); temp = 0; + + // fixme: appearently some LWO files shipping with Doom3 don't + // have clips at all ... check whether that's true or whether + // it's a bug in the loader. + + s.Set("$texture.png"); + + //continue; } - if (Clip::UNSUPPORTED == (*clip).type) { - DefaultLogger::get()->error("LWO2: Clip type is not supported"); - continue; + else { + if (Clip::UNSUPPORTED == (*clip).type) { + DefaultLogger::get()->error("LWO2: Clip type is not supported"); + continue; + } + AdjustTexturePath((*clip).path); + s.Set((*clip).path); + + // Additional image settings + int flags = 0; + if ((*clip).negate) { + flags |= aiTextureFlags_Invert; + } + pcMat->AddProperty(&flags,1,AI_MATKEY_TEXFLAGS(type,cur)); } - AdjustTexturePath((*clip).path); - s.Set((*clip).path); } else { @@ -232,6 +249,7 @@ bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, a DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement"); } + // Setup texture operation pcMat->AddProperty((int*)&temp,1,AI_MATKEY_TEXOP(type,cur)); // setup the mapping mode @@ -258,12 +276,12 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat st.Set(surf.mName); pcMat->AddProperty(&st,AI_MATKEY_NAME); - int i = surf.bDoubleSided ? 1 : 0; - pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED); + const int i = surf.bDoubleSided ? 1 : 0; + pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED); // add the refraction index and the bump intensity - pcMat->AddProperty(&surf.mIOR,1,AI_MATKEY_REFRACTI); - pcMat->AddProperty(&surf.mBumpIntensity,1,AI_MATKEY_BUMPSCALING); + pcMat->AddProperty(&surf.mIOR,1,AI_MATKEY_REFRACTI); + pcMat->AddProperty(&surf.mBumpIntensity,1,AI_MATKEY_BUMPSCALING); aiShadingMode m; if (surf.mSpecularValue && surf.mGlossiness) @@ -281,16 +299,16 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat else fGloss = 80.0f; } - pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH); - pcMat->AddProperty(&fGloss,1,AI_MATKEY_SHININESS); + pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH); + pcMat->AddProperty(&fGloss,1,AI_MATKEY_SHININESS); m = aiShadingMode_Phong; } else m = aiShadingMode_Gouraud; // specular color aiColor3D clr = lerp( aiColor3D(1.f,1.f,1.f), surf.mColor, surf.mColorHighlights ); - pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_SPECULAR); - pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH); + pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_SPECULAR); + pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH); // emissive color // (luminosity is not really the same but it affects the surface in @@ -298,12 +316,21 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat clr.g = clr.b = clr.r = surf.mLuminosity*0.8f; pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE); - // opacity - if (10e10f != surf.mTransparency) + // opacity ... either additive or default-blended, please + if (10e10f != surf.mAdditiveTransparency) { - float f = 1.0f-surf.mTransparency; - pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY); + const int add = aiBlendMode_Additive; + pcMat->AddProperty(&surf.mAdditiveTransparency,1,AI_MATKEY_OPACITY); + pcMat->AddProperty(&add,1,AI_MATKEY_BLEND_FUNC); } + else if (10e10f != surf.mTransparency) + { + const int def = aiBlendMode_Default; + const float f = 1.0f-surf.mTransparency; + pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY); + pcMat->AddProperty(&def,1,AI_MATKEY_BLEND_FUNC); + } + // ADD TEXTURES to the material // TODO: find out how we can handle COLOR textures correctly... @@ -315,25 +342,21 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat HandleTextures(pcMat,surf.mOpacityTextures,aiTextureType_OPACITY); HandleTextures(pcMat,surf.mReflectionTextures,aiTextureType_REFLECTION); - // now we need to know which shader we must use + // Now we need to know which shader we must use // iterate through the shader list of the surface and - // search for a name we know + // search for a name which we know ... for (ShaderList::const_iterator it = surf.mShaders.begin(), end = surf.mShaders.end(); it != end;++it) { //if (!(*it).enabled)continue; - if ((*it).functionName == "LW_SuperCelShader" || - (*it).functionName == "AH_CelShader") - { + if ((*it).functionName == "LW_SuperCelShader" || (*it).functionName == "AH_CelShader") { DefaultLogger::get()->info("LWO2: Mapping LW_SuperCelShader/AH_CelShader " "to aiShadingMode_Toon"); m = aiShadingMode_Toon; break; } - else if ((*it).functionName == "LW_RealFresnel" || - (*it).functionName == "LW_FastFresnel") - { + else if ((*it).functionName == "LW_RealFresnel" || (*it).functionName == "LW_FastFresnel") { DefaultLogger::get()->info("LWO2: Mapping LW_RealFresnel/LW_FastFresnel " "to aiShadingMode_Fresnel"); @@ -345,12 +368,13 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat DefaultLogger::get()->warn("LWO2: Unknown surface shader: " + (*it).functionName); } } - if (surf.mMaximumSmoothAngle <= 0.0f)m = aiShadingMode_Flat; + if (surf.mMaximumSmoothAngle <= 0.0f) + m = aiShadingMode_Flat; pcMat->AddProperty((int*)&m,1,AI_MATKEY_SHADING_MODEL); // (the diffuse value is just a scaling factor) // If a diffuse texture is set, we set this value to 1.0 - clr = (b ? aiColor3D(1.f,1.f,1.f) : surf.mColor); + clr = (b && false ? aiColor3D(1.f,1.f,1.f) : surf.mColor); clr.r *= surf.mDiffuseValue; clr.g *= surf.mDiffuseValue; clr.b *= surf.mDiffuseValue; @@ -365,9 +389,7 @@ void LWOImporter::FindUVChannels(LWO::TextureList& list, LWO::Layer& layer, it != end;++it) { // Ignore textures with non-UV mappings for the moment. - if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex || - (*it).mapMode != LWO::Texture::UV) - { + if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex || (*it).mapMode != LWO::Texture::UV) { continue; } for (unsigned int i = 0; i < layer.mUVChannels.size();++i) @@ -379,6 +401,7 @@ void LWOImporter::FindUVChannels(LWO::TextureList& list, LWO::Layer& layer, { if (i == out[m]) { (*it).mRealUVIndex = m; + break; } } if (0xffffffff == (*it).mRealUVIndex) @@ -710,7 +733,9 @@ void LWOImporter::LoadLWO2Surface(unsigned int size) // transparency case AI_LWO_TRAN: { - if (surf.mTransparency == 10e10f)break; + // transparency explicitly disabled? + if (surf.mTransparency == 10e10f) + break; AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4); surf.mTransparency = GetF4(); @@ -741,6 +766,13 @@ void LWOImporter::LoadLWO2Surface(unsigned int size) } break; } + // additive transparency + case AI_LWO_ADTR: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ADTR,4); + surf.mAdditiveTransparency = GetF4(); + break; + } // wireframe mode case AI_LWO_LINE: { @@ -788,7 +820,7 @@ void LWOImporter::LoadLWO2Surface(unsigned int size) case AI_LWO_SMAN: { AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4); - surf.mMaximumSmoothAngle = GetF4(); + surf.mMaximumSmoothAngle = fabs( GetF4() ); break; } // vertex color channel to be applied to the surface diff --git a/code/LWSLoader.cpp b/code/LWSLoader.cpp index c0bb78c47..8bc71270b 100644 --- a/code/LWSLoader.cpp +++ b/code/LWSLoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the LWS importer class */ +/** @file LWSLoader.cpp + * @brief Implementation of the LWS importer class + */ #include "AssimpPCH.h" @@ -48,9 +50,60 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "fast_atof.h" #include "SceneCombiner.h" +#include "GenericProperty.h" +#include "SkeletonMeshBuilder.h" using namespace Assimp; +// ------------------------------------------------------------------------------------------------ +// Recursive parsing of LWS files +void LWS::Element::Parse (const char*& buffer) +{ + for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) { + + // begin of a new element with children + bool sub = false; + if (*buffer == '{') { + ++buffer; + SkipSpaces(&buffer); + sub = true; + } + else if (*buffer == '}') + return; + + children.push_back(Element()); + + // copy data line - read token per token + + const char* cur = buffer; + while (!IsSpaceOrNewLine(*buffer)) ++buffer; + children.back().tokens[0] = std::string(cur,(size_t) (buffer-cur)); + SkipSpaces(&buffer); + + if (children.back().tokens[0] == "Plugin") + { + DefaultLogger::get()->debug("LWS: Skipping over plugin-specific data"); + + // strange stuff inside Plugin/Endplugin blocks. Needn't + // follow LWS syntax, so we skip over it + for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) { + if (!::strncmp(buffer,"EndPlugin",9)) { + //SkipLine(&buffer); + break; + } + } + continue; + } + + cur = buffer; + while (!IsLineEnd(*buffer)) ++buffer; + children.back().tokens[1] = std::string(cur,(size_t) (buffer-cur)); + + // parse more elements recursively + if (sub) + children.back().Parse(buffer); + } +} // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer @@ -68,30 +121,755 @@ LWSImporter::~LWSImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler,bool checkSig) const { - std::string::size_type pos = pFile.find_last_of('.'); + const std::string extension = GetExtension(pFile); + if (extension == "lws" || extension == "mot") + return true; - // no file extension - can't read - if( pos == std::string::npos) - return false; - - std::string extension = pFile.substr( pos); - for (std::string::iterator i = extension.begin(); i != extension.end();++i) - *i = ::tolower(*i); - - return extension == ".lws"; + // if check for extension is not enough, check for the magic tokens LWSC and LWMO + if (!extension.length() || checkSig) { + uint32_t tokens[2]; + tokens[0] = AI_MAKE_MAGIC("LWSC"); + tokens[1] = AI_MAKE_MAGIC("LWMO"); + return CheckMagicToken(pIOHandler,pFile,tokens,2); + } + return false; } // ------------------------------------------------------------------------------------------------ +// Get list of file extensions void LWSImporter::GetExtensionList(std::string& append) { - append.append("*.lws"); + append.append("*.lws;*.mot"); } // ------------------------------------------------------------------------------------------------ +// Setup configuration properties +void LWSImporter::SetupProperties(const Importer* pImp) +{ + // AI_CONFIG_FAVOUR_SPEED + configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0)); + + // AI_CONFIG_IMPORT_LWS_ANIM_START + first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START, + 150392 /* magic hack */); + + // AI_CONFIG_IMPORT_LWS_ANIM_END + last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END, + 150392 /* magic hack */); + + if (last < first) { + std::swap(last,first); + } +} + +// ------------------------------------------------------------------------------------------------ +// Read an envelope description +void LWSImporter::ReadEnvelope(const LWS::Element& dad, LWO::Envelope& fill ) +{ + if (dad.children.empty()) { + DefaultLogger::get()->error("LWS: Envelope descriptions must not be empty"); + return; + } + + // reserve enough storage + std::list< LWS::Element >::const_iterator it = dad.children.begin();; + fill.keys.reserve(strtol10(it->tokens[1].c_str())); + + for (++it; it != dad.children.end(); ++it) { + const char* c = (*it).tokens[1].c_str(); + + if ((*it).tokens[0] == "Key") { + fill.keys.push_back(LWO::Key()); + LWO::Key& key = fill.keys.back(); + + float f; + SkipSpaces(&c); + c = fast_atof_move(c,key.value); + SkipSpaces(&c); + c = fast_atof_move(c,f); + + key.time = f; + + unsigned int span = strtol10(c,&c), num = 0; + switch (span) { + + case 0: + key.inter = LWO::IT_TCB; + num = 5; + break; + case 1: + case 2: + key.inter = LWO::IT_HERM; + num = 5; + break; + case 3: + key.inter = LWO::IT_LINE; + num = 0; + break; + case 4: + key.inter = LWO::IT_STEP; + num = 0; + break; + case 5: + key.inter = LWO::IT_BEZ2; + num = 4; + break; + default: + DefaultLogger::get()->error("LWS: Unknown span type"); + } + for (unsigned int i = 0; i < num;++i) { + SkipSpaces(&c); + c = fast_atof_move(c,key.params[i]); + } + } + else if ((*it).tokens[0] == "Behaviors") { + SkipSpaces(&c); + fill.pre = (LWO::PrePostBehaviour) strtol10(c,&c); + SkipSpaces(&c); + fill.post = (LWO::PrePostBehaviour) strtol10(c,&c); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Read animation channels in the old LightWave animation format +void LWSImporter::ReadEnvelope_Old( + std::list< LWS::Element >::const_iterator& it, + const std::list< LWS::Element >::const_iterator& end, + LWS::NodeDesc& nodes, + unsigned int version) +{ + unsigned int num,sub_num; + if (++it == end)goto unexpected_end; + + num = strtol10((*it).tokens[0].c_str()); + for (unsigned int i = 0; i < num; ++i) { + + nodes.channels.push_back(LWO::Envelope()); + LWO::Envelope& envl = nodes.channels.back(); + + envl.index = i; + envl.type = (LWO::EnvelopeType)(i+1); + + if (++it == end)goto unexpected_end; + sub_num = strtol10((*it).tokens[0].c_str()); + + for (unsigned int n = 0; n < sub_num;++n) { + + if (++it == end)goto unexpected_end; + + // parse value and time, skip the rest for the moment. + LWO::Key key; + const char* c = fast_atof_move((*it).tokens[0].c_str(),key.value); + SkipSpaces(&c); + float f; + fast_atof_move((*it).tokens[0].c_str(),f); + key.time = f; + + envl.keys.push_back(key); + } + } + return; + +unexpected_end: + DefaultLogger::get()->error("LWS: Encountered unexpected end of file while parsing object motion"); +} + +// ------------------------------------------------------------------------------------------------ +// Setup a nice name for a node +void LWSImporter::SetupNodeName(aiNode* nd, LWS::NodeDesc& src) +{ + const unsigned int combined = src.number | ((unsigned int)src.type) << 28u; + + // the name depends on the type. We break LWS's strange naming convention + // and return human-readable, but still machine-parsable and unique, strings. + if (src.type == LWS::NodeDesc::OBJECT) { + + if (src.path.length()) { + std::string::size_type s = src.path.find_last_of("\\/"); + if (s == std::string::npos) + s = 0; + else ++s; + + nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.path.substr(s).c_str(),combined); + return; + } + } + nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.name,combined); +} + +// ------------------------------------------------------------------------------------------------ +// Recursively build the scenegraph +void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector& attach, + BatchLoader& batch, + aiCamera**& camOut, + aiLight**& lightOut, + std::vector& animOut) +{ + // Setup a very cryptic name for the node, we want the user to be happy + SetupNodeName(nd,src); + + // If this is an object from an external file - get the scene + // and setup proper attachment tags + if (src.type == LWS::NodeDesc::OBJECT && src.path.length() ) { + aiScene* obj = batch.GetImport(src.id); + if (!obj) { + DefaultLogger::get()->error("LWS: Failed to read external file " + src.path); + } + else { + attach.push_back(AttachmentInfo(obj,nd)); + } + } + + // If object is a light source - setup a corresponding ai structure + else if (src.type == LWS::NodeDesc::LIGHT) { + aiLight* lit = *lightOut++ = new aiLight(); + + // compute final light color + lit->mColorDiffuse = lit->mColorSpecular = src.lightColor*src.lightIntensity; + + // name to attach light to node -> unique due to LWs indexing system + lit->mName = nd->mName; + + // detemine light type and setup additional members + if (src.lightType == 2) { /* spot light */ + + lit->mType = aiLightSource_SPOT; + lit->mAngleInnerCone = (float)AI_DEG_TO_RAD( src.lightConeAngle ); + lit->mAngleOuterCone = lit->mAngleInnerCone+(float)AI_DEG_TO_RAD( src.lightEdgeAngle ); + + } + else if (src.lightType == 1) { /* directional light source */ + lit->mType = aiLightSource_DIRECTIONAL; + } + else lit->mType = aiLightSource_POINT; + + // fixme: no proper handling of light falloffs yet + if (src.lightFalloffType == 1) + lit->mAttenuationConstant = 1.f; + else if (src.lightFalloffType == 1) + lit->mAttenuationLinear = 1.f; + else + lit->mAttenuationQuadratic = 1.f; + } + + // If object is a camera - setup a corresponding ai structure + else if (src.type == LWS::NodeDesc::CAMERA) { + aiCamera* cam = *camOut++ = new aiCamera(); + + // name to attach cam to node -> unique due to LWs indexing system + cam->mName = nd->mName; + } + + // Get the node transformation from the LWO key + LWO::AnimResolver resolver(src.channels,fps); + resolver.ExtractBindPose(nd->mTransformation); + + // .. and construct animation channels + aiNodeAnim* anim = NULL; +#if 0 /* not yet */ + if (first != last) { + resolver.SetAnimationRange(first,last); + resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO); + if (anim) { + anim->mNodeName = nd->mName; + animOut.push_back(anim); + } + } +#endif + + // process pivot point, if any + if (src.pivotPos != aiVector3D()) { + aiMatrix4x4 tmp; + aiMatrix4x4::Translation(-src.pivotPos,tmp); + + if (anim) { + + // We have an animation channel for this node. Problem: to combine the pivot + // point with the node anims, we'd need to interpolate *all* keys, get + // transformation matrices from them, apply the translation and decompose + // the resulting matrices again in order to reconstruct the keys. This + // solution here is *much* easier ... we're just inserting an extra node + // in the hierarchy. + // Maybe the final optimization here will be done during postprocessing. + + aiNode* pivot = new aiNode(); + pivot->mName.Set("$Pivot"); + pivot->mTransformation = tmp; + + pivot->mChildren = new aiNode*[pivot->mNumChildren = 1]; + pivot->mChildren[0] = nd; + + pivot->mParent = nd->mParent; + nd->mParent = pivot; + + // swap children ad hope the parents wont see a huge difference + pivot->mParent->mChildren[pivot->mParent->mNumChildren-1] = pivot; + } + else { + nd->mTransformation = tmp * nd->mTransformation; + } + } + + // Add children + if (src.children.size()) { + nd->mChildren = new aiNode*[src.children.size()]; + for (std::list::iterator it = src.children.begin(); it != src.children.end(); ++it) { + aiNode* ndd = nd->mChildren[nd->mNumChildren++] = new aiNode(); + ndd->mParent = nd; + + BuildGraph(ndd,**it,attach,batch,camOut,lightOut,animOut); + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Determine the exact location of a LWO file +std::string LWSImporter::FindLWOFile(const std::string& in) +{ + // insert missing directory seperator if necessary + std::string tmp; + if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/') + { + tmp = in[0] + ":\\" + in.substr(2); + } + else tmp = in; + + if (io->Exists(tmp)) + return in; + + // file is not accessible for us ... maybe it's packed by + // LightWave's 'Package Scene' command? + + // Relevant for us are the following two directories: + // \Objects\\<*>.lwo + // \Scenes\\<*>.lws + // where is optional. + + std::string test = ".." + io->getOsSeparator() + tmp; + if (io->Exists(test)) + return test; + + test = ".." + io->getOsSeparator() + test; + if (io->Exists(test)) + return test; + + // return original path, maybe the IOsystem knows better + return tmp; +} + +// ------------------------------------------------------------------------------------------------ +// Read file into given scene data structure void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { - return; + io = pIOHandler; + boost::scoped_ptr file( pIOHandler->Open( pFile, "rb")); + + // Check whether we can read from the file + if( file.get() == NULL) + throw new ImportErrorException( "Failed to open LWS file " + pFile + "."); + + // Allocate storage and copy the contents of the file to a memory buffer + const size_t fileSize = file->FileSize(); + std::vector< char > mBuffer(fileSize); + file->Read( &mBuffer[0], 1, fileSize); + + // Parse the file structure + LWS::Element root; const char* dummy = &mBuffer[0]; + root.Parse(dummy); + + // Construct a Batchimporter to read more files recursively + BatchLoader batch(pIOHandler); + batch.SetBasePath(pFile); + + // Construct an array to receive the flat output graph + std::list nodes; + + unsigned int cur_light = 0, cur_camera = 0, cur_object = 0; + unsigned int num_light = 0, num_camera = 0, num_object = 0; + + // check magic identifier, 'LWSC' + bool motion_file = false; + std::list< LWS::Element >::const_iterator it = root.children.begin(); + + if ((*it).tokens[0] == "LWMO") + motion_file = true; + + if ((*it).tokens[0] != "LWSC" && !motion_file) + throw new ImportErrorException("LWS: Not a LightWave scene, magic tag LWSC not found"); + + // get file format version and print to log + ++it; + unsigned int version = strtol10((*it).tokens[0].c_str()); + DefaultLogger::get()->info("LWS file format version is " + (*it).tokens[0]); + first = 0.; + last = 60.; + fps = 25.; /* seems to be a good default frame rate */ + + // Now read all elements in a very straghtforward manner + for (; it != root.children.end(); ++it) { + const char* c = (*it).tokens[1].c_str(); + + // 'FirstFrame': begin of animation slice + if ((*it).tokens[0] == "FirstFrame") { + if (150392. != first /* see SetupProperties() */) + first = strtol10(c,&c)-1.; /* we're zero-based */ + } + + // 'LastFrame': end of animation slice + else if ((*it).tokens[0] == "LastFrame") { + if (150392. != last /* see SetupProperties() */) + last = strtol10(c,&c)-1.; /* we're zero-based */ + } + + // 'FramesPerSecond': frames per second + else if ((*it).tokens[0] == "FramesPerSecond") { + fps = strtol10(c,&c); + } + + // 'LoadObjectLayer': load a layer of a specific LWO file + else if ((*it).tokens[0] == "LoadObjectLayer") { + + // get layer index + const int layer = strtol10(c,&c); + + // setup the layer to be loaded + BatchLoader::PropertyMap props; + SetGenericProperty(props.ints,AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,layer); + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + if (version >= 4) { // handle LWSC 4 explicit ID + SkipSpaces(&c); + d.number = strtol16(c,&c) & AI_LWS_MASK; + } + else d.number = cur_object++; + + // and add the file to the import list + SkipSpaces(&c); + std::string path = FindLWOFile( c ); + d.path = path; + d.id = batch.AddLoadRequest(path,0,&props); + + nodes.push_back(d); + num_object++; + } + // 'LoadObject': load a LWO file into the scenegraph + else if ((*it).tokens[0] == "LoadObject") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtol16(c,&c) & AI_LWS_MASK; + SkipSpaces(&c); + } + else d.number = cur_object++; + std::string path = FindLWOFile( c ); + d.id = batch.AddLoadRequest(path,0,NULL); + + d.path = path; + nodes.push_back(d); + num_object++; + } + // 'AddNullObject': add a dummy node to the hierarchy + else if ((*it).tokens[0] == "AddNullObject") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + d.name = c; + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtol16(c,&c) & AI_LWS_MASK; + } + else d.number = cur_object++; + nodes.push_back(d); + + num_object++; + } + // 'NumChannels': Number of envelope channels assigned to last layer + else if ((*it).tokens[0] == "NumChannels") { + // ignore for now + } + // 'Channel': preceedes any envelope description + else if ((*it).tokens[0] == "Channel") { + if (nodes.empty()) { + if (motion_file) { + + // LightWave motion file. Add dummy node + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + d.name = c; + d.number = cur_object++; + nodes.push_back(d); + } + else DefaultLogger::get()->error("LWS: Unexpected keyword: \'Channel\'"); + } + + // important: index of channel + nodes.back().channels.push_back(LWO::Envelope()); + LWO::Envelope& env = nodes.back().channels.back(); + + env.index = strtol10(c); + + // currently we can just interpret the standard channels 0...9 + // (hack) assume that index-i yields the binary channel type from LWO + env.type = (LWO::EnvelopeType)(env.index+1); + + } + // 'Envelope': a single animation channel + else if ((*it).tokens[0] == "Envelope") { + if (nodes.empty() || nodes.back().channels.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'Envelope\'"); + else { + ReadEnvelope((*it),nodes.back().channels.back()); + } + } + // 'ObjectMotion': animation information for older lightwave formats + else if (version < 3 && ((*it).tokens[0] == "ObjectMotion" || + (*it).tokens[0] == "CameraMotion" || + (*it).tokens[0] == "LightMotion")) { + + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'Motion\'"); + else { + ReadEnvelope_Old(it,root.children.end(),nodes.back(),version); + } + } + // 'Pre/PostBehavior': pre/post animation behaviour for LWSC 2 + else if (version == 2 && (*it).tokens[0] == "Pre/PostBehavior") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'Pre/PostBehavior'"); + else { + for (std::list::iterator it = nodes.back().channels.begin(); it != nodes.back().channels.end(); ++it) { + // two ints per envelope + LWO::Envelope& env = *it; + env.pre = (LWO::PrePostBehaviour) strtol10(c,&c); SkipSpaces(&c); + env.post = (LWO::PrePostBehaviour) strtol10(c,&c); SkipSpaces(&c); + } + } + } + // 'ParentItem': specifies the parent of the current element + else if ((*it).tokens[0] == "ParentItem") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentItem\'"); + + else nodes.back().parent = strtol16(c,&c); + } + // 'ParentObject': deprecated one for older formats + else if (version < 3 && (*it).tokens[0] == "ParentObject") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentObject\'"); + + else { + nodes.back().parent = strtol10(c,&c) | (1u << 28u); + } + } + // 'AddCamera': add a camera to the scenegraph + else if ((*it).tokens[0] == "AddCamera") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::CAMERA; + + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtol16(c,&c) & AI_LWS_MASK; + } + else d.number = cur_camera++; + nodes.push_back(d); + + num_camera++; + } + // 'CameraName': set name of currently active camera + else if ((*it).tokens[0] == "CameraName") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'CameraName\'"); + + else nodes.back().name = c; + } + // 'AddLight': add a light to the scenegraph + else if ((*it).tokens[0] == "AddLight") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::LIGHT; + + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtol16(c,&c) & AI_LWS_MASK; + } + else d.number = cur_light++; + nodes.push_back(d); + + num_light++; + } + // 'LightName': set name of currently active light + else if ((*it).tokens[0] == "LightName") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightName\'"); + + else nodes.back().name = c; + } + // 'LightIntensity': set intensity of currently active light + else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity" ) { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightIntensity\'"); + + else fast_atof_move(c, nodes.back().lightIntensity ); + + } + // 'LightType': set type of currently active light + else if ((*it).tokens[0] == "LightType") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightType\'"); + + else nodes.back().lightType = strtol10(c); + + } + // 'LightFalloffType': set falloff type of currently active light + else if ((*it).tokens[0] == "LightFalloffType") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightFalloffType\'"); + + else nodes.back().lightFalloffType = strtol10(c); + + } + // 'LightConeAngle': set cone angle of currently active light + else if ((*it).tokens[0] == "LightConeAngle") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightConeAngle\'"); + + else nodes.back().lightConeAngle = fast_atof(c); + + } + // 'LightEdgeAngle': set area where we're smoothing from min to max intensity + else if ((*it).tokens[0] == "LightEdgeAngle") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightEdgeAngle\'"); + + else nodes.back().lightEdgeAngle = fast_atof(c); + + } + // 'LightColor': set color of currently active light + else if ((*it).tokens[0] == "LightColor") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightColor\'"); + + else { + c = fast_atof_move(c, (float&) nodes.back().lightColor.r ); + SkipSpaces(&c); + c = fast_atof_move(c, (float&) nodes.back().lightColor.g ); + SkipSpaces(&c); + c = fast_atof_move(c, (float&) nodes.back().lightColor.b ); + } + } + + // 'PivotPosition': position of local transformation origin + else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'PivotPosition\'"); + else { + c = fast_atof_move(c, (float&) nodes.back().pivotPos.x ); + SkipSpaces(&c); + c = fast_atof_move(c, (float&) nodes.back().pivotPos.y ); + SkipSpaces(&c); + c = fast_atof_move(c, (float&) nodes.back().pivotPos.z ); + } + } + } + + // resolve parenting + for (std::list::iterator it = nodes.begin(); it != nodes.end(); ++it) { + + // check whether there is another node which calls us a parent + for (std::list::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) { + if (dit != it && *it == (*dit).parent) { + if ((*dit).parent_resolved) { + // fixme: it's still possible to produce an overflow due to cross references .. + DefaultLogger::get()->error("LWS: Found cross reference in scenegraph"); + continue; + } + + (*it).children.push_back(&*dit); + (*dit).parent_resolved = &*it; + } + } + } + + // find out how many nodes have no parent yet + unsigned int no_parent = 0; + for (std::list::iterator it = nodes.begin(); it != nodes.end(); ++it) { + if (!(*it).parent_resolved) + ++ no_parent; + } + if (!no_parent) + throw new ImportErrorException("LWS: Unable to find scene root node"); + + + // Load all subsequent files + batch.LoadAll(); + + // and build the final output graph by attaching the loaded external + // files to ourselves. first build a master graph + aiScene* master = new aiScene(); + aiNode* nd = master->mRootNode = new aiNode(); + + // allocate storage for cameras&lights + if (num_camera) { + master->mCameras = new aiCamera*[master->mNumCameras = num_camera]; + } + aiCamera** cams = master->mCameras; + if (num_light) { + master->mLights = new aiLight*[master->mNumLights = num_light]; + } + aiLight** lights = master->mLights; + + std::vector attach; + std::vector anims; + + nd->mName.Set(""); + nd->mChildren = new aiNode*[no_parent]; + for (std::list::iterator it = nodes.begin(); it != nodes.end(); ++it) { + if (!(*it).parent_resolved) { + aiNode* ro = nd->mChildren[ nd->mNumChildren++ ] = new aiNode(); + ro->mParent = nd; + + // ... and build the scene graph. If we encounter object nodes, + // add then to our attachment table. + BuildGraph(ro,*it, attach, batch, cams, lights, anims); + } + } + + // create a master animation channel for us + if (anims.size()) { + master->mAnimations = new aiAnimation*[master->mNumAnimations = 1]; + aiAnimation* anim = master->mAnimations[0] = new aiAnimation(); + anim->mName.Set("LWSMasterAnim"); + + // LWS uses seconds as time units, but we convert to frames + anim->mTicksPerSecond = fps; + anim->mDuration = last-(first-1); /* fixme ... zero or one-based?*/ + + anim->mChannels = new aiNodeAnim*[anim->mNumChannels = anims.size()]; + std::copy(anims.begin(),anims.end(),anim->mChannels); + } + + // OK ... finally build the output graph + SceneCombiner::MergeScenes(&pScene,master,attach, + AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( + AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : 0)); + + // Check flags + if (!pScene->mNumMeshes || !pScene->mNumMaterials) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + + if (pScene->mNumAnimations) { + // construct skeleton mesh + SkeletonMeshBuilder builder(pScene); + } + } } diff --git a/code/LWSLoader.h b/code/LWSLoader.h index 766a7c3b9..0835748a4 100644 --- a/code/LWSLoader.h +++ b/code/LWSLoader.h @@ -38,10 +38,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the .LWS (LightWave Scene Format) importer class. */ +/** @file LWSLoader.h + * @brief Declaration of the LightWave scene importer class. + */ #ifndef AI_LWSLOADER_H_INCLUDED #define AI_LWSLOADER_H_INCLUDED +#include "LWOFileData.h" +#include "SceneCombiner.h" namespace Assimp { namespace LWS { @@ -49,17 +53,107 @@ namespace Assimp { // --------------------------------------------------------------------------- /** Represents an element in a LWS file. * - * This can either be a single data line - or it can - * be a data group - { name ... n } + * This can either be a single data line - or a data + * group - { name ... n } */ class Element { - std::string name, data; +public: + Element() + {} + + // first: name, second: rest + std::string tokens[2]; std::list children; - void Parse (const char* buffer); + //! Recursive parsing function + void Parse (const char*& buffer); }; +#define AI_LWS_MASK (0xffffffff >> 4u) + +// --------------------------------------------------------------------------- +/** Represents a LWS scenegraph element + */ +struct NodeDesc +{ + NodeDesc() + : number (0) + , parent (0) + , name ("") + , parent_resolved (NULL) + , lightIntensity (1.f) + , lightColor (1.f,1.f,1.f) + , lightType (0) + , lightFalloffType (0) + , lightConeAngle (45.f) + {} + + enum { + + OBJECT = 1, + LIGHT = 2, + CAMERA = 3, + BONE = 4, + } type; // type of node + + // if object: path + std::string path; + unsigned int id; + + // number of object + unsigned int number; + + // index of parent index + unsigned int parent; + + // lights & cameras & dummies: name + const char* name; + + // animation channels + std::list< LWO::Envelope > channels; + + // position of pivot point + aiVector3D pivotPos; + + + + // color of light source + aiColor3D lightColor; + + // intensity of light source + float lightIntensity; + + // type of light source + unsigned int lightType; + + // falloff type of light source + unsigned int lightFalloffType; + + // cone angle of (spot) light source + float lightConeAngle; + + // soft cone angle of (spot) light source + float lightEdgeAngle; + + + + // list of resolved children + std::list< NodeDesc* > children; + + // resolved parent node + NodeDesc* parent_resolved; + + + // for std::find() + bool operator == (unsigned int num) const { + if (!num) + return false; + unsigned int _type = num >> 28u; + + return _type == type && (num & AI_LWS_MASK) == number; + } +}; } // end namespace LWS @@ -84,28 +178,63 @@ protected: public: // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + // Check whether we can read a specific file + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: // ------------------------------------------------------------------- - /** Called by Importer::GetExtensionList() for each loaded importer. - * See BaseImporter::GetExtensionList() for details - */ + // Get list of supported extensions void GetExtensionList(std::string& append); // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ + // Import file into given scene data structure void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + // ------------------------------------------------------------------- + // Setup import properties + void SetupProperties(const Importer* pImp); + private: + // ------------------------------------------------------------------- + // Read an envelope description + void ReadEnvelope(const LWS::Element& dad, LWO::Envelope& out ); + + // ------------------------------------------------------------------- + // Read an envelope description for the older LW file format + void ReadEnvelope_Old(std::list< LWS::Element >::const_iterator& it, + const std::list< LWS::Element >::const_iterator& end, + LWS::NodeDesc& nodes, + unsigned int version); + + // ------------------------------------------------------------------- + // Setup a nice name for a node + void SetupNodeName(aiNode* nd, LWS::NodeDesc& src); + + // ------------------------------------------------------------------- + // Recursively build the scenegraph + void BuildGraph(aiNode* nd, + LWS::NodeDesc& src, + std::vector& attach, + BatchLoader& batch, + aiCamera**& camOut, + aiLight**& lightOut, + std::vector& animOut); + + // ------------------------------------------------------------------- + // Try several dirs until we find the right location of a LWS file. + std::string FindLWOFile(const std::string& in); + +private: + + bool configSpeedFlag; + IOSystem* io; + + double first,last,fps; }; } // end of namespace Assimp diff --git a/code/MD2FileData.h b/code/MD2FileData.h index 7a0ac94c6..45c695fa8 100644 --- a/code/MD2FileData.h +++ b/code/MD2FileData.h @@ -38,21 +38,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines the helper data structures for importing MD2 files - -********************************************************************** -File format specification: -//http://linux.ucla.edu/~phaethon/q3/formats/md2-schoenblum.html -********************************************************************** - -*/ +/** @file MD2FileData.h + * @brief Defines helper data structures for importing MD2 files + * http://linux.ucla.edu/~phaethon/q3/formats/md2-schoenblum.html + */ #ifndef AI_MD2FILEHELPER_H_INC #define AI_MD2FILEHELPER_H_INC -#include -#include -#include - #include "../include/aiTypes.h" #include "../include/aiMesh.h" #include "../include/aiAnim.h" @@ -62,11 +54,9 @@ File format specification: namespace Assimp { namespace MD2 { -// to make it easier for ourselfes, we test the magic word against both "endianesses" -#define MD2_MAKE(string) ((uint32_t)((string[0] << 24) + (string[1] << 16) + (string[2] << 8) + string[3])) - -#define AI_MD2_MAGIC_NUMBER_BE MD2_MAKE("IDP2") -#define AI_MD2_MAGIC_NUMBER_LE MD2_MAKE("2PDI") +// to make it easier for us, we test the magic word against both "endianesses" +#define AI_MD2_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDP2") +#define AI_MD2_MAGIC_NUMBER_LE AI_MAKE_MAGIC("2PDI") // common limitations #define AI_MD2_VERSION 15 diff --git a/code/MD2Loader.cpp b/code/MD2Loader.cpp index e990c44dc..ae3614dd9 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2Loader.cpp @@ -62,11 +62,8 @@ using namespace Assimp::MD2; void MD2::LookupNormalIndex(uint8_t iNormalIndex,aiVector3D& vOut) { // make sure the normal index has a valid value - if (iNormalIndex >= ARRAYSIZE(g_avNormals)) - { - DefaultLogger::get()->warn("Index overflow in Quake II normal vector list (the " - " LUT has only 162 entries). "); - + if (iNormalIndex >= ARRAYSIZE(g_avNormals)) { + DefaultLogger::get()->warn("Index overflow in Quake II normal vector list"); iNormalIndex = ARRAYSIZE(g_avNormals) - 1; } vOut = *((const aiVector3D*)(&g_avNormals[iNormalIndex])); @@ -76,31 +73,37 @@ void MD2::LookupNormalIndex(uint8_t iNormalIndex,aiVector3D& vOut) // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer MD2Importer::MD2Importer() -{ -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well MD2Importer::~MD2Importer() -{ -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - - std::string extension = pFile.substr( pos); - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); + const std::string extension = GetExtension(pFile); + if (extension == "md2") + return true; - return ( extension == ".md2"); + // if check for extension is not enough, check for the magic tokens + if (!extension.length() || checkSig) { + uint32_t tokens[1]; + tokens[0] = AI_MD2_MAGIC_NUMBER_LE; + return CheckMagicToken(pIOHandler,pFile,tokens,1); + } + return false; } + +// ------------------------------------------------------------------------------------------------ +// Get a list of all extensions supported by this loader +void MD2Importer::GetExtensionList(std::string& append) +{ + append.append("*.md2"); +} + // ------------------------------------------------------------------------------------------------ // Setup configuration properties void MD2Importer::SetupProperties(const Importer* pImp) @@ -161,8 +164,8 @@ void MD2Importer::ValidateHeader( ) if (m_pcHeader->numFrames <= configFrameID ) throw new ImportErrorException("The requested frame is not existing the file"); - } + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void MD2Importer::InternReadFile( const std::string& pFile, @@ -319,14 +322,14 @@ void MD2Importer::InternReadFile( const std::string& pFile, pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); aiString szName; - szName.Set("MD2Default"); + szName.Set(AI_DEFAULT_TEXTURED_MATERIAL_NAME); pcHelper->AddProperty(&szName,AI_MATKEY_NAME); aiString sz; // TODO: Try to guess the name of the texture file from the model file name - sz.Set("texture_dummmy.bmp"); + sz.Set("$texture_dummy.bmp"); pcHelper->AddProperty(&sz,AI_MATKEY_TEXTURE_DIFFUSE(0)); } diff --git a/code/MD2Loader.h b/code/MD2Loader.h index faeaeb8e2..314c54747 100644 --- a/code/MD2Loader.h +++ b/code/MD2Loader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Definition of the .MD2 importer class. */ +/** @file MD2Loader.h + * @brief Declaration of the .MD2 importer class. + */ #ifndef AI_MD2LOADER_H_INCLUDED #define AI_MD2LOADER_H_INCLUDED @@ -48,14 +50,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiNode; #include "MD2FileData.h" -namespace Assimp -{ +namespace Assimp { class MaterialHelper; using namespace MD2; // --------------------------------------------------------------------------- -/** Used to load MD2 files +/** Importer class for MD2 */ class MD2Importer : public BaseImporter { @@ -73,7 +74,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; // ------------------------------------------------------------------- @@ -89,10 +91,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.md2"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/MD3FileData.h b/code/MD3FileData.h index 50a62bf7b..49bcab966 100644 --- a/code/MD3FileData.h +++ b/code/MD3FileData.h @@ -59,11 +59,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace MD3 { -// to make it easier for ourselfes, we test the magic word against both "endianesses" -#define MD3_MAKE(string) ((uint32_t)((string[0] << 24) + (string[1] << 16) + (string[2] << 8) + string[3])) - -#define AI_MD3_MAGIC_NUMBER_BE MD3_MAKE("IDP3") -#define AI_MD3_MAGIC_NUMBER_LE MD3_MAKE("3PDI") +// to make it easier for us, we test the magic word against both "endianesses" +#define AI_MD3_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDP3") +#define AI_MD3_MAGIC_NUMBER_LE AI_MAKE_MAGIC("3PDI") // common limitations #define AI_MD3_VERSION 15 diff --git a/code/MD3Loader.cpp b/code/MD3Loader.cpp index ed17302d8..de7f17af8 100644 --- a/code/MD3Loader.cpp +++ b/code/MD3Loader.cpp @@ -344,18 +344,19 @@ MD3Importer::~MD3Importer() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool MD3Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool MD3Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); + const std::string extension = GetExtension(pFile); + if (extension == "md3") + return true; - return ( extension == ".md3"); + // if check for extension is not enough, check for the magic tokens + if (!extension.length() || checkSig) { + uint32_t tokens[1]; + tokens[0] = AI_MD3_MAGIC_NUMBER_LE; + return CheckMagicToken(pIOHandler,pFile,tokens,1); + } + return false; } // ------------------------------------------------------------------------------------------------ @@ -436,6 +437,9 @@ void MD3Importer::SetupProperties(const Importer* pImp) // AI_CONFIG_IMPORT_MD3_SHADER_SRC configShaderFile = (pImp->GetPropertyString(AI_CONFIG_IMPORT_MD3_SHADER_SRC,"")); + + // AI_CONFIG_FAVOUR_SPEED + configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0)); } // ------------------------------------------------------------------------------------------------ @@ -458,10 +462,7 @@ void MD3Importer::ReadSkin(Q3Shader::SkinData& fill) const void MD3Importer::ReadShader(Q3Shader::ShaderData& fill) const { // Determine Q3 model name from given path - std::string::size_type s = path.find_last_of('\\',path.length()-2); - if (s == std::string::npos) - s = path.find_last_of('/',path.length()-2); - + std::string::size_type s = path.find_last_of("\\/",path.length()-2); const std::string model_file = path.substr(s+1,path.length()-(s+2)); // If no specific dir or file is given, use our default search behaviour @@ -486,6 +487,24 @@ void MD3Importer::ReadShader(Q3Shader::ShaderData& fill) const } } +// ------------------------------------------------------------------------------------------------ +// Tiny helper to remove a single node from its parent' list +void RemoveSingleNodeFromList(aiNode* nd) +{ + if (!nd || nd->mNumChildren || !nd->mParent)return; + aiNode* par = nd->mParent; + for (unsigned int i = 0; i < par->mNumChildren;++i) { + if (par->mChildren[i] == nd) { + --par->mNumChildren; + for (;i < par->mNumChildren;++i) { + par->mChildren[i] = par->mChildren[i+1]; + } + delete nd; + break; + } + } +} + // ------------------------------------------------------------------------------------------------ // Read a multi-part Q3 player model bool MD3Importer::ReadMultipartFile() @@ -520,32 +539,32 @@ bool MD3Importer::ReadMultipartFile() // now read these three files BatchLoader batch(mIOHandler); - batch.AddLoadRequest(lower,0,&props); - batch.AddLoadRequest(upper,0,&props); - batch.AddLoadRequest(head,0,&props); + unsigned int _lower = batch.AddLoadRequest(lower,0,&props); + unsigned int _upper = batch.AddLoadRequest(upper,0,&props); + unsigned int _head = batch.AddLoadRequest(head,0,&props); batch.LoadAll(); // now construct a dummy scene to place these three parts in aiScene* master = new aiScene(); aiNode* nd = master->mRootNode = new aiNode(); - nd->mName.Set(""); + nd->mName.Set(""); // ... and get them. We need all of them. - scene_lower = batch.GetImport(lower); + scene_lower = batch.GetImport(_lower); if (!scene_lower) { DefaultLogger::get()->error("M3D: Failed to read multipart model, lower.md3 fails to load"); failure = "lower"; goto error_cleanup; } - scene_upper = batch.GetImport(upper); + scene_upper = batch.GetImport(_upper); if (!scene_upper) { DefaultLogger::get()->error("M3D: Failed to read multipart model, upper.md3 fails to load"); failure = "upper"; goto error_cleanup; } - scene_head = batch.GetImport(head); + scene_head = batch.GetImport(_head); if (!scene_head) { DefaultLogger::get()->error("M3D: Failed to read multipart model, head.md3 fails to load"); failure = "head"; @@ -555,6 +574,7 @@ bool MD3Importer::ReadMultipartFile() // build attachment infos. search for typical Q3 tags // original root + scene_lower->mRootNode->mName.Set("lower"); attach.push_back(AttachmentInfo(scene_lower, nd)); // tag_torso @@ -563,6 +583,7 @@ bool MD3Importer::ReadMultipartFile() DefaultLogger::get()->error("M3D: Failed to find attachment tag for multipart model: tag_torso expected"); goto error_cleanup; } + scene_upper->mRootNode->mName.Set("upper"); attach.push_back(AttachmentInfo(scene_upper,tag_torso)); // tag_head @@ -571,13 +592,21 @@ bool MD3Importer::ReadMultipartFile() DefaultLogger::get()->error("M3D: Failed to find attachment tag for multipart model: tag_head expected"); goto error_cleanup; } + scene_head->mRootNode->mName.Set("head"); attach.push_back(AttachmentInfo(scene_head,tag_head)); + // Remove tag_head and tag_torso from all other model parts ... + // this ensures (together with AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) + // that tag_torso/tag_head is also the name of the (unique) output node + RemoveSingleNodeFromList (scene_upper->mRootNode->FindNode("tag_torso")); + RemoveSingleNodeFromList (scene_head-> mRootNode->FindNode("tag_head" )); + // and merge the scenes SceneCombiner::MergeScenes(&mScene,master, attach, - AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | - AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES | - AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS); + AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | + AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES | + AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS | + (!configSpeedFlag ? AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY : 0)); return true; diff --git a/code/MD3Loader.h b/code/MD3Loader.h index 57cd14f4d..f2795963e 100644 --- a/code/MD3Loader.h +++ b/code/MD3Loader.h @@ -225,7 +225,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; // ------------------------------------------------------------------- @@ -297,6 +298,9 @@ protected: /** Configuration option: name or path of shader */ std::string configShaderFile; + /** Configuration option: speed flag was set? */ + bool configSpeedFlag; + /** Header of the MD3 file */ BE_NCONST MD3::Header* pcHeader; diff --git a/code/MD5Loader.cpp b/code/MD5Loader.cpp index c78202978..1b59f01a2 100644 --- a/code/MD5Loader.cpp +++ b/code/MD5Loader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the MD5 importer class */ +/** @file MD5Loader.cpp + * @brief Implementation of the MD5 importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_MD5_IMPORTER @@ -56,34 +58,35 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer MD5Importer::MD5Importer() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well MD5Importer::~MD5Importer() -{ - // nothing to do here -} +{} + // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool MD5Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool MD5Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); + const std::string extension = GetExtension(pFile); - if (extension.length() < 4)return false; - if (extension[0] != '.')return false; + if (extension == "md5anim" || extension == "md5mesh") + return true; + else if (!extension.length() || checkSig) { + if (!pIOHandler) + return true; + const char* tokens[] = {"MD5Version"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; +} - if (extension[1] != 'm' && extension[1] != 'M')return false; - if (extension[2] != 'd' && extension[2] != 'D')return false; - if (extension[3] != '5')return false; - return true; +// ------------------------------------------------------------------------------------------------ +// Get list of all supported extensions +void MD5Importer::GetExtensionList(std::string& append) +{ + append.append("*.md5mesh;*.md5anim"); } // ------------------------------------------------------------------------------------------------ @@ -93,17 +96,17 @@ void MD5Importer::InternReadFile( { // remove the file extension std::string::size_type pos = pFile.find_last_of('.'); - this->mFile = pFile.substr(0,pos+1); + mFile = pFile.substr(0,pos+1); this->pIOHandler = pIOHandler; this->pScene = pScene; bHadMD5Mesh = bHadMD5Anim = false; // load the animation keyframes - this->LoadMD5AnimFile(); + LoadMD5AnimFile(); // load the mesh vertices and bones - this->LoadMD5MeshFile(); + LoadMD5MeshFile(); // make sure we return no incomplete data if (!bHadMD5Mesh && !bHadMD5Anim) @@ -260,7 +263,7 @@ void MD5Importer::LoadMD5MeshFile () bHadMD5Mesh = true; // now load the file into memory - this->LoadFileIntoMemory(file.get()); + LoadFileIntoMemory(file.get()); // now construct a parser and parse the file MD5::MD5Parser parser(mBuffer,fileSize); @@ -341,10 +344,7 @@ void MD5Importer::LoadMD5MeshFile () unsigned int* piCount = new unsigned int[meshParser.mJoints.size()]; ::memset(piCount,0,sizeof(unsigned int)*meshParser.mJoints.size()); - for (MD5::VertexList::const_iterator - iter = meshSrc.mVertices.begin(); - iter != meshSrc.mVertices.end();++iter,++pv) - { + for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin();iter != meshSrc.mVertices.end();++iter,++pv) { for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w) { MD5::WeightDesc& desc = meshSrc.mWeights[w]; @@ -444,7 +444,7 @@ void MD5Importer::LoadMD5MeshFile () // ------------------------------------------------------------------------------------------------ void MD5Importer::LoadMD5AnimFile () { - std::string pFile = this->mFile + "MD5ANIM"; + std::string pFile = mFile + "MD5ANIM"; boost::scoped_ptr file( pIOHandler->Open( pFile, "rb")); // Check whether we can read from the file diff --git a/code/MD5Loader.h b/code/MD5Loader.h index 9ced176b2..c2c7d8981 100644 --- a/code/MD5Loader.h +++ b/code/MD5Loader.h @@ -39,8 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** @file Definition of the .MD5 importer class. -http://www.modwiki.net/wiki/MD5_(file_format) +/** @file MD5Loader.h + * @brief Definition of the .MD5 importer class. + * http://www.modwiki.net/wiki/MD5_(file_format) */ #ifndef AI_MD5LOADER_H_INCLUDED #define AI_MD5LOADER_H_INCLUDED @@ -74,7 +75,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -82,11 +84,8 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.md5mesh;*.md5anim"); - } - + void GetExtensionList(std::string& append); + // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. * See BaseImporter::InternReadFile() for details diff --git a/code/MD5Parser.cpp b/code/MD5Parser.cpp index c253da2ed..bd25b6dbe 100644 --- a/code/MD5Parser.cpp +++ b/code/MD5Parser.cpp @@ -112,21 +112,22 @@ void MD5Parser::ParseHeader() if (0 != ASSIMP_strincmp(buffer,"MD5Version",10) || !IsSpace(*(buffer+=10))) { - this->ReportError("Invalid MD5 file: MD5Version tag has not been found"); + ReportError("Invalid MD5 file: MD5Version tag has not been found"); } SkipSpaces(); unsigned int iVer = ::strtol10(buffer,(const char**)&buffer); if (10 != iVer) { - this->ReportWarning("MD5 version tag is unknown (10 is expected)"); + ReportWarning("MD5 version tag is unknown (10 is expected)"); } - this->SkipLine(); + SkipLine(); // print the command line options to the console + // fix: can break the log length limit ... char* sz = buffer; while (!IsLineEnd( *buffer++)); - DefaultLogger::get()->info(std::string(sz,(uintptr_t)(buffer-sz))); - this->SkipSpacesAndLineEnd(); + DefaultLogger::get()->info(std::string(sz,std::min((uintptr_t)MAX_LOG_MESSAGE_LENGTH, (uintptr_t)(buffer-sz)))); + SkipSpacesAndLineEnd(); } // ------------------------------------------------------------------------------------------------ bool MD5Parser::ParseSection(Section& out) diff --git a/code/MD5Parser.h b/code/MD5Parser.h index 41156d7e5..5ad5a92fc 100644 --- a/code/MD5Parser.h +++ b/code/MD5Parser.h @@ -39,21 +39,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** @file Definition of the .MD5 parser class. -http://www.modwiki.net/wiki/MD5_(file_format) -*/ +/** @file MD5Parser.h + * @brief Definition of the .MD5 parser class. + * http://www.modwiki.net/wiki/MD5_(file_format) + */ #ifndef AI_MD5PARSER_H_INCLUDED #define AI_MD5PARSER_H_INCLUDED #include "../include/aiTypes.h" #include "ParsingUtils.h" -#include struct aiFace; namespace Assimp { -namespace MD5 { - +namespace MD5 { // --------------------------------------------------------------------------- /** Represents a single element in a MD5 file @@ -335,12 +334,13 @@ public: static void ReportWarning (const char* warn, unsigned int line); - inline void ReportError (const char* error) - {return ReportError(error, this->lineNumber);} - - inline void ReportWarning (const char* warn) - {return ReportWarning(warn, this->lineNumber);} + void ReportError (const char* error) { + return ReportError(error, lineNumber); + } + void ReportWarning (const char* warn) { + return ReportWarning(warn, lineNumber); + } public: @@ -367,24 +367,22 @@ private: // override these functions to make sure the line counter gets incremented // ------------------------------------------------------------------- - inline bool SkipLine( const char* in, const char** out) + bool SkipLine( const char* in, const char** out) { ++lineNumber; return Assimp::SkipLine(in,out); } // ------------------------------------------------------------------- - inline bool SkipLine( ) + bool SkipLine( ) { return SkipLine(buffer,(const char**)&buffer); } // ------------------------------------------------------------------- - inline bool SkipSpacesAndLineEnd( const char* in, const char** out) + bool SkipSpacesAndLineEnd( const char* in, const char** out) { bool bHad = false; - while (true) - { - if( *in == '\r' || *in == '\n') - { + while (true) { + if( *in == '\r' || *in == '\n') { if (!bHad) // we open files in binary mode, so there could be \r\n sequences ... { bHad = true; @@ -400,12 +398,12 @@ private: return *in != '\0'; } // ------------------------------------------------------------------- - inline bool SkipSpacesAndLineEnd( ) + bool SkipSpacesAndLineEnd( ) { return SkipSpacesAndLineEnd(buffer,(const char**)&buffer); } // ------------------------------------------------------------------- - inline bool SkipSpaces( ) + bool SkipSpaces( ) { return Assimp::SkipSpaces((const char**)&buffer); } diff --git a/code/MDCFileData.h b/code/MDCFileData.h index e2438f0d0..99bfc2ccd 100644 --- a/code/MDCFileData.h +++ b/code/MDCFileData.h @@ -60,11 +60,9 @@ namespace Assimp { namespace MDC { -// to make it easier for ourselfes, we test the magic word against both "endianesses" -#define MDC_MAKE(string) ((uint32_t)((string[0] << 24) + (string[1] << 16) + (string[2] << 8) + string[3])) - -#define AI_MDC_MAGIC_NUMBER_BE MDC_MAKE("CPDI") -#define AI_MDC_MAGIC_NUMBER_LE MDC_MAKE("IDPC") +// to make it easier for us, we test the magic word against both "endianesses" +#define AI_MDC_MAGIC_NUMBER_BE AI_MAKE_MAGIC("CPDI") +#define AI_MDC_MAGIC_NUMBER_LE AI_MAKE_MAGIC("IDPC") // common limitations #define AI_MDC_VERSION 2 diff --git a/code/MDCLoader.cpp b/code/MDCLoader.cpp index 24038f774..6a137d1e5 100644 --- a/code/MDCLoader.cpp +++ b/code/MDCLoader.cpp @@ -87,23 +87,25 @@ MDCImporter::~MDCImporter() } // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool MDCImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool MDCImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); + const std::string extension = GetExtension(pFile); + if (extension == "mdc") + return true; - if (extension.length() < 4)return false; - if (extension[0] != '.')return false; - - if( extension[1] != 'M' && extension[1] != 'm')return false; - if( extension[2] != 'D' && extension[2] != 'd')return false; - if( extension[3] != 'C' && extension[3] != 'c')return false; + // if check for extension is not enough, check for the magic tokens + if (!extension.length() || checkSig) { + uint32_t tokens[1]; + tokens[0] = AI_MDC_MAGIC_NUMBER_LE; + return CheckMagicToken(pIOHandler,pFile,tokens,1); + } + return false; +} - return true; +// ------------------------------------------------------------------------------------------------ +void MDCImporter::GetExtensionList(std::string& append) +{ + append.append("*.mdc"); } // ------------------------------------------------------------------------------------------------ diff --git a/code/MDCLoader.h b/code/MDCLoader.h index 08d24b392..60ef038d0 100644 --- a/code/MDCLoader.h +++ b/code/MDCLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Definition of the MDC importer class. */ +/** @file MDCLoader.h + * @brief Definition of the MDC importer class. + */ #ifndef AI_MDCLOADER_H_INCLUDED #define AI_MDCLOADER_H_INCLUDED @@ -48,12 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "MDCFileData.h" #include "ByteSwap.h" -namespace Assimp -{ +namespace Assimp { using namespace MDC; // --------------------------------------------------------------------------- -/** Used to load MDC files +/** Importer class to load the RtCW MDC file format */ class MDCImporter : public BaseImporter { @@ -71,7 +72,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; // ------------------------------------------------------------------- /** Called prior to ReadFile(). @@ -86,10 +88,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.mdc"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/MDLFileData.h b/code/MDLFileData.h index 1dc936bc9..0982fd343 100644 --- a/code/MDLFileData.h +++ b/code/MDLFileData.h @@ -58,30 +58,29 @@ namespace Assimp { namespace MDL { // ------------------------------------------------------------------------------------- -// to make it easier for ourselfes, we test the magic word against both "endianesses" -#define MDL_MAKE(string) ((uint32_t)((string[0] << 24) + (string[1] << 16) + (string[2] << 8) + string[3])) +// to make it easier for us, we test the magic word against both "endianesses" // magic bytes used in Quake 1 MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE MDL_MAKE("IDPO") -#define AI_MDL_MAGIC_NUMBER_LE MDL_MAKE("OPDI") +#define AI_MDL_MAGIC_NUMBER_BE AI_MAKE_MAGIC("IDPO") +#define AI_MDL_MAGIC_NUMBER_LE AI_MAKE_MAGIC("OPDI") // magic bytes used in GameStudio A MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS3 MDL_MAKE("MDL2") -#define AI_MDL_MAGIC_NUMBER_LE_GS3 MDL_MAKE("2LDM") +#define AI_MDL_MAGIC_NUMBER_BE_GS3 AI_MAKE_MAGIC("MDL2") +#define AI_MDL_MAGIC_NUMBER_LE_GS3 AI_MAKE_MAGIC("2LDM") // magic bytes used in GameStudio A4 MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS4 MDL_MAKE("MDL3") -#define AI_MDL_MAGIC_NUMBER_LE_GS4 MDL_MAKE("3LDM") +#define AI_MDL_MAGIC_NUMBER_BE_GS4 AI_MAKE_MAGIC("MDL3") +#define AI_MDL_MAGIC_NUMBER_LE_GS4 AI_MAKE_MAGIC("3LDM") // magic bytes used in GameStudio A5+ MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS5a MDL_MAKE("MDL4") -#define AI_MDL_MAGIC_NUMBER_LE_GS5a MDL_MAKE("4LDM") -#define AI_MDL_MAGIC_NUMBER_BE_GS5b MDL_MAKE("MDL5") -#define AI_MDL_MAGIC_NUMBER_LE_GS5b MDL_MAKE("5LDM") +#define AI_MDL_MAGIC_NUMBER_BE_GS5a AI_MAKE_MAGIC("MDL4") +#define AI_MDL_MAGIC_NUMBER_LE_GS5a AI_MAKE_MAGIC("4LDM") +#define AI_MDL_MAGIC_NUMBER_BE_GS5b AI_MAKE_MAGIC("MDL5") +#define AI_MDL_MAGIC_NUMBER_LE_GS5b AI_MAKE_MAGIC("5LDM") // magic bytes used in GameStudio A7+ MDL meshes -#define AI_MDL_MAGIC_NUMBER_BE_GS7 MDL_MAKE("MDL7") -#define AI_MDL_MAGIC_NUMBER_LE_GS7 MDL_MAKE("7LDM") +#define AI_MDL_MAGIC_NUMBER_BE_GS7 AI_MAKE_MAGIC("MDL7") +#define AI_MDL_MAGIC_NUMBER_LE_GS7 AI_MAKE_MAGIC("7LDM") // common limitations for Quake1 meshes. The loader does not check them, diff --git a/code/MDLLoader.cpp b/code/MDLLoader.cpp index 28a4b8146..dcb061b2f 100644 --- a/code/MDLLoader.cpp +++ b/code/MDLLoader.cpp @@ -77,32 +77,41 @@ MDLImporter::~MDLImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - (void)pIOHandler; //this avoids the compiler warning of unused element - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; + const std::string extension = GetExtension(pFile); + if (extension == "mdl" ) + return true; - std::string extension = pFile.substr( pos); - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); - - return extension == ".mdl"; + // if check for extension is not enough, check for the magic tokens + if (!extension.length() || checkSig) { + uint32_t tokens[8]; + tokens[0] = AI_MDL_MAGIC_NUMBER_LE_HL2a; + tokens[1] = AI_MDL_MAGIC_NUMBER_LE_HL2b; + tokens[2] = AI_MDL_MAGIC_NUMBER_LE_GS7; + tokens[3] = AI_MDL_MAGIC_NUMBER_LE_GS5b; + tokens[4] = AI_MDL_MAGIC_NUMBER_LE_GS5a; + tokens[5] = AI_MDL_MAGIC_NUMBER_LE_GS4; + tokens[6] = AI_MDL_MAGIC_NUMBER_LE_GS3; + tokens[7] = AI_MDL_MAGIC_NUMBER_LE; + return CheckMagicToken(pIOHandler,pFile,tokens,7,0); + } + return false; } // ------------------------------------------------------------------------------------------------ // Setup configuration properties void MDLImporter::SetupProperties(const Importer* pImp) { - // The AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff); + + // The + // AI_CONFIG_IMPORT_MDL_KEYFRAME option overrides the // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. - if(0xffffffff == (configFrameID = pImp->GetPropertyInteger( - AI_CONFIG_IMPORT_MDL_KEYFRAME,0xffffffff))) - { + if(0xffffffff == configFrameID) { configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); } + + // AI_CONFIG_IMPORT_MDL_COLORMAP - pallette file configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP,"colormap.lmp"); } diff --git a/code/MDLLoader.h b/code/MDLLoader.h index 4eaef778b..9f4bd302a 100644 --- a/code/MDLLoader.h +++ b/code/MDLLoader.h @@ -96,7 +96,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; // ------------------------------------------------------------------- diff --git a/code/MDLMaterialLoader.cpp b/code/MDLMaterialLoader.cpp index 119914a4f..e7b3fa975 100644 --- a/code/MDLMaterialLoader.cpp +++ b/code/MDLMaterialLoader.cpp @@ -89,7 +89,7 @@ aiColor4D MDLImporter::ReplaceTextureWithColor(const aiTexture* pcTexture) ai_assert(NULL != pcTexture); aiColor4D clrOut; - clrOut.r = std::numeric_limits::quiet_NaN(); + clrOut.r = get_qnan(); if (!pcTexture->mHeight || !pcTexture->mWidth) return clrOut; @@ -572,7 +572,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7( // been converted to MDL7 from other formats, such as MDL5 aiColor4D clrTexture; if (pcNew)clrTexture = this->ReplaceTextureWithColor(pcNew); - else clrTexture.r = std::numeric_limits::quiet_NaN(); + else clrTexture.r = get_qnan(); // check whether a material definition is contained in the skin if (iType & AI_MDL7_SKINTYPE_MATERIAL) diff --git a/code/NFFLoader.cpp b/code/NFFLoader.cpp index a806545ff..983119808 100644 --- a/code/NFFLoader.cpp +++ b/code/NFFLoader.cpp @@ -65,22 +65,16 @@ NFFImporter::~NFFImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); + return SimpleExtensionCheck(pFile,"nff","enff"); +} - // extensions: enff and nff - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); - - if( extension == ".nff" || extension == ".enff") - return true; - - return false; +// ------------------------------------------------------------------------------------------------ +// Get the list of all supported file extensions +void NFFImporter::GetExtensionList(std::string& append) +{ + append.append("*.nff;*.enff"); } // ------------------------------------------------------------------------------------------------ @@ -96,7 +90,7 @@ bool NFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const // ------------------------------------------------------------------------------------------------ #define AI_NFF_PARSE_SHAPE_INFORMATION() \ - aiVector3D center, radius(1.0f,std::numeric_limits::quiet_NaN(),std::numeric_limits::quiet_NaN()); \ + aiVector3D center, radius(1.0f,get_qnan(),get_qnan()); \ AI_NFF_PARSE_TRIPLE(center); \ AI_NFF_PARSE_TRIPLE(radius); \ if (is_qnan(radius.z))radius.z = radius.x; \ @@ -282,7 +276,7 @@ void NFFImporter::InternReadFile( const std::string& pFile, // check whether this is the NFF2 file format if (TokenMatch(buffer,"nff",3)) { - const float qnan = std::numeric_limits::quiet_NaN(); + const float qnan = get_qnan(); const aiColor4D cQNAN = aiColor4D (qnan,0.f,0.f,1.f); const aiVector3D vQNAN = aiVector3D(qnan,0.f,0.f); diff --git a/code/NFFLoader.h b/code/NFFLoader.h index 3bc1bbffc..65d612a4a 100644 --- a/code/NFFLoader.h +++ b/code/NFFLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the NFF importer class. */ +/** @file NFFLoader.h + * @brief Declaration of the NFF importer class. + */ #ifndef AI_NFFLOADER_H_INCLUDED #define AI_NFFLOADER_H_INCLUDED @@ -49,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -// --------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------- /** NFF (Neutral File Format) Importer class. * * The class implements both Eric Haynes NFF format and Sense8's NFF (NFF2) format. @@ -71,8 +73,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -80,10 +84,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.nff;*.enff"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/OFFLoader.cpp b/code/OFFLoader.cpp index 13b858c23..869c3acf9 100644 --- a/code/OFFLoader.cpp +++ b/code/OFFLoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the OFF importer class */ +/** @file OFFLoader.cpp + * @brief Implementation of the OFF importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_OFF_IMPORTER @@ -64,25 +66,31 @@ OFFImporter::~OFFImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); + const std::string extension = GetExtension(pFile); + if (extension == "off") + return true; + else if (!extension.length() || checkSig) + { + if (!pIOHandler)return true; + const char* tokens[] = {"off"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; +} - return !(extension.length() != 4 || extension[0] != '.' || - extension[1] != 'o' && extension[1] != 'O' || - extension[2] != 'f' && extension[2] != 'F' || - extension[3] != 'f' && extension[3] != 'F'); +// ------------------------------------------------------------------------------------------------ +void OFFImporter::GetExtensionList(std::string& append) +{ + append.append("*.off"); } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void OFFImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) + aiScene* pScene, IOSystem* pIOHandler) { boost::scoped_ptr file( pIOHandler->Open( pFile, "rb")); diff --git a/code/OFFLoader.h b/code/OFFLoader.h index 1007b5731..9e6dd13a9 100644 --- a/code/OFFLoader.h +++ b/code/OFFLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the OFF importer class. */ +/** @file OFFLoader.h + * @brief Declaration of the OFF importer class. + */ #ifndef AI_OFFLOADER_H_INCLUDED #define AI_OFFLOADER_H_INCLUDED @@ -67,7 +69,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -75,10 +78,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.off"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/ObjFileImporter.cpp b/code/ObjFileImporter.cpp index 8b3d3ff8f..dc7953ff8 100644 --- a/code/ObjFileImporter.cpp +++ b/code/ObjFileImporter.cpp @@ -51,9 +51,6 @@ namespace Assimp { using namespace std; -//! Obj-file-format extention -const string ObjFileImporter::OBJ_EXT = "obj"; - // ------------------------------------------------------------------------------------------------ // Default constructor ObjFileImporter::ObjFileImporter() : @@ -76,20 +73,10 @@ ObjFileImporter::~ObjFileImporter() // ------------------------------------------------------------------------------------------------ // Returns true, fi file is an obj file -bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - if (pFile.empty()) - return false; - - string::size_type pos = pFile.find_last_of("."); - if (string::npos == pos) - return false; - - const string ext = pFile.substr(pos+1, pFile.size() - pos - 1); - if (ext == OBJ_EXT) - return true; - - return false; + // fixme: auto detection + return SimpleExtensionCheck(pFile,"obj"); } // ------------------------------------------------------------------------------------------------ diff --git a/code/ObjFileImporter.h b/code/ObjFileImporter.h index 78017953b..bbfc48c9c 100644 --- a/code/ObjFileImporter.h +++ b/code/ObjFileImporter.h @@ -66,9 +66,6 @@ class ObjFileImporter : { friend class Importer; - //! OB file extention - static const std::string OBJ_EXT; - protected: /// \brief Default constructor ObjFileImporter(); @@ -79,7 +76,7 @@ protected: public: /// \brief Returns whether the class can handle the format of the given file. /// \remark See BaseImporter::CanRead() for details. - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; private: diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index 1dd380b64..cea27033c 100644 --- a/code/PlyLoader.cpp +++ b/code/PlyLoader.cpp @@ -64,27 +64,31 @@ PLYImporter::~PLYImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool PLYImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool PLYImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); + const std::string extension = GetExtension(pFile); - if (extension.length() < 4)return false; - if (extension[0] != '.') return false; - if (extension[1] != 'p' && extension[1] != 'P')return false; - if (extension[2] != 'l' && extension[2] != 'L')return false; - if (extension[3] != 'y' && extension[3] != 'Y')return false; - return true; + if (extension == "ply") + return true; + else if (!extension.length() || checkSig) + { + if (!pIOHandler)return true; + const char* tokens[] = {"ply"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; +} + +// ------------------------------------------------------------------------------------------------ +void PLYImporter::GetExtensionList(std::string& append) +{ + append.append("*.ply"); } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void PLYImporter::InternReadFile( - const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) + const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { boost::scoped_ptr file( pIOHandler->Open( pFile)); @@ -108,8 +112,7 @@ void PLYImporter::InternReadFile( // the beginning of the file must be PLY - magic, magic if (mBuffer[0] != 'P' && mBuffer[0] != 'p' || mBuffer[1] != 'L' && mBuffer[1] != 'l' || - mBuffer[2] != 'Y' && mBuffer[2] != 'y') - { + mBuffer[2] != 'Y' && mBuffer[2] != 'y') { throw new ImportErrorException( "Invalid .ply file: Magic number \'ply\' is no there"); } @@ -789,19 +792,17 @@ void PLYImporter::LoadFaces(std::vector* pvOut) } else // triangle strips { - // HUGE TODO: MAKE THAT FUCK WORK! - // normally we have only one triangle strip instance where // a value of -1 indicates a restart of the strip for (std::vector::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end();++i) { + const std::vector& quak = (*i).alProperties[iProperty].avList; + pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); + int aiTable[2] = {-1,-1}; - for (std::vector::const_iterator - a = (*i).alProperties[iProperty].avList.begin(); - a != (*i).alProperties[iProperty].avList.end();++a) - { - int p = PLY::PropertyInstance::ConvertTo(*a,eType); + for (std::vector::const_iterator a = quak.begin();a != quak.end();++a) { + const int p = PLY::PropertyInstance::ConvertTo(*a,eType); if (-1 == p) { // restart the strip ... @@ -819,12 +820,12 @@ void PLYImporter::LoadFaces(std::vector* pvOut) continue; } - PLY::Face sFace; + pvOut->push_back(PLY::Face()); + PLY::Face& sFace = pvOut->back(); sFace.mIndices.push_back((unsigned int)aiTable[0]); sFace.mIndices.push_back((unsigned int)aiTable[1]); sFace.mIndices.push_back((unsigned int)p); - pvOut->push_back(sFace); - + aiTable[0] = aiTable[1]; aiTable[1] = p; } @@ -1054,4 +1055,4 @@ void PLYImporter::LoadMaterial(std::vector* pvOut) } } -#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER \ No newline at end of file +#endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER diff --git a/code/PlyLoader.h b/code/PlyLoader.h index ab857e3e1..11c423fef 100644 --- a/code/PlyLoader.h +++ b/code/PlyLoader.h @@ -38,8 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - -/** @file Declaration of the .ply importer class. */ +/** @file PLYLoader.h + * @brief Declaration of the .ply importer class. + */ #ifndef AI_PLYLOADER_H_INCLUDED #define AI_PLYLOADER_H_INCLUDED @@ -50,15 +51,13 @@ struct aiNode; #include "PlyParser.h" -namespace Assimp -{ +namespace Assimp { class MaterialHelper; - using namespace PLY; // --------------------------------------------------------------------------- -/** Used to load PLY files +/** Importer class to load the stanford PLY file format */ class PLYImporter : public BaseImporter { @@ -75,8 +74,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -84,10 +85,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.ply"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/PlyParser.cpp b/code/PlyParser.cpp index 310280367..a5f3300d0 100644 --- a/code/PlyParser.cpp +++ b/code/PlyParser.cpp @@ -744,10 +744,9 @@ bool PLY::PropertyInstance::ParseInstanceBinary ( unsigned int iNum = PLY::PropertyInstance::ConvertTo(v,prop->eFirstType); // parse all list elements - for (unsigned int i = 0; i < iNum;++i) - { - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&v,p_bBE); - p_pcOut->avList.push_back(v); + p_pcOut->avList.resize(iNum); + for (unsigned int i = 0; i < iNum;++i){ + PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&p_pcOut->avList[i],p_bBE); } } else diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index 181aaa13d..d9c9bbc99 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -39,12 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the "PretransformVertices" post processing step +/** @file PretransformVertices.cpp + * @brief Implementation of the "PretransformVertices" post processing step */ #include "AssimpPCH.h" #include "PretransformVertices.h" #include "ProcessHelper.h" +#include "SceneCombiner.h" using namespace Assimp; @@ -55,6 +57,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer PretransformVertices::PretransformVertices() +: configKeepHierarchy (false) { } @@ -72,9 +75,17 @@ bool PretransformVertices::IsActive( unsigned int pFlags) const return (pFlags & aiProcess_PreTransformVertices) != 0; } +// ------------------------------------------------------------------------------------------------ +// Setup import configuration +void PretransformVertices::SetupProperties(const Importer* pImp) +{ + // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY + configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0)); +} + // ------------------------------------------------------------------------------------------------ // Count the number of nodes -unsigned int CountNodes( aiNode* pcNode ) +unsigned int PretransformVertices::CountNodes( aiNode* pcNode ) { unsigned int iRet = 1; for (unsigned int i = 0;i < pcNode->mNumChildren;++i) @@ -86,7 +97,7 @@ unsigned int CountNodes( aiNode* pcNode ) // ------------------------------------------------------------------------------------------------ // Get a bitwise combination identifying the vertex format of a mesh -unsigned int GetMeshVFormat(aiMesh* pcMesh) +unsigned int PretransformVertices::GetMeshVFormat(aiMesh* pcMesh) { // the vertex format is stored in aiMesh::mBones for later retrieval. // there isn't a good reason to compute it a few hundred times @@ -106,7 +117,7 @@ unsigned int GetMeshVFormat(aiMesh* pcMesh) // ------------------------------------------------------------------------------------------------ // Count the number of vertices in the whole scene and a given // material index -void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, +void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices) { for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) @@ -127,39 +138,73 @@ void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, // ------------------------------------------------------------------------------------------------ // Collect vertex/face data -void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, +void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, unsigned int iVFormat, aiMesh* pcMeshOut, - unsigned int aiCurrent[2]) + unsigned int aiCurrent[2], unsigned int* num_refs) { + // No need to multiply if there's no transformation + const bool identity = pcNode->mTransformation.IsIdentity(); for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) { aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) { - // copy positions, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) - pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n]; - + // Decrement mesh reference counter + unsigned int& num_ref = num_refs[pcNode->mMeshes[i]]; + ai_assert(0 != num_ref); + --num_ref; - aiMatrix4x4 mWorldIT = pcNode->mTransformation; - mWorldIT.Inverse().Transpose(); + if (identity) { + // copy positions without modifying them + ::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mVertices, + pcMesh->mNumVertices * sizeof(aiVector3D)); - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - - if (iVFormat & 0x2) - { - // copy normals, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] = m * pcMesh->mNormals[n]; + if (iVFormat & 0x2) { + // copy normals without modifying them + ::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mNormals, + pcMesh->mNumVertices * sizeof(aiVector3D)); + } + if (iVFormat & 0x4) + { + // copy tangents without modifying them + ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mTangents, + pcMesh->mNumVertices * sizeof(aiVector3D)); + // copy bitangents without modifying them + ::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX], + pcMesh->mBitangents, + pcMesh->mNumVertices * sizeof(aiVector3D)); } } - if (iVFormat & 0x4) + else { - // copy tangents and bitangents, transform them to worldspace + // copy positions, transform them to worldspace for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = m * pcMesh->mTangents[n]; - pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = m * pcMesh->mBitangents[n]; + pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n]; + } + aiMatrix4x4 mWorldIT = pcNode->mTransformation; + mWorldIT.Inverse().Transpose(); + + // TODO: implement Inverse() for aiMatrix3x3 + aiMatrix3x3 m = aiMatrix3x3(mWorldIT); + + if (iVFormat & 0x2) + { + // copy normals, transform them to worldspace + for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { + pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] = + m * pcMesh->mNormals[n]; + } + } + if (iVFormat & 0x4) + { + // copy tangents and bitangents, transform them to worldspace + for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { + pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = m * pcMesh->mTangents[n]; + pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = m * pcMesh->mBitangents[n]; + } } } unsigned int p = 0; @@ -180,26 +225,35 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, pcMesh->mNumVertices * sizeof(aiColor4D)); ++p; } - // now we need to copy all faces - // since we will delete the source mesh afterwards, - // we don't need to reallocate the array of indices - for (unsigned int planck = 0;planckmNumFaces;++planck) + // now we need to copy all faces. since we will delete the source mesh afterwards, + // we don't need to reallocate the array of indices except if this mesh is + // referenced multiple times. + for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck) { - pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck].mNumIndices = - pcMesh->mFaces[planck].mNumIndices; + aiFace& f_src = pcMesh->mFaces[planck]; + aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck]; - unsigned int* pi = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck]. - mIndices = pcMesh->mFaces[planck].mIndices; + const unsigned int num_idx = f_src.mNumIndices; - // offset all vrtex indices - for (unsigned int hahn = 0; hahn < pcMesh->mFaces[planck].mNumIndices;++hahn) - { - pi[hahn] += aiCurrent[AI_PTVS_VERTEX]; + f_dst.mNumIndices = num_idx; + + unsigned int* pi; + if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */ + pi = f_dst.mIndices = f_src.mIndices; + + // offset all vertex indices + for (unsigned int hahn = 0; hahn < num_idx;++hahn){ + pi[hahn] += aiCurrent[AI_PTVS_VERTEX]; + } + } + else { + pi = f_dst.mIndices = new unsigned int[num_idx]; + + // copy and offset all vertex indices + for (unsigned int hahn = 0; hahn < num_idx;++hahn){ + pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX]; + } } - - // just make sure the array won't be deleted by the - // aiFace destructor ... - pcMesh->mFaces[planck].mIndices = NULL; // Update the mPrimitiveTypes member of the mesh switch (pcMesh->mFaces[planck].mNumIndices) @@ -222,24 +276,24 @@ void CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces; } } - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) - { + + // append all children of us + for (unsigned int i = 0;i < pcNode->mNumChildren;++i) { CollectData(pcScene,pcNode->mChildren[i],iMat, - iVFormat,pcMeshOut,aiCurrent); + iVFormat,pcMeshOut,aiCurrent,num_refs); } } // ------------------------------------------------------------------------------------------------ // Get a list of all vertex formats that occur for a given material index // The output list contains duplicate elements -void GetVFormatList( aiScene* pcScene, unsigned int iMat, +void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat, std::list& aiOut) { for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { aiMesh* pcMesh = pcScene->mMeshes[ i ]; - if (iMat == pcMesh->mMaterialIndex) - { + if (iMat == pcMesh->mMaterialIndex) { aiOut.push_back(GetMeshVFormat(pcMesh)); } } @@ -247,7 +301,7 @@ void GetVFormatList( aiScene* pcScene, unsigned int iMat, // ------------------------------------------------------------------------------------------------ // Compute the absolute transformation matrices of each node -void ComputeAbsoluteTransform( aiNode* pcNode ) +void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode ) { if (pcNode->mParent) { pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation; @@ -258,12 +312,126 @@ void ComputeAbsoluteTransform( aiNode* pcNode ) } } +// ------------------------------------------------------------------------------------------------ +// Apply the node transformation to a mesh +void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat) +{ + // Check whether we need to transform the coordinates at all + if (!mat.IsIdentity()) { + + if (mesh->HasPositions()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + mesh->mVertices[i] = mat * mesh->mVertices[i]; + } + } + if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { + aiMatrix4x4 mWorldIT = mat; + mWorldIT.Inverse().Transpose(); + + // TODO: implement Inverse() for aiMatrix3x3 + aiMatrix3x3 m = aiMatrix3x3(mWorldIT); + + if (mesh->HasNormals()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + mesh->mNormals[i] = m * mesh->mNormals[i]; + } + } + if (mesh->HasTangentsAndBitangents()) { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + mesh->mTangents[i] = m * mesh->mTangents[i]; + mesh->mBitangents[i] = m * mesh->mBitangents[i]; + } + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Simple routine to build meshes in worldspace, no further optimization +void PretransformVertices::BuildWCSMeshes(std::vector& out, aiMesh** in, + unsigned int numIn, aiNode* node) +{ + // NOTE: + // aiMesh::mNumBones store original source mesh, or 0xffffffff if not a copy + // aiMesh::mBones store reference to abs. transform we multiplied with + + // process meshes + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + aiMesh* mesh = in[node->mMeshes[i]]; + + // check whether we can operate on this mesh + if (!mesh->mBones || *reinterpret_cast(mesh->mBones) == node->mTransformation) { + // yes, we can. + mesh->mBones = reinterpret_cast (&node->mTransformation); + mesh->mNumBones = 0xffffffff; + } + else { + + // try to find us in the list of newly created meshes + for (unsigned int n = 0; n < out.size(); ++n) { + aiMesh* ctz = out[n]; + if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast(ctz->mBones) == node->mTransformation) { + + // ok, use this one. Update node mesh index + node->mMeshes[i] = numIn + n; + } + } + if (node->mMeshes[i] < numIn) { + // Worst case. Need to operate on a full copy of the mesh + DefaultLogger::get()->info("PretransformVertices: Copying mesh due to mismatching transforms"); + aiMesh* ntz; + + const unsigned int tmp = mesh->mNumBones; // + mesh->mNumBones = 0; + SceneCombiner::Copy(&ntz,mesh); + mesh->mNumBones = tmp; + + ntz->mNumBones = node->mMeshes[i]; + ntz->mBones = reinterpret_cast (&node->mTransformation); + + out.push_back(ntz); + } + } + } + + // call children + for (unsigned int i = 0; i < node->mNumChildren;++i) + BuildWCSMeshes(out,in,numIn,node->mChildren[i]); +} + +// ------------------------------------------------------------------------------------------------ +// Reset transformation matrices to identity +void PretransformVertices::MakeIdentityTransform(aiNode* nd) +{ + nd->mTransformation = aiMatrix4x4(); + + // call children + for (unsigned int i = 0; i < nd->mNumChildren;++i) + MakeIdentityTransform(nd->mChildren[i]); +} + +// ------------------------------------------------------------------------------------------------ +// Build reference counters for all meshes +void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs) +{ + for (unsigned int i = 0; i< nd->mNumMeshes;++i) + refs[nd->mMeshes[i]]++; + + // call children + for (unsigned int i = 0; i < nd->mNumChildren;++i) + BuildMeshRefCountArray(nd->mChildren[i],refs); +} + // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void PretransformVertices::Execute( aiScene* pScene) { DefaultLogger::get()->debug("PretransformVerticesProcess begin"); + // Return immediately if we have no meshes + if (!pScene->mNumMeshes) + return; + const unsigned int iOldMeshes = pScene->mNumMeshes; const unsigned int iOldAnimationChannels = pScene->mNumAnimations; const unsigned int iOldNodes = CountNodes(pScene->mRootNode); @@ -271,11 +439,10 @@ void PretransformVertices::Execute( aiScene* pScene) // first compute absolute transformation matrices for all nodes ComputeAbsoluteTransform(pScene->mRootNode); - // delete aiMesh::mBones for all meshes. The bones are + // Delete aiMesh::mBones for all meshes. The bones are // removed during this step and we need the pointer as // temporary storage - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { aiMesh* mesh = pScene->mMeshes[i]; for (unsigned int a = 0; a < mesh->mNumBones;++a) @@ -287,50 +454,123 @@ void PretransformVertices::Execute( aiScene* pScene) // now build a list of output meshes std::vector apcOutMeshes; - apcOutMeshes.reserve(pScene->mNumMaterials<<1u); - std::list aiVFormats; - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - // get the list of all vertex formats for this material - aiVFormats.clear(); - GetVFormatList(pScene,i,aiVFormats); - aiVFormats.sort(); - aiVFormats.unique(); - for (std::list::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) { - unsigned int iVertices = 0; - unsigned int iFaces = 0; - CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices); - if (iFaces && iVertices) - { - apcOutMeshes.push_back(new aiMesh()); - aiMesh* pcMesh = apcOutMeshes.back(); - pcMesh->mNumFaces = iFaces; - pcMesh->mNumVertices = iVertices; - pcMesh->mFaces = new aiFace[iFaces]; - pcMesh->mVertices = new aiVector3D[iVertices]; - pcMesh->mMaterialIndex = i; - if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices]; - if ((*j) & 0x4) - { - pcMesh->mTangents = new aiVector3D[iVertices]; - pcMesh->mBitangents = new aiVector3D[iVertices]; - } - iFaces = 0; - while ((*j) & (0x100 << iFaces)) - { - pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; - if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3; - else pcMesh->mNumUVComponents[iFaces] = 2; - iFaces++; - } - iFaces = 0; - while ((*j) & (0x1000000 << iFaces)) - pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; - // fill the mesh ... - unsigned int aiTemp[2] = {0,0}; - CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp); + // Keep scene hierarchy? It's an easy job in this case ... + // we go on and transform all meshes, if one is referenced by nodes + // with different absolute transformations a depth copy of the mesh + // is required. + if( configKeepHierarchy ) { + + // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones + BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode); + + // ... if new meshes have been generated, append them to the end of the scene + if (apcOutMeshes.size() > 0) { + aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()]; + + ::memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes); + ::memcpy(npp+pScene->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size()); + + pScene->mNumMeshes += apcOutMeshes.size(); + delete[] pScene->mMeshes; pScene->mMeshes = npp; + } + + // now iterate through all meshes and transform them to worldspace + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + ApplyTransform(pScene->mMeshes[i],*reinterpret_cast( pScene->mMeshes[i]->mBones )); + + // prevent improper destruction + pScene->mMeshes[i]->mBones = NULL; + pScene->mMeshes[i]->mNumBones = 0; + } + } + else { + + apcOutMeshes.reserve(pScene->mNumMaterials<<1u); + std::list aiVFormats; + + std::vector s(pScene->mNumMeshes,0); + BuildMeshRefCountArray(pScene->mRootNode,&s[0]); + + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { + // get the list of all vertex formats for this material + aiVFormats.clear(); + GetVFormatList(pScene,i,aiVFormats); + aiVFormats.sort(); + aiVFormats.unique(); + for (std::list::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) { + unsigned int iVertices = 0; + unsigned int iFaces = 0; + CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices); + if (0 != iFaces && 0 != iVertices) + { + apcOutMeshes.push_back(new aiMesh()); + aiMesh* pcMesh = apcOutMeshes.back(); + pcMesh->mNumFaces = iFaces; + pcMesh->mNumVertices = iVertices; + pcMesh->mFaces = new aiFace[iFaces]; + pcMesh->mVertices = new aiVector3D[iVertices]; + pcMesh->mMaterialIndex = i; + if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices]; + if ((*j) & 0x4) + { + pcMesh->mTangents = new aiVector3D[iVertices]; + pcMesh->mBitangents = new aiVector3D[iVertices]; + } + iFaces = 0; + while ((*j) & (0x100 << iFaces)) + { + pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; + if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3; + else pcMesh->mNumUVComponents[iFaces] = 2; + iFaces++; + } + iFaces = 0; + while ((*j) & (0x1000000 << iFaces)) + pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; + + // fill the mesh ... + unsigned int aiTemp[2] = {0,0}; + CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]); + } } } + + // now delete all meshes in the scene and build a new mesh list + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + { + aiMesh* mesh = pScene->mMeshes[i]; + mesh->mNumBones = 0; + mesh->mBones = NULL; + + // we're reusing the face index arrays. avoid destruction + for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { + mesh->mFaces[a].mNumIndices = 0; + mesh->mFaces[a].mIndices = NULL; + } + + delete mesh; + + // Invalidate the contents of the old mesh array. We will most + // likely have less output meshes now, so the last entries of + // the mesh array are not overridden. We set them to NULL to + // make sure the developer gets notified when his application + // attempts to access these fields ... + mesh = NULL; + } + + // If no meshes are referenced in the node graph it is possible that we get no output meshes. + if (apcOutMeshes.empty()) { + throw new ImportErrorException("No output meshes: all meshes are orphaned and are not referenced by nodes"); + } + else + { + // It is impossible that we have more output meshes than + // input meshes, so we can easily reuse the old mesh array + pScene->mNumMeshes = (unsigned int)apcOutMeshes.size(); + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) + pScene->mMeshes[i] = apcOutMeshes[i]; + } } // remove all animations from the scene @@ -341,40 +581,6 @@ void PretransformVertices::Execute( aiScene* pScene) pScene->mAnimations = NULL; pScene->mNumAnimations = 0; - // now delete all meshes in the scene and build a new mesh list - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - pScene->mMeshes[i]->mBones = NULL; - delete pScene->mMeshes[i]; - - // invalidate the contents of the old mesh array. We will most - // likely have less output meshes now, so the last entries of - // the mesh array are not overridden. We set them to NULL to - // make sure the developer gets notified when his application - // attempts to access these fields ... - pScene->mMeshes[i] = NULL; - } - - // If no meshes are referenced in the node graph it is - // possible that we get no output meshes. However, this - // is OK if we had no input meshes, too - if (apcOutMeshes.empty()) - { - if (pScene->mNumMeshes) - { - throw new ImportErrorException("No output meshes: all meshes are orphaned " - "and have no node references"); - } - } - else - { - // It is impossible that we have more output meshes than - // input meshes, so we can easily reuse the old mesh array - pScene->mNumMeshes = (unsigned int)apcOutMeshes.size(); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - pScene->mMeshes[i] = apcOutMeshes[i]; - } - // --- we need to keep all cameras and lights for (unsigned int i = 0; i < pScene->mNumCameras;++i) { @@ -401,51 +607,58 @@ void PretransformVertices::Execute( aiScene* pScene) l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection; } - // now delete all nodes in the scene and build a new - // flat node graph with a root node and some level 1 children - delete pScene->mRootNode; - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mName.Set(""); + if( !configKeepHierarchy ) { - if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) - { - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[1]; - pScene->mRootNode->mMeshes[0] = 0; + // now delete all nodes in the scene and build a new + // flat node graph with a root node and some level 1 children + delete pScene->mRootNode; + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mName.Set(""); + + if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) + { + pScene->mRootNode->mNumMeshes = 1; + pScene->mRootNode->mMeshes = new unsigned int[1]; + pScene->mRootNode->mMeshes[0] = 0; + } + else + { + pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras; + aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; + + // generate mesh nodes + for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes) + { + aiNode* pcNode = *nodes = new aiNode(); + pcNode->mParent = pScene->mRootNode; + pcNode->mName.length = ::sprintf(pcNode->mName.data,"mesh_%i",i); + + // setup mesh indices + pcNode->mNumMeshes = 1; + pcNode->mMeshes = new unsigned int[1]; + pcNode->mMeshes[0] = i; + } + // generate light nodes + for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes) + { + aiNode* pcNode = *nodes = new aiNode(); + pcNode->mParent = pScene->mRootNode; + pcNode->mName.length = ::sprintf(pcNode->mName.data,"light_%i",i); + pScene->mLights[i]->mName = pcNode->mName; + } + // generate camera nodes + for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes) + { + aiNode* pcNode = *nodes = new aiNode(); + pcNode->mParent = pScene->mRootNode; + pcNode->mName.length = ::sprintf(pcNode->mName.data,"cam_%i",i); + pScene->mCameras[i]->mName = pcNode->mName; + } + } } - else - { - pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras; - aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; - - // generate mesh nodes - for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes) - { - aiNode* pcNode = *nodes = new aiNode(); - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::sprintf(pcNode->mName.data,"mesh_%i",i); - - // setup mesh indices - pcNode->mNumMeshes = 1; - pcNode->mMeshes = new unsigned int[1]; - pcNode->mMeshes[0] = i; - } - // generate light nodes - for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes) - { - aiNode* pcNode = *nodes = new aiNode(); - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::sprintf(pcNode->mName.data,"light_%i",i); - pScene->mLights[i]->mName = pcNode->mName; - } - // generate camera nodes - for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes) - { - aiNode* pcNode = *nodes = new aiNode(); - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::sprintf(pcNode->mName.data,"cam_%i",i); - pScene->mCameras[i]->mName = pcNode->mName; - } + else { + // ... and finally set the transformation matrix of all nodes to identity + MakeIdentityTransform(pScene->mRootNode); } // print statistics @@ -467,7 +680,5 @@ void PretransformVertices::Execute( aiScene* pScene) iOldMeshes,pScene->mNumMeshes); DefaultLogger::get()->info(buffer); } - - return; } diff --git a/code/PretransformVertices.h b/code/PretransformVertices.h index 9e1cb2685..2327cc0e3 100644 --- a/code/PretransformVertices.h +++ b/code/PretransformVertices.h @@ -38,16 +38,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines a post processing step to pretransform all - vertices in the scenegraph */ +/** @file PretransformVertices.h + * @brief Defines a post processing step to pretransform all + * vertices in the scenegraph + */ #ifndef AI_PRETRANSFORMVERTICES_H_INC #define AI_PRETRANSFORMVERTICES_H_INC #include "BaseProcess.h" #include "../include/aiMesh.h" -namespace Assimp -{ +class PretransformVerticesTest; +namespace Assimp { // --------------------------------------------------------------------------- /** The PretransformVertices pretransforms all vertices in the nodegraph @@ -57,6 +59,7 @@ namespace Assimp class ASSIMP_API PretransformVertices : public BaseProcess { friend class Importer; + friend class ::PretransformVerticesTest; protected: /** Constructor to be privately used by Importer */ @@ -66,21 +69,96 @@ protected: ~PretransformVertices (); public: + // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ + // Check whether step is active bool IsActive( unsigned int pFlags) const; // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ + // Execute step on a given scene void Execute( aiScene* pScene); + // ------------------------------------------------------------------- + // Setup import settings + void SetupProperties(const Importer* pImp); + + + // ------------------------------------------------------------------- + /** @brief Toggle the 'keep hierarchy' option + * @param d hm ... difficult to guess what this means, hu!? + */ + void KeepHierarchy(bool d) { + configKeepHierarchy = d; + } + + // ------------------------------------------------------------------- + /** @brief Check whether 'keep hierarchy' is currently enabled. + * @return ... + */ + bool IsHierarchyKept() const { + return configKeepHierarchy; + } + +private: + + // ------------------------------------------------------------------- + // Count the number of nodes + unsigned int CountNodes( aiNode* pcNode ); + + // ------------------------------------------------------------------- + // Get a bitwise combination identifying the vertex format of a mesh + unsigned int GetMeshVFormat(aiMesh* pcMesh); + + // ------------------------------------------------------------------- + // Count the number of vertices in the whole scene and a given + // material index + void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, + unsigned int iMat, + unsigned int iVFormat, + unsigned int* piFaces, + unsigned int* piVertices); + + // ------------------------------------------------------------------- + // Collect vertex/face data + void CollectData( aiScene* pcScene, aiNode* pcNode, + unsigned int iMat, + unsigned int iVFormat, + aiMesh* pcMeshOut, + unsigned int aiCurrent[2], + unsigned int* num_refs); + + // ------------------------------------------------------------------- + // Get a list of all vertex formats that occur for a given material + // The output list contains duplicate elements + void GetVFormatList( aiScene* pcScene, unsigned int iMat, + std::list& aiOut); + + // ------------------------------------------------------------------- + // Compute the absolute transformation matrices of each node + void ComputeAbsoluteTransform( aiNode* pcNode ); + + // ------------------------------------------------------------------- + // Simple routine to build meshes in worldspace, no further optimization + void BuildWCSMeshes(std::vector& out, aiMesh** in, + unsigned int numIn, aiNode* node); + + // ------------------------------------------------------------------- + // Apply the node transformation to a mesh + void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat); + + // ------------------------------------------------------------------- + // Reset transformation matrices to identity + void MakeIdentityTransform(aiNode* nd); + + // ------------------------------------------------------------------- + // Build reference counters for all meshes + void BuildMeshRefCountArray(aiNode* nd, unsigned int * refs); + + + + //! Configuration option: keep scene hierarchy as long as possible + bool configKeepHierarchy; + }; } // end of namespace Assimp diff --git a/code/ProcessHelper.h b/code/ProcessHelper.h index c076ba0fc..9c67e35fb 100644 --- a/code/ProcessHelper.h +++ b/code/ProcessHelper.h @@ -46,11 +46,144 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SpatialSort.h" #include "BaseProcess.h" +// ------------------------------------------------------------------------------- +// Some extensions to std namespace. Mainly std::min and std::max for all +// flat data types in the aiScene. They're used to quickly determine the +// min/max bounds of data arrays. +#ifdef __cplusplus +namespace std { + + // std::min for aiVector3D + inline ::aiVector3D min (const ::aiVector3D& a, const ::aiVector3D& b) { + return ::aiVector3D (min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); + } + + // std::max for aiVector3D + inline ::aiVector3D max (const ::aiVector3D& a, const ::aiVector3D& b) { + return ::aiVector3D (max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); + } + + // std::min for aiColor4D + inline ::aiColor4D min (const ::aiColor4D& a, const ::aiColor4D& b) { + return ::aiColor4D (min(a.r,b.r),min(a.g,b.g),min(a.b,b.b),min(a.a,b.a)); + } + + // std::max for aiColor4D + inline ::aiColor4D max (const ::aiColor4D& a, const ::aiColor4D& b) { + return ::aiColor4D (max(a.r,b.r),max(a.g,b.g),max(a.b,b.b),max(a.a,b.a)); + } + + // std::min for aiQuaternion + inline ::aiQuaternion min (const ::aiQuaternion& a, const ::aiQuaternion& b) { + return ::aiQuaternion (min(a.w,b.w),min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); + } + + // std::max for aiQuaternion + inline ::aiQuaternion max (const ::aiQuaternion& a, const ::aiQuaternion& b) { + return ::aiQuaternion (max(a.w,b.w),max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); + } + + // std::min for aiVectorKey + inline ::aiVectorKey min (const ::aiVectorKey& a, const ::aiVectorKey& b) { + return ::aiVectorKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue)); + } + + // std::max for aiVectorKey + inline ::aiVectorKey max (const ::aiVectorKey& a, const ::aiVectorKey& b) { + return ::aiVectorKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue)); + } + + // std::min for aiQuatKey + inline ::aiQuatKey min (const ::aiQuatKey& a, const ::aiQuatKey& b) { + return ::aiQuatKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue)); + } + + // std::max for aiQuatKey + inline ::aiQuatKey max (const ::aiQuatKey& a, const ::aiQuatKey& b) { + return ::aiQuatKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue)); + } + + // std::min for aiVertexWeight + inline ::aiVertexWeight min (const ::aiVertexWeight& a, const ::aiVertexWeight& b) { + return ::aiVertexWeight (min(a.mVertexId,b.mVertexId),min(a.mWeight,b.mWeight)); + } + + // std::max for aiVertexWeight + inline ::aiVertexWeight max (const ::aiVertexWeight& a, const ::aiVertexWeight& b) { + return ::aiVertexWeight (max(a.mVertexId,b.mVertexId),max(a.mWeight,b.mWeight)); + } + +} // end namespace std +#endif // !! C++ + namespace Assimp { -// some aliases to make the whole stuff easier to read -typedef std::pair < unsigned int,float > PerVertexWeight; -typedef std::vector < PerVertexWeight > VertexWeightTable; +// ------------------------------------------------------------------------------- +// Start points for ArrayBounds for all supported Ts +template +struct MinMaxChooser; + +template <> struct MinMaxChooser { + void operator ()(float& min,float& max) { + max = -10e10f; + min = 10e10f; +}}; +template <> struct MinMaxChooser { + void operator ()(double& min,double& max) { + max = -10e10; + min = 10e10; +}}; +template <> struct MinMaxChooser { + void operator ()(unsigned int& min,unsigned int& max) { + max = 0; + min = (1u<<(sizeof(unsigned int)*8-1)); +}}; + +template <> struct MinMaxChooser { + void operator ()(aiVector3D& min,aiVector3D& max) { + max = aiVector3D(-10e10f,-10e10f,-10e10f); + min = aiVector3D( 10e10f, 10e10f, 10e10f); +}}; +template <> struct MinMaxChooser { + void operator ()(aiColor4D& min,aiColor4D& max) { + max = aiColor4D(-10e10f,-10e10f,-10e10f,-10e10f); + min = aiColor4D( 10e10f, 10e10f, 10e10f, 10e10f); +}}; + +template <> struct MinMaxChooser { + void operator ()(aiQuaternion& min,aiQuaternion& max) { + max = aiQuaternion(-10e10f,-10e10f,-10e10f,-10e10f); + min = aiQuaternion( 10e10f, 10e10f, 10e10f, 10e10f); +}}; + +template <> struct MinMaxChooser { + void operator ()(aiVectorKey& min,aiVectorKey& max) { + MinMaxChooser()(min.mTime,max.mTime); + MinMaxChooser()(min.mValue,max.mValue); +}}; +template <> struct MinMaxChooser { + void operator ()(aiQuatKey& min,aiQuatKey& max) { + MinMaxChooser()(min.mTime,max.mTime); + MinMaxChooser()(min.mValue,max.mValue); +}}; + +template <> struct MinMaxChooser { + void operator ()(aiVertexWeight& min,aiVertexWeight& max) { + MinMaxChooser()(min.mVertexId,max.mVertexId); + MinMaxChooser()(min.mWeight,max.mWeight); +}}; + +// ------------------------------------------------------------------------------- +// Find the min/max values of an array of Ts +template +inline void ArrayBounds(const T* in, unsigned int size, T& min, T& max) +{ + MinMaxChooser ()(min,max); + for (unsigned int i = 0; i < size;++i) { + min = std::min(in[i],min); + max = std::max(in[i],max); + } +} // ------------------------------------------------------------------------------- /** Little helper function to calculate the quadratic difference @@ -67,24 +200,6 @@ inline float GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pCol return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a; } -// ------------------------------------------------------------------------------- -// Compute the AABB of a mesh -inline void FindAABB (const aiMesh* mesh, aiVector3D& min, aiVector3D& max) -{ - min = aiVector3D (10e10f, 10e10f, 10e10f); - max = aiVector3D (-10e10f,-10e10f,-10e10f); - for (unsigned int i = 0;i < mesh->mNumVertices;++i) - { - const aiVector3D& v = mesh->mVertices[i]; - min.x = ::std::min(v.x,min.x); - min.y = ::std::min(v.y,min.y); - min.z = ::std::min(v.z,min.z); - max.x = ::std::max(v.x,max.x); - max.y = ::std::max(v.y,max.y); - max.z = ::std::max(v.z,max.z); - } -} - // ------------------------------------------------------------------------------- // Compute the AABB of a mesh after applying a given transform inline void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, @@ -95,12 +210,8 @@ inline void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D for (unsigned int i = 0;i < mesh->mNumVertices;++i) { const aiVector3D v = m * mesh->mVertices[i]; - min.x = ::std::min(v.x,min.x); - min.y = ::std::min(v.y,min.y); - min.z = ::std::min(v.z,min.z); - max.x = ::std::max(v.x,max.x); - max.y = ::std::max(v.y,max.y); - max.z = ::std::max(v.z,max.z); + min = std::min(v,min); + max = std::max(v,max); } } @@ -108,7 +219,7 @@ inline void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D // Helper function to determine the 'real' center of a mesh inline void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max) { - FindAABB(mesh,min,max); + ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max); out = min + (max-min)*0.5f; } @@ -146,7 +257,7 @@ inline float ComputePositionEpsilon(const aiMesh* pMesh) // calculate the position bounds so we have a reliable epsilon to check position differences against aiVector3D minVec, maxVec; - FindAABB(pMesh,minVec,maxVec); + ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec); return (maxVec - minVec).Length() * epsilon; } @@ -165,8 +276,10 @@ inline unsigned int GetMeshVFormatUnique(aiMesh* pcMesh) // tangents and bitangents if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4; +#ifdef BOOST_STATIC_ASSERT BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); +#endif // texture coordinates unsigned int p = 0; @@ -184,6 +297,9 @@ inline unsigned int GetMeshVFormatUnique(aiMesh* pcMesh) return iRet; } +typedef std::pair PerVertexWeight; +typedef std::vector VertexWeightTable; + // ------------------------------------------------------------------------------- // Compute a per-vertex bone weight table // please .... delete result with operator delete[] ... @@ -205,13 +321,14 @@ inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh) return avPerVertexWeights; } - // ------------------------------------------------------------------------------- // Get a string for a given aiTextureType inline const char* TextureTypeToString(aiTextureType in) { switch (in) { + case aiTextureType_NONE: + return "n/a"; case aiTextureType_DIFFUSE: return "Diffuse"; case aiTextureType_SPECULAR: @@ -237,7 +354,7 @@ inline const char* TextureTypeToString(aiTextureType in) case aiTextureType_UNKNOWN: return "Unknown"; default: - return "HUGE ERROR, please leave the room immediately and call the police"; + return "HUGE ERROR. Expect BSOD (linux guys: kernel panic ...)."; } } @@ -260,7 +377,7 @@ inline const char* MappingTypeToString(aiTextureMapping in) case aiTextureMapping_OTHER: return "Other"; default: - return "HUGE ERROR, please leave the room immediately and call the police"; + return "HUGE ERROR. Expect BSOD (linux guys: kernel panic ...)."; } } diff --git a/code/Q3DLoader.cpp b/code/Q3DLoader.cpp index 6c61ef9e2..0a0653715 100644 --- a/code/Q3DLoader.cpp +++ b/code/Q3DLoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the Q3D importer class */ +/** @file Q3DLoader.cpp + * @brief Implementation of the Q3D importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER @@ -54,30 +56,34 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer Q3DImporter::Q3DImporter() -{ -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well Q3DImporter::~Q3DImporter() -{ -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool Q3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool Q3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; + const std::string extension = GetExtension(pFile); - std::string extension = pFile.substr( pos); - for (std::string::iterator it = extension.begin(); - it != extension.end(); ++it) - *it = ::tolower(*it); + if (extension == "q3s" || extension == "q3o") + return true; + else if (!extension.length() || checkSig) { + if (!pIOHandler) + return true; + const char* tokens[] = {"quick3Do","quick3Ds"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,2); + } + return false; +} - return (extension == ".q3o" || extension == ".q3s"); +// ------------------------------------------------------------------------------------------------ +void Q3DImporter::GetExtensionList(std::string& append) +{ + append.append("*.q3o;*.q3s"); } // ------------------------------------------------------------------------------------------------ @@ -91,11 +97,11 @@ void Q3DImporter::InternReadFile( const std::string& pFile, if (stream.GetRemainingSize() < 22) throw new ImportErrorException("File is either empty or corrupt: " + pFile); - // Check the file signature + // Check the file's signature if (ASSIMP_strincmp( (const char*)stream.GetPtr(), "quick3Do", 8 ) && ASSIMP_strincmp( (const char*)stream.GetPtr(), "quick3Ds", 8 )) { - throw new ImportErrorException("No Quick3D file. Signature is: " + + throw new ImportErrorException("Not a Quick3D file. Signature string is: " + std::string((const char*)stream.GetPtr(),8)); } diff --git a/code/Q3DLoader.h b/code/Q3DLoader.h index ca4b0f7d3..a80b978f9 100644 --- a/code/Q3DLoader.h +++ b/code/Q3DLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the Q3D importer class. */ +/** @file Q3DLoader.h + * @brief Declaration of the Q3D importer class. + */ #ifndef AI_Q3DLOADER_H_INCLUDED #define AI_Q3DLOADER_H_INCLUDED @@ -67,7 +69,8 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -75,10 +78,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.q3o;*.q3s"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/RawLoader.cpp b/code/RawLoader.cpp index 674054183..1a2e89b6d 100644 --- a/code/RawLoader.cpp +++ b/code/RawLoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the RAW importer class */ +/** @file RawLoader.cpp + * @brief Implementation of the RAW importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_RAW_IMPORTER @@ -63,21 +65,16 @@ RAWImporter::~RAWImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool RAWImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool RAWImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); + return SimpleExtensionCheck(pFile,"raw"); +} - if (extension.length() < 4)return false; - if (extension[0] != '.')return false; - - return !(extension.length() != 4 || extension[0] != '.' || - extension[1] != 'r' && extension[1] != 'R' || - extension[2] != 'a' && extension[2] != 'A' || - extension[3] != 'w' && extension[3] != 'W'); +// ------------------------------------------------------------------------------------------------ +// Get the list of all supported file extensions +void RAWImporter::GetExtensionList(std::string& append) +{ + append.append("*.raw"); } // ------------------------------------------------------------------------------------------------ diff --git a/code/RawLoader.h b/code/RawLoader.h index 2d0366527..f91449246 100644 --- a/code/RawLoader.h +++ b/code/RawLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the RAW importer class. */ +/** @file RAWLoader.h + * @brief Declaration of the RAW importer class. + */ #ifndef AI_RAWLOADER_H_INCLUDED #define AI_RAWLOADER_H_INCLUDED @@ -66,8 +68,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -75,10 +79,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.raw"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/RemoveRedundantMaterials.cpp b/code/RemoveRedundantMaterials.cpp index 70611a0e8..9132f8552 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/RemoveRedundantMaterials.cpp @@ -38,12 +38,14 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the "RemoveRedundantMaterials" post processing step +/** @file RemoveRedundantMaterials.cpp + * @brief Implementation of the "RemoveRedundantMaterials" post processing step */ // internal headers #include "AssimpPCH.h" #include "RemoveRedundantMaterials.h" +#include "ParsingUtils.h" using namespace Assimp; @@ -68,6 +70,39 @@ bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const return (pFlags & aiProcess_RemoveRedundantMaterials) != 0; } +// ------------------------------------------------------------------------------------------------ +// Setup import properties +void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) +{ + // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST + configFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,""); +} + +// ------------------------------------------------------------------------------------------------ +// Extract single strings from a list of identifiers +void ConvertListToStrings(const std::string& in, std::list& out) +{ + const char* s = in.c_str(); + while (*s) { + SkipSpacesAndLineEnd(&s); + if (*s == '\'') { + const char* base = ++s; + while (*s != '\'') { + ++s; + if (*s == '\0') { + DefaultLogger::get()->error("RemoveRedundantMaterials: String list is ill-formatted"); + return; + } + } + out.push_back(std::string(base,(size_t)(s-base))); + ++s; + } + else { + out.push_back(GetNextToken(s)); + } + } +} + // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void RemoveRedundantMatsProcess::Execute( aiScene* pScene) @@ -77,16 +112,49 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) unsigned int iCnt = 0, unreferenced = 0; if (pScene->mNumMaterials) { + // Find out which materials are referenced by meshes + std::vector abReferenced(pScene->mNumMaterials,false); + for (unsigned int i = 0;i < pScene->mNumMeshes;++i) + abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; + + // If a list of materials to be excluded was given, match the list with + // our imported materials and 'salt' all positive matches to ensure that + // we get unique hashes later. + if (configFixedMaterials.length()) { + + std::list strings; + ConvertListToStrings(configFixedMaterials,strings); + + for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { + aiMaterial* mat = pScene->mMaterials[i]; + + aiString name; + mat->Get(AI_MATKEY_NAME,name); + + if (name.length) { + std::list::const_iterator it = std::find(strings.begin(), strings.end(), name.data); + if (it != strings.end()) { + + // Our brilliant 'salt': A single material property with ~ as first + // character to mark it as internal and temporary. + const int dummy = 1; + ((MaterialHelper*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0); + + // Keep this material even if no mesh references it + abReferenced[i] = true; + DefaultLogger::get()->debug(std::string("Found positive match in exclusion list: \'") + name.data + "\'"); + } + } + } + } + + // TODO: reimplement this algorithm to work in-place unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials]; unsigned int iNewNum = 0; - std::vector abReferenced(pScene->mNumMaterials,false); - for (unsigned int i = 0;i < pScene->mNumMeshes;++i) - abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; - - // iterate through all materials and calculate a hash for them + // Iterate through all materials and calculate a hash for them // store all hashes in a list and so a quick search whether // we do already have a specific hash. This allows us to // determine which materials are identical. @@ -136,8 +204,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) else ppcMaterials[idx] = pScene->mMaterials[p]; } // update all material indices - for (unsigned int p = 0; p < pScene->mNumMeshes;++p) - { + for (unsigned int p = 0; p < pScene->mNumMeshes;++p) { aiMesh* mesh = pScene->mMeshes[p]; mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex]; } diff --git a/code/RemoveRedundantMaterials.h b/code/RemoveRedundantMaterials.h index 4578ddb31..9a6270003 100644 --- a/code/RemoveRedundantMaterials.h +++ b/code/RemoveRedundantMaterials.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines a post processing step to remove redundant materials */ +/** @file RemoveRedundantMaterials.h + * @brief Defines a post processing step to remove redundant materials + */ #ifndef AI_REMOVEREDUNDANTMATERIALS_H_INC #define AI_REMOVEREDUNDANTMATERIALS_H_INC @@ -46,12 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../include/aiMesh.h" class RemoveRedundantMatsTest; -namespace Assimp - { +namespace Assimp { // --------------------------------------------------------------------------- -/** RemoveRedundantMatsProcess: Class to remove redundant materials -*/ +/** RemoveRedundantMatsProcess: Postprocessing steo to remove redundant + * materials from the imported scene. + */ class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess { friend class Importer; @@ -66,19 +68,38 @@ protected: public: // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ + // Check whether step is active bool IsActive( unsigned int pFlags) const; // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ + // Execute step on a given scene void Execute( aiScene* pScene); + + // ------------------------------------------------------------------- + // Setup import settings + void SetupProperties(const Importer* pImp); + + + // ------------------------------------------------------------------- + /** @brief Set list of fixed (unmutable) materials + * @param fixed See #AI_CONFIG_PP_RRM_EXCLUDE_LIST + */ + void SetFixedMaterialsString(const std::string& fixed = "") { + configFixedMaterials = fixed; + } + + // ------------------------------------------------------------------- + /** @brief Get list of fixed (unmutable) materials + * @return See #AI_CONFIG_PP_RRM_EXCLUDE_LIST + */ + const std::string& GetFixedMaterialsString() const { + return configFixedMaterials; + } + +private: + + //! Configuration option: list of all fixed materials + std::string configFixedMaterials; }; } // end of namespace Assimp diff --git a/code/RemoveVCProcess.cpp b/code/RemoveVCProcess.cpp index b6a832b78..23a2eb28e 100644 --- a/code/RemoveVCProcess.cpp +++ b/code/RemoveVCProcess.cpp @@ -51,15 +51,12 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer RemoveVCProcess::RemoveVCProcess() -{ -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well RemoveVCProcess::~RemoveVCProcess() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. diff --git a/code/SMDLoader.cpp b/code/SMDLoader.cpp index 0b6eec9c3..226b7f2d0 100644 --- a/code/SMDLoader.cpp +++ b/code/SMDLoader.cpp @@ -39,7 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the SMD importer class */ +/** @file SMDLoader.cpp + * @brief Implementation of the SMD importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_SMD_IMPORTER @@ -54,56 +56,37 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer SMDImporter::SMDImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well SMDImporter::~SMDImporter() -{ - // nothing to do here -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool SMDImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool SMDImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); + // fixme: auto format detection + return SimpleExtensionCheck(pFile,"smd","vta"); +} - if (extension.length() < 4)return false; - if (extension[0] != '.')return false; - - // VTA is not really supported as it contains vertex animations. - // However, at least the first keyframe can be loaded - if ((extension[1] != 's' && extension[1] != 'S') || - (extension[2] != 'm' && extension[2] != 'M') || - (extension[3] != 'd' && extension[3] != 'D')) - { - if ((extension[1] != 'v' && extension[1] != 'V') || - (extension[2] != 't' && extension[2] != 'T') || - (extension[3] != 'a' && extension[3] != 'A')) - { - return false; - } - } - return true; +// ------------------------------------------------------------------------------------------------ +// Get a list of all supported file extensions +void SMDImporter::GetExtensionList(std::string& append) +{ + append.append("*.smd;*.vta"); } // ------------------------------------------------------------------------------------------------ // Setup configuration properties void SMDImporter::SetupProperties(const Importer* pImp) { - // The AI_CONFIG_IMPORT_SMD_KEYFRAME option overrides the + // The + // AI_CONFIG_IMPORT_SMD_KEYFRAME option overrides the // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. - if(0xffffffff == (configFrameID = pImp->GetPropertyInteger( - AI_CONFIG_IMPORT_SMD_KEYFRAME,0xffffffff))) - { + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_SMD_KEYFRAME,0xffffffff); + if(0xffffffff == configFrameID) { configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); } } diff --git a/code/SMDLoader.h b/code/SMDLoader.h index b5e9f12bb..e3f863df4 100644 --- a/code/SMDLoader.h +++ b/code/SMDLoader.h @@ -38,10 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - -//! -//! @file Definition of SMD importer class -//! +/** @file SMDLoader.h + * @brief Defintion of the Valve SMD file format + */ #ifndef AI_SMDLOADER_H_INCLUDED #define AI_SMDLOADER_H_INCLUDED @@ -186,14 +185,16 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; // ------------------------------------------------------------------- /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - */ + * The function is a request to the importer to update its configuration + * basing on the Importer's configuration property list. + */ void SetupProperties(const Importer* pImp); protected: @@ -203,10 +204,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.smd;*.vta"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index 8e96a0157..60baf3ce7 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -64,27 +64,31 @@ STLImporter::~STLImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool STLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool STLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); + const std::string extension = GetExtension(pFile); - if (extension.length() < 4)return false; - if (extension[0] != '.')return false; - - if (extension[1] != 's' && extension[1] != 'S')return false; - if (extension[2] != 't' && extension[2] != 'T')return false; - if (extension[3] != 'l' && extension[3] != 'L')return false; - - return true; + if (extension == "stl") + return true; + else if (!extension.length() || checkSig) { + if (!pIOHandler) + return true; + const char* tokens[] = {"STL","solid"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,2); + } + return false; } + +// ------------------------------------------------------------------------------------------------ +void STLImporter::GetExtensionList(std::string& append) +{ + append.append("*.stl"); +} + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void STLImporter::InternReadFile( - const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) + const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { boost::scoped_ptr file( pIOHandler->Open( pFile, "rb")); @@ -183,7 +187,7 @@ void STLImporter::LoadASCIIFile() pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - unsigned int curFace = 0, curVertex = 0; + unsigned int curFace = 0, curVertex = 3; while (true) { // go to the next token diff --git a/code/STLLoader.h b/code/STLLoader.h index a89d551d9..4a59736de 100644 --- a/code/STLLoader.h +++ b/code/STLLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the STL importer class. */ +/** @file STLLoader.h + * Declaration of the STL importer class. + */ #ifndef AI_STLLOADER_H_INCLUDED #define AI_STLLOADER_H_INCLUDED @@ -48,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { // --------------------------------------------------------------------------- -/** Clas to load STL files +/** Importer class for the sterolithography STL file format */ class STLImporter : public BaseImporter { @@ -65,8 +67,10 @@ public: // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. */ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + * See BaseImporter::CanRead() for details. + */ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: @@ -74,10 +78,7 @@ protected: /** Called by Importer::GetExtensionList() for each loaded importer. * See BaseImporter::GetExtensionList() for details */ - void GetExtensionList(std::string& append) - { - append.append("*.stl"); - } + void GetExtensionList(std::string& append); // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. diff --git a/code/SceneCombiner.cpp b/code/SceneCombiner.cpp index 1d426e201..97e3a790f 100644 --- a/code/SceneCombiner.cpp +++ b/code/SceneCombiner.cpp @@ -74,40 +74,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -// ------------------------------------------------------------------------------------------------ -/** This is a small helper data structure simplifying our work - */ -struct SceneHelper -{ - SceneHelper () - : scene (NULL) - , idlen (0) - { - id[0] = 0; - } - - SceneHelper (aiScene* _scene) - : scene (_scene) - , idlen (0) - { - id[0] = 0; - } - - AI_FORCE_INLINE aiScene* operator-> () const - { - return scene; - } - - // scene we're working on - aiScene* scene; - - // prefix to be added to all identifiers in the scene ... - char id [32]; - - // and its strlen() - unsigned int idlen; -}; - // ------------------------------------------------------------------------------------------------ // Add a prefix to a string inline void PrefixString(aiString& string,const char* prefix, unsigned int len) @@ -124,6 +90,21 @@ inline void PrefixString(aiString& string,const char* prefix, unsigned int len) string.length += len; } +// ------------------------------------------------------------------------------------------------ +// Add node identifiers to a hashing set +void SceneCombiner::AddNodeHashes(aiNode* node, std::set& hashes) +{ + // Add node name to hashing set if it is non-empty - empty nodes are allowed + // and they can't have any anims assigned so its absolutely safe to duplicate them. + if (node->mName.length) { + hashes.insert( SuperFastHash(node->mName.data,node->mName.length) ); + } + + // Process all children recursively + for (unsigned int i = 0; i < node->mNumChildren;++i) + AddNodeHashes(node->mChildren[i],hashes); +} + // ------------------------------------------------------------------------------------------------ // Add a name prefix to all nodes in a hierarchy void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len) @@ -136,6 +117,44 @@ void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned i AddNodePrefixes(node->mChildren[i],prefix,len); } +// ------------------------------------------------------------------------------------------------ +// Search for matching names +bool SceneCombiner::FindNameMatch(const aiString& name, std::vector& input, unsigned int cur) +{ + const unsigned int hash = SuperFastHash(name.data, name.length); + + // Check whether we find a positive match in one of the given sets + for (unsigned int i = 0; i < input.size(); ++i) { + + if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { + return true; + } + } + return false; +} + +// ------------------------------------------------------------------------------------------------ +// Add a name prefix to all nodes in a hierarchy if a hash match is found +void SceneCombiner::AddNodePrefixesChecked(aiNode* node, const char* prefix, unsigned int len, + std::vector& input, unsigned int cur) +{ + ai_assert(NULL != prefix); + const unsigned int hash = SuperFastHash(node->mName.data,node->mName.length); + + // Check whether we find a positive match in one of the given sets + for (unsigned int i = 0; i < input.size(); ++i) { + + if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { + PrefixString(node->mName,prefix,len); + break; + } + } + + // Process all children recursively + for (unsigned int i = 0; i < node->mNumChildren;++i) + AddNodePrefixesChecked(node->mChildren[i],prefix,len,input,cur); +} + // ------------------------------------------------------------------------------------------------ // Add an offset to all mesh indices in a node graph void SceneCombiner::OffsetNodeMeshIndices (aiNode* node, unsigned int offset) @@ -300,6 +319,20 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, const unsigned int random = rndGen(); src[i].idlen = ::sprintf(src[i].id,"$%.6X$_",random); + + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { + + // Compute hashes for all identifiers in this scene and store them + // in a sorted table (for convenience I'm using std::set). We hash + // just the node and animation channel names, all identifiers except + // the material names should be caught by doing this. + AddNodeHashes(src[i]->mRootNode,src[i].hashes); + + for (unsigned int a = 0; a < src[i]->mNumAnimations;++a) { + aiAnimation* anim = src[i]->mAnimations[a]; + src[i].hashes.insert(SuperFastHash(anim->mName.data,anim->mName.length)); + } + } } } @@ -321,7 +354,11 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, dest->mNumAnimations += (*cur)->mNumAnimations; // Combine the flags of all scenes - dest->mFlags |= (*cur)->mFlags; + // We need to process them flag-by-flag here to get correct results + // dest->mFlags ; //|= (*cur)->mFlags; + if ((*cur)->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { + dest->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; + } } // generate the output texture list + an offset table for all texture indices @@ -352,11 +389,10 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, // generate the output material list + an offset table for all material indices if (dest->mNumMaterials) - { + { aiMaterial** pip = dest->mMaterials = new aiMaterial*[dest->mNumMaterials]; cnt = 0; - for ( unsigned int n = 0; n < src.size();++n ) - { + for ( unsigned int n = 0; n < src.size();++n ) { SceneHelper* cur = &src[n]; for (unsigned int i = 0; i < (*cur)->mNumMaterials;++i) { @@ -369,8 +405,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, } else *pip = (*cur)->mMaterials[i]; - if ((*cur)->mNumTextures != dest->mNumTextures) - { + if ((*cur)->mNumTextures != dest->mNumTextures) { // We need to update all texture indices of the mesh. So we need to search for // a material property called '$tex.file' @@ -391,8 +426,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, } // Need to generate new, unique material names? - else if (!::strcmp( prop->mKey.data,"$mat.name" ) && - flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) + else if (!::strcmp( prop->mKey.data,"$mat.name" ) && flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) { aiString* pcSrc = (aiString*) prop->mData; PrefixString(*pcSrc, (*cur).id, (*cur).idlen); @@ -458,7 +492,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, aiAnimation** ppAnims = dest->mAnimations = (dest->mNumAnimations ? new aiAnimation*[dest->mNumAnimations] : NULL); - for ( unsigned int n = 0; n < src.size();++n ) + for ( int n = src.size()-1; n >= 0 ;--n ) /* !!! important !!! */ { SceneHelper* cur = &src[n]; aiNode* node; @@ -466,7 +500,9 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, // To offset or not to offset, this is the question if (n != duplicates[n]) { + // Get full scenegraph copy Copy( &node, (*cur)->mRootNode ); + OffsetNodeMeshIndices(node,offset[duplicates[n]]); if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) { // (note:) they are already 'offseted' by offset[duplicates[n]] @@ -481,6 +517,30 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, if (n) // src[0] is the master node nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode,n )); + // add name prefixes? + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { + + // or the whole scenegraph + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { + AddNodePrefixesChecked(node,(*cur).id,(*cur).idlen,src,n); + } + else AddNodePrefixes(node,(*cur).id,(*cur).idlen); + + // meshes + for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) { + aiMesh* mesh = (*cur)->mMeshes[i]; + + // rename all bones + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { + if (!FindNameMatch(mesh->mBones[a]->mName,src,n)) + continue; + } + PrefixString(mesh->mBones[a]->mName,(*cur).id,(*cur).idlen); + } + } + } + // -------------------------------------------------------------------- // Copy light sources for (unsigned int i = 0; i < (*cur)->mNumLights;++i,++ppLights) @@ -490,6 +550,17 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, Copy(ppLights, (*cur)->mLights[i]); } else *ppLights = (*cur)->mLights[i]; + + + // Add name prefixes? + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { + if (!FindNameMatch((*ppLights)->mName,src,n)) + continue; + } + + PrefixString((*ppLights)->mName,(*cur).id,(*cur).idlen); + } } // -------------------------------------------------------------------- @@ -500,6 +571,16 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, Copy(ppCameras, (*cur)->mCameras[i]); } else *ppCameras = (*cur)->mCameras[i]; + + // Add name prefixes? + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { + if (!FindNameMatch((*ppCameras)->mName,src,n)) + continue; + } + + PrefixString((*ppCameras)->mName,(*cur).id,(*cur).idlen); + } } // -------------------------------------------------------------------- @@ -510,30 +591,26 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, Copy(ppAnims, (*cur)->mAnimations[i]); } else *ppAnims = (*cur)->mAnimations[i]; - } - } - for ( unsigned int n = 1; n < src.size();++n ) { - SceneHelper* cur = &src[n]; - // -------------------------------------------------------------------- - // Add prefixes - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) - { - for (unsigned int i = 0; i < (*cur)->mNumLights;++i) - PrefixString(dest->mLights[i]->mName,(*cur).id,(*cur).idlen); + // Add name prefixes? + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { + if (!FindNameMatch((*ppAnims)->mName,src,n)) + continue; + } - for (unsigned int i = 0; i < (*cur)->mNumCameras;++i) - PrefixString(dest->mCameras[i]->mName,(*cur).id,(*cur).idlen); - - for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i) { - aiAnimation* anim = dest->mAnimations[i]; - PrefixString(anim->mName,(*cur).id,(*cur).idlen); + PrefixString((*ppAnims)->mName,(*cur).id,(*cur).idlen); // don't forget to update all node animation channels - for (unsigned int a = 0; a < anim->mNumChannels;++a) - PrefixString(anim->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen); + for (unsigned int a = 0; a < (*ppAnims)->mNumChannels;++a) { + if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { + if (!FindNameMatch((*ppAnims)->mChannels[a]->mNodeName,src,n)) + continue; + } + + PrefixString((*ppAnims)->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen); + } } - AddNodePrefixes(nodes[n-1].node,(*cur).id,(*cur).idlen); } } @@ -585,6 +662,11 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, delete deleteMe; } + // Check flags + if (!dest->mNumMeshes || !dest->mNumMaterials) { + dest->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } + // We're finished } @@ -605,10 +687,8 @@ void SceneCombiner::BuildUniqueBoneList(std::list& asBones, std::list::iterator it2 = asBones.begin(); std::list::iterator end2 = asBones.end(); - for (;it2 != end2;++it2) - { - if ((*it2).first == itml) - { + for (;it2 != end2;++it2) { + if ((*it2).first == itml) { (*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset)); break; } @@ -666,10 +746,7 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator if (wmit != (*it).pSrcBones.begin() && pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix) { - DefaultLogger::get()->warn("Bones with equal names but different " - "offset matrices can't be joined at the moment. If this causes " - "problems, deactivate the OptimizeGraph-Step"); - + DefaultLogger::get()->warn("Bones with equal names but different offset matrices can't be joined at the moment"); continue; } pc->mOffsetMatrix = (*wmit).first->mOffsetMatrix; @@ -1026,7 +1103,7 @@ void SceneCombiner::Copy (aiAnimation** _dest, const aiAnimation* src) ::memcpy(dest,src,sizeof(aiAnimation)); // and reallocate all arrays - GetArrayCopy( dest->mChannels, dest->mNumChannels ); + CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels ); } // ------------------------------------------------------------------------------------------------ diff --git a/code/SceneCombiner.h b/code/SceneCombiner.h index 769403bfa..497224d03 100644 --- a/code/SceneCombiner.h +++ b/code/SceneCombiner.h @@ -118,7 +118,7 @@ struct NodeAttachmentInfo /** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY * Can be combined with AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES. * Unique names are generated, but only if this is absolutely - * required (if there would be conflicts otherwuse.) + * required to avoid name conflicts. */ #define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10 @@ -133,6 +133,43 @@ struct BoneWithHash : public std::pair { }; +// --------------------------------------------------------------------------- +/** @brief Utility for SceneCombiner + */ +struct SceneHelper +{ + SceneHelper () + : scene (NULL) + , idlen (0) + { + id[0] = 0; + } + + SceneHelper (aiScene* _scene) + : scene (_scene) + , idlen (0) + { + id[0] = 0; + } + + AI_FORCE_INLINE aiScene* operator-> () const + { + return scene; + } + + // scene we're working on + aiScene* scene; + + // prefix to be added to all identifiers in the scene ... + char id [32]; + + // and its strlen() + unsigned int idlen; + + // hash table to quickly check whether a name is contained in the scene + std::set hashes; +}; + // --------------------------------------------------------------------------- /** \brief Static helper class providing various utilities to merge two * scenes. It is intended as internal utility and NOT for use by @@ -301,6 +338,26 @@ public: // recursive, of course static void Copy (aiNode** dest, const aiNode* src); + + +private: + + // ------------------------------------------------------------------- + // Same as AddNodePrefixes, but with an additional check + static void AddNodePrefixesChecked(aiNode* node, const char* prefix, + unsigned int len, + std::vector& input, + unsigned int cur); + + // ------------------------------------------------------------------- + // Add node identifiers to a hashing set + static void AddNodeHashes(aiNode* node, std::set& hashes); + + + // ------------------------------------------------------------------- + // Search for duplicate names + static bool FindNameMatch(const aiString& name, + std::vector& input, unsigned int cur); }; } diff --git a/code/ScenePreprocessor.cpp b/code/ScenePreprocessor.cpp index 384b7c9b5..e678cc602 100644 --- a/code/ScenePreprocessor.cpp +++ b/code/ScenePreprocessor.cpp @@ -64,26 +64,56 @@ void ScenePreprocessor::ProcessScene () // Generate a default material if none was specified if (!scene->mNumMaterials && scene->mNumMeshes) { - scene->mMaterials = new aiMaterial*[scene->mNumMaterials = 1]; - MaterialHelper* helper = new MaterialHelper(); - scene->mMaterials[0] = helper; + scene->mMaterials = new aiMaterial*[2]; + MaterialHelper* helper; - // gray - aiColor3D clr(0.6f,0.6f,0.6f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); + aiString name; - // add a small ambient color value - clr = aiColor3D(0.05f,0.05f,0.05f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT); + // Check whether there are meshes with at least one set of uv coordinates ... add a dummy texture for them + // meshes without texture coordinates receive a boring gray default material. + unsigned int mat0 = 0xffffffff, mat1 = 0xffffffff; + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + if (scene->mMeshes[i]->mTextureCoords[0]) { - // setup the default name - aiString name(AI_DEFAULT_MATERIAL_NAME); - helper->AddProperty(&name,AI_MATKEY_NAME); + if (mat0 == 0xffffffff) { + scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper(); - for (unsigned int i = 0; i < scene->mNumMeshes;++i) - scene->mMeshes[i]->mMaterialIndex = 0; + // dummy texture + name.Set("texture.png"); + helper->AddProperty(&name,AI_MATKEY_TEXTURE_DIFFUSE(0)); - DefaultLogger::get()->debug("ScenePreprocessor: Added default material \'" AI_DEFAULT_MATERIAL_NAME "\'"); + // setup default name + name.Set(AI_DEFAULT_TEXTURED_MATERIAL_NAME); + helper->AddProperty(&name,AI_MATKEY_NAME); + + mat0 = scene->mNumMaterials++; + DefaultLogger::get()->debug("ScenePreprocessor: Adding textured material \'" AI_DEFAULT_TEXTURED_MATERIAL_NAME "\'"); + } + scene->mMeshes[i]->mMaterialIndex = mat0; + } + else + { + if (mat1 == 0xffffffff) { + scene->mMaterials[scene->mNumMaterials] = helper = new MaterialHelper(); + + // gray + aiColor3D clr(0.6f,0.6f,0.6f); + helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); + + // add a small ambient color value + clr = aiColor3D(0.05f,0.05f,0.05f); + helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT); + + // setup the default name + name.Set(AI_DEFAULT_MATERIAL_NAME); + helper->AddProperty(&name,AI_MATKEY_NAME); + + mat1 = scene->mNumMaterials++; + DefaultLogger::get()->debug("ScenePreprocessor: Adding grey material \'" AI_DEFAULT_MATERIAL_NAME "\'"); + } + scene->mMeshes[i]->mMaterialIndex = mat1; + } + } } } @@ -96,8 +126,22 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh) if (!mesh->mTextureCoords[i]) mesh->mNumUVComponents[i] = 0; - else if( !mesh->mNumUVComponents[i]) - mesh->mNumUVComponents[i] = 2; + else { + if( !mesh->mNumUVComponents[i]) + mesh->mNumUVComponents[i] = 2; + + // Ensure unsued components are zeroed. This will make 1D texture channels work + // as if they were 2D channels .. just in case an application doesn't handle + // this case + if (2 == mesh->mNumUVComponents[i]) { + for (aiVector3D* p = mesh->mTextureCoords[i], *end = p+mesh->mNumVertices; p != end; ++p) + p->z = 0.f; + } + else if (1 == mesh->mNumUVComponents[i]) { + for (aiVector3D* p = mesh->mTextureCoords[i], *end = p+mesh->mNumVertices; p != end; ++p) + p->z = p->y = 0.f; + } + } } // If the information which primitive types are there in the @@ -127,6 +171,15 @@ void ScenePreprocessor::ProcessMesh (aiMesh* mesh) } } } + + // If tangents and normals are given but no bitangents compute them + if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) + { + mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; + for (unsigned int i = 0; i < mesh->mNumVertices;++i) { + mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; + } + } } // --------------------------------------------------------------------------------------------- diff --git a/code/SkeletonMeshBuilder.cpp b/code/SkeletonMeshBuilder.cpp index e411720f5..776ddb260 100644 --- a/code/SkeletonMeshBuilder.cpp +++ b/code/SkeletonMeshBuilder.cpp @@ -120,11 +120,12 @@ void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode) mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8)); mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11)); } - } else + } + else { // if the node has no children, it's an end node. Put a little knob there instead aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4); - float sizeEstimate = ownpos.Length() * 0.2f; + float sizeEstimate = ownpos.Length() * 0.18f; mVertices.push_back( aiVector3D( -sizeEstimate, 0.0f, 0.0f)); mVertices.push_back( aiVector3D( 0.0f, sizeEstimate, 0.0f)); diff --git a/code/SortByPTypeProcess.cpp b/code/SortByPTypeProcess.cpp index 9b7bbbbde..279aa5651 100644 --- a/code/SortByPTypeProcess.cpp +++ b/code/SortByPTypeProcess.cpp @@ -303,7 +303,7 @@ void SortByPTypeProcess::Execute( aiScene* pScene) if (vert) { *vert++ = mesh->mVertices[idx]; - //mesh->mVertices[idx].x = std::numeric_limits::quiet_NaN(); + //mesh->mVertices[idx].x = get_qnan(); } if (nor )*nor++ = mesh->mNormals[idx]; if (tan ) diff --git a/code/SpatialSort.cpp b/code/SpatialSort.cpp index ecf3048c2..4d4da7908 100644 --- a/code/SpatialSort.cpp +++ b/code/SpatialSort.cpp @@ -75,7 +75,7 @@ void SpatialSort::Fill( const aiVector3D* pPositions, unsigned int pNumPositions for( unsigned int a = 0; a < pNumPositions; a++) { const char* tempPointer = reinterpret_cast (pPositions); - const aiVector3D* vec = reinterpret_cast (tempPointer + a * pElementOffset); + const aiVector3D* vec = reinterpret_cast (tempPointer + a * pElementOffset); // store position by index and distance float distance = *vec * mPlaneNormal; @@ -90,8 +90,8 @@ void SpatialSort::Fill( const aiVector3D* pPositions, unsigned int pNumPositions // Returns an iterator for all positions close to the given position. void SpatialSort::FindPositions( const aiVector3D& pPosition, float pRadius, std::vector& poResults) const { - float dist = pPosition * mPlaneNormal; - float minDist = dist - pRadius, maxDist = dist + pRadius; + const float dist = pPosition * mPlaneNormal; + const float minDist = dist - pRadius, maxDist = dist + pRadius; // clear the array in this strange fashion because a simple clear() would also deallocate // the array which we want to avoid @@ -128,10 +128,10 @@ void SpatialSort::FindPositions( const aiVector3D& pPosition, float pRadius, std // Mow start iterating from there until the first position lays outside of the distance range. // Add all positions inside the distance range within the given radius to the result aray std::vector::const_iterator it = mPositions.begin() + index; - float squareEpsilon = pRadius * pRadius; + const float pSquared = pRadius*pRadius; while( it->mDistance < maxDist) { - if( (it->mPosition - pPosition).SquareLength() < squareEpsilon) + if( (it->mPosition - pPosition).SquareLength() < pSquared) poResults.push_back( it->mIndex); ++it; if( it == mPositions.end()) diff --git a/code/StreamReader.h b/code/StreamReader.h index 64ab2739c..143ec9957 100644 --- a/code/StreamReader.h +++ b/code/StreamReader.h @@ -68,13 +68,15 @@ public: * The stream will be deleted afterwards. * @param stream Input stream */ - StreamReader(IOStream* stream) + StreamReader(IOStream* _stream) { - ai_assert(NULL != stream); - this->stream = stream; + if (!_stream) + throw new ImportErrorException("StreamReader: Unable to open file"); + stream = _stream; size_t s = stream->FileSize(); - if (!s)throw new ImportErrorException("File is empty"); + if (!s) + throw new ImportErrorException("StreamReader: File is empty"); current = buffer = new int8_t[s]; stream->Read(current,s,1); diff --git a/code/StringComparison.h b/code/StringComparison.h index 6b919506e..18e316b28 100644 --- a/code/StringComparison.h +++ b/code/StringComparison.h @@ -89,7 +89,7 @@ inline unsigned int ASSIMP_itoa10( char* out, unsigned int max, int32_t number) *out++ = lookup[digit]; ++written; - number -= digit*10; + number -= digit*cur; } cur /= 10; } diff --git a/code/TerragenLoader.cpp b/code/TerragenLoader.cpp index 4f336777a..8f4907398 100644 --- a/code/TerragenLoader.cpp +++ b/code/TerragenLoader.cpp @@ -51,6 +51,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer TerragenImporter::TerragenImporter() +: configComputeUVs (false) {} // ------------------------------------------------------------------------------------------------ @@ -60,19 +61,24 @@ TerragenImporter::~TerragenImporter() // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool TerragenImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool TerragenImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of('.'); + // check file extension + std::string extension = GetExtension(pFile); + + if( extension == "ter") + return true; - // no file extension - can't read - if( pos == std::string::npos)return false; - std::string extension = pFile.substr( pos); - - for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) - *it = tolower( *it); - - return extension == ".ter"; + if( !extension.length() || checkSig) { + /* If CanRead() is called in order to check whether we + * support a specific file extension in general pIOHandler + * might be NULL and it's our duty to return true here. + */ + if (!pIOHandler)return true; + const char* tokens[] = {"terragen"}; + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + } + return false; } // ------------------------------------------------------------------------------------------------ @@ -82,6 +88,14 @@ void TerragenImporter::GetExtensionList(std::string& append) append.append("*.ter;"); } +// ------------------------------------------------------------------------------------------------ +// Setup import properties +void TerragenImporter::SetupProperties(const Importer* pImp) +{ + // AI_CONFIG_IMPORT_TER_MAKE_UVS + configComputeUVs = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS,0) ); +} + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void TerragenImporter::InternReadFile( const std::string& pFile, @@ -182,7 +196,14 @@ void TerragenImporter::InternReadFile( const std::string& pFile, // We return quads aiFace* f = m->mFaces = new aiFace[m->mNumFaces = (x-1)*(y-1)]; aiVector3D* pv = m->mVertices = new aiVector3D[m->mNumVertices = m->mNumFaces*4]; - + + aiVector3D* uv; + float step_y,step_x; + if (configComputeUVs) { + uv = m->mTextureCoords[0] = new aiVector3D[m->mNumVertices]; + step_y = 1.f/y; + step_x = 1.f/x; + } const int16_t* data = (const int16_t*)reader.GetPtr(); for (unsigned int yy = 0, t = 0; yy < y-1;++yy) { @@ -196,6 +217,14 @@ void TerragenImporter::InternReadFile( const std::string& pFile, *pv++ = aiVector3D(fx+1,fy+1,(float)data[tmp + xx+1] * hscale + bheight); *pv++ = aiVector3D(fx+1,fy, (float)data[tmp2 + xx+1] * hscale + bheight); + // also make texture coordinates, if necessary + if (configComputeUVs) { + *uv++ = aiVector3D( step_x*xx, step_y*yy, 0.f ); + *uv++ = aiVector3D( step_x*xx, step_y*(yy+1), 0.f ); + *uv++ = aiVector3D( step_x*(xx+1), step_y*(yy+1), 0.f ); + *uv++ = aiVector3D( step_x*(xx+1), step_y*yy, 0.f ); + } + // make indices f->mIndices = new unsigned int[f->mNumIndices = 4]; for (unsigned int i = 0; i < 4;++i) diff --git a/code/TerragenLoader.h b/code/TerragenLoader.h index 7567d6be6..8e84cf5e8 100644 --- a/code/TerragenLoader.h +++ b/code/TerragenLoader.h @@ -38,7 +38,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Declaration of the .ter importer class. */ +/** @file TerragenLoader.h + * @brief Declaration of the .ter importer class. + */ #ifndef INCLUDED_AI_TERRAGEN_TERRAIN_LOADER_H #define INCLUDED_AI_TERRAGEN_TERRAIN_LOADER_H @@ -79,29 +81,25 @@ protected: public: // ------------------------------------------------------------------- - /** @brief Returns whether we can handle the format of the given file - * - * See BaseImporter::CanRead() for details. - **/ - bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const; + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; protected: // ------------------------------------------------------------------- - /** @brief Called by Importer::GetExtensionList() - * - * See BaseImporter::GetExtensionList() for details - */ void GetExtensionList(std::string& append); // ------------------------------------------------------------------- - /** @brief Imports the given file into the given scene structure. - * - * See BaseImporter::InternReadFile() for details - */ void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + // ------------------------------------------------------------------- + void SetupProperties(const Importer* pImp); + +private: + + bool configComputeUVs; + }; //! class TerragenImporter } // end of namespace Assimp diff --git a/code/UnrealLoader.cpp b/code/UnrealLoader.cpp new file mode 100644 index 000000000..760cb6a7b --- /dev/null +++ b/code/UnrealLoader.cpp @@ -0,0 +1,448 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file UnrealLoader.cpp + * @brief Implementation of the UNREAL (*.3D) importer class + * + * Sources: + * http://local.wasp.uwa.edu.au/~pbourke/dataformats/unreal/ + */ + +#include "AssimpPCH.h" + +#ifndef AI_BUILD_NO_3D_IMPORTER + +#include "UnrealLoader.h" +#include "StreamReader.h" +#include "ParsingUtils.h" +#include "fast_atof.h" + +using namespace Assimp; + +// ------------------------------------------------------------------------------------------------ +// Constructor to be privately used by Importer +UnrealImporter::UnrealImporter() +: configFrameID (0) +, configHandleFlags (true) +{} + +// ------------------------------------------------------------------------------------------------ +// Destructor, private as well +UnrealImporter::~UnrealImporter() +{} + +// ------------------------------------------------------------------------------------------------ +// Returns whether the class can handle the format of the given file. +bool UnrealImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const +{ + return SimpleExtensionCheck(pFile,"3d","uc"); +} + +// ------------------------------------------------------------------------------------------------ +// Build a string of all file extensions supported +void UnrealImporter::GetExtensionList(std::string& append) +{ + append.append("*.3d;*.uc"); +} + +// ------------------------------------------------------------------------------------------------ +// Setup configuration properties for the loader +void UnrealImporter::SetupProperties(const Importer* pImp) +{ + // The + // AI_CONFIG_IMPORT_UNREAL_KEYFRAME option overrides the + // AI_CONFIG_IMPORT_GLOBAL_KEYFRAME option. + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_KEYFRAME,0xffffffff); + if(0xffffffff == configFrameID) { + configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0); + } + + // AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS, default is true + configHandleFlags = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS,1)); +} + +// ------------------------------------------------------------------------------------------------ +// Imports the given file into the given scene structure. +void UnrealImporter::InternReadFile( const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) +{ + // For any of the 3 files being passed get the three correct paths + // First of all, determine file extension + std::string::size_type pos = pFile.find_last_of('.'); + std::string extension = pFile.substr( pos); + + for( std::string::iterator it = extension.begin(); it != extension.end(); ++it) + *it = tolower( *it); + + std::string d_path,a_path,uc_path; + if (extension == ".3d") + { + // jjjj_d.3d + // jjjj_a.3d + pos = pFile.find_last_of('_'); + if (std::string::npos == pos) { + throw new ImportErrorException("UNREAL: Unexpected naming scheme"); + } + extension = pFile.substr(0,pos); + } + else // if (extension == ".uc") + { + extension = pFile.substr(0,pos); + } + + // build proper paths + d_path = extension+"_d.3d"; + a_path = extension+"_a.3d"; + uc_path = extension+".uc"; + + DefaultLogger::get()->debug("UNREAL: data file is " + d_path); + DefaultLogger::get()->debug("UNREAL: aniv file is " + a_path); + DefaultLogger::get()->debug("UNREAL: uc file is " + uc_path); + + // and open the files ... we can't live without them + IOStream* p = pIOHandler->Open(d_path); + if (!p) + throw new ImportErrorException("UNREAL: Unable to open _d file"); + StreamReaderLE d_reader(pIOHandler->Open(d_path)); + + const uint16_t numTris = d_reader.GetI2(); + const uint16_t numVert = d_reader.GetI2(); + d_reader.IncPtr(44); + if (!numTris || numVert < 3) + throw new ImportErrorException("UNREAL: Invalid number of vertices/triangles"); + + // maximum texture index + unsigned int maxTexIdx = 0; + + // collect triangles + std::vector triangles(numTris); + for (std::vector::iterator it = triangles.begin(), end = triangles.end(); + it != end; ++it) + { + Unreal::Triangle& tri = *it; + + for (unsigned int i = 0; i < 3;++i) + { + tri.mVertex[i] = d_reader.GetI2(); + if (tri.mVertex[i] >= numTris) + { + DefaultLogger::get()->warn("UNREAL: vertex index out of range"); + tri.mVertex[i] = 0; + } + } + tri.mType = d_reader.GetI1(); + + // handle mesh flagss? + if (configHandleFlags) + tri.mType = Unreal::MF_NORMAL_OS; + else { + // ignore MOD and MASKED for the moment, treat them as two-sided + if (tri.mType == Unreal::MF_NORMAL_MOD_TS || tri.mType == Unreal::MF_NORMAL_MASKED_TS) + tri.mType = Unreal::MF_NORMAL_TS; + } + d_reader.IncPtr(1); + + for (unsigned int i = 0; i < 3;++i) + for (unsigned int i2 = 0; i2 < 2;++i2) + tri.mTex[i][i2] = d_reader.GetI1(); + + tri.mTextureNum = d_reader.GetI1(); + maxTexIdx = std::max(maxTexIdx,(unsigned int)tri.mTextureNum); + d_reader.IncPtr(1); + } + + p = pIOHandler->Open(a_path); + if (!p) + throw new ImportErrorException("UNREAL: Unable to open _a file"); + StreamReaderLE a_reader(pIOHandler->Open(a_path)); + + // read number of frames + const uint32_t numFrames = a_reader.GetI2(); + if (configFrameID >= numFrames) + throw new ImportErrorException("UNREAL: The requested frame does not exist"); + + uint32_t st = a_reader.GetI2(); + if (st != numVert*4) + throw new ImportErrorException("UNREAL: Unexpected aniv file length"); + + // skip to our frame + a_reader.IncPtr(configFrameID *numVert*4); + + // collect vertices + std::vector vertices(numVert); + for (std::vector::iterator it = vertices.begin(), end = vertices.end(); + it != end; ++it) + { + int32_t val = a_reader.GetI4(); + Unreal::DecompressVertex(*it,val); + } + + // list of textures. + std::vector< std::pair > textures; + + // allocate the output scene + aiNode* nd = pScene->mRootNode = new aiNode(); + nd->mName.Set(""); + + // we can live without the uc file if necessary + boost::scoped_ptr pb (pIOHandler->Open(uc_path)); + if (pb.get()) { + + size_t s = pb->FileSize(); + std::vector _data(s+1); + pb->Read(&_data[0],s,1); + + _data[s] = 0; + const char* data = &_data[0]; + + std::vector< std::pair< std::string,std::string > > tempTextures; + + // do a quick search in the UC file for some known, usually texture-related, tags + for (;*data;++data) + { + if (TokenMatchI(data,"#exec",5)) { + SkipSpacesAndLineEnd(&data); + + // #exec TEXTURE IMPORT [...] NAME=jjjjj [...] FILE=jjjj.pcx [...] + if (TokenMatchI(data,"TEXTURE",7)) { + SkipSpacesAndLineEnd(&data); + + if (TokenMatchI(data,"IMPORT",6)) + { + tempTextures.push_back(std::pair< std::string,std::string >()); + std::pair< std::string,std::string >& me = tempTextures.back(); + for (;!IsLineEnd(*data);++data) + { + if (!::ASSIMP_strincmp(data,"NAME=",5)) + { + const char *d = data+=5; + for (;!IsSpaceOrNewLine(*data);++data); + me.first = std::string(d,(size_t)(data-d)); + } + else if (!::ASSIMP_strincmp(data,"FILE=",5)) + { + const char *d = data+=5; + for (;!IsSpaceOrNewLine(*data);++data); + me.second = std::string(d,(size_t)(data-d)); + } + } + if (!me.first.length() || !me.second.length()) + tempTextures.pop_back(); + } + } + // #exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1 + // #exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2 + else if (TokenMatchI(data,"MESHMAP",7)) { + SkipSpacesAndLineEnd(&data); + + if (TokenMatchI(data,"SETTEXTURE",10)) { + + textures.push_back(std::pair()); + std::pair& me = textures.back(); + + for (;!IsLineEnd(*data);++data) { + if (!::ASSIMP_strincmp(data,"NUM=",4)) + { + data += 4; + me.first = strtol10(data,&data); + } + else if (!::ASSIMP_strincmp(data,"TEXTURE=",8)) + { + data += 8; + const char *d = data; + for (;!IsSpaceOrNewLine(*data);++data); + me.second = std::string(d,(size_t)(data-d)); + + // try to find matching path names, doesn't care if we don't find them + for (std::vector< std::pair< std::string,std::string > >::const_iterator it = tempTextures.begin(); + it != tempTextures.end(); ++it) + { + if ((*it).first == me.second) + { + me.second = (*it).second; + break; + } + } + } + } + } + else if (TokenMatchI(data,"SCALE",5)) { + + for (;!IsLineEnd(*data);++data) { + if (data[0] == 'X' && data[1] == '=') { + data = fast_atof_move(data+2,(float&)nd->mTransformation.a1); + } + else if (data[0] == 'Y' && data[1] == '=') { + data = fast_atof_move(data+2,(float&)nd->mTransformation.b2); + } + else if (data[0] == 'Z' && data[1] == '=') { + data = fast_atof_move(data+2,(float&)nd->mTransformation.c3); + } + } + } + } + } + } + } + else { + DefaultLogger::get()->error("Unable to open .uc file"); + } + + std::vector materials; + materials.reserve(textures.size()*2+5); + + // find out how many output meshes and materials we'll have and build material indices + for (std::vector::iterator it = triangles.begin(), end = triangles.end(); + it != end; ++it) + { + Unreal::Triangle& tri = *it; + Unreal::TempMat mat(tri); + std::vector::iterator nt = std::find(materials.begin(),materials.end(),mat); + if (nt == materials.end()) { + // add material + tri.matIndex = materials.size(); + mat.numFaces = 1; + materials.push_back(mat); + + ++pScene->mNumMeshes; + } + else { + tri.matIndex = nt-materials.begin(); + ++nt->numFaces; + } + } + + if (!pScene->mNumMeshes) + throw new ImportErrorException("UNREAL: Unable to find valid mesh data"); + + // allocate meshes and bind them to the node graph + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes]; + + nd->mNumMeshes = pScene->mNumMeshes; + nd->mMeshes = new unsigned int[nd->mNumMeshes]; + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { + aiMesh* m = pScene->mMeshes[i] = new aiMesh(); + m->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + + const unsigned int num = materials[i].numFaces; + m->mFaces = new aiFace [num]; + m->mVertices = new aiVector3D [num*3]; + m->mTextureCoords[0] = new aiVector3D [num*3]; + + nd->mMeshes[i] = i; + + // create materials, too + MaterialHelper* mat = new MaterialHelper(); + pScene->mMaterials[i] = mat; + + // all white by default - texture rulez + aiColor3D color(1.f,1.f,1.f); + + aiString s; + ::sprintf(s.data,"mat%i_tx%i_",i,materials[i].tex); + + // set the two-sided flag + if (materials[i].type == Unreal::MF_NORMAL_TS) { + const int twosided = 1; + mat->AddProperty(&twosided,1,AI_MATKEY_TWOSIDED); + ::strcat(s.data,"ts_"); + } + else ::strcat(s.data,"os_"); + + // make TRANS faces 90% opaque that RemRedundantMaterials won't catch us + if (materials[i].type == Unreal::MF_NORMAL_TRANS_TS) + { + const float opac = 0.9f; + mat->AddProperty(&opac,1,AI_MATKEY_OPACITY); + ::strcat(s.data,"tran_"); + } + else ::strcat(s.data,"opaq_"); + + // a special name for the weapon attachment point + if (materials[i].type == Unreal::MF_WEAPON_PLACEHOLDER) + { + s.length = ::sprintf(s.data,"$WeaponTag$"); + color = aiColor3D(0.f,0.f,0.f); + } + + // set color and name + mat->AddProperty(&color,1,AI_MATKEY_COLOR_DIFFUSE); + s.length = ::strlen(s.data); + mat->AddProperty(&s,AI_MATKEY_NAME); + + // set texture, if any + const unsigned int tex = materials[i].tex; + for (std::vector< std::pair< unsigned int, std::string > >::const_iterator it = textures.begin(); + it != textures.end();++it) + { + if ((*it).first == tex) + { + s.Set((*it).second); + mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); + break; + } + } + } + + // fill them. + for (std::vector::iterator it = triangles.begin(), end = triangles.end(); + it != end; ++it) + { + Unreal::Triangle& tri = *it; + Unreal::TempMat mat(tri); + std::vector::iterator nt = std::find(materials.begin(),materials.end(),mat); + + aiMesh* mesh = pScene->mMeshes[nt-materials.begin()]; + aiFace& f = mesh->mFaces[mesh->mNumFaces++]; + f.mIndices = new unsigned int[f.mNumIndices = 3]; + + for (unsigned int i = 0; i < 3;++i,mesh->mNumVertices++) + { + f.mIndices[i] = mesh->mNumVertices; + + mesh->mVertices[mesh->mNumVertices] = vertices[ tri.mVertex[i] ]; + mesh->mTextureCoords[0][mesh->mNumVertices] = aiVector3D( tri.mTex[i][0] / 255.f, 1.f - tri.mTex[i][1] / 255.f, 0.f); + } + } +} + +#endif // !! AI_BUILD_NO_3D_IMPORTER \ No newline at end of file diff --git a/code/UnrealLoader.h b/code/UnrealLoader.h new file mode 100644 index 000000000..efd20ceab --- /dev/null +++ b/code/UnrealLoader.h @@ -0,0 +1,196 @@ +/* +Open Asset Import Library (ASSIMP) +---------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file UnrealLoader.h + * @brief Declaration of the .3d (UNREAL) importer class. + */ +#ifndef INCLUDED_AI_3D_LOADER_H +#define INCLUDED_AI_3D_LOADER_H + +#include "BaseImporter.h" +namespace Assimp { +namespace Unreal { + + /* + 0 = Normal one-sided + 1 = Normal two-sided + 2 = Translucent two-sided + 3 = Masked two-sided + 4 = Modulation blended two-sided + 8 = Placeholder triangle for weapon positioning (invisible) + */ +enum MeshFlags { + MF_NORMAL_OS = 0, + MF_NORMAL_TS = 1, + MF_NORMAL_TRANS_TS = 2, + MF_NORMAL_MASKED_TS = 3, + MF_NORMAL_MOD_TS = 4, + MF_WEAPON_PLACEHOLDER = 8 +}; + + // a single triangle +struct Triangle { + uint16_t mVertex[3]; // Vertex indices + char mType; // James' Mesh Type + char mColor; // Color for flat and Gourand Shaded + unsigned char mTex[3][2]; // Texture UV coordinates + unsigned char mTextureNum; // Source texture offset + char mFlags; // Unreal Mesh Flags (unused) + + unsigned int matIndex; +}; + +// temporary representation for a material +struct TempMat { + TempMat() + : numFaces (0) + {} + + TempMat(const Triangle& in) + : type ((Unreal::MeshFlags)in.mType) + , tex (in.mTextureNum) + , numFaces (0) + {} + + // type of mesh + Unreal::MeshFlags type; + + // index of texture + unsigned int tex; + + // number of faces using us + unsigned int numFaces; + + // for std::find + bool operator == (const TempMat& o ) { + return (tex == o.tex && type == o.type); + } +}; + +struct Vertex +{ + int32_t X : 11; + int32_t Y : 11; + int32_t Z : 10; +}; + + // UNREAL vertex compression +inline void CompressVertex(const aiVector3D& v, uint32_t& out) +{ + Vertex n; + n.X = (int32_t)v.x; + n.Y = (int32_t)v.y; + n.Z = (int32_t)v.z; + out = *((uint32_t*)&n); +} + + // UNREAL vertex decompression +inline void DecompressVertex(aiVector3D& v, int32_t in) +{ + Vertex n = *((Vertex*)&in); + v.x = (float)n.X; + v.y = (float)n.Y; + v.z = (float)n.Z; +} + +} // end namespace Unreal + +// --------------------------------------------------------------------------- +/** @brief Importer class to load UNREAL files (*.3d) +*/ +class UnrealImporter : public BaseImporter +{ + friend class Importer; + +protected: + /** Constructor to be privately used by Importer */ + UnrealImporter(); + + /** Destructor, private as well */ + ~UnrealImporter(); + +public: + + // ------------------------------------------------------------------- + /** @brief Returns whether we can handle the format of the given file + * + * See BaseImporter::CanRead() for details. + **/ + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, + bool checkSig) const; + +protected: + + // ------------------------------------------------------------------- + /** @brief Called by Importer::GetExtensionList() + * + * See BaseImporter::GetExtensionList() for details + */ + void GetExtensionList(std::string& append); + + + // ------------------------------------------------------------------- + /** @brief Setup properties for the importer + * + * See BaseImporter::SetupProperties() for details + */ + void SetupProperties(const Importer* pImp); + + + // ------------------------------------------------------------------- + /** @brief Imports the given file into the given scene structure. + * + * See BaseImporter::InternReadFile() for details + */ + void InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler); + +private: + + //! frame to be loaded + uint32_t configFrameID; + + //! process surface flags + bool configHandleFlags; + +}; // !class UnrealImporter + +} // end of namespace Assimp +#endif // AI_UNREALIMPORTER_H_INC diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index d888b9efc..2b2b01259 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -39,8 +39,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the post processing step to validate - * the data structure returned by Assimp +/** @file ValidateDataStructure.cpp + * @brief Implementation of the post processing step to validate + * the data structure returned by Assimp. */ #include "AssimpPCH.h" @@ -50,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseImporter.h" #include "fast_atof.h" - // CRT headers #include @@ -85,15 +85,9 @@ void ValidateDSProcess::ReportError(const char* msg,...) va_start(args,msg); char szBuffer[3000]; + const int iLen = vsprintf(szBuffer,msg,args); + ai_assert(iLen > 0); - int iLen; - iLen = vsprintf(szBuffer,msg,args); - - if (0 >= iLen) - { - // :-) should not happen ... - throw new ImportErrorException("Idiot ... learn coding!"); - } va_end(args); #ifdef _DEBUG aiAssert( false,szBuffer,__LINE__,__FILE__ ); @@ -109,15 +103,9 @@ void ValidateDSProcess::ReportWarning(const char* msg,...) va_start(args,msg); char szBuffer[3000]; + const int iLen = vsprintf(szBuffer,msg,args); + ai_assert(iLen > 0); - int iLen; - iLen = vsprintf(szBuffer,msg,args); - - if (0 >= iLen) - { - // :-) should not happen ... - throw new ImportErrorException("Idiot ... learn coding!"); - } va_end(args); DefaultLogger::get()->warn("Validation warning: " + std::string(szBuffer,iLen)); } @@ -126,8 +114,7 @@ void ValidateDSProcess::ReportWarning(const char* msg,...) inline int HasNameMatch(const aiString& in, aiNode* node) { int result = (node->mName == in ? 1 : 0 ); - for (unsigned int i = 0; i < node->mNumChildren;++i) - { + for (unsigned int i = 0; i < node->mNumChildren;++i) { result += HasNameMatch(in,node->mChildren[i]); } return result; @@ -166,8 +153,7 @@ inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size, // validate all entries if (size) { - if (!parray) - { + if (!parray) { ReportError("aiScene::%s is NULL (aiScene::%s is %i)", firstName, secondName, size); } @@ -205,13 +191,11 @@ inline void ValidateDSProcess::DoValidationWithNameCheck(T** array, for (unsigned int i = 0; i < size;++i) { int res = HasNameMatch(array[i]->mName,mScene->mRootNode); - if (!res) - { + if (!res) { ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)", firstName,i,array[i]->mName.data); } - else if (1 != res) - { + else if (1 != res) { ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name", firstName,i,array[i]->mName.data); } @@ -228,79 +212,68 @@ void ValidateDSProcess::Execute( aiScene* pScene) // validate the node graph of the scene Validate(pScene->mRootNode); - // at least one of the mXXX arrays must be non-empty or we'll flag - // the sebe as invalid + // At least one of the mXXX arrays must be non-empty or we'll flag + // the scene as invalid bool has = false; // validate all meshes - if (pScene->mNumMeshes) - { - has = true; + if (pScene->mNumMeshes) { + // has = true; DoValidation(pScene->mMeshes,pScene->mNumMeshes,"mMeshes","mNumMeshes"); } - else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) - { + else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there"); } - else if (pScene->mMeshes) - { + else if (pScene->mMeshes) { ReportError("aiScene::mMeshes is non-null although there are no meshes"); } // validate all animations - if (pScene->mNumAnimations) - { - has = true; + if (pScene->mNumAnimations) { + // has = true; DoValidation(pScene->mAnimations,pScene->mNumAnimations, "mAnimations","mNumAnimations"); } - else if (pScene->mAnimations) - { + else if (pScene->mAnimations) { ReportError("aiScene::mAnimations is non-null although there are no animations"); } // validate all cameras - if (pScene->mNumCameras) - { - has = true; + if (pScene->mNumCameras) { + // has = true; DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras, "mCameras","mNumCameras"); } - else if (pScene->mCameras) - { + else if (pScene->mCameras) { ReportError("aiScene::mCameras is non-null although there are no cameras"); } // validate all lights - if (pScene->mNumLights) - { - has = true; + if (pScene->mNumLights) { + // has = true; DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights, "mLights","mNumLights"); } - else if (pScene->mLights) - { + else if (pScene->mLights) { ReportError("aiScene::mLights is non-null although there are no lights"); } // validate all materials - if (pScene->mNumMaterials) - { - has = true; + if (pScene->mNumMaterials) { + // has = true; DoValidation(pScene->mMaterials,pScene->mNumMaterials,"mMaterials","mNumMaterials"); } - else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) - { - // NOTE: ScenePreprocessor generates a default material if none is there - // (and at least one mesh is found). So this should never be triggered ... +#if 0 + // NOTE: ScenePreprocessor generates a default material if none is there + else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { ReportError("aiScene::mNumMaterials is 0. At least one material must be there"); } - else if (pScene->mMaterials) - { +#endif + else if (pScene->mMaterials) { ReportError("aiScene::mMaterials is non-null although there are no materials"); } - if (!has)ReportError("The aiScene data structure is empty"); +// if (!has)ReportError("The aiScene data structure is empty"); DefaultLogger::get()->debug("ValidateDataStructureProcess end"); } @@ -312,8 +285,7 @@ void ValidateDSProcess::Validate( const aiLight* pLight) if (!pLight->mAttenuationConstant && !pLight->mAttenuationLinear && - !pLight->mAttenuationQuadratic) - { + !pLight->mAttenuationQuadratic) { ReportWarning("aiLight::mAttenuationXXX - all are zero"); } @@ -333,6 +305,8 @@ void ValidateDSProcess::Validate( const aiCamera* pCamera) if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear) ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear"); + // FIX: there are many 3ds files with invalid FOVs. No reason to + // reject them at all ... a warning is appropriate. if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI) ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV",pCamera->mHorizontalFOV); } @@ -341,10 +315,10 @@ void ValidateDSProcess::Validate( const aiCamera* pCamera) void ValidateDSProcess::Validate( const aiMesh* pMesh) { // validate the material index of the mesh - if (pMesh->mMaterialIndex >= this->mScene->mNumMaterials) + if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) { - this->ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)", - pMesh->mMaterialIndex,this->mScene->mNumMaterials-1); + ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)", + pMesh->mMaterialIndex,mScene->mNumMaterials-1); } for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) @@ -356,25 +330,25 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) switch (face.mNumIndices) { case 0: - this->ReportError("aiMesh::mFaces[%i].mNumIndices is 0",i); + ReportError("aiMesh::mFaces[%i].mNumIndices is 0",i); case 1: if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) { - this->ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimtiveTypes " + ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimtiveTypes " "does not report the POINT flag",i); } break; case 2: if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) { - this->ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimtiveTypes " + ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimtiveTypes " "does not report the LINE flag",i); } break; case 3: if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) { - this->ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimtiveTypes " + ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimtiveTypes " "does not report the TRIANGLE flag",i); } break; @@ -388,25 +362,23 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) }; } - if (!face.mIndices)this->ReportError("aiMesh::mFaces[%i].mIndices is NULL",i); + if (!face.mIndices) + ReportError("aiMesh::mFaces[%i].mIndices is NULL",i); } // positions must always be there ... - if (!pMesh->mNumVertices || !pMesh->mVertices && !mScene->mFlags) - { - this->ReportError("The mesh contains no vertices"); + if (!pMesh->mNumVertices || !pMesh->mVertices && !mScene->mFlags) { + ReportError("The mesh contains no vertices"); } // if tangents are there there must also be bitangent vectors ... - if ((pMesh->mTangents != NULL) != (pMesh->mBitangents != NULL)) - { - this->ReportError("If there are tangents there must also be bitangent vectors"); + if ((pMesh->mTangents != NULL) != (pMesh->mBitangents != NULL)) { + ReportError("If there are tangents there must also be bitangent vectors"); } // faces, too - if (!pMesh->mNumFaces || !pMesh->mFaces && !mScene->mFlags) - { - this->ReportError("The mesh contains no faces"); + if (!pMesh->mNumFaces || !pMesh->mFaces && !mScene->mFlags) { + ReportError("The mesh contains no faces"); } // now check whether the face indexing layout is correct: @@ -418,8 +390,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) aiFace& face = pMesh->mFaces[i]; for (unsigned int a = 0; a < face.mNumIndices;++a) { - if (face.mIndices[a] >= pMesh->mNumVertices) - { + if (face.mIndices[a] >= pMesh->mNumVertices) { ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a); } // the MSB flag is temporarily used by the extra verbose @@ -436,8 +407,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) // check whether there are vertices that aren't referenced by a face bool b = false; - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) - { + for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { if (!abRefList[i])b = true; } abRefList.clear(); @@ -495,7 +465,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) if (!pMesh->mBones[i]) { delete[] afSum; - this->ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)", + ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)", i,pMesh->mNumBones); } Validate(pMesh,pMesh->mBones[i],afSum); @@ -505,7 +475,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName) { delete[] afSum; - this->ReportError("aiMesh::mBones[%i] has the same name as " + ReportError("aiMesh::mBones[%i] has the same name as " "aiMesh::mBones[%i]",i,a); } } @@ -513,8 +483,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) // check whether all bone weights for a vertex sum to 1.0 ... for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) - { + if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) { ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]); } } @@ -532,21 +501,18 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh, { this->Validate(&pBone->mName); - if (!pBone->mNumWeights) - { - this->ReportError("aiBone::mNumWeights is zero"); + if (!pBone->mNumWeights) { + ReportError("aiBone::mNumWeights is zero"); } // check whether all vertices affected by this bone are valid for (unsigned int i = 0; i < pBone->mNumWeights;++i) { - if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) - { - this->ReportError("aiBone::mWeights[%i].mVertexId is out of range",i); + if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) { + ReportError("aiBone::mWeights[%i].mVertexId is out of range",i); } - else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) - { - this->ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value",i); + else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) { + ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value",i); } afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight; } @@ -555,27 +521,26 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh, // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) { - this->Validate(&pAnimation->mName); + Validate(&pAnimation->mName); // validate all materials - if (pAnimation->mNumChannels) + if (pAnimation->mNumChannels) { - if (!pAnimation->mChannels) - { - this->ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", + if (!pAnimation->mChannels) { + ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", pAnimation->mNumChannels); } for (unsigned int i = 0; i < pAnimation->mNumChannels;++i) { if (!pAnimation->mChannels[i]) { - this->ReportError("aiAnimation::mChannels[%i] is NULL (aiAnimation::mNumChannels is %i)", + ReportError("aiAnimation::mChannels[%i] is NULL (aiAnimation::mNumChannels is %i)", i, pAnimation->mNumChannels); } - this->Validate(pAnimation, pAnimation->mChannels[i]); + Validate(pAnimation, pAnimation->mChannels[i]); } } - else this->ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); + else ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); // Animation duration is allowed to be zero in cases where the anim contains only a single key frame. // if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero"); @@ -619,7 +584,6 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, case aiTextureType_HEIGHT: szType = "Height"; break; - default: break; }; @@ -746,8 +710,7 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) "aiMaterial::mProperties[%i].mData is 0",i,i); } // check all predefined types - if (aiPTI_String == prop->mType) - { + if (aiPTI_String == prop->mType) { // FIX: strings are now stored in a less expensive way ... if (prop->mDataLength < sizeof(size_t) + ((const aiString*)prop->mData)->length + 1) { ReportError("aiMaterial::mProperties[%i].mDataLength is " @@ -756,16 +719,14 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) } Validate((const aiString*)prop->mData); } - else if (aiPTI_Float == prop->mType) - { + else if (aiPTI_Float == prop->mType) { if (prop->mDataLength < sizeof(float)) { ReportError("aiMaterial::mProperties[%i].mDataLength is " "too small to contain a float (%i, needed: %i)", i,prop->mDataLength,sizeof(float)); } } - else if (aiPTI_Integer == prop->mType) - { + else if (aiPTI_Integer == prop->mType) { if (prop->mDataLength < sizeof(int)) { ReportError("aiMaterial::mProperties[%i].mDataLength is " "too small to contain an integer (%i, needed: %i)", @@ -822,29 +783,25 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) void ValidateDSProcess::Validate( const aiTexture* pTexture) { // the data section may NEVER be NULL - if (!pTexture->pcData) - { - this->ReportError("aiTexture::pcData is NULL"); + if (!pTexture->pcData) { + ReportError("aiTexture::pcData is NULL"); } if (pTexture->mHeight) { - if (!pTexture->mWidth)this->ReportError("aiTexture::mWidth is zero " + if (!pTexture->mWidth)ReportError("aiTexture::mWidth is zero " "(aiTexture::mHeight is %i, uncompressed texture)",pTexture->mHeight); } else { - if (!pTexture->mWidth)this->ReportError("aiTexture::mWidth is zero (compressed texture)"); - if ('.' == pTexture->achFormatHint[0]) - { - char szTemp[5]; - szTemp[0] = pTexture->achFormatHint[0]; - szTemp[1] = pTexture->achFormatHint[1]; - szTemp[2] = pTexture->achFormatHint[2]; - szTemp[3] = pTexture->achFormatHint[3]; - szTemp[4] = '\0'; - - this->ReportWarning("aiTexture::achFormatHint should contain a file extension " - "without a leading dot (format hint: %s).",szTemp); + if (!pTexture->mWidth) { + ReportError("aiTexture::mWidth is zero (compressed texture)"); + } + if ('\0' != pTexture->achFormatHint[3]) { + ReportWarning("aiTexture::achFormatHint must be zero-terminated"); + } + else if ('.' == pTexture->achFormatHint[0]) { + ReportWarning("aiTexture::achFormatHint should contain a file extension " + "without a leading dot (format hint: %s).",pTexture->achFormatHint); } } @@ -852,9 +809,8 @@ void ValidateDSProcess::Validate( const aiTexture* pTexture) if (sz[0] >= 'A' && sz[0] <= 'Z' || sz[1] >= 'A' && sz[1] <= 'Z' || sz[2] >= 'A' && sz[2] <= 'Z' || - sz[3] >= 'A' && sz[3] <= 'Z') - { - this->ReportError("aiTexture::achFormatHint contains non-lowercase characters"); + sz[3] >= 'A' && sz[3] <= 'Z') { + ReportError("aiTexture::achFormatHint contains non-lowercase characters"); } } @@ -864,6 +820,9 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, { Validate(&pNodeAnim->mNodeName); + if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) + ReportError("Empty node animation channel"); + // otherwise check whether one of the keys exceeds the total duration of the animation if (pNodeAnim->mNumPositionKeys) { @@ -875,7 +834,8 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, double dLast = -10e10; for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys;++i) { - if (pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration) + // ScenePreprocessor will compute the duration if still teh default value + if (-1. != pAnimation->mDuration && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration) { ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger " "than aiAnimation::mDuration (which is %.5f)",i, @@ -903,7 +863,7 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, double dLast = -10e10; for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys;++i) { - if (pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration) + if (-1. != pAnimation->mDuration && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration) { ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger " "than aiAnimation::mDuration (which is %.5f)",i, @@ -923,15 +883,14 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, // scaling keys if (pNodeAnim->mNumScalingKeys) { - if (!pNodeAnim->mScalingKeys) - { - this->ReportError("aiNodeAnim::mScalingKeys is NULL (aiNodeAnim::mNumScalingKeys is %i)", + if (!pNodeAnim->mScalingKeys) { + ReportError("aiNodeAnim::mScalingKeys is NULL (aiNodeAnim::mNumScalingKeys is %i)", pNodeAnim->mNumScalingKeys); } double dLast = -10e10; for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys;++i) { - if (pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration) + if (-1. != pAnimation->mDuration && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration) { ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger " "than aiAnimation::mDuration (which is %.5f)",i, @@ -992,13 +951,11 @@ void ValidateDSProcess::Validate( const aiNode* pNode) } if (pNode->mNumChildren) { - if (!pNode->mChildren) - { - this->ReportError("aiNode::mChildren is NULL (aiNode::mNumChildren is %i)", + if (!pNode->mChildren) { + ReportError("aiNode::mChildren is NULL (aiNode::mNumChildren is %i)", pNode->mNumChildren); } - for (unsigned int i = 0; i < pNode->mNumChildren;++i) - { + for (unsigned int i = 0; i < pNode->mNumChildren;++i) { Validate(pNode->mChildren[i]); } } diff --git a/code/ValidateDataStructure.h b/code/ValidateDataStructure.h index 5cacb03ed..7a8124c08 100644 --- a/code/ValidateDataStructure.h +++ b/code/ValidateDataStructure.h @@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines a post processing step to validate the loader's +/** @file Defines a (dummy) post processing step to validate the loader's * output data structure (for debugging) */ #ifndef AI_VALIDATEPROCESS_H_INC @@ -56,8 +56,7 @@ struct aiMaterial; struct aiNode; struct aiString; -namespace Assimp -{ +namespace Assimp { // --------------------------------------------------------------------------- /** Validates the ASSIMP data structure @@ -75,18 +74,9 @@ protected: public: // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ bool IsActive( unsigned int pFlags) const; // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * A process should throw an ImportErrorException* if it fails. - * @param pScene The imported data to work at. - */ void Execute( aiScene* pScene); protected: diff --git a/code/XFileImporter.cpp b/code/XFileImporter.cpp index 95f4d20fb..e634efd24 100644 --- a/code/XFileImporter.cpp +++ b/code/XFileImporter.cpp @@ -38,7 +38,9 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the XFile importer class */ +/** @file XFileImporter.cpp + * @brief Implementation of the XFile importer class + */ #include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_X_IMPORTER @@ -53,31 +55,35 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer XFileImporter::XFileImporter() -{ -} +{} // ------------------------------------------------------------------------------------------------ // Destructor, private as well XFileImporter::~XFileImporter() -{ -} +{} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const +bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - // simple check of file extension is enough for the moment - std::string::size_type pos = pFile.find_last_of( '.'); - // no file extension - can't read - if( pos == std::string::npos) - return false; - std::string extension = pFile.substr( pos); - if( extension == ".x" || extension == ".X") + std::string extension = GetExtension(pFile); + if(extension == "x") { return true; - + } + if (!extension.length() || checkSig) { + uint32_t token[1]; + token[0] = AI_MAKE_MAGIC("xof "); + return CheckMagicToken(pIOHandler,pFile,token,1,0); + } return false; } +// ------------------------------------------------------------------------------------------------ +void XFileImporter::GetExtensionList(std::string& append) +{ + append.append("*.x"); +} + // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) @@ -611,17 +617,13 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, const std::vector* newWeights = new std::vector[pcMesh->mNumBones]; - for (unsigned int i = 0;i < pcMesh->mNumBones;++i) - { + for (unsigned int i = 0;i < pcMesh->mNumBones;++i) { newWeights[i].reserve(pcMesh->mBones[i]->mNumWeights*3); } @@ -124,7 +123,7 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh) for (unsigned int a = 0; a< pcMesh->mNumFaces;++a) { aiFace* pcFace = &pcMesh->mFaces[a]; - for (unsigned int q = 0; q < 3;++q,++iIndex) + for (unsigned int q = 0; q < pcFace->mNumIndices;++q,++iIndex) { // need to build a clean list of bones, too for (unsigned int i = 0;i < pcMesh->mNumBones;++i) diff --git a/code/fast_atof.h b/code/fast_atof.h index 2511d229f..b7e36476e 100644 --- a/code/fast_atof.h +++ b/code/fast_atof.h @@ -165,11 +165,12 @@ inline unsigned int strtol_cppstyle( const char* in, const char** out=0) } // ------------------------------------------------------------------------------------ -// Special version of the function, providing higher accuracy +// Special version of the function, providing higher accuracy and security // It is mainly used bx fast_atof to prevent ugly integer overflows. // ------------------------------------------------------------------------------------ -inline uint64_t strtol10_64( const char* in, const char** out=0) +inline uint64_t strtol10_64( const char* in, const char** out=0, unsigned int* max_inout=0) { + unsigned int cur = 0; uint64_t value = 0; while ( 1 ) @@ -177,14 +178,36 @@ inline uint64_t strtol10_64( const char* in, const char** out=0) if ( *in < '0' || *in > '9' ) break; - value = ( value * 10 ) + ( *in - '0' ); + const uint64_t new_value = ( value * 10 ) + ( *in - '0' ); + + if (new_value < value) /* numeric overflow */ + return value; + + value = new_value; + ++in; + ++cur; + + if (max_inout && *max_inout == cur) { + + if (out) { /* skip to end */ + while (*in >= '0' && *in <= '9')++in; + *out = in; + } + + return value; + } } if (out) *out = in; + + if (max_inout) + *max_inout = cur; + return value; } +#define AI_FAST_ATOF_RELAVANT_DECIMALS 6 // ------------------------------------------------------------------------------------ //! Provides a fast function for converting a string into a float, @@ -216,15 +239,18 @@ inline const char* fast_atof_move( const char* c, float& out) // Casting to double seems to solve the problem. // strtol_64 is used to prevent integer overflow. - //float pl = (float)strtol(c, &t, 10); - double pl = (double) strtol10_64 ( c, &t ); - pl *= fast_atof_table[t-c]; + // Another fix: this tends to become 0 if we don't limit + // the maximum number of digits + unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS; + double pl = (double) strtol10_64 ( c, &t, &diff ); + + pl *= fast_atof_table[diff]; f += (float)pl; c = t; - // FIX: a large 'E' should be allowed, too + // FIX: a large 'E' should be allowed, too (occurs in some DXF files) if (*c == 'e' || *c == 'E') { ++c; diff --git a/code/makefile.mingw b/code/makefile.mingw index 6c685e727..e8aec53c2 100644 --- a/code/makefile.mingw +++ b/code/makefile.mingw @@ -1,4 +1,5 @@ +# --------------------------------------------------------------------------- # Makefile for Open Asset Import Library (MinGW32-make) # aramis_acg@users.sourceforge.net # - just a quick'n'dirty one, could be buggy ... @@ -15,6 +16,7 @@ # SINGLETHREADED=1 Build single-threaded library # DEBUG=1 Build debug build of library # +# --------------------------------------------------------------------------- # C++ object files OBJECTS := $(patsubst %.cpp,%.o, $(wildcard *.cpp)) @@ -60,7 +62,7 @@ ifeq ($(DEBUG),1) DEFINEFLAGS += -D_DEBUG -DDEBUG # NAMESUFFIX += -debug else - CPPFLAGS += -o3 + CPPFLAGS += -o3 -s DEFINEFLAGS += -DNDEBUG -D_NDEBUG endif diff --git a/code/qnan.h b/code/qnan.h index 3d3e7630d..fdebab6a9 100644 --- a/code/qnan.h +++ b/code/qnan.h @@ -1,9 +1,20 @@ +/** @file qnan.h + * @brief Some utilities for our dealings with qnans. + * + * @note Some loaders use qnans heavily to mark invalid values (and they're + * even returned by Gen(Smooth)Normals if normals are undefined for a + * primitive). Their whole usage is wrapped here, so you can easily + * fix issues with platforms with a different qnan implementation. + */ #if (!defined AI_QNAN_H_INCLUDED) #define AI_QNAN_H_INCLUDED -// Data structure for a 32 Bit IEEE 754 floating-point number +// --------------------------------------------------------------------------- +/** @brief Data structure for the bit pattern of a 32 Bit + * IEEE 754 floating-point number. + */ union _IEEESingle { float Float; @@ -16,25 +27,40 @@ union _IEEESingle } ; // --------------------------------------------------------------------------- -// check whether a float is NaN +/** @brief check whether a float is qNaN. + * @param in Input value + */ AI_FORCE_INLINE bool is_qnan(float in) { return (in != in); } // --------------------------------------------------------------------------- -// check whether a float is NOT NaN. +/** @brief check whether a float is NOT qNaN. + * @param in Input value + */ AI_FORCE_INLINE bool is_not_qnan(float in) { return (in == in); } // --------------------------------------------------------------------------- -// check whether a float is either NaN or (+/-) INF. Denorms return false, -// they're treated like normal values. +/** @brief check whether a float is either NaN or (+/-) INF. + * + * Denorms return false, they're treated like normal values. + * @param in Input value + */ AI_FORCE_INLINE bool is_special_float(float in) { return (((_IEEESingle*)&in)->IEEE.Exp == (1u << 8)-1); } +// --------------------------------------------------------------------------- +/** @brief Get a qnan + */ +AI_FORCE_INLINE float get_qnan() +{ + return std::numeric_limits::quiet_NaN(); +} + #endif // !! AI_QNAN_H_INCLUDED diff --git a/code/res/assimp.rc b/code/res/assimp.rc index 0bf5f111f..60ceaef3d 100644 --- a/code/res/assimp.rc +++ b/code/res/assimp.rc @@ -1,6 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "resource.h" +#include "..\..\mkutil\revision.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -32,8 +33,8 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN #if (!defined ASSIMP_JNI_EXPORT) VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,1 - PRODUCTVERSION 1,0,0,1 + FILEVERSION 1,0,SVNRevision, 0 + PRODUCTVERSION 1,0,SVNRevision,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,12 +52,13 @@ BEGIN VALUE "Comments", "Licensed under a 3-clause BSD license" VALUE "CompanyName", "ASSIMP Development Team" VALUE "FileDescription", "Open Asset Import Library" - VALUE "FileVersion", "1, 0, 0, 0" - VALUE "InternalName", "assimp" + VALUE "FileVersion", 1,0,SVNRevision,0 + VALUE "InternalName", "assimp " VALUE "LegalCopyright", "Copyright (C) 2008" VALUE "OriginalFilename", "assimpNN.dll" VALUE "ProductName", "Open Asset Import Library" - VALUE "ProductVersion", "1, 0, 0, 0" + VALUE "ProductVersion", 1,0,SVNRevision,0 + ,0 END END BLOCK "VarFileInfo" diff --git a/contrib/cppunit_note.txt b/contrib/cppunit_note.txt index 5953a1083..cf1e02608 100644 --- a/contrib/cppunit_note.txt +++ b/contrib/cppunit_note.txt @@ -3,5 +3,6 @@ This is a "slim" version of CPPunit. It contains everything we need, but nothing - Tools have been removed - x64-Build configs have been added - VC6 build & headers have been removed (Assimp can't be compiled with vc6) +- vc9 solution has been added, vc8 solution uses Assimp 'FastSTL' settings ---- Aramis \ No newline at end of file +--- Alex \ No newline at end of file diff --git a/contrib/zlib/compress.c b/contrib/zlib/compress.c new file mode 100644 index 000000000..df04f0148 --- /dev/null +++ b/contrib/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/contrib/zlib/deflate.c b/contrib/zlib/deflate.c new file mode 100644 index 000000000..29ce1f64a --- /dev/null +++ b/contrib/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/contrib/zlib/deflate.h b/contrib/zlib/deflate.h new file mode 100644 index 000000000..05a5ab3a2 --- /dev/null +++ b/contrib/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/contrib/zlib/trees.c b/contrib/zlib/trees.c new file mode 100644 index 000000000..395e4e168 --- /dev/null +++ b/contrib/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/contrib/zlib/trees.h b/contrib/zlib/trees.h new file mode 100644 index 000000000..72facf900 --- /dev/null +++ b/contrib/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/contrib/zlib_note.txt b/contrib/zlib_note.txt index f97c85be2..538f8011f 100644 --- a/contrib/zlib_note.txt +++ b/contrib/zlib_note.txt @@ -2,12 +2,10 @@ This is a heavily modified and shrinked version of zlib 1.2.3 - Removed comments from zlib.h - Removed gzip/zip archive I/O -- Removed Compression part - Removed infback.c - Added Assimp #idefs to exclude it if not needed - Disabled debug macros in zutil.h -All inflateNNN functions are available, for the rest you need to try. -If a function is needed but is not there, get zlib and add the -corresponding files to the repos. zlib is quite clean, it shouldn't -be too difficult to configure it to your needs. \ No newline at end of file +Assimp itself does not use the compression part yet, so +it needn't be compiled (trees.c, deflate.c, compress.c). +Currently these units are just used by assimp_cmd. \ No newline at end of file diff --git a/doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm b/doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm new file mode 100644 index 000000000..e45d7e7b1 Binary files /dev/null and b/doc/AssimpCmdDoc_Html/AssimpCmdDoc.chm differ diff --git a/doc/AssimpCmdDoc_Html/dragonsplash.png b/doc/AssimpCmdDoc_Html/dragonsplash.png new file mode 100644 index 000000000..d5ff70175 Binary files /dev/null and b/doc/AssimpCmdDoc_Html/dragonsplash.png differ diff --git a/doc/AssimpDoc_Html/AssimpDoc.chm b/doc/AssimpDoc_Html/AssimpDoc.chm new file mode 100644 index 000000000..5fd440f66 Binary files /dev/null and b/doc/AssimpDoc_Html/AssimpDoc.chm differ diff --git a/doc/lib_html/dragonsplash.png b/doc/AssimpDoc_Html/dragonsplash.png similarity index 100% rename from doc/lib_html/dragonsplash.png rename to doc/AssimpDoc_Html/dragonsplash.png diff --git a/doc/Doxyfile b/doc/Doxyfile index 6476a46bd..cc8d47200 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -574,7 +574,7 @@ WARN_LOGFILE = # with spaces. INPUT = ../include/ \ - ../doc/ + ../doc/dox.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -796,7 +796,7 @@ GENERATE_HTML = YES # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. -HTML_OUTPUT = lib_html +HTML_OUTPUT = AssimpDoc_Html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank diff --git a/doc/Doxyfile_Cmd b/doc/Doxyfile_Cmd new file mode 100644 index 000000000..71956901e --- /dev/null +++ b/doc/Doxyfile_Cmd @@ -0,0 +1,1540 @@ +# Doxyfile 1.5.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = AssimpCMD + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = r325 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class " \ + "The $name widget " \ + "The $name file " \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = YES + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = YES + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../doc/dox_cmd.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = ../include/BoostWorkaround + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */.svn/* \ + */.svn + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = AssimpCmdDoc_Html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = style.css + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = YES + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = AssimpCmdDoc.chm + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = "C:/Program Files/HTML Help Workshop/hhc.exe" + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = ASSIMP_DOXYGEN_BUILD=1 \ + __cplusplus + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = C_STRUCT \ + C_ENUM + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 1000 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/doc/dox_cmd.h b/doc/dox_cmd.h new file mode 100644 index 000000000..af0cbce9e --- /dev/null +++ b/doc/dox_cmd.h @@ -0,0 +1,427 @@ +/** @file dox_cmd.h + * @brief General documentation for assimp_cmd + */ + + +//---------------------------------------------------------------------------------------------- +// ASSIMP CMD MAINPAGE +/** +@mainpage ASSIMP Command-line tools + + + +@section intro Introduction + +This document describes the usage of assimp's command line tools. +This is *not* the SDK reference and programming-related stuff is not covered here. +

+NOTE: For simplicity, the following sections are written with Windows in mind. However +it's not different for Linux/Mac at all, except there's probably no assimp.exe ... + +@section basic_use Basic use + +Open a command prompt and navigate to the directory where assimp.exe resides. The basic command line is: + +@code +assimp [command] [parameters] +@endcode + +The following commands are available: + + + + + + + + + + + + + + + + + + + +
@link version version @endlinkRetrieve the current version of assimp
@link help help @endlinkGet a list of all commands (yes, it's this list ...)
@link dump dump @endlinkGenerate a human-readable text dump of a model
@link extract extract @endlinkExtract an embedded texture image
+ +If you use assimp's command line frequently, consider adding assimp to your PATH +environment. + + */ + + +/** +@page version 'version'-Command + + + */ + +/** +@page help 'help'-Command + + + */ + +//---------------------------------------------------------------------------------------------- +// ASSIMP DUMP + +/** +@page dump 'dump'-Command + +Generate a text or binary dump of a model. This is the core component of Assimp's internal +regression test suite but it could also be useful for other developers to quickly +examine the contents of a model. Note that text dumps are not intended to be used as +intermediate format, Assimp is not able to read them again, nor is the file format +stable or well-defined. It may change with every revision without notice. +Binary dumps (*.assfile) are backward- and forward-compatible. + +

Syntax:

+ +@code +assimp dump [] [-b] [-s] [common parameters] +@endcode + + +

Parameters:

+ +

+ +model

+Required. Relative or absolute path to the input model. A wildcard may be specified. +See the @link wildcard wildcards page @endlink for more information. +

+

+ +out

+Optional. Relative or absolute path to write the output dump to. If it is ommitted, +the dump is written to -dump.txt +

+ +

+-b
+

+Optional. If this switch is specified, the dumb is written in binary format. +The long form of this parameter is --binary. +

+ +

+-s
+

+Optional. If this switch is specified, the dumb is shortened to include only +min/max values for all vertex components and animation channels. The resulting +file is much smaller, but the original model can't be reconstructed from it. This is +used by Assimp's regression test suite,comapring those minidumps provides +a fast way to verify whether a loader works correctly or not. +The long form of this parameter is --short. +

+ +

+ +common parameters

+Optional. Import configuration & postprocessing. +See the @link common common parameters page @endlink for more information. +

+ +
+ +

Sample:

+ +@code +assimp dump test.3ds test.txt -l -cfull +assimp dump test.3ds test.txt -include-log -config=full +@endcode + +Dumps 'test.3ds' to 'test.txt' after executing full post-processing on tehe imported data. +The log output is included with the dump. + + +@code +assimp dump files\*.* +assimp dump files\*.* +@endcode + +Dumps all loadable model files in the 'files' subdir. The output dumps are named +-dump.txt. The log is not included. + */ + +//---------------------------------------------------------------------------------------------- +// ASSIMP EXTRACT + +/** +@page extract 'extract'-Command + +Extracts one or more embedded texture images from models. + +

Syntax:

+ +@code +assimp extract [] [-t] [-f] [-ba] [-s] [common parameters] +@endcode + + +

Parameters:

+ +

+ +model

+Required. Relative or absolute path to the input model. A wildcard may be specified. +See the @link wildcard wildcards page @endlink for more information. +

+

+ +out

+Optional. Relative or absolute path to write the output images to. If the file name is +ommitted the output images are named
+The suffix _img is appended to the file name if the -s switch is not specified +(where is the zero-based index of the texture in the model file).
+ +The output file format is determined from the given file extension. Supported +formats are BMP and TGA. If the file format can't be determined, +the value specified with the -f switch is taken. +
+Format settings are ignored for compressed embedded textures. They're always +written in their native file format (e.g. jpg). +

+ +

+-t
+

+Optional. Specifies the (zero-based) index of the embedded texture to be extracted from +the model. If this option is *not* specified all textures found are exported. +The long form of this parameter is --texture=. +

+ +

+-t
+

+Optional. Specifies whether output BMPs contain an alpha channel or not. +The long form of this parameter is --bmp-with-alpha=. +

+ + +

+-f
+

+Optional. Specifies the output file format. Supported +formats are BMP and TGA. The default value is BMP (if a full output filename is +specified, the output file format is taken from its extension, not from here). +The long form of this parameter is --format=. +

+ +

+-s
+

+Optional. Prevents the tool from adding the _img suffix to all filenames. This option +must be specified together with -t to ensure that just one image is written. +The long form of this parameter is --nosuffix. +

+ +

+ +common parameters

+Optional. Import configuration & postprocessing. Most postprocessing-steps don't affect +embedded texture images, configuring too much is probably senseless here. +See the @link common common parameters page @endlink for more information. +

+ +
+ +

Sample:

+ +@code +assimp extract test.mdl test.bmp --texture=0 --validate-data-structure +assimp extract test.mdl test.bmp -t=0 -vds +@endcode + +Extracts the first embedded texture (if any) from test.mdl after validating the +imported data structure and writes it to test_img0.bmp. + + +@code +assimp extract files\*.mdl *.bmp +assimp extract files\*.mdl *.bmp +@endcode + +Extracts all embedded textures from all loadable .mdl files in the 'files' subdirectory +and writes them to bitmaps which are named _img.bmp + */ + +//---------------------------------------------------------------------------------------------- +// ASSIMP COMMON PARAMETERS +/** +@page common Common parameters + +The parameters described on this page are commonly used by almost every assimp command. They +specify how the library will postprocess the imported data. This is done by several +configurable pipeline stages, called 'post processing steps'. Below you can find a list +of all supported steps along with short descriptions of what they're doing.
Programmers: +more information can be found in the aiPostProcess.h header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterLong parameterDescription
-ptv--pretransform-verticesMove all vertices into worldspace and collapse the scene graph. Animation data is lost. + This is intended for applications which don't support scenegraph-oriented rendering.
-gsn--gen-smooth-normalsComputes 'smooth' per-vertex normal vectors if necessary. Mutually exclusive with -gn
-gn--gen-normalsComputes 'hard' per-face normal vectors if necessary. Mutually exclusive with -gsn
-cts--calc-tangent-spaceIf one UV channel and normal vectors are given, compute tangents and bitangents
-jiv--join-identical-verticesOptimize the index buffer. If this flag is not specified all vertices are referenced once.
-rrm--remove-redundant-materialsRemove redundant materials from the imported data.
-fd--find-degeneratesFind and process degenerates primitives.
-slm--split-large-meshesSplit large meshes over a specific treshold in smaller sub meshes. The default vertex & face limit is 1000000
-lbw--limit-bone-weightsLimit the number of bones influencing a single vertex. The default limit is 4.
-vds--validate-data-structurePerforms a full validation of the imported data structure. Recommended to avoid crashes if + an import plugin produces rubbish
-icl--improve-cache-localityImprove the cache locality of the vertex buffer by reordering the index buffer + to achieve a lower ACMR (average post-transform vertex cache miss ratio)
-sbpt--sort-by-ptypeSplits meshes which consist of more than one kind of primitives (e.g. lines and triangles mixed up) + in 'clean' submeshes.
-lh--convert-to-lhConverts the imported data to left-handed coordinate space
-fuv--flip-uvFlip UV coordinates from upper-left origin to lower-left origin
-fwo--flip-winding-orderFlip face winding order from CCW to CW
-ett--evaluate-texture-transformEvaluate per-texture UV transformations (e.g scaling, offset) and build pretransformed UV channels
-guv--gen-uvcoordsReplace abstract mapping descriptions, such as 'spherical' or 'cylindrical' with proper UV channels
-fixn--fix-normalsRun a heuristic algorithm to detect meshes with wrong face winding order/normals.
-tri--triangulateTriangulate poylgons with 4 and more points. Lines, points and triangles are not affected.
-fi--find-instancesSearch the data structure for instanced meshes and replace them by references. This can + reduce vertex/face counts but the postprocessing-step takes some time.
+ +For convenience some default postprocessing configurations are provided. +The corresponding command line parameter is -c (or --config=). + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionList of steps executed
fastFast post processing config, performs some essential optimizations and computes tangents-cts, -gn, -jiv, -tri, -guv, -sbpt
defaultBalanced post processing config, performs most optimizations-cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv
fullFull post processing. May take a while, but results in best output quality for most purposes-cts, -gsn, -jiv, -icl, -lbw, -rrm, -slm, -tri, -guv, -sbpt, -fd, -fiv, -fi, -vds
+ +There are also some common flags to specify Assimp's logging behaviour: + + + + + + + + + + + + + + + + + + + +
NameDescription
-l or --show-logShow log file on console window (stderr)
-lo or --log-out=Streams the log to
-v or --verboseEnables verbose logging. Debug messages will be produced, too. This will + decrease loading performance and might result in *very* long logs ...
+ */ diff --git a/doc/lib_html/AssimpDoc.chm b/doc/lib_html/AssimpDoc.chm deleted file mode 100644 index 4306657c8..000000000 Binary files a/doc/lib_html/AssimpDoc.chm and /dev/null differ diff --git a/doc/style.css b/doc/style.css index 7a1c00bc7..4412c73df 100644 --- a/doc/style.css +++ b/doc/style.css @@ -8,6 +8,7 @@ body, table, div, p, dl { h1 { text-align: center; font-size: 150%; + color: black; } h2 { @@ -125,7 +126,7 @@ div.groupText { body { background: white; - color: black; + color: #333333; margin-right: 20px; margin-left: 20px; } diff --git a/include/BoostWorkaround/boost/static_assert.hpp b/include/BoostWorkaround/boost/static_assert.hpp index 4326c240d..f97971f80 100644 --- a/include/BoostWorkaround/boost/static_assert.hpp +++ b/include/BoostWorkaround/boost/static_assert.hpp @@ -17,4 +17,4 @@ namespace boost { {boost::detail::static_assertion_failure<(eval)> assert_dummy;assert_dummy;} #endif -#endif // !! AI_BOOST_STATIC_ASSERT_INCLUDED \ No newline at end of file +#endif // !! AI_BOOST_STATIC_ASSERT_INCLUDED diff --git a/include/DefaultLogger.h b/include/DefaultLogger.h index ede298623..eeee24181 100644 --- a/include/DefaultLogger.h +++ b/include/DefaultLogger.h @@ -54,7 +54,7 @@ namespace Assimp { class IOStream; struct LogStreamInfo; -//! Default log file +//! Default log file name #define ASSIMP_DEFAULT_LOG_NAME "AssimpLog.txt" // ------------------------------------------------------------------------------------ @@ -111,17 +111,13 @@ public: /** @brief Will kill the singleton instance and setup a NullLogger as logger */ static void kill(); - - - /** @brief Severity setter */ - /* override */ void setLogSeverity(LogSeverity log_severity); /** @brief Attach a stream to the logger. */ - /* override */ void attachStream(LogStream *pStream, + /* override */ bool attachStream(LogStream *pStream, unsigned int severity); /** @brief Detach a still attached stream from logger */ - /* override */ void detatchStream(LogStream *pStream, + /* override */ bool detatchStream(LogStream *pStream, unsigned int severity); private: @@ -165,8 +161,6 @@ private: static Logger *m_pLogger; static NullLogger s_pNullLogger; - //! Logger severity - LogSeverity m_Severity; //! Attached streams StreamArray m_StreamArray; diff --git a/include/Logger.h b/include/Logger.h index 48ac91da0..45dff2cc0 100644 --- a/include/Logger.h +++ b/include/Logger.h @@ -50,6 +50,9 @@ namespace Assimp { class LogStream; +// maximum length of a log message. Longer messages are rejected. +#define MAX_LOG_MESSAGE_LENGTH 1024u + // ---------------------------------------------------------------------------------- /** @class Logger * @brief Abstract interface for logger implementations. @@ -85,11 +88,8 @@ public: ERR = 8 //!< Error log message }; - /** @brief Maximum length for log messages - */ - static const size_t MAX_LOG_MESSAGE_LENGTH = 1024; - public: + /** @brief Virtual destructor */ virtual ~Logger(); @@ -99,24 +99,28 @@ public: void debug(const std::string &message); /** @brief Writes a info message - * @param message Info message + * @param message Info message */ void info(const std::string &message); /** @brief Writes a warning message - * @param message Warn message + * @param message Warn message */ void warn(const std::string &message); /** @brief Writes an error message - * @param message Error message + * @param message Error message */ void error(const std::string &message); /** @brief Set a new log severity. - * @param log_severity New severity for logging + * @param log_severity New severity for logging */ - virtual void setLogSeverity(LogSeverity log_severity) = 0; + void setLogSeverity(LogSeverity log_severity); + + /** @brief Get the current log severity + */ + LogSeverity getLogSeverity() const; /** @brief Attach a new logstream * @@ -128,8 +132,9 @@ public: * @param severity Message filter, specified which types of log * messages are dispatched to the stream. Provide a bitwise * combination of the ErrorSeverity flags. + * @return true if the stream has been attached, false otherwise. */ - virtual void attachStream(LogStream *pStream, + virtual bool attachStream(LogStream *pStream, unsigned int severity = DEBUGGING | ERR | WARN | INFO) = 0; /** @brief Detach a still attached stream from the logger (or @@ -139,14 +144,19 @@ public: * flags. This value is &~ed with the current flags of the stream, * if the result is 0 the stream is detached from the Logger and * the caller retakes the possession of the stream. + * @return true if the stream has been dettached, false otherwise. */ - virtual void detatchStream(LogStream *pStream, + virtual bool detatchStream(LogStream *pStream, unsigned int severity = DEBUGGING | ERR | WARN | INFO) = 0; protected: - /** @brief Default constructor */ + + /** Default constructor */ Logger(); + /** Construction with a given log severity */ + Logger(LogSeverity severity); + /** @brief Called as a request to write a specific debug message * @param message Debug message. Never longer than * MAX_LOG_MESSAGE_LENGTH characters (exluding the '0'). @@ -178,21 +188,43 @@ protected: * the function is left. */ virtual void OnError(const char* message) = 0; + +protected: + + //! Logger severity + LogSeverity m_Severity; }; // ---------------------------------------------------------------------------------- // Default constructor -inline Logger::Logger() -{ - // empty +inline Logger::Logger() { + setLogSeverity(NORMAL); } // ---------------------------------------------------------------------------------- // Virtual destructor inline Logger::~Logger() { - // empty } + +// ---------------------------------------------------------------------------------- +// Construction with given logging severity +inline Logger::Logger(LogSeverity severity) { + setLogSeverity(severity); +} + +// ---------------------------------------------------------------------------------- +// Log severity setter +inline void Logger::setLogSeverity(LogSeverity log_severity){ + m_Severity = log_severity; +} + +// ---------------------------------------------------------------------------------- +// Log severity getter +inline Logger::LogSeverity Logger::getLogSeverity() const { + return m_Severity; +} + // ---------------------------------------------------------------------------------- } // Namespace Assimp diff --git a/include/NullLogger.h b/include/NullLogger.h index ddeca4fc2..0ef19f841 100644 --- a/include/NullLogger.h +++ b/include/NullLogger.h @@ -58,6 +58,7 @@ namespace Assimp { class ASSIMP_API NullLogger : public Logger { public: + /** @brief Logs a debug message */ void OnDebug(const char* message) { (void)message; //this avoids compiler warnings @@ -78,20 +79,19 @@ public: (void)message; //this avoids compiler warnings } - /** @brief Log severity setter */ - void setLogSeverity(LogSeverity log_severity) { - (void)log_severity; //this avoids compiler warnings + /** @brief Detach a still attached stream from logger */ + bool attachStream(LogStream *pStream, unsigned int severity) { + (void)pStream; (void)severity; //this avoids compiler warnings + return false; } /** @brief Detach a still attached stream from logger */ - void attachStream(LogStream *pStream, unsigned int severity) { + bool detatchStream(LogStream *pStream, unsigned int severity) { (void)pStream; (void)severity; //this avoids compiler warnings + return false; } - /** @brief Detach a still attached stream from logger */ - void detatchStream(LogStream *pStream, unsigned int severity) { - (void)pStream; (void)severity; //this avoids compiler warnings - } +private: }; } diff --git a/include/aiAnim.h b/include/aiAnim.h index a53710874..4084e711f 100644 --- a/include/aiAnim.h +++ b/include/aiAnim.h @@ -57,29 +57,42 @@ extern "C" { /** A time-value pair specifying a certain 3D vector for the given time. */ struct aiVectorKey { - double mTime; ///< The time of this key - C_STRUCT aiVector3D mValue; ///< The value of this key + //! The time of this key + double mTime; + //! The value of this key + C_STRUCT aiVector3D mValue; #ifdef __cplusplus + + //! Default constructor + aiVectorKey(){} + + //! Construction from a given time and key value + aiVectorKey(double time, const aiVector3D& value) + : mTime (time) + , mValue (value) + {} + + typedef aiVector3D elem_type; - // time is not compared - bool operator == (const aiVectorKey& o) const - {return o.mValue == this->mValue;} - - bool operator != (const aiVectorKey& o) const - {return o.mValue != this->mValue;} - - - - // Only time is compared. This operator is defined - // for use with std::sort - bool operator < (const aiVectorKey& o) const - {return mTime < o.mTime;} - - bool operator > (const aiVectorKey& o) const - {return mTime > o.mTime;} + //! Comparison operators. Just the key value is compared + //! For use with std::find(); + bool operator == (const aiVectorKey& o) const { + return o.mValue == this->mValue; + } + bool operator != (const aiVectorKey& o) const { + return o.mValue != this->mValue; + } + //! Relational operators. Just the key time is compared + //! For use with std::sort(); + bool operator < (const aiVectorKey& o) const { + return mTime < o.mTime; + } + bool operator > (const aiVectorKey& o) const { + return mTime > o.mTime; + } #endif }; @@ -89,28 +102,41 @@ struct aiVectorKey */ struct aiQuatKey { - double mTime; ///< The time of this key - C_STRUCT aiQuaternion mValue; ///< The value of this key + //! The time of this key + double mTime; + //! The value of this key + C_STRUCT aiQuaternion mValue; #ifdef __cplusplus + + //! Default constructor + aiQuatKey(){} + + //! Construction from a given time and key value + aiQuatKey(double time, const aiQuaternion& value) + : mTime (time) + , mValue (value) + {} + typedef aiQuaternion elem_type; - // time is not compared - bool operator == (const aiQuatKey& o) const - {return o.mValue == this->mValue;} - - bool operator != (const aiQuatKey& o) const - {return o.mValue != this->mValue;} - - - // Only time is compared. This operator is defined - // for use with std::sort - bool operator < (const aiQuatKey& o) const - {return mTime < o.mTime;} - - bool operator > (const aiQuatKey& o) const - {return mTime < o.mTime;} + //! Comparison operators. Just the key value is compared + //! For use with std::find(); + bool operator == (const aiQuatKey& o) const { + return o.mValue == this->mValue; + } + bool operator != (const aiQuatKey& o) const { + return o.mValue != this->mValue; + } + //! Relational operators. Just the key time is compared + //! For use with std::sort(); + bool operator < (const aiQuatKey& o) const { + return mTime < o.mTime; + } + bool operator > (const aiQuatKey& o) const { + return mTime > o.mTime; + } #endif }; @@ -314,7 +340,8 @@ struct Interpolator /** @brief Get the result of the interpolation between a,b. * * The interpolation algorithm depends on the type of the operands. - * aiVectorKey LERPs, aiQuatKey SLERPs. Any other type lerps, too. + * aiQuaternion's and aiQuatKey's SLERP, the rest does a simple + * linear interpolation. */ void operator () (T& out,const T& a, const T& b, float d) const { out = a + (b-a)*d; @@ -354,5 +381,8 @@ struct Interpolator { //! @endcond } // ! end namespace Assimp + + + #endif // __cplusplus #endif // AI_ANIM_H_INC diff --git a/include/aiCamera.h b/include/aiCamera.h index fa6d7bfa6..52745fedd 100644 --- a/include/aiCamera.h +++ b/include/aiCamera.h @@ -152,7 +152,7 @@ struct aiCamera /** Distance of the far clipping plane from the camera. * * The far clipping plane must, of course, be farer away than the - * near clipping plane. The default value is 1000.f. The radio + * near clipping plane. The default value is 1000.f. The ratio * between the near and the far plane should not be too * large (between 1000-10000 should be ok) to avoid floating-point * inaccuracies which could lead to z-fighting. diff --git a/include/aiConfig.h b/include/aiConfig.h index ffd9d66c2..c49f1c9bd 100644 --- a/include/aiConfig.h +++ b/include/aiConfig.h @@ -43,14 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Defines constants for configurable properties for the library * * Typically these properties are set via - * #Importer::SetPropertyFloat, - * #Importer::SetPropertyInteger or - * #Importer::SetPropertyString, + * #Assimp::Importer::SetPropertyFloat, + * #Assimp::Importer::SetPropertyInteger or + * #Assimp::Importer::SetPropertyString, * depending on the data type of a property. All properties have a * default value. See the doc for the mentioned methods for more details. * - * @note - * The functions for use with the plain-c API are: + *

+ * The corresponding functions for use with the plain-c API are: * #aiSetImportPropertyInteger, * #aiSetImportPropertyFloat, * #aiSetImportPropertyString @@ -63,34 +63,66 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This is used by the "SplitLargeMeshes" PostProcess-Step to determine * whether a mesh must be split or not. - * @note The default value is AI_SLM_DEFAULT_MAX_VERTICES, defined in - * the internal header file SplitLargeMeshes.h + * @note The default value is AI_SLM_DEFAULT_MAX_VERTICES * Property type: integer. */ -#define AI_CONFIG_PP_SLM_TRIANGLE_LIMIT "pp.slm.triangle_limit" +#define AI_CONFIG_PP_SLM_TRIANGLE_LIMIT \ + "PP_SLM_TRIANGLE_LIMIT" +// default value for AI_CONFIG_PP_SLM_TRIANGLE_LIMIT +#if (!defined AI_SLM_DEFAULT_MAX_TRIANGLES) +# define AI_SLM_DEFAULT_MAX_TRIANGLES 1000000 +#endif // --------------------------------------------------------------------------- /** @brief Set the maximum number of triangles in a mesh. * * This is used by the "SplitLargeMeshes" PostProcess-Step to determine * whether a mesh must be split or not. - * @note The default value is AI_SLM_DEFAULT_MAX_TRIANGLES, defined in - * the internal header file SplitLargeMeshes.h + * @note The default value is AI_SLM_DEFAULT_MAX_TRIANGLES * Property type: integer. */ -#define AI_CONFIG_PP_SLM_VERTEX_LIMIT "pp.slm.vertex_limit" +#define AI_CONFIG_PP_SLM_VERTEX_LIMIT \ + "PP_SLM_VERTEX_LIMIT" +// default value for AI_CONFIG_PP_SLM_VERTEX_LIMIT +#if (!defined AI_SLM_DEFAULT_MAX_VERTICES) +# define AI_SLM_DEFAULT_MAX_VERTICES 1000000 +#endif // --------------------------------------------------------------------------- /** @brief Set the maximum number of bones affecting a single vertex * - * This is used by the aiProcess_LimitBoneWeights PostProcess-Step. - * @note The default value is AI_LBW_MAX_WEIGHTS, defined in - * the internal header file LimitBoneWeightsProcess.h + * This is used by the #aiProcess_LimitBoneWeights PostProcess-Step. + * @note The default value is AI_LBW_MAX_WEIGHTS * Property type: integer. */ -#define AI_CONFIG_PP_LBW_MAX_WEIGHTS "pp.lbw.weights_limit" +#define AI_CONFIG_PP_LBW_MAX_WEIGHTS \ + "PP_LBW_MAX_WEIGHTS" + +// default value for AI_CONFIG_PP_LBW_MAX_WEIGHTS +#if (!defined AI_LMW_MAX_WEIGHTS) +# define AI_LMW_MAX_WEIGHTS 0x4 +#endif // !! AI_LMW_MAX_WEIGHTS + +/** @brief Default value for the #AI_CONFIG_PP_ICL_PTCACHE_SIZE property + */ +#ifndef PP_ICL_PTCACHE_SIZE +# define PP_ICL_PTCACHE_SIZE 12 +#endif + +// --------------------------------------------------------------------------- +/** @brief Set the size of the post-transform vertex cache to optimize the + * vertices for. This configures the #aiProcess_ImproveCacheLocality step. + * + * The size is given in vertices. Of course you can't know how the vertex + * format will exactly look like after the import returns, but you can still + * guess what your meshes will probably have. + * @note The default value is #PP_ICL_PTCACHE_SIZE. That results in slight + * performance improvements for most nVidia/AMD cards since 2002. + * Property type: integer. + */ +#define AI_CONFIG_PP_ICL_PTCACHE_SIZE "PP_ICL_PTCACHE_SIZE" // --------------------------------------------------------------------------- @@ -106,15 +138,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * want to override the global setting). * Property type: integer. */ -#define AI_CONFIG_IMPORT_GLOBAL_KEYFRAME "imp.global.kf" - -#define AI_CONFIG_IMPORT_MD3_KEYFRAME "imp.md3.kf" -#define AI_CONFIG_IMPORT_MD2_KEYFRAME "imp.md2.kf" -#define AI_CONFIG_IMPORT_MDL_KEYFRAME "imp.mdl.kf" -#define AI_CONFIG_IMPORT_MDC_KEYFRAME "imp.mdc.kf" -#define AI_CONFIG_IMPORT_MDR_KEYFRAME "imp.mdr.kf" -#define AI_CONFIG_IMPORT_SMD_KEYFRAME "imp.smd.kf" +#define AI_CONFIG_IMPORT_GLOBAL_KEYFRAME "IMPORT_GLOBAL_KEYFRAME" +#define AI_CONFIG_IMPORT_MD3_KEYFRAME "IMPORT_MD3_KEYFRAME" +#define AI_CONFIG_IMPORT_MD2_KEYFRAME "IMPORT_MD2_KEYFRAME" +#define AI_CONFIG_IMPORT_MDL_KEYFRAME "IMPORT_MDL_KEYFRAME" +#define AI_CONFIG_IMPORT_MDC_KEYFRAME "IMPORT_MDC_KEYFRAME" +#define AI_CONFIG_IMPORT_SMD_KEYFRAME "IMPORT_SMD_KEYFRAME" +#define AI_CONFIG_IMPORT_UNREAL_KEYFRAME "IMPORT_UNREAL_KEYFRAME" // --------------------------------------------------------------------------- @@ -123,8 +154,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Property type: integer (0: false; !0: true). Default value: true. */ -#define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL "imp.ac.sepbfcull" +#define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL \ + "IMPORT_AC_SEPARATE_BFCULL" +// --------------------------------------------------------------------------- +/** @brief Configures the UNREAL 3D loader to separate faces with different + * surface flags (e.g. two-sided vs. single-sided). + * + * Property type: integer (0: false; !0: true). Default value: true. + */ +#define AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS \ + "UNREAL_HANDLE_FLAGS" + +// --------------------------------------------------------------------------- +/** @brief Configures the terragen import plugin to compute uv's for + * terrains, if not given. Furthermore a default texture is assigned. + * + * UV coordinates for terrains are so simple to compute that you'll usually + * want to compute them on your own, if you need them. This option is intended + * for model viewers which want to offer an easy way to apply textures to + * terrains. + * Property type: integer (0: false; !0: true). Default value: false. + */ +#define AI_CONFIG_IMPORT_TER_MAKE_UVS \ + "IMPORT_TER_MAKE_UVS" // --------------------------------------------------------------------------- /** @brief Configures the ASE loader to always reconstruct normal vectors @@ -133,8 +186,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Many ASE files have invalid normals (they're not orthonormal). * Property type: integer (0: false; !0: true). Default value: true. */ -#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS "imp.ase.reconn" - +#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS \ + "IMPORT_ASE_RECONSTRUCT_NORMALS" // --------------------------------------------------------------------------- /** @brief Configures the M3D loader to process multi-part player models. @@ -177,7 +230,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_CONFIG_IMPORT_MD3_SHADER_SRC \ "IMPORT_MD3_SHADER_SRC" - // --------------------------------------------------------------------------- /** @brief Configures the LWO loader to load just one layer from the model. * @@ -186,11 +238,34 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * the name of the layer - or an integer - the index of the layer. If the * property is not set the whole LWO model is loaded. Loading fails if the * requested layer is not available. The layer index is zero-based and the - * layer name may not be empty. + * layer name may not be empty.
+ * Property type: Integer. Default value: all layers are loaded. */ -#define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY "imp.lwo.layer" +#define AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY \ + "IMPORT_LWO_ONE_LAYER_ONLY" +// --------------------------------------------------------------------------- +/** @brief Defines the begin of the time range for which the LWS loader + * evaluates animations and computes aiNodeAnim's. + * + * Assimp provides full conversion of LightWave's envelope system, including + * pre and post conditions. The loader computes linearly subsampled animation + * chanels with the frame rate given in the LWS file. This property defines + * the start time. Note: animation channels are only generated if a node + * has at least one envelope with more tan one key assigned. This property. + * is given in frames, '0' is the first frame. By default, if this property + * is not set, the importer takes the animation start from the input LWS + * file ('FirstFrame' line)
+ * Property type: Integer. Default value: taken from file. + * + * @see AI_CONFIG_IMPORT_LWS_ANIM_END - end of the imported time range + */ +#define AI_CONFIG_IMPORT_LWS_ANIM_START \ + "IMPORT_LWS_ANIM_START" +#define AI_CONFIG_IMPORT_LWS_ANIM_END \ + "IMPORT_LWS_ANIM_END" + // --------------------------------------------------------------------------- /** @brief Defines the output frame rate of the IRR loader. * @@ -199,8 +274,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * are returned by the converter.
* Property type: integer. Default value: 100 */ -#define AI_CONFIG_IMPORT_IRR_ANIM_FPS "imp.irr.fps" - +#define AI_CONFIG_IMPORT_IRR_ANIM_FPS \ + "IMPORT_IRR_ANIM_FPS" // --------------------------------------------------------------------------- /** @brief Specifies the maximum angle that may be between two vertex tangents @@ -211,7 +286,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 45 degrees. The maximum value is 175. * Property type: float. */ -#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE "pp.ct.max_smoothing" +#define AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE \ + "PP_CT_MAX_SMOOTHING_ANGLE" // --------------------------------------------------------------------------- /** @brief Specifies the maximum angle that may be between two face normals @@ -225,32 +301,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * performance is unaffected if the AI_CONFIG_FAVOUR_SPEED flag is set, but * the output quality may be reduced. */ -#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE "pp.gsn.max_smoothing" - - -// --------------------------------------------------------------------------- -/** @brief Specifies the minimum number of faces a node should have. - * This is an input parameter to the OptimizeGraph-Step. - * - * Nodes whose referenced meshes have less faces than this value - * are probably joined with neighbors with identical local matrices. - * However, it is just a hint to the step. - * Property type: integer - */ -#define AI_CONFIG_PP_OG_MIN_NUM_FACES "pp.og.min_faces" - - -// --------------------------------------------------------------------------- -/** @brief Specifies whether the OptimizeGraphProcess joins nodes even if - * their local transformations are not equal. - * - * By default, nodes with different local transformations are never joined. - * The intention is that all vertices should remain in their original - * local coordinate space where they are correctly centered and aligned, - * which could also allow for significant culling improvements. - */ -#define AI_CONFIG_PP_OG_JOIN_INEQUAL_TRANSFORMS "pp.og.allow_diffwm" - +#define AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE \ + "PP_GSN_MAX_SMOOTHING_ANGLE" // --------------------------------------------------------------------------- /** @brief Sets the colormap (= palette) to be used to decode embedded @@ -262,8 +314,72 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * a default palette (from Quake 1) is used. * Property type: string. */ -#define AI_CONFIG_IMPORT_MDL_COLORMAP "imp.mdl.color_map" +#define AI_CONFIG_IMPORT_MDL_COLORMAP \ + "IMPORT_MDL_COLORMAP" +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_RemoveRedundantMaterials step to + * keep materials matching a name in a given list. + * + * This is a list of 1 to n strings, ' ' serves as delimiter character. + * Identifiers containing whitespaces must be enclosed in *single* + * quotation marks. For example: + * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'". + * If a material matches on of these names, it will not be modified or + * removed by the postprocessing step nor will other materials be replaced + * by a reference to it.
+ * This option might be useful if you are using some magic material names + * to pass additional semantics through the content pipeline. This ensures + * they won't be optimized away, but a general optimization is still + * performed for materials not contained in the list. + * Property type: String. Default value: n/a + * @note Linefeeds, tabs or carriage returns are treated as whitespace. + * Material names are case sensitive. + */ +#define AI_CONFIG_PP_RRM_EXCLUDE_LIST \ + "PP_RRM_EXCLUDE_LIST" + +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_PretransformVertices step to + * keep the scene hierarchy. Meshes are moved to worldspace, but + * no optimization is performed (means: meshes are not joined. The total + * number of meshes won't change). + * + * This option could be of use for you if the scene hierarchy contains + * important additional information which you want to interpret. + * For rendering, you can still render all meshes in the scene without + * any transformations. + * Property type: integer (0: false; !0: true). Default value: false. + */ +#define AI_CONFIG_PP_PTV_KEEP_HIERARCHY \ + "PP_PTV_KEEP_HIERARCHY" + +// --------------------------------------------------------------------------- +/** @brief Configures the #aiProcess_FindDegenerates step to + * remove degenerated primitives from the import - immediately. + * + * The default behaviour converts degenerated triangles to lines and + * degenerated lines to points. See the documentation to the + * #aiProcess_FindDegenerates step for a detailed example of the various ways + * to get rid of these lines and points if you don't want them. + * Property type: integer (0: false; !0: true). Default value: false. + */ +#define AI_CONFIG_PP_FD_REMOVE \ + "PP_FD_REMOVE" + +#if 0 +// --------------------------------------------------------------------------- +/** @brief Specifies the shape of the scene returned by the CSM format loader. + * + * If this property is set to 1, the loader tries to build a hierarchy from + * the capture points laoded from the file. A dummy mesh representing the + * recorded human is build. Otherwise, no meshes are returned, there's just + * a single root node with several children. These children represent the + * capture points, their translation channel is absolute. + * Property type: integer. Default value: 1 + */ +#define AI_CONFIG_IMPORT_CSM_BUILD_HIERARCHY "imp.csm.mkhier" +#endif // --------------------------------------------------------------------------- /** @brief Enumerates components of the aiScene and aiMesh data structures @@ -342,7 +458,8 @@ enum aiComponent * of the flags defined above) the import FAILS. Mainly because there is * no data to work on anymore ... */ -#define AI_CONFIG_PP_RVC_FLAGS "pp.rvc.flags" +#define AI_CONFIG_PP_RVC_FLAGS \ + "PP_RVC_FLAGS" // --------------------------------------------------------------------------- /** @brief Input parameter to the #aiProcess_SortByPType step: @@ -353,7 +470,8 @@ enum aiComponent * be to exclude all line and point meshes from the import. This * is an integer property, its default value is 0. */ -#define AI_CONFIG_PP_SBP_REMOVE "pp.sbp.remove" +#define AI_CONFIG_PP_SBP_REMOVE \ + "PP_SBP_REMOVE" // TransformUVCoords evaluates UV scalings @@ -376,7 +494,8 @@ enum aiComponent * property, of course). By default all transformations are enabled * (AI_UVTRAFO_ALL). */ -#define AI_CONFIG_PP_TUV_EVALUATE "pp.tuv.process" +#define AI_CONFIG_PP_TUV_EVALUATE \ + "PP_TUV_EVALUATE" // --------------------------------------------------------------------------- @@ -388,5 +507,7 @@ enum aiComponent * This property is expected to be an integer, != 0 stands for true. * The default value is 0. */ -#define AI_CONFIG_FAVOUR_SPEED "imp.speed_flag" +#define AI_CONFIG_FAVOUR_SPEED \ + "FAVOUR_SPEED" + #endif // !! AI_CONFIG_H_INC diff --git a/include/aiDefines.h b/include/aiDefines.h index cfab02a3a..773a789ce 100644 --- a/include/aiDefines.h +++ b/include/aiDefines.h @@ -190,6 +190,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define AI_C_THREADSAFE #endif // !! ASSIMP_BUILD_SINGLETHREADED + #if (defined _DEBUG || defined DEBUG) // one of the two should be defined .. # define ASSIMP_BUILD_DEBUG #endif diff --git a/include/aiLight.h b/include/aiLight.h index 4da3c61b8..b610f4d9b 100644 --- a/include/aiLight.h +++ b/include/aiLight.h @@ -134,6 +134,7 @@ struct aiLight * Atten = 1/( att0 + att1 * d + att2 * d*d) * @endcode * This member corresponds to the att0 variable in the equation. + * Naturally undefined for directional lights. */ float mAttenuationConstant; @@ -145,6 +146,7 @@ struct aiLight * Atten = 1/( att0 + att1 * d + att2 * d*d) * @endcode * This member corresponds to the att1 variable in the equation. + * Naturally undefined for directional lights. */ float mAttenuationLinear; @@ -156,6 +158,7 @@ struct aiLight * Atten = 1/( att0 + att1 * d + att2 * d*d) * @endcode * This member corresponds to the att2 variable in the equation. + * Naturally undefined for directional lights. */ float mAttenuationQuadratic; diff --git a/include/aiMaterial.h b/include/aiMaterial.h index fe4d1604d..232ef88c0 100644 --- a/include/aiMaterial.h +++ b/include/aiMaterial.h @@ -52,8 +52,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #endif -// Name for the default material -#define AI_DEFAULT_MATERIAL_NAME "aiDefaultMat" +// Name for default materials (2nd is used if meshes have UV coords) +#define AI_DEFAULT_MATERIAL_NAME "DefaultMaterial" +#define AI_DEFAULT_TEXTURED_MATERIAL_NAME "TexturedDefaultMaterial" // --------------------------------------------------------------------------- /** @brief A very primitive RTTI system to store the data type of a @@ -577,7 +578,7 @@ struct aiUVTransform * ~ * A temporary property for internal use. If someone forgets to * cleanup, some of these might still be contained in the output. - * Don't complain, if you understood what the first paragraph tried + * Don't complain! If you understood what the first paragraph tried * to tell you, you wouldn't even know. * @endcode * @see aiMaterial @@ -1475,7 +1476,6 @@ extern "C" { */ #define AI_MATKEY_GLOBAL_BACKGROUND_IMAGE "$global.bg.image2d",0,0 - // --------------------------------------------------------------------------- /** @brief Retrieve a material property with a specific key from the material * @@ -1495,7 +1495,6 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialProperty( unsigned int index, const C_STRUCT aiMaterialProperty** pPropOut); - // --------------------------------------------------------------------------- /** @brief Retrieve an array of float values with a specific key * from the material @@ -1532,7 +1531,6 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( unsigned int* pMax); - #ifdef __cplusplus // --------------------------------------------------------------------------- diff --git a/include/aiMaterial.inl b/include/aiMaterial.inl index 5bc49e4eb..009bff423 100644 --- a/include/aiMaterial.inl +++ b/include/aiMaterial.inl @@ -70,7 +70,7 @@ inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, unsigned int iNum = pMax ? *pMax : 1; aiMaterialProperty* prop; - aiReturn ret = aiGetMaterialProperty(this,pKey,type,idx,&prop); + aiReturn ret = ::aiGetMaterialProperty(this,pKey,type,idx,&prop); if ( AI_SUCCESS == ret ) { if (prop->mDataLength < sizeof(Type)*iNum) @@ -92,7 +92,7 @@ inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, unsigned int idx,Type& pOut) const { aiMaterialProperty* prop; - aiReturn ret = aiGetMaterialProperty(this,pKey,type,idx,&prop); + aiReturn ret = ::aiGetMaterialProperty(this,pKey,type,idx,&prop); if ( AI_SUCCESS == ret ) { if (prop->mDataLength < sizeof(Type)) diff --git a/include/aiMatrix4x4.h b/include/aiMatrix4x4.h index d43de7202..df3c59f91 100644 --- a/include/aiMatrix4x4.h +++ b/include/aiMatrix4x4.h @@ -201,6 +201,14 @@ public: */ static aiMatrix4x4& Translation( const aiVector3D& v, aiMatrix4x4& out); + // ------------------------------------------------------------------- + /** @brief Returns a scaling matrix + * @param v Scaling vector + * @param out Receives the output matrix + * @return Reference to the output matrix + */ + static aiMatrix4x4& Scaling( const aiVector3D& v, aiMatrix4x4& out); + // ------------------------------------------------------------------- /** @brief A function for creating a rotation matrix that rotates a diff --git a/include/aiMatrix4x4.inl b/include/aiMatrix4x4.inl index 94d0fca2a..93942e6dc 100644 --- a/include/aiMatrix4x4.inl +++ b/include/aiMatrix4x4.inl @@ -385,6 +385,16 @@ inline aiMatrix4x4& aiMatrix4x4::Translation( const aiVector3D& v, aiMatrix4x4& return out; } +// ---------------------------------------------------------------------------------------- +inline aiMatrix4x4& aiMatrix4x4::Scaling( const aiVector3D& v, aiMatrix4x4& out) +{ + out = aiMatrix4x4(); + out.a1 = v.x; + out.b2 = v.y; + out.c3 = v.z; + return out; +} + // ---------------------------------------------------------------------------------------- /** A function for creating a rotation matrix that rotates a vector called * "from" into another vector called "to". diff --git a/include/aiPostProcess.h b/include/aiPostProcess.h index 09e8659df..d6cceb517 100644 --- a/include/aiPostProcess.h +++ b/include/aiPostProcess.h @@ -296,30 +296,46 @@ enum aiPostProcessSteps }; -/** @def AI_POSTPROCESS_DEFAULT_REALTIME_FASTEST - * @brief Default postprocess configuration targeted at realtime applications - * which need to load models as fast as possible. +// --------------------------------------------------------------------------------------- +/** @def aiProcessPreset_TargetRealtimeUse_Fast + * @brief Default postprocess configuration optimizing the data for real-time rendering. * - * If you're using DirectX, don't forget to combine this value with - * the #aiProcess_ConvertToLeftHanded step. + * Applications would want to use this preset to load models on end-user PCs, + * maybe for direct use in game. + * + * If you're using DirectX, don't forget to combine this value with + * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + * in your application apply the #aiProcess_TransformUVCoords step, too. + * @note Please take the time to read the doc to the steps enabled by this preset. + * Some of them offer further configurable properties, some of them might not be of + * use for you so it might be better to not specify them. */ -#define AI_POSTPROCESS_DEFAULT_REALTIME_FASTEST \ +#define aiProcessPreset_TargetRealtime_Fast \ aiProcess_CalcTangentSpace | \ aiProcess_GenNormals | \ aiProcess_JoinIdenticalVertices | \ aiProcess_Triangulate | \ - aiProcess_GenUVCoords + aiProcess_GenUVCoords | \ + aiProcess_SortByPType | \ + 0 - - /** @def AI_POSTPROCESS_DEFAULT_REALTIME - * @brief Default postprocess configuration targeted at realtime applications. - * Unlike AI_POSTPROCESS_DEFAULT_REALTIME_FASTEST, this configuration - * performs some extra optimizations. - * - * If you're using DirectX, don't forget to combine this value with - * the #aiProcess_ConvertToLeftHanded step. - */ -#define AI_POSTPROCESS_DEFAULT_REALTIME \ + // --------------------------------------------------------------------------------------- + /** @def aiProcessPreset_TargetRealtime_Quality + * @brief Default postprocess configuration optimizing the data for real-time rendering. + * + * Unlike #aiProcessPreset_TargetRealtime_Fast, this configuration + * performs some extra optimizations to improve rendering speed and + * to minimize memory usage. It could be a good choice for a level editor + * environment where import speed is not so important. + * + * If you're using DirectX, don't forget to combine this value with + * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + * in your application apply the #aiProcess_TransformUVCoords step, too. + * @note Please take the time to read the doc to the steps enabled by this preset. + * Some of them offer further configurable properties, some of them might not be of + * use for you so it might be better to not specify them. + */ +#define aiProcessPreset_TargetRealtime_Quality \ aiProcess_CalcTangentSpace | \ aiProcess_GenSmoothNormals | \ aiProcess_JoinIdenticalVertices | \ @@ -327,9 +343,33 @@ enum aiPostProcessSteps aiProcess_LimitBoneWeights | \ aiProcess_RemoveRedundantMaterials | \ aiProcess_SplitLargeMeshes | \ - aiProcess_OptimizeGraph | \ aiProcess_Triangulate | \ - aiProcess_GenUVCoords + aiProcess_GenUVCoords | \ + aiProcess_SortByPType | \ + aiProcess_FindDegenerates | \ + aiProcess_FindInvalidData | \ + 0 + + // --------------------------------------------------------------------------------------- + /** @def aiProcessPreset_TargetRealtime_MaxQuality + * @brief Default postprocess configuration optimizing the data for real-time rendering. + * + * This preset enables almost every optimization step to achieve perfectly + * optimized data. It's your choice for level editor environments where import speed + * doesn't care. + * + * If you're using DirectX, don't forget to combine this value with + * the #aiProcess_ConvertToLeftHanded step. If you don't support UV transformations + * in your application apply the #aiProcess_TransformUVCoords step, too. + * @note Please take the time to read the doc to the steps enabled by this preset. + * Some of them offer further configurable properties, some of them might not be of + * use for you so it might be better to not specify them. + */ +#define aiProcessPreset_TargetRealtime_MaxQuality \ + aiProcessPreset_TargetRealtime_Quality | \ + aiProcess_FindInstances | \ + aiProcess_ValidateDataStructure | \ + 0 #ifdef __cplusplus diff --git a/include/aiQuaternion.h b/include/aiQuaternion.h index 223ff4268..8cab09d14 100644 --- a/include/aiQuaternion.h +++ b/include/aiQuaternion.h @@ -281,6 +281,7 @@ inline aiQuaternion aiQuaternion::operator* (const aiQuaternion& t) const } } // end extern "C" + #endif // __cplusplus #endif // AI_QUATERNION_H_INC diff --git a/include/aiScene.h b/include/aiScene.h index cd921df87..80f399a08 100644 --- a/include/aiScene.h +++ b/include/aiScene.h @@ -77,6 +77,10 @@ struct aiNode * * Cameras and lights are assigned to a specific node name - if there * are multiple nodes with this name, they're assigned to each of them. + *
+ * There are no limitations regarding the characters contained in + * this text. You should be able to handle stuff like whitespace, tabs, + * linefeeds, quotation marks, ampersands, ... . */ C_STRUCT aiString mName; diff --git a/include/aiTexture.h b/include/aiTexture.h index 4fa7446a1..c00310486 100644 --- a/include/aiTexture.h +++ b/include/aiTexture.h @@ -143,7 +143,8 @@ struct aiTexture * file extension of the format without a trailing dot. If there * are multiple file extensions for a format, the shortest * extension is chosen (JPEG maps to 'jpg', not to 'jpeg'). - * E.g. 'dds\\0', 'pcx\\0', 'jpg'. All characters are lower-case. + * E.g. 'dds\\0', 'pcx\\0', 'jpg\\0'. All characters are lower-case. + * The fourth character will always be '\\0'. */ char achFormatHint[4]; @@ -162,13 +163,13 @@ struct aiTexture //! For compressed textures (mHeight == 0): compare the //! format hint against a given string. - //! @param s Input string. 4 characters are maximally processed. + //! @param s Input string. 3 characters are maximally processed. //! Example values: "jpg", "png" //! @return true if the given string matches the format hint bool CheckFormat(const char* s) const { ai_assert(s && !mHeight); - return (0 == ::strncmp(achFormatHint,s,4)); + return (0 == ::strncmp(achFormatHint,s,3)); } // Construction diff --git a/include/aiTypes.h b/include/aiTypes.h index 31cdda8b8..3ff2a8053 100644 --- a/include/aiTypes.h +++ b/include/aiTypes.h @@ -245,6 +245,7 @@ struct aiColor4D float r, g, b, a; } PACK_STRUCT; // !struct aiColor4D + #include "./Compiler/poppack1.h" @@ -477,5 +478,6 @@ struct aiMemoryInfo #include "aiMatrix4x4.inl" + #endif //!! include guard diff --git a/include/aiVector3D.inl b/include/aiVector3D.inl index 394bf8663..e228aa0de 100644 --- a/include/aiVector3D.inl +++ b/include/aiVector3D.inl @@ -176,21 +176,6 @@ AI_FORCE_INLINE aiVector3D operator - ( const aiVector3D& v) { return aiVector3D( -v.x, -v.y, -v.z); } -#ifdef ASSIMP_INTERNAL_BUILD -namespace std { - - // std::min for aiVector3D - inline ::aiVector3D min (const ::aiVector3D& a, const ::aiVector3D& b) { - return ::aiVector3D (min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); - } - - // std::max for aiVector3D - inline ::aiVector3D max (const ::aiVector3D& a, const ::aiVector3D& b) { - return ::aiVector3D (max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); - } - -} // end namespace std -#endif // !! ASSIMP_INTERNAL_BUILD #endif // __cplusplus #endif // AI_VECTOR3D_INL_INC diff --git a/include/assimp.hpp b/include/assimp.hpp index 816be4be2..f737334e3 100644 --- a/include/assimp.hpp +++ b/include/assimp.hpp @@ -300,6 +300,20 @@ public: bool IsDefaultIOHandler(); + // ------------------------------------------------------------------- + /** @brief Check whether a given set of postprocessing flags + * is supported. + * + * Some flags are mutually exclusive, others are probably + * not available because your excluded them from your + * Assimp builds. Calling this function is recommended if + * you're unsure. + * + * @param pFlags Bitwise combination of the aiPostProcess flags. + * @return true if this flag combination is not supported. + */ + bool ValidateFlags(unsigned int pFlags); + // ------------------------------------------------------------------- /** Reads the given file and returns its contents if successful. * @@ -316,6 +330,10 @@ public: * @return A pointer to the imported data, NULL if the import failed. * The pointer to the scene remains in possession of the Importer * instance. Use GetOrphanedScene() to take ownership of it. + * + * @note Assimp is able to determine the file format of a file + * automatically. However, you should make sure that the input file + * does not even have a file extension at all to enable this feature. */ const aiScene* ReadFile( const char* pFile, unsigned int pFlags); diff --git a/make_mingw.bat b/make_mingw.bat deleted file mode 100644 index 8935d0cd2..000000000 --- a/make_mingw.bat +++ /dev/null @@ -1,4 +0,0 @@ -cd code -mingw32-make -f makefile.mingw - -pause \ No newline at end of file diff --git a/mkutil/revision.h b/mkutil/revision.h index 65814ae21..328df1a59 100644 --- a/mkutil/revision.h +++ b/mkutil/revision.h @@ -1 +1 @@ -#define SVNRevision 342 +#define SVNRevision 355 diff --git a/test/RunUnitTestSuite.bat b/test/RunUnitTestSuite.bat index 1c39d1771..74917bc89 100644 --- a/test/RunUnitTestSuite.bat +++ b/test/RunUnitTestSuite.bat @@ -20,8 +20,8 @@ IF %PROCESSOR_ARCHITECTURE% == x86 ( rem Setup standard paths from here SET OUTDIR=results\ SET BINDIR=..\bin\ -SET FIRSTUTFAILURE=none -SET FIRSTUTNA=none +SET FIRSTUTFAILURE=nil +SET FIRSTUTNA=nil echo #===================================================================== echo # Open Asset Import Library - Unittests @@ -97,11 +97,11 @@ call RunSingleUnitTestSuite unit_debug-dll_%ARCHEXT% debug-dll.txt echo. echo ---------------------------------------------------------------------- -IF NOT FIRSTUTNA==none ( +IF NOT FIRSTUTNA== nil ( echo One or more test configs are not available. ) -IF NOT FIRSTUTFAILURE==none ( +IF NOT FIRSTUTFAILURE== nil ( echo One or more tests failed. ) diff --git a/test/models/3D/box.uc b/test/models/3D/box.uc new file mode 100644 index 000000000..9e2b593cd --- /dev/null +++ b/test/models/3D/box.uc @@ -0,0 +1,20 @@ +class box expands Actor; + +#exec MESH IMPORT MESH=box ANIVFILE=MODELS\box_a.3d DATAFILE=MODELS\box_d.3d X=0 Y=0 Z=0 +#exec MESH ORIGIN MESH=box X=0 Y=0 Z=0 + +#exec MESH SEQUENCE MESH=box SEQ=All STARTFRAME=0 NUMFRAMES=30 +//#exec MESH SEQUENCE MESH=box SEQ=??? STARTFRAME=0 NUMFRAMES=30 + +#exec MESHMAP NEW MESHMAP=box MESH=box +#exec MESHMAP SCALE MESHMAP=box X=0.1 Y=0.1 Z=0.2 + +#exec TEXTURE IMPORT NAME=Jtex1 FILE=texture1.pcx GROUP=Skins FLAGS=2 +#exec TEXTURE IMPORT NAME=Jtex1 FILE=texture1.pcx GROUP=Skins PALETTE=Jtex1 +#exec MESHMAP SETTEXTURE MESHMAP=box NUM=1 TEXTURE=Jtex1 + +defaultproperties +{ + DrawType=DT_Mesh + Mesh=box +} diff --git a/test/models/3D/box_a.3d b/test/models/3D/box_a.3d new file mode 100644 index 000000000..22884c3ff Binary files /dev/null and b/test/models/3D/box_a.3d differ diff --git a/test/models/3D/box_d.3d b/test/models/3D/box_d.3d new file mode 100644 index 000000000..2f127a8cc Binary files /dev/null and b/test/models/3D/box_d.3d differ diff --git a/test/models/3D/mar_rifle.source.txt b/test/models/3D/mar_rifle.source.txt new file mode 100644 index 000000000..ac8721d26 --- /dev/null +++ b/test/models/3D/mar_rifle.source.txt @@ -0,0 +1,18 @@ +===================================================================== + +From http://telias.free.fr +Model copyright: Elias Tsiantas + +===================================================================== + +Downloaded 4th November 2008. +Notice found on the page: + +" +Free the models is a site that offers free 3d models in 3ds, bryce, poser, +lightwave and md2 format. Also a great collection of textures to use in +your favorite modelling and rendering program. All the content is free +for any use. In the future more 3d formats will be added and some other +sections such as wallpapers, 3d screensavers, 3d coding source code and +tutorials. +" diff --git a/test/models/3D/mar_rifle.uc b/test/models/3D/mar_rifle.uc new file mode 100644 index 000000000..be01ca657 --- /dev/null +++ b/test/models/3D/mar_rifle.uc @@ -0,0 +1,20 @@ +class mar expands Actor; + +#exec MESH IMPORT MESH=mar ANIVFILE=MODELS\mar_a.3d DATAFILE=MODELS\mar_d.3d X=0 Y=0 Z=0 +#exec MESH ORIGIN MESH=mar X=0 Y=0 Z=0 + +#exec MESH SEQUENCE MESH=mar SEQ=All STARTFRAME=0 NUMFRAMES=30 +//#exec MESH SEQUENCE MESH=mar SEQ=??? STARTFRAME=0 NUMFRAMES=30 + +#exec MESHMAP NEW MESHMAP=mar MESH=mar +#exec MESHMAP SCALE MESHMAP=mar X=0.1 Y=0.1 Z=0.2 + +#exec TEXTURE IMPORT NAME=Jtex1 FILE=..\3DS\m_rifl.bmp GROUP=Skins FLAGS=2 +#exec TEXTURE IMPORT NAME=Jtex1 FILE=texture1.pcx GROUP=Skins PALETTE=Jtex1 +#exec MESHMAP SETTEXTURE MESHMAP=mar NUM=1 TEXTURE=Jtex1 + +defaultproperties +{ + DrawType=DT_Mesh + Mesh=mar +} diff --git a/test/models/3D/mar_rifle_a.3d b/test/models/3D/mar_rifle_a.3d new file mode 100644 index 000000000..a01d9fe8b Binary files /dev/null and b/test/models/3D/mar_rifle_a.3d differ diff --git a/test/models/3D/mar_rifle_d.3d b/test/models/3D/mar_rifle_d.3d new file mode 100644 index 000000000..66852b214 Binary files /dev/null and b/test/models/3D/mar_rifle_d.3d differ diff --git a/test/models/3DS/testFormatDetection b/test/models/3DS/testFormatDetection new file mode 100644 index 000000000..a2f573625 Binary files /dev/null and b/test/models/3DS/testFormatDetection differ diff --git a/test/models/AC/Rectangle.ac b/test/models/AC/TestFormatDetection similarity index 100% rename from test/models/AC/Rectangle.ac rename to test/models/AC/TestFormatDetection diff --git a/test/models/ASE/MotionCaptureROM.source.txt b/test/models/ASE/MotionCaptureROM.source.txt index c8dd070f3..27f8aac49 100644 --- a/test/models/ASE/MotionCaptureROM.source.txt +++ b/test/models/ASE/MotionCaptureROM.source.txt @@ -1,6 +1,4 @@ -"MotionCaptureROM.ase" - Recorded at HTW Aalen (http://www.htw-aalen.de) using LycosIQ. -Many thanks to Prof. Carsten Lecon! - +"MotionCaptureROM.ase" - Recorded using Vicon IQ. NOTE: The errors in the middle of the animation are there in the -original animation track, too. The captured person lost a sensor ... \ No newline at end of file +original animation track, too. The captured person lost a marker ... \ No newline at end of file diff --git a/test/models/ASE/würfel.ASE b/test/models/ASE/TestFormatDetection similarity index 100% rename from test/models/ASE/würfel.ASE rename to test/models/ASE/TestFormatDetection diff --git a/test/models/HMP/planar.hmp b/test/models/HMP/formatDetection similarity index 100% rename from test/models/HMP/planar.hmp rename to test/models/HMP/formatDetection diff --git a/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr new file mode 100644 index 000000000..1f0916d4d Binary files /dev/null and b/test/models/IRR/EpisodeII_TheDwarfesStrikeBack.irr differ diff --git a/test/models/IRR/EpisodeI_ANewDwarf.irr b/test/models/IRR/EpisodeI_ANewDwarf.irr new file mode 100644 index 000000000..39d99e440 Binary files /dev/null and b/test/models/IRR/EpisodeI_ANewDwarf.irr differ diff --git a/test/models/IRR/animMesh.irr b/test/models/IRR/animMesh.irr index d0b472f2c..d1c9e1018 100644 Binary files a/test/models/IRR/animMesh.irr and b/test/models/IRR/animMesh.irr differ diff --git a/test/models/IRR/warn_dwarf_scaling_is_intended.txt b/test/models/IRR/warn_dwarf_scaling_is_intended.txt new file mode 100644 index 000000000..1fcb03b9a --- /dev/null +++ b/test/models/IRR/warn_dwarf_scaling_is_intended.txt @@ -0,0 +1,3 @@ +for dawfInCellar_ChildOfCellar & dawfInCellar_SameHierarchy: + +the strange scalings of cellar and dwarf are intended. diff --git a/test/models/LWO/LWO2/boxuv.lwo b/test/models/LWO/LWO2/boxuv.lwo new file mode 100644 index 000000000..9f314d016 Binary files /dev/null and b/test/models/LWO/LWO2/boxuv.lwo differ diff --git a/test/models/LWO/LWO2/boxuv.png b/test/models/LWO/LWO2/boxuv.png new file mode 100644 index 000000000..9da32691e Binary files /dev/null and b/test/models/LWO/LWO2/boxuv.png differ diff --git a/test/models/LWO/LWO2/formatDetection b/test/models/LWO/LWO2/formatDetection new file mode 100644 index 000000000..14e805fdb Binary files /dev/null and b/test/models/LWO/LWO2/formatDetection differ diff --git a/test/models/LWO/LWOB/MappingModes/bluewithcylindrictexz.lwo b/test/models/LWO/LWOB/MappingModes/bluewithcylindrictexz.lwo new file mode 100644 index 000000000..c26927077 Binary files /dev/null and b/test/models/LWO/LWOB/MappingModes/bluewithcylindrictexz.lwo differ diff --git a/test/models/LWO/LWOB/formatDetection b/test/models/LWO/LWOB/formatDetection new file mode 100644 index 000000000..49f24e826 Binary files /dev/null and b/test/models/LWO/LWOB/formatDetection differ diff --git a/test/models/LWS/QuickDraw v.2.2.lws b/test/models/LWS/QuickDraw v.2.2.lws index 0222af835..c1d713e24 100644 --- a/test/models/LWS/QuickDraw v.2.2.lws +++ b/test/models/LWS/QuickDraw v.2.2.lws @@ -10,7 +10,7 @@ PreviewFrameStep 1 CurrentFrame 0 FramesPerSecond 30 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--Chasis.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--Chasis.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -85,7 +85,7 @@ ParentItem 1000000e IKAnchor 1 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--Wheels-Back.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--Wheels-Back.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -160,7 +160,7 @@ PivotPosition 0 0.99 2.58 ParentItem 10000000 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--Wheels-Front.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--Wheels-Front.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -235,7 +235,7 @@ PivotPosition 0 0.6799999 -2.539999 ParentItem 10000000 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--CabinPortals.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--CabinPortals.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -312,7 +312,7 @@ PivotPosition 0 2.55 -1.61 ParentItem 10000000 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--Arm-Shoulder.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--Arm-Shoulder.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -390,7 +390,7 @@ PivotPosition 0 1.81 -4.240001 ParentItem 10000000 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--Arm-ForeArm.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--Arm-ForeArm.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -467,7 +467,7 @@ PivotPosition 0 1.82 -5.410002 ParentItem 10000004 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--Arm-Tip.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--Arm-Tip.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -544,7 +544,7 @@ PivotPosition 0 3.98 -5.510003 ParentItem 10000005 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--GP-Pod.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--GP-Pod.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -621,7 +621,7 @@ PivotPosition 0 3.1 -0.870001 ParentItem 10000000 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--GP-Lid.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--GP-Lid.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -698,7 +698,7 @@ PivotPosition 0 3.13 1.66 ParentItem 10000007 ShadowOptions 7 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--GP-Gun.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--GP-Gun.lwo ShowObject 5 7 ObjectMotion NumChannels 9 @@ -1395,7 +1395,7 @@ LockedChannels 4088 ParentItem 1000000e ShadowOptions 0 -LoadObjectLayer 1 Objects/WW_QuickDraw/QuickDraw--Standin-Driver.lwo +LoadObjectLayer 1 ../LWO/LWO2/LWSReferences/QuickDraw--Standin-Driver.lwo ShowObject 5 7 ObjectMotion NumChannels 9 diff --git a/test/models/LWS/QuickDraw v.2.2_oldformat_56.lws b/test/models/LWS/QuickDraw v.2.2_oldformat_56.lws new file mode 100644 index 000000000..926e03814 --- /dev/null +++ b/test/models/LWS/QuickDraw v.2.2_oldformat_56.lws @@ -0,0 +1,987 @@ +LWSC +2 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 30 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-30 +PreviewFirstFrame 0 +PreviewLastFrame 30 +PreviewFrameStep 1 +FramesPerSecond 30 + +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--Chasis.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +HLimits 0 0 +PLimits 0 0 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 15 +IKInitialState 0 +IKAnchor 1 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--Wheels-Back.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0.99 0 2 0 0 0 + 0.99 1 2 0 0 0 + 2 + 2.58 0 2 0 0 0 + 2.58 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 0.99 2.58 +ParentObject 1 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--Wheels-Front.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0.6799999 0 2 0 0 0 + 0.6799999 1 2 0 0 0 + 2 + -2.539999 0 2 0 0 0 + -2.539999 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 0.6799999 -2.539999 +ParentObject 1 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--CabinPortals.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 2.55 0 2 0 0 0 + 2.55 1 2 0 0 0 + 2 + -1.61 0 2 0 0 0 + -1.61 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + -114 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +PController 3 +PLimits -114 0 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 2.55 -1.61 +ParentObject 1 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--Arm-Shoulder.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1.81 0 2 0 0 0 + 1.81 1 2 0 0 0 + 2 + -4.240001 0 2 0 0 0 + -4.240001 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + -23 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4071 +HController 3 +HLimits -59.99999 59.99999 +PController 3 +PLimits -23 123 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 1.81 -4.240001 +ParentObject 1 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--Arm-ForeArm.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1.82 0 2 0 0 0 + 1.82 1 2 0 0 0 + 2 + -5.410002 0 2 0 0 0 + -5.410002 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 45.675 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +PController 3 +PLimits -90 46 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 1.82 -5.410002 +ParentObject 5 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--Arm-Tip.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.98 0 2 0 0 0 + 3.98 1 2 0 0 0 + 2 + -5.510003 0 2 0 0 0 + -5.510003 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + -28 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +PController 3 +PLimits -28 140 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 3.98 -5.510003 +ParentObject 6 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--GP-Pod.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.1 0 2 0 0 0 + 3.1 1 2 0 0 0 + 2 + -0.870001 0 2 0 0 0 + -0.870001 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + -89.99999 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +PController 3 +PLimits -90 0 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 3.1 -0.870001 +ParentObject 1 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--GP-Lid.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.13 0 2 0 0 0 + 3.13 1 2 0 0 0 + 2 + 1.66 0 2 0 0 0 + 1.66 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 140 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +PController 3 +PLimits 0 140 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 3.13 1.66 +ParentObject 8 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--GP-Gun.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.409999 0 2 0 0 0 + 3.409999 1 2 0 0 0 + 2 + 1.580001 0 2 0 0 0 + 1.580001 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 89.99999 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4079 +HLimits 0 0 +PController 3 +PLimits 0 90 +BLimits 0 0 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +PivotPoint 0 3.409999 1.580001 +ParentObject 8 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw -- magnet -- Portals +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1.92 0 2 0 0 0 + 1.92 1 2 0 0 0 + 2 + -2.869999 0 2 0 0 0 + -2.869999 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4095 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 4 +GoalObject 16 +FullTimeIK 0 +GoalStrength 1 +GoalObjective 0 +IKSoft 0 +IKSoftDistType 0 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw -- magnet -- Pod-Gun +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.329999 0 2 0 0 0 + 3.329999 1 2 0 0 0 + 2 + -0.13 0 2 0 0 0 + -0.13 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4095 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 10 +GoalObject 17 +FullTimeIK 0 +GoalStrength 1 +GoalObjective 0 +IKSoft 0 +IKSoftDistType 0 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw -- magnet -- Pod Lid +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.56 0 2 0 0 0 + 3.56 1 2 0 0 0 + 2 + -0.28 0 2 0 0 0 + -0.28 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4095 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 9 +GoalObject 18 +FullTimeIK 1 +GoalStrength 1 +GoalObjective 0 +IKSoft 0 +IKSoftDistType 0 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw -- magnet -- Arm +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.999999 0 2 0 0 0 + 3.999999 1 2 0 0 0 + 2 + -6.8 0 2 0 0 0 + -6.8 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4095 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 7 +GoalObject 19 +FullTimeIK 0 +GoalStrength 1 +GoalObjective 0 +IKSoft 0 +IKSoftDistType 0 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw == HANDLE == MASTER +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4064 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw == HANDLE == Portals +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 1 + 0 0 2 0 0 0 + 1 + 1.92 0 2 0 0 0 + 1 + -2.869999 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4089 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 15 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw == HANDLE == Pod-Gun +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 1 + 0 0 2 0 0 0 + 1 + 3.329999 0 2 0 0 0 + 1 + -0.13 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4089 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 15 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw == HANDLE == Pod Lid +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 3.56 0 2 0 0 0 + 8.400002 1 2 0 0 0 + 2 + -0.28 0 2 0 0 0 + -2.279999 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 0 0 2 0 0 0 + 0 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 + 2 + 1 0 2 0 0 0 + 1 1 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4089 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 15 +IKInitialState 0 +SubPatchLevel 3 3 +AddNullObject Quick Draw == HANDLE == Arm +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 1 + 0 0 2 0 0 0 + 1 + 3.999999 0 2 0 0 0 + 1 + -6.8 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +LockedChannels 4088 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 15 +IKInitialState 0 +SubPatchLevel 3 3 +LoadObject ..\LWO\LWO2\LWSReferences\QuickDraw--Standin-Driver.lwo +ShowObject 5 7 +Group 0 +ObjectMotion (unnamed) + 9 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +ParentObject 1 +IKInitialState 0 +SubPatchLevel 3 3 +AmbientColor 255 255 255 +AmbIntensity 0.25 +DoubleSidedAreaLights 1 + +AddLight +LightName Light +ShowLight 0 7 +LightMotion (unnamed) + 9 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 60 0 2 0 0 0 + 1 + 30 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 255 255 255 +LgtIntensity 1.6 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 80 20 10 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera +CameraName Camera +ShowCamera 1 7 +CameraMotion (unnamed) + 6 + 1 + -9.570365 0 2 0 0 0 + 1 + 8.390076 0 2 0 0 0 + 1 + -9.28088 0 2 0 0 0 + 1 + 50.3 0 2 0 0 0 + 1 + 25.40001 0 2 0 0 0 + 1 + 0 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +Resolution 1 +CustomSize 640 480 +PixelAspectRatio -1 +CustomPixelRatio 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +AdaptiveThreshold 8 +Plugin CameraHandler 1 Classic +EndPlugin + +SegmentMemory 32000000 +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 1 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 40 80 +SkyColor 120 180 240 +GroundColor 50 40 30 +NadirColor 100 80 60 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 130 130 140 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 9 +ViewLevel 5 +ViewAimpoint 0 2.859999 -1.620002 +ViewZoomFactor 3.2 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 30 +GridSize 2 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 diff --git a/test/models/LWS/move_x.lws b/test/models/LWS/move_x.lws new file mode 100644 index 000000000..41453b1b3 --- /dev/null +++ b/test/models/LWS/move_x.lws @@ -0,0 +1,472 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 60 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 60 +PreviewFrameStep 1 +CurrentFrame 40 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.0682507681379909 0 + Key 2.0691125392913818 0.66666666666666663 0 0 0 0 -1.1874328851699829 -1.1874328851699829 0 + Key -2.3748657703399658 1.3333333333333333 0 0 0 0 -4.4421274232050125 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key -0.040000002831220627 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 0.97975808382034302 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 0.88587331771850586 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 0.95491594076156616 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_x_oldformat_56.lws b/test/models/LWS/move_x_oldformat_56.lws new file mode 100644 index 000000000..0acf0f27c --- /dev/null +++ b/test/models/LWS/move_x_oldformat_56.lws @@ -0,0 +1,196 @@ +LWSC +2 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 60 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 60 +PreviewFrameStep 1 +FramesPerSecond 30 + +LoadObject simple_cube.lwo +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion (unnamed) + 9 + 3 + 0 0 2 0 0 0 + 2.069113 0.6666667 2 0 0 0 + -2.374866 1.333333 2 0 0 0 + 1 + -0.04 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0.9797581 0 2 0 0 0 + 1 + 0.8858733 0 2 0 0 0 + 1 + 0.9549159 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +AmbientColor 255 255 255 +AmbIntensity 0.05 +DoubleSidedAreaLights 1 + +AddLight +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion (unnamed) + 9 + 1 + -2 0 2 0 0 0 + 1 + 2 0 2 0 0 0 + 1 + -2 0 2 0 0 0 + 1 + 45 0 2 0 0 0 + 1 + 35 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 + 1 + 1 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 255 255 255 +LgtIntensity 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 80 20 10 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion (unnamed) + 6 + 1 + -0.1 0 2 0 0 0 + 1 + 0.95 0 2 0 0 0 + 1 + -6.384 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 + 1 + 0 0 2 0 0 0 +Pre/PostBehavior 1 1 1 1 1 1 1 1 1 1 1 1 +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +Resolution 1 +CustomSize 640 480 +PixelAspectRatio -1 +CustomPixelRatio 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +Plugin CameraHandler 1 Perspective +EndPlugin + +SegmentMemory 32000000 +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 40 80 +SkyColor 120 180 240 +GroundColor 50 40 30 +NadirColor 100 80 60 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 130 130 140 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewDirection 0.3001966 -0.3141592 -0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 diff --git a/test/models/LWS/move_x_oldformat_6.lws b/test/models/LWS/move_x_oldformat_6.lws new file mode 100644 index 000000000..ecafe3f7b --- /dev/null +++ b/test/models/LWS/move_x_oldformat_6.lws @@ -0,0 +1,447 @@ +LWSC +3 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 60 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 60 +PreviewFrameStep 1 +CurrentFrame 40 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 simple_cube.lwo +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.0682507681379905 0 + Key 2.0691125392913814 0.66666666666666663 0 0 0 0 -1.1874328851699831 -1.1874328851699831 0 + Key -2.3748657703399658 1.3333333333333333 0 0 0 0 -4.4421274232050125 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key -0.040000002831220634 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 0.97975808382034302 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 0.88587331771850575 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 0.95491594076156605 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999986 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185792 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_x_post_constant.lws b/test/models/LWS/move_x_post_constant.lws new file mode 100644 index 000000000..f7fc47642 --- /dev/null +++ b/test/models/LWS/move_x_post_constant.lws @@ -0,0 +1,472 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 0 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.1372954575696919 0 + Key 2.1381859973436792 0.66666666666666663 0 0 0 0 -0.8400939672421186 -0.79808926888001264 0 + Key -1.6381832361221313 1.3 0 0 0 0 -3.7747136573003282 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_x_post_linear.lws b/test/models/LWS/move_x_post_linear.lws new file mode 100644 index 000000000..11ea23f96 --- /dev/null +++ b/test/models/LWS/move_x_post_linear.lws @@ -0,0 +1,472 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 5 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.1372954575696919 0 + Key 2.1381859973436792 0.66666666666666663 0 0 0 0 -0.8400939672421186 -0.79808926888001264 0 + Key -1.6381832361221313 1.3 0 0 0 0 -3.7747136573003282 0 0 + Behaviors 1 5 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_x_post_offset_repeat.lws b/test/models/LWS/move_x_post_offset_repeat.lws new file mode 100644 index 000000000..1bb4c8f90 --- /dev/null +++ b/test/models/LWS/move_x_post_offset_repeat.lws @@ -0,0 +1,472 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 0 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.1372954575696919 0 + Key 2.1381859973436792 0.66666666666666663 0 0 0 0 -0.8400939672421186 -0.79808926888001264 0 + Key -1.6381832361221313 1.3 0 0 0 0 -3.7747136573003282 0 0 + Behaviors 1 4 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_x_post_repeat.lws b/test/models/LWS/move_x_post_repeat.lws new file mode 100644 index 000000000..c5db40ae2 --- /dev/null +++ b/test/models/LWS/move_x_post_repeat.lws @@ -0,0 +1,472 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 120 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.1372954575696919 0 + Key 2.1381859973436792 0.66666666666666663 0 0 0 0 -0.8400939672421186 -0.79808926888001264 0 + Key -1.6381832361221313 1.3 0 0 0 0 -3.7747136573003282 0 0 + Behaviors 1 2 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_x_post_reset.lws b/test/models/LWS/move_x_post_reset.lws new file mode 100644 index 000000000..980e08e35 --- /dev/null +++ b/test/models/LWS/move_x_post_reset.lws @@ -0,0 +1,472 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 1 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.1372954575696919 0 + Key 2.1381859973436792 0.66666666666666663 0 0 0 0 -0.8400939672421186 -0.79808926888001264 0 + Key -1.6381832361221313 1.3 0 0 0 0 -3.7747136573003282 0 0 + Behaviors 1 0 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_xz_bezier.lws b/test/models/LWS/move_xz_bezier.lws new file mode 100644 index 000000000..1627f37c4 --- /dev/null +++ b/test/models/LWS/move_xz_bezier.lws @@ -0,0 +1,474 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 96 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 5 0 0 0.22222 0.64163307824462457 2.0144942798797212 0 + Key 1.924918483918713 0.66666666666666663 5 -0.22222 0.012913536517090266 0.44444 -0.10330829213672213 -0.3486689726511637 0 + Key -0.52300345897674561 2 5 -0.44444 0.81596582122534322 0 0 0 0 + Behaviors 0 1 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 3 + Key 0 0 5 0 0 0.44444 -0.88536338761568067 -2.6555634816222775 0 + Key -2.6561167240142822 1.3333333333333333 5 -0.46576443257676908 0.0086004390920015397 0.56576343257676909 -0.018818992720682302 -0.062782856771785217 0 + Key -0.095800442759067794 2.9666666666666668 5 -0.54443900000000001 -0.85343022603080076 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_xz_hermite.lws b/test/models/LWS/move_xz_hermite.lws new file mode 100644 index 000000000..6a026dc90 --- /dev/null +++ b/test/models/LWS/move_xz_hermite.lws @@ -0,0 +1,474 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 0 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 1 0 0 0 0 2.0144942798797212 0 + Key 1.924918483918713 0.66666666666666663 1 0 0 0 -0.17433448632558185 -0.3486689726511637 0 + Key -0.52300345897674561 2 1 0 0 0 -2.4474120653818376 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 3 + Key 0 0 1 0 0 0 0 -2.6555634816222775 0 + Key -2.6561167240142822 1.3333333333333333 1 0 0 0 -0.043056378768120331 -0.062782856771785217 0 + Key -0.095800442759067794 2.9666666666666668 1 0 0 0 2.5416503021393155 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_xz_linear.lws b/test/models/LWS/move_xz_linear.lws new file mode 100644 index 000000000..fed06e935 --- /dev/null +++ b/test/models/LWS/move_xz_linear.lws @@ -0,0 +1,474 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 9 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.0144942798797212 0 + Key 1.924918483918713 0.66666666666666663 3 0 0 0 -0.17433448632558185 -0.3486689726511637 0 + Key -0.52300345897674561 2 3 0 0 0 -2.4474120653818376 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 -2.6555634816222775 0 + Key -2.6561167240142822 1.3333333333333333 3 0 0 0 -0.043056378768120331 -0.062782856771785217 0 + Key -0.095800442759067794 2.9666666666666668 3 0 0 0 2.5416503021393155 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_xz_spline.lws b/test/models/LWS/move_xz_spline.lws new file mode 100644 index 000000000..de16a958d --- /dev/null +++ b/test/models/LWS/move_xz_spline.lws @@ -0,0 +1,474 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 0 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.0144942798797212 0 + Key 2.0153336524963379 0.66666666666666663 0 0 0 0 -0.17433448632558185 -0.3486689726511637 0 + Key -0.52300345897674561 2 0 0 0 0 -2.5378084013894608 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 -2.6555634816222775 0 + Key -2.6561167240142822 1.3333333333333333 0 0 0 0 -0.051251311650436913 -0.062782856771785217 0 + Key -0.11403416842222214 2.9666666666666668 0 0 0 0 2.5416503021393155 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_xz_stepped.lws b/test/models/LWS/move_xz_stepped.lws new file mode 100644 index 000000000..5f4e7f9ef --- /dev/null +++ b/test/models/LWS/move_xz_stepped.lws @@ -0,0 +1,474 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame 1 +LastFrame 120 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame 0 +PreviewLastFrame 120 +PreviewFrameStep 1 +CurrentFrame 10 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 2.0144942798797212 0 + Key 1.924918483918713 0.66666666666666663 4 0 0 0 -0.17433448632558185 -0.3486689726511637 0 + Key -0.52300345897674561 2 4 0 0 0 -2.4474120653818376 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 -2.6555634816222775 0 + Key -2.6561167240142822 1.3333333333333333 4 0 0 0 -0.043056378768120331 -0.062782856771785217 0 + Key -0.095800442759067794 2.9666666666666668 4 0 0 0 2.5416503021393155 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/move_y_pre_ofrep_post_osc.lws b/test/models/LWS/move_y_pre_ofrep_post_osc.lws new file mode 100644 index 000000000..a0f928375 --- /dev/null +++ b/test/models/LWS/move_y_pre_ofrep_post_osc.lws @@ -0,0 +1,480 @@ +LWSC +5 + +RenderRangeType 0 +FirstFrame -240 +LastFrame 240 +FrameStep 1 +RenderRangeObject 0 +RenderRangeArbitrary 1-60 +PreviewFirstFrame -240 +PreviewLastFrame 240 +PreviewFrameStep 1 +CurrentFrame -179 +FramesPerSecond 30 +ChangeScene 0 + +LoadObjectLayer 1 10000000 simple_cube.lwo +ChangeObject 0 +ShowObject 7 -1 0.376471 0.878431 0.941176 +Group 0 +ObjectMotion +NumChannels 9 +Channel 0 +{ Envelope + 2 + Key 0 0 0 0 0 0 0 0 0 + Key 0 1 0 0 0 0 0 0 0 + Behaviors 0 3 +} +Channel 1 +{ Envelope + 3 + Key 0 0 0 0 0 0 0 0 0 + Key 0 1 0 0 0 0 0.58182278100182028 0.40727594670127421 0 + Key 0.98909872770309448 1.7 0 0 0 0 0.98870638389995957 0 0 + Behaviors 4 3 +} +Channel 2 +{ Envelope + 2 + Key 0 0 0 0 0 0 0 0 0 + Key 0 1 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 2 + Key 0 0 0 0 0 0 0 0 0 + Key 0 1 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 2 + Key 0 0 0 0 0 0 0 0 0 + Key 0 1 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 2 + Key 0 0 0 0 0 0 0 0 0 + Key 0 1 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 2 + Key 1 0 0 0 0 0 0 0 0 + Key 1 1 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 2 + Key 1 0 0 0 0 0 0 0 0 + Key 1 1 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 2 + Key 1 0 0 0 0 0 0 0 0 + Key 1 1 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +SubPatchLevel 3 3 +APSDisplay +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +APSRender +{ APS + Version 1 + Method 0 + { VParm + { ObjectLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonLevel + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 3 + 0 + } + } + } + { PolygonPixelSize + 0 + { VariantParameter + 3 + 0 + { ParameterValue + 256 + 0 + } + } + } + } +} +NodeDisplacement 0 +{ Nodal_Block + { Root + Location 0 0 + Zoom 1 + Disabled 1 + } + Version 1 + { Nodes + Server "Displacement" + { Tag + RealName "Displacement" + Name "Displacement" + Coordinates -10 -10 + Mode 1 + { Data + } + Preview "" + Comment "" + } + } + { Connections + } +} +NodeDisplacementOrder 0 +UseObjGI 0 +ObjGIRadiosityRays 64 +ObjGISecondaryBounceRays 16 +ObjGIRadiosityTolerance 0.292893 +ObjGIMinPixelSpacing 4.000000 +ObjGIMaxPixelSpacing 100.000000 +ShadowOptions 7 + +AmbientColor 1 1 1 +AmbientIntensity 0.05 +DoubleSidedAreaLights 1 +RadiosityType 2 +RadiosityInterpolated 1 +RadiosityTransparency 0 +RadiosityIntensity 1 +RadiosityTolerance 0.2928932 +RadiosityRays 64 +SecondaryBounceRays 16 +RadiosityMinPixelSpacing 4 +RadiosityMaxPixelSpacing 100 +RadiosityMultiplier 1 +RadiosityDirectionalRays 0 +RadiosityUseGradients 0 +RadiosityUseBehindTest 1 +BlurRadiosity 1 +RadiosityFlags 0 +RadiosityCacheModulus 1 +RadiosityCacheFilePath radiosity.cache +PixelFilterForceMT 0 + +AddLight 20000000 +LightName Light +ShowLight 1 -1 0.941176 0.376471 0.941176 +LightMotion +NumChannels 9 +Channel 0 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -2 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0.78539813999999997 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0.61086521999999999 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 6 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 7 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 8 +{ Envelope + 1 + Key 1 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +LightColor 1 1 1 +LightIntensity 1 +AffectCaustics 1 +LightType 0 +LensFlare 0 +FlareIntensity 0.5 +FlareDissolve 0 +LensFlareFade 4 +LensFlareOptions 11 +FlareRingColor 0.3137 0.0784 0.0392 +FlareRingSize 0.22 +FlareRandStreakInt 0.03 +FlareRandStreakDens 50 +FlareRandStreakSharp 6 +ShadowType 1 +ShadowColor 0 0 0 +Plugin LightHandler 1 DistantLight +EndPlugin + +AddCamera 30000000 +CameraName Camera +ShowCamera 1 -1 0.125490 0.878431 0.125490 +CameraMotion +NumChannels 6 +Channel 0 +{ Envelope + 1 + Key -0.10000002384185791 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 1 +{ Envelope + 1 + Key 0.94999998807907104 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 2 +{ Envelope + 1 + Key -6.384000301361084 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 3 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 4 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +Channel 5 +{ Envelope + 1 + Key 0 0 0 0 0 0 0 0 0 + Behaviors 1 1 +} +IKInitCustomFrame 0 +GoalStrength 1 +IKFKBlending 0 +IKSoftMin 0.25 +IKSoftMax 0.75 +CtrlPosItemBlend 1 +CtrlRotItemBlend 1 +CtrlScaleItemBlend 1 + +PathAlignLookAhead 0.033 +PathAlignMaxLookSteps 10 +PathAlignReliableDist 0.001 +IKInitialState 0 +ZoomFactor 3.2 +ZoomType 1 +ResolutionMultiplier 1.0 +FrameSize 640 480 +PixelAspect 1 +MaskPosition 0 0 640 480 +MotionBlur 0 +MotionBlurPasses 1 +ShutterEfficiency 1 +Oversampling 0 +FieldRendering 0 +ApertureHeight 0.015 +DepthOfField 0 +FocalDistance 1 +LensFStop 4 +DiaphragmSides 0 +DiaphragmRotation 0 +AASamples 1 +Sampler 1 +UseGlobalResolution 0 +UseGlobalMask 0 +UseGlobalBlur 0 +Plugin CameraHandler 1 Perspective +EndPlugin + +GlobalFrameSize 640 480 +GlobalMultiplier 1.0 +GlobalFieldRendering 0 +GlobalMotionBlur 0 +GlobalMaskPosition 0 0 640 480 +GlobalFilmHeight 0.015 +GlobalPixelAspect 1 + +Antialiasing 0 +AntiAliasingLevel -1 +ReconstructionFilter 0 +AdaptiveSampling 0 + +SolidBackdrop 1 +BackdropColor 0 0 0 +ZenithColor 0 0.1569 0.3137 +SkyColor 0.4706 0.7059 0.9412 +GroundColor 0.1961 0.1569 0.1176 +NadirColor 0.3922 0.3137 0.2353 +FogType 0 +FogMinDistance 0 +FogMaxDistance 1 +FogMinAmount 0 +FogMaxAmount 1 +FogColor 0.5098 0.5098 0.549 +BackdropFog 0 +VolumeClipDiscance 0.1 +DynamicRangeMin 0 +DynamicRangeLimit 1 +DitherIntensity 1 +AnimatedDither 0 + +RenderMode 2 +RayTraceEffects 0 +DepthBufferAA 0 +RenderLines 1 +RayRecursionLimit 16 +RayPrecision 6 +RayCutoff 0.01 +DataOverlayLabel +SaveRGB 0 +SaveAlpha 0 + +ViewConfiguration 0 +DefineView 0 +ViewType 7 +ViewLevel 5 +ViewAimpoint 0 0 0 +ViewRotation -17.2 18 0 +ViewZoomFactor 4 +ViewXRay 0 +ViewMBDofPreview 0 +ViewHeadlight 0 + +GridNumber 80 +GridSize 1 +CameraViewBG 0 +ShowMotionPath 1 +ShowFogRadius 0 +ShowFogEffect 0 +ShowFieldChart 0 +OverlayColor_fv 0 0 0 +MeshBackgroundGroup 1 + +CurrentObject 0 +CurrentLight 0 +CurrentCamera 0 +GraphEditorData +{ GraphEd_Favorites +} +{ GE_Expression_Lib + 1 +} +ImageEditorData +NumberOfClips 0 diff --git a/test/models/LWS/simple_cube.lwo b/test/models/LWS/simple_cube.lwo new file mode 100644 index 000000000..aac49498b Binary files /dev/null and b/test/models/LWS/simple_cube.lwo differ diff --git a/test/models/MDL/IDPO (Quake1)/gijoe-readme.txt b/test/models/MDL/IDPO (Quake1)/gijoe-readme.txt new file mode 100644 index 000000000..93afb7cb1 --- /dev/null +++ b/test/models/MDL/IDPO (Quake1)/gijoe-readme.txt @@ -0,0 +1,73 @@ +Title : G.I.Joe Skins +Filename : joemodel.zip +Version : 1 +Date : 11/05/97 +Author : Kenneth Whelan +Email : JWHELAN@pop.prodigy.net +Credits : id software, Larry Hama, Steven Polge, and Rene Post for making Quake ME + + + +Build time: ??? Time??? + +Type of Mod +----------- +Quake C : no +Sound : no +MDL : Yes + + +Format of QuakeC (if a Quake C Mod) +----------------------------------- +unified diff : no +context diff : no +.qc files : no +progs.dat : no + + +Description of the Modification +------------------------------- + +This is a new player.mdl for quake. It's main use is for bots. The Skins are Snake Eyes v4, Duke v3, Low-Light, +Storm Shadow v2, Shockwave, Repeater, Gung-Ho, Shipwreck, Dusty v3, and +Tunnel Rat v2. + + + +Known bugs +None that I know of. + +How to Install the Modification +------------------------------- + +First back up the current player.mdl(copy player.mdl player.bak). Just put +it in the progs dir in the hack your using, if any. + +Technical Details +----------------- + +can't think of any + + +Author Information +------------------ + +This is my first publicly distributed quake graphic change. +I did it to get away from the stress of school. + + +Copyright and Distribution Permissions +-------------------------------------- + +You may distribute this Quake modification in any electronic format as long as + all the files in this archive remain intact and unmodified and are distributed + together. + + +Availability +------------ + +This modification is available from the following places: + + http://www.yojoe.com/ + diff --git a/test/models/MDL/IDPO (Quake1)/gijoe.mdl b/test/models/MDL/IDPO (Quake1)/gijoe.mdl new file mode 100644 index 000000000..81fed1fc4 Binary files /dev/null and b/test/models/MDL/IDPO (Quake1)/gijoe.mdl differ diff --git a/test/models/OFF/formatDetection b/test/models/OFF/formatDetection new file mode 100644 index 000000000..597158fd1 --- /dev/null +++ b/test/models/OFF/formatDetection @@ -0,0 +1,16 @@ +OFF +8 6 0 +-0.500000 -0.500000 0.500000 +0.500000 -0.500000 0.500000 +-0.500000 0.500000 0.500000 +0.500000 0.500000 0.500000 +-0.500000 0.500000 -0.500000 +0.500000 0.500000 -0.500000 +-0.500000 -0.500000 -0.500000 +0.500000 -0.500000 -0.500000 +4 0 1 3 2 +4 2 3 5 4 +4 4 5 7 6 +4 6 7 1 0 +4 1 7 5 3 +4 6 0 2 4 diff --git a/test/models/STL/Spider_ascii.stl b/test/models/STL/Spider_ascii.stl new file mode 100644 index 000000000..c91d27bf0 --- /dev/null +++ b/test/models/STL/Spider_ascii.stl @@ -0,0 +1,9578 @@ +solid NoName_1 + facet normal 0.468282 -0.863498 -0.187306 + outer loop + vertex 0.907128 0.646165 0.795193 + vertex 1.655401 1.111567 0.520398 + vertex 0.766146 0.680483 0.284519 + endloop + endfacet + facet normal 0.373241 -0.860316 -0.347200 + outer loop + vertex 1.856645 0.887426 1.218116 + vertex 0.907128 0.646165 0.795193 + vertex 1.313948 0.554956 1.458532 + endloop + endfacet + facet normal -0.148455 -0.953197 -0.263395 + outer loop + vertex 1.655401 1.111567 0.520398 + vertex 1.856645 0.887426 1.218116 + vertex 2.339231 0.936288 0.769292 + endloop + endfacet + facet normal 0.383431 -0.841372 -0.380884 + outer loop + vertex 1.856645 0.887426 1.218116 + vertex 1.655401 1.111567 0.520398 + vertex 0.907128 0.646165 0.795193 + endloop + endfacet + facet normal 0.562677 -0.799798 -0.209085 + outer loop + vertex 0.451615 0.391451 0.543683 + vertex 0.907128 0.646165 0.795193 + vertex 0.766146 0.680483 0.284519 + endloop + endfacet + facet normal 0.807133 -0.364619 -0.464316 + outer loop + vertex 0.681458 0.234029 1.066846 + vertex 0.451615 0.391451 0.543683 + vertex 0.382212 -0.020684 0.746682 + endloop + endfacet + facet normal 0.612119 -0.640684 -0.463502 + outer loop + vertex 0.907128 0.646165 0.795193 + vertex 0.681458 0.234029 1.066846 + vertex 1.313948 0.554956 1.458532 + endloop + endfacet + facet normal 0.613334 -0.640478 -0.462180 + outer loop + vertex 0.681458 0.234029 1.066846 + vertex 0.907128 0.646165 0.795193 + vertex 0.451615 0.391451 0.543683 + endloop + endfacet + facet normal 0.730571 0.000000 -0.682837 + outer loop + vertex 0.681458 -0.275398 1.066846 + vertex 0.681458 0.234029 1.066846 + vertex 0.382212 -0.020684 0.746682 + endloop + endfacet + facet normal 0.622256 0.257774 -0.739155 + outer loop + vertex 1.253999 -0.062053 1.623241 + vertex 0.681458 -0.275398 1.066846 + vertex 1.313948 -0.679062 1.458532 + endloop + endfacet + facet normal 0.600342 -0.260203 -0.756230 + outer loop + vertex 0.681458 0.234029 1.066846 + vertex 1.253999 -0.062053 1.623241 + vertex 1.313948 0.554956 1.458532 + endloop + endfacet + facet normal 0.696922 0.000000 -0.717147 + outer loop + vertex 1.253999 -0.062053 1.623241 + vertex 0.681458 0.234029 1.066846 + vertex 0.681458 -0.275398 1.066846 + endloop + endfacet + facet normal 0.168448 -0.269475 -0.948160 + outer loop + vertex 1.253999 -0.062053 1.623241 + vertex 1.981021 0.300615 1.649329 + vertex 1.313948 0.554956 1.458532 + endloop + endfacet + facet normal 0.168448 0.269475 -0.948160 + outer loop + vertex 1.981021 -0.424722 1.649329 + vertex 1.253999 -0.062053 1.623241 + vertex 1.313948 -0.679062 1.458532 + endloop + endfacet + facet normal -0.248867 0.000000 -0.968538 + outer loop + vertex 1.981021 0.300615 1.649329 + vertex 1.981021 -0.424722 1.649329 + vertex 2.550832 -0.062053 1.502915 + endloop + endfacet + facet normal 0.035860 0.000000 -0.999357 + outer loop + vertex 1.981021 -0.424722 1.649329 + vertex 1.981021 0.300615 1.649329 + vertex 1.253999 -0.062053 1.623241 + endloop + endfacet + facet normal 0.005124 -0.591441 -0.806332 + outer loop + vertex 1.981021 0.300615 1.649329 + vertex 1.856645 0.887426 1.218116 + vertex 1.313948 0.554956 1.458532 + endloop + endfacet + facet normal -0.432703 -0.343308 -0.833611 + outer loop + vertex 2.583668 0.524757 1.244204 + vertex 1.981021 0.300615 1.649329 + vertex 2.550832 -0.062053 1.502915 + endloop + endfacet + facet normal -0.375216 -0.787361 -0.489158 + outer loop + vertex 1.856645 0.887426 1.218116 + vertex 2.583668 0.524757 1.244204 + vertex 2.339231 0.936288 0.769292 + endloop + endfacet + facet normal -0.275769 -0.606463 -0.745757 + outer loop + vertex 2.583668 0.524757 1.244204 + vertex 1.856645 0.887426 1.218116 + vertex 1.981021 0.300615 1.649329 + endloop + endfacet + facet normal -0.241511 -0.380123 -0.892849 + outer loop + vertex 3.114895 -0.062053 1.350339 + vertex 2.583668 0.524757 1.244204 + vertex 2.550832 -0.062053 1.502915 + endloop + endfacet + facet normal -0.950931 -0.278835 0.134094 + outer loop + vertex 2.831748 0.524757 0.562609 + vertex 3.114895 -0.062053 1.350339 + vertex 2.972891 -0.062053 0.343318 + endloop + endfacet + facet normal -0.680310 -0.689831 -0.247613 + outer loop + vertex 2.583668 0.524757 1.244204 + vertex 2.831748 0.524757 0.562609 + vertex 2.339231 0.936288 0.769292 + endloop + endfacet + facet normal -0.694122 -0.674069 -0.252640 + outer loop + vertex 2.831748 0.524757 0.562609 + vertex 2.583668 0.524757 1.244204 + vertex 3.114895 -0.062053 1.350339 + endloop + endfacet + facet normal -0.241511 0.380123 -0.892849 + outer loop + vertex 2.583668 -0.648863 1.244204 + vertex 3.114895 -0.062053 1.350339 + vertex 2.550832 -0.062053 1.502915 + endloop + endfacet + facet normal -0.680310 0.689830 -0.247613 + outer loop + vertex 2.831748 -0.648863 0.562609 + vertex 2.583668 -0.648863 1.244204 + vertex 2.339231 -1.060395 0.769292 + endloop + endfacet + facet normal -0.950931 0.278835 0.134094 + outer loop + vertex 3.114895 -0.062053 1.350339 + vertex 2.831748 -0.648863 0.562609 + vertex 2.972891 -0.062053 0.343318 + endloop + endfacet + facet normal -0.694122 0.674069 -0.252640 + outer loop + vertex 2.831748 -0.648863 0.562609 + vertex 3.114895 -0.062053 1.350339 + vertex 2.583668 -0.648863 1.244204 + endloop + endfacet + facet normal 0.005124 0.591441 -0.806332 + outer loop + vertex 1.856645 -1.011532 1.218116 + vertex 1.981021 -0.424722 1.649329 + vertex 1.313948 -0.679062 1.458532 + endloop + endfacet + facet normal -0.375216 0.787361 -0.489159 + outer loop + vertex 2.583668 -0.648863 1.244204 + vertex 1.856645 -1.011532 1.218116 + vertex 2.339231 -1.060395 0.769292 + endloop + endfacet + facet normal -0.432703 0.343308 -0.833611 + outer loop + vertex 1.981021 -0.424722 1.649329 + vertex 2.583668 -0.648863 1.244204 + vertex 2.550832 -0.062053 1.502915 + endloop + endfacet + facet normal -0.275769 0.606463 -0.745757 + outer loop + vertex 2.583668 -0.648863 1.244204 + vertex 1.981021 -0.424722 1.649329 + vertex 1.856645 -1.011532 1.218116 + endloop + endfacet + facet normal 0.415251 0.870015 -0.265782 + outer loop + vertex 0.907128 -0.687534 0.795193 + vertex 1.856645 -1.011532 1.218116 + vertex 1.313948 -0.679062 1.458532 + endloop + endfacet + facet normal 0.529567 0.823971 -0.201569 + outer loop + vertex 1.655401 -1.235674 0.520398 + vertex 0.907128 -0.687534 0.795193 + vertex 0.766146 -0.721851 0.284519 + endloop + endfacet + facet normal -0.148455 0.953197 -0.263395 + outer loop + vertex 1.856645 -1.011532 1.218116 + vertex 1.655401 -1.235674 0.520398 + vertex 2.339231 -1.060395 0.769292 + endloop + endfacet + facet normal 0.447699 0.805646 -0.387944 + outer loop + vertex 1.655401 -1.235674 0.520398 + vertex 1.856645 -1.011532 1.218116 + vertex 0.907128 -0.687534 0.795193 + endloop + endfacet + facet normal 0.410494 0.855419 0.315836 + outer loop + vertex 1.042427 -0.687534 -0.167513 + vertex 1.655401 -1.235674 0.520398 + vertex 0.766146 -0.721851 0.284519 + endloop + endfacet + facet normal 0.118899 0.867570 0.482892 + outer loop + vertex 2.258047 -1.011532 0.115273 + vertex 1.042427 -0.687534 -0.167513 + vertex 1.996854 -0.679062 -0.417736 + endloop + endfacet + facet normal -0.283030 0.953197 0.106347 + outer loop + vertex 1.655401 -1.235674 0.520398 + vertex 2.258047 -1.011532 0.115273 + vertex 2.339231 -1.060395 0.769292 + endloop + endfacet + facet normal 0.083372 0.814240 0.574511 + outer loop + vertex 2.258047 -1.011532 0.115273 + vertex 1.655401 -1.235674 0.520398 + vertex 1.042427 -0.687534 -0.167513 + endloop + endfacet + facet normal -0.514375 0.591441 0.620980 + outer loop + vertex 2.630503 -0.424722 -0.135108 + vertex 2.258047 -1.011532 0.115273 + vertex 1.996854 -0.679062 -0.417736 + endloop + endfacet + facet normal -0.867304 0.343309 0.360447 + outer loop + vertex 2.831748 -0.648863 0.562609 + vertex 2.630503 -0.424722 -0.135108 + vertex 2.972891 -0.062053 0.343318 + endloop + endfacet + facet normal -0.601857 0.787361 0.133534 + outer loop + vertex 2.258047 -1.011532 0.115273 + vertex 2.831748 -0.648863 0.562609 + vertex 2.339231 -1.060395 0.769292 + endloop + endfacet + facet normal -0.690615 0.606463 0.394022 + outer loop + vertex 2.831748 -0.648863 0.562609 + vertex 2.258047 -1.011532 0.115273 + vertex 2.630503 -0.424722 -0.135108 + endloop + endfacet + facet normal -0.480427 0.269475 0.834610 + outer loop + vertex 2.056803 -0.062053 -0.582445 + vertex 2.630503 -0.424722 -0.135108 + vertex 1.996854 -0.679062 -0.417736 + endloop + endfacet + facet normal -0.480427 -0.269475 0.834610 + outer loop + vertex 2.630503 0.300615 -0.135108 + vertex 2.056803 -0.062053 -0.582445 + vertex 1.996854 0.554956 -0.417736 + endloop + endfacet + facet normal -0.813207 0.000000 0.581975 + outer loop + vertex 2.630503 -0.424722 -0.135108 + vertex 2.630503 0.300615 -0.135108 + vertex 2.972891 -0.062053 0.343318 + endloop + endfacet + facet normal -0.614904 0.000000 0.788602 + outer loop + vertex 2.630503 0.300615 -0.135108 + vertex 2.630503 -0.424722 -0.135108 + vertex 2.056803 -0.062053 -0.582445 + endloop + endfacet + facet normal 0.029484 0.255128 0.966458 + outer loop + vertex 0.900377 -0.275398 -0.490845 + vertex 2.056803 -0.062053 -0.582445 + vertex 1.996854 -0.679062 -0.417736 + endloop + endfacet + facet normal 0.514055 0.000000 0.857758 + outer loop + vertex 0.900377 0.234029 -0.490845 + vertex 0.900377 -0.275398 -0.490845 + vertex 0.524475 -0.020684 -0.265567 + endloop + endfacet + facet normal 0.010764 -0.256924 0.966372 + outer loop + vertex 2.056803 -0.062053 -0.582445 + vertex 0.900377 0.234029 -0.490845 + vertex 1.996854 0.554956 -0.417736 + endloop + endfacet + facet normal 0.078962 0.000000 0.996878 + outer loop + vertex 0.900377 0.234029 -0.490845 + vertex 2.056803 -0.062053 -0.582445 + vertex 0.900377 -0.275398 -0.490845 + endloop + endfacet + facet normal 0.647884 -0.364619 0.668805 + outer loop + vertex 0.535235 0.391451 -0.051302 + vertex 0.900377 0.234029 -0.490845 + vertex 0.524475 -0.020684 -0.265567 + endloop + endfacet + facet normal 0.483248 -0.799798 0.356081 + outer loop + vertex 1.042427 0.646165 -0.167513 + vertex 0.535235 0.391451 -0.051302 + vertex 0.766146 0.680483 0.284519 + endloop + endfacet + facet normal 0.136987 -0.640223 0.755877 + outer loop + vertex 0.900377 0.234029 -0.490845 + vertex 1.042427 0.646165 -0.167513 + vertex 1.996854 0.554956 -0.417736 + endloop + endfacet + facet normal 0.462180 -0.640478 0.613333 + outer loop + vertex 1.042427 0.646165 -0.167513 + vertex 0.900377 0.234029 -0.490845 + vertex 0.535235 0.391451 -0.051302 + endloop + endfacet + facet normal 0.355839 -0.890012 0.285057 + outer loop + vertex 1.655401 1.111567 0.520398 + vertex 1.042427 0.646165 -0.167513 + vertex 0.766146 0.680483 0.284519 + endloop + endfacet + facet normal -0.283030 -0.953197 0.106347 + outer loop + vertex 2.258047 0.887426 0.115273 + vertex 1.655401 1.111567 0.520398 + vertex 2.339231 0.936288 0.769292 + endloop + endfacet + facet normal 0.051708 -0.858517 0.510171 + outer loop + vertex 1.042427 0.646165 -0.167513 + vertex 2.258047 0.887426 0.115273 + vertex 1.996854 0.554956 -0.417736 + endloop + endfacet + facet normal 0.043802 -0.845141 0.532745 + outer loop + vertex 2.258047 0.887426 0.115273 + vertex 1.042427 0.646165 -0.167513 + vertex 1.655401 1.111567 0.520398 + endloop + endfacet + facet normal -0.514375 -0.591441 0.620980 + outer loop + vertex 2.258047 0.887426 0.115273 + vertex 2.630503 0.300615 -0.135108 + vertex 1.996854 0.554956 -0.417736 + endloop + endfacet + facet normal -0.601857 -0.787361 0.133533 + outer loop + vertex 2.831748 0.524757 0.562609 + vertex 2.258047 0.887426 0.115273 + vertex 2.339231 0.936288 0.769292 + endloop + endfacet + facet normal -0.867304 -0.343309 0.360447 + outer loop + vertex 2.630503 0.300615 -0.135108 + vertex 2.831748 0.524757 0.562609 + vertex 2.972891 -0.062053 0.343318 + endloop + endfacet + facet normal -0.690615 -0.606464 0.394022 + outer loop + vertex 2.831748 0.524757 0.562609 + vertex 2.630503 0.300615 -0.135108 + vertex 2.258047 0.887426 0.115273 + endloop + endfacet + facet normal 0.964518 -0.227996 -0.133130 + outer loop + vertex 0.451615 0.391451 0.543683 + vertex 0.309564 -0.020684 0.220351 + vertex 0.382212 -0.020684 0.746682 + endloop + endfacet + facet normal 0.716926 -0.689830 0.100757 + outer loop + vertex 0.535235 0.391451 -0.051302 + vertex 0.451615 0.391451 0.543683 + vertex 0.766146 0.680483 0.284519 + endloop + endfacet + facet normal 0.890458 -0.227996 0.393830 + outer loop + vertex 0.309564 -0.020684 0.220351 + vertex 0.535235 0.391451 -0.051302 + vertex 0.524475 -0.020684 -0.265567 + endloop + endfacet + facet normal 0.902877 -0.410744 0.126891 + outer loop + vertex 0.535235 0.391451 -0.051302 + vertex 0.309564 -0.020684 0.220351 + vertex 0.451615 0.391451 0.543683 + endloop + endfacet + facet normal 0.964518 0.227996 -0.133130 + outer loop + vertex 0.309564 -0.020684 0.220351 + vertex 0.451615 -0.432820 0.543683 + vertex 0.382212 -0.020684 0.746682 + endloop + endfacet + facet normal 0.890458 0.227996 0.393830 + outer loop + vertex 0.535235 -0.432820 -0.051302 + vertex 0.309564 -0.020684 0.220351 + vertex 0.524475 -0.020684 -0.265567 + endloop + endfacet + facet normal 0.716926 0.689830 0.100757 + outer loop + vertex 0.451615 -0.432820 0.543683 + vertex 0.535235 -0.432820 -0.051302 + vertex 0.766146 -0.721851 0.284519 + endloop + endfacet + facet normal 0.902877 0.410744 0.126891 + outer loop + vertex 0.535235 -0.432820 -0.051302 + vertex 0.451615 -0.432820 0.543683 + vertex 0.309564 -0.020684 0.220351 + endloop + endfacet + facet normal 0.807133 0.364619 -0.464316 + outer loop + vertex 0.451615 -0.432820 0.543683 + vertex 0.681458 -0.275398 1.066846 + vertex 0.382212 -0.020684 0.746682 + endloop + endfacet + facet normal 0.562677 0.799798 -0.209086 + outer loop + vertex 0.907128 -0.687534 0.795193 + vertex 0.451615 -0.432820 0.543683 + vertex 0.766146 -0.721851 0.284519 + endloop + endfacet + facet normal 0.657568 0.631190 -0.411343 + outer loop + vertex 0.681458 -0.275398 1.066846 + vertex 0.907128 -0.687534 0.795193 + vertex 1.313948 -0.679062 1.458532 + endloop + endfacet + facet normal 0.613334 0.640478 -0.462180 + outer loop + vertex 0.907128 -0.687534 0.795193 + vertex 0.681458 -0.275398 1.066846 + vertex 0.451615 -0.432820 0.543683 + endloop + endfacet + facet normal 0.188311 0.645559 0.740130 + outer loop + vertex 1.042427 -0.687534 -0.167513 + vertex 0.900377 -0.275398 -0.490845 + vertex 1.996854 -0.679062 -0.417736 + endloop + endfacet + facet normal 0.483248 0.799798 0.356081 + outer loop + vertex 0.535235 -0.432820 -0.051302 + vertex 1.042427 -0.687534 -0.167513 + vertex 0.766146 -0.721851 0.284519 + endloop + endfacet + facet normal 0.647883 0.364619 0.668805 + outer loop + vertex 0.900377 -0.275398 -0.490845 + vertex 0.535235 -0.432820 -0.051302 + vertex 0.524475 -0.020684 -0.265567 + endloop + endfacet + facet normal 0.462180 0.640478 0.613333 + outer loop + vertex 0.535235 -0.432820 -0.051302 + vertex 0.900377 -0.275398 -0.490845 + vertex 1.042427 -0.687534 -0.167513 + endloop + endfacet + facet normal -0.432697 -0.859040 0.273538 + outer loop + vertex -0.631551 0.764486 0.547108 + vertex -0.438125 0.541163 0.151739 + vertex -1.013416 0.803828 0.066608 + endloop + endfacet + facet normal -0.541727 -0.466255 -0.699385 + outer loop + vertex -0.060684 0.437810 0.322711 + vertex -0.631551 0.764486 0.547108 + vertex -0.291320 0.284506 0.603558 + endloop + endfacet + facet normal -0.175983 -0.964927 -0.194797 + outer loop + vertex -0.438125 0.541163 0.151739 + vertex -0.060684 0.437810 0.322711 + vertex 0.253932 0.460341 -0.073124 + endloop + endfacet + facet normal -0.378487 -0.872899 0.307887 + outer loop + vertex -0.060684 0.437810 0.322711 + vertex -0.438125 0.541163 0.151739 + vertex -0.631551 0.764486 0.547108 + endloop + endfacet + facet normal 0.429853 -0.805670 -0.407581 + outer loop + vertex -1.138573 0.472478 0.589594 + vertex -0.631551 0.764486 0.547108 + vertex -1.013416 0.803828 0.066608 + endloop + endfacet + facet normal 0.334310 -0.263623 -0.904842 + outer loop + vertex -0.753356 0.292008 0.784499 + vertex -1.138573 0.472478 0.589594 + vertex -1.137030 0.000000 0.727819 + endloop + endfacet + facet normal -0.346726 -0.348206 -0.870938 + outer loop + vertex -0.631551 0.764486 0.547108 + vertex -0.753356 0.292008 0.784499 + vertex -0.291320 0.284506 0.603558 + endloop + endfacet + facet normal 0.205720 -0.481182 -0.852140 + outer loop + vertex -0.753356 0.292008 0.784499 + vertex -0.631551 0.764486 0.547108 + vertex -1.138573 0.472478 0.589594 + endloop + endfacet + facet normal 0.146142 0.000000 -0.989264 + outer loop + vertex -0.753356 -0.292008 0.784499 + vertex -0.753356 0.292008 0.784499 + vertex -1.137030 0.000000 0.727819 + endloop + endfacet + facet normal -0.353928 0.280805 -0.892123 + outer loop + vertex -0.265545 0.000000 0.682884 + vertex -0.753356 -0.292008 0.784499 + vertex -0.291320 -0.284506 0.603558 + endloop + endfacet + facet normal -0.353928 -0.280805 -0.892123 + outer loop + vertex -0.753356 0.292008 0.784499 + vertex -0.265545 0.000000 0.682884 + vertex -0.291320 0.284506 0.603558 + endloop + endfacet + facet normal -0.203930 0.000000 -0.978985 + outer loop + vertex -0.265545 0.000000 0.682884 + vertex -0.753356 0.292008 0.784499 + vertex -0.753356 -0.292008 0.784499 + endloop + endfacet + facet normal -0.370298 -0.280459 -0.885563 + outer loop + vertex -0.265545 0.000000 0.682884 + vertex 0.369308 0.167229 0.364459 + vertex -0.291320 0.284506 0.603558 + endloop + endfacet + facet normal -0.370298 0.280459 -0.885563 + outer loop + vertex 0.369308 -0.167229 0.364459 + vertex -0.265545 0.000000 0.682884 + vertex -0.291320 -0.284506 0.603558 + endloop + endfacet + facet normal -0.601119 0.000000 -0.799159 + outer loop + vertex 0.369308 0.167229 0.364459 + vertex 0.369308 -0.167229 0.364459 + vertex 0.662828 0.000000 0.143676 + endloop + endfacet + facet normal -0.448338 0.000000 -0.893864 + outer loop + vertex 0.369308 -0.167229 0.364459 + vertex 0.369308 0.167229 0.364459 + vertex -0.265545 0.000000 0.682884 + endloop + endfacet + facet normal -0.355542 -0.666160 -0.655607 + outer loop + vertex 0.369308 0.167229 0.364459 + vertex -0.060684 0.437810 0.322711 + vertex -0.291320 0.284506 0.603558 + endloop + endfacet + facet normal -0.681212 -0.339002 -0.648867 + outer loop + vertex 0.581242 0.389086 0.026050 + vertex 0.369308 0.167229 0.364459 + vertex 0.662828 0.000000 0.143676 + endloop + endfacet + facet normal -0.156875 -0.971084 -0.179961 + outer loop + vertex -0.060684 0.437810 0.322711 + vertex 0.581242 0.389086 0.026050 + vertex 0.253932 0.460341 -0.073124 + endloop + endfacet + facet normal -0.354409 -0.664684 -0.657715 + outer loop + vertex 0.581242 0.389086 0.026050 + vertex -0.060684 0.437810 0.322711 + vertex 0.369308 0.167229 0.364459 + endloop + endfacet + facet normal -0.967072 -0.233436 -0.101392 + outer loop + vertex 0.700781 0.000000 -0.218314 + vertex 0.581242 0.389086 0.026050 + vertex 0.662828 0.000000 0.143676 + endloop + endfacet + facet normal -0.722781 -0.233436 0.650459 + outer loop + vertex 0.460438 0.389086 -0.345746 + vertex 0.700781 0.000000 -0.218314 + vertex 0.457304 0.000000 -0.488862 + endloop + endfacet + facet normal -0.234045 -0.969247 0.076046 + outer loop + vertex 0.581242 0.389086 0.026050 + vertex 0.460438 0.389086 -0.345746 + vertex 0.253932 0.460341 -0.073124 + endloop + endfacet + facet normal -0.855296 -0.437310 0.277902 + outer loop + vertex 0.460438 0.389086 -0.345746 + vertex 0.581242 0.389086 0.026050 + vertex 0.700781 0.000000 -0.218314 + endloop + endfacet + facet normal -0.967072 0.233436 -0.101392 + outer loop + vertex 0.581242 -0.389086 0.026050 + vertex 0.700781 0.000000 -0.218314 + vertex 0.662828 0.000000 0.143676 + endloop + endfacet + facet normal -0.234045 0.969247 0.076046 + outer loop + vertex 0.460438 -0.389086 -0.345746 + vertex 0.581242 -0.389086 0.026050 + vertex 0.253932 -0.460341 -0.073124 + endloop + endfacet + facet normal -0.722780 0.233436 0.650458 + outer loop + vertex 0.700781 0.000000 -0.218314 + vertex 0.460438 -0.389086 -0.345746 + vertex 0.457304 0.000000 -0.488862 + endloop + endfacet + facet normal -0.855296 0.437310 0.277902 + outer loop + vertex 0.460438 -0.389086 -0.345746 + vertex 0.700781 0.000000 -0.218314 + vertex 0.581242 -0.389086 0.026050 + endloop + endfacet + facet normal -0.355542 0.666160 -0.655608 + outer loop + vertex -0.060684 -0.437810 0.322711 + vertex 0.369308 -0.167229 0.364459 + vertex -0.291320 -0.284506 0.603558 + endloop + endfacet + facet normal -0.156875 0.971084 -0.179960 + outer loop + vertex 0.581242 -0.389086 0.026050 + vertex -0.060684 -0.437810 0.322711 + vertex 0.253932 -0.460341 -0.073124 + endloop + endfacet + facet normal -0.681212 0.339002 -0.648867 + outer loop + vertex 0.369308 -0.167229 0.364459 + vertex 0.581242 -0.389086 0.026050 + vertex 0.662828 0.000000 0.143676 + endloop + endfacet + facet normal -0.354409 0.664684 -0.657715 + outer loop + vertex 0.581242 -0.389086 0.026050 + vertex 0.369308 -0.167229 0.364459 + vertex -0.060684 -0.437810 0.322711 + endloop + endfacet + facet normal -0.541727 0.466255 -0.699385 + outer loop + vertex -0.631551 -0.764486 0.547108 + vertex -0.060684 -0.437810 0.322711 + vertex -0.291320 -0.284506 0.603558 + endloop + endfacet + facet normal -0.432697 0.859040 0.273538 + outer loop + vertex -0.438125 -0.541163 0.151739 + vertex -0.631551 -0.764486 0.547108 + vertex -1.013416 -0.803828 0.066608 + endloop + endfacet + facet normal -0.175983 0.964927 -0.194797 + outer loop + vertex -0.060684 -0.437810 0.322711 + vertex -0.438125 -0.541163 0.151739 + vertex 0.253932 -0.460341 -0.073124 + endloop + endfacet + facet normal -0.378487 0.872899 0.307887 + outer loop + vertex -0.438125 -0.541163 0.151739 + vertex -0.060684 -0.437810 0.322711 + vertex -0.631551 -0.764486 0.547108 + endloop + endfacet + facet normal -0.411905 0.910833 -0.026765 + outer loop + vertex -0.903297 -0.764486 -0.289242 + vertex -0.438125 -0.541163 0.151739 + vertex -1.013416 -0.803828 0.066608 + endloop + endfacet + facet normal -0.188857 0.147192 0.970911 + outer loop + vertex -0.233263 -0.437810 -0.208435 + vertex -0.903297 -0.764486 -0.289242 + vertex -0.584930 -0.284506 -0.300080 + endloop + endfacet + facet normal -0.027874 0.964927 0.261034 + outer loop + vertex -0.438125 -0.541163 0.151739 + vertex -0.233263 -0.437810 -0.208435 + vertex 0.253932 -0.460341 -0.073124 + endloop + endfacet + facet normal -0.439015 0.898443 0.008106 + outer loop + vertex -0.233263 -0.437810 -0.208435 + vertex -0.438125 -0.541163 0.151739 + vertex -0.903297 -0.764486 -0.289242 + endloop + endfacet + facet normal -0.021137 0.971084 0.237800 + outer loop + vertex -0.233263 -0.437810 -0.208435 + vertex 0.460438 -0.389086 -0.345746 + vertex 0.253932 -0.460341 -0.073124 + endloop + endfacet + facet normal 0.645767 -0.710955 0.278437 + outer loop + vertex -0.903297 0.764486 -0.289242 + vertex -1.338460 0.472478 -0.025593 + vertex -1.013416 0.803828 0.066608 + endloop + endfacet + facet normal -0.411905 -0.910833 -0.026765 + outer loop + vertex -0.438125 0.541163 0.151739 + vertex -0.903297 0.764486 -0.289242 + vertex -1.013416 0.803828 0.066608 + endloop + endfacet + facet normal -0.027874 -0.964927 0.261035 + outer loop + vertex -0.233263 0.437810 -0.208435 + vertex -0.438125 0.541163 0.151739 + vertex 0.253932 0.460341 -0.073124 + endloop + endfacet + facet normal -0.188857 -0.147192 0.970911 + outer loop + vertex -0.903297 0.764486 -0.289242 + vertex -0.233263 0.437810 -0.208435 + vertex -0.584930 0.284506 -0.300080 + endloop + endfacet + facet normal -0.439015 -0.898443 0.008106 + outer loop + vertex -0.233263 0.437810 -0.208435 + vertex -0.903297 0.764486 -0.289242 + vertex -0.438125 0.541163 0.151739 + endloop + endfacet + facet normal -0.021137 -0.971084 0.237800 + outer loop + vertex 0.460438 0.389086 -0.345746 + vertex -0.233263 0.437810 -0.208435 + vertex 0.253932 0.460341 -0.073124 + endloop + endfacet + facet normal 0.719866 -0.192729 -0.666820 + outer loop + vertex -1.138573 0.472478 0.589594 + vertex -1.376651 0.000000 0.469136 + vertex -1.137030 0.000000 0.727819 + endloop + endfacet + facet normal 0.725731 -0.646305 -0.235805 + outer loop + vertex -1.338460 0.472478 -0.025593 + vertex -1.138573 0.472478 0.589594 + vertex -1.013416 0.803828 0.066608 + endloop + endfacet + facet normal 0.986233 -0.150788 -0.067873 + outer loop + vertex -1.376651 0.000000 0.469136 + vertex -1.338460 0.472478 -0.025593 + vertex -1.418457 0.000000 -0.138327 + endloop + endfacet + facet normal 0.882898 -0.371747 -0.286871 + outer loop + vertex -1.338460 0.472478 -0.025593 + vertex -1.376651 0.000000 0.469136 + vertex -1.138573 0.472478 0.589594 + endloop + endfacet + facet normal 0.719866 0.192729 -0.666820 + outer loop + vertex -1.376651 0.000000 0.469136 + vertex -1.138573 -0.472478 0.589594 + vertex -1.137030 0.000000 0.727819 + endloop + endfacet + facet normal 0.986233 0.150789 -0.067873 + outer loop + vertex -1.338460 -0.472478 -0.025593 + vertex -1.376651 0.000000 0.469136 + vertex -1.418457 0.000000 -0.138327 + endloop + endfacet + facet normal 0.725731 0.646305 -0.235805 + outer loop + vertex -1.138573 -0.472478 0.589594 + vertex -1.338460 -0.472478 -0.025593 + vertex -1.013416 -0.803828 0.066608 + endloop + endfacet + facet normal 0.882898 0.371748 -0.286871 + outer loop + vertex -1.338460 -0.472478 -0.025593 + vertex -1.138573 -0.472478 0.589594 + vertex -1.376651 0.000000 0.469136 + endloop + endfacet + facet normal 0.334310 0.263623 -0.904842 + outer loop + vertex -1.138573 -0.472478 0.589594 + vertex -0.753356 -0.292008 0.784499 + vertex -1.137030 0.000000 0.727819 + endloop + endfacet + facet normal 0.429853 0.805670 -0.407581 + outer loop + vertex -0.631551 -0.764486 0.547108 + vertex -1.138573 -0.472478 0.589594 + vertex -1.013416 -0.803828 0.066608 + endloop + endfacet + facet normal -0.346726 0.348206 -0.870938 + outer loop + vertex -0.753356 -0.292008 0.784499 + vertex -0.631551 -0.764486 0.547108 + vertex -0.291320 -0.284506 0.603558 + endloop + endfacet + facet normal 0.205720 0.481182 -0.852140 + outer loop + vertex -0.631551 -0.764486 0.547108 + vertex -0.753356 -0.292008 0.784499 + vertex -1.138573 -0.472478 0.589594 + endloop + endfacet + facet normal 0.645768 0.710955 0.278437 + outer loop + vertex -1.338460 -0.472478 -0.025593 + vertex -0.903297 -0.764486 -0.289242 + vertex -1.013416 -0.803828 0.066608 + endloop + endfacet + facet normal -0.021383 -0.399432 0.916514 + outer loop + vertex -1.128773 -0.458771 -0.044633 + vertex -1.017831 -0.351024 0.004914 + vertex -0.964388 -0.470329 -0.045835 + endloop + endfacet + facet normal 0.781845 0.449936 0.431597 + outer loop + vertex -2.920253 -3.899432 -1.534378 + vertex -2.916979 -3.882807 -1.557641 + vertex -2.906007 -3.903219 -1.556237 + endloop + endfacet + facet normal -0.945810 0.167999 -0.277883 + outer loop + vertex -1.232261 -1.145156 0.457925 + vertex -1.230263 -1.223898 0.403520 + vertex -0.964388 -0.470329 -0.045835 + endloop + endfacet + facet normal -0.805882 -0.113844 -0.581028 + outer loop + vertex -1.017831 -0.351024 0.004914 + vertex -1.232261 -1.145156 0.457925 + vertex -0.964388 -0.470329 -0.045835 + endloop + endfacet + facet normal -0.942645 0.173226 -0.285331 + outer loop + vertex -1.232261 -1.145156 0.457925 + vertex -1.575499 -1.696975 1.256863 + vertex -1.230263 -1.223898 0.403520 + endloop + endfacet + facet normal -0.941975 0.154292 -0.298121 + outer loop + vertex -1.232261 -1.145156 0.457925 + vertex -1.590448 -1.669669 1.318229 + vertex -1.575499 -1.696975 1.256863 + endloop + endfacet + facet normal -0.747971 0.285770 -0.599062 + outer loop + vertex -1.678477 -1.863228 1.306131 + vertex -1.615599 -1.845137 1.236253 + vertex -1.575499 -1.696975 1.256863 + endloop + endfacet + facet normal -0.832129 0.402305 -0.381723 + outer loop + vertex -1.590448 -1.669669 1.318229 + vertex -1.678477 -1.863228 1.306131 + vertex -1.575499 -1.696975 1.256863 + endloop + endfacet + facet normal -0.673662 0.581969 -0.455512 + outer loop + vertex -1.678477 -1.863228 1.306131 + vertex -2.094317 -2.855290 0.653648 + vertex -1.615599 -1.845137 1.236253 + endloop + endfacet + facet normal -0.556548 0.606641 -0.567663 + outer loop + vertex -1.678477 -1.863228 1.306131 + vertex -2.173273 -2.901780 0.681377 + vertex -2.094317 -2.855290 0.653648 + endloop + endfacet + facet normal -0.405424 0.861934 -0.304469 + outer loop + vertex -2.706306 -3.775590 -1.136756 + vertex -2.660793 -3.776623 -1.200285 + vertex -2.094317 -2.855290 0.653648 + endloop + endfacet + facet normal -0.551748 0.803282 -0.224305 + outer loop + vertex -2.173273 -2.901780 0.681377 + vertex -2.706306 -3.775590 -1.136756 + vertex -2.094317 -2.855290 0.653648 + endloop + endfacet + facet normal -0.230881 0.956007 -0.180954 + outer loop + vertex -2.706306 -3.775590 -1.136756 + vertex -2.906007 -3.903219 -1.556237 + vertex -2.660793 -3.776623 -1.200285 + endloop + endfacet + facet normal -0.112019 0.964274 -0.240056 + outer loop + vertex -2.706306 -3.775590 -1.136756 + vertex -2.920253 -3.899432 -1.534378 + vertex -2.906007 -3.903219 -1.556237 + endloop + endfacet + facet normal -0.021386 -0.399429 0.916515 + outer loop + vertex -1.128773 -0.458771 -0.044633 + vertex -1.154815 -0.312854 0.018352 + vertex -1.017831 -0.351024 0.004914 + endloop + endfacet + facet normal 0.781793 0.449994 0.431631 + outer loop + vertex -2.932034 -3.883127 -1.530038 + vertex -2.916979 -3.882807 -1.557641 + vertex -2.920253 -3.899432 -1.534378 + endloop + endfacet + facet normal -0.208629 -0.441484 -0.872677 + outer loop + vertex -1.154815 -0.312854 0.018352 + vertex -1.232261 -1.145156 0.457925 + vertex -1.017831 -0.351024 0.004914 + endloop + endfacet + facet normal -0.460988 -0.380509 -0.801688 + outer loop + vertex -1.154815 -0.312854 0.018352 + vertex -1.303237 -1.081824 0.468678 + vertex -1.232261 -1.145156 0.457925 + endloop + endfacet + facet normal -0.578610 -0.566799 -0.586472 + outer loop + vertex -1.636777 -1.636377 1.331761 + vertex -1.590448 -1.669669 1.318229 + vertex -1.232261 -1.145156 0.457925 + endloop + endfacet + facet normal -0.587184 -0.558590 -0.585826 + outer loop + vertex -1.303237 -1.081824 0.468678 + vertex -1.636777 -1.636377 1.331761 + vertex -1.232261 -1.145156 0.457925 + endloop + endfacet + facet normal -0.181255 0.143246 -0.972948 + outer loop + vertex -1.636777 -1.636377 1.331761 + vertex -1.678477 -1.863228 1.306131 + vertex -1.590448 -1.669669 1.318229 + endloop + endfacet + facet normal -0.106968 0.131019 -0.985592 + outer loop + vertex -1.636777 -1.636377 1.331761 + vertex -1.764490 -1.823814 1.320705 + vertex -1.678477 -1.863228 1.306131 + endloop + endfacet + facet normal 0.127293 0.466053 -0.875552 + outer loop + vertex -2.263256 -2.869378 0.685542 + vertex -2.173273 -2.901780 0.681377 + vertex -1.678477 -1.863228 1.306131 + endloop + endfacet + facet normal 0.077594 0.490328 -0.868077 + outer loop + vertex -1.764490 -1.823814 1.320705 + vertex -2.263256 -2.869378 0.685542 + vertex -1.678477 -1.863228 1.306131 + endloop + endfacet + facet normal 0.277229 0.831728 -0.481012 + outer loop + vertex -2.263256 -2.869378 0.685542 + vertex -2.706306 -3.775590 -1.136756 + vertex -2.173273 -2.901780 0.681377 + endloop + endfacet + facet normal 0.557430 0.681362 -0.474361 + outer loop + vertex -2.263256 -2.869378 0.685542 + vertex -2.735109 -3.742669 -1.123315 + vertex -2.706306 -3.775590 -1.136756 + endloop + endfacet + facet normal 0.622136 0.587330 -0.517678 + outer loop + vertex -2.932034 -3.883127 -1.530038 + vertex -2.920253 -3.899432 -1.534378 + vertex -2.706306 -3.775590 -1.136756 + endloop + endfacet + facet normal 0.542568 0.677462 -0.496654 + outer loop + vertex -2.735109 -3.742669 -1.123315 + vertex -2.932034 -3.883127 -1.530038 + vertex -2.706306 -3.775590 -1.136756 + endloop + endfacet + facet normal -0.021384 -0.399428 0.916515 + outer loop + vertex -1.128773 -0.458771 -0.044633 + vertex -1.272189 -0.384565 -0.015639 + vertex -1.154815 -0.312854 0.018352 + endloop + endfacet + facet normal 0.781801 0.449976 0.431635 + outer loop + vertex -2.932478 -3.866581 -1.546482 + vertex -2.916979 -3.882807 -1.557641 + vertex -2.932034 -3.883127 -1.530038 + endloop + endfacet + facet normal 0.364127 -0.521987 -0.771324 + outer loop + vertex -1.389744 -1.081592 0.427683 + vertex -1.303237 -1.081824 0.468678 + vertex -1.154815 -0.312854 0.018352 + endloop + endfacet + facet normal 0.515085 -0.520164 -0.681261 + outer loop + vertex -1.272189 -0.384565 -0.015639 + vertex -1.389744 -1.081592 0.427683 + vertex -1.154815 -0.312854 0.018352 + endloop + endfacet + facet normal 0.218663 -0.857194 -0.466266 + outer loop + vertex -1.389744 -1.081592 0.427683 + vertex -1.636777 -1.636377 1.331761 + vertex -1.303237 -1.081824 0.468678 + endloop + endfacet + facet normal 0.204399 -0.858234 -0.470802 + outer loop + vertex -1.389744 -1.081592 0.427683 + vertex -1.679600 -1.622170 1.287271 + vertex -1.636777 -1.636377 1.331761 + endloop + endfacet + facet normal 0.502007 -0.294077 -0.813332 + outer loop + vertex -1.808867 -1.756572 1.269002 + vertex -1.764490 -1.823814 1.320705 + vertex -1.636777 -1.636377 1.331761 + endloop + endfacet + facet normal 0.566597 -0.451232 -0.689462 + outer loop + vertex -1.679600 -1.622170 1.287271 + vertex -1.808867 -1.756572 1.269002 + vertex -1.636777 -1.636377 1.331761 + endloop + endfacet + facet normal 0.770831 0.019108 -0.636753 + outer loop + vertex -1.808867 -1.756572 1.269002 + vertex -2.263256 -2.869378 0.685542 + vertex -1.764490 -1.823814 1.320705 + endloop + endfacet + facet normal 0.701270 0.084781 -0.707837 + outer loop + vertex -1.808867 -1.756572 1.269002 + vertex -2.296507 -2.782482 0.663007 + vertex -2.263256 -2.869378 0.685542 + endloop + endfacet + facet normal 0.940782 -0.327590 -0.087253 + outer loop + vertex -2.725511 -3.702651 -1.170079 + vertex -2.735109 -3.742669 -1.123315 + vertex -2.263256 -2.869378 0.685542 + endloop + endfacet + facet normal 0.904131 0.257567 -0.340890 + outer loop + vertex -2.296507 -2.782482 0.663007 + vertex -2.725511 -3.702651 -1.170079 + vertex -2.263256 -2.869378 0.685542 + endloop + endfacet + facet normal 0.841783 -0.483177 -0.240711 + outer loop + vertex -2.725511 -3.702651 -1.170079 + vertex -2.932034 -3.883127 -1.530038 + vertex -2.735109 -3.742669 -1.123315 + endloop + endfacet + facet normal 0.882122 -0.319912 -0.345712 + outer loop + vertex -2.725511 -3.702651 -1.170079 + vertex -2.932478 -3.866581 -1.546482 + vertex -2.932034 -3.883127 -1.530038 + endloop + endfacet + facet normal -0.021389 -0.399436 0.916512 + outer loop + vertex -1.128773 -0.458771 -0.044633 + vertex -1.281568 -0.512152 -0.071463 + vertex -1.272189 -0.384565 -0.015639 + endloop + endfacet + facet normal 0.781812 0.450064 0.431524 + outer loop + vertex -2.921253 -3.862256 -1.571330 + vertex -2.916979 -3.882807 -1.557641 + vertex -2.932478 -3.866581 -1.546482 + endloop + endfacet + facet normal 0.989923 -0.111154 0.087731 + outer loop + vertex -1.281568 -0.512152 -0.071463 + vertex -1.389744 -1.081592 0.427683 + vertex -1.272189 -0.384565 -0.015639 + endloop + endfacet + facet normal 0.917861 -0.345540 -0.195280 + outer loop + vertex -1.281568 -0.512152 -0.071463 + vertex -1.426641 -1.144634 0.365809 + vertex -1.389744 -1.081592 0.427683 + endloop + endfacet + facet normal 0.889154 -0.457447 0.012146 + outer loop + vertex -1.686670 -1.637745 1.218260 + vertex -1.679600 -1.622170 1.287271 + vertex -1.389744 -1.081592 0.427683 + endloop + endfacet + facet normal 0.870758 -0.491359 -0.018619 + outer loop + vertex -1.426641 -1.144634 0.365809 + vertex -1.686670 -1.637745 1.218260 + vertex -1.389744 -1.081592 0.427683 + endloop + endfacet + facet normal 0.712434 -0.696665 0.084239 + outer loop + vertex -1.686670 -1.637745 1.218260 + vertex -1.808867 -1.756572 1.269002 + vertex -1.679600 -1.622170 1.287271 + endloop + endfacet + facet normal 0.652189 -0.740312 -0.163056 + outer loop + vertex -1.686670 -1.637745 1.218260 + vertex -1.778190 -1.712136 1.189953 + vertex -1.808867 -1.756572 1.269002 + endloop + endfacet + facet normal 0.860250 -0.490703 0.138491 + outer loop + vertex -2.247988 -2.706529 0.630741 + vertex -2.296507 -2.782482 0.663007 + vertex -1.808867 -1.756572 1.269002 + endloop + endfacet + facet normal 0.882484 -0.463115 0.082134 + outer loop + vertex -1.778190 -1.712136 1.189953 + vertex -2.247988 -2.706529 0.630741 + vertex -1.808867 -1.756572 1.269002 + endloop + endfacet + facet normal 0.852697 -0.518845 0.060889 + outer loop + vertex -2.247988 -2.706529 0.630741 + vertex -2.725511 -3.702651 -1.170079 + vertex -2.296507 -2.782482 0.663007 + endloop + endfacet + facet normal 0.671965 -0.708992 0.213993 + outer loop + vertex -2.247988 -2.706529 0.630741 + vertex -2.684741 -3.685669 -1.241837 + vertex -2.725511 -3.702651 -1.170079 + endloop + endfacet + facet normal 0.517962 -0.851084 0.085857 + outer loop + vertex -2.921253 -3.862256 -1.571330 + vertex -2.932478 -3.866581 -1.546482 + vertex -2.725511 -3.702651 -1.170079 + endloop + endfacet + facet normal 0.512933 -0.853763 0.089375 + outer loop + vertex -2.684741 -3.685669 -1.241837 + vertex -2.921253 -3.862256 -1.571330 + vertex -2.725511 -3.702651 -1.170079 + endloop + endfacet + facet normal -0.021388 -0.399439 0.916510 + outer loop + vertex -1.128773 -0.458771 -0.044633 + vertex -1.175889 -0.599544 -0.107085 + vertex -1.281568 -0.512152 -0.071463 + endloop + endfacet + facet normal 0.781846 0.450043 0.431483 + outer loop + vertex -2.906811 -3.873407 -1.585869 + vertex -2.916979 -3.882807 -1.557641 + vertex -2.921253 -3.862256 -1.571330 + endloop + endfacet + facet normal 0.826284 0.179566 0.533864 + outer loop + vertex -1.386143 -1.223479 0.329648 + vertex -1.426641 -1.144634 0.365809 + vertex -1.281568 -0.512152 -0.071463 + endloop + endfacet + facet normal 0.545637 0.349325 0.761743 + outer loop + vertex -1.175889 -0.599544 -0.107085 + vertex -1.386143 -1.223479 0.329648 + vertex -1.281568 -0.512152 -0.071463 + endloop + endfacet + facet normal 0.872463 0.257706 0.415206 + outer loop + vertex -1.386143 -1.223479 0.329648 + vertex -1.686670 -1.637745 1.218260 + vertex -1.426641 -1.144634 0.365809 + endloop + endfacet + facet normal 0.843503 0.317460 0.433269 + outer loop + vertex -1.386143 -1.223479 0.329648 + vertex -1.652663 -1.671374 1.176695 + vertex -1.686670 -1.637745 1.218260 + endloop + endfacet + facet normal 0.305911 -0.643380 0.701770 + outer loop + vertex -1.695561 -1.723969 1.143086 + vertex -1.778190 -1.712136 1.189953 + vertex -1.686670 -1.637745 1.218260 + endloop + endfacet + facet normal 0.235419 -0.652366 0.720414 + outer loop + vertex -1.652663 -1.671374 1.176695 + vertex -1.695561 -1.723969 1.143086 + vertex -1.686670 -1.637745 1.218260 + endloop + endfacet + facet normal 0.338569 -0.577656 0.742755 + outer loop + vertex -1.695561 -1.723969 1.143086 + vertex -2.247988 -2.706529 0.630741 + vertex -1.778190 -1.712136 1.189953 + endloop + endfacet + facet normal 0.199457 -0.538896 0.818418 + outer loop + vertex -1.695561 -1.723969 1.143086 + vertex -2.154233 -2.698711 0.613040 + vertex -2.247988 -2.706529 0.630741 + endloop + endfacet + facet normal 0.060717 -0.890279 0.451350 + outer loop + vertex -2.643498 -3.704512 -1.284553 + vertex -2.684741 -3.685669 -1.241837 + vertex -2.247988 -2.706529 0.630741 + endloop + endfacet + facet normal 0.155501 -0.888839 0.431027 + outer loop + vertex -2.154233 -2.698711 0.613040 + vertex -2.643498 -3.704512 -1.284553 + vertex -2.247988 -2.706529 0.630741 + endloop + endfacet + facet normal 0.050401 -0.894893 0.443426 + outer loop + vertex -2.643498 -3.704512 -1.284553 + vertex -2.921253 -3.862256 -1.571330 + vertex -2.684741 -3.685669 -1.241837 + endloop + endfacet + facet normal -0.092013 -0.832158 0.546852 + outer loop + vertex -2.643498 -3.704512 -1.284553 + vertex -2.906811 -3.873407 -1.585869 + vertex -2.921253 -3.862256 -1.571330 + endloop + endfacet + facet normal -0.021384 -0.399440 0.916510 + outer loop + vertex -1.128773 -0.458771 -0.044633 + vertex -1.034731 -0.580930 -0.095679 + vertex -1.175889 -0.599544 -0.107085 + endloop + endfacet + facet normal 0.781865 0.450013 0.431480 + outer loop + vertex -2.900025 -3.891637 -1.579153 + vertex -2.916979 -3.882807 -1.557641 + vertex -2.906811 -3.873407 -1.585869 + endloop + endfacet + facet normal -0.142683 0.599397 0.787633 + outer loop + vertex -1.034731 -0.580930 -0.095679 + vertex -1.386143 -1.223479 0.329648 + vertex -1.175889 -0.599544 -0.107085 + endloop + endfacet + facet normal 0.052053 0.531268 0.845603 + outer loop + vertex -1.034731 -0.580930 -0.095679 + vertex -1.298746 -1.258755 0.346431 + vertex -1.386143 -1.223479 0.329648 + endloop + endfacet + facet normal 0.257589 0.818346 0.513768 + outer loop + vertex -1.603187 -1.697733 1.193876 + vertex -1.652663 -1.671374 1.176695 + vertex -1.386143 -1.223479 0.329648 + endloop + endfacet + facet normal 0.235025 0.826016 0.512310 + outer loop + vertex -1.298746 -1.258755 0.346431 + vertex -1.603187 -1.697733 1.193876 + vertex -1.386143 -1.223479 0.329648 + endloop + endfacet + facet normal -0.421862 -0.218250 0.880000 + outer loop + vertex -1.603187 -1.697733 1.193876 + vertex -1.695561 -1.723969 1.143086 + vertex -1.652663 -1.671374 1.176695 + endloop + endfacet + facet normal -0.423999 -0.211792 0.880550 + outer loop + vertex -1.603187 -1.697733 1.193876 + vertex -1.623202 -1.783161 1.163691 + vertex -1.695561 -1.723969 1.143086 + endloop + endfacet + facet normal -0.403748 -0.283087 0.869971 + outer loop + vertex -2.085844 -2.764916 0.623236 + vertex -2.154233 -2.698711 0.613040 + vertex -1.695561 -1.723969 1.143086 + endloop + endfacet + facet normal -0.452994 -0.256549 0.853803 + outer loop + vertex -1.623202 -1.783161 1.163691 + vertex -2.085844 -2.764916 0.623236 + vertex -1.695561 -1.723969 1.143086 + endloop + endfacet + facet normal -0.645807 -0.593054 0.480854 + outer loop + vertex -2.085844 -2.764916 0.623236 + vertex -2.643498 -3.704512 -1.284553 + vertex -2.154233 -2.698711 0.613040 + endloop + endfacet + facet normal -0.940770 -0.099653 0.324070 + outer loop + vertex -2.085844 -2.764916 0.623236 + vertex -2.632840 -3.744989 -1.266060 + vertex -2.643498 -3.704512 -1.284553 + endloop + endfacet + facet normal -0.743959 -0.031004 0.667505 + outer loop + vertex -2.900025 -3.891637 -1.579153 + vertex -2.906811 -3.873407 -1.585869 + vertex -2.643498 -3.704512 -1.284553 + endloop + endfacet + facet normal -0.776583 0.080968 0.624790 + outer loop + vertex -2.632840 -3.744989 -1.266060 + vertex -2.900025 -3.891637 -1.579153 + vertex -2.643498 -3.704512 -1.284553 + endloop + endfacet + facet normal -0.021383 -0.399439 0.916510 + outer loop + vertex -1.128773 -0.458771 -0.044633 + vertex -0.964388 -0.470329 -0.045835 + vertex -1.034731 -0.580930 -0.095679 + endloop + endfacet + facet normal 0.781881 0.449950 0.431518 + outer loop + vertex -2.906007 -3.903219 -1.556237 + vertex -2.916979 -3.882807 -1.557641 + vertex -2.900025 -3.891637 -1.579153 + endloop + endfacet + facet normal -0.677965 0.568237 0.466337 + outer loop + vertex -1.230263 -1.223898 0.403520 + vertex -1.298746 -1.258755 0.346431 + vertex -1.034731 -0.580930 -0.095679 + endloop + endfacet + facet normal -0.864687 0.444542 0.233879 + outer loop + vertex -0.964388 -0.470329 -0.045835 + vertex -1.230263 -1.223898 0.403520 + vertex -1.034731 -0.580930 -0.095679 + endloop + endfacet + facet normal -0.574036 0.792884 0.204496 + outer loop + vertex -1.230263 -1.223898 0.403520 + vertex -1.603187 -1.697733 1.193876 + vertex -1.298746 -1.258755 0.346431 + endloop + endfacet + facet normal -0.542411 0.808382 0.228709 + outer loop + vertex -1.230263 -1.223898 0.403520 + vertex -1.575499 -1.696975 1.256863 + vertex -1.603187 -1.697733 1.193876 + endloop + endfacet + facet normal -0.963225 0.145960 0.225595 + outer loop + vertex -1.615599 -1.845137 1.236253 + vertex -1.623202 -1.783161 1.163691 + vertex -1.603187 -1.697733 1.193876 + endloop + endfacet + facet normal -0.899821 0.188828 0.393275 + outer loop + vertex -1.575499 -1.696975 1.256863 + vertex -1.615599 -1.845137 1.236253 + vertex -1.603187 -1.697733 1.193876 + endloop + endfacet + facet normal -0.913564 0.256981 0.315217 + outer loop + vertex -1.615599 -1.845137 1.236253 + vertex -2.085844 -2.764916 0.623236 + vertex -1.623202 -1.783161 1.163691 + endloop + endfacet + facet normal -0.902424 0.211018 0.375635 + outer loop + vertex -1.615599 -1.845137 1.236253 + vertex -2.094317 -2.855290 0.653648 + vertex -2.085844 -2.764916 0.623236 + endloop + endfacet + facet normal -0.811798 0.580203 -0.065945 + outer loop + vertex -2.660793 -3.776623 -1.200285 + vertex -2.632840 -3.744989 -1.266060 + vertex -2.085844 -2.764916 0.623236 + endloop + endfacet + facet normal -0.963328 0.162240 0.213721 + outer loop + vertex -2.094317 -2.855290 0.653648 + vertex -2.660793 -3.776623 -1.200285 + vertex -2.085844 -2.764916 0.623236 + endloop + endfacet + facet normal -0.591019 0.795851 0.131594 + outer loop + vertex -2.660793 -3.776623 -1.200285 + vertex -2.900025 -3.891637 -1.579153 + vertex -2.632840 -3.744989 -1.266060 + endloop + endfacet + facet normal -0.658655 0.726656 0.195307 + outer loop + vertex -2.660793 -3.776623 -1.200285 + vertex -2.906007 -3.903219 -1.556237 + vertex -2.900025 -3.891637 -1.579153 + endloop + endfacet + facet normal -0.076765 0.424315 0.902255 + outer loop + vertex -1.017698 0.488881 -0.032670 + vertex -1.054016 0.365147 0.022430 + vertex -1.178874 0.454621 -0.030272 + endloop + endfacet + facet normal 0.760863 -0.570059 0.310031 + outer loop + vertex -3.086113 2.794081 -1.545862 + vertex -3.098632 2.775017 -1.550191 + vertex -3.099803 2.787534 -1.524302 + endloop + endfacet + facet normal -0.885644 -0.070812 -0.458933 + outer loop + vertex -1.017698 0.488881 -0.032670 + vertex -1.317050 1.294574 0.420700 + vertex -1.324158 1.203249 0.448508 + endloop + endfacet + facet normal -0.840063 0.005007 -0.542465 + outer loop + vertex -1.017698 0.488881 -0.032670 + vertex -1.324158 1.203249 0.448508 + vertex -1.054016 0.365147 0.022430 + endloop + endfacet + facet normal -0.967987 -0.001088 -0.250997 + outer loop + vertex -1.317050 1.294574 0.420700 + vertex -1.526310 1.673322 1.226081 + vertex -1.324158 1.203249 0.448508 + endloop + endfacet + facet normal -0.909263 0.206636 -0.361307 + outer loop + vertex -1.526310 1.673322 1.226081 + vertex -1.554071 1.628527 1.270326 + vertex -1.324158 1.203249 0.448508 + endloop + endfacet + facet normal -0.512468 -0.124689 -0.849606 + outer loop + vertex -1.526310 1.673322 1.226081 + vertex -1.577267 1.819272 1.235398 + vertex -1.658703 1.813423 1.285377 + endloop + endfacet + facet normal -0.638088 -0.303488 -0.707629 + outer loop + vertex -1.526310 1.673322 1.226081 + vertex -1.658703 1.813423 1.285377 + vertex -1.554071 1.628527 1.270326 + endloop + endfacet + facet normal -0.160780 -0.915375 -0.369104 + outer loop + vertex -1.577267 1.819272 1.235398 + vertex -2.072943 2.213083 0.474666 + vertex -1.658703 1.813423 1.285377 + endloop + endfacet + facet normal -0.373682 -0.893377 -0.249476 + outer loop + vertex -2.072943 2.213083 0.474666 + vertex -2.161622 2.246180 0.488976 + vertex -1.658703 1.813423 1.285377 + endloop + endfacet + facet normal -0.073049 -0.980069 -0.184738 + outer loop + vertex -2.072943 2.213083 0.474666 + vertex -2.838396 2.591279 -1.229057 + vertex -2.881531 2.582325 -1.164499 + endloop + endfacet + facet normal -0.354478 -0.934386 -0.035621 + outer loop + vertex -2.072943 2.213083 0.474666 + vertex -2.881531 2.582325 -1.164499 + vertex -2.161622 2.246180 0.488976 + endloop + endfacet + facet normal -0.308527 -0.892182 -0.329883 + outer loop + vertex -2.838396 2.591279 -1.229057 + vertex -3.086113 2.794081 -1.545862 + vertex -2.881531 2.582325 -1.164499 + endloop + endfacet + facet normal -0.192877 -0.898111 -0.395216 + outer loop + vertex -3.086113 2.794081 -1.545862 + vertex -3.099803 2.787534 -1.524302 + vertex -2.881531 2.582325 -1.164499 + endloop + endfacet + facet normal -0.076769 0.424311 0.902256 + outer loop + vertex -1.054016 0.365147 0.022430 + vertex -1.184355 0.308787 0.037844 + vertex -1.178874 0.454621 -0.030272 + endloop + endfacet + facet normal 0.760849 -0.570075 0.310037 + outer loop + vertex -3.099803 2.787534 -1.524302 + vertex -3.098632 2.775017 -1.550191 + vertex -3.112612 2.771560 -1.522239 + endloop + endfacet + facet normal -0.264522 0.367929 -0.891435 + outer loop + vertex -1.054016 0.365147 0.022430 + vertex -1.324158 1.203249 0.448508 + vertex -1.184355 0.308787 0.037844 + endloop + endfacet + facet normal -0.023282 0.414123 -0.909923 + outer loop + vertex -1.324158 1.203249 0.448508 + vertex -1.386909 1.136856 0.419897 + vertex -1.184355 0.308787 0.037844 + endloop + endfacet + facet normal -0.489268 0.711136 -0.504880 + outer loop + vertex -1.324158 1.203249 0.448508 + vertex -1.554071 1.628527 1.270326 + vertex -1.597825 1.590944 1.259791 + endloop + endfacet + facet normal -0.508115 0.697803 -0.504866 + outer loop + vertex -1.324158 1.203249 0.448508 + vertex -1.597825 1.590944 1.259791 + vertex -1.386909 1.136856 0.419897 + endloop + endfacet + facet normal 0.113028 0.143990 -0.983103 + outer loop + vertex -1.554071 1.628527 1.270326 + vertex -1.658703 1.813423 1.285377 + vertex -1.597825 1.590944 1.259791 + endloop + endfacet + facet normal 0.185815 0.162296 -0.969089 + outer loop + vertex -1.658703 1.813423 1.285377 + vertex -1.739812 1.768143 1.262242 + vertex -1.597825 1.590944 1.259791 + endloop + endfacet + facet normal 0.498545 -0.589780 -0.635306 + outer loop + vertex -1.658703 1.813423 1.285377 + vertex -2.161622 2.246180 0.488976 + vertex -2.244519 2.210517 0.457031 + endloop + endfacet + facet normal 0.506276 -0.581512 -0.636810 + outer loop + vertex -1.658703 1.813423 1.285377 + vertex -2.244519 2.210517 0.457031 + vertex -1.739812 1.768143 1.262242 + endloop + endfacet + facet normal 0.484050 -0.792129 -0.371789 + outer loop + vertex -2.161622 2.246180 0.488976 + vertex -2.881531 2.582325 -1.164499 + vertex -2.244519 2.210517 0.457031 + endloop + endfacet + facet normal 0.612227 -0.683636 -0.397265 + outer loop + vertex -2.881531 2.582325 -1.164499 + vertex -2.912222 2.549601 -1.155484 + vertex -2.244519 2.210517 0.457031 + endloop + endfacet + facet normal 0.557069 -0.529381 -0.639867 + outer loop + vertex -2.881531 2.582325 -1.164499 + vertex -3.099803 2.787534 -1.524302 + vertex -3.112612 2.771560 -1.522239 + endloop + endfacet + facet normal 0.471754 -0.616192 -0.630679 + outer loop + vertex -2.881531 2.582325 -1.164499 + vertex -3.112612 2.771560 -1.522239 + vertex -2.912222 2.549601 -1.155484 + endloop + endfacet + facet normal -0.076767 0.424311 0.902257 + outer loop + vertex -1.184355 0.308787 0.037844 + vertex -1.310567 0.362245 0.001966 + vertex -1.178874 0.454621 -0.030272 + endloop + endfacet + facet normal 0.760856 -0.570063 0.310042 + outer loop + vertex -3.112612 2.771560 -1.522239 + vertex -3.098632 2.775017 -1.550191 + vertex -3.114895 2.758189 -1.541222 + endloop + endfacet + facet normal 0.624605 0.447931 -0.639708 + outer loop + vertex -1.184355 0.308787 0.037844 + vertex -1.386909 1.136856 0.419897 + vertex -1.458049 1.145392 0.356413 + endloop + endfacet + facet normal 0.412785 0.438942 -0.798084 + outer loop + vertex -1.184355 0.308787 0.037844 + vertex -1.458049 1.145392 0.356413 + vertex -1.310567 0.362245 0.001966 + endloop + endfacet + facet normal 0.413569 0.840320 -0.350461 + outer loop + vertex -1.386909 1.136856 0.419897 + vertex -1.597825 1.590944 1.259791 + vertex -1.458049 1.145392 0.356413 + endloop + endfacet + facet normal 0.566477 0.770476 -0.292355 + outer loop + vertex -1.597825 1.590944 1.259791 + vertex -1.624625 1.588875 1.202410 + vertex -1.458049 1.145392 0.356413 + endloop + endfacet + facet normal 0.666043 0.540797 -0.513737 + outer loop + vertex -1.597825 1.590944 1.259791 + vertex -1.739812 1.768143 1.262242 + vertex -1.759516 1.717527 1.183414 + endloop + endfacet + facet normal 0.673964 0.656675 -0.338454 + outer loop + vertex -1.597825 1.590944 1.259791 + vertex -1.759516 1.717527 1.183414 + vertex -1.624625 1.588875 1.202410 + endloop + endfacet + facet normal 0.875283 0.276827 -0.396542 + outer loop + vertex -1.739812 1.768143 1.262242 + vertex -2.244519 2.210517 0.457031 + vertex -1.759516 1.717527 1.183414 + endloop + endfacet + facet normal 0.868040 0.162955 -0.468990 + outer loop + vertex -2.244519 2.210517 0.457031 + vertex -2.259210 2.132949 0.402887 + vertex -1.759516 1.717527 1.183414 + endloop + endfacet + facet normal 0.824457 0.515765 -0.232931 + outer loop + vertex -2.244519 2.210517 0.457031 + vertex -2.912222 2.549601 -1.155484 + vertex -2.907359 2.517750 -1.208798 + endloop + endfacet + facet normal 0.931220 0.072883 -0.357095 + outer loop + vertex -2.244519 2.210517 0.457031 + vertex -2.907359 2.517750 -1.208798 + vertex -2.259210 2.132949 0.402887 + endloop + endfacet + facet normal 0.866476 0.459384 -0.195414 + outer loop + vertex -2.912222 2.549601 -1.155484 + vertex -3.112612 2.771560 -1.522239 + vertex -2.907359 2.517750 -1.208798 + endloop + endfacet + facet normal 0.890596 0.314460 -0.328562 + outer loop + vertex -3.112612 2.771560 -1.522239 + vertex -3.114895 2.758189 -1.541222 + vertex -2.907359 2.517750 -1.208798 + endloop + endfacet + facet normal -0.076772 0.424317 0.902253 + outer loop + vertex -1.310567 0.362245 0.001966 + vertex -1.337611 0.485262 -0.058188 + vertex -1.178874 0.454621 -0.030272 + endloop + endfacet + facet normal 0.760856 -0.570104 0.309966 + outer loop + vertex -3.114895 2.758189 -1.541222 + vertex -3.098632 2.775017 -1.550191 + vertex -3.104932 2.757492 -1.566960 + endloop + endfacet + facet normal 0.979394 0.199278 -0.032785 + outer loop + vertex -1.310567 0.362245 0.001966 + vertex -1.458049 1.145392 0.356413 + vertex -1.337611 0.485262 -0.058188 + endloop + endfacet + facet normal 0.961778 0.248166 -0.115743 + outer loop + vertex -1.458049 1.145392 0.356413 + vertex -1.484010 1.222427 0.305859 + vertex -1.337611 0.485262 -0.058188 + endloop + endfacet + facet normal 0.983234 0.024646 0.180678 + outer loop + vertex -1.458049 1.145392 0.356413 + vertex -1.624625 1.588875 1.202410 + vertex -1.614290 1.623878 1.141392 + endloop + endfacet + facet normal 0.948482 0.316803 -0.004324 + outer loop + vertex -1.458049 1.145392 0.356413 + vertex -1.614290 1.623878 1.141392 + vertex -1.484010 1.222427 0.305859 + endloop + endfacet + facet normal 0.569356 0.667771 0.479496 + outer loop + vertex -1.624625 1.588875 1.202410 + vertex -1.759516 1.717527 1.183414 + vertex -1.614290 1.623878 1.141392 + endloop + endfacet + facet normal 0.574626 0.780224 0.247095 + outer loop + vertex -1.759516 1.717527 1.183414 + vertex -1.702977 1.699690 1.108251 + vertex -1.614290 1.623878 1.141392 + endloop + endfacet + facet normal 0.674839 0.736889 -0.039836 + outer loop + vertex -1.759516 1.717527 1.183414 + vertex -2.259210 2.132949 0.402887 + vertex -2.194634 2.071888 0.367314 + endloop + endfacet + facet normal 0.458697 0.878017 0.136684 + outer loop + vertex -1.759516 1.717527 1.183414 + vertex -2.194634 2.071888 0.367314 + vertex -1.702977 1.699690 1.108251 + endloop + endfacet + facet normal 0.658888 0.747244 -0.086566 + outer loop + vertex -2.259210 2.132949 0.402887 + vertex -2.907359 2.517750 -1.208798 + vertex -2.194634 2.071888 0.367314 + endloop + endfacet + facet normal 0.369676 0.924361 0.094321 + outer loop + vertex -2.907359 2.517750 -1.208798 + vertex -2.870606 2.510755 -1.284297 + vertex -2.194634 2.071888 0.367314 + endloop + endfacet + facet normal 0.583255 0.786133 0.204471 + outer loop + vertex -2.907359 2.517750 -1.208798 + vertex -3.114895 2.758189 -1.541222 + vertex -3.104932 2.757492 -1.566960 + endloop + endfacet + facet normal 0.578597 0.788484 0.208613 + outer loop + vertex -2.907359 2.517750 -1.208798 + vertex -3.104932 2.757492 -1.566960 + vertex -2.870606 2.510755 -1.284297 + endloop + endfacet + facet normal -0.076770 0.424323 0.902251 + outer loop + vertex -1.337611 0.485262 -0.058188 + vertex -1.245123 0.585205 -0.097321 + vertex -1.178874 0.454621 -0.030272 + endloop + endfacet + facet normal 0.760858 -0.570103 0.309963 + outer loop + vertex -3.104932 2.757492 -1.566960 + vertex -3.098632 2.775017 -1.550191 + vertex -3.090227 2.769990 -1.580069 + endloop + endfacet + facet normal 0.584712 -0.262889 0.767465 + outer loop + vertex -1.337611 0.485262 -0.058188 + vertex -1.484010 1.222427 0.305859 + vertex -1.445241 1.309955 0.306304 + endloop + endfacet + facet normal 0.598775 -0.257104 0.758529 + outer loop + vertex -1.337611 0.485262 -0.058188 + vertex -1.445241 1.309955 0.306304 + vertex -1.245123 0.585205 -0.097321 + endloop + endfacet + facet normal 0.865648 -0.385051 0.319982 + outer loop + vertex -1.484010 1.222427 0.305859 + vertex -1.614290 1.623878 1.141392 + vertex -1.445241 1.309955 0.306304 + endloop + endfacet + facet normal 0.773065 -0.526167 0.354288 + outer loop + vertex -1.614290 1.623878 1.141392 + vertex -1.574602 1.669594 1.122686 + vertex -1.445241 1.309955 0.306304 + endloop + endfacet + facet normal 0.018355 0.418432 0.908063 + outer loop + vertex -1.614290 1.623878 1.141392 + vertex -1.702977 1.699690 1.108251 + vertex -1.612771 1.728064 1.093353 + endloop + endfacet + facet normal -0.055122 0.418750 0.906427 + outer loop + vertex -1.614290 1.623878 1.141392 + vertex -1.612771 1.728064 1.093353 + vertex -1.574602 1.669594 1.122686 + endloop + endfacet + facet normal -0.173070 0.829251 0.531404 + outer loop + vertex -1.702977 1.699690 1.108251 + vertex -2.194634 2.071888 0.367314 + vertex -1.612771 1.728064 1.093353 + endloop + endfacet + facet normal -0.061163 0.882239 0.466812 + outer loop + vertex -2.194634 2.071888 0.367314 + vertex -2.099415 2.073312 0.377099 + vertex -1.612771 1.728064 1.093353 + endloop + endfacet + facet normal -0.196835 0.924568 0.326237 + outer loop + vertex -2.194634 2.071888 0.367314 + vertex -2.870606 2.510755 -1.284297 + vertex -2.829635 2.533885 -1.325127 + endloop + endfacet + facet normal -0.042923 0.959606 0.278055 + outer loop + vertex -2.194634 2.071888 0.367314 + vertex -2.829635 2.533885 -1.325127 + vertex -2.099415 2.073312 0.377099 + endloop + endfacet + facet normal 0.133578 0.798819 0.586553 + outer loop + vertex -2.870606 2.510755 -1.284297 + vertex -3.104932 2.757492 -1.566960 + vertex -2.829635 2.533885 -1.325127 + endloop + endfacet + facet normal -0.009276 0.728916 0.684540 + outer loop + vertex -3.104932 2.757492 -1.566960 + vertex -3.090227 2.769990 -1.580069 + vertex -2.829635 2.533885 -1.325127 + endloop + endfacet + facet normal -0.076769 0.424323 0.902251 + outer loop + vertex -1.245123 0.585205 -0.097321 + vertex -1.102749 0.586816 -0.085965 + vertex -1.178874 0.454621 -0.030272 + endloop + endfacet + facet normal 0.760912 -0.570029 0.309966 + outer loop + vertex -3.090227 2.769990 -1.580069 + vertex -3.098632 2.775017 -1.550191 + vertex -3.081852 2.786274 -1.570680 + endloop + endfacet + facet normal -0.063304 -0.498861 0.864367 + outer loop + vertex -1.245123 0.585205 -0.097321 + vertex -1.445241 1.309955 0.306304 + vertex -1.102749 0.586816 -0.085965 + endloop + endfacet + facet normal -0.292044 -0.559202 0.775889 + outer loop + vertex -1.445241 1.309955 0.306304 + vertex -1.370937 1.342063 0.357414 + vertex -1.102749 0.586816 -0.085965 + endloop + endfacet + facet normal 0.108098 -0.903342 0.415076 + outer loop + vertex -1.445241 1.309955 0.306304 + vertex -1.574602 1.669594 1.122686 + vertex -1.535446 1.691598 1.160377 + endloop + endfacet + facet normal 0.105117 -0.903754 0.414945 + outer loop + vertex -1.445241 1.309955 0.306304 + vertex -1.535446 1.691598 1.160377 + vertex -1.370937 1.342063 0.357414 + endloop + endfacet + facet normal -0.671669 -0.068380 0.737689 + outer loop + vertex -1.574602 1.669594 1.122686 + vertex -1.612771 1.728064 1.093353 + vertex -1.535446 1.691598 1.160377 + endloop + endfacet + facet normal -0.673059 -0.074809 0.735796 + outer loop + vertex -1.612771 1.728064 1.093353 + vertex -1.556825 1.781284 1.149940 + vertex -1.535446 1.691598 1.160377 + endloop + endfacet + facet normal -0.765665 0.193449 0.613461 + outer loop + vertex -1.612771 1.728064 1.093353 + vertex -2.099415 2.073312 0.377099 + vertex -2.045259 2.136150 0.424876 + endloop + endfacet + facet normal -0.776329 0.171037 0.606679 + outer loop + vertex -1.612771 1.728064 1.093353 + vertex -2.045259 2.136150 0.424876 + vertex -1.556825 1.781284 1.149940 + endloop + endfacet + facet normal -0.816773 0.362871 0.448561 + outer loop + vertex -2.099415 2.073312 0.377099 + vertex -2.829635 2.533885 -1.325127 + vertex -2.045259 2.136150 0.424876 + endloop + endfacet + facet normal -0.903896 0.072367 0.421587 + outer loop + vertex -2.829635 2.533885 -1.325127 + vertex -2.815300 2.569721 -1.300544 + vertex -2.045259 2.136150 0.424876 + endloop + endfacet + facet normal -0.714902 -0.034977 0.698350 + outer loop + vertex -2.829635 2.533885 -1.325127 + vertex -3.090227 2.769990 -1.580069 + vertex -3.081852 2.786274 -1.570680 + endloop + endfacet + facet normal -0.757349 -0.135291 0.638842 + outer loop + vertex -2.829635 2.533885 -1.325127 + vertex -3.081852 2.786274 -1.570680 + vertex -2.815300 2.569721 -1.300544 + endloop + endfacet + facet normal -0.076766 0.424322 0.902252 + outer loop + vertex -1.102749 0.586816 -0.085965 + vertex -1.017698 0.488881 -0.032670 + vertex -1.178874 0.454621 -0.030272 + endloop + endfacet + facet normal 0.760899 -0.570062 0.309938 + outer loop + vertex -3.081852 2.786274 -1.570680 + vertex -3.098632 2.775017 -1.550191 + vertex -3.086113 2.794081 -1.545862 + endloop + endfacet + facet normal -0.811858 -0.481851 0.329707 + outer loop + vertex -1.102749 0.586816 -0.085965 + vertex -1.370937 1.342063 0.357414 + vertex -1.317050 1.294574 0.420700 + endloop + endfacet + facet normal -0.792782 -0.494815 0.355886 + outer loop + vertex -1.102749 0.586816 -0.085965 + vertex -1.317050 1.294574 0.420700 + vertex -1.017698 0.488881 -0.032670 + endloop + endfacet + facet normal -0.739785 -0.659091 0.135341 + outer loop + vertex -1.370937 1.342063 0.357414 + vertex -1.535446 1.691598 1.160377 + vertex -1.317050 1.294574 0.420700 + endloop + endfacet + facet normal -0.882459 -0.470320 -0.008108 + outer loop + vertex -1.535446 1.691598 1.160377 + vertex -1.526310 1.673322 1.226081 + vertex -1.317050 1.294574 0.420700 + endloop + endfacet + facet normal -0.962198 -0.243543 -0.121908 + outer loop + vertex -1.535446 1.691598 1.160377 + vertex -1.556825 1.781284 1.149940 + vertex -1.577267 1.819272 1.235398 + endloop + endfacet + facet normal -0.942624 -0.331589 0.038845 + outer loop + vertex -1.535446 1.691598 1.160377 + vertex -1.577267 1.819272 1.235398 + vertex -1.526310 1.673322 1.226081 + endloop + endfacet + facet normal -0.708267 -0.692264 0.138306 + outer loop + vertex -1.556825 1.781284 1.149940 + vertex -2.045259 2.136150 0.424876 + vertex -1.577267 1.819272 1.235398 + endloop + endfacet + facet normal -0.826425 -0.483796 0.288031 + outer loop + vertex -2.045259 2.136150 0.424876 + vertex -2.072943 2.213083 0.474666 + vertex -1.577267 1.819272 1.235398 + endloop + endfacet + facet normal -0.582625 -0.810790 0.056282 + outer loop + vertex -2.045259 2.136150 0.424876 + vertex -2.815300 2.569721 -1.300544 + vertex -2.838396 2.591279 -1.229057 + endloop + endfacet + facet normal -0.836838 -0.476067 0.270299 + outer loop + vertex -2.045259 2.136150 0.424876 + vertex -2.838396 2.591279 -1.229057 + vertex -2.072943 2.213083 0.474666 + endloop + endfacet + facet normal -0.644050 -0.764652 0.022523 + outer loop + vertex -2.815300 2.569721 -1.300544 + vertex -3.081852 2.786274 -1.570680 + vertex -2.838396 2.591279 -1.229057 + endloop + endfacet + facet normal -0.703942 -0.703137 0.100317 + outer loop + vertex -3.081852 2.786274 -1.570680 + vertex -3.086113 2.794081 -1.545862 + vertex -2.838396 2.591279 -1.229057 + endloop + endfacet + facet normal 0.072988 -0.424980 0.902256 + outer loop + vertex -0.790998 -0.401975 -0.030272 + vertex -0.704272 -0.275192 0.022430 + vertex -0.627824 -0.379043 -0.032670 + endloop + endfacet + facet normal 0.288141 0.809048 0.512265 + outer loop + vertex -1.089436 -3.534324 -1.601137 + vertex -1.098497 -3.517481 -1.622642 + vertex -1.076676 -3.525398 -1.622411 + endloop + endfacet + facet normal -0.722977 -0.260383 -0.639926 + outer loop + vertex -0.785680 -1.123303 0.448508 + vertex -0.733861 -1.198839 0.420700 + vertex -0.627824 -0.379043 -0.032670 + endloop + endfacet + facet normal -0.757175 -0.233753 -0.609955 + outer loop + vertex -0.704272 -0.275192 0.022430 + vertex -0.785680 -1.123303 0.448508 + vertex -0.627824 -0.379043 -0.032670 + endloop + endfacet + facet normal -0.822169 -0.424316 -0.379466 + outer loop + vertex -0.785680 -1.123303 0.448508 + vertex -0.835425 -1.722300 1.226081 + vertex -0.733861 -1.198839 0.420700 + endloop + endfacet + facet normal -0.716561 -0.529666 -0.453865 + outer loop + vertex -0.785680 -1.123303 0.448508 + vertex -0.881864 -1.697387 1.270326 + vertex -0.835425 -1.722300 1.226081 + endloop + endfacet + facet normal -0.506154 -0.148250 -0.849606 + outer loop + vertex -0.880030 -1.909828 1.285377 + vertex -0.806580 -1.874175 1.235398 + vertex -0.835425 -1.722300 1.226081 + endloop + endfacet + facet normal -0.704344 -0.056216 -0.707629 + outer loop + vertex -0.881864 -1.697387 1.270326 + vertex -0.880030 -1.909828 1.285377 + vertex -0.835425 -1.722300 1.226081 + endloop + endfacet + facet normal -0.632493 0.574024 -0.520048 + outer loop + vertex -0.880030 -1.909828 1.285377 + vertex -0.908545 -2.863121 0.267821 + vertex -0.806580 -1.874175 1.235398 + endloop + endfacet + facet normal -0.727582 0.510696 -0.458055 + outer loop + vertex -0.880030 -1.909828 1.285377 + vertex -0.968795 -2.936123 0.282131 + vertex -0.908545 -2.863121 0.267821 + endloop + endfacet + facet normal -0.823961 0.552372 -0.126389 + outer loop + vertex -1.006375 -3.340990 -1.182885 + vertex -0.972894 -3.304943 -1.243616 + vertex -0.908545 -2.863121 0.267821 + endloop + endfacet + facet normal -0.776781 0.611851 -0.149163 + outer loop + vertex -0.968795 -2.936123 0.282131 + vertex -1.006375 -3.340990 -1.182885 + vertex -0.908545 -2.863121 0.267821 + endloop + endfacet + facet normal -0.813524 0.571128 -0.109502 + outer loop + vertex -1.006375 -3.340990 -1.182885 + vertex -1.076676 -3.525398 -1.622411 + vertex -0.972894 -3.304943 -1.243616 + endloop + endfacet + facet normal -0.731633 0.662436 -0.160910 + outer loop + vertex -1.006375 -3.340990 -1.182885 + vertex -1.089436 -3.534324 -1.601137 + vertex -1.076676 -3.525398 -1.622411 + endloop + endfacet + facet normal 0.072985 -0.424978 0.902257 + outer loop + vertex -0.790998 -0.401975 -0.030272 + vertex -0.846026 -0.266810 0.037844 + vertex -0.704272 -0.275192 0.022430 + endloop + endfacet + facet normal 0.288123 0.809050 0.512273 + outer loop + vertex -1.109021 -3.530566 -1.596056 + vertex -1.098497 -3.517481 -1.622642 + vertex -1.089436 -3.534324 -1.601137 + endloop + endfacet + facet normal -0.122729 -0.436093 -0.891493 + outer loop + vertex -0.846026 -0.266810 0.037844 + vertex -0.785680 -1.123303 0.448508 + vertex -0.704272 -0.275192 0.022430 + endloop + endfacet + facet normal 0.167711 -0.416587 -0.893492 + outer loop + vertex -0.846026 -0.266810 0.037844 + vertex -0.873220 -1.097180 0.419897 + vertex -0.785680 -1.123303 0.448508 + endloop + endfacet + facet normal -0.046677 -0.816322 -0.575708 + outer loop + vertex -0.938548 -1.686716 1.259791 + vertex -0.881864 -1.697387 1.270326 + vertex -0.785680 -1.123303 0.448508 + endloop + endfacet + facet normal -0.054856 -0.815250 -0.576505 + outer loop + vertex -0.873220 -1.097180 0.419897 + vertex -0.938548 -1.686716 1.259791 + vertex -0.785680 -1.123303 0.448508 + endloop + endfacet + facet normal 0.169880 -0.068186 -0.983103 + outer loop + vertex -0.938548 -1.686716 1.259791 + vertex -0.880030 -1.909828 1.285377 + vertex -0.881864 -1.697387 1.270326 + endloop + endfacet + facet normal 0.242069 -0.047645 -0.969089 + outer loop + vertex -0.938548 -1.686716 1.259791 + vertex -0.972913 -1.911169 1.262242 + vertex -0.880030 -1.909828 1.285377 + endloop + endfacet + facet normal 0.173446 0.680724 -0.711710 + outer loop + vertex -1.058417 -2.946686 0.250187 + vertex -0.968795 -2.936123 0.282131 + vertex -0.880030 -1.909828 1.285377 + endloop + endfacet + facet normal 0.167480 0.681978 -0.711938 + outer loop + vertex -0.972913 -1.911169 1.262242 + vertex -1.058417 -2.946686 0.250187 + vertex -0.880030 -1.909828 1.285377 + endloop + endfacet + facet normal -0.018832 0.963823 -0.265876 + outer loop + vertex -1.058417 -2.946686 0.250187 + vertex -1.006375 -3.340990 -1.182885 + vertex -0.968795 -2.936123 0.282131 + endloop + endfacet + facet normal -0.005774 0.964100 -0.265478 + outer loop + vertex -1.058417 -2.946686 0.250187 + vertex -1.049571 -3.337220 -1.168255 + vertex -1.006375 -3.340990 -1.182885 + endloop + endfacet + facet normal 0.061675 0.901267 -0.428852 + outer loop + vertex -1.109021 -3.530566 -1.596056 + vertex -1.089436 -3.534324 -1.601137 + vertex -1.006375 -3.340990 -1.182885 + endloop + endfacet + facet normal -0.057356 0.912722 -0.404536 + outer loop + vertex -1.049571 -3.337220 -1.168255 + vertex -1.109021 -3.530566 -1.596056 + vertex -1.006375 -3.340990 -1.182885 + endloop + endfacet + facet normal 0.072986 -0.424977 0.902257 + outer loop + vertex -0.790998 -0.401975 -0.030272 + vertex -0.946343 -0.360211 0.001966 + vertex -0.846026 -0.266810 0.037844 + endloop + endfacet + facet normal 0.288120 0.809051 0.512273 + outer loop + vertex -1.120681 -3.516955 -1.610994 + vertex -1.098497 -3.517481 -1.622642 + vertex -1.109021 -3.530566 -1.596056 + endloop + endfacet + facet normal 0.798519 -0.272997 -0.536508 + outer loop + vertex -0.930561 -1.140143 0.356413 + vertex -0.873220 -1.097180 0.419897 + vertex -0.846026 -0.266810 0.037844 + endloop + endfacet + facet normal 0.574402 -0.329013 -0.749542 + outer loop + vertex -0.946343 -0.360211 0.001966 + vertex -0.930561 -1.140143 0.356413 + vertex -0.846026 -0.266810 0.037844 + endloop + endfacet + facet normal 0.770562 -0.548316 -0.324937 + outer loop + vertex -0.930561 -1.140143 0.356413 + vertex -0.938548 -1.686716 1.259791 + vertex -0.873220 -1.097180 0.419897 + endloop + endfacet + facet normal 0.849924 -0.454108 -0.267236 + outer loop + vertex -0.930561 -1.140143 0.356413 + vertex -0.962792 -1.698324 1.202410 + vertex -0.938548 -1.686716 1.259791 + endloop + endfacet + facet normal 0.847211 -0.135323 -0.513733 + outer loop + vertex -1.015284 -1.877186 1.183414 + vertex -0.972913 -1.911169 1.262242 + vertex -0.938548 -1.686716 1.259791 + endloop + endfacet + facet normal 0.912007 -0.231712 -0.338458 + outer loop + vertex -0.962792 -1.698324 1.202410 + vertex -1.015284 -1.877186 1.183414 + vertex -0.938548 -1.686716 1.259791 + endloop + endfacet + facet normal 0.891001 0.277562 -0.359273 + outer loop + vertex -1.015284 -1.877186 1.183414 + vertex -1.058417 -2.946686 0.250187 + vertex -0.972913 -1.911169 1.262242 + endloop + endfacet + facet normal 0.839563 0.337563 -0.425659 + outer loop + vertex -1.015284 -1.877186 1.183414 + vertex -1.109924 -2.886856 0.196043 + vertex -1.058417 -2.946686 0.250187 + endloop + endfacet + facet normal 0.926300 0.364708 -0.094637 + outer loop + vertex -1.069953 -3.296477 -1.210740 + vertex -1.049571 -3.337220 -1.168255 + vertex -1.058417 -2.946686 0.250187 + endloop + endfacet + facet normal 0.810221 0.568532 -0.142522 + outer loop + vertex -1.109924 -2.886856 0.196043 + vertex -1.069953 -3.296477 -1.210740 + vertex -1.058417 -2.946686 0.250187 + endloop + endfacet + facet normal 0.944952 0.228233 -0.234468 + outer loop + vertex -1.069953 -3.296477 -1.210740 + vertex -1.109021 -3.530566 -1.596056 + vertex -1.049571 -3.337220 -1.168255 + endloop + endfacet + facet normal 0.864127 0.386453 -0.322396 + outer loop + vertex -1.069953 -3.296477 -1.210740 + vertex -1.120681 -3.516955 -1.610994 + vertex -1.109021 -3.530566 -1.596056 + endloop + endfacet + facet normal 0.072983 -0.424986 0.902253 + outer loop + vertex -0.790998 -0.401975 -0.030272 + vertex -0.929682 -0.485059 -0.058188 + vertex -0.946343 -0.360211 0.001966 + endloop + endfacet + facet normal 0.288079 0.809116 0.512193 + outer loop + vertex -1.115638 -3.503742 -1.634704 + vertex -1.098497 -3.517481 -1.622642 + vertex -1.120681 -3.516955 -1.610994 + endloop + endfacet + facet normal 0.990014 0.074439 0.119715 + outer loop + vertex -0.929682 -0.485059 -0.058188 + vertex -0.930561 -1.140143 0.356413 + vertex -0.946343 -0.360211 0.001966 + endloop + endfacet + facet normal 0.982704 0.098089 0.157068 + outer loop + vertex -0.929682 -0.485059 -0.058188 + vertex -0.914527 -1.219838 0.305859 + vertex -0.930561 -1.140143 0.356413 + endloop + endfacet + facet normal 0.907099 0.334624 0.255340 + outer loop + vertex -0.936340 -1.723470 1.141392 + vertex -0.962792 -1.698324 1.202410 + vertex -0.930561 -1.140143 0.356413 + endloop + endfacet + facet normal 0.985708 0.131662 0.105095 + outer loop + vertex -0.914527 -1.219838 0.305859 + vertex -0.936340 -1.723470 1.141392 + vertex -0.930561 -1.140143 0.356413 + endloop + endfacet + facet normal 0.826961 -0.293625 0.479500 + outer loop + vertex -0.936340 -1.723470 1.141392 + vertex -1.015284 -1.877186 1.183414 + vertex -0.962792 -1.698324 1.202410 + endloop + endfacet + facet normal 0.887754 -0.388382 0.247088 + outer loop + vertex -0.936340 -1.723470 1.141392 + vertex -0.975239 -1.833469 1.108251 + vertex -1.015284 -1.877186 1.183414 + endloop + endfacet + facet normal 0.963315 -0.228283 0.141105 + outer loop + vertex -1.084530 -2.801688 0.160470 + vertex -1.109924 -2.886856 0.196043 + vertex -1.015284 -1.877186 1.183414 + endloop + endfacet + facet normal 0.893704 -0.361284 0.266019 + outer loop + vertex -0.975239 -1.833469 1.108251 + vertex -1.084530 -2.801688 0.160470 + vertex -1.015284 -1.877186 1.183414 + endloop + endfacet + facet normal 0.964169 -0.246102 0.099053 + outer loop + vertex -1.084530 -2.801688 0.160470 + vertex -1.069953 -3.296477 -1.210740 + vertex -1.109924 -2.886856 0.196043 + endloop + endfacet + facet normal 0.968372 -0.231237 0.093734 + outer loop + vertex -1.084530 -2.801688 0.160470 + vertex -1.052176 -3.249437 -1.278350 + vertex -1.069953 -3.296477 -1.210740 + endloop + endfacet + facet normal 0.955380 -0.292644 0.040117 + outer loop + vertex -1.115638 -3.503742 -1.634704 + vertex -1.120681 -3.516955 -1.610994 + vertex -1.069953 -3.296477 -1.210740 + endloop + endfacet + facet normal 0.953479 -0.298361 0.043116 + outer loop + vertex -1.052176 -3.249437 -1.278350 + vertex -1.115638 -3.503742 -1.634704 + vertex -1.069953 -3.296477 -1.210740 + endloop + endfacet + facet normal 0.072986 -0.424990 0.902251 + outer loop + vertex -0.790998 -0.401975 -0.030272 + vertex -0.808589 -0.547342 -0.097321 + vertex -0.929682 -0.485059 -0.058188 + endloop + endfacet + facet normal 0.288051 0.809107 0.512222 + outer loop + vertex -1.097689 -3.500874 -1.649329 + vertex -1.098497 -3.517481 -1.622642 + vertex -1.115638 -3.503742 -1.634704 + endloop + endfacet + facet normal 0.307019 0.427586 0.850241 + outer loop + vertex -0.837188 -1.276254 0.306304 + vertex -0.914527 -1.219838 0.305859 + vertex -0.929682 -0.485059 -0.058188 + endloop + endfacet + facet normal 0.465867 0.414589 0.781719 + outer loop + vertex -0.808589 -0.547342 -0.097321 + vertex -0.837188 -1.276254 0.306304 + vertex -0.929682 -0.485059 -0.058188 + endloop + endfacet + facet normal 0.524762 0.722922 0.449453 + outer loop + vertex -0.837188 -1.276254 0.306304 + vertex -0.936340 -1.723470 1.141392 + vertex -0.914527 -1.219838 0.305859 + endloop + endfacet + facet normal 0.420922 0.777906 0.466570 + outer loop + vertex -0.837188 -1.276254 0.306304 + vertex -0.879110 -1.743217 1.122686 + vertex -0.936340 -1.723470 1.141392 + endloop + endfacet + facet normal 0.225111 -0.353196 0.908063 + outer loop + vertex -0.882931 -1.812938 1.093353 + vertex -0.975239 -1.833469 1.108251 + vertex -0.936340 -1.723470 1.141392 + endloop + endfacet + facet normal 0.161638 -0.390208 0.906427 + outer loop + vertex -0.879110 -1.743217 1.122686 + vertex -0.882931 -1.812938 1.093353 + vertex -0.936340 -1.723470 1.141392 + endloop + endfacet + facet normal 0.262340 -0.689983 0.674611 + outer loop + vertex -0.882931 -1.812938 1.093353 + vertex -1.084530 -2.801688 0.160470 + vertex -0.975239 -1.833469 1.108251 + endloop + endfacet + facet normal 0.304612 -0.685769 0.661009 + outer loop + vertex -0.882931 -1.812938 1.093353 + vertex -1.001356 -2.755311 0.170255 + vertex -1.084530 -2.801688 0.160470 + endloop + endfacet + facet normal 0.576874 -0.776171 0.254510 + outer loop + vertex -1.009624 -3.231524 -1.320172 + vertex -1.052176 -3.249437 -1.278350 + vertex -1.084530 -2.801688 0.160470 + endloop + endfacet + facet normal 0.444392 -0.854044 0.270414 + outer loop + vertex -1.001356 -2.755311 0.170255 + vertex -1.009624 -3.231524 -1.320172 + vertex -1.084530 -2.801688 0.160470 + endloop + endfacet + facet normal 0.642835 -0.673016 0.365804 + outer loop + vertex -1.009624 -3.231524 -1.320172 + vertex -1.115638 -3.503742 -1.634704 + vertex -1.052176 -3.249437 -1.278350 + endloop + endfacet + facet normal 0.496771 -0.732070 0.466146 + outer loop + vertex -1.009624 -3.231524 -1.320172 + vertex -1.097689 -3.500874 -1.649329 + vertex -1.115638 -3.503742 -1.634704 + endloop + endfacet + facet normal 0.072988 -0.424990 0.902251 + outer loop + vertex -0.790998 -0.401975 -0.030272 + vertex -0.674250 -0.500161 -0.085965 + vertex -0.808589 -0.547342 -0.097321 + endloop + endfacet + facet normal 0.288186 0.809071 0.512204 + outer loop + vertex -1.080349 -3.510513 -1.643859 + vertex -1.098497 -3.517481 -1.622642 + vertex -1.097689 -3.500874 -1.649329 + endloop + endfacet + facet normal -0.239185 0.477531 0.845432 + outer loop + vertex -0.674250 -0.500161 -0.085965 + vertex -0.837188 -1.276254 0.306304 + vertex -0.808589 -0.547342 -0.097321 + endloop + endfacet + facet normal -0.511623 0.470720 0.718794 + outer loop + vertex -0.674250 -0.500161 -0.085965 + vertex -0.756784 -1.266909 0.357414 + vertex -0.837188 -1.276254 0.306304 + endloop + endfacet + facet normal -0.382026 0.810513 0.443988 + outer loop + vertex -0.834199 -1.742695 1.160377 + vertex -0.879110 -1.743217 1.122686 + vertex -0.837188 -1.276254 0.306304 + endloop + endfacet + facet normal -0.377227 0.812248 0.444919 + outer loop + vertex -0.756784 -1.266909 0.357414 + vertex -0.834199 -1.742695 1.160377 + vertex -0.837188 -1.276254 0.306304 + endloop + endfacet + facet normal -0.615875 -0.276611 0.737688 + outer loop + vertex -0.834199 -1.742695 1.160377 + vertex -0.882931 -1.812938 1.093353 + vertex -0.879110 -1.743217 1.122686 + endloop + endfacet + facet normal -0.620293 -0.271740 0.735795 + outer loop + vertex -0.834199 -1.742695 1.160377 + vertex -0.807871 -1.831055 1.149940 + vertex -0.882931 -1.812938 1.093353 + endloop + endfacet + facet normal -0.567791 -0.538507 0.622594 + outer loop + vertex -0.923037 -2.782653 0.218032 + vertex -1.001356 -2.755311 0.170255 + vertex -0.882931 -1.812938 1.093353 + endloop + endfacet + facet normal -0.588796 -0.528039 0.611959 + outer loop + vertex -0.807871 -1.831055 1.149940 + vertex -0.923037 -2.782653 0.218032 + vertex -0.882931 -1.812938 1.093353 + endloop + endfacet + facet normal -0.461007 -0.844552 0.272404 + outer loop + vertex -0.923037 -2.782653 0.218032 + vertex -1.009624 -3.231524 -1.320172 + vertex -1.001356 -2.755311 0.170255 + endloop + endfacet + facet normal -0.626500 -0.738025 0.250633 + outer loop + vertex -0.923037 -2.782653 0.218032 + vertex -0.974341 -3.256226 -1.304714 + vertex -1.009624 -3.231524 -1.320172 + endloop + endfacet + facet normal -0.521525 -0.586633 0.619576 + outer loop + vertex -1.080349 -3.510513 -1.643859 + vertex -1.097689 -3.500874 -1.649329 + vertex -1.009624 -3.231524 -1.320172 + endloop + endfacet + facet normal -0.621272 -0.521287 0.585048 + outer loop + vertex -0.974341 -3.256226 -1.304714 + vertex -1.080349 -3.510513 -1.643859 + vertex -1.009624 -3.231524 -1.320172 + endloop + endfacet + facet normal 0.072989 -0.424988 0.902251 + outer loop + vertex -0.790998 -0.401975 -0.030272 + vertex -0.627824 -0.379043 -0.032670 + vertex -0.674250 -0.500161 -0.085965 + endloop + endfacet + facet normal 0.288157 0.809092 0.512187 + outer loop + vertex -1.076676 -3.525398 -1.622411 + vertex -1.098497 -3.517481 -1.622642 + vertex -1.080349 -3.510513 -1.643859 + endloop + endfacet + facet normal -0.970688 0.189770 0.147484 + outer loop + vertex -0.733861 -1.198839 0.420700 + vertex -0.756784 -1.266909 0.357414 + vertex -0.674250 -0.500161 -0.085965 + endloop + endfacet + facet normal -0.937110 0.253749 0.239660 + outer loop + vertex -0.627824 -0.379043 -0.032670 + vertex -0.733861 -1.198839 0.420700 + vertex -0.674250 -0.500161 -0.085965 + endloop + endfacet + facet normal -0.962245 0.264556 0.063988 + outer loop + vertex -0.733861 -1.198839 0.420700 + vertex -0.834199 -1.742695 1.160377 + vertex -0.756784 -1.266909 0.357414 + endloop + endfacet + facet normal -0.992403 0.111044 -0.052974 + outer loop + vertex -0.733861 -1.198839 0.420700 + vertex -0.835425 -1.722300 1.226081 + vertex -0.834199 -1.742695 1.160377 + endloop + endfacet + facet normal -0.955061 -0.270182 -0.121903 + outer loop + vertex -0.806580 -1.874175 1.235398 + vertex -0.807871 -1.831055 1.149940 + vertex -0.834199 -1.742695 1.160377 + endloop + endfacet + facet normal -0.982131 -0.184147 0.038845 + outer loop + vertex -0.835425 -1.722300 1.226081 + vertex -0.806580 -1.874175 1.235398 + vertex -0.834199 -1.742695 1.160377 + endloop + endfacet + facet normal -0.996195 0.070829 0.050785 + outer loop + vertex -0.806580 -1.874175 1.235398 + vertex -0.923037 -2.782653 0.218032 + vertex -0.807871 -1.831055 1.149940 + endloop + endfacet + facet normal -0.982286 -0.069130 0.174172 + outer loop + vertex -0.806580 -1.874175 1.235398 + vertex -0.908545 -2.863121 0.267821 + vertex -0.923037 -2.782653 0.218032 + endloop + endfacet + facet normal -0.999483 0.009033 0.030865 + outer loop + vertex -0.972894 -3.304943 -1.243616 + vertex -0.974341 -3.256226 -1.304714 + vertex -0.923037 -2.782653 0.218032 + endloop + endfacet + facet normal -0.988476 -0.128697 0.079705 + outer loop + vertex -0.908545 -2.863121 0.267821 + vertex -0.972894 -3.304943 -1.243616 + vertex -0.923037 -2.782653 0.218032 + endloop + endfacet + facet normal -0.969164 0.180972 0.167245 + outer loop + vertex -0.972894 -3.304943 -1.243616 + vertex -1.080349 -3.510513 -1.643859 + vertex -0.974341 -3.256226 -1.304714 + endloop + endfacet + facet normal -0.972173 0.078271 0.220801 + outer loop + vertex -0.972894 -3.304943 -1.243616 + vertex -1.076676 -3.525398 -1.622411 + vertex -1.080349 -3.510513 -1.643859 + endloop + endfacet + facet normal -0.041442 0.415022 0.908867 + outer loop + vertex -0.614051 0.300803 -0.009824 + vertex -0.709183 0.205512 0.029352 + vertex -0.771921 0.340665 -0.035225 + endloop + endfacet + facet normal 0.109959 -0.990334 0.084544 + outer loop + vertex -0.453719 3.545088 -1.521005 + vertex -0.475866 3.542093 -1.527286 + vertex -0.468992 3.545227 -1.499515 + endloop + endfacet + facet normal -0.570165 0.334529 -0.750334 + outer loop + vertex -0.614051 0.300803 -0.009824 + vertex -0.712241 1.127192 0.433227 + vertex -0.775598 1.057486 0.450292 + endloop + endfacet + facet normal -0.611606 0.311619 -0.727208 + outer loop + vertex -0.614051 0.300803 -0.009824 + vertex -0.775598 1.057486 0.450292 + vertex -0.709183 0.205512 0.029352 + endloop + endfacet + facet normal -0.695669 0.507933 -0.507986 + outer loop + vertex -0.712241 1.127192 0.433227 + vertex -0.897681 1.658402 1.218335 + vertex -0.775598 1.057486 0.450292 + endloop + endfacet + facet normal -0.568472 0.601666 -0.561104 + outer loop + vertex -0.897681 1.658402 1.218335 + vertex -0.953412 1.638479 1.253435 + vertex -0.775598 1.057486 0.450292 + endloop + endfacet + facet normal -0.332946 0.200344 -0.921417 + outer loop + vertex -0.897681 1.658402 1.218335 + vertex -0.855414 1.806430 1.235248 + vertex -0.932361 1.849565 1.272431 + endloop + endfacet + facet normal -0.561176 0.129532 -0.817498 + outer loop + vertex -0.897681 1.658402 1.218335 + vertex -0.932361 1.849565 1.272431 + vertex -0.953412 1.638479 1.253435 + endloop + endfacet + facet normal -0.571413 -0.403153 -0.714811 + outer loop + vertex -0.855414 1.806430 1.235248 + vertex -0.710753 2.348053 0.814132 + vertex -0.932361 1.849565 1.272431 + endloop + endfacet + facet normal -0.609458 -0.372496 -0.699863 + outer loop + vertex -0.710753 2.348053 0.814132 + vertex -0.764732 2.426953 0.819145 + vertex -0.932361 1.849565 1.272431 + endloop + endfacet + facet normal -0.704305 -0.627008 -0.332891 + outer loop + vertex -0.710753 2.348053 0.814132 + vertex -0.440545 3.160259 -1.287360 + vertex -0.480171 3.169330 -1.220608 + endloop + endfacet + facet normal -0.795601 -0.525117 -0.302111 + outer loop + vertex -0.710753 2.348053 0.814132 + vertex -0.480171 3.169330 -1.220608 + vertex -0.764732 2.426953 0.819145 + endloop + endfacet + facet normal -0.836550 -0.304983 -0.455159 + outer loop + vertex -0.440545 3.160259 -1.287360 + vertex -0.453719 3.545088 -1.521005 + vertex -0.480171 3.169330 -1.220608 + endloop + endfacet + facet normal -0.756833 -0.374799 -0.535471 + outer loop + vertex -0.453719 3.545088 -1.521005 + vertex -0.468992 3.545227 -1.499515 + vertex -0.480171 3.169330 -1.220608 + endloop + endfacet + facet normal -0.041446 0.415020 0.908868 + outer loop + vertex -0.709183 0.205512 0.029352 + vertex -0.851559 0.211993 0.019900 + vertex -0.771921 0.340665 -0.035225 + endloop + endfacet + facet normal 0.109957 -0.990334 0.084545 + outer loop + vertex -0.468992 3.545227 -1.499515 + vertex -0.475866 3.542093 -1.527286 + vertex -0.489443 3.543005 -1.498937 + endloop + endfacet + facet normal 0.079495 0.446532 -0.891229 + outer loop + vertex -0.709183 0.205512 0.029352 + vertex -0.775598 1.057486 0.450292 + vertex -0.851559 0.211993 0.019900 + endloop + endfacet + facet normal 0.362294 0.396775 -0.843394 + outer loop + vertex -0.775598 1.057486 0.450292 + vertex -0.859056 1.040657 0.406524 + vertex -0.851559 0.211993 0.019900 + endloop + endfacet + facet normal 0.138292 0.816729 -0.560204 + outer loop + vertex -0.775598 1.057486 0.450292 + vertex -0.953412 1.638479 1.253435 + vertex -1.008198 1.633792 1.233077 + endloop + endfacet + facet normal 0.130304 0.816518 -0.562422 + outer loop + vertex -0.775598 1.057486 0.450292 + vertex -1.008198 1.633792 1.233077 + vertex -0.859056 1.040657 0.406524 + endloop + endfacet + facet normal 0.344124 0.050054 -0.937589 + outer loop + vertex -0.953412 1.638479 1.253435 + vertex -0.932361 1.849565 1.272431 + vertex -1.008198 1.633792 1.233077 + endloop + endfacet + facet normal 0.410273 0.022082 -0.911696 + outer loop + vertex -0.932361 1.849565 1.272431 + vertex -1.019176 1.860608 1.233630 + vertex -1.008198 1.633792 1.233077 + endloop + endfacet + facet normal 0.258675 -0.641834 -0.721898 + outer loop + vertex -0.932361 1.849565 1.272431 + vertex -0.764732 2.426953 0.819145 + vertex -0.845875 2.446826 0.772400 + endloop + endfacet + facet normal 0.242763 -0.643158 -0.726232 + outer loop + vertex -0.932361 1.849565 1.272431 + vertex -0.845875 2.446826 0.772400 + vertex -1.019176 1.860608 1.233630 + endloop + endfacet + facet normal -0.030602 -0.937878 -0.345614 + outer loop + vertex -0.764732 2.426953 0.819145 + vertex -0.480171 3.169330 -1.220608 + vertex -0.845875 2.446826 0.772400 + endloop + endfacet + facet normal 0.004704 -0.940396 -0.340049 + outer loop + vertex -0.480171 3.169330 -1.220608 + vertex -0.525406 3.166777 -1.214174 + vertex -0.845875 2.446826 0.772400 + endloop + endfacet + facet normal 0.042110 -0.596148 -0.801769 + outer loop + vertex -0.480171 3.169330 -1.220608 + vertex -0.468992 3.545227 -1.499515 + vertex -0.489443 3.543005 -1.498937 + endloop + endfacet + facet normal -0.079894 -0.596715 -0.798466 + outer loop + vertex -0.480171 3.169330 -1.220608 + vertex -0.489443 3.543005 -1.498937 + vertex -0.525406 3.166777 -1.214174 + endloop + endfacet + facet normal -0.041444 0.415020 0.908868 + outer loop + vertex -0.851559 0.211993 0.019900 + vertex -0.933966 0.315369 -0.031063 + vertex -0.771921 0.340665 -0.035225 + endloop + endfacet + facet normal 0.109934 -0.990338 0.084534 + outer loop + vertex -0.489443 3.543005 -1.498937 + vertex -0.475866 3.542093 -1.527286 + vertex -0.499670 3.540097 -1.519705 + endloop + endfacet + facet normal 0.903346 0.188033 -0.385498 + outer loop + vertex -0.851559 0.211993 0.019900 + vertex -0.859056 1.040657 0.406524 + vertex -0.899771 1.089378 0.334881 + endloop + endfacet + facet normal 0.726601 0.267169 -0.632986 + outer loop + vertex -0.851559 0.211993 0.019900 + vertex -0.899771 1.089378 0.334881 + vertex -0.933966 0.315369 -0.031063 + endloop + endfacet + facet normal 0.867568 0.464764 -0.176972 + outer loop + vertex -0.859056 1.040657 0.406524 + vertex -1.008198 1.633792 1.233077 + vertex -0.899771 1.089378 0.334881 + endloop + endfacet + facet normal 0.925578 0.362779 -0.108154 + outer loop + vertex -1.008198 1.633792 1.233077 + vertex -1.020784 1.647871 1.172592 + vertex -0.899771 1.089378 0.334881 + endloop + endfacet + facet normal 0.932907 0.046024 -0.357164 + outer loop + vertex -1.008198 1.633792 1.233077 + vertex -1.019176 1.860608 1.233630 + vertex -1.050486 1.831240 1.148066 + endloop + endfacet + facet normal 0.975856 0.135113 -0.171609 + outer loop + vertex -1.008198 1.633792 1.233077 + vertex -1.050486 1.831240 1.148066 + vertex -1.020784 1.647871 1.172592 + endloop + endfacet + facet normal 0.892838 -0.410217 -0.185908 + outer loop + vertex -1.019176 1.860608 1.233630 + vertex -0.845875 2.446826 0.772400 + vertex -1.050486 1.831240 1.148066 + endloop + endfacet + facet normal 0.857569 -0.443765 -0.260093 + outer loop + vertex -0.845875 2.446826 0.772400 + vertex -0.893078 2.392708 0.709098 + vertex -1.050486 1.831240 1.148066 + endloop + endfacet + facet normal 0.783792 -0.613570 -0.095924 + outer loop + vertex -0.845875 2.446826 0.772400 + vertex -0.525406 3.166777 -1.214174 + vertex -0.542185 3.154524 -1.272899 + endloop + endfacet + facet normal 0.799033 -0.594930 -0.087211 + outer loop + vertex -0.845875 2.446826 0.772400 + vertex -0.542185 3.154524 -1.272899 + vertex -0.893078 2.392708 0.709098 + endloop + endfacet + facet normal 0.942718 -0.253892 -0.216383 + outer loop + vertex -0.525406 3.166777 -1.214174 + vertex -0.489443 3.543005 -1.498937 + vertex -0.542185 3.154524 -1.272899 + endloop + endfacet + facet normal 0.862534 -0.336816 -0.377612 + outer loop + vertex -0.489443 3.543005 -1.498937 + vertex -0.499670 3.540097 -1.519705 + vertex -0.542185 3.154524 -1.272899 + endloop + endfacet + facet normal -0.041446 0.415029 0.908864 + outer loop + vertex -0.933966 0.315369 -0.031063 + vertex -0.894350 0.437791 -0.085160 + vertex -0.771921 0.340665 -0.035225 + endloop + endfacet + facet normal 0.109906 -0.990349 0.084440 + outer loop + vertex -0.499670 3.540097 -1.519705 + vertex -0.475866 3.542093 -1.527286 + vertex -0.491974 3.538694 -1.546181 + endloop + endfacet + facet normal 0.941181 -0.177516 0.287518 + outer loop + vertex -0.933966 0.315369 -0.031063 + vertex -0.899771 1.089378 0.334881 + vertex -0.894350 0.437791 -0.085160 + endloop + endfacet + facet normal 0.925102 -0.200272 0.322611 + outer loop + vertex -0.899771 1.089378 0.334881 + vertex -0.867084 1.166961 0.289312 + vertex -0.894350 0.437791 -0.085160 + endloop + endfacet + facet normal 0.809640 -0.427607 0.402039 + outer loop + vertex -0.899771 1.089378 0.334881 + vertex -1.020784 1.647871 1.172592 + vertex -0.981692 1.670114 1.117526 + endloop + endfacet + facet normal 0.933612 -0.233975 0.271337 + outer loop + vertex -0.899771 1.089378 0.334881 + vertex -0.981692 1.670114 1.117526 + vertex -0.867084 1.166961 0.289312 + endloop + endfacet + facet normal 0.756897 0.205577 0.620359 + outer loop + vertex -1.020784 1.647871 1.172592 + vertex -1.050486 1.831240 1.148066 + vertex -0.981692 1.670114 1.117526 + endloop + endfacet + facet normal 0.866550 0.293460 0.403698 + outer loop + vertex -1.050486 1.831240 1.148066 + vertex -1.002712 1.783576 1.080167 + vertex -0.981692 1.670114 1.117526 + endloop + endfacet + facet normal 0.904025 0.075514 0.420758 + outer loop + vertex -1.050486 1.831240 1.148066 + vertex -0.893078 2.392708 0.709098 + vertex -0.870797 2.305352 0.676905 + endloop + endfacet + facet normal 0.856917 0.161638 0.489456 + outer loop + vertex -1.050486 1.831240 1.148066 + vertex -0.870797 2.305352 0.676905 + vertex -1.002712 1.783576 1.080167 + endloop + endfacet + facet normal 0.959723 0.159563 0.231240 + outer loop + vertex -0.893078 2.392708 0.709098 + vertex -0.542185 3.154524 -1.272899 + vertex -0.870797 2.305352 0.676905 + endloop + endfacet + facet normal 0.942927 0.216353 0.253142 + outer loop + vertex -0.542185 3.154524 -1.272899 + vertex -0.517877 3.141793 -1.352567 + vertex -0.870797 2.305352 0.676905 + endloop + endfacet + facet normal 0.958870 0.070300 0.275003 + outer loop + vertex -0.542185 3.154524 -1.272899 + vertex -0.499670 3.540097 -1.519705 + vertex -0.491974 3.538694 -1.546181 + endloop + endfacet + facet normal 0.957077 0.074212 0.280173 + outer loop + vertex -0.542185 3.154524 -1.272899 + vertex -0.491974 3.538694 -1.546181 + vertex -0.517877 3.141793 -1.352567 + endloop + endfacet + facet normal -0.041443 0.415033 0.908862 + outer loop + vertex -0.894350 0.437791 -0.085160 + vertex -0.762543 0.487076 -0.101655 + vertex -0.771921 0.340665 -0.035225 + endloop + endfacet + facet normal 0.109902 -0.990349 0.084443 + outer loop + vertex -0.491974 3.538694 -1.546181 + vertex -0.475866 3.542093 -1.527286 + vertex -0.472149 3.539850 -1.558426 + endloop + endfacet + facet normal 0.109040 -0.457336 0.882584 + outer loop + vertex -0.894350 0.437791 -0.085160 + vertex -0.867084 1.166961 0.289312 + vertex -0.785607 1.214984 0.304130 + endloop + endfacet + facet normal 0.277855 -0.461014 0.842771 + outer loop + vertex -0.894350 0.437791 -0.085160 + vertex -0.785607 1.214984 0.304130 + vertex -0.762543 0.487076 -0.101655 + endloop + endfacet + facet normal 0.361493 -0.773815 0.520128 + outer loop + vertex -0.867084 1.166961 0.289312 + vertex -0.981692 1.670114 1.117526 + vertex -0.785607 1.214984 0.304130 + endloop + endfacet + facet normal 0.251163 -0.817641 0.518054 + outer loop + vertex -0.981692 1.670114 1.117526 + vertex -0.920360 1.683771 1.109345 + vertex -0.785607 1.214984 0.304130 + endloop + endfacet + facet normal 0.099152 0.327728 0.939555 + outer loop + vertex -0.981692 1.670114 1.117526 + vertex -1.002712 1.783576 1.080167 + vertex -0.911831 1.753510 1.081064 + endloop + endfacet + facet normal 0.041085 0.371169 0.927656 + outer loop + vertex -0.981692 1.670114 1.117526 + vertex -0.911831 1.753510 1.081064 + vertex -0.920360 1.683771 1.109345 + endloop + endfacet + facet normal 0.181426 0.572242 0.799764 + outer loop + vertex -1.002712 1.783576 1.080167 + vertex -0.870797 2.305352 0.676905 + vertex -0.911831 1.753510 1.081064 + endloop + endfacet + facet normal 0.172062 0.573693 0.800794 + outer loop + vertex -0.870797 2.305352 0.676905 + vertex -0.795808 2.250535 0.700063 + vertex -0.911831 1.753510 1.081064 + endloop + endfacet + facet normal 0.413948 0.814009 0.407476 + outer loop + vertex -0.870797 2.305352 0.676905 + vertex -0.517877 3.141793 -1.352567 + vertex -0.470782 3.138176 -1.393183 + endloop + endfacet + facet normal 0.453949 0.792808 0.406677 + outer loop + vertex -0.870797 2.305352 0.676905 + vertex -0.470782 3.138176 -1.393183 + vertex -0.795808 2.250535 0.700063 + endloop + endfacet + facet normal 0.635360 0.304674 0.709571 + outer loop + vertex -0.517877 3.141793 -1.352567 + vertex -0.491974 3.538694 -1.546181 + vertex -0.470782 3.138176 -1.393183 + endloop + endfacet + facet normal 0.480959 0.334958 0.810235 + outer loop + vertex -0.491974 3.538694 -1.546181 + vertex -0.472149 3.539850 -1.558426 + vertex -0.470782 3.138176 -1.393183 + endloop + endfacet + facet normal -0.041440 0.415033 0.908862 + outer loop + vertex -0.762543 0.487076 -0.101655 + vertex -0.637798 0.426110 -0.068128 + vertex -0.771921 0.340665 -0.035225 + endloop + endfacet + facet normal 0.110049 -0.990331 0.084460 + outer loop + vertex -0.472149 3.539850 -1.558426 + vertex -0.475866 3.542093 -1.527286 + vertex -0.455124 3.542697 -1.547222 + endloop + endfacet + facet normal -0.430225 -0.449914 0.782614 + outer loop + vertex -0.762543 0.487076 -0.101655 + vertex -0.785607 1.214984 0.304130 + vertex -0.637798 0.426110 -0.068128 + endloop + endfacet + facet normal -0.674363 -0.414663 0.610974 + outer loop + vertex -0.785607 1.214984 0.304130 + vertex -0.716696 1.197285 0.368179 + vertex -0.637798 0.426110 -0.068128 + endloop + endfacet + facet normal -0.534693 -0.766140 0.356556 + outer loop + vertex -0.785607 1.214984 0.304130 + vertex -0.920360 1.683771 1.109345 + vertex -0.882972 1.678557 1.154210 + endloop + endfacet + facet normal -0.530333 -0.768368 0.358271 + outer loop + vertex -0.785607 1.214984 0.304130 + vertex -0.882972 1.678557 1.154210 + vertex -0.716696 1.197285 0.368179 + endloop + endfacet + facet normal -0.702823 0.339469 0.625140 + outer loop + vertex -0.920360 1.683771 1.109345 + vertex -0.911831 1.753510 1.081064 + vertex -0.882972 1.678557 1.154210 + endloop + endfacet + facet normal -0.707317 0.335091 0.622428 + outer loop + vertex -0.911831 1.753510 1.081064 + vertex -0.846277 1.763681 1.150082 + vertex -0.882972 1.678557 1.154210 + endloop + endfacet + facet normal -0.619192 0.563640 0.546727 + outer loop + vertex -0.911831 1.753510 1.081064 + vertex -0.795808 2.250535 0.700063 + vertex -0.724583 2.269540 0.761136 + endloop + endfacet + facet normal -0.640846 0.558844 0.526318 + outer loop + vertex -0.911831 1.753510 1.081064 + vertex -0.724583 2.269540 0.761136 + vertex -0.846277 1.763681 1.150082 + endloop + endfacet + facet normal -0.466305 0.838134 0.283005 + outer loop + vertex -0.795808 2.250535 0.700063 + vertex -0.470782 3.138176 -1.393183 + vertex -0.724583 2.269540 0.761136 + endloop + endfacet + facet normal -0.445954 0.847108 0.289021 + outer loop + vertex -0.470782 3.138176 -1.393183 + vertex -0.436367 3.146393 -1.364164 + vertex -0.724583 2.269540 0.761136 + endloop + endfacet + facet normal -0.558004 0.314088 0.768102 + outer loop + vertex -0.470782 3.138176 -1.393183 + vertex -0.472149 3.539850 -1.558426 + vertex -0.455124 3.542697 -1.547222 + endloop + endfacet + facet normal -0.656411 0.290524 0.696219 + outer loop + vertex -0.470782 3.138176 -1.393183 + vertex -0.455124 3.542697 -1.547222 + vertex -0.436367 3.146393 -1.364164 + endloop + endfacet + facet normal -0.041439 0.415031 0.908863 + outer loop + vertex -0.637798 0.426110 -0.068128 + vertex -0.614051 0.300803 -0.009824 + vertex -0.771921 0.340665 -0.035225 + endloop + endfacet + facet normal 0.109999 -0.990341 0.084407 + outer loop + vertex -0.455124 3.542697 -1.547222 + vertex -0.475866 3.542093 -1.527286 + vertex -0.453719 3.545088 -1.521005 + endloop + endfacet + facet normal -0.995850 -0.087267 -0.025835 + outer loop + vertex -0.637798 0.426110 -0.068128 + vertex -0.716696 1.197285 0.368179 + vertex -0.712241 1.127192 0.433227 + endloop + endfacet + facet normal -0.985555 -0.154404 0.069576 + outer loop + vertex -0.637798 0.426110 -0.068128 + vertex -0.712241 1.127192 0.433227 + vertex -0.614051 0.300803 -0.009824 + endloop + endfacet + facet normal -0.980780 -0.162526 -0.107962 + outer loop + vertex -0.716696 1.197285 0.368179 + vertex -0.882972 1.678557 1.154210 + vertex -0.712241 1.127192 0.433227 + endloop + endfacet + facet normal -0.974204 -0.006703 -0.225569 + outer loop + vertex -0.882972 1.678557 1.154210 + vertex -0.897681 1.658402 1.218335 + vertex -0.712241 1.127192 0.433227 + endloop + endfacet + facet normal -0.886417 0.368533 -0.280085 + outer loop + vertex -0.882972 1.678557 1.154210 + vertex -0.846277 1.763681 1.150082 + vertex -0.855414 1.806430 1.235248 + endloop + endfacet + facet normal -0.949701 0.285797 -0.128012 + outer loop + vertex -0.882972 1.678557 1.154210 + vertex -0.855414 1.806430 1.235248 + vertex -0.897681 1.658402 1.218335 + endloop + endfacet + facet normal -0.980542 0.111841 -0.161335 + outer loop + vertex -0.846277 1.763681 1.150082 + vertex -0.724583 2.269540 0.761136 + vertex -0.855414 1.806430 1.235248 + endloop + endfacet + facet normal -0.975146 0.212986 -0.061048 + outer loop + vertex -0.724583 2.269540 0.761136 + vertex -0.710753 2.348053 0.814132 + vertex -0.855414 1.806430 1.235248 + endloop + endfacet + facet normal -0.987725 0.135249 -0.078147 + outer loop + vertex -0.724583 2.269540 0.761136 + vertex -0.436367 3.146393 -1.364164 + vertex -0.440545 3.160259 -1.287360 + endloop + endfacet + facet normal -0.977861 0.203926 -0.046917 + outer loop + vertex -0.724583 2.269540 0.761136 + vertex -0.440545 3.160259 -1.287360 + vertex -0.710753 2.348053 0.814132 + endloop + endfacet + facet normal -0.996882 -0.066672 -0.042191 + outer loop + vertex -0.436367 3.146393 -1.364164 + vertex -0.455124 3.542697 -1.547222 + vertex -0.440545 3.160259 -1.287360 + endloop + endfacet + facet normal -0.998558 -0.001607 0.053657 + outer loop + vertex -0.455124 3.542697 -1.547222 + vertex -0.453719 3.545088 -1.521005 + vertex -0.440545 3.160259 -1.287360 + endloop + endfacet + facet normal 0.272474 0.292852 0.916513 + outer loop + vertex -0.253797 0.214561 -0.045835 + vertex -0.376741 0.170128 0.004914 + vertex -0.376302 0.324781 -0.044633 + endloop + endfacet + facet normal -0.247446 -0.867470 0.431586 + outer loop + vertex 0.933725 3.979607 -1.556237 + vertex 0.911266 3.985315 -1.557641 + vertex 0.926604 3.992514 -1.534378 + endloop + endfacet + facet normal -0.777863 0.563658 -0.277884 + outer loop + vertex -0.253797 0.214561 -0.045835 + vertex 0.103584 0.929287 0.403520 + vertex 0.045554 0.876026 0.457925 + endloop + endfacet + facet normal -0.477920 0.658786 -0.581028 + outer loop + vertex -0.253797 0.214561 -0.045835 + vertex 0.045554 0.876026 0.457925 + vertex -0.376741 0.170128 0.004914 + endloop + endfacet + facet normal -0.779423 0.557750 -0.285332 + outer loop + vertex 0.103584 0.929287 0.403520 + vertex 0.204066 1.506257 1.256863 + vertex 0.045554 0.876026 0.457925 + endloop + endfacet + facet normal -0.765340 0.570419 -0.298121 + outer loop + vertex 0.204066 1.506257 1.256863 + vertex 0.174039 1.498042 1.318229 + vertex 0.045554 0.876026 0.457925 + endloop + endfacet + facet normal -0.725150 0.339533 -0.599062 + outer loop + vertex 0.204066 1.506257 1.256863 + vertex 0.282789 1.638025 1.236253 + vertex 0.252124 1.695822 1.306131 + endloop + endfacet + facet normal -0.867439 0.319119 -0.381722 + outer loop + vertex 0.204066 1.506257 1.256863 + vertex 0.252124 1.695822 1.306131 + vertex 0.174039 1.498042 1.318229 + endloop + endfacet + facet normal -0.886598 0.080321 -0.455513 + outer loop + vertex 0.282789 1.638025 1.236253 + vertex 0.676887 2.684097 0.653648 + vertex 0.252124 1.695822 1.306131 + endloop + endfacet + facet normal -0.822990 -0.021063 -0.567665 + outer loop + vertex 0.676887 2.684097 0.653648 + vertex 0.655481 2.773188 0.681377 + vertex 0.252124 1.695822 1.306131 + endloop + endfacet + facet normal -0.987821 -0.067298 -0.140287 + outer loop + vertex 0.676887 2.684097 0.653648 + vertex 0.870213 3.711051 -1.200285 + vertex 0.858199 3.754962 -1.136756 + endloop + endfacet + facet normal -0.965102 -0.169849 -0.199324 + outer loop + vertex 0.676887 2.684097 0.653648 + vertex 0.858199 3.754962 -1.136756 + vertex 0.655481 2.773188 0.681377 + endloop + endfacet + facet normal -0.983464 -0.007265 -0.180959 + outer loop + vertex 0.870213 3.711051 -1.200285 + vertex 0.933725 3.979607 -1.556237 + vertex 0.858199 3.754962 -1.136756 + endloop + endfacet + facet normal -0.962733 -0.124581 -0.240053 + outer loop + vertex 0.933725 3.979607 -1.556237 + vertex 0.926604 3.992514 -1.534378 + vertex 0.858199 3.754962 -1.136756 + endloop + endfacet + facet normal 0.272467 0.292852 0.916515 + outer loop + vertex -0.376741 0.170128 0.004914 + vertex -0.499356 0.242150 0.018352 + vertex -0.376302 0.324781 -0.044633 + endloop + endfacet + facet normal -0.247478 -0.867453 0.431602 + outer loop + vertex 0.926604 3.992514 -1.534378 + vertex 0.911266 3.985315 -1.557641 + vertex 0.907933 4.000000 -1.530038 + endloop + endfacet + facet normal 0.172648 0.456757 -0.872677 + outer loop + vertex -0.376741 0.170128 0.004914 + vertex 0.045554 0.876026 0.457925 + vertex -0.499356 0.242150 0.018352 + endloop + endfacet + facet normal -0.046516 0.595932 -0.801687 + outer loop + vertex 0.045554 0.876026 0.457925 + vertex -0.049308 0.883088 0.468678 + vertex -0.499356 0.242150 0.018352 + endloop + endfacet + facet normal 0.005787 0.809949 -0.586472 + outer loop + vertex 0.045554 0.876026 0.457925 + vertex 0.174039 1.498042 1.318229 + vertex 0.117908 1.508241 1.331761 + endloop + endfacet + facet normal -0.006080 0.810414 -0.585826 + outer loop + vertex 0.045554 0.876026 0.457925 + vertex 0.117908 1.508241 1.331761 + vertex -0.049308 0.883088 0.468678 + endloop + endfacet + facet normal -0.228952 0.030877 -0.972948 + outer loop + vertex 0.174039 1.498042 1.318229 + vertex 0.252124 1.695822 1.306131 + vertex 0.117908 1.508241 1.331761 + endloop + endfacet + facet normal -0.168553 -0.014067 -0.985592 + outer loop + vertex 0.252124 1.695822 1.306131 + vertex 0.164022 1.730315 1.320705 + vertex 0.117908 1.508241 1.331761 + endloop + endfacet + facet normal -0.246821 -0.415317 -0.875552 + outer loop + vertex 0.252124 1.695822 1.306131 + vertex 0.655481 2.773188 0.681377 + vertex 0.569666 2.815407 0.685542 + endloop + endfacet + facet normal -0.298811 -0.396427 -0.868077 + outer loop + vertex 0.252124 1.695822 1.306131 + vertex 0.569666 2.815407 0.685542 + vertex 0.164022 1.730315 1.320705 + endloop + endfacet + facet normal -0.408191 -0.783465 -0.468576 + outer loop + vertex 0.655481 2.773188 0.681377 + vertex 0.858199 3.754962 -1.136756 + vertex 0.569666 2.815407 0.685542 + endloop + endfacet + facet normal -0.526140 -0.719046 -0.454038 + outer loop + vertex 0.858199 3.754962 -1.136756 + vertex 0.819289 3.774946 -1.123315 + vertex 0.569666 2.815407 0.685542 + endloop + endfacet + facet normal -0.419350 -0.745756 -0.517681 + outer loop + vertex 0.858199 3.754962 -1.136756 + vertex 0.926604 3.992514 -1.534378 + vertex 0.907933 4.000000 -1.530038 + endloop + endfacet + facet normal -0.526109 -0.690328 -0.496646 + outer loop + vertex 0.858199 3.754962 -1.136756 + vertex 0.907933 4.000000 -1.530038 + vertex 0.819289 3.774946 -1.123315 + endloop + endfacet + facet normal 0.272470 0.292848 0.916515 + outer loop + vertex -0.499356 0.242150 0.018352 + vertex -0.529306 0.376396 -0.015639 + vertex -0.376302 0.324781 -0.044633 + endloop + endfacet + facet normal -0.247462 -0.867456 0.431605 + outer loop + vertex 0.907933 4.000000 -1.530038 + vertex 0.911266 3.985315 -1.557641 + vertex 0.891771 3.996428 -1.546482 + endloop + endfacet + facet normal 0.628429 0.100671 -0.771325 + outer loop + vertex -0.499356 0.242150 0.018352 + vertex -0.049308 0.883088 0.468678 + vertex -0.109567 0.945155 0.427683 + endloop + endfacet + facet normal 0.731984 -0.009186 -0.681260 + outer loop + vertex -0.499356 0.242150 0.018352 + vertex -0.109567 0.945155 0.427683 + vertex -0.529306 0.376396 -0.015639 + endloop + endfacet + facet normal 0.768509 0.438165 -0.466267 + outer loop + vertex -0.049308 0.883088 0.468678 + vertex 0.117908 1.508241 1.331761 + vertex -0.109567 0.945155 0.427683 + endloop + endfacet + facet normal 0.759350 0.449147 -0.470802 + outer loop + vertex 0.117908 1.508241 1.331761 + vertex 0.077941 1.529177 1.287271 + vertex -0.109567 0.945155 0.427683 + endloop + endfacet + facet normal 0.560265 -0.156831 -0.813331 + outer loop + vertex 0.117908 1.508241 1.331761 + vertex 0.164022 1.730315 1.320705 + vertex 0.084825 1.715526 1.269002 + endloop + endfacet + facet normal 0.718180 -0.094124 -0.689462 + outer loop + vertex 0.117908 1.508241 1.331761 + vertex 0.084825 1.715526 1.269002 + vertex 0.077941 1.529177 1.287271 + endloop + endfacet + facet normal 0.521722 -0.567763 -0.636751 + outer loop + vertex 0.164022 1.730315 1.320705 + vertex 0.569666 2.815407 0.685542 + vertex 0.084825 1.715526 1.269002 + endloop + endfacet + facet normal 0.426157 -0.563345 -0.707836 + outer loop + vertex 0.569666 2.815407 0.685542 + vertex 0.484060 2.778963 0.663007 + vertex 0.084825 1.715526 1.269002 + endloop + endfacet + facet normal 0.688727 -0.675522 -0.263297 + outer loop + vertex 0.569666 2.815407 0.685542 + vertex 0.819289 3.774946 -1.123315 + vertex 0.782781 3.755951 -1.170079 + endloop + endfacet + facet normal 0.444304 -0.818636 -0.363908 + outer loop + vertex 0.569666 2.815407 0.685542 + vertex 0.782781 3.755951 -1.170079 + vertex 0.484060 2.778963 0.663007 + endloop + endfacet + facet normal 0.672471 -0.699887 -0.240710 + outer loop + vertex 0.819289 3.774946 -1.123315 + vertex 0.907933 4.000000 -1.530038 + vertex 0.782781 3.755951 -1.170079 + endloop + endfacet + facet normal 0.523807 -0.778528 -0.345716 + outer loop + vertex 0.907933 4.000000 -1.530038 + vertex 0.891771 3.996428 -1.546482 + vertex 0.782781 3.755951 -1.170079 + endloop + endfacet + facet normal 0.272472 0.292858 0.916511 + outer loop + vertex -0.529306 0.376396 -0.015639 + vertex -0.444043 0.471773 -0.071463 + vertex -0.376302 0.324781 -0.044633 + endloop + endfacet + facet normal -0.247544 -0.867487 0.431495 + outer loop + vertex 0.891771 3.996428 -1.546482 + vertex 0.911266 3.985315 -1.557641 + vertex 0.890291 3.984491 -1.571330 + endloop + endfacet + facet normal 0.767618 -0.634876 0.087728 + outer loop + vertex -0.529306 0.376396 -0.015639 + vertex -0.109567 0.945155 0.427683 + vertex -0.444043 0.471773 -0.071463 + endloop + endfacet + facet normal 0.886160 -0.420222 -0.195281 + outer loop + vertex -0.109567 0.945155 0.427683 + vertex -0.089849 1.015489 0.365809 + vertex -0.444043 0.471773 -0.071463 + endloop + endfacet + facet normal 0.946717 -0.321838 0.012149 + outer loop + vertex -0.109567 0.945155 0.427683 + vertex 0.077941 1.529177 1.287271 + vertex 0.084233 1.545081 1.218260 + endloop + endfacet + facet normal 0.958333 -0.285045 -0.018619 + outer loop + vertex -0.109567 0.945155 0.427683 + vertex 0.084233 1.545081 1.218260 + vertex -0.089849 1.015489 0.365809 + endloop + endfacet + facet normal 0.996037 -0.028539 0.084242 + outer loop + vertex 0.077941 1.529177 1.287271 + vertex 0.084825 1.715526 1.269002 + vertex 0.084233 1.545081 1.218260 + endloop + endfacet + facet normal 0.985585 0.045119 -0.163055 + outer loop + vertex 0.084825 1.715526 1.269002 + vertex 0.074171 1.662592 1.189953 + vertex 0.084233 1.545081 1.218260 + endloop + endfacet + facet normal 0.950562 -0.277941 0.138492 + outer loop + vertex 0.084825 1.715526 1.269002 + vertex 0.484060 2.778963 0.663007 + vertex 0.463129 2.691300 0.630741 + endloop + endfacet + facet normal 0.946162 -0.313099 0.082134 + outer loop + vertex 0.084825 1.715526 1.269002 + vertex 0.463129 2.691300 0.630741 + vertex 0.074171 1.662592 1.189953 + endloop + endfacet + facet normal 0.969792 -0.242211 0.028945 + outer loop + vertex 0.484060 2.778963 0.663007 + vertex 0.782781 3.755951 -1.170079 + vertex 0.463129 2.691300 0.630741 + endloop + endfacet + facet normal 0.974733 -0.219097 0.043488 + outer loop + vertex 0.782781 3.755951 -1.170079 + vertex 0.776167 3.712284 -1.241837 + vertex 0.463129 2.691300 0.630741 + endloop + endfacet + facet normal 0.951111 -0.296674 0.085861 + outer loop + vertex 0.782781 3.755951 -1.170079 + vertex 0.891771 3.996428 -1.546482 + vertex 0.890291 3.984491 -1.571330 + endloop + endfacet + facet normal 0.952495 -0.291144 0.089382 + outer loop + vertex 0.782781 3.755951 -1.170079 + vertex 0.890291 3.984491 -1.571330 + vertex 0.776167 3.712284 -1.241837 + endloop + endfacet + facet normal 0.272474 0.292858 0.916511 + outer loop + vertex -0.444043 0.471773 -0.071463 + vertex -0.307767 0.456462 -0.107085 + vertex -0.376302 0.324781 -0.044633 + endloop + endfacet + facet normal -0.247540 -0.867492 0.431488 + outer loop + vertex 0.890291 3.984491 -1.571330 + vertex 0.911266 3.985315 -1.557641 + vertex 0.904605 3.973175 -1.585869 + endloop + endfacet + facet normal 0.444817 -0.719116 0.533863 + outer loop + vertex -0.444043 0.471773 -0.071463 + vertex -0.089849 1.015489 0.365809 + vertex -0.005001 1.041127 0.329648 + endloop + endfacet + facet normal 0.127749 -0.635160 0.761743 + outer loop + vertex -0.444043 0.471773 -0.071463 + vertex -0.005001 1.041127 0.329648 + vertex -0.307767 0.456462 -0.107085 + endloop + endfacet + facet normal 0.420686 -0.806615 0.415206 + outer loop + vertex -0.089849 1.015489 0.365809 + vertex 0.084233 1.545081 1.218260 + vertex -0.005001 1.041127 0.329648 + endloop + endfacet + facet normal 0.357584 -0.827292 0.433269 + outer loop + vertex 0.084233 1.545081 1.218260 + vertex 0.132047 1.543980 1.176695 + vertex -0.005001 1.041127 0.329648 + endloop + endfacet + facet normal 0.675312 0.226875 0.701770 + outer loop + vertex 0.084233 1.545081 1.218260 + vertex 0.074171 1.662592 1.189953 + vertex 0.140081 1.611374 1.143086 + endloop + endfacet + facet normal 0.632812 0.283821 0.720413 + outer loop + vertex 0.084233 1.545081 1.218260 + vertex 0.140081 1.611374 1.143086 + vertex 0.132047 1.543980 1.176695 + endloop + endfacet + facet normal 0.650721 0.157727 0.742755 + outer loop + vertex 0.074171 1.662592 1.189953 + vertex 0.463129 2.691300 0.630741 + vertex 0.140081 1.611374 1.143086 + endloop + endfacet + facet normal 0.526204 0.230871 0.818418 + outer loop + vertex 0.463129 2.691300 0.630741 + vertex 0.522632 2.618428 0.613040 + vertex 0.140081 1.611374 1.143086 + endloop + endfacet + facet normal 0.890469 0.320122 0.323399 + outer loop + vertex 0.463129 2.691300 0.630741 + vertex 0.776167 3.712284 -1.241837 + vertex 0.804428 3.676825 -1.284553 + endloop + endfacet + facet normal 0.754780 0.518794 0.401447 + outer loop + vertex 0.463129 2.691300 0.630741 + vertex 0.804428 3.676825 -1.284553 + vertex 0.522632 2.618428 0.613040 + endloop + endfacet + facet normal 0.880505 0.167589 0.443425 + outer loop + vertex 0.776167 3.712284 -1.241837 + vertex 0.890291 3.984491 -1.571330 + vertex 0.804428 3.676825 -1.284553 + endloop + endfacet + facet normal 0.785179 0.290597 0.546852 + outer loop + vertex 0.890291 3.984491 -1.571330 + vertex 0.904605 3.973175 -1.585869 + vertex 0.804428 3.676825 -1.284553 + endloop + endfacet + facet normal 0.272477 0.292857 0.916510 + outer loop + vertex -0.307767 0.456462 -0.107085 + vertex -0.223100 0.341991 -0.095679 + vertex -0.376302 0.324781 -0.044633 + endloop + endfacet + facet normal -0.247494 -0.867507 0.431484 + outer loop + vertex 0.904605 3.973175 -1.585869 + vertex 0.911266 3.985315 -1.557641 + vertex 0.923934 3.971001 -1.579153 + endloop + endfacet + facet normal -0.530285 -0.313740 0.787633 + outer loop + vertex -0.307767 0.456462 -0.107085 + vertex -0.005001 1.041127 0.329648 + vertex -0.223100 0.341991 -0.095679 + endloop + endfacet + facet normal -0.346002 -0.406495 0.845603 + outer loop + vertex -0.005001 1.041127 0.329648 + vertex 0.081085 1.002764 0.346431 + vertex -0.223100 0.341991 -0.095679 + endloop + endfacet + facet normal -0.409732 -0.753765 0.513768 + outer loop + vertex -0.005001 1.041127 0.329648 + vertex 0.132047 1.543980 1.176695 + vertex 0.185377 1.526700 1.193876 + endloop + endfacet + facet normal -0.430921 -0.742863 0.512310 + outer loop + vertex -0.005001 1.041127 0.329648 + vertex 0.185377 1.526700 1.193876 + vertex 0.081085 1.002764 0.346431 + endloop + endfacet + facet normal -0.136054 0.455070 0.880000 + outer loop + vertex 0.132047 1.543980 1.176695 + vertex 0.140081 1.611374 1.143086 + vertex 0.185377 1.526700 1.193876 + endloop + endfacet + facet normal -0.142184 0.452121 0.880551 + outer loop + vertex 0.140081 1.611374 1.143086 + vertex 0.232926 1.600441 1.163691 + vertex 0.185377 1.526700 1.193876 + endloop + endfacet + facet normal -0.076833 0.487081 0.869971 + outer loop + vertex 0.140081 1.611374 1.143086 + vertex 0.522632 2.618428 0.613040 + vertex 0.617763 2.615223 0.623236 + endloop + endfacet + facet normal -0.130131 0.504070 0.853803 + outer loop + vertex 0.140081 1.611374 1.143086 + vertex 0.617763 2.615223 0.623236 + vertex 0.232926 1.600441 1.163691 + endloop + endfacet + facet normal -0.022463 0.874535 0.484443 + outer loop + vertex 0.522632 2.618428 0.613040 + vertex 0.804428 3.676825 -1.284553 + vertex 0.617763 2.615223 0.623236 + endloop + endfacet + facet normal -0.193058 0.865289 0.462606 + outer loop + vertex 0.804428 3.676825 -1.284553 + vertex 0.846281 3.676276 -1.266060 + vertex 0.617763 2.615223 0.623236 + endloop + endfacet + facet normal -0.149909 0.729362 0.667502 + outer loop + vertex 0.804428 3.676825 -1.284553 + vertex 0.904605 3.973175 -1.585869 + vertex 0.923934 3.971001 -1.579153 + endloop + endfacet + facet normal -0.266440 0.733927 0.624789 + outer loop + vertex 0.804428 3.676825 -1.284553 + vertex 0.923934 3.971001 -1.579153 + vertex 0.846281 3.676276 -1.266060 + endloop + endfacet + facet normal 0.272477 0.292856 0.916511 + outer loop + vertex -0.223100 0.341991 -0.095679 + vertex -0.253797 0.214561 -0.045835 + vertex -0.376302 0.324781 -0.044633 + endloop + endfacet + facet normal -0.247450 -0.867507 0.431509 + outer loop + vertex 0.923934 3.971001 -1.579153 + vertex 0.911266 3.985315 -1.557641 + vertex 0.933725 3.979607 -1.556237 + endloop + endfacet + facet normal -0.879711 0.092958 0.466334 + outer loop + vertex -0.223100 0.341991 -0.095679 + vertex 0.081085 1.002764 0.346431 + vertex 0.103584 0.929287 0.403520 + endloop + endfacet + facet normal -0.920438 0.313202 0.233875 + outer loop + vertex -0.223100 0.341991 -0.095679 + vertex 0.103584 0.929287 0.403520 + vertex -0.253797 0.214561 -0.045835 + endloop + endfacet + facet normal -0.969112 -0.137853 0.204494 + outer loop + vertex 0.081085 1.002764 0.346431 + vertex 0.185377 1.526700 1.193876 + vertex 0.103584 0.929287 0.403520 + endloop + endfacet + facet normal -0.958292 -0.171373 0.228711 + outer loop + vertex 0.185377 1.526700 1.193876 + vertex 0.204066 1.506257 1.256863 + vertex 0.103584 0.929287 0.403520 + endloop + endfacet + facet normal -0.774108 0.591493 0.225596 + outer loop + vertex 0.185377 1.526700 1.193876 + vertex 0.232926 1.600441 1.163691 + vertex 0.282789 1.638025 1.236253 + endloop + endfacet + facet normal -0.760900 0.516107 0.393274 + outer loop + vertex 0.185377 1.526700 1.193876 + vertex 0.282789 1.638025 1.236253 + vertex 0.204066 1.506257 1.256863 + endloop + endfacet + facet normal -0.819471 0.478649 0.315217 + outer loop + vertex 0.232926 1.600441 1.163691 + vertex 0.617763 2.615223 0.623236 + vertex 0.282789 1.638025 1.236253 + endloop + endfacet + facet normal -0.778669 0.502565 0.375637 + outer loop + vertex 0.617763 2.615223 0.623236 + vertex 0.676887 2.684097 0.653648 + vertex 0.282789 1.638025 1.236253 + endloop + endfacet + facet normal -0.907486 0.403504 0.116849 + outer loop + vertex 0.617763 2.615223 0.623236 + vertex 0.846281 3.676276 -1.266060 + vertex 0.870213 3.711051 -1.200285 + endloop + endfacet + facet normal -0.786380 0.571480 0.234559 + outer loop + vertex 0.617763 2.615223 0.623236 + vertex 0.870213 3.711051 -1.200285 + vertex 0.676887 2.684097 0.653648 + endloop + endfacet + facet normal -0.915194 0.380924 0.131592 + outer loop + vertex 0.846281 3.676276 -1.266060 + vertex 0.923934 3.971001 -1.579153 + vertex 0.870213 3.711051 -1.200285 + endloop + endfacet + facet normal -0.864412 0.463299 0.195311 + outer loop + vertex 0.923934 3.971001 -1.579153 + vertex 0.933725 3.979607 -1.556237 + vertex 0.870213 3.711051 -1.200285 + endloop + endfacet + facet normal 0.272474 -0.292852 0.916513 + outer loop + vertex -0.376302 -0.324781 -0.044633 + vertex -0.376741 -0.170128 0.004914 + vertex -0.253797 -0.214561 -0.045835 + endloop + endfacet + facet normal -0.247446 0.867470 0.431586 + outer loop + vertex 0.926604 -3.992514 -1.534378 + vertex 0.911266 -3.985315 -1.557641 + vertex 0.933725 -3.979607 -1.556237 + endloop + endfacet + facet normal -0.777863 -0.563658 -0.277884 + outer loop + vertex 0.045554 -0.876026 0.457925 + vertex 0.103584 -0.929287 0.403520 + vertex -0.253797 -0.214561 -0.045835 + endloop + endfacet + facet normal -0.477920 -0.658786 -0.581028 + outer loop + vertex -0.376741 -0.170128 0.004914 + vertex 0.045554 -0.876026 0.457925 + vertex -0.253797 -0.214561 -0.045835 + endloop + endfacet + facet normal -0.779423 -0.557750 -0.285332 + outer loop + vertex 0.045554 -0.876026 0.457925 + vertex 0.204066 -1.506257 1.256863 + vertex 0.103584 -0.929287 0.403520 + endloop + endfacet + facet normal -0.765340 -0.570420 -0.298120 + outer loop + vertex 0.045554 -0.876026 0.457925 + vertex 0.174039 -1.498041 1.318229 + vertex 0.204066 -1.506257 1.256863 + endloop + endfacet + facet normal -0.725149 -0.339533 -0.599063 + outer loop + vertex 0.252124 -1.695822 1.306131 + vertex 0.282789 -1.638024 1.236253 + vertex 0.204066 -1.506257 1.256863 + endloop + endfacet + facet normal -0.867439 -0.319119 -0.381722 + outer loop + vertex 0.174039 -1.498041 1.318229 + vertex 0.252124 -1.695822 1.306131 + vertex 0.204066 -1.506257 1.256863 + endloop + endfacet + facet normal -0.886598 -0.080321 -0.455513 + outer loop + vertex 0.252124 -1.695822 1.306131 + vertex 0.676887 -2.684097 0.653648 + vertex 0.282789 -1.638024 1.236253 + endloop + endfacet + facet normal -0.822990 0.021063 -0.567665 + outer loop + vertex 0.252124 -1.695822 1.306131 + vertex 0.655481 -2.773188 0.681377 + vertex 0.676887 -2.684097 0.653648 + endloop + endfacet + facet normal -0.987821 0.067298 -0.140287 + outer loop + vertex 0.858199 -3.754962 -1.136756 + vertex 0.870213 -3.711051 -1.200285 + vertex 0.676887 -2.684097 0.653648 + endloop + endfacet + facet normal -0.965102 0.169849 -0.199324 + outer loop + vertex 0.655481 -2.773188 0.681377 + vertex 0.858199 -3.754962 -1.136756 + vertex 0.676887 -2.684097 0.653648 + endloop + endfacet + facet normal -0.983464 0.007265 -0.180959 + outer loop + vertex 0.858199 -3.754962 -1.136756 + vertex 0.933725 -3.979607 -1.556237 + vertex 0.870213 -3.711051 -1.200285 + endloop + endfacet + facet normal -0.962733 0.124581 -0.240053 + outer loop + vertex 0.858199 -3.754962 -1.136756 + vertex 0.926604 -3.992514 -1.534378 + vertex 0.933725 -3.979607 -1.556237 + endloop + endfacet + facet normal 0.272467 -0.292852 0.916515 + outer loop + vertex -0.376302 -0.324781 -0.044633 + vertex -0.499356 -0.242150 0.018352 + vertex -0.376741 -0.170128 0.004914 + endloop + endfacet + facet normal -0.247477 0.867453 0.431602 + outer loop + vertex 0.907933 -4.000000 -1.530038 + vertex 0.911266 -3.985315 -1.557641 + vertex 0.926604 -3.992514 -1.534378 + endloop + endfacet + facet normal 0.172648 -0.456757 -0.872677 + outer loop + vertex -0.499356 -0.242150 0.018352 + vertex 0.045554 -0.876026 0.457925 + vertex -0.376741 -0.170128 0.004914 + endloop + endfacet + facet normal -0.046516 -0.595931 -0.801687 + outer loop + vertex -0.499356 -0.242150 0.018352 + vertex -0.049308 -0.883088 0.468678 + vertex 0.045554 -0.876026 0.457925 + endloop + endfacet + facet normal 0.005789 -0.809949 -0.586472 + outer loop + vertex 0.117908 -1.508241 1.331761 + vertex 0.174039 -1.498041 1.318229 + vertex 0.045554 -0.876026 0.457925 + endloop + endfacet + facet normal -0.006079 -0.810414 -0.585826 + outer loop + vertex -0.049308 -0.883088 0.468678 + vertex 0.117908 -1.508241 1.331761 + vertex 0.045554 -0.876026 0.457925 + endloop + endfacet + facet normal -0.228951 -0.030877 -0.972948 + outer loop + vertex 0.117908 -1.508241 1.331761 + vertex 0.252124 -1.695822 1.306131 + vertex 0.174039 -1.498041 1.318229 + endloop + endfacet + facet normal -0.168553 0.014067 -0.985592 + outer loop + vertex 0.117908 -1.508241 1.331761 + vertex 0.164022 -1.730315 1.320705 + vertex 0.252124 -1.695822 1.306131 + endloop + endfacet + facet normal -0.246820 0.415317 -0.875552 + outer loop + vertex 0.569666 -2.815407 0.685542 + vertex 0.655481 -2.773188 0.681377 + vertex 0.252124 -1.695822 1.306131 + endloop + endfacet + facet normal -0.298811 0.396427 -0.868077 + outer loop + vertex 0.164022 -1.730315 1.320705 + vertex 0.569666 -2.815407 0.685542 + vertex 0.252124 -1.695822 1.306131 + endloop + endfacet + facet normal -0.408189 0.783466 -0.468576 + outer loop + vertex 0.569666 -2.815407 0.685542 + vertex 0.858199 -3.754962 -1.136756 + vertex 0.655481 -2.773188 0.681377 + endloop + endfacet + facet normal -0.526140 0.719046 -0.454038 + outer loop + vertex 0.569666 -2.815407 0.685542 + vertex 0.819289 -3.774946 -1.123315 + vertex 0.858199 -3.754962 -1.136756 + endloop + endfacet + facet normal -0.419349 0.745757 -0.517681 + outer loop + vertex 0.907933 -4.000000 -1.530038 + vertex 0.926604 -3.992514 -1.534378 + vertex 0.858199 -3.754962 -1.136756 + endloop + endfacet + facet normal -0.526109 0.690328 -0.496646 + outer loop + vertex 0.819289 -3.774946 -1.123315 + vertex 0.907933 -4.000000 -1.530038 + vertex 0.858199 -3.754962 -1.136756 + endloop + endfacet + facet normal 0.272470 -0.292848 0.916515 + outer loop + vertex -0.376302 -0.324781 -0.044633 + vertex -0.529306 -0.376397 -0.015639 + vertex -0.499356 -0.242150 0.018352 + endloop + endfacet + facet normal -0.247463 0.867456 0.431605 + outer loop + vertex 0.891771 -3.996428 -1.546482 + vertex 0.911266 -3.985315 -1.557641 + vertex 0.907933 -4.000000 -1.530038 + endloop + endfacet + facet normal 0.628429 -0.100671 -0.771325 + outer loop + vertex -0.109567 -0.945155 0.427683 + vertex -0.049308 -0.883088 0.468678 + vertex -0.499356 -0.242150 0.018352 + endloop + endfacet + facet normal 0.731984 0.009186 -0.681260 + outer loop + vertex -0.529306 -0.376397 -0.015639 + vertex -0.109567 -0.945155 0.427683 + vertex -0.499356 -0.242150 0.018352 + endloop + endfacet + facet normal 0.768509 -0.438166 -0.466267 + outer loop + vertex -0.109567 -0.945155 0.427683 + vertex 0.117908 -1.508241 1.331761 + vertex -0.049308 -0.883088 0.468678 + endloop + endfacet + facet normal 0.759350 -0.449147 -0.470802 + outer loop + vertex -0.109567 -0.945155 0.427683 + vertex 0.077941 -1.529177 1.287271 + vertex 0.117908 -1.508241 1.331761 + endloop + endfacet + facet normal 0.560265 0.156831 -0.813331 + outer loop + vertex 0.084825 -1.715526 1.269002 + vertex 0.164022 -1.730315 1.320705 + vertex 0.117908 -1.508241 1.331761 + endloop + endfacet + facet normal 0.718180 0.094124 -0.689462 + outer loop + vertex 0.077941 -1.529177 1.287271 + vertex 0.084825 -1.715526 1.269002 + vertex 0.117908 -1.508241 1.331761 + endloop + endfacet + facet normal 0.521721 0.567763 -0.636752 + outer loop + vertex 0.084825 -1.715526 1.269002 + vertex 0.569666 -2.815407 0.685542 + vertex 0.164022 -1.730315 1.320705 + endloop + endfacet + facet normal 0.426157 0.563346 -0.707836 + outer loop + vertex 0.084825 -1.715526 1.269002 + vertex 0.484060 -2.778963 0.663007 + vertex 0.569666 -2.815407 0.685542 + endloop + endfacet + facet normal 0.688727 0.675522 -0.263297 + outer loop + vertex 0.782781 -3.755951 -1.170079 + vertex 0.819289 -3.774946 -1.123315 + vertex 0.569666 -2.815407 0.685542 + endloop + endfacet + facet normal 0.444304 0.818636 -0.363908 + outer loop + vertex 0.484060 -2.778963 0.663007 + vertex 0.782781 -3.755951 -1.170079 + vertex 0.569666 -2.815407 0.685542 + endloop + endfacet + facet normal 0.672471 0.699887 -0.240710 + outer loop + vertex 0.782781 -3.755951 -1.170079 + vertex 0.907933 -4.000000 -1.530038 + vertex 0.819289 -3.774946 -1.123315 + endloop + endfacet + facet normal 0.523808 0.778528 -0.345715 + outer loop + vertex 0.782781 -3.755951 -1.170079 + vertex 0.891771 -3.996428 -1.546482 + vertex 0.907933 -4.000000 -1.530038 + endloop + endfacet + facet normal 0.272472 -0.292858 0.916512 + outer loop + vertex -0.376302 -0.324781 -0.044633 + vertex -0.444043 -0.471773 -0.071463 + vertex -0.529306 -0.376397 -0.015639 + endloop + endfacet + facet normal -0.247544 0.867488 0.431494 + outer loop + vertex 0.890291 -3.984491 -1.571330 + vertex 0.911266 -3.985315 -1.557641 + vertex 0.891771 -3.996428 -1.546482 + endloop + endfacet + facet normal 0.767618 0.634875 0.087727 + outer loop + vertex -0.444043 -0.471773 -0.071463 + vertex -0.109567 -0.945155 0.427683 + vertex -0.529306 -0.376397 -0.015639 + endloop + endfacet + facet normal 0.886160 0.420222 -0.195281 + outer loop + vertex -0.444043 -0.471773 -0.071463 + vertex -0.089849 -1.015489 0.365809 + vertex -0.109567 -0.945155 0.427683 + endloop + endfacet + facet normal 0.946717 0.321838 0.012149 + outer loop + vertex 0.084233 -1.545081 1.218260 + vertex 0.077941 -1.529177 1.287271 + vertex -0.109567 -0.945155 0.427683 + endloop + endfacet + facet normal 0.958333 0.285045 -0.018619 + outer loop + vertex -0.089849 -1.015489 0.365809 + vertex 0.084233 -1.545081 1.218260 + vertex -0.109567 -0.945155 0.427683 + endloop + endfacet + facet normal 0.996037 0.028539 0.084242 + outer loop + vertex 0.084233 -1.545081 1.218260 + vertex 0.084825 -1.715526 1.269002 + vertex 0.077941 -1.529177 1.287271 + endloop + endfacet + facet normal 0.985585 -0.045119 -0.163055 + outer loop + vertex 0.084233 -1.545081 1.218260 + vertex 0.074171 -1.662592 1.189953 + vertex 0.084825 -1.715526 1.269002 + endloop + endfacet + facet normal 0.950562 0.277941 0.138492 + outer loop + vertex 0.463129 -2.691300 0.630741 + vertex 0.484060 -2.778963 0.663007 + vertex 0.084825 -1.715526 1.269002 + endloop + endfacet + facet normal 0.946162 0.313099 0.082134 + outer loop + vertex 0.074171 -1.662592 1.189953 + vertex 0.463129 -2.691300 0.630741 + vertex 0.084825 -1.715526 1.269002 + endloop + endfacet + facet normal 0.969792 0.242211 0.028945 + outer loop + vertex 0.463129 -2.691300 0.630741 + vertex 0.782781 -3.755951 -1.170079 + vertex 0.484060 -2.778963 0.663007 + endloop + endfacet + facet normal 0.974733 0.219097 0.043488 + outer loop + vertex 0.463129 -2.691300 0.630741 + vertex 0.776167 -3.712284 -1.241837 + vertex 0.782781 -3.755951 -1.170079 + endloop + endfacet + facet normal 0.951111 0.296673 0.085862 + outer loop + vertex 0.890291 -3.984491 -1.571330 + vertex 0.891771 -3.996428 -1.546482 + vertex 0.782781 -3.755951 -1.170079 + endloop + endfacet + facet normal 0.952495 0.291144 0.089382 + outer loop + vertex 0.776167 -3.712284 -1.241837 + vertex 0.890291 -3.984491 -1.571330 + vertex 0.782781 -3.755951 -1.170079 + endloop + endfacet + facet normal 0.272474 -0.292858 0.916511 + outer loop + vertex -0.376302 -0.324781 -0.044633 + vertex -0.307767 -0.456462 -0.107085 + vertex -0.444043 -0.471773 -0.071463 + endloop + endfacet + facet normal -0.247540 0.867492 0.431487 + outer loop + vertex 0.904605 -3.973175 -1.585869 + vertex 0.911266 -3.985315 -1.557641 + vertex 0.890291 -3.984491 -1.571330 + endloop + endfacet + facet normal 0.444816 0.719116 0.533864 + outer loop + vertex -0.005001 -1.041127 0.329648 + vertex -0.089849 -1.015489 0.365809 + vertex -0.444043 -0.471773 -0.071463 + endloop + endfacet + facet normal 0.127749 0.635160 0.761743 + outer loop + vertex -0.307767 -0.456462 -0.107085 + vertex -0.005001 -1.041127 0.329648 + vertex -0.444043 -0.471773 -0.071463 + endloop + endfacet + facet normal 0.420685 0.806615 0.415206 + outer loop + vertex -0.005001 -1.041127 0.329648 + vertex 0.084233 -1.545081 1.218260 + vertex -0.089849 -1.015489 0.365809 + endloop + endfacet + facet normal 0.357582 0.827292 0.433270 + outer loop + vertex -0.005001 -1.041127 0.329648 + vertex 0.132047 -1.543979 1.176695 + vertex 0.084233 -1.545081 1.218260 + endloop + endfacet + facet normal 0.675312 -0.226875 0.701770 + outer loop + vertex 0.140081 -1.611374 1.143086 + vertex 0.074171 -1.662592 1.189953 + vertex 0.084233 -1.545081 1.218260 + endloop + endfacet + facet normal 0.632813 -0.283820 0.720412 + outer loop + vertex 0.132047 -1.543979 1.176695 + vertex 0.140081 -1.611374 1.143086 + vertex 0.084233 -1.545081 1.218260 + endloop + endfacet + facet normal 0.650721 -0.157727 0.742755 + outer loop + vertex 0.140081 -1.611374 1.143086 + vertex 0.463129 -2.691300 0.630741 + vertex 0.074171 -1.662592 1.189953 + endloop + endfacet + facet normal 0.526204 -0.230871 0.818418 + outer loop + vertex 0.140081 -1.611374 1.143086 + vertex 0.522632 -2.618427 0.613040 + vertex 0.463129 -2.691300 0.630741 + endloop + endfacet + facet normal 0.890469 -0.320122 0.323399 + outer loop + vertex 0.804428 -3.676825 -1.284553 + vertex 0.776167 -3.712284 -1.241837 + vertex 0.463129 -2.691300 0.630741 + endloop + endfacet + facet normal 0.754780 -0.518794 0.401448 + outer loop + vertex 0.522632 -2.618427 0.613040 + vertex 0.804428 -3.676825 -1.284553 + vertex 0.463129 -2.691300 0.630741 + endloop + endfacet + facet normal 0.880505 -0.167589 0.443425 + outer loop + vertex 0.804428 -3.676825 -1.284553 + vertex 0.890291 -3.984491 -1.571330 + vertex 0.776167 -3.712284 -1.241837 + endloop + endfacet + facet normal 0.785178 -0.290599 0.546853 + outer loop + vertex 0.804428 -3.676825 -1.284553 + vertex 0.904605 -3.973175 -1.585869 + vertex 0.890291 -3.984491 -1.571330 + endloop + endfacet + facet normal 0.272477 -0.292857 0.916510 + outer loop + vertex -0.376302 -0.324781 -0.044633 + vertex -0.223100 -0.341991 -0.095679 + vertex -0.307767 -0.456462 -0.107085 + endloop + endfacet + facet normal -0.247495 0.867507 0.431483 + outer loop + vertex 0.923934 -3.971001 -1.579153 + vertex 0.911266 -3.985315 -1.557641 + vertex 0.904605 -3.973175 -1.585869 + endloop + endfacet + facet normal -0.530285 0.313740 0.787633 + outer loop + vertex -0.223100 -0.341991 -0.095679 + vertex -0.005001 -1.041127 0.329648 + vertex -0.307767 -0.456462 -0.107085 + endloop + endfacet + facet normal -0.346002 0.406495 0.845603 + outer loop + vertex -0.223100 -0.341991 -0.095679 + vertex 0.081085 -1.002764 0.346431 + vertex -0.005001 -1.041127 0.329648 + endloop + endfacet + facet normal -0.409730 0.753766 0.513768 + outer loop + vertex 0.185377 -1.526700 1.193876 + vertex 0.132047 -1.543979 1.176695 + vertex -0.005001 -1.041127 0.329648 + endloop + endfacet + facet normal -0.430921 0.742863 0.512310 + outer loop + vertex 0.081085 -1.002764 0.346431 + vertex 0.185377 -1.526700 1.193876 + vertex -0.005001 -1.041127 0.329648 + endloop + endfacet + facet normal -0.136055 -0.455070 0.880000 + outer loop + vertex 0.185377 -1.526700 1.193876 + vertex 0.140081 -1.611374 1.143086 + vertex 0.132047 -1.543979 1.176695 + endloop + endfacet + facet normal -0.142183 -0.452122 0.880551 + outer loop + vertex 0.185377 -1.526700 1.193876 + vertex 0.232926 -1.600441 1.163691 + vertex 0.140081 -1.611374 1.143086 + endloop + endfacet + facet normal -0.076834 -0.487082 0.869970 + outer loop + vertex 0.617763 -2.615223 0.623236 + vertex 0.522632 -2.618427 0.613040 + vertex 0.140081 -1.611374 1.143086 + endloop + endfacet + facet normal -0.130130 -0.504070 0.853803 + outer loop + vertex 0.232926 -1.600441 1.163691 + vertex 0.617763 -2.615223 0.623236 + vertex 0.140081 -1.611374 1.143086 + endloop + endfacet + facet normal -0.022465 -0.874535 0.484442 + outer loop + vertex 0.617763 -2.615223 0.623236 + vertex 0.804428 -3.676825 -1.284553 + vertex 0.522632 -2.618427 0.613040 + endloop + endfacet + facet normal -0.193058 -0.865289 0.462606 + outer loop + vertex 0.617763 -2.615223 0.623236 + vertex 0.846281 -3.676276 -1.266060 + vertex 0.804428 -3.676825 -1.284553 + endloop + endfacet + facet normal -0.149910 -0.729362 0.667502 + outer loop + vertex 0.923934 -3.971001 -1.579153 + vertex 0.904605 -3.973175 -1.585869 + vertex 0.804428 -3.676825 -1.284553 + endloop + endfacet + facet normal -0.266440 -0.733927 0.624789 + outer loop + vertex 0.846281 -3.676276 -1.266060 + vertex 0.923934 -3.971001 -1.579153 + vertex 0.804428 -3.676825 -1.284553 + endloop + endfacet + facet normal 0.272478 -0.292856 0.916511 + outer loop + vertex -0.376302 -0.324781 -0.044633 + vertex -0.253797 -0.214561 -0.045835 + vertex -0.223100 -0.341991 -0.095679 + endloop + endfacet + facet normal -0.247450 0.867507 0.431509 + outer loop + vertex 0.933725 -3.979607 -1.556237 + vertex 0.911266 -3.985315 -1.557641 + vertex 0.923934 -3.971001 -1.579153 + endloop + endfacet + facet normal -0.879711 -0.092959 0.466334 + outer loop + vertex 0.103584 -0.929287 0.403520 + vertex 0.081085 -1.002764 0.346431 + vertex -0.223100 -0.341991 -0.095679 + endloop + endfacet + facet normal -0.920438 -0.313202 0.233875 + outer loop + vertex -0.253797 -0.214561 -0.045835 + vertex 0.103584 -0.929287 0.403520 + vertex -0.223100 -0.341991 -0.095679 + endloop + endfacet + facet normal -0.969112 0.137854 0.204494 + outer loop + vertex 0.103584 -0.929287 0.403520 + vertex 0.185377 -1.526700 1.193876 + vertex 0.081085 -1.002764 0.346431 + endloop + endfacet + facet normal -0.958292 0.171373 0.228710 + outer loop + vertex 0.103584 -0.929287 0.403520 + vertex 0.204066 -1.506257 1.256863 + vertex 0.185377 -1.526700 1.193876 + endloop + endfacet + facet normal -0.774107 -0.591494 0.225595 + outer loop + vertex 0.282789 -1.638024 1.236253 + vertex 0.232926 -1.600441 1.163691 + vertex 0.185377 -1.526700 1.193876 + endloop + endfacet + facet normal -0.760900 -0.516107 0.393275 + outer loop + vertex 0.204066 -1.506257 1.256863 + vertex 0.282789 -1.638024 1.236253 + vertex 0.185377 -1.526700 1.193876 + endloop + endfacet + facet normal -0.819471 -0.478649 0.315218 + outer loop + vertex 0.282789 -1.638024 1.236253 + vertex 0.617763 -2.615223 0.623236 + vertex 0.232926 -1.600441 1.163691 + endloop + endfacet + facet normal -0.778668 -0.502565 0.375638 + outer loop + vertex 0.282789 -1.638024 1.236253 + vertex 0.676887 -2.684097 0.653648 + vertex 0.617763 -2.615223 0.623236 + endloop + endfacet + facet normal -0.907486 -0.403504 0.116849 + outer loop + vertex 0.870213 -3.711051 -1.200285 + vertex 0.846281 -3.676276 -1.266060 + vertex 0.617763 -2.615223 0.623236 + endloop + endfacet + facet normal -0.786379 -0.571481 0.234559 + outer loop + vertex 0.676887 -2.684097 0.653648 + vertex 0.870213 -3.711051 -1.200285 + vertex 0.617763 -2.615223 0.623236 + endloop + endfacet + facet normal -0.915194 -0.380924 0.131592 + outer loop + vertex 0.870213 -3.711051 -1.200285 + vertex 0.923934 -3.971001 -1.579153 + vertex 0.846281 -3.676276 -1.266060 + endloop + endfacet + facet normal -0.864412 -0.463299 0.195311 + outer loop + vertex 0.870213 -3.711051 -1.200285 + vertex 0.933725 -3.979607 -1.556237 + vertex 0.923934 -3.971001 -1.579153 + endloop + endfacet + facet normal 0.287101 0.225652 0.930943 + outer loop + vertex 0.254596 0.172017 -0.203340 + vertex 0.134732 0.118958 -0.153513 + vertex 0.128368 0.277101 -0.189883 + endloop + endfacet + facet normal -0.184374 -0.887741 0.421808 + outer loop + vertex 1.541262 3.228386 -1.480601 + vertex 1.518561 3.233232 -1.480323 + vertex 1.535171 3.240416 -1.457945 + endloop + endfacet + facet normal -0.475138 0.667519 -0.573291 + outer loop + vertex 0.254596 0.172017 -0.203340 + vertex 0.599097 0.871928 0.326091 + vertex 0.515124 0.832623 0.349921 + endloop + endfacet + facet normal -0.518251 0.659949 -0.543952 + outer loop + vertex 0.254596 0.172017 -0.203340 + vertex 0.515124 0.832623 0.349921 + vertex 0.134732 0.118958 -0.153513 + endloop + endfacet + facet normal -0.472387 0.830830 -0.294232 + outer loop + vertex 0.599097 0.871928 0.326091 + vertex 0.790359 1.282756 1.179089 + vertex 0.515124 0.832623 0.349921 + endloop + endfacet + facet normal -0.327001 0.871802 -0.364734 + outer loop + vertex 0.790359 1.282756 1.179089 + vertex 0.737774 1.281594 1.223455 + vertex 0.515124 0.832623 0.349921 + endloop + endfacet + facet normal -0.350684 0.480596 -0.803771 + outer loop + vertex 0.790359 1.282756 1.179089 + vertex 0.895302 1.394673 1.200220 + vertex 0.851906 1.458227 1.257154 + endloop + endfacet + facet normal -0.567528 0.492582 -0.659754 + outer loop + vertex 0.790359 1.282756 1.179089 + vertex 0.851906 1.458227 1.257154 + vertex 0.737774 1.281594 1.223455 + endloop + endfacet + facet normal -0.840571 -0.096438 -0.533047 + outer loop + vertex 0.895302 1.394673 1.200220 + vertex 1.332892 2.383628 0.331257 + vertex 0.851906 1.458227 1.257154 + endloop + endfacet + facet normal -0.887653 0.000607 -0.460512 + outer loop + vertex 1.332892 2.383628 0.331257 + vertex 1.320483 2.475455 0.355297 + vertex 0.851906 1.458227 1.257154 + endloop + endfacet + facet normal -0.991471 -0.018419 -0.129021 + outer loop + vertex 1.332892 2.383628 0.331257 + vertex 1.512451 2.948164 -1.129171 + vertex 1.503159 2.989863 -1.063723 + endloop + endfacet + facet normal -0.982980 -0.091065 -0.159555 + outer loop + vertex 1.332892 2.383628 0.331257 + vertex 1.503159 2.989863 -1.063723 + vertex 1.320483 2.475455 0.355297 + endloop + endfacet + facet normal -0.992560 -0.041503 -0.114468 + outer loop + vertex 1.512451 2.948164 -1.129171 + vertex 1.541262 3.228386 -1.480601 + vertex 1.503159 2.989863 -1.063723 + endloop + endfacet + facet normal -0.971499 -0.156291 -0.178220 + outer loop + vertex 1.541262 3.228386 -1.480601 + vertex 1.535171 3.240416 -1.457945 + vertex 1.503159 2.989863 -1.063723 + endloop + endfacet + facet normal 0.287098 0.225652 0.930943 + outer loop + vertex 0.134732 0.118958 -0.153513 + vertex 0.010076 0.184984 -0.131074 + vertex 0.128368 0.277101 -0.189883 + endloop + endfacet + facet normal -0.184355 -0.887751 0.421796 + outer loop + vertex 1.535171 3.240416 -1.457945 + vertex 1.518561 3.233232 -1.480323 + vertex 1.516571 3.247036 -1.452140 + endloop + endfacet + facet normal 0.127014 0.525668 -0.841154 + outer loop + vertex 0.134732 0.118958 -0.153513 + vertex 0.515124 0.832623 0.349921 + vertex 0.010076 0.184984 -0.131074 + endloop + endfacet + facet normal 0.362983 0.356361 -0.860959 + outer loop + vertex 0.515124 0.832623 0.349921 + vertex 0.427043 0.859716 0.324000 + vertex 0.010076 0.184984 -0.131074 + endloop + endfacet + facet normal 0.393000 0.773265 -0.497606 + outer loop + vertex 0.515124 0.832623 0.349921 + vertex 0.737774 1.281594 1.223455 + vertex 0.684049 1.303568 1.215172 + endloop + endfacet + facet normal 0.385495 0.776756 -0.498040 + outer loop + vertex 0.515124 0.832623 0.349921 + vertex 0.684049 1.303568 1.215172 + vertex 0.427043 0.859716 0.324000 + endloop + endfacet + facet normal 0.180200 0.070741 -0.981083 + outer loop + vertex 0.737774 1.281594 1.223455 + vertex 0.851906 1.458227 1.257154 + vertex 0.684049 1.303568 1.215172 + endloop + endfacet + facet normal 0.230536 0.013907 -0.972965 + outer loop + vertex 0.851906 1.458227 1.257154 + vertex 0.773848 1.510727 1.239410 + vertex 0.684049 1.303568 1.215172 + endloop + endfacet + facet normal -0.213642 -0.591138 -0.777762 + outer loop + vertex 0.851906 1.458227 1.257154 + vertex 1.320483 2.475455 0.355297 + vertex 1.250076 2.534936 0.329428 + endloop + endfacet + facet normal -0.219361 -0.589029 -0.777769 + outer loop + vertex 0.851906 1.458227 1.257154 + vertex 1.250076 2.534936 0.329428 + vertex 0.773848 1.510727 1.239410 + endloop + endfacet + facet normal -0.526722 -0.775172 -0.348814 + outer loop + vertex 1.320483 2.475455 0.355297 + vertex 1.503159 2.989863 -1.063723 + vertex 1.250076 2.534936 0.329428 + endloop + endfacet + facet normal -0.515795 -0.782329 -0.349166 + outer loop + vertex 1.503159 2.989863 -1.063723 + vertex 1.464530 3.007919 -1.047115 + vertex 1.250076 2.534936 0.329428 + endloop + endfacet + facet normal -0.425265 -0.747819 -0.509820 + outer loop + vertex 1.503159 2.989863 -1.063723 + vertex 1.535171 3.240416 -1.457945 + vertex 1.516571 3.247036 -1.452140 + endloop + endfacet + facet normal -0.532313 -0.697276 -0.480051 + outer loop + vertex 1.503159 2.989863 -1.063723 + vertex 1.516571 3.247036 -1.452140 + vertex 1.464530 3.007919 -1.047115 + endloop + endfacet + facet normal 0.287100 0.225650 0.930943 + outer loop + vertex 0.010076 0.184984 -0.131074 + vertex -0.025503 0.320378 -0.152919 + vertex 0.128368 0.277101 -0.189883 + endloop + endfacet + facet normal -0.184421 -0.887741 0.421787 + outer loop + vertex 1.516571 3.247036 -1.452140 + vertex 1.518561 3.233232 -1.480323 + vertex 1.499470 3.243264 -1.467557 + endloop + endfacet + facet normal 0.821850 -0.134507 -0.553598 + outer loop + vertex 0.010076 0.184984 -0.131074 + vertex 0.427043 0.859716 0.324000 + vertex 0.401182 0.932807 0.267848 + endloop + endfacet + facet normal 0.661470 0.053120 -0.748088 + outer loop + vertex 0.010076 0.184984 -0.131074 + vertex 0.401182 0.932807 0.267848 + vertex -0.025503 0.320378 -0.152919 + endloop + endfacet + facet normal 0.944038 0.090313 -0.317233 + outer loop + vertex 0.427043 0.859716 0.324000 + vertex 0.684049 1.303568 1.215172 + vertex 0.401182 0.932807 0.267848 + endloop + endfacet + facet normal 0.961417 -0.036992 -0.272598 + outer loop + vertex 0.684049 1.303568 1.215172 + vertex 0.669640 1.332134 1.160477 + vertex 0.401182 0.932807 0.267848 + endloop + endfacet + facet normal 0.790184 -0.278662 -0.545854 + outer loop + vertex 0.684049 1.303568 1.215172 + vertex 0.773848 1.510727 1.239410 + vertex 0.719906 1.512637 1.160348 + endloop + endfacet + facet normal 0.896213 -0.249837 -0.366583 + outer loop + vertex 0.684049 1.303568 1.215172 + vertex 0.719906 1.512637 1.160348 + vertex 0.669640 1.332134 1.160477 + endloop + endfacet + facet normal 0.608523 -0.666115 -0.431267 + outer loop + vertex 0.773848 1.510727 1.239410 + vertex 1.250076 2.534936 0.329428 + vertex 0.719906 1.512637 1.160348 + endloop + endfacet + facet normal 0.533110 -0.682671 -0.499754 + outer loop + vertex 1.250076 2.534936 0.329428 + vertex 1.174691 2.517280 0.273131 + vertex 0.719906 1.512637 1.160348 + endloop + endfacet + facet normal 0.592279 -0.785880 -0.177758 + outer loop + vertex 1.250076 2.534936 0.329428 + vertex 1.464530 3.007919 -1.047115 + vertex 1.425654 2.988739 -1.091849 + endloop + endfacet + facet normal 0.385834 -0.891602 -0.237017 + outer loop + vertex 1.250076 2.534936 0.329428 + vertex 1.425654 2.988739 -1.091849 + vertex 1.174691 2.517280 0.273131 + endloop + endfacet + facet normal 0.680419 -0.665989 -0.305759 + outer loop + vertex 1.464530 3.007919 -1.047115 + vertex 1.516571 3.247036 -1.452140 + vertex 1.425654 2.988739 -1.091849 + endloop + endfacet + facet normal 0.528015 -0.747652 -0.402762 + outer loop + vertex 1.516571 3.247036 -1.452140 + vertex 1.499470 3.243264 -1.467557 + vertex 1.425654 2.988739 -1.091849 + endloop + endfacet + facet normal 0.287102 0.225660 0.930940 + outer loop + vertex -0.025503 0.320378 -0.152919 + vertex 0.054785 0.423181 -0.202600 + vertex 0.128368 0.277101 -0.189883 + endloop + endfacet + facet normal -0.184494 -0.887768 0.421699 + outer loop + vertex 1.499470 3.243264 -1.467557 + vertex 1.518561 3.233232 -1.480323 + vertex 1.496745 3.231941 -1.492587 + endloop + endfacet + facet normal 0.800133 -0.597049 0.057623 + outer loop + vertex -0.025503 0.320378 -0.152919 + vertex 0.401182 0.932807 0.267848 + vertex 0.054785 0.423181 -0.202600 + endloop + endfacet + facet normal 0.781402 -0.617047 0.093078 + outer loop + vertex 0.401182 0.932807 0.267848 + vertex 0.457012 0.996856 0.223749 + vertex 0.054785 0.423181 -0.202600 + endloop + endfacet + facet normal 0.591942 -0.786968 0.174031 + outer loop + vertex 0.401182 0.932807 0.267848 + vertex 0.669640 1.332134 1.160477 + vertex 0.705398 1.345779 1.100557 + endloop + endfacet + facet normal 0.766158 -0.641513 0.038248 + outer loop + vertex 0.401182 0.932807 0.267848 + vertex 0.705398 1.345779 1.100557 + vertex 0.457012 0.996856 0.223749 + endloop + endfacet + facet normal 0.856900 -0.238298 0.457095 + outer loop + vertex 0.669640 1.332134 1.160477 + vertex 0.719906 1.512637 1.160348 + vertex 0.705398 1.345779 1.100557 + endloop + endfacet + facet normal 0.958668 -0.166126 0.230992 + outer loop + vertex 0.719906 1.512637 1.160348 + vertex 0.730700 1.462517 1.079503 + vertex 0.705398 1.345779 1.100557 + endloop + endfacet + facet normal 0.937909 -0.329898 0.107209 + outer loop + vertex 0.719906 1.512637 1.160348 + vertex 1.174691 2.517280 0.273131 + vertex 1.151094 2.435785 0.228796 + endloop + endfacet + facet normal 0.949356 -0.194094 0.247086 + outer loop + vertex 0.719906 1.512637 1.160348 + vertex 1.151094 2.435785 0.228796 + vertex 0.730700 1.462517 1.079503 + endloop + endfacet + facet normal 0.948076 -0.310924 0.066920 + outer loop + vertex 1.174691 2.517280 0.273131 + vertex 1.425654 2.988739 -1.091849 + vertex 1.151094 2.435785 0.228796 + endloop + endfacet + facet normal 0.943762 -0.325122 0.060078 + outer loop + vertex 1.425654 2.988739 -1.091849 + vertex 1.415802 2.946763 -1.164243 + vertex 1.151094 2.435785 0.228796 + endloop + endfacet + facet normal 0.965288 -0.260870 0.012923 + outer loop + vertex 1.425654 2.988739 -1.091849 + vertex 1.499470 3.243264 -1.467557 + vertex 1.496745 3.231941 -1.492587 + endloop + endfacet + facet normal 0.966702 -0.255370 0.016512 + outer loop + vertex 1.425654 2.988739 -1.091849 + vertex 1.496745 3.231941 -1.492587 + vertex 1.415802 2.946763 -1.164243 + endloop + endfacet + facet normal 0.287105 0.225662 0.930939 + outer loop + vertex 0.054785 0.423181 -0.202600 + vertex 0.190484 0.415984 -0.242705 + vertex 0.128368 0.277101 -0.189883 + endloop + endfacet + facet normal -0.184529 -0.887732 0.421759 + outer loop + vertex 1.496745 3.231941 -1.492587 + vertex 1.518561 3.233232 -1.480323 + vertex 1.510447 3.221589 -1.508381 + endloop + endfacet + facet normal 0.033782 -0.611306 0.790673 + outer loop + vertex 0.054785 0.423181 -0.202600 + vertex 0.457012 0.996856 0.223749 + vertex 0.552495 1.003632 0.224908 + endloop + endfacet + facet normal 0.175380 -0.676897 0.714880 + outer loop + vertex 0.054785 0.423181 -0.202600 + vertex 0.552495 1.003632 0.224908 + vertex 0.190484 0.415984 -0.242705 + endloop + endfacet + facet normal 0.061934 -0.933253 0.353840 + outer loop + vertex 0.457012 0.996856 0.223749 + vertex 0.705398 1.345779 1.100557 + vertex 0.552495 1.003632 0.224908 + endloop + endfacet + facet normal -0.055269 -0.926690 0.371741 + outer loop + vertex 0.705398 1.345779 1.100557 + vertex 0.764395 1.334228 1.080534 + vertex 0.552495 1.003632 0.224908 + endloop + endfacet + facet normal 0.378070 0.084331 0.921928 + outer loop + vertex 0.705398 1.345779 1.100557 + vertex 0.730700 1.462517 1.079503 + vertex 0.798102 1.398111 1.057754 + endloop + endfacet + facet normal 0.343856 0.149169 0.927099 + outer loop + vertex 0.705398 1.345779 1.100557 + vertex 0.798102 1.398111 1.057754 + vertex 0.764395 1.334228 1.080534 + endloop + endfacet + facet normal 0.588113 0.373160 0.717548 + outer loop + vertex 0.730700 1.462517 1.079503 + vertex 1.151094 2.435785 0.228796 + vertex 0.798102 1.398111 1.057754 + endloop + endfacet + facet normal 0.621727 0.348749 0.701305 + outer loop + vertex 1.151094 2.435785 0.228796 + vertex 1.197054 2.351813 0.229809 + vertex 0.798102 1.398111 1.057754 + endloop + endfacet + facet normal 0.900524 0.324002 0.289966 + outer loop + vertex 1.151094 2.435785 0.228796 + vertex 1.415802 2.946763 -1.164243 + vertex 1.442396 2.913601 -1.209781 + endloop + endfacet + facet normal 0.829440 0.457835 0.320024 + outer loop + vertex 1.151094 2.435785 0.228796 + vertex 1.442396 2.913601 -1.209781 + vertex 1.197054 2.351813 0.229809 + endloop + endfacet + facet normal 0.901798 0.190602 0.387855 + outer loop + vertex 1.415802 2.946763 -1.164243 + vertex 1.496745 3.231941 -1.492587 + vertex 1.442396 2.913601 -1.209781 + endloop + endfacet + facet normal 0.809248 0.306871 0.500946 + outer loop + vertex 1.496745 3.231941 -1.492587 + vertex 1.510447 3.221589 -1.508381 + vertex 1.442396 2.913601 -1.209781 + endloop + endfacet + facet normal 0.287106 0.225661 0.930939 + outer loop + vertex 0.190484 0.415984 -0.242705 + vertex 0.279407 0.304206 -0.243034 + vertex 0.128368 0.277101 -0.189883 + endloop + endfacet + facet normal -0.184330 -0.887790 0.421725 + outer loop + vertex 1.510447 3.221589 -1.508381 + vertex 1.518561 3.233232 -1.480323 + vertex 1.530259 3.220009 -1.503047 + endloop + endfacet + facet normal -0.455894 -0.365068 0.811718 + outer loop + vertex 0.190484 0.415984 -0.242705 + vertex 0.552495 1.003632 0.224908 + vertex 0.279407 0.304206 -0.243034 + endloop + endfacet + facet normal -0.683324 -0.202508 0.701469 + outer loop + vertex 0.552495 1.003632 0.224908 + vertex 0.615729 0.948034 0.270455 + vertex 0.279407 0.304206 -0.243034 + endloop + endfacet + facet normal -0.753481 -0.528666 0.390869 + outer loop + vertex 0.552495 1.003632 0.224908 + vertex 0.764395 1.334228 1.080534 + vertex 0.802205 1.306180 1.115484 + endloop + endfacet + facet normal -0.750331 -0.532756 0.391375 + outer loop + vertex 0.552495 1.003632 0.224908 + vertex 0.802205 1.306180 1.115484 + vertex 0.615729 0.948034 0.270455 + endloop + endfacet + facet normal -0.375712 0.480761 0.792281 + outer loop + vertex 0.764395 1.334228 1.080534 + vertex 0.798102 1.398111 1.057754 + vertex 0.802205 1.306180 1.115484 + endloop + endfacet + facet normal -0.382036 0.479180 0.790212 + outer loop + vertex 0.798102 1.398111 1.057754 + vertex 0.871357 1.367918 1.111479 + vertex 0.802205 1.306180 1.115484 + endloop + endfacet + facet normal -0.196148 0.688335 0.698371 + outer loop + vertex 0.798102 1.398111 1.057754 + vertex 1.197054 2.351813 0.229809 + vertex 1.277961 2.328603 0.275409 + endloop + endfacet + facet normal -0.219507 0.691687 0.688030 + outer loop + vertex 0.798102 1.398111 1.057754 + vertex 1.277961 2.328603 0.275409 + vertex 0.871357 1.367918 1.111479 + endloop + endfacet + facet normal 0.056591 0.926782 0.371313 + outer loop + vertex 1.197054 2.351813 0.229809 + vertex 1.442396 2.913601 -1.209781 + vertex 1.277961 2.328603 0.275409 + endloop + endfacet + facet normal -0.140208 0.926429 0.349386 + outer loop + vertex 1.442396 2.913601 -1.209781 + vertex 1.485407 2.914224 -1.194173 + vertex 1.277961 2.328603 0.275409 + endloop + endfacet + facet normal -0.131446 0.704857 0.697064 + outer loop + vertex 1.442396 2.913601 -1.209781 + vertex 1.510447 3.221589 -1.508381 + vertex 1.530259 3.220009 -1.503047 + endloop + endfacet + facet normal -0.250629 0.705920 0.662467 + outer loop + vertex 1.442396 2.913601 -1.209781 + vertex 1.530259 3.220009 -1.503047 + vertex 1.485407 2.914224 -1.194173 + endloop + endfacet + facet normal 0.287107 0.225659 0.930939 + outer loop + vertex 0.279407 0.304206 -0.243034 + vertex 0.254596 0.172017 -0.203340 + vertex 0.128368 0.277101 -0.189883 + endloop + endfacet + facet normal -0.184386 -0.887791 0.421697 + outer loop + vertex 1.530259 3.220009 -1.503047 + vertex 1.518561 3.233232 -1.480323 + vertex 1.541262 3.228386 -1.480601 + endloop + endfacet + facet normal -0.923753 0.336100 0.183621 + outer loop + vertex 0.279407 0.304206 -0.243034 + vertex 0.615729 0.948034 0.270455 + vertex 0.599097 0.871928 0.326091 + endloop + endfacet + facet normal -0.929181 0.254807 0.267763 + outer loop + vertex 0.279407 0.304206 -0.243034 + vertex 0.599097 0.871928 0.326091 + vertex 0.254596 0.172017 -0.203340 + endloop + endfacet + facet normal -0.956223 0.277304 0.093486 + outer loop + vertex 0.615729 0.948034 0.270455 + vertex 0.802205 1.306180 1.115484 + vertex 0.599097 0.871928 0.326091 + endloop + endfacet + facet normal -0.900450 0.434894 -0.007556 + outer loop + vertex 0.802205 1.306180 1.115484 + vertex 0.790359 1.282756 1.179089 + vertex 0.599097 0.871928 0.326091 + endloop + endfacet + facet normal -0.666761 0.743949 -0.044383 + outer loop + vertex 0.802205 1.306180 1.115484 + vertex 0.871357 1.367918 1.111479 + vertex 0.895302 1.394673 1.200220 + endloop + endfacet + facet normal -0.735310 0.668849 0.109359 + outer loop + vertex 0.802205 1.306180 1.115484 + vertex 0.895302 1.394673 1.200220 + vertex 0.790359 1.282756 1.179089 + endloop + endfacet + facet normal -0.882355 0.459965 0.099409 + outer loop + vertex 0.871357 1.367918 1.111479 + vertex 1.277961 2.328603 0.275409 + vertex 0.895302 1.394673 1.200220 + endloop + endfacet + facet normal -0.796392 0.557779 0.233757 + outer loop + vertex 1.277961 2.328603 0.275409 + vertex 1.332892 2.383628 0.331257 + vertex 0.895302 1.394673 1.200220 + endloop + endfacet + facet normal -0.852394 0.515902 0.085260 + outer loop + vertex 1.277961 2.328603 0.275409 + vertex 1.485407 2.914224 -1.194173 + vertex 1.512451 2.948164 -1.129171 + endloop + endfacet + facet normal -0.770076 0.621155 0.145430 + outer loop + vertex 1.277961 2.328603 0.275409 + vertex 1.512451 2.948164 -1.129171 + vertex 1.332892 2.383628 0.331257 + endloop + endfacet + facet normal -0.917797 0.340653 0.203972 + outer loop + vertex 1.485407 2.914224 -1.194173 + vertex 1.530259 3.220009 -1.503047 + vertex 1.512451 2.948164 -1.129171 + endloop + endfacet + facet normal -0.865919 0.423268 0.266512 + outer loop + vertex 1.530259 3.220009 -1.503047 + vertex 1.541262 3.228386 -1.480601 + vertex 1.512451 2.948164 -1.129171 + endloop + endfacet + facet normal 0.287101 -0.225652 0.930943 + outer loop + vertex 0.073210 -0.249522 -0.189883 + vertex 0.079574 -0.091378 -0.153513 + vertex 0.199438 -0.144437 -0.203340 + endloop + endfacet + facet normal -0.184375 0.887742 0.421806 + outer loop + vertex 1.480012 -3.212837 -1.457945 + vertex 1.463403 -3.205654 -1.480323 + vertex 1.486104 -3.200807 -1.480601 + endloop + endfacet + facet normal -0.475138 -0.667519 -0.573291 + outer loop + vertex 0.459966 -0.805043 0.349921 + vertex 0.543939 -0.844349 0.326091 + vertex 0.199438 -0.144437 -0.203340 + endloop + endfacet + facet normal -0.518250 -0.659949 -0.543952 + outer loop + vertex 0.079574 -0.091378 -0.153513 + vertex 0.459966 -0.805043 0.349921 + vertex 0.199438 -0.144437 -0.203340 + endloop + endfacet + facet normal -0.472387 -0.830830 -0.294232 + outer loop + vertex 0.459966 -0.805043 0.349921 + vertex 0.735200 -1.255177 1.179089 + vertex 0.543939 -0.844349 0.326091 + endloop + endfacet + facet normal -0.327001 -0.871802 -0.364734 + outer loop + vertex 0.459966 -0.805043 0.349921 + vertex 0.682616 -1.254015 1.223455 + vertex 0.735200 -1.255177 1.179089 + endloop + endfacet + facet normal -0.350685 -0.480595 -0.803771 + outer loop + vertex 0.796747 -1.430648 1.257154 + vertex 0.840144 -1.367094 1.200220 + vertex 0.735200 -1.255177 1.179089 + endloop + endfacet + facet normal -0.567528 -0.492582 -0.659754 + outer loop + vertex 0.682616 -1.254015 1.223455 + vertex 0.796747 -1.430648 1.257154 + vertex 0.735200 -1.255177 1.179089 + endloop + endfacet + facet normal -0.840572 0.096438 -0.533047 + outer loop + vertex 0.796747 -1.430648 1.257154 + vertex 1.277733 -2.356050 0.331257 + vertex 0.840144 -1.367094 1.200220 + endloop + endfacet + facet normal -0.887653 -0.000607 -0.460512 + outer loop + vertex 0.796747 -1.430648 1.257154 + vertex 1.265324 -2.447876 0.355297 + vertex 1.277733 -2.356050 0.331257 + endloop + endfacet + facet normal -0.991471 0.018419 -0.129021 + outer loop + vertex 1.448001 -2.962284 -1.063723 + vertex 1.457292 -2.920585 -1.129171 + vertex 1.277733 -2.356050 0.331257 + endloop + endfacet + facet normal -0.982980 0.091065 -0.159555 + outer loop + vertex 1.265324 -2.447876 0.355297 + vertex 1.448001 -2.962284 -1.063723 + vertex 1.277733 -2.356050 0.331257 + endloop + endfacet + facet normal -0.992560 0.041503 -0.114468 + outer loop + vertex 1.448001 -2.962284 -1.063723 + vertex 1.486104 -3.200807 -1.480601 + vertex 1.457292 -2.920585 -1.129171 + endloop + endfacet + facet normal -0.971498 0.156296 -0.178223 + outer loop + vertex 1.448001 -2.962284 -1.063723 + vertex 1.480012 -3.212837 -1.457945 + vertex 1.486104 -3.200807 -1.480601 + endloop + endfacet + facet normal 0.287098 -0.225652 0.930943 + outer loop + vertex 0.073210 -0.249522 -0.189883 + vertex -0.045083 -0.157405 -0.131074 + vertex 0.079574 -0.091378 -0.153513 + endloop + endfacet + facet normal -0.184356 0.887751 0.421795 + outer loop + vertex 1.461412 -3.219458 -1.452140 + vertex 1.463403 -3.205654 -1.480323 + vertex 1.480012 -3.212837 -1.457945 + endloop + endfacet + facet normal 0.127014 -0.525668 -0.841154 + outer loop + vertex -0.045083 -0.157405 -0.131074 + vertex 0.459966 -0.805043 0.349921 + vertex 0.079574 -0.091378 -0.153513 + endloop + endfacet + facet normal 0.362984 -0.356360 -0.860959 + outer loop + vertex -0.045083 -0.157405 -0.131074 + vertex 0.371885 -0.832137 0.324000 + vertex 0.459966 -0.805043 0.349921 + endloop + endfacet + facet normal 0.393003 -0.773264 -0.497606 + outer loop + vertex 0.628890 -1.275990 1.215172 + vertex 0.682616 -1.254015 1.223455 + vertex 0.459966 -0.805043 0.349921 + endloop + endfacet + facet normal 0.385496 -0.776755 -0.498040 + outer loop + vertex 0.371885 -0.832137 0.324000 + vertex 0.628890 -1.275990 1.215172 + vertex 0.459966 -0.805043 0.349921 + endloop + endfacet + facet normal 0.180201 -0.070741 -0.981083 + outer loop + vertex 0.628890 -1.275990 1.215172 + vertex 0.796747 -1.430648 1.257154 + vertex 0.682616 -1.254015 1.223455 + endloop + endfacet + facet normal 0.230535 -0.013907 -0.972965 + outer loop + vertex 0.628890 -1.275990 1.215172 + vertex 0.718689 -1.483148 1.239410 + vertex 0.796747 -1.430648 1.257154 + endloop + endfacet + facet normal -0.213642 0.591138 -0.777762 + outer loop + vertex 1.194918 -2.507357 0.329428 + vertex 1.265324 -2.447876 0.355297 + vertex 0.796747 -1.430648 1.257154 + endloop + endfacet + facet normal -0.219361 0.589029 -0.777769 + outer loop + vertex 0.718689 -1.483148 1.239410 + vertex 1.194918 -2.507357 0.329428 + vertex 0.796747 -1.430648 1.257154 + endloop + endfacet + facet normal -0.526722 0.775172 -0.348814 + outer loop + vertex 1.194918 -2.507357 0.329428 + vertex 1.448001 -2.962284 -1.063723 + vertex 1.265324 -2.447876 0.355297 + endloop + endfacet + facet normal -0.515792 0.782331 -0.349166 + outer loop + vertex 1.194918 -2.507357 0.329428 + vertex 1.409371 -2.980340 -1.047115 + vertex 1.448001 -2.962284 -1.063723 + endloop + endfacet + facet normal -0.425267 0.747819 -0.509819 + outer loop + vertex 1.461412 -3.219458 -1.452140 + vertex 1.480012 -3.212837 -1.457945 + vertex 1.448001 -2.962284 -1.063723 + endloop + endfacet + facet normal -0.532310 0.697278 -0.480052 + outer loop + vertex 1.409371 -2.980340 -1.047115 + vertex 1.461412 -3.219458 -1.452140 + vertex 1.448001 -2.962284 -1.063723 + endloop + endfacet + facet normal 0.287100 -0.225650 0.930943 + outer loop + vertex 0.073210 -0.249522 -0.189883 + vertex -0.080662 -0.292799 -0.152919 + vertex -0.045083 -0.157405 -0.131074 + endloop + endfacet + facet normal -0.184420 0.887742 0.421786 + outer loop + vertex 1.444311 -3.215685 -1.467557 + vertex 1.463403 -3.205654 -1.480323 + vertex 1.461412 -3.219458 -1.452140 + endloop + endfacet + facet normal 0.821850 0.134507 -0.553598 + outer loop + vertex 0.346023 -0.905228 0.267848 + vertex 0.371885 -0.832137 0.324000 + vertex -0.045083 -0.157405 -0.131074 + endloop + endfacet + facet normal 0.661470 -0.053120 -0.748088 + outer loop + vertex -0.080662 -0.292799 -0.152919 + vertex 0.346023 -0.905228 0.267848 + vertex -0.045083 -0.157405 -0.131074 + endloop + endfacet + facet normal 0.944038 -0.090313 -0.317233 + outer loop + vertex 0.346023 -0.905228 0.267848 + vertex 0.628890 -1.275990 1.215172 + vertex 0.371885 -0.832137 0.324000 + endloop + endfacet + facet normal 0.961417 0.036993 -0.272597 + outer loop + vertex 0.346023 -0.905228 0.267848 + vertex 0.614482 -1.304555 1.160477 + vertex 0.628890 -1.275990 1.215172 + endloop + endfacet + facet normal 0.790185 0.278662 -0.545853 + outer loop + vertex 0.664747 -1.485057 1.160348 + vertex 0.718689 -1.483148 1.239410 + vertex 0.628890 -1.275990 1.215172 + endloop + endfacet + facet normal 0.896214 0.249837 -0.366582 + outer loop + vertex 0.614482 -1.304555 1.160477 + vertex 0.664747 -1.485057 1.160348 + vertex 0.628890 -1.275990 1.215172 + endloop + endfacet + facet normal 0.608523 0.666115 -0.431267 + outer loop + vertex 0.664747 -1.485057 1.160348 + vertex 1.194918 -2.507357 0.329428 + vertex 0.718689 -1.483148 1.239410 + endloop + endfacet + facet normal 0.533112 0.682671 -0.499752 + outer loop + vertex 0.664747 -1.485057 1.160348 + vertex 1.119533 -2.489701 0.273131 + vertex 1.194918 -2.507357 0.329428 + endloop + endfacet + facet normal 0.592274 0.785884 -0.177760 + outer loop + vertex 1.370495 -2.961160 -1.091849 + vertex 1.409371 -2.980340 -1.047115 + vertex 1.194918 -2.507357 0.329428 + endloop + endfacet + facet normal 0.385836 0.891602 -0.237017 + outer loop + vertex 1.119533 -2.489701 0.273131 + vertex 1.370495 -2.961160 -1.091849 + vertex 1.194918 -2.507357 0.329428 + endloop + endfacet + facet normal 0.680415 0.665992 -0.305761 + outer loop + vertex 1.370495 -2.961160 -1.091849 + vertex 1.461412 -3.219458 -1.452140 + vertex 1.409371 -2.980340 -1.047115 + endloop + endfacet + facet normal 0.528015 0.747652 -0.402761 + outer loop + vertex 1.370495 -2.961160 -1.091849 + vertex 1.444311 -3.215685 -1.467557 + vertex 1.461412 -3.219458 -1.452140 + endloop + endfacet + facet normal 0.287102 -0.225660 0.930940 + outer loop + vertex 0.073210 -0.249522 -0.189883 + vertex -0.000373 -0.395602 -0.202600 + vertex -0.080662 -0.292799 -0.152919 + endloop + endfacet + facet normal -0.184492 0.887768 0.421700 + outer loop + vertex 1.441586 -3.204362 -1.492587 + vertex 1.463403 -3.205654 -1.480323 + vertex 1.444311 -3.215685 -1.467557 + endloop + endfacet + facet normal 0.800133 0.597049 0.057623 + outer loop + vertex -0.000373 -0.395602 -0.202600 + vertex 0.346023 -0.905228 0.267848 + vertex -0.080662 -0.292799 -0.152919 + endloop + endfacet + facet normal 0.781401 0.617048 0.093079 + outer loop + vertex -0.000373 -0.395602 -0.202600 + vertex 0.401854 -0.969277 0.223749 + vertex 0.346023 -0.905228 0.267848 + endloop + endfacet + facet normal 0.591942 0.786967 0.174031 + outer loop + vertex 0.650239 -1.318200 1.100557 + vertex 0.614482 -1.304555 1.160477 + vertex 0.346023 -0.905228 0.267848 + endloop + endfacet + facet normal 0.766158 0.641513 0.038248 + outer loop + vertex 0.401854 -0.969277 0.223749 + vertex 0.650239 -1.318200 1.100557 + vertex 0.346023 -0.905228 0.267848 + endloop + endfacet + facet normal 0.856900 0.238298 0.457095 + outer loop + vertex 0.650239 -1.318200 1.100557 + vertex 0.664747 -1.485057 1.160348 + vertex 0.614482 -1.304555 1.160477 + endloop + endfacet + facet normal 0.958668 0.166127 0.230991 + outer loop + vertex 0.650239 -1.318200 1.100557 + vertex 0.675542 -1.434938 1.079503 + vertex 0.664747 -1.485057 1.160348 + endloop + endfacet + facet normal 0.937909 0.329899 0.107207 + outer loop + vertex 1.095935 -2.408206 0.228796 + vertex 1.119533 -2.489701 0.273131 + vertex 0.664747 -1.485057 1.160348 + endloop + endfacet + facet normal 0.949356 0.194094 0.247086 + outer loop + vertex 0.675542 -1.434938 1.079503 + vertex 1.095935 -2.408206 0.228796 + vertex 0.664747 -1.485057 1.160348 + endloop + endfacet + facet normal 0.948076 0.310925 0.066919 + outer loop + vertex 1.095935 -2.408206 0.228796 + vertex 1.370495 -2.961160 -1.091849 + vertex 1.119533 -2.489701 0.273131 + endloop + endfacet + facet normal 0.943763 0.325119 0.060079 + outer loop + vertex 1.095935 -2.408206 0.228796 + vertex 1.360644 -2.919185 -1.164243 + vertex 1.370495 -2.961160 -1.091849 + endloop + endfacet + facet normal 0.965285 0.260878 0.012918 + outer loop + vertex 1.441586 -3.204362 -1.492587 + vertex 1.444311 -3.215685 -1.467557 + vertex 1.370495 -2.961160 -1.091849 + endloop + endfacet + facet normal 0.966703 0.255367 0.016514 + outer loop + vertex 1.360644 -2.919185 -1.164243 + vertex 1.441586 -3.204362 -1.492587 + vertex 1.370495 -2.961160 -1.091849 + endloop + endfacet + facet normal 0.287105 -0.225662 0.930939 + outer loop + vertex 0.073210 -0.249522 -0.189883 + vertex 0.135325 -0.388405 -0.242705 + vertex -0.000373 -0.395602 -0.202600 + endloop + endfacet + facet normal -0.184526 0.887733 0.421758 + outer loop + vertex 1.455288 -3.194010 -1.508381 + vertex 1.463403 -3.205654 -1.480323 + vertex 1.441586 -3.204362 -1.492587 + endloop + endfacet + facet normal 0.033782 0.611306 0.790673 + outer loop + vertex 0.497337 -0.976053 0.224908 + vertex 0.401854 -0.969277 0.223749 + vertex -0.000373 -0.395602 -0.202600 + endloop + endfacet + facet normal 0.175380 0.676897 0.714880 + outer loop + vertex 0.135325 -0.388405 -0.242705 + vertex 0.497337 -0.976053 0.224908 + vertex -0.000373 -0.395602 -0.202600 + endloop + endfacet + facet normal 0.061934 0.933253 0.353840 + outer loop + vertex 0.497337 -0.976053 0.224908 + vertex 0.650239 -1.318200 1.100557 + vertex 0.401854 -0.969277 0.223749 + endloop + endfacet + facet normal -0.055268 0.926690 0.371741 + outer loop + vertex 0.497337 -0.976053 0.224908 + vertex 0.709237 -1.306649 1.080534 + vertex 0.650239 -1.318200 1.100557 + endloop + endfacet + facet normal 0.378070 -0.084331 0.921928 + outer loop + vertex 0.742944 -1.370532 1.057754 + vertex 0.675542 -1.434938 1.079503 + vertex 0.650239 -1.318200 1.100557 + endloop + endfacet + facet normal 0.343856 -0.149169 0.927099 + outer loop + vertex 0.709237 -1.306649 1.080534 + vertex 0.742944 -1.370532 1.057754 + vertex 0.650239 -1.318200 1.100557 + endloop + endfacet + facet normal 0.588113 -0.373160 0.717548 + outer loop + vertex 0.742944 -1.370532 1.057754 + vertex 1.095935 -2.408206 0.228796 + vertex 0.675542 -1.434938 1.079503 + endloop + endfacet + facet normal 0.621728 -0.348749 0.701305 + outer loop + vertex 0.742944 -1.370532 1.057754 + vertex 1.141895 -2.324234 0.229809 + vertex 1.095935 -2.408206 0.228796 + endloop + endfacet + facet normal 0.900526 -0.323996 0.289965 + outer loop + vertex 1.387238 -2.886023 -1.209781 + vertex 1.360644 -2.919185 -1.164243 + vertex 1.095935 -2.408206 0.228796 + endloop + endfacet + facet normal 0.829441 -0.457835 0.320024 + outer loop + vertex 1.141895 -2.324234 0.229809 + vertex 1.387238 -2.886023 -1.209781 + vertex 1.095935 -2.408206 0.228796 + endloop + endfacet + facet normal 0.901800 -0.190600 0.387852 + outer loop + vertex 1.387238 -2.886023 -1.209781 + vertex 1.441586 -3.204362 -1.492587 + vertex 1.360644 -2.919185 -1.164243 + endloop + endfacet + facet normal 0.809241 -0.306879 0.500953 + outer loop + vertex 1.387238 -2.886023 -1.209781 + vertex 1.455288 -3.194010 -1.508381 + vertex 1.441586 -3.204362 -1.492587 + endloop + endfacet + facet normal 0.287106 -0.225661 0.930939 + outer loop + vertex 0.073210 -0.249522 -0.189883 + vertex 0.224249 -0.276626 -0.243034 + vertex 0.135325 -0.388405 -0.242705 + endloop + endfacet + facet normal -0.184330 0.887790 0.421725 + outer loop + vertex 1.475101 -3.192430 -1.503047 + vertex 1.463403 -3.205654 -1.480323 + vertex 1.455288 -3.194010 -1.508381 + endloop + endfacet + facet normal -0.455894 0.365068 0.811718 + outer loop + vertex 0.224249 -0.276626 -0.243034 + vertex 0.497337 -0.976053 0.224908 + vertex 0.135325 -0.388405 -0.242705 + endloop + endfacet + facet normal -0.683324 0.202508 0.701469 + outer loop + vertex 0.224249 -0.276626 -0.243034 + vertex 0.560570 -0.920455 0.270455 + vertex 0.497337 -0.976053 0.224908 + endloop + endfacet + facet normal -0.753482 0.528665 0.390869 + outer loop + vertex 0.747047 -1.278601 1.115484 + vertex 0.709237 -1.306649 1.080534 + vertex 0.497337 -0.976053 0.224908 + endloop + endfacet + facet normal -0.750331 0.532756 0.391375 + outer loop + vertex 0.560570 -0.920455 0.270455 + vertex 0.747047 -1.278601 1.115484 + vertex 0.497337 -0.976053 0.224908 + endloop + endfacet + facet normal -0.375711 -0.480761 0.792282 + outer loop + vertex 0.747047 -1.278601 1.115484 + vertex 0.742944 -1.370532 1.057754 + vertex 0.709237 -1.306649 1.080534 + endloop + endfacet + facet normal -0.382036 -0.479179 0.790212 + outer loop + vertex 0.747047 -1.278601 1.115484 + vertex 0.816199 -1.340339 1.111479 + vertex 0.742944 -1.370532 1.057754 + endloop + endfacet + facet normal -0.196148 -0.688335 0.698371 + outer loop + vertex 1.222802 -2.301024 0.275409 + vertex 1.141895 -2.324234 0.229809 + vertex 0.742944 -1.370532 1.057754 + endloop + endfacet + facet normal -0.219507 -0.691687 0.688030 + outer loop + vertex 0.816199 -1.340339 1.111479 + vertex 1.222802 -2.301024 0.275409 + vertex 0.742944 -1.370532 1.057754 + endloop + endfacet + facet normal 0.056590 -0.926781 0.371313 + outer loop + vertex 1.222802 -2.301024 0.275409 + vertex 1.387238 -2.886023 -1.209781 + vertex 1.141895 -2.324234 0.229809 + endloop + endfacet + facet normal -0.140208 -0.926429 0.349386 + outer loop + vertex 1.222802 -2.301024 0.275409 + vertex 1.430249 -2.886646 -1.194173 + vertex 1.387238 -2.886023 -1.209781 + endloop + endfacet + facet normal -0.131446 -0.704858 0.697064 + outer loop + vertex 1.475101 -3.192430 -1.503047 + vertex 1.455288 -3.194010 -1.508381 + vertex 1.387238 -2.886023 -1.209781 + endloop + endfacet + facet normal -0.250628 -0.705920 0.662467 + outer loop + vertex 1.430249 -2.886646 -1.194173 + vertex 1.475101 -3.192430 -1.503047 + vertex 1.387238 -2.886023 -1.209781 + endloop + endfacet + facet normal 0.287107 -0.225659 0.930939 + outer loop + vertex 0.073210 -0.249522 -0.189883 + vertex 0.199438 -0.144437 -0.203340 + vertex 0.224249 -0.276626 -0.243034 + endloop + endfacet + facet normal -0.184387 0.887791 0.421696 + outer loop + vertex 1.486104 -3.200807 -1.480601 + vertex 1.463403 -3.205654 -1.480323 + vertex 1.475101 -3.192430 -1.503047 + endloop + endfacet + facet normal -0.923753 -0.336100 0.183621 + outer loop + vertex 0.543939 -0.844349 0.326091 + vertex 0.560570 -0.920455 0.270455 + vertex 0.224249 -0.276626 -0.243034 + endloop + endfacet + facet normal -0.929181 -0.254807 0.267762 + outer loop + vertex 0.199438 -0.144437 -0.203340 + vertex 0.543939 -0.844349 0.326091 + vertex 0.224249 -0.276626 -0.243034 + endloop + endfacet + facet normal -0.956223 -0.277304 0.093486 + outer loop + vertex 0.543939 -0.844349 0.326091 + vertex 0.747047 -1.278601 1.115484 + vertex 0.560570 -0.920455 0.270455 + endloop + endfacet + facet normal -0.900450 -0.434894 -0.007556 + outer loop + vertex 0.543939 -0.844349 0.326091 + vertex 0.735200 -1.255177 1.179089 + vertex 0.747047 -1.278601 1.115484 + endloop + endfacet + facet normal -0.666762 -0.743948 -0.044383 + outer loop + vertex 0.840144 -1.367094 1.200220 + vertex 0.816199 -1.340339 1.111479 + vertex 0.747047 -1.278601 1.115484 + endloop + endfacet + facet normal -0.735310 -0.668849 0.109359 + outer loop + vertex 0.735200 -1.255177 1.179089 + vertex 0.840144 -1.367094 1.200220 + vertex 0.747047 -1.278601 1.115484 + endloop + endfacet + facet normal -0.882355 -0.459965 0.099409 + outer loop + vertex 0.840144 -1.367094 1.200220 + vertex 1.222802 -2.301024 0.275409 + vertex 0.816199 -1.340339 1.111479 + endloop + endfacet + facet normal -0.796393 -0.557778 0.233755 + outer loop + vertex 0.840144 -1.367094 1.200220 + vertex 1.277733 -2.356050 0.331257 + vertex 1.222802 -2.301024 0.275409 + endloop + endfacet + facet normal -0.852396 -0.515899 0.085259 + outer loop + vertex 1.457292 -2.920585 -1.129171 + vertex 1.430249 -2.886646 -1.194173 + vertex 1.222802 -2.301024 0.275409 + endloop + endfacet + facet normal -0.770078 -0.621153 0.145429 + outer loop + vertex 1.277733 -2.356050 0.331257 + vertex 1.457292 -2.920585 -1.129171 + vertex 1.222802 -2.301024 0.275409 + endloop + endfacet + facet normal -0.917798 -0.340652 0.203971 + outer loop + vertex 1.457292 -2.920585 -1.129171 + vertex 1.475101 -3.192430 -1.503047 + vertex 1.430249 -2.886646 -1.194173 + endloop + endfacet + facet normal -0.865921 -0.423265 0.266510 + outer loop + vertex 1.457292 -2.920585 -1.129171 + vertex 1.486104 -3.200807 -1.480601 + vertex 1.475101 -3.192430 -1.503047 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.891946 0.305186 -0.333607 + outer loop + vertex -1.823871 0.262815 0.436649 + vertex -1.887549 0.152714 0.506180 + vertex -1.825895 0.173241 0.360119 + endloop + endfacet + facet normal -0.885286 -0.462164 0.051707 + outer loop + vertex -1.964459 0.327821 0.278563 + vertex -1.928270 0.255226 0.249315 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -1.964459 0.327821 0.278563 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.782589 -0.524956 0.334628 + outer loop + vertex -1.964459 0.327821 0.278563 + vertex -1.825895 0.173241 0.360119 + vertex -1.928270 0.255226 0.249315 + endloop + endfacet + facet normal -0.758137 -0.413600 0.504146 + outer loop + vertex -1.964459 0.327821 0.278563 + vertex -1.823871 0.262815 0.436649 + vertex -1.825895 0.173241 0.360119 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.891943 0.305170 -0.333629 + outer loop + vertex -1.869800 0.269480 0.565534 + vertex -1.887549 0.152714 0.506180 + vertex -1.823871 0.262815 0.436649 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -1.964459 0.327821 0.278563 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.239093 -0.967433 -0.083113 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.059240 0.350344 0.289045 + vertex -1.964459 0.327821 0.278563 + endloop + endfacet + facet normal -0.347356 -0.934694 -0.075443 + outer loop + vertex -1.869800 0.269480 0.565534 + vertex -1.823871 0.262815 0.436649 + vertex -1.964459 0.327821 0.278563 + endloop + endfacet + facet normal -0.241774 -0.963362 -0.116098 + outer loop + vertex -2.059240 0.350344 0.289045 + vertex -1.869800 0.269480 0.565534 + vertex -1.964459 0.327821 0.278563 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.891948 0.305166 -0.333620 + outer loop + vertex -1.929093 0.188218 0.649726 + vertex -1.887549 0.152714 0.506180 + vertex -1.869800 0.269480 0.565534 + endloop + endfacet + facet normal 0.485254 -0.872347 -0.059485 + outer loop + vertex -2.141237 0.305836 0.272870 + vertex -2.059240 0.350344 0.289045 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.141237 0.305836 0.272870 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal 0.482345 -0.694664 -0.533652 + outer loop + vertex -2.141237 0.305836 0.272870 + vertex -1.869800 0.269480 0.565534 + vertex -2.059240 0.350344 0.289045 + endloop + endfacet + facet normal 0.403895 -0.783667 -0.471948 + outer loop + vertex -2.141237 0.305836 0.272870 + vertex -1.929093 0.188218 0.649726 + vertex -1.869800 0.269480 0.565534 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.891945 0.305175 -0.333622 + outer loop + vertex -1.957105 0.080220 0.625826 + vertex -1.887549 0.152714 0.506180 + vertex -1.929093 0.188218 0.649726 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.141237 0.305836 0.272870 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal 0.982346 -0.141966 0.121830 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.148711 0.227811 0.242217 + vertex -2.141237 0.305836 0.272870 + endloop + endfacet + facet normal 0.851678 -0.107380 -0.512947 + outer loop + vertex -1.957105 0.080220 0.625826 + vertex -1.929093 0.188218 0.649726 + vertex -2.141237 0.305836 0.272870 + endloop + endfacet + facet normal 0.903622 0.078834 -0.421014 + outer loop + vertex -2.148711 0.227811 0.242217 + vertex -1.957105 0.080220 0.625826 + vertex -2.141237 0.305836 0.272870 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.891943 0.305188 -0.333613 + outer loop + vertex -1.932741 0.026811 0.511829 + vertex -1.887549 0.152714 0.506180 + vertex -1.957105 0.080220 0.625826 + endloop + endfacet + facet normal 0.618495 0.724667 0.303843 + outer loop + vertex -2.076031 0.175025 0.220167 + vertex -2.148711 0.227811 0.242217 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.076031 0.175025 0.220167 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal 0.590632 0.806794 0.015398 + outer loop + vertex -2.076031 0.175025 0.220167 + vertex -1.957105 0.080220 0.625826 + vertex -2.148711 0.227811 0.242217 + endloop + endfacet + facet normal 0.806725 0.582334 -0.100412 + outer loop + vertex -2.076031 0.175025 0.220167 + vertex -1.932741 0.026811 0.511829 + vertex -1.957105 0.080220 0.625826 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.891946 0.305190 -0.333603 + outer loop + vertex -1.874349 0.068210 0.393579 + vertex -1.887549 0.152714 0.506180 + vertex -1.932741 0.026811 0.511829 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.076031 0.175025 0.220167 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.126801 0.930913 0.342523 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -1.977924 0.187225 0.223327 + vertex -2.076031 0.175025 0.220167 + endloop + endfacet + facet normal 0.145876 0.909062 0.390290 + outer loop + vertex -1.874349 0.068210 0.393579 + vertex -1.932741 0.026811 0.511829 + vertex -2.076031 0.175025 0.220167 + endloop + endfacet + facet normal -0.116741 0.779242 0.615755 + outer loop + vertex -1.977924 0.187225 0.223327 + vertex -1.874349 0.068210 0.393579 + vertex -2.076031 0.175025 0.220167 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.891944 0.305194 -0.333605 + outer loop + vertex -1.825895 0.173241 0.360119 + vertex -1.887549 0.152714 0.506180 + vertex -1.874349 0.068210 0.393579 + endloop + endfacet + facet normal -0.824144 0.500415 0.265276 + outer loop + vertex -1.928270 0.255226 0.249315 + vertex -1.977924 0.187225 0.223327 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.044177 0.405290 -0.393859 + vertex -1.928270 0.255226 0.249315 + vertex -2.044177 0.405290 -0.393859 + endloop + endfacet + facet normal -0.719097 0.282446 0.634920 + outer loop + vertex -1.928270 0.255226 0.249315 + vertex -1.874349 0.068210 0.393579 + vertex -1.977924 0.187225 0.223327 + endloop + endfacet + facet normal -0.460381 0.455179 0.762143 + outer loop + vertex -1.928270 0.255226 0.249315 + vertex -1.825895 0.173241 0.360119 + vertex -1.874349 0.068210 0.393579 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.417209 0.680008 -0.602931 + outer loop + vertex -1.578235 0.290569 0.523094 + vertex -1.568903 0.382055 0.619818 + vertex -1.690046 0.288253 0.597851 + endloop + endfacet + facet normal 0.390952 0.768585 0.506393 + outer loop + vertex -1.677769 0.494724 0.372043 + vertex -1.751140 0.490709 0.434782 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.677769 0.494724 0.372043 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.482775 0.633069 0.605105 + outer loop + vertex -1.677769 0.494724 0.372043 + vertex -1.690046 0.288253 0.597851 + vertex -1.751140 0.490709 0.434782 + endloop + endfacet + facet normal 0.406461 0.663174 0.628482 + outer loop + vertex -1.677769 0.494724 0.372043 + vertex -1.578235 0.290569 0.523094 + vertex -1.690046 0.288253 0.597851 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.417208 0.680009 -0.602931 + outer loop + vertex -1.459397 0.361776 0.521173 + vertex -1.568903 0.382055 0.619818 + vertex -1.578235 0.290569 0.523094 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.677769 0.494724 0.372043 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.141780 0.442906 0.885287 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.610792 0.552543 0.353843 + vertex -1.677769 0.494724 0.372043 + endloop + endfacet + facet normal -0.275093 0.481557 0.832122 + outer loop + vertex -1.459397 0.361776 0.521173 + vertex -1.578235 0.290569 0.523094 + vertex -1.677769 0.494724 0.372043 + endloop + endfacet + facet normal -0.234951 0.528878 0.815528 + outer loop + vertex -1.610792 0.552543 0.353843 + vertex -1.459397 0.361776 0.521173 + vertex -1.677769 0.494724 0.372043 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.417209 0.680007 -0.602932 + outer loop + vertex -1.423018 0.448254 0.593532 + vertex -1.568903 0.382055 0.619818 + vertex -1.459397 0.361776 0.521173 + endloop + endfacet + facet normal -0.577505 -0.348286 0.738367 + outer loop + vertex -1.600651 0.620626 0.393889 + vertex -1.610792 0.552543 0.353843 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.600651 0.620626 0.393889 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.825805 -0.189440 0.531186 + outer loop + vertex -1.600651 0.620626 0.393889 + vertex -1.459397 0.361776 0.521173 + vertex -1.610792 0.552543 0.353843 + endloop + endfacet + facet normal -0.799487 -0.150301 0.581575 + outer loop + vertex -1.600651 0.620626 0.393889 + vertex -1.423018 0.448254 0.593532 + vertex -1.459397 0.361776 0.521173 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.417208 0.680003 -0.602937 + outer loop + vertex -1.496495 0.484885 0.685687 + vertex -1.568903 0.382055 0.619818 + vertex -1.423018 0.448254 0.593532 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.600651 0.620626 0.393889 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.432328 -0.901613 0.013673 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.654973 0.647707 0.462025 + vertex -1.600651 0.620626 0.393889 + endloop + endfacet + facet normal -0.591238 -0.791076 -0.156960 + outer loop + vertex -1.496495 0.484885 0.685687 + vertex -1.423018 0.448254 0.593532 + vertex -1.600651 0.620626 0.393889 + endloop + endfacet + facet normal -0.591242 -0.791074 -0.156958 + outer loop + vertex -1.654973 0.647707 0.462025 + vertex -1.496495 0.484885 0.685687 + vertex -1.600651 0.620626 0.393889 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.417218 0.680005 -0.602929 + outer loop + vertex -1.624494 0.444081 0.728241 + vertex -1.568903 0.382055 0.619818 + vertex -1.496495 0.484885 0.685687 + endloop + endfacet + facet normal 0.053749 -0.836287 -0.545651 + outer loop + vertex -1.732860 0.613395 0.506941 + vertex -1.654973 0.647707 0.462025 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.732860 0.613395 0.506941 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.011834 -0.804398 -0.593973 + outer loop + vertex -1.732860 0.613395 0.506941 + vertex -1.496495 0.484885 0.685687 + vertex -1.654973 0.647707 0.462025 + endloop + endfacet + facet normal 0.043387 -0.783097 -0.620384 + outer loop + vertex -1.732860 0.613395 0.506941 + vertex -1.624494 0.444081 0.728241 + vertex -1.496495 0.484885 0.685687 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.417210 0.680010 -0.602928 + outer loop + vertex -1.710631 0.356573 0.689150 + vertex -1.568903 0.382055 0.619818 + vertex -1.624494 0.444081 0.728241 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.732860 0.613395 0.506941 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.644526 -0.270724 -0.715049 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.775658 0.543522 0.494818 + vertex -1.732860 0.613395 0.506941 + endloop + endfacet + facet normal 0.676753 -0.386139 -0.626819 + outer loop + vertex -1.710631 0.356573 0.689150 + vertex -1.624494 0.444081 0.728241 + vertex -1.732860 0.613395 0.506941 + endloop + endfacet + facet normal 0.734698 -0.349097 -0.581679 + outer loop + vertex -1.775658 0.543522 0.494818 + vertex -1.710631 0.356573 0.689150 + vertex -1.732860 0.613395 0.506941 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal -0.417210 0.680010 -0.602929 + outer loop + vertex -1.690046 0.288253 0.597851 + vertex -1.568903 0.382055 0.619818 + vertex -1.710631 0.356573 0.689150 + endloop + endfacet + facet normal 0.811765 0.561055 -0.162035 + outer loop + vertex -1.751140 0.490709 0.434782 + vertex -1.775658 0.543522 0.494818 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 0.828595 0.146647 + vertex -1.751140 0.490709 0.434782 + vertex -2.042185 0.828595 0.146647 + endloop + endfacet + facet normal 0.926234 0.373678 0.049547 + outer loop + vertex -1.751140 0.490709 0.434782 + vertex -1.710631 0.356573 0.689150 + vertex -1.775658 0.543522 0.494818 + endloop + endfacet + facet normal 0.957406 0.288746 -0.000204 + outer loop + vertex -1.751140 0.490709 0.434782 + vertex -1.690046 0.288253 0.597851 + vertex -1.710631 0.356573 0.689150 + endloop + endfacet + facet normal -0.188931 -0.058235 -0.980262 + outer loop + vertex -1.068990 0.002298 1.101103 + vertex -1.102244 0.110185 1.101103 + vertex -1.515773 0.002298 1.187214 + endloop + endfacet + facet normal -0.184716 -0.074175 -0.979989 + outer loop + vertex -1.102244 0.110185 1.101103 + vertex -1.211482 0.382218 1.101103 + vertex -1.515773 0.002298 1.187214 + endloop + endfacet + facet normal -0.069184 -0.258199 0.963611 + outer loop + vertex -1.515773 0.250511 0.260870 + vertex -1.391667 0.217257 0.260870 + vertex -1.515773 0.002298 0.194362 + endloop + endfacet + facet normal 0.049739 -0.258499 -0.964730 + outer loop + vertex -1.211482 0.382218 1.101103 + vertex -1.515773 0.250511 1.120705 + vertex -1.515773 0.002298 1.187214 + endloop + endfacet + facet normal 0.865196 -0.129781 0.484348 + outer loop + vertex -1.590238 0.217257 0.384977 + vertex -1.515773 0.250511 0.260870 + vertex -1.515773 0.002298 0.194362 + endloop + endfacet + facet normal 0.069184 -0.258199 -0.963611 + outer loop + vertex -1.515773 0.250511 1.120705 + vertex -1.639879 0.217257 1.120705 + vertex -1.515773 0.002298 1.187214 + endloop + endfacet + facet normal 0.202386 -0.609559 0.766471 + outer loop + vertex -1.681090 0.126405 0.336713 + vertex -1.590238 0.217257 0.384977 + vertex -1.515773 0.002298 0.194362 + endloop + endfacet + facet normal 0.189015 -0.189015 -0.963611 + outer loop + vertex -1.639879 0.217257 1.120705 + vertex -1.730732 0.126405 1.120705 + vertex -1.515773 0.002298 1.187214 + endloop + endfacet + facet normal 0.575660 -0.154247 0.803009 + outer loop + vertex -1.714344 0.002298 0.336713 + vertex -1.681090 0.126405 0.336713 + vertex -1.515773 0.002298 0.194362 + endloop + endfacet + facet normal 0.258199 -0.069185 -0.963611 + outer loop + vertex -1.730732 0.126405 1.120705 + vertex -1.763986 0.002298 1.120705 + vertex -1.515773 0.002298 1.187214 + endloop + endfacet + facet normal 0.202414 -0.788103 0.581311 + outer loop + vertex -1.391667 0.217257 0.260870 + vertex -1.300815 0.374617 0.442575 + vertex -1.161840 0.410311 0.442575 + endloop + endfacet + facet normal -0.085783 -0.731518 0.676405 + outer loop + vertex -1.515773 0.489080 0.539102 + vertex -1.300815 0.374617 0.442575 + vertex -1.391667 0.217257 0.260870 + endloop + endfacet + facet normal -0.199330 -0.743908 0.637862 + outer loop + vertex -1.515773 0.250511 0.260870 + vertex -1.515773 0.489080 0.539102 + vertex -1.391667 0.217257 0.260870 + endloop + endfacet + facet normal 0.818344 -0.436300 0.374105 + outer loop + vertex -1.590238 0.217257 0.384977 + vertex -1.515773 0.489080 0.539102 + vertex -1.515773 0.250511 0.260870 + endloop + endfacet + facet normal -0.151084 -0.455931 0.877098 + outer loop + vertex -1.590238 0.217257 0.384977 + vertex -1.730732 0.374617 0.442575 + vertex -1.515773 0.489080 0.539102 + endloop + endfacet + facet normal 0.186527 -0.186527 0.964580 + outer loop + vertex -1.888092 0.217257 0.442575 + vertex -1.730732 0.374617 0.442575 + vertex -1.590238 0.217257 0.384977 + endloop + endfacet + facet normal 0.154704 -0.579695 0.800012 + outer loop + vertex -1.681090 0.126405 0.336713 + vertex -1.888092 0.217257 0.442575 + vertex -1.590238 0.217257 0.384977 + endloop + endfacet + facet normal 0.413534 -0.110806 0.903721 + outer loop + vertex -1.714344 0.002298 0.336713 + vertex -1.888092 0.217257 0.442575 + vertex -1.681090 0.126405 0.336713 + endloop + endfacet + facet normal 0.303035 -0.212556 0.928972 + outer loop + vertex -1.714344 0.002298 0.336713 + vertex -1.937417 0.002298 0.409480 + vertex -1.888092 0.217257 0.442575 + endloop + endfacet + facet normal -0.839147 -0.156274 0.520972 + outer loop + vertex -1.161840 0.410311 0.442575 + vertex -0.820777 0.002298 0.869546 + vertex -1.085856 0.002298 0.442575 + endloop + endfacet + facet normal -0.844083 -0.175277 0.506756 + outer loop + vertex -1.161840 0.410311 0.442575 + vertex -0.905672 0.411127 0.869546 + vertex -0.820777 0.002298 0.869546 + endloop + endfacet + facet normal -0.610179 -0.701911 0.367427 + outer loop + vertex -1.087376 0.569084 0.869546 + vertex -0.905672 0.411127 0.869546 + vertex -1.161840 0.410311 0.442575 + endloop + endfacet + facet normal 0.237148 -0.923342 0.301993 + outer loop + vertex -1.300815 0.374617 0.442575 + vertex -1.087376 0.569084 0.869546 + vertex -1.161840 0.410311 0.442575 + endloop + endfacet + facet normal -0.224840 -0.839457 0.494731 + outer loop + vertex -1.515773 0.489080 0.539102 + vertex -1.087376 0.569084 0.869546 + vertex -1.300815 0.374617 0.442575 + endloop + endfacet + facet normal 0.136154 -0.988692 0.062858 + outer loop + vertex -1.515773 0.489080 0.539102 + vertex -1.515773 0.498724 0.690788 + vertex -1.087376 0.569084 0.869546 + endloop + endfacet + facet normal 0.379295 -0.923411 0.058708 + outer loop + vertex -1.822320 0.370554 0.655329 + vertex -1.515773 0.498724 0.690788 + vertex -1.515773 0.489080 0.539102 + endloop + endfacet + facet normal 0.407738 -0.899263 0.158352 + outer loop + vertex -1.730732 0.374617 0.442575 + vertex -1.822320 0.370554 0.655329 + vertex -1.515773 0.489080 0.539102 + endloop + endfacet + facet normal 0.678963 -0.678963 0.279317 + outer loop + vertex -1.888092 0.217257 0.442575 + vertex -1.822320 0.370554 0.655329 + vertex -1.730732 0.374617 0.442575 + endloop + endfacet + facet normal 0.852383 -0.512161 0.105518 + outer loop + vertex -1.888092 0.217257 0.442575 + vertex -1.954668 0.150289 0.655329 + vertex -1.822320 0.370554 0.655329 + endloop + endfacet + facet normal 0.871156 -0.475356 0.122977 + outer loop + vertex -2.028746 0.002298 0.608051 + vertex -1.954668 0.150289 0.655329 + vertex -1.888092 0.217257 0.442575 + endloop + endfacet + facet normal 0.876484 -0.263182 0.403126 + outer loop + vertex -1.937417 0.002298 0.409480 + vertex -2.028746 0.002298 0.608051 + vertex -1.888092 0.217257 0.442575 + endloop + endfacet + facet normal -0.881306 -0.176261 -0.438442 + outer loop + vertex -0.963269 0.382218 1.003234 + vertex -0.887285 0.002298 1.003234 + vertex -0.820777 0.002298 0.869546 + endloop + endfacet + facet normal -0.887549 -0.184303 -0.422243 + outer loop + vertex -0.905672 0.411127 0.869546 + vertex -0.963269 0.382218 1.003234 + vertex -0.820777 0.002298 0.869546 + endloop + endfacet + facet normal -0.599210 -0.689293 -0.407213 + outer loop + vertex -1.087376 0.569084 0.869546 + vertex -0.963269 0.382218 1.003234 + vertex -0.905672 0.411127 0.869546 + endloop + endfacet + facet normal -0.599209 -0.689293 -0.407213 + outer loop + vertex -1.087376 0.569084 0.869546 + vertex -1.120630 0.519014 1.003234 + vertex -0.963269 0.382218 1.003234 + endloop + endfacet + facet normal 0.249579 -0.925593 -0.284583 + outer loop + vertex -1.515773 0.432215 0.939001 + vertex -1.120630 0.519014 1.003234 + vertex -1.087376 0.569084 0.869546 + endloop + endfacet + facet normal 0.257640 -0.933317 -0.250082 + outer loop + vertex -1.515773 0.498724 0.690788 + vertex -1.515773 0.432215 0.939001 + vertex -1.087376 0.569084 0.869546 + endloop + endfacet + facet normal 0.397968 -0.886140 -0.237440 + outer loop + vertex -1.822320 0.370554 0.655329 + vertex -1.515773 0.432215 0.939001 + vertex -1.515773 0.498724 0.690788 + endloop + endfacet + facet normal 0.404057 -0.881292 -0.245075 + outer loop + vertex -1.822320 0.370554 0.655329 + vertex -1.776119 0.322712 0.903542 + vertex -1.515773 0.432215 0.939001 + endloop + endfacet + facet normal 0.894505 -0.365526 -0.257395 + outer loop + vertex -2.028746 0.002298 0.608051 + vertex -1.890735 0.131957 0.903542 + vertex -1.954668 0.150289 0.655329 + endloop + endfacet + facet normal 0.875203 -0.431019 -0.219643 + outer loop + vertex -2.028746 0.002298 0.608051 + vertex -1.945691 0.002298 0.939001 + vertex -1.890735 0.131957 0.903542 + endloop + endfacet + facet normal -0.472085 -0.094417 -0.876482 + outer loop + vertex -0.963269 0.382218 1.003234 + vertex -1.068990 0.002298 1.101103 + vertex -0.887285 0.002298 1.003234 + endloop + endfacet + facet normal -0.399085 -0.123011 -0.908625 + outer loop + vertex -0.963269 0.382218 1.003234 + vertex -1.102244 0.110185 1.101103 + vertex -1.068990 0.002298 1.101103 + endloop + endfacet + facet normal -0.362893 -0.145724 -0.920366 + outer loop + vertex -1.211482 0.382218 1.101103 + vertex -1.102244 0.110185 1.101103 + vertex -0.963269 0.382218 1.003234 + endloop + endfacet + facet normal -0.337955 -0.388762 -0.857117 + outer loop + vertex -1.120630 0.519014 1.003234 + vertex -1.211482 0.382218 1.101103 + vertex -0.963269 0.382218 1.003234 + endloop + endfacet + facet normal 0.260203 -0.670138 -0.695133 + outer loop + vertex -1.515773 0.432215 0.939001 + vertex -1.211482 0.382218 1.101103 + vertex -1.120630 0.519014 1.003234 + endloop + endfacet + facet normal 0.252094 -0.684269 -0.684269 + outer loop + vertex -1.515773 0.432215 0.939001 + vertex -1.515773 0.250511 1.120705 + vertex -1.211482 0.382218 1.101103 + endloop + endfacet + facet normal 0.186157 -0.694746 -0.694747 + outer loop + vertex -1.639879 0.217257 1.120705 + vertex -1.515773 0.250511 1.120705 + vertex -1.515773 0.432215 0.939001 + endloop + endfacet + facet normal 0.380661 -0.715228 -0.586128 + outer loop + vertex -1.776119 0.322712 0.903542 + vertex -1.639879 0.217257 1.120705 + vertex -1.515773 0.432215 0.939001 + endloop + endfacet + facet normal 0.673307 -0.404561 -0.618861 + outer loop + vertex -1.890735 0.131957 0.903542 + vertex -1.639879 0.217257 1.120705 + vertex -1.776119 0.322712 0.903542 + endloop + endfacet + facet normal 0.622430 -0.622430 -0.474513 + outer loop + vertex -1.890735 0.131957 0.903542 + vertex -1.730732 0.126405 1.120705 + vertex -1.639879 0.217257 1.120705 + endloop + endfacet + facet normal 0.784513 -0.210212 -0.583395 + outer loop + vertex -1.763986 0.002298 1.120705 + vertex -1.730732 0.126405 1.120705 + vertex -1.890735 0.131957 0.903542 + endloop + endfacet + facet normal 0.634201 -0.442244 -0.634200 + outer loop + vertex -1.945691 0.002298 0.939001 + vertex -1.763986 0.002298 1.120705 + vertex -1.890735 0.131957 0.903542 + endloop + endfacet + facet normal -0.521937 0.820092 0.234586 + outer loop + vertex -1.860467 0.186705 0.720924 + vertex -1.861866 0.181822 0.734879 + vertex -1.901368 0.159714 0.724277 + endloop + endfacet + facet normal 0.561336 0.037146 -0.826754 + outer loop + vertex -1.860467 0.186705 0.720924 + vertex -1.886257 0.190699 0.703593 + vertex -1.954668 0.150289 0.655329 + endloop + endfacet + facet normal 0.511620 -0.810681 -0.284677 + outer loop + vertex -1.954668 0.150289 0.655329 + vertex -1.901368 0.159714 0.724277 + vertex -1.860467 0.186705 0.720924 + endloop + endfacet + facet normal 0.675249 -0.414224 -0.610292 + outer loop + vertex -1.954668 0.150289 0.655329 + vertex -1.886257 0.190699 0.703593 + vertex -1.862077 0.240275 0.696698 + endloop + endfacet + facet normal 0.672121 -0.413267 -0.614380 + outer loop + vertex -1.849925 0.223467 0.721298 + vertex -1.862077 0.240275 0.696698 + vertex -1.886257 0.190699 0.703593 + endloop + endfacet + facet normal 0.536241 -0.145309 -0.831463 + outer loop + vertex -1.886257 0.190699 0.703593 + vertex -1.860467 0.186705 0.720924 + vertex -1.849925 0.223467 0.721298 + endloop + endfacet + facet normal 0.895058 -0.005534 -0.445915 + outer loop + vertex -1.862077 0.240275 0.696698 + vertex -1.849925 0.223467 0.721298 + vertex -1.835890 0.272417 0.748863 + endloop + endfacet + facet normal 0.914936 -0.290189 -0.280504 + outer loop + vertex -1.835890 0.272417 0.748863 + vertex -1.831853 0.302246 0.731172 + vertex -1.862077 0.240275 0.696698 + endloop + endfacet + facet normal 0.968834 -0.246922 -0.019740 + outer loop + vertex -1.822786 0.320837 0.786330 + vertex -1.835890 0.272417 0.748863 + vertex -1.828249 0.299062 0.790559 + endloop + endfacet + facet normal 0.977088 -0.189592 -0.096715 + outer loop + vertex -1.835890 0.272417 0.748863 + vertex -1.822786 0.320837 0.786330 + vertex -1.831853 0.302246 0.731172 + endloop + endfacet + facet normal 0.997900 -0.059398 0.025814 + outer loop + vertex -1.828830 0.308443 0.834594 + vertex -1.828249 0.299062 0.790559 + vertex -1.829451 0.294871 0.827351 + endloop + endfacet + facet normal 0.970842 -0.231529 0.062124 + outer loop + vertex -1.828830 0.308443 0.834594 + vertex -1.822786 0.320837 0.786330 + vertex -1.828249 0.299062 0.790559 + endloop + endfacet + facet normal 0.980896 -0.124577 0.149411 + outer loop + vertex -1.829451 0.294871 0.827351 + vertex -1.835347 0.274306 0.848914 + vertex -1.828830 0.308443 0.834594 + endloop + endfacet + facet normal 0.919196 -0.010333 0.393664 + outer loop + vertex -1.835347 0.274306 0.848914 + vertex -1.840920 0.283655 0.862173 + vertex -1.828830 0.308443 0.834594 + endloop + endfacet + facet normal 0.793512 -0.287576 0.536319 + outer loop + vertex -1.835347 0.274306 0.848914 + vertex -1.859056 0.246472 0.869068 + vertex -1.840920 0.283655 0.862173 + endloop + endfacet + facet normal 0.804794 -0.326705 0.495551 + outer loop + vertex -1.859056 0.246472 0.869068 + vertex -1.835347 0.274306 0.848914 + vertex -1.842342 0.249915 0.844194 + endloop + endfacet + facet normal 0.715217 -0.572144 0.401392 + outer loop + vertex -1.842342 0.249915 0.844194 + vertex -1.877191 0.209291 0.848384 + vertex -1.859056 0.246472 0.869068 + endloop + endfacet + facet normal 0.653586 -0.502280 0.566163 + outer loop + vertex -1.877191 0.209291 0.848384 + vertex -1.842342 0.249915 0.844194 + vertex -1.849634 0.224481 0.830049 + endloop + endfacet + facet normal 0.553775 -0.818229 0.154385 + outer loop + vertex -1.877191 0.209291 0.848384 + vertex -1.849634 0.224481 0.830049 + vertex -1.851632 0.217521 0.800321 + endloop + endfacet + facet normal 0.600953 -0.777222 0.186495 + outer loop + vertex -1.851632 0.217521 0.800321 + vertex -1.886257 0.190699 0.800120 + vertex -1.877191 0.209291 0.848384 + endloop + endfacet + facet normal 0.597519 -0.772989 0.213209 + outer loop + vertex -1.886257 0.190699 0.800120 + vertex -1.851632 0.217521 0.800321 + vertex -1.855076 0.205509 0.766424 + endloop + endfacet + facet normal 0.664247 -0.676876 0.317198 + outer loop + vertex -1.855076 0.205509 0.766424 + vertex -1.898347 0.165911 0.772540 + vertex -1.886257 0.190699 0.800120 + endloop + endfacet + facet normal 0.657633 -0.663550 0.356679 + outer loop + vertex -1.898347 0.165911 0.772540 + vertex -1.855076 0.205509 0.766424 + vertex -1.861866 0.181822 0.734879 + endloop + endfacet + facet normal 0.469526 -0.878965 0.083462 + outer loop + vertex -1.861866 0.181822 0.734879 + vertex -1.901368 0.159714 0.724277 + vertex -1.898347 0.165911 0.772540 + endloop + endfacet + facet normal 0.373063 -0.913279 -0.163542 + outer loop + vertex -1.954668 0.150289 0.655329 + vertex -1.890735 0.131957 0.903542 + vertex -1.901368 0.159714 0.724277 + endloop + endfacet + facet normal 0.998070 -0.011605 -0.060998 + outer loop + vertex -1.890735 0.131957 0.903542 + vertex -1.898347 0.165911 0.772540 + vertex -1.901368 0.159714 0.724277 + endloop + endfacet + facet normal 0.941414 -0.309132 -0.134823 + outer loop + vertex -1.890735 0.131957 0.903542 + vertex -1.886257 0.190699 0.800120 + vertex -1.898347 0.165911 0.772540 + endloop + endfacet + facet normal 0.967766 -0.234684 -0.091397 + outer loop + vertex -1.890735 0.131957 0.903542 + vertex -1.877191 0.209291 0.848384 + vertex -1.886257 0.190699 0.800120 + endloop + endfacet + facet normal 0.919147 -0.322406 -0.226325 + outer loop + vertex -1.890735 0.131957 0.903542 + vertex -1.859056 0.246472 0.869068 + vertex -1.877191 0.209291 0.848384 + endloop + endfacet + facet normal 0.629824 -0.378435 -0.678313 + outer loop + vertex -1.859056 0.246472 0.869068 + vertex -1.890735 0.131957 0.903542 + vertex -1.776119 0.322712 0.903542 + endloop + endfacet + facet normal 0.655910 -0.434390 -0.617322 + outer loop + vertex -1.776119 0.322712 0.903542 + vertex -1.840920 0.283655 0.862173 + vertex -1.859056 0.246472 0.869068 + endloop + endfacet + facet normal 0.635727 -0.691575 -0.342891 + outer loop + vertex -1.776119 0.322712 0.903542 + vertex -1.828830 0.308443 0.834594 + vertex -1.840920 0.283655 0.862173 + endloop + endfacet + facet normal 0.669934 -0.402535 -0.623822 + outer loop + vertex -1.822320 0.370554 0.655329 + vertex -1.954668 0.150289 0.655329 + vertex -1.862077 0.240275 0.696698 + endloop + endfacet + facet normal 0.919928 -0.341762 -0.192175 + outer loop + vertex -1.822320 0.370554 0.655329 + vertex -1.862077 0.240275 0.696698 + vertex -1.831853 0.302246 0.731172 + endloop + endfacet + facet normal 0.970270 -0.227405 -0.082850 + outer loop + vertex -1.822320 0.370554 0.655329 + vertex -1.831853 0.302246 0.731172 + vertex -1.822786 0.320837 0.786330 + endloop + endfacet + facet normal 0.549645 -0.795334 -0.255606 + outer loop + vertex -1.828830 0.308443 0.834594 + vertex -1.776119 0.322712 0.903542 + vertex -1.822320 0.370554 0.655329 + endloop + endfacet + facet normal -0.685612 -0.679787 -0.260433 + outer loop + vertex -1.822320 0.370554 0.655329 + vertex -1.828830 0.308443 0.834594 + vertex -1.822786 0.320837 0.786330 + endloop + endfacet + facet normal 0.097717 0.666160 0.739380 + outer loop + vertex 0.090069 -0.167229 -0.494952 + vertex -0.233263 -0.437810 -0.208435 + vertex -0.584930 -0.284506 -0.300080 + endloop + endfacet + facet normal -0.169718 0.339002 0.925350 + outer loop + vertex 0.460438 -0.389086 -0.345746 + vertex 0.090069 -0.167229 -0.494952 + vertex 0.457304 0.000000 -0.488862 + endloop + endfacet + facet normal 0.099872 0.664684 0.740419 + outer loop + vertex 0.460438 -0.389086 -0.345746 + vertex -0.233263 -0.437810 -0.208435 + vertex 0.090069 -0.167229 -0.494952 + endloop + endfacet + facet normal 0.220944 0.280460 0.934091 + outer loop + vertex -0.610705 0.000000 -0.379406 + vertex 0.090069 -0.167229 -0.494952 + vertex -0.584930 -0.284506 -0.300080 + endloop + endfacet + facet normal 0.220944 -0.280460 0.934091 + outer loop + vertex 0.090069 0.167229 -0.494952 + vertex -0.610705 0.000000 -0.379406 + vertex -0.584930 0.284506 -0.300080 + endloop + endfacet + facet normal -0.016582 0.000000 0.999862 + outer loop + vertex 0.090069 -0.167229 -0.494952 + vertex 0.090069 0.167229 -0.494952 + vertex 0.457304 0.000000 -0.488862 + endloop + endfacet + facet normal 0.162687 0.000000 0.986678 + outer loop + vertex 0.090069 0.167229 -0.494952 + vertex 0.090069 -0.167229 -0.494952 + vertex -0.610705 0.000000 -0.379406 + endloop + endfacet + facet normal -0.190478 0.247609 0.949951 + outer loop + vertex -1.141375 -0.292008 -0.409700 + vertex -0.610705 0.000000 -0.379406 + vertex -0.584930 -0.284506 -0.300080 + endloop + endfacet + facet normal 0.699707 0.000000 0.714430 + outer loop + vertex -1.141375 0.292008 -0.409700 + vertex -1.141375 -0.292008 -0.409700 + vertex -1.418457 0.000000 -0.138327 + endloop + endfacet + facet normal -0.190478 -0.247609 0.949951 + outer loop + vertex -0.610705 0.000000 -0.379406 + vertex -1.141375 0.292008 -0.409700 + vertex -0.584930 0.284506 -0.300080 + endloop + endfacet + facet normal -0.056992 0.000000 0.998375 + outer loop + vertex -1.141375 0.292008 -0.409700 + vertex -0.610705 0.000000 -0.379406 + vertex -1.141375 -0.292008 -0.409700 + endloop + endfacet + facet normal 0.802316 -0.263622 0.535530 + outer loop + vertex -1.338460 0.472478 -0.025593 + vertex -1.141375 0.292008 -0.409700 + vertex -1.418457 0.000000 -0.138327 + endloop + endfacet + facet normal -0.193045 -0.149942 0.969666 + outer loop + vertex -1.141375 0.292008 -0.409700 + vertex -0.903297 0.764486 -0.289242 + vertex -0.584930 0.284506 -0.300080 + endloop + endfacet + facet normal 0.667307 -0.481182 0.568477 + outer loop + vertex -0.903297 0.764486 -0.289242 + vertex -1.141375 0.292008 -0.409700 + vertex -1.338460 0.472478 -0.025593 + endloop + endfacet + facet normal 0.097717 -0.666160 0.739380 + outer loop + vertex -0.233263 0.437810 -0.208435 + vertex 0.090069 0.167229 -0.494952 + vertex -0.584930 0.284506 -0.300080 + endloop + endfacet + facet normal -0.169718 -0.339002 0.925350 + outer loop + vertex 0.090069 0.167229 -0.494952 + vertex 0.460438 0.389086 -0.345746 + vertex 0.457304 0.000000 -0.488862 + endloop + endfacet + facet normal 0.099872 -0.664684 0.740419 + outer loop + vertex 0.460438 0.389086 -0.345746 + vertex 0.090069 0.167229 -0.494952 + vertex -0.233263 0.437810 -0.208435 + endloop + endfacet + facet normal -0.193045 0.149942 0.969666 + outer loop + vertex -0.903297 -0.764486 -0.289242 + vertex -1.141375 -0.292008 -0.409700 + vertex -0.584930 -0.284506 -0.300080 + endloop + endfacet + facet normal 0.802316 0.263622 0.535530 + outer loop + vertex -1.141375 -0.292008 -0.409700 + vertex -1.338460 -0.472478 -0.025593 + vertex -1.418457 0.000000 -0.138327 + endloop + endfacet + facet normal 0.667307 0.481182 0.568476 + outer loop + vertex -1.338460 -0.472478 -0.025593 + vertex -1.141375 -0.292008 -0.409700 + vertex -0.903297 -0.764486 -0.289242 + endloop + endfacet + facet normal -0.188931 0.058235 -0.980262 + outer loop + vertex -1.515773 0.000460 1.187214 + vertex -1.102244 -0.107427 1.101103 + vertex -1.068990 0.000460 1.101103 + endloop + endfacet + facet normal -0.184716 0.074175 -0.979989 + outer loop + vertex -1.515773 0.000460 1.187214 + vertex -1.211482 -0.379460 1.101103 + vertex -1.102244 -0.107427 1.101103 + endloop + endfacet + facet normal -0.069184 0.258199 0.963611 + outer loop + vertex -1.515773 0.000460 0.194362 + vertex -1.391667 -0.214499 0.260870 + vertex -1.515773 -0.247753 0.260870 + endloop + endfacet + facet normal 0.049739 0.258499 -0.964730 + outer loop + vertex -1.515773 0.000460 1.187214 + vertex -1.515773 -0.247753 1.120705 + vertex -1.211482 -0.379460 1.101103 + endloop + endfacet + facet normal 0.865196 0.129781 0.484348 + outer loop + vertex -1.515773 0.000460 0.194362 + vertex -1.515773 -0.247753 0.260870 + vertex -1.590238 -0.214499 0.384977 + endloop + endfacet + facet normal 0.069184 0.258199 -0.963611 + outer loop + vertex -1.515773 0.000460 1.187214 + vertex -1.639879 -0.214499 1.120705 + vertex -1.515773 -0.247753 1.120705 + endloop + endfacet + facet normal 0.202386 0.609559 0.766471 + outer loop + vertex -1.515773 0.000460 0.194362 + vertex -1.590238 -0.214499 0.384977 + vertex -1.681090 -0.123647 0.336713 + endloop + endfacet + facet normal 0.189015 0.189015 -0.963611 + outer loop + vertex -1.515773 0.000460 1.187214 + vertex -1.730732 -0.123647 1.120705 + vertex -1.639879 -0.214499 1.120705 + endloop + endfacet + facet normal 0.575660 0.154247 0.803009 + outer loop + vertex -1.515773 0.000460 0.194362 + vertex -1.681090 -0.123647 0.336713 + vertex -1.714344 0.000460 0.336713 + endloop + endfacet + facet normal 0.258199 0.069185 -0.963611 + outer loop + vertex -1.515773 0.000460 1.187214 + vertex -1.763986 0.000460 1.120705 + vertex -1.730732 -0.123647 1.120705 + endloop + endfacet + facet normal 0.202414 0.788103 0.581311 + outer loop + vertex -1.161840 -0.407553 0.442575 + vertex -1.300815 -0.371860 0.442575 + vertex -1.391667 -0.214499 0.260870 + endloop + endfacet + facet normal -0.085783 0.731518 0.676405 + outer loop + vertex -1.391667 -0.214499 0.260870 + vertex -1.300815 -0.371860 0.442575 + vertex -1.515773 -0.486322 0.539102 + endloop + endfacet + facet normal -0.199329 0.743908 0.637862 + outer loop + vertex -1.391667 -0.214499 0.260870 + vertex -1.515773 -0.486322 0.539102 + vertex -1.515773 -0.247753 0.260870 + endloop + endfacet + facet normal 0.818344 0.436300 0.374105 + outer loop + vertex -1.515773 -0.247753 0.260870 + vertex -1.515773 -0.486322 0.539102 + vertex -1.590238 -0.214499 0.384977 + endloop + endfacet + facet normal -0.151084 0.455931 0.877098 + outer loop + vertex -1.515773 -0.486322 0.539102 + vertex -1.730732 -0.371860 0.442575 + vertex -1.590238 -0.214499 0.384977 + endloop + endfacet + facet normal 0.186527 0.186527 0.964580 + outer loop + vertex -1.590238 -0.214499 0.384977 + vertex -1.730732 -0.371860 0.442575 + vertex -1.888092 -0.214499 0.442575 + endloop + endfacet + facet normal 0.154704 0.579696 0.800012 + outer loop + vertex -1.590238 -0.214499 0.384977 + vertex -1.888092 -0.214499 0.442575 + vertex -1.681090 -0.123647 0.336713 + endloop + endfacet + facet normal 0.413534 0.110806 0.903721 + outer loop + vertex -1.681090 -0.123647 0.336713 + vertex -1.888092 -0.214499 0.442575 + vertex -1.714344 0.000460 0.336713 + endloop + endfacet + facet normal 0.303035 0.212556 0.928972 + outer loop + vertex -1.888092 -0.214499 0.442575 + vertex -1.937417 0.000460 0.409480 + vertex -1.714344 0.000460 0.336713 + endloop + endfacet + facet normal -0.839147 0.156274 0.520972 + outer loop + vertex -1.085856 0.000460 0.442575 + vertex -0.820777 0.000460 0.869546 + vertex -1.161840 -0.407553 0.442575 + endloop + endfacet + facet normal -0.844083 0.175277 0.506756 + outer loop + vertex -0.820777 0.000460 0.869546 + vertex -0.905672 -0.408369 0.869546 + vertex -1.161840 -0.407553 0.442575 + endloop + endfacet + facet normal -0.610179 0.701911 0.367427 + outer loop + vertex -1.161840 -0.407553 0.442575 + vertex -0.905672 -0.408369 0.869546 + vertex -1.087376 -0.566326 0.869546 + endloop + endfacet + facet normal 0.237148 0.923342 0.301994 + outer loop + vertex -1.161840 -0.407553 0.442575 + vertex -1.087376 -0.566326 0.869546 + vertex -1.300815 -0.371860 0.442575 + endloop + endfacet + facet normal -0.224840 0.839457 0.494731 + outer loop + vertex -1.300815 -0.371860 0.442575 + vertex -1.087376 -0.566326 0.869546 + vertex -1.515773 -0.486322 0.539102 + endloop + endfacet + facet normal 0.136154 0.988692 0.062858 + outer loop + vertex -1.087376 -0.566326 0.869546 + vertex -1.515773 -0.495966 0.690788 + vertex -1.515773 -0.486322 0.539102 + endloop + endfacet + facet normal 0.379295 0.923411 0.058708 + outer loop + vertex -1.515773 -0.486322 0.539102 + vertex -1.515773 -0.495966 0.690788 + vertex -1.822320 -0.367796 0.655329 + endloop + endfacet + facet normal 0.407738 0.899263 0.158352 + outer loop + vertex -1.515773 -0.486322 0.539102 + vertex -1.822320 -0.367796 0.655329 + vertex -1.730732 -0.371860 0.442575 + endloop + endfacet + facet normal 0.678963 0.678963 0.279318 + outer loop + vertex -1.730732 -0.371860 0.442575 + vertex -1.822320 -0.367796 0.655329 + vertex -1.888092 -0.214499 0.442575 + endloop + endfacet + facet normal 0.852383 0.512161 0.105518 + outer loop + vertex -1.822320 -0.367796 0.655329 + vertex -1.954668 -0.147531 0.655329 + vertex -1.888092 -0.214499 0.442575 + endloop + endfacet + facet normal 0.871156 0.475356 0.122977 + outer loop + vertex -1.888092 -0.214499 0.442575 + vertex -1.954668 -0.147531 0.655329 + vertex -2.028746 0.000460 0.608051 + endloop + endfacet + facet normal 0.876484 0.263183 0.403126 + outer loop + vertex -1.888092 -0.214499 0.442575 + vertex -2.028746 0.000460 0.608051 + vertex -1.937417 0.000460 0.409480 + endloop + endfacet + facet normal -0.881306 0.176261 -0.438442 + outer loop + vertex -0.820777 0.000460 0.869546 + vertex -0.887285 0.000460 1.003234 + vertex -0.963269 -0.379460 1.003234 + endloop + endfacet + facet normal -0.887549 0.184303 -0.422243 + outer loop + vertex -0.820777 0.000460 0.869546 + vertex -0.963269 -0.379460 1.003234 + vertex -0.905672 -0.408369 0.869546 + endloop + endfacet + facet normal -0.599210 0.689293 -0.407213 + outer loop + vertex -0.905672 -0.408369 0.869546 + vertex -0.963269 -0.379460 1.003234 + vertex -1.087376 -0.566326 0.869546 + endloop + endfacet + facet normal -0.599209 0.689293 -0.407214 + outer loop + vertex -0.963269 -0.379460 1.003234 + vertex -1.120630 -0.516256 1.003234 + vertex -1.087376 -0.566326 0.869546 + endloop + endfacet + facet normal 0.249579 0.925593 -0.284584 + outer loop + vertex -1.087376 -0.566326 0.869546 + vertex -1.120630 -0.516256 1.003234 + vertex -1.515773 -0.429457 0.939001 + endloop + endfacet + facet normal 0.257641 0.933317 -0.250082 + outer loop + vertex -1.087376 -0.566326 0.869546 + vertex -1.515773 -0.429457 0.939001 + vertex -1.515773 -0.495966 0.690788 + endloop + endfacet + facet normal 0.397968 0.886140 -0.237441 + outer loop + vertex -1.515773 -0.495966 0.690788 + vertex -1.515773 -0.429457 0.939001 + vertex -1.822320 -0.367796 0.655329 + endloop + endfacet + facet normal 0.404057 0.881292 -0.245075 + outer loop + vertex -1.515773 -0.429457 0.939001 + vertex -1.776119 -0.319954 0.903542 + vertex -1.822320 -0.367796 0.655329 + endloop + endfacet + facet normal 0.894505 0.365526 -0.257395 + outer loop + vertex -1.954668 -0.147531 0.655329 + vertex -1.890735 -0.129199 0.903542 + vertex -2.028746 0.000460 0.608051 + endloop + endfacet + facet normal 0.875203 0.431019 -0.219643 + outer loop + vertex -1.890735 -0.129199 0.903542 + vertex -1.945691 0.000460 0.939001 + vertex -2.028746 0.000460 0.608051 + endloop + endfacet + facet normal -0.472085 0.094417 -0.876482 + outer loop + vertex -0.887285 0.000460 1.003234 + vertex -1.068990 0.000460 1.101103 + vertex -0.963269 -0.379460 1.003234 + endloop + endfacet + facet normal -0.399085 0.123011 -0.908625 + outer loop + vertex -1.068990 0.000460 1.101103 + vertex -1.102244 -0.107427 1.101103 + vertex -0.963269 -0.379460 1.003234 + endloop + endfacet + facet normal -0.362893 0.145724 -0.920366 + outer loop + vertex -0.963269 -0.379460 1.003234 + vertex -1.102244 -0.107427 1.101103 + vertex -1.211482 -0.379460 1.101103 + endloop + endfacet + facet normal -0.337955 0.388762 -0.857118 + outer loop + vertex -0.963269 -0.379460 1.003234 + vertex -1.211482 -0.379460 1.101103 + vertex -1.120630 -0.516256 1.003234 + endloop + endfacet + facet normal 0.260203 0.670138 -0.695133 + outer loop + vertex -1.120630 -0.516256 1.003234 + vertex -1.211482 -0.379460 1.101103 + vertex -1.515773 -0.429457 0.939001 + endloop + endfacet + facet normal 0.252094 0.684269 -0.684269 + outer loop + vertex -1.211482 -0.379460 1.101103 + vertex -1.515773 -0.247753 1.120705 + vertex -1.515773 -0.429457 0.939001 + endloop + endfacet + facet normal 0.186156 0.694746 -0.694747 + outer loop + vertex -1.515773 -0.429457 0.939001 + vertex -1.515773 -0.247753 1.120705 + vertex -1.639879 -0.214499 1.120705 + endloop + endfacet + facet normal 0.380661 0.715228 -0.586128 + outer loop + vertex -1.515773 -0.429457 0.939001 + vertex -1.639879 -0.214499 1.120705 + vertex -1.776119 -0.319954 0.903542 + endloop + endfacet + facet normal 0.673307 0.404561 -0.618861 + outer loop + vertex -1.776119 -0.319954 0.903542 + vertex -1.639879 -0.214499 1.120705 + vertex -1.890735 -0.129199 0.903542 + endloop + endfacet + facet normal 0.622430 0.622430 -0.474513 + outer loop + vertex -1.639879 -0.214499 1.120705 + vertex -1.730732 -0.123647 1.120705 + vertex -1.890735 -0.129199 0.903542 + endloop + endfacet + facet normal 0.784513 0.210211 -0.583395 + outer loop + vertex -1.890735 -0.129199 0.903542 + vertex -1.730732 -0.123647 1.120705 + vertex -1.763986 0.000460 1.120705 + endloop + endfacet + facet normal 0.634201 0.442244 -0.634200 + outer loop + vertex -1.890735 -0.129199 0.903542 + vertex -1.763986 0.000460 1.120705 + vertex -1.945691 0.000460 0.939001 + endloop + endfacet + facet normal -0.521937 -0.820093 0.234582 + outer loop + vertex -1.901368 -0.156956 0.724277 + vertex -1.861866 -0.179064 0.734879 + vertex -1.860467 -0.183947 0.720924 + endloop + endfacet + facet normal 0.561336 -0.037146 -0.826754 + outer loop + vertex -1.954668 -0.147531 0.655329 + vertex -1.886257 -0.187942 0.703593 + vertex -1.860467 -0.183947 0.720924 + endloop + endfacet + facet normal 0.511620 0.810681 -0.284676 + outer loop + vertex -1.860467 -0.183947 0.720924 + vertex -1.901368 -0.156956 0.724277 + vertex -1.954668 -0.147531 0.655329 + endloop + endfacet + facet normal 0.675249 0.414225 -0.610292 + outer loop + vertex -1.862077 -0.237518 0.696698 + vertex -1.886257 -0.187942 0.703593 + vertex -1.954668 -0.147531 0.655329 + endloop + endfacet + facet normal 0.672121 0.413267 -0.614381 + outer loop + vertex -1.886257 -0.187942 0.703593 + vertex -1.862077 -0.237518 0.696698 + vertex -1.849925 -0.220709 0.721298 + endloop + endfacet + facet normal 0.536241 0.145310 -0.831463 + outer loop + vertex -1.849925 -0.220709 0.721298 + vertex -1.860467 -0.183947 0.720924 + vertex -1.886257 -0.187942 0.703593 + endloop + endfacet + facet normal 0.895058 0.005534 -0.445915 + outer loop + vertex -1.835890 -0.269659 0.748863 + vertex -1.849925 -0.220709 0.721298 + vertex -1.862077 -0.237518 0.696698 + endloop + endfacet + facet normal 0.914936 0.290190 -0.280504 + outer loop + vertex -1.862077 -0.237518 0.696698 + vertex -1.831853 -0.299488 0.731172 + vertex -1.835890 -0.269659 0.748863 + endloop + endfacet + facet normal 0.968834 0.246923 -0.019739 + outer loop + vertex -1.828249 -0.296305 0.790559 + vertex -1.835890 -0.269659 0.748863 + vertex -1.822786 -0.318079 0.786330 + endloop + endfacet + facet normal 0.977088 0.189592 -0.096715 + outer loop + vertex -1.831853 -0.299488 0.731172 + vertex -1.822786 -0.318079 0.786330 + vertex -1.835890 -0.269659 0.748863 + endloop + endfacet + facet normal 0.997901 0.059398 0.025814 + outer loop + vertex -1.829451 -0.292113 0.827351 + vertex -1.828249 -0.296305 0.790559 + vertex -1.828830 -0.305685 0.834594 + endloop + endfacet + facet normal 0.970842 0.231530 0.062124 + outer loop + vertex -1.828249 -0.296305 0.790559 + vertex -1.822786 -0.318079 0.786330 + vertex -1.828830 -0.305685 0.834594 + endloop + endfacet + facet normal 0.980896 0.124577 0.149412 + outer loop + vertex -1.828830 -0.305685 0.834594 + vertex -1.835347 -0.271548 0.848914 + vertex -1.829451 -0.292113 0.827351 + endloop + endfacet + facet normal 0.919196 0.010333 0.393664 + outer loop + vertex -1.828830 -0.305685 0.834594 + vertex -1.840920 -0.280897 0.862173 + vertex -1.835347 -0.271548 0.848914 + endloop + endfacet + facet normal 0.793512 0.287575 0.536319 + outer loop + vertex -1.840920 -0.280897 0.862173 + vertex -1.859056 -0.243714 0.869068 + vertex -1.835347 -0.271548 0.848914 + endloop + endfacet + facet normal 0.804794 0.326706 0.495550 + outer loop + vertex -1.842342 -0.247157 0.844194 + vertex -1.835347 -0.271548 0.848914 + vertex -1.859056 -0.243714 0.869068 + endloop + endfacet + facet normal 0.715218 0.572144 0.401390 + outer loop + vertex -1.859056 -0.243714 0.869068 + vertex -1.877191 -0.206533 0.848384 + vertex -1.842342 -0.247157 0.844194 + endloop + endfacet + facet normal 0.653585 0.502279 0.566165 + outer loop + vertex -1.849634 -0.221723 0.830049 + vertex -1.842342 -0.247157 0.844194 + vertex -1.877191 -0.206533 0.848384 + endloop + endfacet + facet normal 0.553774 0.818230 0.154383 + outer loop + vertex -1.851632 -0.214763 0.800321 + vertex -1.849634 -0.221723 0.830049 + vertex -1.877191 -0.206533 0.848384 + endloop + endfacet + facet normal 0.600953 0.777223 0.186494 + outer loop + vertex -1.877191 -0.206533 0.848384 + vertex -1.886257 -0.187942 0.800120 + vertex -1.851632 -0.214763 0.800321 + endloop + endfacet + facet normal 0.597519 0.772990 0.213208 + outer loop + vertex -1.855076 -0.202751 0.766424 + vertex -1.851632 -0.214763 0.800321 + vertex -1.886257 -0.187942 0.800120 + endloop + endfacet + facet normal 0.664247 0.676876 0.317198 + outer loop + vertex -1.886257 -0.187942 0.800120 + vertex -1.898347 -0.163153 0.772540 + vertex -1.855076 -0.202751 0.766424 + endloop + endfacet + facet normal 0.657633 0.663550 0.356678 + outer loop + vertex -1.861866 -0.179064 0.734879 + vertex -1.855076 -0.202751 0.766424 + vertex -1.898347 -0.163153 0.772540 + endloop + endfacet + facet normal 0.469526 0.878965 0.083462 + outer loop + vertex -1.898347 -0.163153 0.772540 + vertex -1.901368 -0.156956 0.724277 + vertex -1.861866 -0.179064 0.734879 + endloop + endfacet + facet normal 0.373063 0.913279 -0.163542 + outer loop + vertex -1.901368 -0.156956 0.724277 + vertex -1.890735 -0.129199 0.903542 + vertex -1.954668 -0.147531 0.655329 + endloop + endfacet + facet normal 0.998070 0.011605 -0.060998 + outer loop + vertex -1.901368 -0.156956 0.724277 + vertex -1.898347 -0.163153 0.772540 + vertex -1.890735 -0.129199 0.903542 + endloop + endfacet + facet normal 0.941414 0.309131 -0.134823 + outer loop + vertex -1.898347 -0.163153 0.772540 + vertex -1.886257 -0.187942 0.800120 + vertex -1.890735 -0.129199 0.903542 + endloop + endfacet + facet normal 0.967765 0.234684 -0.091397 + outer loop + vertex -1.886257 -0.187942 0.800120 + vertex -1.877191 -0.206533 0.848384 + vertex -1.890735 -0.129199 0.903542 + endloop + endfacet + facet normal 0.919147 0.322407 -0.226325 + outer loop + vertex -1.877191 -0.206533 0.848384 + vertex -1.859056 -0.243714 0.869068 + vertex -1.890735 -0.129199 0.903542 + endloop + endfacet + facet normal 0.629825 0.378435 -0.678313 + outer loop + vertex -1.776119 -0.319954 0.903542 + vertex -1.890735 -0.129199 0.903542 + vertex -1.859056 -0.243714 0.869068 + endloop + endfacet + facet normal 0.655910 0.434389 -0.617323 + outer loop + vertex -1.859056 -0.243714 0.869068 + vertex -1.840920 -0.280897 0.862173 + vertex -1.776119 -0.319954 0.903542 + endloop + endfacet + facet normal 0.635727 0.691576 -0.342891 + outer loop + vertex -1.840920 -0.280897 0.862173 + vertex -1.828830 -0.305685 0.834594 + vertex -1.776119 -0.319954 0.903542 + endloop + endfacet + facet normal 0.669934 0.402535 -0.623822 + outer loop + vertex -1.862077 -0.237518 0.696698 + vertex -1.954668 -0.147531 0.655329 + vertex -1.822320 -0.367796 0.655329 + endloop + endfacet + facet normal 0.919928 0.341762 -0.192175 + outer loop + vertex -1.831853 -0.299488 0.731172 + vertex -1.862077 -0.237518 0.696698 + vertex -1.822320 -0.367796 0.655329 + endloop + endfacet + facet normal 0.970270 0.227404 -0.082849 + outer loop + vertex -1.822786 -0.318079 0.786330 + vertex -1.831853 -0.299488 0.731172 + vertex -1.822320 -0.367796 0.655329 + endloop + endfacet + facet normal 0.549645 0.795334 -0.255606 + outer loop + vertex -1.822320 -0.367796 0.655329 + vertex -1.776119 -0.319954 0.903542 + vertex -1.828830 -0.305685 0.834594 + endloop + endfacet + facet normal -0.685613 0.679786 -0.260433 + outer loop + vertex -1.822786 -0.318079 0.786330 + vertex -1.828830 -0.305685 0.834594 + vertex -1.822320 -0.367796 0.655329 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.891946 -0.305187 -0.333607 + outer loop + vertex -1.818374 -0.186279 0.356358 + vertex -1.880028 -0.165751 0.502419 + vertex -1.816350 -0.275852 0.432888 + endloop + endfacet + facet normal -0.885286 0.462164 0.051707 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -1.920747 -0.268264 0.245554 + vertex -1.956937 -0.340858 0.274802 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -1.956937 -0.340858 0.274802 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.782591 0.524956 0.334623 + outer loop + vertex -1.920747 -0.268264 0.245554 + vertex -1.818374 -0.186279 0.356358 + vertex -1.956937 -0.340858 0.274802 + endloop + endfacet + facet normal -0.758139 0.413598 0.504145 + outer loop + vertex -1.818374 -0.186279 0.356358 + vertex -1.816350 -0.275852 0.432888 + vertex -1.956937 -0.340858 0.274802 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.891943 -0.305171 -0.333630 + outer loop + vertex -1.816350 -0.275852 0.432888 + vertex -1.880028 -0.165751 0.502419 + vertex -1.862278 -0.282517 0.561774 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -1.956937 -0.340858 0.274802 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.239093 0.967433 -0.083113 + outer loop + vertex -1.956937 -0.340858 0.274802 + vertex -2.051718 -0.363382 0.285284 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.347357 0.934693 -0.075444 + outer loop + vertex -1.956937 -0.340858 0.274802 + vertex -1.816350 -0.275852 0.432888 + vertex -1.862278 -0.282517 0.561774 + endloop + endfacet + facet normal -0.241774 0.963362 -0.116099 + outer loop + vertex -1.956937 -0.340858 0.274802 + vertex -1.862278 -0.282517 0.561774 + vertex -2.051718 -0.363382 0.285284 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.891950 -0.305165 -0.333615 + outer loop + vertex -1.862278 -0.282517 0.561774 + vertex -1.880028 -0.165751 0.502419 + vertex -1.921571 -0.201255 0.645966 + endloop + endfacet + facet normal 0.485254 0.872347 -0.059485 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.051718 -0.363382 0.285284 + vertex -2.133715 -0.318873 0.269109 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.133715 -0.318873 0.269109 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal 0.482345 0.694665 -0.533651 + outer loop + vertex -2.051718 -0.363382 0.285284 + vertex -1.862278 -0.282517 0.561774 + vertex -2.133715 -0.318873 0.269109 + endloop + endfacet + facet normal 0.403897 0.783665 -0.471949 + outer loop + vertex -1.862278 -0.282517 0.561774 + vertex -1.921571 -0.201255 0.645966 + vertex -2.133715 -0.318873 0.269109 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.891947 -0.305175 -0.333616 + outer loop + vertex -1.921571 -0.201255 0.645966 + vertex -1.880028 -0.165751 0.502419 + vertex -1.949582 -0.093257 0.622065 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.133715 -0.318873 0.269109 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal 0.982346 0.141966 0.121830 + outer loop + vertex -2.133715 -0.318873 0.269109 + vertex -2.141189 -0.240848 0.238457 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal 0.851677 0.107381 -0.512947 + outer loop + vertex -2.133715 -0.318873 0.269109 + vertex -1.921571 -0.201255 0.645966 + vertex -1.949582 -0.093257 0.622065 + endloop + endfacet + facet normal 0.903622 -0.078834 -0.421014 + outer loop + vertex -2.133715 -0.318873 0.269109 + vertex -1.949582 -0.093257 0.622065 + vertex -2.141189 -0.240848 0.238457 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.891946 -0.305182 -0.333612 + outer loop + vertex -1.949582 -0.093257 0.622065 + vertex -1.880028 -0.165751 0.502419 + vertex -1.925218 -0.039849 0.508068 + endloop + endfacet + facet normal 0.618494 -0.724668 0.303843 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.141189 -0.240848 0.238457 + vertex -2.068509 -0.188062 0.216406 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.068509 -0.188062 0.216406 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal 0.590631 -0.806795 0.015399 + outer loop + vertex -2.141189 -0.240848 0.238457 + vertex -1.949582 -0.093257 0.622065 + vertex -2.068509 -0.188062 0.216406 + endloop + endfacet + facet normal 0.806724 -0.582335 -0.100411 + outer loop + vertex -1.949582 -0.093257 0.622065 + vertex -1.925218 -0.039849 0.508068 + vertex -2.068509 -0.188062 0.216406 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.891950 -0.305184 -0.333600 + outer loop + vertex -1.925218 -0.039849 0.508068 + vertex -1.880028 -0.165751 0.502419 + vertex -1.866827 -0.081247 0.389819 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.068509 -0.188062 0.216406 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.126801 -0.930913 0.342523 + outer loop + vertex -2.068509 -0.188062 0.216406 + vertex -1.970402 -0.200263 0.219567 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal 0.145877 -0.909062 0.390290 + outer loop + vertex -2.068509 -0.188062 0.216406 + vertex -1.925218 -0.039849 0.508068 + vertex -1.866827 -0.081247 0.389819 + endloop + endfacet + facet normal -0.116741 -0.779242 0.615755 + outer loop + vertex -2.068509 -0.188062 0.216406 + vertex -1.866827 -0.081247 0.389819 + vertex -1.970402 -0.200263 0.219567 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.891944 -0.305192 -0.333606 + outer loop + vertex -1.866827 -0.081247 0.389819 + vertex -1.880028 -0.165751 0.502419 + vertex -1.818374 -0.186279 0.356358 + endloop + endfacet + facet normal -0.824144 -0.500415 0.265276 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -1.970402 -0.200263 0.219567 + vertex -1.920747 -0.268264 0.245554 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.036655 -0.418328 -0.397620 + vertex -1.920747 -0.268264 0.245554 + vertex -2.036655 -0.418328 -0.397620 + endloop + endfacet + facet normal -0.719098 -0.282447 0.634918 + outer loop + vertex -1.970402 -0.200263 0.219567 + vertex -1.866827 -0.081247 0.389819 + vertex -1.920747 -0.268264 0.245554 + endloop + endfacet + facet normal -0.460383 -0.455179 0.762141 + outer loop + vertex -1.866827 -0.081247 0.389819 + vertex -1.818374 -0.186279 0.356358 + vertex -1.920747 -0.268264 0.245554 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.417208 -0.680009 -0.602931 + outer loop + vertex -1.690046 -0.233094 0.600108 + vertex -1.568903 -0.326897 0.622075 + vertex -1.578235 -0.235411 0.525351 + endloop + endfacet + facet normal 0.390952 -0.768585 0.506392 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.751140 -0.435551 0.437038 + vertex -1.677769 -0.439566 0.374299 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.677769 -0.439566 0.374299 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal 0.482776 -0.633070 0.605104 + outer loop + vertex -1.751140 -0.435551 0.437038 + vertex -1.690046 -0.233094 0.600108 + vertex -1.677769 -0.439566 0.374299 + endloop + endfacet + facet normal 0.406461 -0.663174 0.628482 + outer loop + vertex -1.690046 -0.233094 0.600108 + vertex -1.578235 -0.235411 0.525351 + vertex -1.677769 -0.439566 0.374299 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.417208 -0.680009 -0.602931 + outer loop + vertex -1.578235 -0.235411 0.525351 + vertex -1.568903 -0.326897 0.622075 + vertex -1.459397 -0.306618 0.523429 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.677769 -0.439566 0.374299 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.141780 -0.442905 0.885287 + outer loop + vertex -1.677769 -0.439566 0.374299 + vertex -1.610792 -0.497384 0.356099 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.275093 -0.481557 0.832122 + outer loop + vertex -1.677769 -0.439566 0.374299 + vertex -1.578235 -0.235411 0.525351 + vertex -1.459397 -0.306618 0.523429 + endloop + endfacet + facet normal -0.234952 -0.528877 0.815528 + outer loop + vertex -1.677769 -0.439566 0.374299 + vertex -1.459397 -0.306618 0.523429 + vertex -1.610792 -0.497384 0.356099 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.417209 -0.680007 -0.602932 + outer loop + vertex -1.459397 -0.306618 0.523429 + vertex -1.568903 -0.326897 0.622075 + vertex -1.423018 -0.393096 0.595789 + endloop + endfacet + facet normal -0.577505 0.348286 0.738367 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.610792 -0.497384 0.356099 + vertex -1.600651 -0.565468 0.396146 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.600651 -0.565468 0.396146 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.825805 0.189440 0.531186 + outer loop + vertex -1.610792 -0.497384 0.356099 + vertex -1.459397 -0.306618 0.523429 + vertex -1.600651 -0.565468 0.396146 + endloop + endfacet + facet normal -0.799487 0.150301 0.581575 + outer loop + vertex -1.459397 -0.306618 0.523429 + vertex -1.423018 -0.393096 0.595789 + vertex -1.600651 -0.565468 0.396146 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.417208 -0.680003 -0.602937 + outer loop + vertex -1.423018 -0.393096 0.595789 + vertex -1.568903 -0.326897 0.622075 + vertex -1.496495 -0.429726 0.687944 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.600651 -0.565468 0.396146 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.432328 0.901613 0.013672 + outer loop + vertex -1.600651 -0.565468 0.396146 + vertex -1.654973 -0.592549 0.464281 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.591238 0.791076 -0.156961 + outer loop + vertex -1.600651 -0.565468 0.396146 + vertex -1.423018 -0.393096 0.595789 + vertex -1.496495 -0.429726 0.687944 + endloop + endfacet + facet normal -0.591241 0.791074 -0.156958 + outer loop + vertex -1.600651 -0.565468 0.396146 + vertex -1.496495 -0.429726 0.687944 + vertex -1.654973 -0.592549 0.464281 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.417217 -0.680005 -0.602929 + outer loop + vertex -1.496495 -0.429726 0.687944 + vertex -1.568903 -0.326897 0.622075 + vertex -1.624494 -0.388922 0.730498 + endloop + endfacet + facet normal 0.053748 0.836287 -0.545650 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.654973 -0.592549 0.464281 + vertex -1.732860 -0.558236 0.509198 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.732860 -0.558236 0.509198 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal 0.011833 0.804398 -0.593973 + outer loop + vertex -1.654973 -0.592549 0.464281 + vertex -1.496495 -0.429726 0.687944 + vertex -1.732860 -0.558236 0.509198 + endloop + endfacet + facet normal 0.043387 0.783097 -0.620384 + outer loop + vertex -1.496495 -0.429726 0.687944 + vertex -1.624494 -0.388922 0.730498 + vertex -1.732860 -0.558236 0.509198 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.417210 -0.680010 -0.602928 + outer loop + vertex -1.624494 -0.388922 0.730498 + vertex -1.568903 -0.326897 0.622075 + vertex -1.710631 -0.301414 0.691406 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.732860 -0.558236 0.509198 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal 0.644526 0.270723 -0.715049 + outer loop + vertex -1.732860 -0.558236 0.509198 + vertex -1.775658 -0.488364 0.497074 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal 0.676753 0.386138 -0.626819 + outer loop + vertex -1.732860 -0.558236 0.509198 + vertex -1.624494 -0.388922 0.730498 + vertex -1.710631 -0.301414 0.691406 + endloop + endfacet + facet normal 0.734698 0.349097 -0.581678 + outer loop + vertex -1.732860 -0.558236 0.509198 + vertex -1.710631 -0.301414 0.691406 + vertex -1.775658 -0.488364 0.497074 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal -0.417210 -0.680010 -0.602929 + outer loop + vertex -1.710631 -0.301414 0.691406 + vertex -1.568903 -0.326897 0.622075 + vertex -1.690046 -0.233094 0.600108 + endloop + endfacet + facet normal 0.811765 -0.561055 -0.162035 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.775658 -0.488364 0.497074 + vertex -1.751140 -0.435551 0.437038 + endloop + endfacet + facet normal 0.000000 0.000000 0.000000 + outer loop + vertex -2.042185 -0.773436 0.148903 + vertex -1.751140 -0.435551 0.437038 + vertex -2.042185 -0.773436 0.148903 + endloop + endfacet + facet normal 0.926234 -0.373678 0.049547 + outer loop + vertex -1.775658 -0.488364 0.497074 + vertex -1.710631 -0.301414 0.691406 + vertex -1.751140 -0.435551 0.437038 + endloop + endfacet + facet normal 0.957406 -0.288746 -0.000204 + outer loop + vertex -1.710631 -0.301414 0.691406 + vertex -1.690046 -0.233094 0.600108 + vertex -1.751140 -0.435551 0.437038 + endloop + endfacet + facet normal -0.416389 -0.719636 -0.555648 + outer loop + vertex -1.741939 0.308654 0.859300 + vertex -1.712011 0.319710 0.822553 + vertex -1.750357 0.337030 0.828857 + endloop + endfacet + facet normal 0.054302 -0.722882 -0.688835 + outer loop + vertex -1.790363 0.316971 0.846754 + vertex -1.741939 0.308654 0.859300 + vertex -1.750357 0.337030 0.828857 + endloop + endfacet + facet normal 0.418187 -0.411097 -0.810012 + outer loop + vertex -1.787783 0.271717 0.871053 + vertex -1.790363 0.316971 0.846754 + vertex -1.828352 0.274189 0.848854 + endloop + endfacet + facet normal 0.147421 -0.461365 -0.874877 + outer loop + vertex -1.787783 0.271717 0.871053 + vertex -1.741939 0.308654 0.859300 + vertex -1.790363 0.316971 0.846754 + endloop + endfacet + facet normal 0.471918 -0.110360 -0.874708 + outer loop + vertex -1.832032 0.223009 0.853326 + vertex -1.787783 0.271717 0.871053 + vertex -1.828352 0.274189 0.848854 + endloop + endfacet + facet normal 0.488866 0.668645 -0.560290 + outer loop + vertex -1.857784 0.181133 0.812886 + vertex -1.825276 0.146936 0.800439 + vertex -1.821248 0.177171 0.840037 + endloop + endfacet + facet normal 0.901277 0.416942 -0.117724 + outer loop + vertex -1.855204 0.162086 0.765183 + vertex -1.857784 0.181133 0.812886 + vertex -1.872164 0.202947 0.780055 + endloop + endfacet + facet normal 0.416388 0.908437 0.036928 + outer loop + vertex -1.825276 0.146936 0.800439 + vertex -1.855204 0.162086 0.765183 + vertex -1.816858 0.144767 0.758879 + endloop + endfacet + facet normal 0.654929 0.713351 -0.249396 + outer loop + vertex -1.855204 0.162086 0.765183 + vertex -1.825276 0.146936 0.800439 + vertex -1.857784 0.181133 0.812886 + endloop + endfacet + facet normal 0.901277 0.243724 0.358188 + outer loop + vertex -1.857784 0.207340 0.740883 + vertex -1.855204 0.162086 0.765183 + vertex -1.872164 0.202947 0.780055 + endloop + endfacet + facet normal 0.488877 0.152067 0.858996 + outer loop + vertex -1.825276 0.173143 0.728435 + vertex -1.857784 0.207340 0.740883 + vertex -1.821248 0.221758 0.717537 + endloop + endfacet + facet normal 0.416391 0.719641 0.555640 + outer loop + vertex -1.855204 0.162086 0.765183 + vertex -1.825276 0.173143 0.728435 + vertex -1.816858 0.144767 0.758879 + endloop + endfacet + facet normal 0.654935 0.386148 0.649577 + outer loop + vertex -1.825276 0.173143 0.728435 + vertex -1.855204 0.162086 0.765183 + vertex -1.857784 0.207340 0.740883 + endloop + endfacet + facet normal 0.289382 -0.326073 0.899964 + outer loop + vertex -1.832032 0.265413 0.736821 + vertex -1.783608 0.267106 0.721864 + vertex -1.821248 0.221758 0.717537 + endloop + endfacet + facet normal 0.471929 -0.646786 0.599125 + outer loop + vertex -1.787783 0.314121 0.754550 + vertex -1.832032 0.265413 0.736821 + vertex -1.828352 0.301745 0.773145 + endloop + endfacet + facet normal 0.005013 -0.570512 0.821274 + outer loop + vertex -1.783608 0.267106 0.721864 + vertex -1.787783 0.314121 0.754550 + vertex -1.745967 0.304626 0.747698 + endloop + endfacet + facet normal 0.266493 -0.534111 0.802313 + outer loop + vertex -1.787783 0.314121 0.754550 + vertex -1.783608 0.267106 0.721864 + vertex -1.832032 0.265413 0.736821 + endloop + endfacet + facet normal 0.418194 -0.835585 0.356246 + outer loop + vertex -1.790363 0.333168 0.802253 + vertex -1.787783 0.314121 0.754550 + vertex -1.828352 0.301745 0.773145 + endloop + endfacet + facet normal 0.054304 -0.996534 0.063015 + outer loop + vertex -1.741939 0.334861 0.787296 + vertex -1.790363 0.333168 0.802253 + vertex -1.750357 0.337030 0.828857 + endloop + endfacet + facet normal -0.079078 -0.788413 0.610042 + outer loop + vertex -1.787783 0.314121 0.754550 + vertex -1.741939 0.334861 0.787296 + vertex -1.745967 0.304626 0.747698 + endloop + endfacet + facet normal 0.147422 -0.915790 0.373625 + outer loop + vertex -1.741939 0.334861 0.787296 + vertex -1.787783 0.314121 0.754550 + vertex -1.790363 0.333168 0.802253 + endloop + endfacet + facet normal -0.416386 -0.908438 -0.036925 + outer loop + vertex -1.712011 0.319710 0.822553 + vertex -1.741939 0.334861 0.787296 + vertex -1.750357 0.337030 0.828857 + endloop + endfacet + facet normal 0.629848 -0.584399 -0.511634 + outer loop + vertex -1.790363 0.316971 0.846754 + vertex -1.836207 0.296231 0.814007 + vertex -1.828352 0.274189 0.848854 + endloop + endfacet + facet normal 0.303187 -0.895462 -0.325923 + outer loop + vertex -1.790363 0.333168 0.802253 + vertex -1.790363 0.316971 0.846754 + vertex -1.750357 0.337030 0.828857 + endloop + endfacet + facet normal 0.629848 -0.776548 0.016290 + outer loop + vertex -1.836207 0.296231 0.814007 + vertex -1.790363 0.333168 0.802253 + vertex -1.828352 0.301745 0.773145 + endloop + endfacet + facet normal 0.556288 -0.780874 -0.284216 + outer loop + vertex -1.790363 0.333168 0.802253 + vertex -1.836207 0.296231 0.814007 + vertex -1.790363 0.316971 0.846754 + endloop + endfacet + facet normal 0.813501 -0.390871 -0.430623 + outer loop + vertex -1.836207 0.296231 0.814007 + vertex -1.861960 0.238159 0.818069 + vertex -1.828352 0.274189 0.848854 + endloop + endfacet + facet normal 0.813501 -0.576223 0.078630 + outer loop + vertex -1.861960 0.254356 0.773568 + vertex -1.836207 0.296231 0.814007 + vertex -1.828352 0.301745 0.773145 + endloop + endfacet + facet normal 0.976356 -0.203134 -0.073935 + outer loop + vertex -1.861960 0.238159 0.818069 + vertex -1.861960 0.254356 0.773568 + vertex -1.872164 0.202947 0.780055 + endloop + endfacet + facet normal 0.900027 -0.409551 -0.149064 + outer loop + vertex -1.861960 0.254356 0.773568 + vertex -1.861960 0.238159 0.818069 + vertex -1.836207 0.296231 0.814007 + endloop + endfacet + facet normal 0.733525 -0.111329 -0.670483 + outer loop + vertex -1.861960 0.238159 0.818069 + vertex -1.832032 0.223009 0.853326 + vertex -1.828352 0.274189 0.848854 + endloop + endfacet + facet normal 0.934059 0.099558 -0.342961 + outer loop + vertex -1.857784 0.181133 0.812886 + vertex -1.861960 0.238159 0.818069 + vertex -1.872164 0.202947 0.780055 + endloop + endfacet + facet normal 0.582926 0.349761 -0.733393 + outer loop + vertex -1.832032 0.223009 0.853326 + vertex -1.857784 0.181133 0.812886 + vertex -1.821248 0.177171 0.840037 + endloop + endfacet + facet normal 0.780924 0.113006 -0.614318 + outer loop + vertex -1.857784 0.181133 0.812886 + vertex -1.832032 0.223009 0.853326 + vertex -1.861960 0.238159 0.818069 + endloop + endfacet + facet normal 0.582938 -0.203490 0.786623 + outer loop + vertex -1.857784 0.207340 0.740883 + vertex -1.832032 0.265413 0.736821 + vertex -1.821248 0.221758 0.717537 + endloop + endfacet + facet normal 0.934059 -0.144185 0.326719 + outer loop + vertex -1.861960 0.254356 0.773568 + vertex -1.857784 0.207340 0.740883 + vertex -1.872164 0.202947 0.780055 + endloop + endfacet + facet normal 0.733523 -0.516261 0.442062 + outer loop + vertex -1.832032 0.265413 0.736821 + vertex -1.861960 0.254356 0.773568 + vertex -1.828352 0.301745 0.773145 + endloop + endfacet + facet normal 0.780922 -0.308308 0.543237 + outer loop + vertex -1.861960 0.254356 0.773568 + vertex -1.832032 0.265413 0.736821 + vertex -1.857784 0.207340 0.740883 + endloop + endfacet + facet normal -0.416389 0.719636 -0.555647 + outer loop + vertex -1.750357 -0.325999 0.817825 + vertex -1.712011 -0.308679 0.811521 + vertex -1.741939 -0.297622 0.848268 + endloop + endfacet + facet normal 0.054303 0.722881 -0.688835 + outer loop + vertex -1.750357 -0.325999 0.817825 + vertex -1.741939 -0.297622 0.848268 + vertex -1.790363 -0.305939 0.835722 + endloop + endfacet + facet normal 0.418187 0.411097 -0.810012 + outer loop + vertex -1.828352 -0.263158 0.837822 + vertex -1.790363 -0.305939 0.835722 + vertex -1.787783 -0.260685 0.860022 + endloop + endfacet + facet normal 0.147422 0.461364 -0.874877 + outer loop + vertex -1.790363 -0.305939 0.835722 + vertex -1.741939 -0.297622 0.848268 + vertex -1.787783 -0.260685 0.860022 + endloop + endfacet + facet normal 0.471918 0.110360 -0.874708 + outer loop + vertex -1.828352 -0.263158 0.837822 + vertex -1.787783 -0.260685 0.860022 + vertex -1.832032 -0.211977 0.842294 + endloop + endfacet + facet normal 0.488865 -0.668645 -0.560290 + outer loop + vertex -1.821248 -0.166140 0.829005 + vertex -1.825276 -0.135904 0.789408 + vertex -1.857784 -0.170101 0.801854 + endloop + endfacet + facet normal 0.901277 -0.416941 -0.117724 + outer loop + vertex -1.872164 -0.191915 0.769023 + vertex -1.857784 -0.170101 0.801854 + vertex -1.855204 -0.151055 0.754151 + endloop + endfacet + facet normal 0.416387 -0.908437 0.036928 + outer loop + vertex -1.816858 -0.133735 0.747847 + vertex -1.855204 -0.151055 0.754151 + vertex -1.825276 -0.135904 0.789408 + endloop + endfacet + facet normal 0.654929 -0.713351 -0.249396 + outer loop + vertex -1.857784 -0.170101 0.801854 + vertex -1.825276 -0.135904 0.789408 + vertex -1.855204 -0.151055 0.754151 + endloop + endfacet + facet normal 0.901277 -0.243725 0.358188 + outer loop + vertex -1.872164 -0.191915 0.769023 + vertex -1.855204 -0.151055 0.754151 + vertex -1.857784 -0.196308 0.729851 + endloop + endfacet + facet normal 0.488876 -0.152067 0.858997 + outer loop + vertex -1.821248 -0.210726 0.706505 + vertex -1.857784 -0.196308 0.729851 + vertex -1.825276 -0.162111 0.717404 + endloop + endfacet + facet normal 0.416390 -0.719640 0.555641 + outer loop + vertex -1.816858 -0.133735 0.747847 + vertex -1.825276 -0.162111 0.717404 + vertex -1.855204 -0.151055 0.754151 + endloop + endfacet + facet normal 0.654934 -0.386148 0.649578 + outer loop + vertex -1.857784 -0.196308 0.729851 + vertex -1.855204 -0.151055 0.754151 + vertex -1.825276 -0.162111 0.717404 + endloop + endfacet + facet normal 0.289382 0.326073 0.899964 + outer loop + vertex -1.821248 -0.210726 0.706505 + vertex -1.783608 -0.256074 0.710832 + vertex -1.832032 -0.254381 0.725790 + endloop + endfacet + facet normal 0.471929 0.646786 0.599125 + outer loop + vertex -1.828352 -0.290714 0.762114 + vertex -1.832032 -0.254381 0.725790 + vertex -1.787783 -0.303089 0.743518 + endloop + endfacet + facet normal 0.005013 0.570513 0.821273 + outer loop + vertex -1.745967 -0.293594 0.736666 + vertex -1.787783 -0.303089 0.743518 + vertex -1.783608 -0.256074 0.710832 + endloop + endfacet + facet normal 0.266493 0.534112 0.802313 + outer loop + vertex -1.832032 -0.254381 0.725790 + vertex -1.783608 -0.256074 0.710832 + vertex -1.787783 -0.303089 0.743518 + endloop + endfacet + facet normal 0.418193 0.835586 0.356245 + outer loop + vertex -1.828352 -0.290714 0.762114 + vertex -1.787783 -0.303089 0.743518 + vertex -1.790363 -0.322136 0.791222 + endloop + endfacet + facet normal 0.054307 0.996534 0.063016 + outer loop + vertex -1.750357 -0.325999 0.817825 + vertex -1.790363 -0.322136 0.791222 + vertex -1.741939 -0.323829 0.776265 + endloop + endfacet + facet normal -0.079078 0.788413 0.610042 + outer loop + vertex -1.745967 -0.293594 0.736666 + vertex -1.741939 -0.323829 0.776265 + vertex -1.787783 -0.303089 0.743518 + endloop + endfacet + facet normal 0.147423 0.915791 0.373623 + outer loop + vertex -1.790363 -0.322136 0.791222 + vertex -1.787783 -0.303089 0.743518 + vertex -1.741939 -0.323829 0.776265 + endloop + endfacet + facet normal -0.416386 0.908438 -0.036925 + outer loop + vertex -1.750357 -0.325999 0.817825 + vertex -1.741939 -0.323829 0.776265 + vertex -1.712011 -0.308679 0.811521 + endloop + endfacet + facet normal 0.629849 0.584398 -0.511634 + outer loop + vertex -1.828352 -0.263158 0.837822 + vertex -1.836207 -0.285199 0.802975 + vertex -1.790363 -0.305939 0.835722 + endloop + endfacet + facet normal 0.303189 0.895462 -0.325921 + outer loop + vertex -1.750357 -0.325999 0.817825 + vertex -1.790363 -0.305939 0.835722 + vertex -1.790363 -0.322136 0.791222 + endloop + endfacet + facet normal 0.629847 0.776549 0.016289 + outer loop + vertex -1.828352 -0.290714 0.762114 + vertex -1.790363 -0.322136 0.791222 + vertex -1.836207 -0.285199 0.802975 + endloop + endfacet + facet normal 0.556288 0.780875 -0.284214 + outer loop + vertex -1.790363 -0.305939 0.835722 + vertex -1.836207 -0.285199 0.802975 + vertex -1.790363 -0.322136 0.791222 + endloop + endfacet + facet normal 0.813501 0.390872 -0.430623 + outer loop + vertex -1.828352 -0.263158 0.837822 + vertex -1.861960 -0.227127 0.807037 + vertex -1.836207 -0.285199 0.802975 + endloop + endfacet + facet normal 0.813501 0.576223 0.078629 + outer loop + vertex -1.828352 -0.290714 0.762114 + vertex -1.836207 -0.285199 0.802975 + vertex -1.861960 -0.243324 0.762536 + endloop + endfacet + facet normal 0.976356 0.203133 -0.073935 + outer loop + vertex -1.872164 -0.191915 0.769023 + vertex -1.861960 -0.243324 0.762536 + vertex -1.861960 -0.227127 0.807037 + endloop + endfacet + facet normal 0.900027 0.409551 -0.149064 + outer loop + vertex -1.836207 -0.285199 0.802975 + vertex -1.861960 -0.227127 0.807037 + vertex -1.861960 -0.243324 0.762536 + endloop + endfacet + facet normal 0.733525 0.111329 -0.670483 + outer loop + vertex -1.828352 -0.263158 0.837822 + vertex -1.832032 -0.211977 0.842294 + vertex -1.861960 -0.227127 0.807037 + endloop + endfacet + facet normal 0.934059 -0.099557 -0.342961 + outer loop + vertex -1.872164 -0.191915 0.769023 + vertex -1.861960 -0.227127 0.807037 + vertex -1.857784 -0.170101 0.801854 + endloop + endfacet + facet normal 0.582925 -0.349761 -0.733393 + outer loop + vertex -1.821248 -0.166140 0.829005 + vertex -1.857784 -0.170101 0.801854 + vertex -1.832032 -0.211977 0.842294 + endloop + endfacet + facet normal 0.780924 -0.113006 -0.614318 + outer loop + vertex -1.861960 -0.227127 0.807037 + vertex -1.832032 -0.211977 0.842294 + vertex -1.857784 -0.170101 0.801854 + endloop + endfacet + facet normal 0.582937 0.203490 0.786623 + outer loop + vertex -1.821248 -0.210726 0.706505 + vertex -1.832032 -0.254381 0.725790 + vertex -1.857784 -0.196308 0.729851 + endloop + endfacet + facet normal 0.934059 0.144185 0.326718 + outer loop + vertex -1.872164 -0.191915 0.769023 + vertex -1.857784 -0.196308 0.729851 + vertex -1.861960 -0.243324 0.762536 + endloop + endfacet + facet normal 0.733523 0.516261 0.442062 + outer loop + vertex -1.828352 -0.290714 0.762114 + vertex -1.861960 -0.243324 0.762536 + vertex -1.832032 -0.254381 0.725790 + endloop + endfacet + facet normal 0.780923 0.308308 0.543237 + outer loop + vertex -1.857784 -0.196308 0.729851 + vertex -1.832032 -0.254381 0.725790 + vertex -1.861960 -0.243324 0.762536 + endloop + endfacet +endsolid NoName_1 diff --git a/test/models/STL/Spider_binary.stl b/test/models/STL/Spider_binary.stl new file mode 100644 index 000000000..3f7daa24d Binary files /dev/null and b/test/models/STL/Spider_binary.stl differ diff --git a/test/models/STL/formatDetection b/test/models/STL/formatDetection new file mode 100644 index 000000000..e2dea2f8a --- /dev/null +++ b/test/models/STL/formatDetection @@ -0,0 +1,9 @@ +solid testTriangle + facet normal 0.0 0.0 1.0 + outer loop + vertex 1.0 1.0 0.0 + vertex -1.0 1.0 0.0 + vertex 0.0 -1.0 0.0 + endloop + endfacet +endsolid \ No newline at end of file diff --git a/test/models/WRL/credits.txt b/test/models/WRL/credits.txt index 6bc4c8329..8024aeb81 100644 --- a/test/models/WRL/credits.txt +++ b/test/models/WRL/credits.txt @@ -1 +1,2 @@ -"MotionCaptureROM.ase" Recorded at the HTW Aalen using LycosIQ. Converted to VRML with 3DS Max 2008. Free for any purpose \ No newline at end of file +"MotionCaptureROM.ase" Recorded using ViconIQ. +Converted to VRML with 3DS Max 2008. diff --git a/test/models/X/TestFormatDetection b/test/models/X/TestFormatDetection new file mode 100644 index 000000000..796714434 --- /dev/null +++ b/test/models/X/TestFormatDetection @@ -0,0 +1,317 @@ +xof 0303txt 0032 + +Frame pCube1 { + FrameTransformMatrix { + 1.000000,0.000000,-0.000000,0.000000,0.000000,1.000000,-0.000000,0.000000,-0.000000,-0.000000,1.000000,0.000000,0.000000,0.000000,-0.000000,1.000000;; + } + Mesh pCubeShape1 { + 24; + -0.820374; -0.680440; -0.820374;, + 0.820374; -0.680440; -0.820374;, + 0.820374; 0.960307; -0.820374;, + -0.820374; 0.960307; -0.820374;, + -0.820374; 0.960307; -0.820374;, + 0.820374; 0.960307; -0.820374;, + 0.820374; 0.960307; 0.820374;, + -0.820374; 0.960307; 0.820374;, + -0.820374; 0.960307; 0.820374;, + 0.820374; 0.960307; 0.820374;, + 0.820374; -0.680440; 0.820374;, + -0.820374; -0.680440; 0.820374;, + -0.820374; -0.680440; 0.820374;, + 0.820374; -0.680440; 0.820374;, + 0.820374; -0.680440; -0.820374;, + -0.820374; -0.680440; -0.820374;, + 0.820374; -0.680440; -0.820374;, + 0.820374; -0.680440; 0.820374;, + 0.820374; 0.960307; 0.820374;, + 0.820374; 0.960307; -0.820374;, + -0.820374; -0.680440; 0.820374;, + -0.820374; -0.680440; -0.820374;, + -0.820374; 0.960307; -0.820374;, + -0.820374; 0.960307; 0.820374;; + 12; + 3;0,3,1;, + 3;1,3,2;, + 3;4,7,5;, + 3;5,7,6;, + 3;8,11,9;, + 3;9,11,10;, + 3;12,15,13;, + 3;13,15,14;, + 3;16,19,17;, + 3;17,19,18;, + 3;20,23,21;, + 3;21,23,22;; + MeshNormals { + 24; + -0.000000;0.000000;-1.000000;, + -0.000000;0.000000;-1.000000;, + -0.000000;0.000000;-1.000000;, + -0.000000;0.000000;-1.000000;, + 0.000000;1.000000;0.000000;, + 0.000000;1.000000;0.000000;, + 0.000000;1.000000;0.000000;, + 0.000000;1.000000;0.000000;, + -0.000000;0.000000;1.000000;, + -0.000000;0.000000;1.000000;, + -0.000000;0.000000;1.000000;, + -0.000000;0.000000;1.000000;, + 0.000000;-1.000000;0.000000;, + 0.000000;-1.000000;0.000000;, + 0.000000;-1.000000;0.000000;, + 0.000000;-1.000000;0.000000;, + 1.000000;-0.000000;-0.000000;, + 1.000000;-0.000000;-0.000000;, + 1.000000;-0.000000;-0.000000;, + 1.000000;-0.000000;-0.000000;, + -1.000000;-0.000000;-0.000000;, + -1.000000;-0.000000;-0.000000;, + -1.000000;-0.000000;-0.000000;, + -1.000000;-0.000000;-0.000000;; + 12; + 3;0,3,1;, + 3;1,3,2;, + 3;4,7,5;, + 3;5,7,6;, + 3;8,11,9;, + 3;9,11,10;, + 3;12,15,13;, + 3;13,15,14;, + 3;16,19,17;, + 3;17,19,18;, + 3;20,23,21;, + 3;21,23,22;; + } + MeshTextureCoords { + 24; + 0.047652;-0.358017;, + 0.280665;-0.358017;, + 0.280665;-0.591031;, + 0.047652;-0.591031;, + 0.006692;-0.252428;, + 0.006692;-0.014798;, + 0.244319;-0.014797;, + 0.244319;-0.252427;, + 0.664454;-0.615566;, + 0.386476;-0.615566;, + 0.386476;-0.337586;, + 0.664454;-0.337586;, + 0.598258;-0.030994;, + 0.598258;-0.252985;, + 0.376269;-0.252985;, + 0.376269;-0.030994;, + 0.047977;-0.707994;, + 0.292494;-0.707994;, + 0.292494;-0.952511;, + 0.047977;-0.952511;, + 0.371893;-0.686273;, + 0.651245;-0.686273;, + 0.651245;-0.965625;, + 0.371893;-0.965625;; + } + MeshMaterialList { + 1; + 12; + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0; + Material { + 0.800000;0.800000;0.800000;1.000000;; + 0.000000; + 0.000000;0.000000;0.000000;; + 0.000000;0.000000;0.000000;; + TextureFileName { + ".\\test.png"; + } + } + } + VertexDuplicationIndices { + 24; + 8; + 0, + 1, + 2, + 3, + 3, + 2, + 6, + 7, + 7, + 6, + 10, + 11, + 11, + 10, + 1, + 0, + 1, + 10, + 6, + 2, + 11, + 0, + 3, + 7; + } + DeclData { + 2; + 2;0;6;0;, + 2;0;7;0;; + 144; + 1065353216, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 1065353216, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 1065353216, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 1065353216, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 3054993143, + 0, + 1065353216, + 3212836864, + 0, + 3054993143, + 3054993142, + 0, + 1065353216, + 3212836864, + 0, + 3054993142, + 3054993141, + 0, + 1065353216, + 3212836864, + 0, + 3054993141, + 3054993142, + 0, + 1065353216, + 3212836864, + 0, + 3054993142, + 3212836864, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 3212836864, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 3212836864, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 3212836864, + 0, + 2147483648, + 0, + 1065353216, + 2147483648, + 3046123087, + 0, + 1065353216, + 1065353216, + 0, + 898639439, + 3037734479, + 0, + 1065353216, + 1065353216, + 0, + 890250831, + 0, + 0, + 1065353216, + 1065353216, + 0, + 2147483648, + 3037734479, + 0, + 1065353216, + 1065353216, + 0, + 890250831, + 0, + 0, + 1065353216, + 2147483648, + 1065353216, + 2147483648, + 0, + 0, + 1065353216, + 2147483648, + 1065353216, + 2147483648, + 0, + 0, + 1065353216, + 2147483648, + 1065353216, + 2147483648, + 0, + 0, + 1065353216, + 2147483648, + 1065353216, + 2147483648, + 0, + 0, + 3212836864, + 0, + 1065353216, + 0, + 0, + 0, + 3212836864, + 0, + 1065353216, + 0, + 0, + 0, + 3212836864, + 0, + 1065353216, + 0, + 0, + 0, + 3212836864, + 0, + 1065353216, + 0; + } + } +} diff --git a/test/models/invalid/empty.md5 b/test/models/invalid/empty.md5mesh similarity index 100% rename from test/models/invalid/empty.md5 rename to test/models/invalid/empty.md5mesh diff --git a/test/unit/utFindDegenerates.cpp b/test/unit/utFindDegenerates.cpp new file mode 100644 index 000000000..11fd47ad8 --- /dev/null +++ b/test/unit/utFindDegenerates.cpp @@ -0,0 +1,92 @@ + +#include "UnitTestPCH.h" +#include "utFindDegenerates.h" + + +CPPUNIT_TEST_SUITE_REGISTRATION (FindDegeneratesProcessTest); + +// ------------------------------------------------------------------------------------------------ +void FindDegeneratesProcessTest :: setUp (void) +{ + mesh = new aiMesh(); + process = new FindDegeneratesProcess(); + + mesh->mNumFaces = 1000; + mesh->mFaces = new aiFace[1000]; + + mesh->mNumVertices = 5000*2; + mesh->mVertices = new aiVector3D[5000*2]; + + for (unsigned int i = 0; i < 5000; ++i) { + mesh->mVertices[i] = mesh->mVertices[i+5000] = aiVector3D((float)i); + } + + mesh->mPrimitiveTypes = aiPrimitiveType_LINE | aiPrimitiveType_POINT | + aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE; + + unsigned int numOut = 0, numFaces = 0; + for (unsigned int i = 0; i < 1000; ++i) { + aiFace& f = mesh->mFaces[i]; + f.mNumIndices = (i % 5)+1; // between 1 and 5 + f.mIndices = new unsigned int[f.mNumIndices]; + bool had = false; + for (unsigned int n = 0; n < f.mNumIndices;++n) { + + // FIXME +#if 0 + // some duplicate indices + if ( n && n == (i / 200)+1) { + f.mIndices[n] = f.mIndices[n-1]; + had = true; + } + // and some duplicate vertices +#endif + if (n && i % 2 && 0 == n % 2) { + f.mIndices[n] = f.mIndices[n-1]+5000; + had = true; + } + else { + f.mIndices[n] = numOut++; + } + } + if (!had) + ++numFaces; + } + mesh->mNumUVComponents[0] = numOut; + mesh->mNumUVComponents[1] = numFaces; +} + +// ------------------------------------------------------------------------------------------------ +void FindDegeneratesProcessTest :: tearDown (void) +{ + delete mesh; + delete process; +} + +// ------------------------------------------------------------------------------------------------ +void FindDegeneratesProcessTest :: testDegeneratesDetection( void ) +{ + process->EnableInstantRemoval(false); + process->ExecuteOnMesh(mesh); + + unsigned int out = 0; + for (unsigned int i = 0; i < 1000; ++i) { + aiFace& f = mesh->mFaces[i]; + out += f.mNumIndices; + } + + CPPUNIT_ASSERT(mesh->mNumFaces == 1000 && mesh->mNumVertices == 10000); + CPPUNIT_ASSERT(mesh->mNumUVComponents[0] == out); + CPPUNIT_ASSERT(mesh->mPrimitiveTypes == (aiPrimitiveType_LINE | aiPrimitiveType_POINT | + aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE)); +} + +// ------------------------------------------------------------------------------------------------ +void FindDegeneratesProcessTest :: testDegeneratesRemoval( void ) +{ + process->EnableInstantRemoval(true); + process->ExecuteOnMesh(mesh); + + CPPUNIT_ASSERT(mesh->mNumUVComponents[1] == mesh->mNumFaces); +} + diff --git a/test/unit/utFindDegenerates.h b/test/unit/utFindDegenerates.h new file mode 100644 index 000000000..a1d05c5fa --- /dev/null +++ b/test/unit/utFindDegenerates.h @@ -0,0 +1,33 @@ +#ifndef TESTDEGENERATES_H +#define TESTDEGENERATES_H + + +#include + +using namespace std; +using namespace Assimp; + +class FindDegeneratesProcessTest : public CPPUNIT_NS :: TestFixture +{ + CPPUNIT_TEST_SUITE (FindDegeneratesProcessTest); + CPPUNIT_TEST (testDegeneratesDetection); + CPPUNIT_TEST (testDegeneratesRemoval); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp (void); + void tearDown (void); + + protected: + + void testDegeneratesDetection (void); + void testDegeneratesRemoval (void); + + private: + + aiMesh* mesh; + FindDegeneratesProcess* process; + +}; + +#endif diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index a54e09d1e..7d819ad83 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -9,7 +9,7 @@ CPPUNIT_TEST_SUITE_REGISTRATION (ImporterTest); bool TestPlugin :: CanRead( const std::string& pFile, - IOSystem* pIOHandler) const + IOSystem* pIOHandler, bool test) const { std::string::size_type pos = pFile.find_last_of('.'); // no file extension - can't read diff --git a/test/unit/utImporter.h b/test/unit/utImporter.h index c935cfe20..57ec0efeb 100644 --- a/test/unit/utImporter.h +++ b/test/unit/utImporter.h @@ -44,7 +44,7 @@ public: // overriden bool CanRead( const std::string& pFile, - IOSystem* pIOHandler) const; + IOSystem* pIOHandler, bool test) const; // overriden void GetExtensionList(std::string& append); diff --git a/test/unit/utPretransformVertices.cpp b/test/unit/utPretransformVertices.cpp index 3e9e49b91..8369f60af 100644 --- a/test/unit/utPretransformVertices.cpp +++ b/test/unit/utPretransformVertices.cpp @@ -1,2 +1,97 @@ -#include "UnitTestPCH.h" \ No newline at end of file +#include "UnitTestPCH.h" +#include "utPretransformVertices.h" + +CPPUNIT_TEST_SUITE_REGISTRATION (PretransformVerticesTest); + +// ------------------------------------------------------------------------------------------------ +void AddNodes(unsigned int num, aiNode* father, unsigned int depth) +{ + father->mChildren = new aiNode*[father->mNumChildren = 5]; + for (unsigned int i = 0; i < 5; ++i) { + aiNode* nd = father->mChildren[i] = new aiNode(); + + nd->mName.length = sprintf(nd->mName.data,"%i%i",depth,i); + + // spawn two meshes + nd->mMeshes = new unsigned int[nd->mNumMeshes = 2]; + nd->mMeshes[0] = num*5+i; + nd->mMeshes[1] = 24-(num*5+i); // mesh 12 is special ... it references the same mesh twice + + // setup an unique transformation matrix + nd->mTransformation.a1 = num*5.f+i + 1; + } + + if (depth > 1) { + for (unsigned int i = 0; i < 5; ++i) + AddNodes(i, father->mChildren[i],depth-1); + } +} + +// ------------------------------------------------------------------------------------------------ +void PretransformVerticesTest :: setUp (void) +{ + scene = new aiScene(); + + // add 5 empty materials + scene->mMaterials = new aiMaterial*[scene->mNumMaterials = 5]; + for (unsigned int i = 0; i < 5;++i) + scene->mMaterials[i] = new MaterialHelper(); + + // add 25 test meshes + scene->mMeshes = new aiMesh*[scene->mNumMeshes = 25]; + for (unsigned int i = 0; i < 25;++i) { + aiMesh* mesh = scene->mMeshes[i] = new aiMesh(); + + mesh->mPrimitiveTypes = aiPrimitiveType_POINT; + mesh->mFaces = new aiFace[ mesh->mNumFaces = 10+i ]; + mesh->mVertices = new aiVector3D[mesh->mNumVertices = mesh->mNumFaces]; + for (unsigned int a = 0; a < mesh->mNumFaces; ++a ) { + aiFace& f = mesh->mFaces[a]; + f.mIndices = new unsigned int [f.mNumIndices = 1]; + f.mIndices[0] = a*3; + + mesh->mVertices[a] = aiVector3D((float)i,(float)a,0.f); + } + mesh->mMaterialIndex = i%5; + + if (i % 2) + mesh->mNormals = new aiVector3D[mesh->mNumVertices]; + } + + // construct some nodes (1+25) + scene->mRootNode = new aiNode(); + scene->mRootNode->mName.Set("Root"); + AddNodes(0,scene->mRootNode,2); + + process = new PretransformVertices(); +} + +// ------------------------------------------------------------------------------------------------ +void PretransformVerticesTest :: tearDown (void) +{ + delete scene; + delete process; +} + + // ------------------------------------------------------------------------------------------------ +void PretransformVerticesTest :: testProcess_CollapseHierarchy (void) +{ + process->KeepHierarchy(false); + process->Execute(scene); + + CPPUNIT_ASSERT(scene->mNumMaterials == 5); + CPPUNIT_ASSERT(scene->mNumMeshes == 10); // every second mesh has normals +} + +// ------------------------------------------------------------------------------------------------ +void PretransformVerticesTest :: testProcess_KeepHierarchy (void) +{ + + process->KeepHierarchy(true); + process->Execute(scene); + + CPPUNIT_ASSERT(scene->mNumMaterials == 5); + CPPUNIT_ASSERT(scene->mNumMeshes == 49); // see note on mesh 12 above + +} \ No newline at end of file diff --git a/test/unit/utPretransformVertices.h b/test/unit/utPretransformVertices.h index e69de29bb..edb95cae9 100644 --- a/test/unit/utPretransformVertices.h +++ b/test/unit/utPretransformVertices.h @@ -0,0 +1,37 @@ +#ifndef TESTLBW_H +#define TESTLBW_H + +#include +#include + +#include +#include + + +using namespace std; +using namespace Assimp; + +class PretransformVerticesTest : public CPPUNIT_NS :: TestFixture +{ + CPPUNIT_TEST_SUITE (PretransformVerticesTest); + CPPUNIT_TEST (testProcess_CollapseHierarchy); + CPPUNIT_TEST (testProcess_KeepHierarchy); + CPPUNIT_TEST_SUITE_END (); + + public: + void setUp (void); + void tearDown (void); + + protected: + + void testProcess_CollapseHierarchy (void); + void testProcess_KeepHierarchy (void); + + + private: + + aiScene* scene; + PretransformVertices* process; +}; + +#endif diff --git a/test/unit/utRemoveRedundantMaterials.cpp b/test/unit/utRemoveRedundantMaterials.cpp index 1c6e7cdf8..e6a10229b 100644 --- a/test/unit/utRemoveRedundantMaterials.cpp +++ b/test/unit/utRemoveRedundantMaterials.cpp @@ -25,7 +25,7 @@ aiMaterial* getUniqueMaterial2() { // setup an unique name for each material - this shouldn't care aiString mTemp; - mTemp.Set("UniqueMat2"); + mTemp.Set("Unique Mat2"); MaterialHelper* pcMat = new MaterialHelper(); pcMat->AddProperty(&mTemp,AI_MATKEY_NAME); @@ -40,7 +40,7 @@ aiMaterial* getUniqueMaterial3() { // setup an unique name for each material - this shouldn't care aiString mTemp; - mTemp.Set("UniqueMat3"); + mTemp.Set("Complex material name"); MaterialHelper* pcMat = new MaterialHelper(); pcMat->AddProperty(&mTemp,AI_MATKEY_NAME); @@ -51,24 +51,23 @@ aiMaterial* getUniqueMaterial3() void RemoveRedundantMatsTest :: setUp (void) { // construct the process - this->piProcess = new RemoveRedundantMatsProcess(); + piProcess = new RemoveRedundantMatsProcess(); // create a scene with 5 materials (2 is a duplicate of 0, 3 of 1) - this->pcScene1 = new aiScene(); - this->pcScene1->mNumMaterials = 5; - this->pcScene1->mMaterials = new aiMaterial*[5]; + pcScene1 = new aiScene(); + pcScene1->mNumMaterials = 5; + pcScene1->mMaterials = new aiMaterial*[5]; - this->pcScene1->mMaterials[0] = getUniqueMaterial1(); - this->pcScene1->mMaterials[1] = getUniqueMaterial2(); - this->pcScene1->mMaterials[4] = getUniqueMaterial3(); + pcScene1->mMaterials[0] = getUniqueMaterial1(); + pcScene1->mMaterials[1] = getUniqueMaterial2(); + pcScene1->mMaterials[4] = getUniqueMaterial3(); // all materials must be referenced - this->pcScene1->mNumMeshes = 5; - this->pcScene1->mMeshes = new aiMesh*[5]; - for (unsigned int i = 0; i < 5;++i) - { - this->pcScene1->mMeshes[i] = new aiMesh(); - this->pcScene1->mMeshes[i]->mMaterialIndex = i; + pcScene1->mNumMeshes = 5; + pcScene1->mMeshes = new aiMesh*[5]; + for (unsigned int i = 0; i < 5;++i) { + pcScene1->mMeshes[i] = new aiMesh(); + pcScene1->mMeshes[i]->mMaterialIndex = i; } // setup an unique name for each material - this shouldn't care @@ -78,13 +77,13 @@ void RemoveRedundantMatsTest :: setUp (void) mTemp.data[1] = 0; MaterialHelper* pcMat; - this->pcScene1->mMaterials[2] = pcMat = new MaterialHelper(); - MaterialHelper::CopyPropertyList(pcMat,(const MaterialHelper*)this->pcScene1->mMaterials[0]); + pcScene1->mMaterials[2] = pcMat = new MaterialHelper(); + MaterialHelper::CopyPropertyList(pcMat,(const MaterialHelper*)pcScene1->mMaterials[0]); pcMat->AddProperty(&mTemp,AI_MATKEY_NAME); mTemp.data[0]++; - this->pcScene1->mMaterials[3] = pcMat = new MaterialHelper(); - MaterialHelper::CopyPropertyList(pcMat,(const MaterialHelper*)this->pcScene1->mMaterials[1]); + pcScene1->mMaterials[3] = pcMat = new MaterialHelper(); + MaterialHelper::CopyPropertyList(pcMat,(const MaterialHelper*)pcScene1->mMaterials[1]); pcMat->AddProperty(&mTemp,AI_MATKEY_NAME); mTemp.data[0]++; } @@ -92,24 +91,42 @@ void RemoveRedundantMatsTest :: setUp (void) // ------------------------------------------------------------------------------------------------ void RemoveRedundantMatsTest :: tearDown (void) { - delete this->piProcess; - delete this->pcScene1; + delete piProcess; + delete pcScene1; } // ------------------------------------------------------------------------------------------------ void RemoveRedundantMatsTest :: testRedundantMaterials (void) { - this->piProcess->Execute(this->pcScene1); - CPPUNIT_ASSERT_EQUAL(this->pcScene1->mNumMaterials,3u); - CPPUNIT_ASSERT(0 != this->pcScene1->mMaterials && - 0 != this->pcScene1->mMaterials[0] && - 0 != this->pcScene1->mMaterials[1] && - 0 != this->pcScene1->mMaterials[2]); + piProcess->SetFixedMaterialsString(); + + piProcess->Execute(pcScene1); + CPPUNIT_ASSERT_EQUAL(pcScene1->mNumMaterials,3u); + CPPUNIT_ASSERT(0 != pcScene1->mMaterials && + 0 != pcScene1->mMaterials[0] && + 0 != pcScene1->mMaterials[1] && + 0 != pcScene1->mMaterials[2]); aiString sName; - CPPUNIT_ASSERT(AI_SUCCESS == aiGetMaterialString(this->pcScene1->mMaterials[2], - AI_MATKEY_NAME,&sName)); - - CPPUNIT_ASSERT(!::strcmp( sName.data, "UniqueMat3" )); + CPPUNIT_ASSERT(AI_SUCCESS == aiGetMaterialString(pcScene1->mMaterials[2],AI_MATKEY_NAME,&sName)); + CPPUNIT_ASSERT(!::strcmp( sName.data, "Complex material name" )); } + +// ------------------------------------------------------------------------------------------------ +void RemoveRedundantMatsTest :: testRedundantMaterialsWithExcludeList (void) +{ + piProcess->SetFixedMaterialsString("\'Unique Mat2\'\t\'Complex material name\' and_another_one_which_we_wont_use"); + + piProcess->Execute(pcScene1); + CPPUNIT_ASSERT_EQUAL(pcScene1->mNumMaterials,4u); + CPPUNIT_ASSERT(0 != pcScene1->mMaterials && + 0 != pcScene1->mMaterials[0] && + 0 != pcScene1->mMaterials[1] && + 0 != pcScene1->mMaterials[2] && + 0 != pcScene1->mMaterials[3]); + + aiString sName; + CPPUNIT_ASSERT(AI_SUCCESS == aiGetMaterialString(pcScene1->mMaterials[3],AI_MATKEY_NAME,&sName)); + CPPUNIT_ASSERT(!::strcmp( sName.data, "Complex material name" )); +} diff --git a/test/unit/utRemoveRedundantMaterials.h b/test/unit/utRemoveRedundantMaterials.h index fb9e508af..b0b310669 100644 --- a/test/unit/utRemoveRedundantMaterials.h +++ b/test/unit/utRemoveRedundantMaterials.h @@ -17,6 +17,7 @@ class RemoveRedundantMatsTest : public CPPUNIT_NS :: TestFixture { CPPUNIT_TEST_SUITE (RemoveRedundantMatsTest); CPPUNIT_TEST (testRedundantMaterials); + CPPUNIT_TEST (testRedundantMaterialsWithExcludeList); CPPUNIT_TEST_SUITE_END (); public: @@ -26,7 +27,7 @@ class RemoveRedundantMatsTest : public CPPUNIT_NS :: TestFixture protected: void testRedundantMaterials (void); - + void testRedundantMaterialsWithExcludeList (void); private: diff --git a/tools/assimp_cmd/CompareDump.cpp b/tools/assimp_cmd/CompareDump.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/tools/assimp_cmd/ImageExtractor.cpp b/tools/assimp_cmd/ImageExtractor.cpp new file mode 100644 index 000000000..464098e33 --- /dev/null +++ b/tools/assimp_cmd/ImageExtractor.cpp @@ -0,0 +1,360 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file ImageExtractor.cpp + * @brief Implementation of the 'assimp extract' utility + */ + +#include "Main.h" + +const char* AICMD_MSG_DUMP_HELP_E = +"todo assimp extract help"; + + +#define AI_EXTRACT_WRITE_BMP_ALPHA 0x1 + +#include "Compiler/pushpack1.h" + +// ----------------------------------------------------------------------------------- +// Data structure for the first header of a BMP +struct BITMAPFILEHEADER +{ + uint16_t bfType ; + uint32_t bfSize; + uint16_t bfReserved1 ; + uint16_t bfReserved2; + uint32_t bfOffBits; +} PACK_STRUCT; + +// ----------------------------------------------------------------------------------- +// Data structure for the second header of a BMP +struct BITMAPINFOHEADER +{ + int32_t biSize; + int32_t biWidth; + int32_t biHeight; + int16_t biPlanes; + int16_t biBitCount; + uint32_t biCompression; + int32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + int32_t biClrUsed; + int32_t biClrImportant; + + // pixel data follows header +} PACK_STRUCT; + +// ----------------------------------------------------------------------------------- +// Data structure for the header of a TGA +struct TGA_HEADER +{ + uint8_t identsize; // size of ID field that follows 18 byte header (0 usually) + uint8_t colourmaptype; // type of colour map 0=none, 1=has palette + uint8_t imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + uint16_t colourmapstart; // first colour map entry in palette + uint16_t colourmaplength; // number of colours in palette + uint8_t colourmapbits; // number of bits per palette entry 15,16,24,32 + + uint16_t xstart; // image x origin + uint16_t ystart; // image y origin + uint16_t width; // image width in pixels + uint16_t height; // image height in pixels + uint8_t bits; // image bits per pixel 8,16,24,32 + uint8_t descriptor; // image descriptor bits (vh flip bits) + + // pixel data follows header +} PACK_STRUCT; + + +#include "Compiler/poppack1.h" + +// ----------------------------------------------------------------------------------- +// Save a texture as bitmap +int SaveAsBMP (FILE* file, const aiTexel* data, unsigned int width, unsigned int height, bool SaveAlpha = false) +{ + if (!file || !data)return 1; + + const unsigned int numc = (SaveAlpha ? 4 : 3); + unsigned char* buffer = new unsigned char[width*height*numc]; + + for (unsigned int y = 0; y < height; ++y) { + for (unsigned int x = 0; x < width; ++x) { + + unsigned char* s = &buffer[(y*width+x) * numc]; + const aiTexel* t = &data [ y*width+x]; + s[0] = t->b; + s[1] = t->g; + s[2] = t->r; + if (4 == numc) + s[3] = t->a; + } + } + + BITMAPFILEHEADER header; + header.bfType = 'MB'; + header.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); + header.bfSize = header.bfOffBits+width*height*numc; + header.bfReserved1 = header.bfReserved2 = 0; + + ::fwrite(&header,sizeof(BITMAPFILEHEADER),1,file); + + BITMAPINFOHEADER info; + info.biSize = 40; + info.biWidth = width; + info.biHeight = height; + info.biPlanes = 1; + info.biBitCount = numc<<3; + info.biCompression = 0; + info.biSizeImage = width*height*numc; + info.biXPelsPerMeter = 1; // dummy + info.biYPelsPerMeter = 1; // dummy + info.biClrUsed = 0; + info.biClrImportant = 0; + + ::fwrite(&info,sizeof(BITMAPINFOHEADER),1,file); + + unsigned char* temp = buffer+info.biSizeImage; + const unsigned int row = width*numc; + + for (int y = 0; temp -= row,y < info.biHeight;++y) { + ::fwrite(temp,row,1,file); + } + + // delete the buffer + delete[] buffer; + return 0; +} + +// ----------------------------------------------------------------------------------- +// Save a texture as tga +int SaveAsTGA (FILE* file, const aiTexel* data, unsigned int width, unsigned int height) +{ + if (!file || !data)return 1; + + + TGA_HEADER head = {0}; + head.bits = 32; + head.height = (uint16_t)height; + head.width = (uint16_t)width; + head.descriptor |= (1u<<5); + + head.imagetype = 2; // actually it's RGBA + ::fwrite(&head,sizeof(TGA_HEADER),1,file); + + for (unsigned int y = 0; y < height; ++y) { + for (unsigned int x = 0; x < width; ++x) { + ::fwrite(data + y*width+x,4,1,file); + } + } + + return 0; +} + +// ----------------------------------------------------------------------------------- +// Do the texture import for a given aiTexture +int DoExport(const aiTexture* tx, FILE* p, const std::string& extension, + unsigned int flags) +{ + // export the image to the appropriate decoder + if (extension == "bmp") { + SaveAsBMP(p,tx->pcData,tx->mWidth,tx->mHeight, + (0 != (flags & AI_EXTRACT_WRITE_BMP_ALPHA))); + } + else if (extension == "tga") { + SaveAsTGA(p,tx->pcData,tx->mWidth,tx->mHeight); + } + else { + printf("assimp extract: No available texture encoder found for %s\n", extension.c_str()); + return 1; + } + return 0; +} + +// ----------------------------------------------------------------------------------- +// Implementation of the assimp extract utility +int Assimp_Extract (const char** params, unsigned int num) +{ + if (num < 1) { + printf("assimp extract: Invalid number of arguments. See \'assimp extract --help\'\n"); + return 1; + } + + // --help + if (!::strcmp( params[0], "-h") || !::strcmp( params[0], "--help") || !::strcmp( params[0], "-?") ) { + printf(AICMD_MSG_DUMP_HELP_E); + return 0; + } + + // asssimp extract in out [options] + if (num < 1) { + printf("assimp extract: Invalid number of arguments. See \'assimp dump --help\'\n"); + return 1; + } + + std::string in = std::string(params[0]); + std::string out = (num > 1 ? std::string(params[1]) : "-"); + + // get import flags + ImportData import; + ProcessStandardArguments(import,params+1,num-1); + + bool nosuffix = false; + unsigned int texIdx = 0xffffffff, flags = 0; + + // process other flags + std::string extension = "bmp"; + for (unsigned int i = (out[0] == '-' ? 1 : 2); i < num;++i) { + if (!params[i])continue; + + if (!::strncmp( params[i], "-f",2)) { + extension = std::string(params[i]+2); + } + else if ( !::strncmp( params[i], "--format=",9)) { + extension = std::string(params[i]+9); + } + else if ( !::strcmp( params[i], "--nosuffix") || !::strcmp(params[i],"-s")) { + nosuffix = true; + } + else if ( !::strncmp( params[i], "--texture=",10)) { + texIdx = ::strtol10(params[i]+10); + } + else if ( !::strncmp( params[i], "-t",2)) { + texIdx = ::strtol10(params[i]+2); + } + else if ( !::strcmp( params[i], "-ba") || !::strcmp( params[i], "--bmp-with-alpha")) { + flags |= AI_EXTRACT_WRITE_BMP_ALPHA; + } + else { + printf("Unknown parameter: %s\n",params[i]); + return 10; + } + } + for (std::string::iterator it = extension.begin();it != extension.end();++it) + *it = ::tolower(*it); + + if (out[0] == '-') { + // take file name from input file + std::string::size_type s = in.find_last_of('.'); + if (s == std::string::npos) + s = in.length(); + + out = in.substr(0,s); + } + + // take file extension from file name, if given + std::string::size_type s = out.find_last_of('.'); + if (s != std::string::npos) { + extension = out.substr(s+1,in.length()-(s+1)); + out = out.substr(0,s); + } + + // import the main model + const aiScene* scene = ImportModel(import,in); + if (!scene) { + printf("assimp extract: Unable to load input file %s\n",in.c_str()); + return 5; + } + + // get the texture(s) to be exported + if (texIdx != 0xffffffff) { + + // check whether the requested texture is existing + if (texIdx >= scene->mNumTextures) { + ::printf("assimp extract: Texture %i requested, but there are just %i textures\n", + texIdx, scene->mNumTextures); + return 6; + } + } + else { + ::printf("assimp extract: Exporting %i textures\n",scene->mNumTextures); + } + + // now write all output textures + for (unsigned int i = 0; i < scene->mNumTextures;++i) + { + if (texIdx != 0xffffffff && texIdx != i) + continue; + + const aiTexture* tex = scene->mTextures[i]; + std::string out_cpy = out, out_ext = extension; + + // append suffix if necessary - always if all textures are exported + if (!nosuffix || (texIdx == 0xffffffff)) { + out_cpy.append ("_img"); + char tmp[10]; + ASSIMP_itoa10(tmp,i); + + out_cpy.append(std::string(tmp)); + } + + // if the texture is a compressed one, we'll export + // it to its native file format + if (!tex->mHeight) { + printf("assimp extract: Texture %i is compressed (%s). Writing native file format.\n", + i,tex->achFormatHint); + + // modify file extension + out_ext = std::string(tex->achFormatHint); + } + out_cpy.append("."+out_ext); + + // open output file + FILE* p = ::fopen(out_cpy.c_str(),"wb"); + if (!p) { + printf("assimp extract: Unable to open output file %s\n",out_cpy.c_str()); + return 7; + } + int m; + + if (!tex->mHeight) { + m = (1 != ::fwrite(tex->pcData,tex->mWidth,1,p)); + } + else m = DoExport(tex,p,extension,flags); + ::fclose(p); + + printf("assimp extract: Wrote texture %i to %s\n",i, out_cpy.c_str()); + if (texIdx != 0xffffffff) + return m; + } + return 0; +} \ No newline at end of file diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp new file mode 100644 index 000000000..ede8945dd --- /dev/null +++ b/tools/assimp_cmd/Main.cpp @@ -0,0 +1,308 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file Main.cpp + * @brief main() function of assimp_cmd + */ + +#include "Main.h" + +const char* AICMD_MSG_ABOUT = +"------------------------------------------------------ \n" +"Open Asset Import Library (Assimp) \n" +"Command-line tools \n" +"------------------------------------------------------ \n\n" + +"Major version: %i\n" +"Minor version: %i\n" +"SVN revision : %i\n" +"Build flags : %s %s %s %s %s\n\n"; + + +const char* AICMD_MSG_HELP = +"todo help"; + + +/*extern*/ Assimp::Importer* globalImporter = NULL; + +// ------------------------------------------------------------------------------ +// Application entry point +int main (int argc, char* argv[]) +{ + if (argc <= 1) { + + printf("assimp: No command specified. Use \'assimp help\' for a detailed command list\n"); + return 0; + } + + // assimp version + // Display a version string + if (! ::strcmp(argv[1], "version")) { + + const unsigned int flags = aiGetCompileFlags(); + printf(AICMD_MSG_ABOUT, + aiGetVersionMajor(), + aiGetVersionMinor(), + aiGetVersionRevision(), + (flags & ASSIMP_CFLAGS_DEBUG ? "-debug" : ""), + (flags & ASSIMP_CFLAGS_NOBOOST ? "-noboost" : ""), + (flags & ASSIMP_CFLAGS_SHARED ? "-shared" : ""), + (flags & ASSIMP_CFLAGS_SINGLETHREADED ? "-st" : ""), + (flags & ASSIMP_CFLAGS_STLPORT ? "-stlport" : "")); + + return 0; + } + + // assimp help + // Display some basic help + if (! ::strcmp(argv[1], "help")) { + + printf(AICMD_MSG_HELP); + return 0; + } + + // construct a global Assimp::Importer instance + Assimp::Importer imp; + globalImporter = &imp; + + // assimp dump + // Dump a model to a file + if (! ::strcmp(argv[1], "dump")) { + return Assimp_Dump ((const char**)&argv[2],argc-2); + } + + // assimp extract + // Extract an embedded texture from a file + if (! ::strcmp(argv[1], "extract")) { + return Assimp_Extract ((const char**)&argv[2],argc-2); + } + + ::printf("Unrecognized command. Use \'assimp help\' for a detailed command list\n"); + return 1; +} + +// ------------------------------------------------------------------------------ +// Import a specific file +const aiScene* ImportModel(const ImportData& imp, const std::string& path) +{ + // Attach log streams + if (imp.log) { + ::printf("\nAttaching log stream ... OK\n"); + + unsigned int flags = 0; + if (imp.logFile.length()) + flags |= DLS_FILE; + if (imp.showLog) + flags |= DLS_CERR; + + DefaultLogger::create(imp.logFile.c_str(),imp.verbose ? Logger::VERBOSE : Logger::NORMAL,flags); + } + ::printf("Launching model import ... OK\n"); + + // Now validate this flag combination + if(!globalImporter->ValidateFlags(imp.ppFlags)) { + ::printf("ERROR: Unsupported post-processing flags \n"); + return NULL; + } + ::printf("Validating postprocessing flags ... OK\n"); + if (imp.showLog) + ::printf("-----------------------------------------------------------------\n"); + + // do the actual import, measure time + const clock_t first = ::clock(); + const aiScene* scene = globalImporter->ReadFile(path,imp.ppFlags); + + if (imp.showLog) + ::printf("-----------------------------------------------------------------\n"); + + if (!scene) { + printf("ERROR: Failed to load file\n"); + return NULL; + } + + const clock_t second = ::clock(); + const float seconds = (float)(second-first) / CLOCKS_PER_SEC; + + ::printf("Importing file ... OK \n import took approx. %.5f seconds\n" + "\n",seconds); + + if (imp.log) { + DefaultLogger::kill(); + } + return scene; +} + +// ------------------------------------------------------------------------------ +// Process standard arguments +int ProcessStandardArguments(ImportData& fill, const char** params, + unsigned int num) +{ + // -ptv --pretransform-vertices + // -gsn --gen-smooth-normals + // -gn --gen-normals + // -cts --calc-tangent-space + // -jiv --join-identical-vertices + // -rrm --remove-redundant-materials + // -fd --find-degenerates + // -slm --split-large-meshes + // -lbw --limit-bone-weights + // -vds --validate-data-structure + // -icl --improve-cache-locality + // -sbpt --sort-by-ptype + // -lh --convert-to-lh + // -fuv --flip-uv + // -fwo --flip-winding-order + // -ett --evaluate-texture-transform + // -guv --gen-uvcoords + // -fid --find-invalid-data + // -fixn --fix normals + // -tri --triangulate + // -fi --find-instances + // + // -c --config-file= + + for (unsigned int i = 0; i < num;++i) + { + if (!params[i]) { // could happen if some args have already been processed + continue; + } + + bool has = true; + if (! ::strcmp(params[i], "-ptv") || ! ::strcmp(params[i], "--pretransform-vertices")) { + fill.ppFlags |= aiProcess_PreTransformVertices; + } + else if (! ::strcmp(params[i], "-gsn") || ! ::strcmp(params[i], "--gen-smooth-normals")) { + fill.ppFlags |= aiProcess_GenSmoothNormals; + } + else if (! ::strcmp(params[i], "-gn") || ! ::strcmp(params[i], "--gen-normals")) { + fill.ppFlags |= aiProcess_GenNormals; + } + else if (! ::strcmp(params[i], "-jiv") || ! ::strcmp(params[i], "--join-identical-vertices")) { + fill.ppFlags |= aiProcess_JoinIdenticalVertices; + } + else if (! ::strcmp(params[i], "-rrm") || ! ::strcmp(params[i], "--remove-redundant-materials")) { + fill.ppFlags |= aiProcess_RemoveRedundantMaterials; + } + else if (! ::strcmp(params[i], "-fd") || ! ::strcmp(params[i], "--find-degenerates")) { + fill.ppFlags |= aiProcess_FindDegenerates; + } + else if (! ::strcmp(params[i], "-slm") || ! ::strcmp(params[i], "--split-large-meshes")) { + fill.ppFlags |= aiProcess_SplitLargeMeshes; + } + else if (! ::strcmp(params[i], "-lbw") || ! ::strcmp(params[i], "--limit-bone-weights")) { + fill.ppFlags |= aiProcess_LimitBoneWeights; + } + else if (! ::strcmp(params[i], "-vds") || ! ::strcmp(params[i], "--validate-data-structure")) { + fill.ppFlags |= aiProcess_ValidateDataStructure; + } + else if (! ::strcmp(params[i], "-icl") || ! ::strcmp(params[i], "--improve-cache-locality")) { + fill.ppFlags |= aiProcess_ImproveCacheLocality; + } + else if (! ::strcmp(params[i], "-sbpt") || ! ::strcmp(params[i], "--sort-by-ptype")) { + fill.ppFlags |= aiProcess_SortByPType; + } + else if (! ::strcmp(params[i], "-lh") || ! ::strcmp(params[i], "--left-handed")) { + fill.ppFlags |= aiProcess_ConvertToLeftHanded; + } + else if (! ::strcmp(params[i], "-fuv") || ! ::strcmp(params[i], "--flip-uv")) { + fill.ppFlags |= aiProcess_ConvertToLeftHanded; + } + else if (! ::strcmp(params[i], "-fwo") || ! ::strcmp(params[i], "--flip-winding-order")) { + fill.ppFlags |= aiProcess_ConvertToLeftHanded; + } + else if (! ::strcmp(params[i], "-ett") || ! ::strcmp(params[i], "--evaluate-texture-transform")) { + fill.ppFlags |= aiProcess_TransformUVCoords; + } + else if (! ::strcmp(params[i], "-guv") || ! ::strcmp(params[i], "--gen-uvcoords")) { + fill.ppFlags |= aiProcess_GenUVCoords; + } + else if (! ::strcmp(params[i], "-fid") || ! ::strcmp(params[i], "--find-invalid-data")) { + fill.ppFlags |= aiProcess_FindInvalidData; + } + else if (! ::strcmp(params[i], "-fixn") || ! ::strcmp(params[i], "--fix-normals")) { + fill.ppFlags |= aiProcess_FixInfacingNormals; + } + else if (! ::strcmp(params[i], "-tri") || ! ::strcmp(params[i], "--triangulate")) { + fill.ppFlags |= aiProcess_Triangulate; + } + else if (! ::strcmp(params[i], "-cts") || ! ::strcmp(params[i], "--calc-tangent-space")) { + fill.ppFlags |= aiProcess_CalcTangentSpace; + } + else if (! ::strcmp(params[i], "-fi") || ! ::strcmp(params[i], "--find-instances")) { + fill.ppFlags |= aiProcess_FindInstances; + } + else if (! ::strncmp(params[i], "-c",2) || ! ::strncmp(params[i], "--config=",9)) { + + const unsigned int ofs = (params[i][1] == '-' ? 9 : 2); + + // use default configurations + if (! ::strncmp(params[i]+ofs,"full",4)) + fill.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality; + + else if (! ::strncmp(params[i]+ofs,"default",7)) + fill.ppFlags |= aiProcessPreset_TargetRealtime_Quality; + + else if (! ::strncmp(params[i]+ofs,"fast",4)) + fill.ppFlags |= aiProcessPreset_TargetRealtime_Fast; + } + else if (! ::strcmp(params[i], "-l") || ! ::strcmp(params[i], "--show-log")) { + fill.showLog = true; + } + else if (! ::strcmp(params[i], "-v") || ! ::strcmp(params[i], "--verbose")) { + fill.verbose = true; + } + else if (! ::strncmp(params[i], "--log-out=",10) || ! ::strncmp(params[i], "-lo",3)) { + fill.logFile = std::string(params[i]+(params[i][1] == '-' ? 10 : 3)); + if (!fill.logFile.length()) + fill.logFile = "assimp-log.txt"; + } + + else has = false; + if (has) { + params[i] = NULL; + } + } + + if (fill.logFile.length() || fill.showLog || fill.verbose) + fill.log = true; + + return 0; +} \ No newline at end of file diff --git a/tools/assimp_cmd/Main.h b/tools/assimp_cmd/Main.h new file mode 100644 index 000000000..b749e81ab --- /dev/null +++ b/tools/assimp_cmd/Main.h @@ -0,0 +1,137 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file Main.h + * @brief Utility declarations for assimp_cmd + */ + +#ifndef AICMD_MAIN_INCLUDED +#define AICMD_MAIN_INCLUDED + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include <../code/fast_atof.h> +#include <../code/StringComparison.h> +#include <../code/Hash.h> + +#include <../contrib/zlib/zlib.h> + +using namespace Assimp; + +// Global assimp importer instance +extern Assimp::Importer* globalImporter; + +// ------------------------------------------------------------------------------ +/** @brief Defines common import parameters + */ +struct ImportData +{ + ImportData() + : ppFlags (0) + , showLog (false) + , verbose (false) + , log (false) + {} + + /** Postprocessing flags + */ + unsigned int ppFlags; + + + // Log to std::err? + bool showLog; + + // Log file + std::string logFile; + + // Verbose log mode? + bool verbose; + + // Need to log? + bool log; +}; + +// ------------------------------------------------------------------------------ +/** @brief Process standard arguments + * + * @param fill Filled by function + * @param params Command line parameters to be processed + * @param num NUmber of params + * @return 0 for success + */ +int ProcessStandardArguments(ImportData& fill, const char** params, + unsigned int num); + +// ------------------------------------------------------------------------------ +/** @brief Import a specific model file + * @param imp Import configuration to be used + * @param path Path to the file to be opened + */ +const aiScene* ImportModel(const ImportData& imp, const std::string& path); + + +// ------------------------------------------------------------------------------ +/** @brief assimp_dump utility + * @param params Command line parameters to 'assimp dumb' + * @param Number of params + * @return 0 for success + */ +int Assimp_Dump (const char** params, unsigned int num); + +// ------------------------------------------------------------------------------ +/** @brief assimp_extract utility + * @param params Command line parameters to 'assimp extract' + * @param Number of params + * @return 0 for success + */ +int Assimp_Extract (const char** params, unsigned int num); + +#endif // !! AICMD_MAIN_INCLUDED \ No newline at end of file diff --git a/tools/assimp_cmd/WriteDumb.cpp b/tools/assimp_cmd/WriteDumb.cpp new file mode 100644 index 000000000..78b674efd --- /dev/null +++ b/tools/assimp_cmd/WriteDumb.cpp @@ -0,0 +1,1024 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (ASSIMP) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2008, ASSIMP Development Team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the ASSIMP team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the ASSIMP Development Team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file WriteTextDumb.cpp + * @brief Implementation of the 'assimp dump' utility + */ + +#include "Main.h" +#include "../code/ProcessHelper.h" + +const char* AICMD_MSG_DUMP_HELP = +"todo assimp dumb help"; + +// ----------------------------------------------------------------------------------- +// Compress a binary dump file (beginning at offset head_size) +void CompressBinaryDump(const char* file, unsigned int head_size) +{ + // for simplicity ... copy the file into memory again and compress it there + FILE* p = ::fopen(file,"r"); + ::fseek(p,0,SEEK_END); + const unsigned int size = (unsigned int)::ftell(p); + ::fseek(p,0,SEEK_SET); + + if (sizemName,out); + WriteMat4x4(node->mTransformation,out); + + WriteInteger(node->mNumMeshes,out); + for (unsigned int i = 0; i < node->mNumMeshes;++i) + WriteInteger(node->mMeshes[i],out); + + WriteInteger(node->mNumChildren,out); + for (unsigned int i = 0; i < node->mNumChildren;++i) + WriteBinaryNode(node->mChildren[i],out); +} + +// ----------------------------------------------------------------------------------- +// Write the min/max values of an array of Ts to the file +template +inline void WriteBounds(const T* in, unsigned int size, FILE* out) +{ + T minc,maxc; + ArrayBounds(in,size,minc,maxc); + ::fwrite(&minc,sizeof(T),1,out); + ::fwrite(&maxc,sizeof(T),1,out); +} + +// ----------------------------------------------------------------------------------- +// Write a binary model dump +void WriteBinaryDump(const aiScene* scene, FILE* out, const char* src, const char* cmd, + bool shortened, bool compressed, ImportData& imp) +{ + time_t tt = ::time(NULL); + tm* p = ::gmtime(&tt); + + // header + ::fprintf(out,"ASSIMP.binary-dump.%s.",::asctime(p)); + // == 45 bytes + + WriteInteger(aiGetVersionMajor(),out); + WriteInteger(aiGetVersionMinor(),out); + WriteInteger(aiGetVersionRevision(),out); + WriteInteger(aiGetCompileFlags(),out); + WriteShort(shortened,out); + WriteShort(compressed,out); + // == 20 bytes + + char buff[256]; + ::strncpy(buff,src,256); + ::fwrite(buff,256,1,out); + + ::strncpy(buff,cmd,128); + ::fwrite(buff,128,1,out); + + // leave 41 bytes free for future extensions + ::memset(buff,0xcd,41); + ::fwrite(buff,32,1,out); + // == 435 bytes + + // ==== total header size: 500 bytes + // Up to here the data is uncompressed. For compressed files, the rest + // is compressed using standard DEFLATE from zlib. + + // basic scene information + WriteInteger(scene->mFlags,out); + WriteInteger(scene->mNumAnimations,out); + WriteInteger(scene->mNumTextures,out); + WriteInteger(scene->mNumMaterials,out); + WriteInteger(scene->mNumCameras,out); + WriteInteger(scene->mNumLights,out); + WriteInteger(scene->mNumMeshes,out); + + // write node graph + WriteBinaryNode(scene->mRootNode,out); + + // write materials + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + + WriteMagic("#MA",out); + WriteInteger(mat->mNumProperties,out); + + for (unsigned int a = 0; a < mat->mNumProperties;++a) { + const aiMaterialProperty* prop = mat->mProperties[a]; + + WriteMagic("#MP",out); + WriteAiString(prop->mKey,out); + WriteInteger(prop->mSemantic,out); + WriteInteger(prop->mIndex,out); + + WriteInteger(prop->mDataLength,out); + ::fwrite(prop->mData,prop->mDataLength,1,out); + } + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + const aiCamera* cam = scene->mCameras[i]; + + WriteMagic("#CA",out); + WriteAiString(cam->mName,out); + WriteVec3(cam->mPosition,out); + WriteVec3(cam->mLookAt,out); + WriteVec3(cam->mUp,out); + WriteFloat(cam->mClipPlaneNear,out); + WriteFloat(cam->mClipPlaneFar,out); + WriteFloat(cam->mHorizontalFOV,out); + WriteFloat(cam->mAspect,out); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + const aiLight* l = scene->mLights[i]; + + WriteMagic("#LI",out); + WriteAiString(l->mName,out); + WriteInteger(l->mType,out); + + WriteVec3((const aiVector3D&)l->mColorDiffuse,out); + WriteVec3((const aiVector3D&)l->mColorSpecular,out); + WriteVec3((const aiVector3D&)l->mColorAmbient,out); + + if (l->mType != aiLightSource_DIRECTIONAL) { + WriteVec3(l->mPosition,out); + WriteFloat(l->mAttenuationLinear,out); + WriteFloat(l->mAttenuationConstant,out); + WriteFloat(l->mAttenuationQuadratic,out); + } + + if (l->mType != aiLightSource_POINT) { + WriteVec3(l->mDirection,out); + } + + if (l->mType == aiLightSource_SPOT) { + WriteFloat(l->mAttenuationConstant,out); + WriteFloat(l->mAttenuationQuadratic,out); + } + } + + // write all animations + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + const aiAnimation* anim = scene->mAnimations[i]; + + WriteMagic("#AN",out); + WriteAiString (anim->mName,out); + WriteDouble (anim->mTicksPerSecond,out); + WriteDouble (anim->mDuration,out); + WriteInteger(anim->mNumChannels,out); + + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + const aiNodeAnim* nd = anim->mChannels[a]; + + WriteMagic("#NA",out); + WriteAiString(nd->mNodeName,out); + WriteInteger(nd->mPreState,out); + WriteInteger(nd->mPostState,out); + WriteInteger(nd->mNumPositionKeys,out); + WriteInteger(nd->mNumRotationKeys,out); + WriteInteger(nd->mNumScalingKeys,out); + + if (nd->mPositionKeys) { + if (shortened) { + WriteBounds(nd->mPositionKeys,nd->mNumPositionKeys,out); + + } // else write as usual + else ::fwrite(nd->mPositionKeys,sizeof(aiVectorKey),nd->mNumPositionKeys,out); + } + if (nd->mRotationKeys) { + if (shortened) { + WriteBounds(nd->mRotationKeys,nd->mNumRotationKeys,out); + + } // else write as usual + else ::fwrite(nd->mRotationKeys,sizeof(aiQuatKey),nd->mNumRotationKeys,out); + } + if (nd->mScalingKeys) { + if (shortened) { + WriteBounds(nd->mScalingKeys,nd->mNumScalingKeys,out); + + } // else write as usual + else ::fwrite(nd->mScalingKeys,sizeof(aiVectorKey),nd->mNumScalingKeys,out); + } + } + } + + // write all meshes + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + const aiMesh* mesh = scene->mMeshes[i]; + + WriteMagic("#ME",out); + WriteInteger(mesh->mPrimitiveTypes,out); + WriteInteger(mesh->mNumBones,out); + WriteInteger(mesh->mNumFaces,out); + WriteInteger(mesh->mNumVertices,out); + + // write bones + if (mesh->mNumBones) { + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + const aiBone* b = mesh->mBones[a]; + + WriteMagic("#BN",out); + WriteAiString(b->mName,out); + WriteMat4x4(b->mOffsetMatrix,out); + WriteInteger(b->mNumWeights,out); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) { + WriteBounds(b->mWeights,b->mNumWeights,out); + } // else write as usual + else ::fwrite(b->mWeights,sizeof(aiVertexWeight),b->mNumWeights,out); + } + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + unsigned int processed = 0; + for (unsigned int job;job = std::min(mesh->mNumFaces-processed,512u);processed += job) { + + unsigned int hash = 0; + for (unsigned int a = 0; a < job;++a) { + + const aiFace& f = mesh->mFaces[processed+a]; + hash = SuperFastHash((const char*)&f.mNumIndices,sizeof(unsigned int),hash); + hash = SuperFastHash((const char*) f.mIndices,f.mNumIndices*sizeof(unsigned int),hash); + } + WriteInteger(hash,out); + } + } + else // else write as usual + { + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + const aiFace& f = mesh->mFaces[i]; + + WriteInteger(f.mNumIndices,out); + for (unsigned int a = 0; a < f.mNumIndices;++a) + WriteInteger(f.mIndices[a],out); + } + } + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) + c |= 1; + if (mesh->mNormals) + c |= 2; + if (mesh->mTangents && mesh->mBitangents) + c |= 4; + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n])break; + c |= (8 << n); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n])break; + c |= (16 << n); + } + WriteInteger(c,out); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + WriteBounds(mesh->mVertices,mesh->mNumVertices,out); + } // else write as usual + else ::fwrite(mesh->mVertices,12*mesh->mNumVertices,1,out); + } + if (mesh->mNormals) { + if (shortened) { + WriteBounds(mesh->mNormals,mesh->mNumVertices,out); + } // else write as usual + else ::fwrite(mesh->mNormals,12*mesh->mNumVertices,1,out); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + WriteBounds(mesh->mTangents,mesh->mNumVertices,out); + WriteBounds(mesh->mBitangents,mesh->mNumVertices,out); + } // else write as usual + else { + ::fwrite(mesh->mTangents,12*mesh->mNumVertices,1,out); + ::fwrite(mesh->mBitangents,12*mesh->mNumVertices,1,out); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n])break; + + // write number of UV components + WriteInteger(mesh->mNumUVComponents[n],out); + + if (shortened) { + WriteBounds(mesh->mTextureCoords[n],mesh->mNumVertices,out); + } // else write as usual + else ::fwrite(mesh->mTextureCoords[n],12*mesh->mNumVertices,1,out); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + WriteBounds(mesh->mColors[n],mesh->mNumVertices,out); + } // else write as usual + else ::fwrite(mesh->mColors[n],16*mesh->mNumVertices,1,out); + } + } +} + +// ----------------------------------------------------------------------------------- +// Convert a name to standard XML format +void ConvertName(aiString& out, const aiString& in) +{ + out.length = 0; + for (unsigned int i = 0; i < in.length; ++i) { + switch (in.data[i]) { + case '<': + out.Append("<");break; + case '>': + out.Append(">");break; + case '&': + out.Append("&");break; + case '\"': + out.Append(""");break; + case '\'': + out.Append("'");break; + default: + out.data[out.length++] = in.data[i]; + } + } + out.data[out.length] = 0; +} + +// ----------------------------------------------------------------------------------- +// Write a single node as text dump +void WriteNode(const aiNode* node, FILE* out, unsigned int depth) +{ + char prefix[512]; + for (unsigned int i = 0; i < depth;++i) + prefix[i] = '\t'; + prefix[depth] = '\0'; + + const aiMatrix4x4& m = node->mTransformation; + + aiString name; + ConvertName(name,node->mName); + ::fprintf(out,"%s \n" + "%s\t \n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t \n", + prefix,name.data,prefix, + prefix,m.a1,m.a2,m.a3,m.a4, + prefix,m.b1,m.b2,m.b3,m.b4, + prefix,m.c1,m.c2,m.c3,m.c4, + prefix,m.d1,m.d2,m.d3,m.d4,prefix); + + if (node->mNumMeshes) { + ::fprintf(out, "%s\t\n%s\t", + prefix,node->mNumMeshes,prefix); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + ::fprintf(out,"%i ",node->mMeshes[i]); + } + ::fprintf(out,"\n%s\t\n",prefix); + } + + ::fprintf(out,"%s\t%i\n", + prefix,node->mNumChildren); + + for (unsigned int i = 0; i < node->mNumChildren;++i) + WriteNode(node->mChildren[i],out,depth+1); + + ::fprintf(out,"%s\n",prefix); +} + +// ----------------------------------------------------------------------------------- +// Write a text model dump +void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd, bool shortened) +{ + time_t tt = ::time(NULL); + tm* p = ::gmtime(&tt); + + aiString name; + + // write header + ::fprintf(out, + "\n" + "\n\n" + + "" + " \n\n" + "\n", + + aiGetVersionMajor(),aiGetVersionMinor(),aiGetVersionRevision(),src,cmd,::asctime(p), + scene->mNumMeshes, scene->mNumMaterials,scene->mNumTextures, + scene->mNumCameras,scene->mNumLights,scene->mNumAnimations); + + // write the node graph + WriteNode(scene->mRootNode, out, 1); + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + aiCamera* cam = scene->mCameras[i]; + ConvertName(name,cam->mName); + + // camera header + ::fprintf(out,"\t\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\n", + name.data, + cam->mUp.x,cam->mUp.y,cam->mUp.z, + cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z, + cam->mPosition.x,cam->mPosition.y,cam->mPosition.z, + cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + aiLight* l = scene->mLights[i]; + ConvertName(name,l->mName); + + // light header + ::fprintf(out,"\t type=\"%s\"\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n", + name.data, + (l->mType == aiLightSource_DIRECTIONAL ? "directional" : + (l->mType == aiLightSource_POINT ? "point" : "spot" )), + l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b, + l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b, + l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); + + if (l->mType != aiLightSource_DIRECTIONAL) { + ::fprintf(out, + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n", + l->mPosition.x,l->mPosition.y,l->mPosition.z, + l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic); + } + + if (l->mType != aiLightSource_POINT) { + ::fprintf(out, + "\t\t %0 8f %0 8f %0 8f \n", + l->mDirection.x,l->mDirection.y,l->mDirection.z); + } + + if (l->mType == aiLightSource_SPOT) { + ::fprintf(out, + "\t\t %f \n" + "\t\t %f \n", + l->mAngleOuterCone,l->mAngleInnerCone); + } + ::fprintf(out,"\t\n"); + } + + // write textures + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + aiTexture* tex = scene->mTextures[i]; + bool compressed = (tex->mHeight == 0); + + // mesh header + ::fprintf(out,"\t \n" + "\t\t %i \n", + "\t\t %i \n", + "\t\t %s \n", + (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight), + (compressed ? "true" : "false")); + + if (compressed) { + ::fprintf(out,"\t\t %i \n",tex->mWidth); + + if (!shortened) { + for (unsigned int n = 0; n < tex->mWidth;++n) { + ::fprintf(out,"\t\t\t%2x",tex->pcData[n]); + if (n && !(n % 50)) + ::fprintf(out,"\n"); + } + } + } + else if (!shortened){ + ::fprintf(out,"\t\t %i \n",tex->mWidth*tex->mHeight*4); + + const unsigned int width = (unsigned int)log10((double)std::max(tex->mHeight,tex->mWidth))+1; + for (unsigned int y = 0; y < tex->mHeight;++y) { + for (unsigned int x = 0; x < tex->mWidth;++x) { + aiTexel* tx = tex->pcData + y*tex->mWidth+x; + unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; + ::fprintf(out,"\t\t\t%2x %2x %2x %2x",r,g,b,a); + + // group by four for readibility + if (0 == (x+y*tex->mWidth) % 4) + ::fprintf(out,"\n"); + } + } + } + ::fprintf(out,"\t\t\n\t\n"); + } + + // write materials + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + + ::fprintf(out, + "\t\n",mat->mNumProperties); + + for (unsigned int n = 0; n < mat->mNumProperties;++n) { + const aiMaterialProperty* prop = mat->mProperties[n]; + + const char* sz = ""; + if (prop->mType == aiPTI_Float) + sz = "float"; + else if (prop->mType == aiPTI_Integer) + sz = "integer"; + else if (prop->mType == aiPTI_String) + sz = "string"; + else if (prop->mType == aiPTI_Buffer) + sz = "binary_buffer"; + + ::fprintf(out, + "\t\tmKey.data, sz, + TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); + + if (prop->mType == aiPTI_Float) { + ::fprintf(out, + " size=\"%i\">\n\t\t\t", + prop->mDataLength/sizeof(float)); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) + ::fprintf(out,"%f ",*((float*)(prop->mData+p*sizeof(float)))); + } + else if (prop->mType == aiPTI_Integer) { + ::fprintf(out, + " size=\"%i\">\n\t\t\t", + prop->mDataLength/sizeof(int)); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) + ::fprintf(out,"%i ",*((int*)(prop->mData+p*sizeof(int)))); + } + else if (prop->mType == aiPTI_Buffer) { + ::fprintf(out, + " size=\"%i\">\n\t\t\t", + prop->mDataLength); + + for (unsigned int p = 0; p < prop->mDataLength;++p) { + ::fprintf(out,"%2x ",prop->mData[p]); + if (p && 0 == p%30) + ::fprintf(out,"\n\t\t\t"); + } + } + else if (prop->mType == aiPTI_String) { + ::fprintf(out,">\n\t\t\t\"%s\"",prop->mData+4 /* skip length */); + } + ::fprintf(out,"\n\t\t\n"); + } + ::fprintf(out,"\t\n"); + } + + // write animations + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + aiAnimation* anim = scene->mAnimations[i]; + + // anim header + ConvertName(name,anim->mName); + ::fprintf(out,"\t\n" + "\t\t %i \n" + "\t\t %e \n" + "\t\t %e \n", + name.data, anim->mNumChannels,anim->mDuration, anim->mTicksPerSecond); + + // write bone animation channels + for (unsigned int n = 0; n < anim->mNumChannels;++n) { + aiNodeAnim* nd = anim->mChannels[n]; + + // node anim header + ConvertName(name,nd->mNodeName); + ::fprintf(out,"\t\t\n" + "\t\t\t %i \n" + "\t\t\t %i \n" + "\t\t\t %i \n", + name.data,nd->mNumPositionKeys,nd->mNumScalingKeys,nd->mNumRotationKeys); + + if (!shortened) { + // write position keys + for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { + aiVectorKey* vc = nd->mPositionKeys+a; + ::fprintf(out,"\t\t\t\n" + "\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,a); + } + + // write scaling keys + for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { + aiVectorKey* vc = nd->mScalingKeys+a; + ::fprintf(out,"\t\t\t\n" + "\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,a); + } + + // write rotation keys + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { + aiQuatKey* vc = nd->mRotationKeys+a; + ::fprintf(out,"\t\t\t\n" + "\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w,a); + } + } + ::fprintf(out,"\t\t\n",n); + } + ::fprintf(out,"\t\n",i); + } + + // write meshes + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + aiMesh* mesh = scene->mMeshes[i]; + const unsigned int width = (unsigned int)log10((double)mesh->mNumVertices)+1; + + // mesh header + ::fprintf(out,"\t\n" + "\t\t %i \n" + "\t\t %i \n", + (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), + mesh->mNumVertices,mesh->mNumFaces); + + // bones + for (unsigned int n = 0; n < mesh->mNumBones;++n) { + aiBone* bone = mesh->mBones[n]; + + ConvertName(name,bone->mName); + // bone header + ::fprintf(out,"\t\t\n" + "\t\t\t \n" + "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t \n" + "\t\t\t %i \n", + name.data, + bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, + bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, + bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, + bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4, + bone->mNumWeights); + + if (!shortened) { + // bone weights + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + aiVertexWeight* wght = bone->mWeights+a; + + ::fprintf(out,"\t\t\t\n\t\t\t\t%f\n\t\t\t\n", + wght->mVertexId,wght->mWeight); + } + } + ::fprintf(out,"\t\t\n",n); + } + + // faces + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { + aiFace& f = mesh->mFaces[n]; + ::fprintf(out,"\t\t\n" + "\t\t\t",f.mNumIndices); + + for (unsigned int j = 0; j < f.mNumIndices;++j) + ::fprintf(out,"%i ",f.mIndices[j]); + + ::fprintf(out,"\n\t\t\n"); + } + } + + // vertex positions + if (mesh->HasPositions()) { + ::fprintf(out,"\t\t \n"); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ::fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mVertices[n].x, + mesh->mVertices[n].y, + mesh->mVertices[n].z); + } + } + else { + } + ::fprintf(out,"\t\t\n"); + } + + // vertex normals + if (mesh->HasNormals()) { + ::fprintf(out,"\t\t \n"); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ::fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mNormals[n].x, + mesh->mNormals[n].y, + mesh->mNormals[n].z); + } + } + else { + } + ::fprintf(out,"\t\t\n"); + } + + // vertex tangents and bitangents + if (mesh->HasTangentsAndBitangents()) { + ::fprintf(out,"\t\t \n"); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ::fprintf(out,"\t\t%0 8f %0 8f %0 8f \t %0 8f %0 8f %0 8f\n", + mesh->mTangents[n].x, + mesh->mTangents[n].y, + mesh->mTangents[n].z, + mesh->mBitangents[n].x, + mesh->mBitangents[n].y, + mesh->mBitangents[n].z); + } + } + else { + } + ::fprintf(out,"\t\t\n"); + } + + // texture coordinates + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (!mesh->mTextureCoords[a]) + break; + + ::fprintf(out,"\t\t \n",mesh->mNumUVComponents[a]); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ::fprintf(out,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y, + mesh->mTextureCoords[a][n].z); + } + } + else { + } + ::fprintf(out,"\t\t\n"); + } + + // vertex colors + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (!mesh->mColors[a]) + break; + ::fprintf(out,"\t\t \n"); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ::fprintf(out,"\t\t%0 8f %0 8f %0 8f %0 8f\n", + mesh->mColors[a][n].r, + mesh->mColors[a][n].g, + mesh->mColors[a][n].b, + mesh->mColors[a][n].a); + } + } + else { + } + ::fprintf(out,"\t\t\n"); + } + ::fprintf(out,"\t\n"); + } + ::fprintf(out,"\n"); +} + + +// ----------------------------------------------------------------------------------- +int Assimp_Dump (const char** params, unsigned int num) +{ + if (num < 1) { + ::printf("assimp dump: Invalid number of arguments. See \'assimp extract --help\'\r\n"); + return 1; + } + + // --help + if (!::strcmp( params[0], "-h") || !::strcmp( params[0], "--help") || !::strcmp( params[0], "-?") ) { + printf(AICMD_MSG_DUMP_HELP); + return 0; + } + + // asssimp dump in out [options] + if (num < 1) { + ::printf("assimp dump: Invalid number of arguments. See \'assimp dump --help\'\r\n"); + return 1; + } + + std::string in = std::string(params[0]); + std::string out = (num > 1 ? std::string(params[1]) : std::string("-")); + + // store full command line + std::string cmd; + for (unsigned int i = (out[0] == '-' ? 1 : 2); i < num;++i) { + if (!params[i])continue; + cmd.append(params[i]); + cmd.append(" "); + } + + // get import flags + ImportData import; + ProcessStandardArguments(import,params+1,num-1); + + bool binary = false, shortened = false,compressed=false; + + // process other flags + for (unsigned int i = 1; i < num;++i) { + if (!params[i])continue; + if (!::strcmp( params[i], "-b") || !::strcmp( params[i], "--binary")) { + binary = true; + } + else if (!::strcmp( params[i], "-s") || !::strcmp( params[i], "--short")) { + shortened = true; + } + else if (!::strcmp( params[i], "-z") || !::strcmp( params[i], "--compressed")) { + compressed = true; + } + else if (i > 2 || params[i][0] == '-') { + ::printf("Unknown parameter: %s\n",params[i]); + return 10; + } + } + + if (out[0] == '-') { + + // take file name from input file + std::string::size_type s = in.find_last_of('.'); + if (s == std::string::npos) + s = in.length(); + + out = in.substr(0,s); + out.append((binary ? ".assfile" : ".xml")); + if (shortened && binary) + out.append(".regress"); + } + + // import the main model + const aiScene* scene = ImportModel(import,in); + if (!scene) { + ::printf("assimp dump: Unable to load input file %s\n",in.c_str()); + return 5; + } + + // open the output file and build the dump + FILE* o = ::fopen(out.c_str(),(binary ? "wb" : "wt")); + if (!o) { + ::printf("assimp dump: Unable to open output file %s\n",out.c_str()); + return 12; + } + + if (binary) + WriteBinaryDump (scene,o,in.c_str(),cmd.c_str(),shortened,compressed,import); + else WriteDump (scene,o,in.c_str(),cmd.c_str(),shortened); + ::fclose(o); + + if (compressed && binary) + CompressBinaryDump(out.c_str(),500); + + ::printf("assimp dump: Wrote output dump %s\n",out.c_str()); + return 0; +} + diff --git a/tools/assimp_cmd/assimp_cmd.rc b/tools/assimp_cmd/assimp_cmd.rc new file mode 100644 index 000000000..96f18afff --- /dev/null +++ b/tools/assimp_cmd/assimp_cmd.rc @@ -0,0 +1,88 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" +#include "../../mkutil/revision.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Deutsch (Deutschland) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ASSIMP_VIEW ICON "../shared/assimp_tools_icon.ico" + + + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,SVNRevision,0 + PRODUCTVERSION 1,0,SVNRevision,1 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040704b0" + BEGIN + VALUE "CompanyName", "ASSIMP Development Team" + VALUE "FileDescription", "ASSIMP Command-line Tools" + VALUE "FileVersion", "1, 0, SVNRevision, 0" + VALUE "InternalName", "assimp_view" + VALUE "LegalCopyright", "Licensed under the LGPL" + VALUE "OriginalFilename", "assimp_cmd32.exe" + VALUE "ProductName", "ASSIMP Command-line Tools" + VALUE "ProductVersion", "1, 0, SVNRevision, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x407, 1200 + END +END + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED +#endif diff --git a/tools/assimp_cmd/makefile b/tools/assimp_cmd/makefile new file mode 100644 index 000000000..413f6859d --- /dev/null +++ b/tools/assimp_cmd/makefile @@ -0,0 +1,63 @@ + +# --------------------------------------------------------------------------- +# Makefile for assimp_cmd +# aramis_acg@users.sourceforge.net +# +# Usage: make + +# TARGETS: +# all Build assimp_cmd tool and assimp if necessary +# clean Cleanup all object files, including those from core +# cleanme Cleanup only my object files + +# MACROS: (make clean before you change one) +# NOBOOST=1 Build Assimp against boost workaround +# SINGLETHREADED=1 Build Assimp single-threaded library +# DEBUG=1 Build debug build of Assimp library +# --------------------------------------------------------------------------- + + +# C++ object files +OBJECTS := $(patsubst %.cpp,%.o, $(wildcard *.cpp)) + + +# Include flags for gcc +INCLUDEFLAGS = -I../../include + +# Library flags for gcc +LIBRARYFLAGS = -L../../bin/gcc/ + +# Preprocessor defines for gcc +DEFINEFLAGS = + +# GCC compiler flags +CPPFLAGS=-Wall + + +# Setup environment for debug build +ifeq ($(DEBUG),1) + DEFINEFLAGS += -D_DEBUG -DDEBUG +else + CPPFLAGS += -o3 + DEFINEFLAGS += -DNDEBUG -D_NDEBUG +endif + +# Output path of executable +OUTPUT = ../../bin/gcc/assimp + + +all: $(OBJECTS) + cd ../../code/ && $(MAKE) static + gcc -s -o$(OUTPUT) $(OBJECTS) $(LIBRARYFLAGS) -lassimp -lstdc++ + +%.o:%.cpp + $(CXX) -g -c $(CPPFLAGS) $? -o $@ $(INCLUDEFLAGS) $(DEFINEFLAGS) + +.PHONY: clean +clean: + -del *.o + cd ../../code/ && $(MAKE) clean + +.PHONY: cleanme +cleanme: + -del *.o \ No newline at end of file diff --git a/tools/assimp_cmd/makefile.mingw b/tools/assimp_cmd/makefile.mingw new file mode 100644 index 000000000..6252ea568 --- /dev/null +++ b/tools/assimp_cmd/makefile.mingw @@ -0,0 +1,61 @@ + +# --------------------------------------------------------------------------- +# Makefile for assimp_cmd (MinGW32-make) +# aramis_acg@users.sourceforge.net +# +# Usage: mingw32-make -f makefile.mingw + +# TARGETS: +# all Build assimp_cmd tool and assimp if necessary +# clean Cleanup all object files, including those from core +# cleanme Cleanup only my object files + +# MACROS: (make clean before you change one) +# NOBOOST=1 Build Assimp against boost workaround +# SINGLETHREADED=1 Build Assimp single-threaded library +# DEBUG=1 Build debug build of Assimp library +# --------------------------------------------------------------------------- + + +# C++ object files +OBJECTS := $(patsubst %.cpp,%.o, $(wildcard *.cpp)) + +# Include flags for gcc +INCLUDEFLAGS = -I../../include + +# Library flags for gcc +LIBRARYFLAGS = -L../../bin/mingw/ + +# Preprocessor defines for gcc +DEFINEFLAGS = + +# GCC compiler flags +CPPFLAGS=-Wall + + +# Setup environment for debug build +ifeq ($(DEBUG),1) + DEFINEFLAGS += -D_DEBUG -DDEBUG +else + CPPFLAGS += -o3 + DEFINEFLAGS += -DNDEBUG -D_NDEBUG +endif + +# Output path of executable +OUTPUT = ../../bin/mingw/assimp + +all: $(OBJECTS) + cd ../../code/ && $(MAKE) -fmakefile.mingw static + gcc -s -o$(OUTPUT) $(OBJECTS) $(LIBRARYFLAGS) -lassimp -lstdc++ + +%.o:%.cpp + $(CXX) -g -c $(CPPFLAGS) $? -o $@ $(INCLUDEFLAGS) $(DEFINEFLAGS) + +.PHONY: clean +clean: + -del *.o + cd ../../code/ && $(MAKE) -fmakefile.mingw clean + +.PHONY: cleanme +cleanme: + -del *.o \ No newline at end of file diff --git a/tools/assimp_cmd/resource.h b/tools/assimp_cmd/resource.h new file mode 100644 index 000000000..e5af4f18e --- /dev/null +++ b/tools/assimp_cmd/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by assimp_view.rc +// +#define IDC_MYICON 2 +#define IDD_ASSIMP_VIEW_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDI_ASSIMP_VIEW 107 + + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 159 +#define _APS_NEXT_COMMAND_VALUE 32831 +#define _APS_NEXT_CONTROL_VALUE 1052 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/tools/assimp_view/Background.cpp b/tools/assimp_view/Background.cpp index 02219022e..c852280fb 100644 --- a/tools/assimp_view/Background.cpp +++ b/tools/assimp_view/Background.cpp @@ -440,7 +440,7 @@ void CBackgroundPainter::RecreateNativeResource() (UINT)g_szSkyboxShader.length(), NULL, NULL, - D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, + AI_SHADER_COMPILE_FLAGS, NULL, &piSkyBoxEffect,&piBuffer))) { diff --git a/tools/assimp_view/Material.cpp b/tools/assimp_view/Material.cpp index 9e3ce7dc5..9d7bef816 100644 --- a/tools/assimp_view/Material.cpp +++ b/tools/assimp_view/Material.cpp @@ -280,10 +280,6 @@ int CMaterialManager::FindValidPath(aiString* p_szString) if (!pFile) { if(TryLongerPath(szTemp, p_szString))return 1; - - // still unable to load ... however, don't spew - // an error message here, simply let it and wait for - // D3DXCreateTextureFromFileEx() to fail ;-) } return 0; } @@ -1354,4 +1350,4 @@ int CMaterialManager::EndMaterial (AssetHelper::MeshHelper* pcMesh) return 1; } -}; // end namespace AssimpView \ No newline at end of file +}; // end namespace AssimpView diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index 2c30d7264..ae448d95e 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -1571,7 +1571,69 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, DragQueryFile(hDrop,0,szFile,sizeof(szFile)); const char* sz = strrchr(szFile,'.'); - if (sz && 0 != aiIsExtensionSupported(sz)) + if (!sz) + sz = szFile; + + if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode()) + { + // replace the selected texture with the new one ... + CDisplay::Instance().ReplaceCurrentTexture(szFile); + } + else + { + // check whether it is a typical texture file format ... + ++sz; + if (0 == ASSIMP_stricmp(sz,"png") || + 0 == ASSIMP_stricmp(sz,"bmp") || + 0 == ASSIMP_stricmp(sz,"jpg") || + 0 == ASSIMP_stricmp(sz,"tga") || + 0 == ASSIMP_stricmp(sz,"tif") || + 0 == ASSIMP_stricmp(sz,"hdr") || + 0 == ASSIMP_stricmp(sz,"ppm") || + 0 == ASSIMP_stricmp(sz,"pfm")) + { + CBackgroundPainter::Instance().SetTextureBG(szFile); + } + else if (0 == Assimp::ASSIMP_stricmp(sz,"dds")) + { + // DDS files could contain skyboxes, but they could also + // contain normal 2D textures. The easiest way to find this + // out is to open the file and check the header ... + FILE* pFile = fopen(szFile,"rb"); + if (!pFile) + return TRUE; + + // header of a dds file (begin) + /* + DWORD dwMagic + DWORD dwSize + DWORD dwFlags + DWORD dwHeight + DWORD dwWidth + DWORD dwPitchOrLinearSize + DWORD dwDepth + DWORD dwMipMapCount -> total with this: 32 + DWORD dwReserved1[11] -> total with this: 76 + DDPIXELFORMAT ddpfPixelFormat -> total with this: 108 + DWORD dwCaps1; -> total with this: 112 + DWORD dwCaps2; ---< here we are! + */ + DWORD dwCaps = 0; + fseek(pFile,112,SEEK_SET); + fread(&dwCaps,4,1,pFile); + + if (dwCaps & 0x00000400L /* DDSCAPS2_CUBEMAP_POSITIVEX */) + { + CLogDisplay::Instance().AddEntry( + "[INFO] Assuming this dds file is a skybox ...", + D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0)); + + CBackgroundPainter::Instance().SetCubeMapBG(szFile); + } + else CBackgroundPainter::Instance().SetTextureBG(szFile); + fclose(pFile); + } + else { strcpy(g_szFileName,szFile); @@ -1580,75 +1642,8 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, UpdateHistory(); SaveHistory(); } - else if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode()) - { - // replace the selected texture with the new one ... - CDisplay::Instance().ReplaceCurrentTexture(szFile); - } - else - { - if (!sz) goto __DRUNKEN_ALIEN_FROM_MARS; - - // check whether it is a typical texture file format ... - ++sz; - if (0 == ASSIMP_stricmp(sz,"png") || - 0 == ASSIMP_stricmp(sz,"bmp") || - 0 == ASSIMP_stricmp(sz,"jpg") || - 0 == ASSIMP_stricmp(sz,"tga") || - 0 == ASSIMP_stricmp(sz,"tif") || - 0 == ASSIMP_stricmp(sz,"hdr") || - 0 == ASSIMP_stricmp(sz,"ppm") || - 0 == ASSIMP_stricmp(sz,"pfm")) - { - CBackgroundPainter::Instance().SetTextureBG(szFile); - } - else if (0 == Assimp::ASSIMP_stricmp(sz,"dds")) - { - // DDS files could contain skyboxes, but they could also - // contain normal 2D textures. The easiest way to find this - // out is to open the file and check the header ... - FILE* pFile = fopen(szFile,"rb"); - if (!pFile)goto __DRUNKEN_ALIEN_FROM_MARS; - - // header of a dds file (begin) - /* - DWORD dwMagic - DWORD dwSize - DWORD dwFlags - DWORD dwHeight - DWORD dwWidth - DWORD dwPitchOrLinearSize - DWORD dwDepth - DWORD dwMipMapCount -> total with this: 32 - DWORD dwReserved1[11] -> total with this: 76 - DDPIXELFORMAT ddpfPixelFormat -> total with this: 108 - DWORD dwCaps1; -> total with this: 112 - DWORD dwCaps2; ---< here we are! - */ - DWORD dwCaps = 0; - fseek(pFile,112,SEEK_SET); - fread(&dwCaps,4,1,pFile); - - if (dwCaps & 0x00000400L /* DDSCAPS2_CUBEMAP_POSITIVEX */) - { - CLogDisplay::Instance().AddEntry( - "[INFO] Assuming this dds file is a skybox ...", - D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0)); - - CBackgroundPainter::Instance().SetCubeMapBG(szFile); - } - else CBackgroundPainter::Instance().SetTextureBG(szFile); - fclose(pFile); - } - else - { -__DRUNKEN_ALIEN_FROM_MARS: - CLogDisplay::Instance().AddEntry( - "[ERROR] File extension is not supported. E.T. can read this.", - D3DCOLOR_ARGB(0xFF,0xFF,0,0)); - } - } - DragFinish(hDrop); + } + DragFinish(hDrop); } return TRUE; diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index cc3b99eda..cd3be8595 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -128,6 +128,9 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter) // get current time double fCur = (double)timeGetTime(); + aiSetImportPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS,1); + //aiSetImportPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,1); + // Call ASSIMPs C-API to load the file g_pcAsset->pcScene = (aiScene*)aiImportFile(g_szFileName, aiProcess_CalcTangentSpace | // calculate tangents and bitangents if possible @@ -145,6 +148,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter) aiProcess_GenUVCoords | // convert spherical, cylindrical, box and planar mapping to proper UVs aiProcess_TransformUVCoords | // preprocess UV transformations (scaling, translation ...) aiProcess_FindInstances | // search for instanced meshes and remove them by references to one master +// aiProcess_PreTransformVertices | 0); // get the end time of zje operation, calculate delta t @@ -1012,7 +1016,7 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) (UINT)g_szDefaultShader.length(), NULL, NULL, - D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, + AI_SHADER_COMPILE_FLAGS, NULL, &g_piDefaultEffect,&piBuffer))) { @@ -1036,7 +1040,7 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) // create the shader used to draw the HUD if(FAILED( D3DXCreateEffect(g_piDevice, g_szPassThroughShader.c_str(),(UINT)g_szPassThroughShader.length(), - NULL,NULL,D3DXSHADER_USE_LEGACY_D3DX9_31_DLL,NULL,&g_piPassThroughEffect,&piBuffer))) + NULL,NULL,AI_SHADER_COMPILE_FLAGS,NULL,&g_piPassThroughEffect,&piBuffer))) { if( piBuffer) { @@ -1058,7 +1062,7 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) // create the shader used to visualize normal vectors if(FAILED( D3DXCreateEffect(g_piDevice, g_szNormalsShader.c_str(),(UINT)g_szNormalsShader.length(), - NULL,NULL,D3DXSHADER_USE_LEGACY_D3DX9_31_DLL,NULL,&g_piNormalsEffect, &piBuffer))) + NULL,NULL,AI_SHADER_COMPILE_FLAGS,NULL,&g_piNormalsEffect, &piBuffer))) { if( piBuffer) { @@ -1073,6 +1077,8 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) piBuffer = NULL; } + //MessageBox( g_hDlg, "Failed to create vertex declaration", "Init", MB_OK); + // use Fixed Function effect when working with shaderless cards if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0)) g_piNormalsEffect->SetTechnique( "RenderNormals_FF"); diff --git a/tools/assimp_view/assimp_view.h b/tools/assimp_view/assimp_view.h index 882bca05f..b2b02a83c 100644 --- a/tools/assimp_view/assimp_view.h +++ b/tools/assimp_view/assimp_view.h @@ -42,6 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if (!defined AV_MAIN_H_INCLUDED) #define AV_MAIN_H_INCLUDED +#define AI_SHADER_COMPILE_FLAGS D3DXSHADER_USE_LEGACY_D3DX9_31_DLL + // include resource definitions #include "resource.h" diff --git a/tools/assimp_view/assimp_view.ico b/tools/assimp_view/assimp_view.ico deleted file mode 100644 index d551aa3aa..000000000 Binary files a/tools/assimp_view/assimp_view.ico and /dev/null differ diff --git a/tools/assimp_view/assimp_view.rc b/tools/assimp_view/assimp_view.rc index 116be7620..5a32a6bf7 100644 --- a/tools/assimp_view/assimp_view.rc +++ b/tools/assimp_view/assimp_view.rc @@ -1,6 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "resource.h" +#include "../../mkutil/revision.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -30,8 +31,7 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_ASSIMP_VIEW ICON "assimp_view.ico" -IDI_SMALL ICON "small.ico" +IDI_ASSIMP_VIEW ICON "../shared/assimp_tools_icon.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -205,8 +205,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,1 - PRODUCTVERSION 1,0,0,1 + FILEVERSION 1,0,SVNRevision,0 + PRODUCTVERSION 1,0,SVNRevision,1 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -223,12 +223,12 @@ BEGIN BEGIN VALUE "CompanyName", "ASSIMP Development Team" VALUE "FileDescription", "ASSIMP Viewer Application" - VALUE "FileVersion", "1, 0, 0, 1" + VALUE "FileVersion", "1, 0, SVNRevision, 0" VALUE "InternalName", "assimp_view" VALUE "LegalCopyright", "Licensed under the LGPL" VALUE "OriginalFilename", "assimpview32.exe" VALUE "ProductName", "ASSIMP Viewer Application" - VALUE "ProductVersion", "1, 0, 0, 1" + VALUE "ProductVersion", "1, 0, SVNRevision, 0" END END BLOCK "VarFileInfo" diff --git a/tools/assimp_view/small.ico b/tools/assimp_view/small.ico deleted file mode 100644 index d551aa3aa..000000000 Binary files a/tools/assimp_view/small.ico and /dev/null differ diff --git a/tools/shared/assimp_tools_icon.ico b/tools/shared/assimp_tools_icon.ico new file mode 100644 index 000000000..55c437b87 Binary files /dev/null and b/tools/shared/assimp_tools_icon.ico differ diff --git a/tools/shared/assimp_tools_icon.png b/tools/shared/assimp_tools_icon.png new file mode 100644 index 000000000..6399ceb0d Binary files /dev/null and b/tools/shared/assimp_tools_icon.png differ diff --git a/tools/shared/assimp_tools_icon.svg b/tools/shared/assimp_tools_icon.svg new file mode 100644 index 000000000..0ebbaf968 --- /dev/null +++ b/tools/shared/assimp_tools_icon.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/workspaces/vc8/UnitTest.vcproj b/workspaces/vc8/UnitTest.vcproj index 5b2dde2e3..6cb864c33 100644 --- a/workspaces/vc8/UnitTest.vcproj +++ b/workspaces/vc8/UnitTest.vcproj @@ -1331,6 +1331,14 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + + + diff --git a/workspaces/vc8/assimp.sln b/workspaces/vc8/assimp.sln index 9c7569c4f..f5f312aab 100644 --- a/workspaces/vc8/assimp.sln +++ b/workspaces/vc8/assimp.sln @@ -25,6 +25,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit", "UnitTest.vcproj", " {5691E159-2D9B-407F-971F-EA5C592DC524} = {5691E159-2D9B-407F-971F-EA5C592DC524} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "assimp_cmd", "assimp_cmd.vcproj", "{7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {5691E159-2D9B-407F-971F-EA5C592DC524} = {5691E159-2D9B-407F-971F-EA5C592DC524} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution debug|Win32 = debug|Win32 @@ -141,6 +150,37 @@ Global {9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.release-st|Win32.Build.0 = release-st|Win32 {9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.release-st|x64.ActiveCfg = release-st|x64 {9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.release-st|x64.Build.0 = release-st|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug|Win32.ActiveCfg = Debug|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug|Win32.Build.0 = Debug|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug|x64.ActiveCfg = Debug|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug|x64.Build.0 = Debug|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-dll|Win32.ActiveCfg = debug-dll|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-dll|Win32.Build.0 = debug-dll|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-dll|x64.ActiveCfg = debug-dll|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-dll|x64.Build.0 = debug-dll|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-noboost-st|Win32.ActiveCfg = debug-noboost-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-noboost-st|Win32.Build.0 = debug-noboost-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-noboost-st|x64.ActiveCfg = debug-noboost-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-st|Win32.ActiveCfg = debug-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-st|Win32.Build.0 = debug-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-st|x64.ActiveCfg = debug-st|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.debug-st|x64.Build.0 = debug-st|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release|Win32.ActiveCfg = Release|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release|Win32.Build.0 = Release|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release|x64.ActiveCfg = Release|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release|x64.Build.0 = Release|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-dll|Win32.ActiveCfg = release-dll|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-dll|Win32.Build.0 = release-dll|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-dll|x64.ActiveCfg = release-dll|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-dll|x64.Build.0 = release-dll|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-noboost-st|Win32.ActiveCfg = release-noboost-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-noboost-st|Win32.Build.0 = release-noboost-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-noboost-st|x64.ActiveCfg = release-noboost-st|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-noboost-st|x64.Build.0 = release-noboost-st|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-st|Win32.ActiveCfg = release-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-st|Win32.Build.0 = release-st|Win32 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-st|x64.ActiveCfg = release-st|x64 + {7C8F7B44-C990-4EA8-A2A5-9028472E0AD3}.release-st|x64.Build.0 = release-st|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/workspaces/vc8/assimp.vcproj b/workspaces/vc8/assimp.vcproj index 5ff938073..c315d5b2c 100644 --- a/workspaces/vc8/assimp.vcproj +++ b/workspaces/vc8/assimp.vcproj @@ -21,6 +21,7 @@ Name="debug|Win32" ConfigurationType="4" InheritedPropertySheets=".\shared\LibShared.vsprops;.\shared\FastSTL.vsprops" + WholeProgramOptimization="0" > @@ -166,9 +172,11 @@ /> @@ -235,13 +245,14 @@ Name="VCCLCompilerTool" InlineFunctionExpansion="2" EnableIntrinsicFunctions="true" - FavorSizeOrSpeed="1" + FavorSizeOrSpeed="0" AdditionalIncludeDirectories="" PreprocessorDefinitions="NDEBUG, _SCL_SECURE_NO_WARNINGS, _CRT_SECURE_NO_WARNINGS,WIN32" StringPooling="true" RuntimeLibrary="2" BufferSecurityCheck="false" EnableEnhancedInstructionSet="0" + FloatingPointModel="2" UsePrecompiledHeader="2" PrecompiledHeaderThrough="AssimpPCH.h" WarningLevel="3" @@ -299,13 +310,16 @@ Name="VCCLCompilerTool" InlineFunctionExpansion="2" EnableIntrinsicFunctions="true" - FavorSizeOrSpeed="1" + FavorSizeOrSpeed="0" + OmitFramePointers="true" + WholeProgramOptimization="false" AdditionalIncludeDirectories="" PreprocessorDefinitions="NDEBUG;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;ASSIMP_BUILD_DLL_EXPORT" StringPooling="true" RuntimeLibrary="2" BufferSecurityCheck="false" EnableEnhancedInstructionSet="2" + FloatingPointModel="2" UsePrecompiledHeader="2" PrecompiledHeaderThrough="AssimpPCH.h" WarningLevel="3" @@ -348,7 +362,7 @@ /> @@ -573,7 +594,7 @@ /> @@ -834,6 +865,7 @@ Name="debug-st|Win32" ConfigurationType="4" InheritedPropertySheets=".\shared\LibShared.vsprops;.\shared\SingleThreadedShared.vsprops;.\shared\FastSTL.vsprops" + WholeProgramOptimization="0" > @@ -979,13 +1016,16 @@ Name="VCCLCompilerTool" InlineFunctionExpansion="2" EnableIntrinsicFunctions="true" - FavorSizeOrSpeed="1" + FavorSizeOrSpeed="0" + OmitFramePointers="true" + WholeProgramOptimization="false" AdditionalIncludeDirectories="" PreprocessorDefinitions="NDEBUG;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32" StringPooling="true" RuntimeLibrary="2" BufferSecurityCheck="false" EnableEnhancedInstructionSet="2" + FloatingPointModel="2" UsePrecompiledHeader="2" PrecompiledHeaderThrough="AssimpPCH.h" WarningLevel="3" @@ -1045,13 +1085,14 @@ Name="VCCLCompilerTool" InlineFunctionExpansion="2" EnableIntrinsicFunctions="true" - FavorSizeOrSpeed="1" + FavorSizeOrSpeed="0" AdditionalIncludeDirectories="" PreprocessorDefinitions="NDEBUG, _SCL_SECURE_NO_WARNINGS, _CRT_SECURE_NO_WARNINGS,WIN32" StringPooling="true" RuntimeLibrary="2" BufferSecurityCheck="false" EnableEnhancedInstructionSet="0" + FloatingPointModel="2" UsePrecompiledHeader="2" PrecompiledHeaderThrough="AssimpPCH.h" WarningLevel="3" @@ -1322,6 +1363,22 @@ + + + + + + + + + + @@ -1970,6 +2035,30 @@ >
+ + + + + + + + + + + + @@ -1994,30 +2083,10 @@ > - - - - - - - -
- - @@ -2101,6 +2170,14 @@ + + + - - + + + + @@ -3383,6 +3464,10 @@ RelativePath="..\..\doc\dox.h" > + + diff --git a/workspaces/vc8/assimp_cmd.vcproj b/workspaces/vc8/assimp_cmd.vcproj new file mode 100644 index 000000000..5b449ae6b --- /dev/null +++ b/workspaces/vc8/assimp_cmd.vcproj @@ -0,0 +1,1508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/workspaces/vc8/assimp_view.vcproj b/workspaces/vc8/assimp_view.vcproj index b5c792185..94c167e2e 100644 --- a/workspaces/vc8/assimp_view.vcproj +++ b/workspaces/vc8/assimp_view.vcproj @@ -25,6 +25,7 @@ ConfigurationType="1" InheritedPropertySheets=".\shared\FastSTL.vsprops" CharacterSet="2" + WholeProgramOptimization="0" > + + + + diff --git a/workspaces/vc9/assimp.vcproj b/workspaces/vc9/assimp.vcproj index 6b7da22a6..914d37200 100644 --- a/workspaces/vc9/assimp.vcproj +++ b/workspaces/vc9/assimp.vcproj @@ -1902,6 +1902,14 @@ + + + + @@ -2019,6 +2027,18 @@ Name="CSM" > + + + + + +