nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file Implementation of the LWO importer class for the older LWOB nuclear@0: file formats, including materials */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER nuclear@0: nuclear@0: // Internal headers nuclear@0: #include "LWOLoader.h" nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void LWOImporter::LoadLWOBFile() nuclear@0: { nuclear@0: LE_NCONST uint8_t* const end = mFileBuffer + fileSize; nuclear@0: bool running = true; nuclear@0: while (running) nuclear@0: { nuclear@0: if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; nuclear@0: LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer); nuclear@0: nuclear@0: if (mFileBuffer + head->length > end) nuclear@0: { nuclear@0: throw DeadlyImportError("LWOB: Invalid chunk length"); nuclear@0: break; nuclear@0: } nuclear@0: uint8_t* const next = mFileBuffer+head->length; nuclear@0: switch (head->type) nuclear@0: { nuclear@0: // vertex list nuclear@0: case AI_LWO_PNTS: nuclear@0: { nuclear@0: if (!mCurLayer->mTempPoints.empty()) nuclear@0: DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice"); nuclear@0: else LoadLWOPoints(head->length); nuclear@0: break; nuclear@0: } nuclear@0: // face list nuclear@0: case AI_LWO_POLS: nuclear@0: { nuclear@0: if (!mCurLayer->mFaces.empty()) nuclear@0: DefaultLogger::get()->warn("LWO: POLS chunk encountered twice"); nuclear@0: else LoadLWOBPolygons(head->length); nuclear@0: break; nuclear@0: } nuclear@0: // list of tags nuclear@0: case AI_LWO_SRFS: nuclear@0: { nuclear@0: if (!mTags->empty()) nuclear@0: DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice"); nuclear@0: else LoadLWOTags(head->length); nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: // surface chunk nuclear@0: case AI_LWO_SURF: nuclear@0: { nuclear@0: LoadLWOBSurface(head->length); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: mFileBuffer = next; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void LWOImporter::LoadLWOBPolygons(unsigned int length) nuclear@0: { nuclear@0: // first find out how many faces and vertices we'll finally need nuclear@0: LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length); nuclear@0: LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer; nuclear@0: nuclear@0: // perform endianess conversions nuclear@0: #ifndef AI_BUILD_BIG_ENDIAN nuclear@0: while (cursor < end)ByteSwap::Swap2(cursor++); nuclear@0: cursor = (LE_NCONST uint16_t*)mFileBuffer; nuclear@0: #endif nuclear@0: nuclear@0: unsigned int iNumFaces = 0,iNumVertices = 0; nuclear@0: CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end); nuclear@0: nuclear@0: // allocate the output array and copy face indices nuclear@0: if (iNumFaces) nuclear@0: { nuclear@0: cursor = (LE_NCONST uint16_t*)mFileBuffer; nuclear@0: nuclear@0: mCurLayer->mFaces.resize(iNumFaces); nuclear@0: FaceList::iterator it = mCurLayer->mFaces.begin(); nuclear@0: CopyFaceIndicesLWOB(it,cursor,end); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& faces, nuclear@0: LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max) nuclear@0: { nuclear@0: while (cursor < end && max--) nuclear@0: { nuclear@0: uint16_t numIndices = *cursor++; nuclear@0: verts += numIndices;faces++; nuclear@0: cursor += numIndices; nuclear@0: int16_t surface = *cursor++; nuclear@0: if (surface < 0) nuclear@0: { nuclear@0: // there are detail polygons nuclear@0: numIndices = *cursor++; nuclear@0: CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it, nuclear@0: LE_NCONST uint16_t*& cursor, nuclear@0: const uint16_t* const end, nuclear@0: unsigned int max) nuclear@0: { nuclear@0: while (cursor < end && max--) nuclear@0: { nuclear@0: LWO::Face& face = *it;++it; nuclear@0: if((face.mNumIndices = *cursor++)) nuclear@0: { nuclear@0: if (cursor + face.mNumIndices >= end)break; nuclear@0: face.mIndices = new unsigned int[face.mNumIndices]; nuclear@0: for (unsigned int i = 0; i < face.mNumIndices;++i) nuclear@0: { nuclear@0: unsigned int & mi = face.mIndices[i] = *cursor++; nuclear@0: if (mi > mCurLayer->mTempPoints.size()) nuclear@0: { nuclear@0: DefaultLogger::get()->warn("LWOB: face index is out of range"); nuclear@0: mi = (unsigned int)mCurLayer->mTempPoints.size()-1; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("LWOB: Face has 0 indices"); nuclear@0: int16_t surface = *cursor++; nuclear@0: if (surface < 0) nuclear@0: { nuclear@0: surface = -surface; nuclear@0: nuclear@0: // there are detail polygons. nuclear@0: const uint16_t numPolygons = *cursor++; nuclear@0: if (cursor < end)CopyFaceIndicesLWOB(it,cursor,end,numPolygons); nuclear@0: } nuclear@0: face.surfaceIndex = surface-1; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned int size) nuclear@0: { nuclear@0: list.push_back(LWO::Texture()); nuclear@0: LWO::Texture* tex = &list.back(); nuclear@0: nuclear@0: std::string type; nuclear@0: GetS0(type,size); nuclear@0: const char* s = type.c_str(); nuclear@0: nuclear@0: if(strstr(s, "Image Map")) nuclear@0: { nuclear@0: // Determine mapping type nuclear@0: if(strstr(s, "Planar")) nuclear@0: tex->mapMode = LWO::Texture::Planar; nuclear@0: else if(strstr(s, "Cylindrical")) nuclear@0: tex->mapMode = LWO::Texture::Cylindrical; nuclear@0: else if(strstr(s, "Spherical")) nuclear@0: tex->mapMode = LWO::Texture::Spherical; nuclear@0: else if(strstr(s, "Cubic")) nuclear@0: tex->mapMode = LWO::Texture::Cubic; nuclear@0: else if(strstr(s, "Front")) nuclear@0: tex->mapMode = LWO::Texture::FrontProjection; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: // procedural or gradient, not supported nuclear@0: DefaultLogger::get()->error("LWOB: Unsupported legacy texture: " + type); nuclear@0: } nuclear@0: nuclear@0: return tex; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void LWOImporter::LoadLWOBSurface(unsigned int size) nuclear@0: { nuclear@0: LE_NCONST uint8_t* const end = mFileBuffer + size; nuclear@0: nuclear@0: mSurfaces->push_back( LWO::Surface () ); nuclear@0: LWO::Surface& surf = mSurfaces->back(); nuclear@0: LWO::Texture* pTex = NULL; nuclear@0: nuclear@0: GetS0(surf.mName,size); nuclear@0: bool runnning = true; nuclear@0: while (runnning) { nuclear@0: if (mFileBuffer + 6 >= end) nuclear@0: break; nuclear@0: nuclear@0: IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer); nuclear@0: nuclear@0: /* A single test file (sonycam.lwo) seems to have invalid surface chunks. nuclear@0: * I'm assuming it's the fault of a single, unknown exporter so there are nuclear@0: * probably THOUSANDS of them. Here's a dirty workaround: nuclear@0: * nuclear@0: * We don't break if the chunk limit is exceeded. Instead, we're computing nuclear@0: * how much storage is actually left and work with this value from now on. nuclear@0: */ nuclear@0: if (mFileBuffer + head->length > end) { nuclear@0: DefaultLogger::get()->error("LWOB: Invalid surface chunk length. Trying to continue."); nuclear@0: head->length = (uint16_t) (end - mFileBuffer); nuclear@0: } nuclear@0: nuclear@0: uint8_t* const next = mFileBuffer+head->length; nuclear@0: switch (head->type) nuclear@0: { nuclear@0: // diffuse color nuclear@0: case AI_LWO_COLR: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,3); nuclear@0: surf.mColor.r = GetU1() / 255.0f; nuclear@0: surf.mColor.g = GetU1() / 255.0f; nuclear@0: surf.mColor.b = GetU1() / 255.0f; nuclear@0: break; nuclear@0: } nuclear@0: // diffuse strength ... nuclear@0: case AI_LWO_DIFF: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,2); nuclear@0: surf.mDiffuseValue = GetU2() / 255.0f; nuclear@0: break; nuclear@0: } nuclear@0: // specular strength ... nuclear@0: case AI_LWO_SPEC: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,2); nuclear@0: surf.mSpecularValue = GetU2() / 255.0f; nuclear@0: break; nuclear@0: } nuclear@0: // luminosity ... nuclear@0: case AI_LWO_LUMI: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LUMI,2); nuclear@0: surf.mLuminosity = GetU2() / 255.0f; nuclear@0: break; nuclear@0: } nuclear@0: // transparency nuclear@0: case AI_LWO_TRAN: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,2); nuclear@0: surf.mTransparency = GetU2() / 255.0f; nuclear@0: break; nuclear@0: } nuclear@0: // surface flags nuclear@0: case AI_LWO_FLAG: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,FLAG,2); nuclear@0: uint16_t flag = GetU2(); nuclear@0: if (flag & 0x4 ) surf.mMaximumSmoothAngle = 1.56207f; nuclear@0: if (flag & 0x8 ) surf.mColorHighlights = 1.f; nuclear@0: if (flag & 0x100) surf.bDoubleSided = true; nuclear@0: break; nuclear@0: } nuclear@0: // maximum smoothing angle nuclear@0: case AI_LWO_SMAN: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4); nuclear@0: surf.mMaximumSmoothAngle = fabs( GetF4() ); nuclear@0: break; nuclear@0: } nuclear@0: // glossiness nuclear@0: case AI_LWO_GLOS: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,2); nuclear@0: surf.mGlossiness = (float)GetU2(); nuclear@0: break; nuclear@0: } nuclear@0: // color texture nuclear@0: case AI_LWO_CTEX: nuclear@0: { nuclear@0: pTex = SetupNewTextureLWOB(surf.mColorTextures, nuclear@0: head->length); nuclear@0: break; nuclear@0: } nuclear@0: // diffuse texture nuclear@0: case AI_LWO_DTEX: nuclear@0: { nuclear@0: pTex = SetupNewTextureLWOB(surf.mDiffuseTextures, nuclear@0: head->length); nuclear@0: break; nuclear@0: } nuclear@0: // specular texture nuclear@0: case AI_LWO_STEX: nuclear@0: { nuclear@0: pTex = SetupNewTextureLWOB(surf.mSpecularTextures, nuclear@0: head->length); nuclear@0: break; nuclear@0: } nuclear@0: // bump texture nuclear@0: case AI_LWO_BTEX: nuclear@0: { nuclear@0: pTex = SetupNewTextureLWOB(surf.mBumpTextures, nuclear@0: head->length); nuclear@0: break; nuclear@0: } nuclear@0: // transparency texture nuclear@0: case AI_LWO_TTEX: nuclear@0: { nuclear@0: pTex = SetupNewTextureLWOB(surf.mOpacityTextures, nuclear@0: head->length); nuclear@0: break; nuclear@0: } nuclear@0: // texture path nuclear@0: case AI_LWO_TIMG: nuclear@0: { nuclear@0: if (pTex) { nuclear@0: GetS0(pTex->mFileName,head->length); nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("LWOB: Unexpected TIMG chunk"); nuclear@0: break; nuclear@0: } nuclear@0: // texture strength nuclear@0: case AI_LWO_TVAL: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TVAL,1); nuclear@0: if (pTex) { nuclear@0: pTex->mStrength = (float)GetU1()/ 255.f; nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("LWOB: Unexpected TVAL chunk"); nuclear@0: break; nuclear@0: } nuclear@0: // texture flags nuclear@0: case AI_LWO_TFLG: nuclear@0: { nuclear@0: AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TFLG,2); nuclear@0: nuclear@0: if (pTex) nuclear@0: { nuclear@0: const uint16_t s = GetU2(); nuclear@0: if (s & 1) nuclear@0: pTex->majorAxis = LWO::Texture::AXIS_X; nuclear@0: else if (s & 2) nuclear@0: pTex->majorAxis = LWO::Texture::AXIS_Y; nuclear@0: else if (s & 4) nuclear@0: pTex->majorAxis = LWO::Texture::AXIS_Z; nuclear@0: nuclear@0: if (s & 16) nuclear@0: DefaultLogger::get()->warn("LWOB: Ignoring \'negate\' flag on texture"); nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("LWOB: Unexpected TFLG chunk"); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: mFileBuffer = next; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: #endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER