Next WIP version of the LWO loader. LWO2 is still unfinished and crashes every time.

Added NFF test model.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@123 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2008-09-08 16:48:21 +00:00
parent d38e83766b
commit af18307f95
9 changed files with 790 additions and 271 deletions

308
code/LWOBLoader.cpp 100644
View File

@ -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 Implementation of the LWO importer class for the older LWOB
file formats, including materials */
// internal headers
#include "LWOLoader.h"
#include "MaterialSystem.h"
#include "ByteSwap.h"
// public assimp headers
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/DefaultLogger.h"
#include "../include/assimp.hpp"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOBFile()
{
LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
while (true)
{
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
LE_NCONST IFF::ChunkHeader* const head = (LE_NCONST IFF::ChunkHeader*)mFileBuffer;
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
mFileBuffer += sizeof(IFF::ChunkHeader);
if (mFileBuffer + head->length > end)
{
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
"a chunk points behind the end of the file");
break;
}
LE_NCONST 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 LoadLWOPolygons(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:
{
if (!mSurfaces->empty())
DefaultLogger::get()->warn("LWO: SURF chunk encountered twice");
else LoadLWOBSurface(head->length);
break;
}
}
mFileBuffer = next;
}
}
// ------------------------------------------------------------------------------------------------
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 = *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);
}
}
}
// ------------------------------------------------------------------------------------------------
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;
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
uint16_t numPolygons = *cursor++;
if (cursor < end)CopyFaceIndicesLWOB(it,cursor,end,numPolygons);
}
face.surfaceIndex = surface-1;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOBSurface(unsigned int size)
{
LE_NCONST uint8_t* const end = mFileBuffer + size;
uint32_t iCursor = 0;
mSurfaces->push_back( LWO::Surface () );
LWO::Surface& surf = mSurfaces->back();
LWO::Texture* pTex = NULL;
ParseString(surf.mName,size);
mFileBuffer+=surf.mName.length()+1;
// skip one byte if the length of the surface name is odd
if (!(surf.mName.length() & 1))++mFileBuffer;
while (true)
{
if (mFileBuffer + 6 > end)break;
// no proper IFF header here - the chunk length is specified as int16
uint32_t head_type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
uint16_t head_length = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2;
AI_LSWAP4(head_type);
AI_LSWAP2(head_length);
if (mFileBuffer + head_length > end)
{
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
"a surface sub chunk points behind the end of the file");
}
LE_NCONST 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 = *mFileBuffer++ / 255.0f;
surf.mColor.g = *mFileBuffer++ / 255.0f;
surf.mColor.b = *mFileBuffer / 255.0f;
break;
}
// diffuse strength ...
case AI_LWO_DIFF:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,DIFF,2);
AI_LSWAP2P(mFileBuffer);
surf.mDiffuseValue = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// specular strength ...
case AI_LWO_SPEC:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,SPEC,2);
AI_LSWAP2P(mFileBuffer);
surf.mSpecularValue = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// luminosity ...
case AI_LWO_LUMI:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,LUMI,2);
AI_LSWAP2P(mFileBuffer);
surf.mLuminosity = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// transparency
case AI_LWO_TRAN:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TRAN,2);
AI_LSWAP2P(mFileBuffer);
surf.mTransparency = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// glossiness
case AI_LWO_GLOS:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,GLOS,2);
AI_LSWAP2P(mFileBuffer);
surf.mGlossiness = float(*((int16_t*)mFileBuffer));
break;
}
// color texture
case AI_LWO_CTEX:
{
pTex = &surf.mColorTexture;
break;
}
// diffuse texture
case AI_LWO_DTEX:
{
pTex = &surf.mDiffuseTexture;
break;
}
// specular texture
case AI_LWO_STEX:
{
pTex = &surf.mSpecularTexture;
break;
}
// bump texture
case AI_LWO_BTEX:
{
pTex = &surf.mBumpTexture;
break;
}
// transparency texture
case AI_LWO_TTEX:
{
pTex = &surf.mTransparencyTexture;
break;
}
// texture path
case AI_LWO_TIMG:
{
if (pTex)
{
ParseString(pTex->mFileName,head_length);
AdjustTexturePath(pTex->mFileName);
mFileBuffer += pTex->mFileName.length();
}
else DefaultLogger::get()->warn("LWOB: TIMG tag was encuntered although "
"there was no xTEX tag before");
break;
}
// texture strength
case AI_LWO_TVAL:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TVAL,1);
if (pTex)pTex->mStrength = *mFileBuffer / 255.0f;
else DefaultLogger::get()->warn("LWOB: TVAL tag was encuntered "
"although there was no xTEX tag before");
break;
}
}
mFileBuffer = next;
}
}

View File

@ -49,12 +49,17 @@ Original copyright notice: "Ernie Wright 17 Sep 00"
#ifndef AI_LWO_FILEDATA_INCLUDED
#define AI_LWO_FILEDATA_INCLUDED
#include "IFF.h"
// STL headers
#include <vector>
#include <list>
// public ASSIMP headers
#include "../include/aiMesh.h"
// internal headers
#include "IFF.h"
#include "SmoothingGroups.h"
namespace Assimp {
namespace LWO {
@ -232,15 +237,94 @@ namespace LWO {
#define AI_LWO_DATA AI_IFF_FOURCC('D','A','T','A')
/* VMAP types */
#define AI_LWO_TXUV AI_IFF_FOURCC('T','X','U','V')
#define AI_LWO_RGB AI_IFF_FOURCC(' ','R','G','B')
#define AI_LWO_RGBA AI_IFF_FOURCC('R','G','B','A')
#define AI_LWO_WGHT AI_IFF_FOURCC('W','G','H','T')
// ---------------------------------------------------------------------------
/** \brief Data structure for a face in a LWO file
*
* \note We can't use the code in SmoothingGroups.inl here - the mesh
* structures of 3DS/ASE and LWO are too different.
*/
struct Face : public aiFace
{
Face() : surfaceIndex(0) {}
Face()
: surfaceIndex(0)
, smoothGroup(0)
{}
unsigned int surfaceIndex;
unsigned int smoothGroup;
};
// ---------------------------------------------------------------------------
/** \brief Base structure for all vertex map representations
*/
struct VMapEntry
{
VMapEntry(unsigned int _dims)
: dims(_dims)
{}
~VMapEntry() {delete[] rawData;}
std::string name;
float* rawData;
unsigned int dims;
};
// ---------------------------------------------------------------------------
/** \brief Represents an extra vertex color channel
*/
struct VColorChannel : public VMapEntry
{
VColorChannel(unsigned int num)
: VMapEntry(4)
{
data = new aiColor4D[num];
for (unsigned int i = 0; i < num;++i)
data[i].a = 1.0f;
rawData = (float*)data;
}
aiColor4D* data;
};
// ---------------------------------------------------------------------------
/** \brief Represents an extra vertex UV channel
*/
struct UVChannel : public VMapEntry
{
UVChannel(unsigned int num)
: VMapEntry(3)
{
data = new aiVector3D[num]; // to make the final copying easier
rawData = (float*)data;
}
aiVector3D* data;
};
// ---------------------------------------------------------------------------
/** \brief Represents a weight map
*/
struct WeightChannel : public VMapEntry
{
WeightChannel(unsigned int num)
: VMapEntry(1)
{
rawData = new float[num];
for (unsigned int m = 0; m < num;++m)
rawData[m] = 0.f;
}
};
// ---------------------------------------------------------------------------
/** \brief LWO2 gradient keyframe
*/
@ -272,7 +356,8 @@ struct GradientInfo
struct Texture
{
Texture()
: mStrength(1.0f)
: mStrength (1.0f)
, iUVChannelIndex (0)
{}
//! File name of the texture
@ -285,6 +370,8 @@ struct Texture
/*************** SPECIFIC TO LWO2 *********************/
uint32_t type; // type of the texture
//! Index of the corresponding UV channel
unsigned int iUVChannelIndex;
GradientInfo mGradient;
// todo ... maybe support for procedurals?
@ -336,11 +423,15 @@ struct Surface
} \
typedef std::vector<aiVector3D> PointList;
typedef std::vector<LWO::Face> FaceList;
typedef std::vector<LWO::Surface> SurfaceList;
typedef std::vector<std::string> TagList;
typedef std::vector<unsigned int> TagMappingTable;
// some typedefs ... to make life with loader monsters like this easier
typedef std::vector < aiVector3D > PointList;
typedef std::vector < LWO::Face > FaceList;
typedef std::vector < LWO::Surface > SurfaceList;
typedef std::vector < std::string > TagList;
typedef std::vector < unsigned int > TagMappingTable;
typedef std::vector < WeightChannel > WeightChannelList;
typedef std::vector < VColorChannel > VColorChannelList;
typedef std::vector < UVChannel > UVChannelList;
// ---------------------------------------------------------------------------
@ -350,14 +441,31 @@ struct Layer
{
Layer()
: mParent (0xffff)
, mFaceIDXOfs(0)
, mPointIDXOfs(0)
{}
/** Temporary point list from the file */
PointList mTempPoints;
/** Weight channel list from the file */
WeightChannelList mWeightChannels;
/** Vertex color list from the file */
VColorChannelList mVColorChannels;
/** UV channel list from the file */
UVChannelList mUVChannels;
/** Temporary face list from the file*/
FaceList mFaces;
/** Current face indexing offset from the beginning of the buffers*/
unsigned int mFaceIDXOfs;
/** Current point indexing offset from the beginning of the buffers*/
unsigned int mPointIDXOfs;
/** Parent index */
uint16_t mParent;

View File

@ -153,7 +153,6 @@ void LWOImporter::InternReadFile( const std::string& pFile,
// new lightwave format
else if (AI_LWO_FOURCC_LWO2 == fileType)
{
throw new ImportErrorException("LWO2 is under development and currently disabled.");
mIsLWO2 = true;
this->LoadLWO2File();
}
@ -252,6 +251,39 @@ void LWOImporter::InternReadFile( const std::string& pFile,
aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
mesh->mMaterialIndex = i;
// find out which vertex color channels and which texture coordinate
// channels are really required by the material attached to this mesh
unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
#if _DEBUG
for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui )
vUVChannelIndices[mui] = 0xffffffff;
for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui )
vVColorIndices[mui] = 0xffffffff;
#endif
FindUVChannels(_mSurfaces[i],layer,vUVChannelIndices);
FindVCChannels(_mSurfaces[i],layer,vVColorIndices);
// allocate storage for UV and CV channels
aiVector3D* pvUV[AI_MAX_NUMBER_OF_TEXTURECOORDS];
for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui )
{
if (0xffffffff == vUVChannelIndices[mui])break;
pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices];
// LightWave doesn't support more than 2 UV components
mesh->mNumUVComponents[0] = 2;
}
aiColor4D* pvVC[AI_MAX_NUMBER_OF_COLOR_SETS];
for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui)
{
if (0xffffffff == vVColorIndices[mui])break;
pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices];
}
// now convert all faces
unsigned int vert = 0;
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
@ -262,7 +294,29 @@ void LWOImporter::InternReadFile( const std::string& pFile,
// copy all vertices
for (unsigned int q = 0; q < face.mNumIndices;++q)
{
*pv++ = layer.mTempPoints[face.mIndices[q]];
register unsigned int idx = face.mIndices[q];
*pv++ = layer.mTempPoints[idx];
// process UV coordinates
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w)
{
if (0xffffffff == vUVChannelIndices[w])break;
*(pvUV[w])++ = layer.mUVChannels[vUVChannelIndices[w]].data[idx];
}
// process vertex colors
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w)
{
if (0xffffffff == vVColorIndices[w])break;
*(pvVC[w])++ = layer.mVColorChannels[vVColorIndices[w]].data[idx];
}
#if 0
// process vertex weights - not yet supported
for (unsigned int w = 0; w < layer.mWeightChannels.size();++w)
{
}
#endif
face.mIndices[q] = vert++;
}
@ -376,65 +430,10 @@ void LWOImporter::GenerateNodeGraph(std::vector<aiNode*>& apcNodes)
if (!pScene->mRootNode)throw new ImportErrorException("LWO: Unable to build a valid node graph");
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::CountVertsAndFaces(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 = *cursor++;
verts += numIndices;faces++;
cursor += numIndices;
int16_t surface = *cursor++;
if (surface < 0)
{
// there are detail polygons
numIndices = *cursor++;
CountVertsAndFaces(verts,faces,cursor,end,numIndices);
}
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::CopyFaceIndices(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;
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("LWO: face index is out of range");
mi = (unsigned int)mCurLayer->mTempPoints.size()-1;
}
}
}
else DefaultLogger::get()->warn("LWO: Face has 0 indices");
int16_t surface = *cursor++;
if (surface < 0)
{
surface = -surface;
// there are detail polygons
uint16_t numPolygons = *cursor++;
if (cursor < end)CopyFaceIndices(it,cursor,end,numPolygons);
}
face.surfaceIndex = surface-1;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::ResolveTags()
{
// --- this function is used for both LWO2 and LWOB
mMapping->resize(mTags->size(),0xffffffff);
for (unsigned int a = 0; a < mTags->size();++a)
{
@ -454,6 +453,7 @@ void LWOImporter::ResolveTags()
// ------------------------------------------------------------------------------------------------
void LWOImporter::ParseString(std::string& out,unsigned int max)
{
// --- this function is used for both LWO2 and LWOB
unsigned int iCursor = 0;
const char* in = (const char*)mFileBuffer,*sz = in;
while (*in)
@ -472,6 +472,7 @@ void LWOImporter::ParseString(std::string& out,unsigned int max)
// ------------------------------------------------------------------------------------------------
void LWOImporter::AdjustTexturePath(std::string& out)
{
// --- this function is used for both LWO2 and LWOB
if (::strstr(out.c_str(), "(sequence)"))
{
// remove the (sequence) and append 000
@ -480,9 +481,34 @@ void LWOImporter::AdjustTexturePath(std::string& out)
}
}
// ------------------------------------------------------------------------------------------------
int LWOImporter::ReadVSizedIntLWO2(uint8_t*& inout)
{
int i;
int c = *inout;inout++;
if(c != 0xFF)
{
i = c << 8;
c = *inout;inout++;
i |= c;
}
else
{
c = *inout;inout++;
i = c << 16;
c = *inout;inout++;
i |= c << 8;
c = *inout;inout++;
i |= c;
}
return i;
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOTags(unsigned int size)
{
// --- this function is used for both LWO2 and LWOB
const char* szCur = (const char*)mFileBuffer, *szLast = szCur;
const char* const szEnd = szLast+size;
while (szCur < szEnd)
@ -501,6 +527,7 @@ void LWOImporter::LoadLWOTags(unsigned int size)
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOPoints(unsigned int length)
{
// --- this function is used for both LWO2 and LWOB
mCurLayer->mTempPoints.resize( length / 12 );
// perform endianess conversions
@ -514,6 +541,17 @@ void LWOImporter::LoadLWOPoints(unsigned int length)
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOPolygons(unsigned int length)
{
// --- this function is used for both LWO2 and LWOB
if (mIsLWO2)
{
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer += 4;
if (type != AI_LWO_FACE)
{
DefaultLogger::get()->warn("LWO2: Only POLS.FACE chunsk are supported.");
return;
}
}
// 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;
@ -525,76 +563,158 @@ void LWOImporter::LoadLWOPolygons(unsigned int length)
#endif
unsigned int iNumFaces = 0,iNumVertices = 0;
CountVertsAndFaces(iNumVertices,iNumFaces,cursor,end);
if (mIsLWO2)CountVertsAndFacesLWO2(iNumVertices,iNumFaces,cursor,end);
else CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end);
// allocate the output array and copy face indices
if (iNumFaces)
{
cursor = (LE_NCONST uint16_t*)mFileBuffer;
// this->mTempPoints->resize(iNumVertices);
mCurLayer->mFaces.resize(iNumFaces);
FaceList::iterator it = mCurLayer->mFaces.begin();
CopyFaceIndices(it,cursor,end);
if (mIsLWO2)CopyFaceIndicesLWO2(it,cursor,end);
else CopyFaceIndicesLWOB(it,cursor,end);
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOBFile()
void LWOImporter::CountVertsAndFacesLWO2(unsigned int& verts, unsigned int& faces,
LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max)
{
LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
while (true)
while (cursor < end && max--)
{
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
LE_NCONST IFF::ChunkHeader* const head = (LE_NCONST IFF::ChunkHeader*)mFileBuffer;
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
mFileBuffer += sizeof(IFF::ChunkHeader);
if (mFileBuffer + head->length > end)
{
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
"a chunk points behind the end of the file");
break;
}
LE_NCONST 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 LoadLWOPolygons(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;
}
uint16_t numIndices = *cursor++;
numIndices &= 0x03FF;
verts += numIndices;++faces;
// surface chunk
case AI_LWO_SURF:
{
if (!mSurfaces->empty())
DefaultLogger::get()->warn("LWO: SURF chunk encountered twice");
else LoadLWOBSurface(head->length);
break;
}
}
mFileBuffer = next;
for(uint16_t i = 0; i < numIndices; i++)
ReadVSizedIntLWO2((uint8_t*&)cursor);
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::CopyFaceIndicesLWO2(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;
if(face.mNumIndices = (*cursor++) & 0x03FF)
{
face.mIndices = new unsigned int[face.mNumIndices];
for(unsigned int i = 0; i < face.mNumIndices; i++)
{
face.mIndices[i] = ReadVSizedIntLWO2((uint8_t*&)cursor) + mCurLayer->mPointIDXOfs;
if(face.mIndices[i] > mCurLayer->mTempPoints.size())
{
DefaultLogger::get()->warn("LWO2: face index is out of range");
face.mIndices[i] = (unsigned int)mCurLayer->mTempPoints.size()-1;
}
}
}
else DefaultLogger::get()->warn("LWO2: face has 0 indices");
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
{
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
AI_LSWAP4(type);
if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
return;
LE_NCONST uint8_t* const end = mFileBuffer+length;
while (mFileBuffer < end)
{
unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
unsigned int j = ReadVSizedIntLWO2(mFileBuffer);
if (i > mCurLayer->mFaces.size())
{
DefaultLogger::get()->warn("LWO2: face index in ptag list is out of range");
continue;
}
switch (type)
{
case AI_LWO_SURF:
mCurLayer->mFaces[i].surfaceIndex = j;
break;
case AI_LWO_SMGP:
mCurLayer->mFaces[i].smoothGroup = j;
break;
};
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
{
unsigned int type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
unsigned int dims = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2;
VMapEntry* base;
switch (type)
{
case AI_LWO_TXUV:
if (dims != 2)
{
DefaultLogger::get()->warn("LWO2: Found UV channel with != 2 components");
}
mCurLayer->mUVChannels.push_back(UVChannel(mCurLayer->mTempPoints.size()));
base = &mCurLayer->mUVChannels.back();
case AI_LWO_WGHT:
if (dims != 1)
{
DefaultLogger::get()->warn("LWO2: found vertex weight map with != 1 components");
}
mCurLayer->mWeightChannels.push_back(WeightChannel(mCurLayer->mTempPoints.size()));
base = &mCurLayer->mWeightChannels.back();
case AI_LWO_RGB:
case AI_LWO_RGBA:
if (dims != 3 && dims != 4)
{
DefaultLogger::get()->warn("LWO2: found vertex color map with != 3&4 components");
}
mCurLayer->mVColorChannels.push_back(VColorChannel(mCurLayer->mTempPoints.size()));
base = &mCurLayer->mVColorChannels.back();
default: return;
};
// read the name of the vertex map
ParseString(base->name,length);
// now read all entries in the map
type = std::min(dims,base->dims);
const unsigned int diff = (dims - type)<<2;
LE_NCONST uint8_t* const end = mFileBuffer+length;
while (mFileBuffer < end)
{
unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs;
if (idx > mCurLayer->mTempPoints.size())
{
DefaultLogger::get()->warn("LWO2: vertex index in vmap/vmad is out of range");
continue;
}
for (unsigned int i = 0; i < type;++i)
{
base->rawData[idx*dims+i]= *((float*)mFileBuffer);
mFileBuffer += 4;
}
mFileBuffer += diff;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2File()
{
@ -647,24 +767,41 @@ void LWOImporter::LoadLWO2File()
// vertex list
case AI_LWO_PNTS:
{
if (!mCurLayer->mTempPoints.empty())
DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice");
else LoadLWOPoints(head->length);
unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
LoadLWOPoints(head->length);
mCurLayer->mPointIDXOfs = old;
break;
}
// vertex tags
//case AI_LWO_VMAD:
case AI_LWO_VMAP:
{
if (mCurLayer->mTempPoints.empty())
DefaultLogger::get()->warn("LWO2: Unexpected VMAD/VMAP chunk");
else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
break;
}
// face list
case AI_LWO_POLS:
{
if (!mCurLayer->mFaces.empty())
DefaultLogger::get()->warn("LWO: POLS chunk encountered twice");
else LoadLWOPolygons(head->length);
unsigned int old = (unsigned int)mCurLayer->mFaces.size();
LoadLWOPolygons(head->length);
mCurLayer->mFaceIDXOfs = old;
break;
}
// polygon tags
case AI_LWO_PTAG:
{
if (mCurLayer->mFaces.empty())
DefaultLogger::get()->warn("LWO2: Unexpected PTAG");
else LoadLWO2PolygonTags(head->length);
break;
}
// list of tags
case AI_LWO_SRFS:
{
if (!mTags->empty())
DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice");
DefaultLogger::get()->warn("LWO2: SRFS chunk encountered twice");
else LoadLWOTags(head->length);
break;
}
@ -673,8 +810,8 @@ void LWOImporter::LoadLWO2File()
case AI_LWO_SURF:
{
if (!mSurfaces->empty())
DefaultLogger::get()->warn("LWO: SURF chunk encountered twice");
else LoadLWOBSurface(head->length);
DefaultLogger::get()->warn("LWO2: SURF chunk encountered twice");
else LoadLWO2Surface(head->length);
break;
}
}

View File

@ -55,7 +55,13 @@ namespace Assimp {
using namespace LWO;
// ---------------------------------------------------------------------------
/** Clas to load LWO files
/** Class to load LWO files.
*
* @note Methods named "xxxLWO2[xxx]" are used with the newer LWO2 format.
* 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
*/
class LWOImporter : public BaseImporter
{
@ -157,6 +163,19 @@ private:
*/
void LoadLWOPolygons(unsigned int length);
// -------------------------------------------------------------------
/** Load polygon tags from a PTAG chunk
* @param length Size of the chunk
*/
void LoadLWO2PolygonTags(unsigned int length);
// -------------------------------------------------------------------
/** Load a vertex map from a VMAP/VMAD chunk
* @param length Size of the chunk
* @param perPoly Operate on per-polygon base?
*/
void LoadLWO2VertexMap(unsigned int length, bool perPoly);
// -------------------------------------------------------------------
/** Load polygons from a PNTS chunk
* @param length Size of the chunk
@ -167,7 +186,13 @@ private:
// -------------------------------------------------------------------
/** Count vertices and faces in a LWOB/LWO2 file
*/
void CountVertsAndFaces(unsigned int& verts,
void CountVertsAndFacesLWO2(unsigned int& verts,
unsigned int& faces,
LE_NCONST uint16_t*& cursor,
const uint16_t* const end,
unsigned int max = 0xffffffff);
void CountVertsAndFacesLWOB(unsigned int& verts,
unsigned int& faces,
LE_NCONST uint16_t*& cursor,
const uint16_t* const end,
@ -176,7 +201,12 @@ private:
// -------------------------------------------------------------------
/** Read vertices and faces in a LWOB/LWO2 file
*/
void CopyFaceIndices(LWO::FaceList::iterator& it,
void CopyFaceIndicesLWO2(LWO::FaceList::iterator& it,
LE_NCONST uint16_t*& cursor,
const uint16_t* const end,
unsigned int max = 0xffffffff);
void CopyFaceIndicesLWOB(LWO::FaceList::iterator& it,
LE_NCONST uint16_t*& cursor,
const uint16_t* const end,
unsigned int max = 0xffffffff);
@ -213,6 +243,23 @@ private:
*/
void ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat);
// -------------------------------------------------------------------
/** Get a list of all UV/VC channels required by a specific surface.
*
* @param surf Working surface
* @param layer Working layer
* @param out Output list. The members are indices into the
* UV/VC channel lists of the layer
*/
void FindUVChannels(const LWO::Surface& surf,
const LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]);
void FindVCChannels(const LWO::Surface& surf,
const LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]);
// -------------------------------------------------------------------
/** Generate the final node graph
* Unused nodes are deleted.
@ -220,6 +267,12 @@ private:
*/
void GenerateNodeGraph(std::vector<aiNode*>& apcNodes);
// -------------------------------------------------------------------
/** Read a variable sized integer
* @param inout Input and output buffer
*/
int ReadVSizedIntLWO2(uint8_t*& inout);
protected:
/** true if the file is a LWO2 file*/

View File

@ -113,140 +113,17 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOBSurface(unsigned int size)
void LWOImporter::FindUVChannels(const LWO::Surface& surf, const LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS])
{
LE_NCONST uint8_t* const end = mFileBuffer + size;
out[0] = 0xffffffff;
}
uint32_t iCursor = 0;
mSurfaces->push_back( LWO::Surface () );
LWO::Surface& surf = mSurfaces->back();
LWO::Texture* pTex = NULL;
ParseString(surf.mName,size);
mFileBuffer+=surf.mName.length()+1;
// skip one byte if the length of the surface name is odd
if (!(surf.mName.length() & 1))++mFileBuffer;
while (true)
{
if (mFileBuffer + 6 > end)break;
// no proper IFF header here - the chunk length is specified as int16
uint32_t head_type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
uint16_t head_length = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2;
AI_LSWAP4(head_type);
AI_LSWAP2(head_length);
if (mFileBuffer + head_length > end)
{
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
"a surface sub chunk points behind the end of the file");
}
LE_NCONST 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 = *mFileBuffer++ / 255.0f;
surf.mColor.g = *mFileBuffer++ / 255.0f;
surf.mColor.b = *mFileBuffer / 255.0f;
break;
}
// diffuse strength ...
case AI_LWO_DIFF:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,DIFF,2);
AI_LSWAP2P(mFileBuffer);
surf.mDiffuseValue = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// specular strength ...
case AI_LWO_SPEC:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,SPEC,2);
AI_LSWAP2P(mFileBuffer);
surf.mSpecularValue = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// luminosity ...
case AI_LWO_LUMI:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,LUMI,2);
AI_LSWAP2P(mFileBuffer);
surf.mLuminosity = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// transparency
case AI_LWO_TRAN:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TRAN,2);
AI_LSWAP2P(mFileBuffer);
surf.mTransparency = *((int16_t*)mFileBuffer) / 255.0f;
break;
}
// glossiness
case AI_LWO_GLOS:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,GLOS,2);
AI_LSWAP2P(mFileBuffer);
surf.mGlossiness = float(*((int16_t*)mFileBuffer));
break;
}
// color texture
case AI_LWO_CTEX:
{
pTex = &surf.mColorTexture;
break;
}
// diffuse texture
case AI_LWO_DTEX:
{
pTex = &surf.mDiffuseTexture;
break;
}
// specular texture
case AI_LWO_STEX:
{
pTex = &surf.mSpecularTexture;
break;
}
// bump texture
case AI_LWO_BTEX:
{
pTex = &surf.mBumpTexture;
break;
}
// transparency texture
case AI_LWO_TTEX:
{
pTex = &surf.mTransparencyTexture;
break;
}
// texture path
case AI_LWO_TIMG:
{
if (pTex)
{
ParseString(pTex->mFileName,head_length);
AdjustTexturePath(pTex->mFileName);
mFileBuffer += pTex->mFileName.length();
}
else DefaultLogger::get()->warn("LWOB: TIMG tag was encuntered although "
"there was no xTEX tag before");
break;
}
// texture strength
case AI_LWO_TVAL:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TVAL,1);
if (pTex)pTex->mStrength = *mFileBuffer / 255.0f;
else DefaultLogger::get()->warn("LWOB: TVAL tag was encuntered "
"although there was no xTEX tag before");
break;
}
}
mFileBuffer = next;
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::FindVCChannels(const LWO::Surface& surf, const LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS])
{
out[0] = 0xffffffff;
}
// ------------------------------------------------------------------------------------------------

View File

@ -140,6 +140,8 @@ void NFFImporter::InternReadFile( const std::string& pFile,
MeshInfo* currentMeshWithNormals = NULL;
MeshInfo* currentMesh = NULL;
ShadingInfo s; // current material info
char line[4096];
const char* sz;
unsigned int sphere = 0,cylinder = 0,cone = 0,numNamed = 0;
@ -197,8 +199,6 @@ void NFFImporter::InternReadFile( const std::string& pFile,
{
SkipSpaces(&line[1],&sz);
ShadingInfo s; // color;
// read just the RGB colors, the rest is ignored for the moment
sz = fast_atof_move(sz, s.color.r);
SkipSpaces(&sz);
@ -241,6 +241,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
{
meshesLocked.push_back(MeshInfo(false,true));
MeshInfo& currentMesh = meshesLocked.back();
currentMesh.shader = s;
sz = &line[1];
aiVector3D center; float radius;
@ -261,6 +262,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
{
meshesLocked.push_back(MeshInfo(false,true));
MeshInfo& currentMesh = meshes.back();
currentMesh.shader = s;
sz = &line[1];
aiVector3D center1, center2; float radius1, radius2;
@ -286,7 +288,8 @@ void NFFImporter::InternReadFile( const std::string& pFile,
// '#' - comment
else if ('#' == line[0])
{
DefaultLogger::get()->info(line);
const char* sz;SkipSpaces(&line[1],&sz);
if (!IsLineEnd(*sz))DefaultLogger::get()->info(sz);
}
}

View File

@ -117,7 +117,6 @@ void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
posEpsilon,poResult);
aiVector3D vNormals;
float fDiv = 0.0f;
for (std::vector<unsigned int>::const_iterator
a = poResult.begin();
a != poResult.end();++a)
@ -125,10 +124,8 @@ void ComputeNormalsWithSmoothingsGroups(MeshWithSmoothingGroups<T>& sMesh)
vNormals += sMesh.mNormals[(*a)];
//fDiv += 1.0f;
}
//vNormals.x /= fDiv;vNormals.y /= fDiv;vNormals.z /= fDiv;
vNormals.Normalize();
avNormals[(*i).mIndices[c]] = vNormals;
//poResult.clear();
}
}
sMesh.mNormals = avNormals;

View File

@ -0,0 +1,24 @@
#default color
# A simple sphere
s 5.0 5.0 5.0 10.0
#blue
f 0.0 0.0 1.0 0 1 1
# Another simple sphere
s 5.0 4.0 8.0 3.0
#green
f 0.0 1.0 0.0 0 1 1
# And another one
s 1.0 -4.0 2.0 4.0
#red
f 1.0 0.0 0.0 0 1 1
# a simple cone
c 10 10 5 3
c 14 14 3 6

View File

@ -1101,6 +1101,14 @@
>
</File>
</Filter>
<Filter
Name="FBX"
>
</Filter>
<Filter
Name="Collada"
>
</Filter>
</Filter>
</Filter>
<Filter
@ -1276,6 +1284,10 @@
<Filter
Name="LWO"
>
<File
RelativePath="..\..\code\LWOBLoader.cpp"
>
</File>
<File
RelativePath="..\..\code\LWOLoader.cpp"
>