| /* |
| --------------------------------------------------------------------------- |
| Open Asset Import Library (assimp) |
| --------------------------------------------------------------------------- |
| |
| Copyright (c) 2006-2017, 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 |
| 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 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 Implementation of the LWO importer class for the older LWOB |
| file formats, including materials */ |
| |
| |
| #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER |
| |
| // Internal headers |
| #include "LWOLoader.h" |
| 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; |
| 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; |
| |
| // perform endianness conversions |
| #ifndef AI_BUILD_BIG_ENDIAN |
| while (cursor < end)ByteSwap::Swap2(cursor++); |
| cursor = (LE_NCONST uint16_t*)mFileBuffer; |
| #endif |
| |
| 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; |
| |
| 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) |
| { |
| 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) |
| { |
| 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; |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| 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 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 |