diff options
Diffstat (limited to 'src/3rdparty/assimp/code/LWOBLoader.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/LWOBLoader.cpp | 664 |
1 files changed, 345 insertions, 319 deletions
diff --git a/src/3rdparty/assimp/code/LWOBLoader.cpp b/src/3rdparty/assimp/code/LWOBLoader.cpp index 9776b8976..639675294 100644 --- a/src/3rdparty/assimp/code/LWOBLoader.cpp +++ b/src/3rdparty/assimp/code/LWOBLoader.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp 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 +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 @@ -25,24 +25,24 @@ conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +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 +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 +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 +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 Implementation of the LWO importer class for the older LWOB +/** @file Implementation of the LWO importer class for the older LWOB file formats, including materials */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER // Internal headers @@ -53,344 +53,370 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ void LWOImporter::LoadLWOBFile() { - LE_NCONST uint8_t* const end = mFileBuffer + fileSize; - bool running = true; - while (running) - { - if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; - LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer); - - if (mFileBuffer + head->length > end) - { - throw DeadlyImportError("LWOB: Invalid chunk length"); - break; - } - uint8_t* const next = mFileBuffer+head->length; - switch (head->type) - { - // vertex list - case AI_LWO_PNTS: - { - if (!mCurLayer->mTempPoints.empty()) - DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice"); - else LoadLWOPoints(head->length); - break; - } - // face list - case AI_LWO_POLS: - { - if (!mCurLayer->mFaces.empty()) - DefaultLogger::get()->warn("LWO: POLS chunk encountered twice"); - else LoadLWOBPolygons(head->length); - break; - } - // list of tags - case AI_LWO_SRFS: - { - if (!mTags->empty()) - DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice"); - else LoadLWOTags(head->length); - break; - } - - // surface chunk - case AI_LWO_SURF: - { - LoadLWOBSurface(head->length); - break; - } - } - mFileBuffer = next; - } + LE_NCONST uint8_t* const end = mFileBuffer + fileSize; + bool running = true; + while (running) + { + if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; + const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); + + if (mFileBuffer + head.length > end) + { + throw DeadlyImportError("LWOB: Invalid chunk length"); + break; + } + uint8_t* const next = mFileBuffer+head.length; + switch (head.type) + { + // vertex list + case AI_LWO_PNTS: + { + if (!mCurLayer->mTempPoints.empty()) + DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice"); + else LoadLWOPoints(head.length); + break; + } + // face list + case AI_LWO_POLS: + { + + if (!mCurLayer->mFaces.empty()) + DefaultLogger::get()->warn("LWO: POLS chunk encountered twice"); + else LoadLWOBPolygons(head.length); + break; + } + // list of tags + case AI_LWO_SRFS: + { + if (!mTags->empty()) + DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice"); + else LoadLWOTags(head.length); + break; + } + + // surface chunk + case AI_LWO_SURF: + { + LoadLWOBSurface(head.length); + break; + } + } + mFileBuffer = next; + } } // ------------------------------------------------------------------------------------------------ void LWOImporter::LoadLWOBPolygons(unsigned int length) { - // first find out how many faces and vertices we'll finally need - LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length); - LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer; + // first find out how many faces and vertices we'll finally need + LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length); + LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer; - // perform endianess conversions + // perform endianness conversions #ifndef AI_BUILD_BIG_ENDIAN - while (cursor < end)ByteSwap::Swap2(cursor++); - cursor = (LE_NCONST uint16_t*)mFileBuffer; + while (cursor < end)ByteSwap::Swap2(cursor++); + cursor = (LE_NCONST uint16_t*)mFileBuffer; #endif - unsigned int iNumFaces = 0,iNumVertices = 0; - CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end); + unsigned int iNumFaces = 0,iNumVertices = 0; + CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end); - // allocate the output array and copy face indices - if (iNumFaces) - { - cursor = (LE_NCONST uint16_t*)mFileBuffer; + // allocate the output array and copy face indices + if (iNumFaces) + { + cursor = (LE_NCONST uint16_t*)mFileBuffer; - mCurLayer->mFaces.resize(iNumFaces); - FaceList::iterator it = mCurLayer->mFaces.begin(); - CopyFaceIndicesLWOB(it,cursor,end); - } + mCurLayer->mFaces.resize(iNumFaces); + FaceList::iterator it = mCurLayer->mFaces.begin(); + CopyFaceIndicesLWOB(it,cursor,end); + } } // ------------------------------------------------------------------------------------------------ void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& faces, - LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max) + LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max) { - while (cursor < end && max--) - { - uint16_t numIndices = *cursor++; - verts += numIndices;faces++; - cursor += numIndices; - int16_t surface = *cursor++; - if (surface < 0) - { - // there are detail polygons - numIndices = *cursor++; - CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices); - } - } + while (cursor < end && max--) + { + uint16_t numIndices; + // must have 2 shorts left for numIndices and surface + if (end - cursor < 2) { + throw DeadlyImportError("LWOB: Unexpected end of file"); + } + ::memcpy(&numIndices, cursor++, 2); + // must have enough left for indices and surface + if (end - cursor < (1 + numIndices)) { + throw DeadlyImportError("LWOB: Unexpected end of file"); + } + verts += numIndices; + faces++; + cursor += numIndices; + int16_t surface; + ::memcpy(&surface, cursor++, 2); + if (surface < 0) + { + // there are detail polygons + ::memcpy(&numIndices, cursor++, 2); + CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices); + } + } } // ------------------------------------------------------------------------------------------------ void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it, - LE_NCONST uint16_t*& cursor, - const uint16_t* const end, - unsigned int max) + LE_NCONST uint16_t*& cursor, + const uint16_t* const end, + unsigned int max) { - while (cursor < end && max--) - { - LWO::Face& face = *it;++it; - if((face.mNumIndices = *cursor++)) - { - if (cursor + face.mNumIndices >= end)break; - face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int i = 0; i < face.mNumIndices;++i) - { - unsigned int & mi = face.mIndices[i] = *cursor++; - if (mi > mCurLayer->mTempPoints.size()) - { - DefaultLogger::get()->warn("LWOB: face index is out of range"); - mi = (unsigned int)mCurLayer->mTempPoints.size()-1; - } - } - } - else DefaultLogger::get()->warn("LWOB: Face has 0 indices"); - int16_t surface = *cursor++; - if (surface < 0) - { - surface = -surface; - - // there are detail polygons. - const uint16_t numPolygons = *cursor++; - if (cursor < end)CopyFaceIndicesLWOB(it,cursor,end,numPolygons); - } - face.surfaceIndex = surface-1; - } + while (cursor < end && max--) + { + LWO::Face& face = *it;++it; + uint16_t numIndices; + ::memcpy(&numIndices, cursor++, 2); + face.mNumIndices = numIndices; + if(face.mNumIndices) + { + if (cursor + face.mNumIndices >= end) + { + break; + } + face.mIndices = new unsigned int[face.mNumIndices]; + for (unsigned int i = 0; i < face.mNumIndices;++i) + { + unsigned int & mi = face.mIndices[i]; + uint16_t index; + ::memcpy(&index, cursor++, 2); + mi = index; + if (mi > mCurLayer->mTempPoints.size()) + { + DefaultLogger::get()->warn("LWOB: face index is out of range"); + mi = (unsigned int)mCurLayer->mTempPoints.size()-1; + } + } + } + else DefaultLogger::get()->warn("LWOB: Face has 0 indices"); + int16_t surface; + ::memcpy(&surface, cursor++, 2); + if (surface < 0) + { + surface = -surface; + + // there are detail polygons. + uint16_t numPolygons; + ::memcpy(&numPolygons, cursor++, 2); + if (cursor < end) + { + CopyFaceIndicesLWOB(it,cursor,end,numPolygons); + } + } + face.surfaceIndex = surface-1; + } } // ------------------------------------------------------------------------------------------------ LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned int size) { - list.push_back(LWO::Texture()); - LWO::Texture* tex = &list.back(); - - 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; + list.push_back(LWO::Texture()); + LWO::Texture* tex = &list.back(); + + 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; } // ------------------------------------------------------------------------------------------------ void LWOImporter::LoadLWOBSurface(unsigned int size) { - LE_NCONST uint8_t* const end = mFileBuffer + size; - - mSurfaces->push_back( LWO::Surface () ); - LWO::Surface& surf = mSurfaces->back(); - LWO::Texture* pTex = NULL; - - GetS0(surf.mName,size); - bool runnning = true; - while (runnning) { - if (mFileBuffer + 6 >= end) - break; - - IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer); - - /* A single test file (sonycam.lwo) seems to have invalid surface chunks. - * I'm assuming it's the fault of a single, unknown exporter so there are - * probably THOUSANDS of them. Here's a dirty workaround: - * - * We don't break if the chunk limit is exceeded. Instead, we're computing - * how much storage is actually left and work with this value from now on. - */ - if (mFileBuffer + head->length > end) { - DefaultLogger::get()->error("LWOB: Invalid surface chunk length. Trying to continue."); - head->length = (uint16_t) (end - mFileBuffer); - } - - uint8_t* const next = mFileBuffer+head->length; - switch (head->type) - { - // diffuse color - case AI_LWO_COLR: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,3); - surf.mColor.r = GetU1() / 255.0f; - surf.mColor.g = GetU1() / 255.0f; - surf.mColor.b = GetU1() / 255.0f; - break; - } - // diffuse strength ... - case AI_LWO_DIFF: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,2); - surf.mDiffuseValue = GetU2() / 255.0f; - break; - } - // specular strength ... - case AI_LWO_SPEC: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,2); - surf.mSpecularValue = GetU2() / 255.0f; - break; - } - // luminosity ... - case AI_LWO_LUMI: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LUMI,2); - surf.mLuminosity = GetU2() / 255.0f; - break; - } - // transparency - case AI_LWO_TRAN: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,2); - surf.mTransparency = GetU2() / 255.0f; - break; - } - // surface flags - case AI_LWO_FLAG: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,FLAG,2); - uint16_t flag = GetU2(); - if (flag & 0x4 ) surf.mMaximumSmoothAngle = 1.56207f; - if (flag & 0x8 ) surf.mColorHighlights = 1.f; - if (flag & 0x100) surf.bDoubleSided = true; - break; - } - // maximum smoothing angle - case AI_LWO_SMAN: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4); - surf.mMaximumSmoothAngle = std::fabs( GetF4() ); - break; - } - // glossiness - case AI_LWO_GLOS: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,2); - surf.mGlossiness = (float)GetU2(); - break; - } - // color texture - case AI_LWO_CTEX: - { - pTex = SetupNewTextureLWOB(surf.mColorTextures, - head->length); - break; - } - // diffuse texture - case AI_LWO_DTEX: - { - pTex = SetupNewTextureLWOB(surf.mDiffuseTextures, - head->length); - break; - } - // specular texture - case AI_LWO_STEX: - { - pTex = SetupNewTextureLWOB(surf.mSpecularTextures, - head->length); - break; - } - // bump texture - case AI_LWO_BTEX: - { - pTex = SetupNewTextureLWOB(surf.mBumpTextures, - head->length); - break; - } - // transparency texture - case AI_LWO_TTEX: - { - pTex = SetupNewTextureLWOB(surf.mOpacityTextures, - head->length); - break; - } - // texture path - case AI_LWO_TIMG: - { - if (pTex) { - GetS0(pTex->mFileName,head->length); - } - else DefaultLogger::get()->warn("LWOB: Unexpected TIMG chunk"); - break; - } - // texture strength - case AI_LWO_TVAL: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TVAL,1); - if (pTex) { - pTex->mStrength = (float)GetU1()/ 255.f; - } - 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; - } - } - mFileBuffer = next; - } + LE_NCONST uint8_t* const end = mFileBuffer + size; + + mSurfaces->push_back( LWO::Surface () ); + LWO::Surface& surf = mSurfaces->back(); + LWO::Texture* pTex = NULL; + + GetS0(surf.mName,size); + bool running = true; + while (running) { + if (mFileBuffer + 6 >= end) + break; + + IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); + + /* A single test file (sonycam.lwo) seems to have invalid surface chunks. + * I'm assuming it's the fault of a single, unknown exporter so there are + * probably THOUSANDS of them. Here's a dirty workaround: + * + * We don't break if the chunk limit is exceeded. Instead, we're computing + * how much storage is actually left and work with this value from now on. + */ + if (mFileBuffer + head.length > end) { + DefaultLogger::get()->error("LWOB: Invalid surface chunk length. Trying to continue."); + head.length = (uint16_t) (end - mFileBuffer); + } + + uint8_t* const next = mFileBuffer+head.length; + switch (head.type) + { + // diffuse color + case AI_LWO_COLR: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,3); + surf.mColor.r = GetU1() / 255.0f; + surf.mColor.g = GetU1() / 255.0f; + surf.mColor.b = GetU1() / 255.0f; + break; + } + // diffuse strength ... + case AI_LWO_DIFF: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,2); + surf.mDiffuseValue = GetU2() / 255.0f; + break; + } + // specular strength ... + case AI_LWO_SPEC: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,2); + surf.mSpecularValue = GetU2() / 255.0f; + break; + } + // luminosity ... + case AI_LWO_LUMI: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LUMI,2); + surf.mLuminosity = GetU2() / 255.0f; + break; + } + // transparency + case AI_LWO_TRAN: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,2); + surf.mTransparency = GetU2() / 255.0f; + break; + } + // surface flags + case AI_LWO_FLAG: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,FLAG,2); + uint16_t flag = GetU2(); + if (flag & 0x4 ) surf.mMaximumSmoothAngle = 1.56207f; + if (flag & 0x8 ) surf.mColorHighlights = 1.f; + if (flag & 0x100) surf.bDoubleSided = true; + break; + } + // maximum smoothing angle + case AI_LWO_SMAN: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4); + surf.mMaximumSmoothAngle = std::fabs( GetF4() ); + break; + } + // glossiness + case AI_LWO_GLOS: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,2); + surf.mGlossiness = (float)GetU2(); + break; + } + // color texture + case AI_LWO_CTEX: + { + pTex = SetupNewTextureLWOB(surf.mColorTextures, + head.length); + break; + } + // diffuse texture + case AI_LWO_DTEX: + { + pTex = SetupNewTextureLWOB(surf.mDiffuseTextures, + head.length); + break; + } + // specular texture + case AI_LWO_STEX: + { + pTex = SetupNewTextureLWOB(surf.mSpecularTextures, + head.length); + break; + } + // bump texture + case AI_LWO_BTEX: + { + pTex = SetupNewTextureLWOB(surf.mBumpTextures, + head.length); + break; + } + // transparency texture + case AI_LWO_TTEX: + { + pTex = SetupNewTextureLWOB(surf.mOpacityTextures, + head.length); + break; + } + // texture path + case AI_LWO_TIMG: + { + if (pTex) { + GetS0(pTex->mFileName,head.length); + } + else DefaultLogger::get()->warn("LWOB: Unexpected TIMG chunk"); + break; + } + // texture strength + case AI_LWO_TVAL: + { + AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TVAL,1); + if (pTex) { + pTex->mStrength = (float)GetU1()/ 255.f; + } + 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; + } + } + mFileBuffer = next; + } } #endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER |