Added vertex color support to the DXF loader, fixed a minor bugs. Coordinate system issue still unsolved.
Modified GenVertexNormals to take always the cross product of the first and the last normal of a face as face normal. Material implementation for LWO - seems to work, but there are some issues with highly complex models. Added some LWO test models Cleaned up the ./test dir - converted some BMPs to JPG to save space, Finished the matrial property list in jAssimp, some other changes, too. The Java part of the API should be working now. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@156 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
This commit is contained in:
@@ -63,6 +63,31 @@ using namespace Assimp;
|
||||
#define AI_DXF_BINARY_IDENT_LEN (24)
|
||||
|
||||
|
||||
// color indices for DXF - 16 are supported
|
||||
static aiColor4D g_aclrDxfIndexColors[] =
|
||||
{
|
||||
aiColor4D (0.6f, 0.6f, 0.6f, 1.0f),
|
||||
aiColor4D (1.0f, 0.0f, 0.0f, 1.0f), // red
|
||||
aiColor4D (0.0f, 1.0f, 0.0f, 1.0f), // green
|
||||
aiColor4D (0.0f, 0.0f, 1.0f, 1.0f), // blue
|
||||
aiColor4D (0.3f, 1.0f, 0.3f, 1.0f), // light green
|
||||
aiColor4D (0.3f, 0.3f, 1.0f, 1.0f), // light blue
|
||||
aiColor4D (1.0f, 0.3f, 0.3f, 1.0f), // light red
|
||||
aiColor4D (1.0f, 0.0f, 1.0f, 1.0f), // pink
|
||||
aiColor4D (1.0f, 0.6f, 0.0f, 1.0f), // orange
|
||||
aiColor4D (0.6f, 0.3f, 0.0f, 1.0f), // dark orange
|
||||
aiColor4D (1.0f, 1.0f, 0.0f, 1.0f), // yellow
|
||||
aiColor4D (0.3f, 0.3f, 0.3f, 1.0f), // dark gray
|
||||
aiColor4D (0.8f, 0.8f, 0.8f, 1.0f), // light gray
|
||||
aiColor4D (0.0f, 00.f, 0.0f, 1.0f), // black
|
||||
aiColor4D (1.0f, 1.0f, 1.0f, 1.0f), // white
|
||||
aiColor4D (0.6f, 0.0f, 1.0f, 1.0f) // violet
|
||||
};
|
||||
#define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0]))
|
||||
|
||||
// invalid/unassigned color value
|
||||
aiColor4D g_clrInvalid = aiColor4D(std::numeric_limits<float>::quiet_NaN(),0.f,0.f,1.f);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
DXFImporter::DXFImporter()
|
||||
@@ -157,7 +182,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
|
||||
{
|
||||
// ENTITIES and BLOCKS sections - skip the whole rest, no need to waste our time with them
|
||||
if (!::strcmp(cursor,"ENTITIES") || !::strcmp(cursor,"BLOCKS"))
|
||||
if (!ParseEntities())break;
|
||||
if (!ParseEntities())break; else bRepeat = true;
|
||||
|
||||
// other sections - skip them to make sure there will be no name conflicts
|
||||
else
|
||||
@@ -200,6 +225,21 @@ void DXFImporter::InternReadFile( const std::string& pFile,
|
||||
// generate the output mesh
|
||||
aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh();
|
||||
const std::vector<aiVector3D>& vPositions = (*it).vPositions;
|
||||
const std::vector<aiColor4D>& vColors = (*it).vColors;
|
||||
|
||||
// check whether we need vertex colors here
|
||||
aiColor4D* clrOut;
|
||||
const aiColor4D* clr = NULL;
|
||||
for (std::vector<aiColor4D>::const_iterator it2 = (*it).vColors.begin(), end2 = (*it).vColors.end();
|
||||
it2 != end2; ++it2)
|
||||
{
|
||||
if (std::numeric_limits<float>::quiet_NaN() != (*it2).r)
|
||||
{
|
||||
clrOut = pMesh->mColors[0] = new aiColor4D[vPositions.size()];
|
||||
clr = &vColors[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pMesh->mNumFaces = (unsigned int)vPositions.size() / 4u;
|
||||
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
|
||||
@@ -222,6 +262,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
|
||||
for (unsigned int a = 0; a < face.mNumIndices;++a)
|
||||
{
|
||||
*vpOut++ = vp[a];
|
||||
if (clr)*clrOut++ = clr[a];
|
||||
face.mIndices[a] = pMesh->mNumVertices++;
|
||||
}
|
||||
vp += 4;
|
||||
@@ -333,6 +374,7 @@ bool DXFImporter::ParsePolyLine()
|
||||
LayerInfo* out = NULL;
|
||||
|
||||
std::vector<aiVector3D> positions;
|
||||
std::vector<aiColor4D> colors;
|
||||
std::vector<unsigned int> indices;
|
||||
unsigned int flags = 0;
|
||||
|
||||
@@ -344,10 +386,14 @@ bool DXFImporter::ParsePolyLine()
|
||||
{
|
||||
if (!::strcmp(cursor,"VERTEX"))
|
||||
{
|
||||
aiVector3D v;
|
||||
aiVector3D v;aiColor4D clr(g_clrInvalid);
|
||||
unsigned int idx[4] = {0xffffffff,0xffffffff,0xffffffff,0xffffffff};
|
||||
ParsePolyLineVertex(v, idx);
|
||||
if (0xffffffff == idx[0])positions.push_back(v);
|
||||
ParsePolyLineVertex(v, clr, idx);
|
||||
if (0xffffffff == idx[0])
|
||||
{
|
||||
positions.push_back(v);
|
||||
colors.push_back(clr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check whether we have a fourth coordinate
|
||||
@@ -413,6 +459,10 @@ bool DXFImporter::ParsePolyLine()
|
||||
// use a default layer if necessary
|
||||
if (!out)SetDefaultLayer(out);
|
||||
|
||||
flags = (unsigned int)(out->vPositions.size()+indices.size());
|
||||
out->vPositions.reserve(flags);
|
||||
out->vColors.reserve(flags);
|
||||
|
||||
// generate unique vertices
|
||||
for (std::vector<unsigned int>::const_iterator it = indices.begin(), end = indices.end();
|
||||
it != end; ++it)
|
||||
@@ -424,13 +474,14 @@ bool DXFImporter::ParsePolyLine()
|
||||
idx = (unsigned int) positions.size();
|
||||
}
|
||||
out->vPositions.push_back(positions[idx-1]); // indices are one-based.
|
||||
out->vColors.push_back(colors[idx-1]); // indices are one-based.
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx)
|
||||
bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned int* outIdx)
|
||||
{
|
||||
bool ret = false;
|
||||
while (GetNextToken())
|
||||
@@ -455,6 +506,9 @@ bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx)
|
||||
case 72: outIdx[1] = strtol10(cursor);break;
|
||||
case 73: outIdx[2] = strtol10(cursor);break;
|
||||
case 74: outIdx[3] = strtol10(cursor);break;
|
||||
|
||||
// color
|
||||
case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break;
|
||||
};
|
||||
if (ret)break;
|
||||
}
|
||||
@@ -468,6 +522,7 @@ bool DXFImporter::Parse3DFace()
|
||||
LayerInfo* out = NULL;
|
||||
|
||||
aiVector3D vip[4]; // -- vectors are initialized to zero
|
||||
aiColor4D clr(g_clrInvalid);
|
||||
while (GetNextToken())
|
||||
{
|
||||
switch (groupCode)
|
||||
@@ -516,6 +571,9 @@ bool DXFImporter::Parse3DFace()
|
||||
|
||||
// z position of the fourth corner
|
||||
case 33: vip[3].z = fast_atof(cursor);break;
|
||||
|
||||
// color
|
||||
case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break;
|
||||
};
|
||||
if (ret)break;
|
||||
}
|
||||
@@ -528,5 +586,8 @@ bool DXFImporter::Parse3DFace()
|
||||
out->vPositions.push_back(vip[1]);
|
||||
out->vPositions.push_back(vip[2]);
|
||||
out->vPositions.push_back(vip[3]); // might be equal to the third
|
||||
|
||||
for (unsigned int i = 0; i < 4;++i)
|
||||
out->vColors.push_back(clr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ protected:
|
||||
|
||||
// face buffer - order is x,y,z,w v1,v2,v3 (w is equal to z if unused)
|
||||
std::vector<aiVector3D> vPositions;
|
||||
std::vector<aiColor4D> vColors;
|
||||
};
|
||||
|
||||
|
||||
@@ -149,11 +150,13 @@ protected:
|
||||
// -------------------------------------------------------------------
|
||||
/** Parses a VERTEX element in a POLYLINE/POLYFACE
|
||||
* @param out Receives the output vertex.
|
||||
* @param clr Receives the output vertex color - won't be modified
|
||||
* if it is not existing.
|
||||
* @param outIdx Receives the output vertex indices, if present.
|
||||
* Wont't be modified otherwise. Size must be at least 4.
|
||||
* @return false if the end of the file was reached
|
||||
*/
|
||||
bool ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx);
|
||||
bool ParsePolyLineVertex(aiVector3D& out, aiColor4D& clr, unsigned int* outIdx);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -106,20 +106,11 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
|
||||
|
||||
aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
|
||||
aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
|
||||
aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[2]];
|
||||
|
||||
aiVector3D pDelta1 = *pV2 - *pV1;
|
||||
aiVector3D pDelta2 = *pV3 - *pV1;
|
||||
aiVector3D vNor = pDelta1 ^ pDelta2;
|
||||
vNor.Normalize();
|
||||
|
||||
//if (face.mIndices[1] > face.mIndices[2])
|
||||
// vNor *= -1.0f;
|
||||
aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
|
||||
aiVector3D vNor = (*pV2 - *pV1) ^ (*pV3 - *pV1).Normalize();
|
||||
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i)
|
||||
{
|
||||
pMesh->mNormals[face.mIndices[i]] = vNor;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -116,12 +116,8 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
||||
|
||||
aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
|
||||
aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
|
||||
aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[2]];
|
||||
|
||||
aiVector3D pDelta1 = *pV2 - *pV1;
|
||||
aiVector3D pDelta2 = *pV3 - *pV1;
|
||||
aiVector3D vNor = pDelta1 ^ pDelta2;
|
||||
vNor.Normalize();
|
||||
aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
|
||||
aiVector3D vNor = (*pV2 - *pV1) ^ (*pV3 - *pV1).Normalize();
|
||||
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i)
|
||||
pMesh->mNormals[face.mIndices[i]] = vNor;
|
||||
@@ -146,7 +142,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
||||
SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
std::vector<unsigned int> verticesFound;
|
||||
|
||||
const float fLimit = cosf(this->configMaxAngle);
|
||||
const float fLimit = cos(this->configMaxAngle);
|
||||
|
||||
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
|
||||
@@ -157,7 +153,6 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
||||
vertexFinder.FindPositions( posThis, posEpsilon, verticesFound);
|
||||
|
||||
aiVector3D pcNor;
|
||||
//unsigned int div = 0;
|
||||
for (unsigned int a = 0; a < verticesFound.size(); ++a)
|
||||
{
|
||||
unsigned int vidx = verticesFound[a];
|
||||
@@ -167,7 +162,6 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
|
||||
continue;
|
||||
|
||||
pcNor += pMesh->mNormals[vidx];
|
||||
//++div;
|
||||
}
|
||||
pcNor.Normalize();
|
||||
pcNew[i] = pcNor;
|
||||
|
||||
61
code/IFF.h
61
code/IFF.h
@@ -2,17 +2,21 @@
|
||||
|
||||
// Definitions for the Interchange File Format (IFF)
|
||||
// Alexander Gessler, 2006
|
||||
// Adapted for Assimp August 2008
|
||||
// Adapted to Assimp August 2008
|
||||
|
||||
#ifndef AI_IFF_H_INCLUDED
|
||||
#define AI_IFF_H_INCLUDED
|
||||
|
||||
#include "ByteSwap.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace IFF {
|
||||
namespace Assimp {
|
||||
namespace IFF {
|
||||
|
||||
#include "./../include/Compiler/pushpack1.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct ChunkHeader
|
||||
{
|
||||
//! Type of the chunk header - FourCC
|
||||
@@ -20,7 +24,22 @@ struct ChunkHeader
|
||||
|
||||
//! Length of the chunk data, in bytes
|
||||
uint32_t length;
|
||||
};
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Describes an IFF sub chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
struct SubChunkHeader
|
||||
{
|
||||
//! Type of the chunk header - FourCC
|
||||
uint32_t type;
|
||||
|
||||
//! Length of the chunk data, in bytes
|
||||
uint16_t length;
|
||||
} PACK_STRUCT;
|
||||
|
||||
#include "./../include/Compiler/poppack1.h"
|
||||
|
||||
|
||||
#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
|
||||
@@ -30,6 +49,34 @@ struct ChunkHeader
|
||||
#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M')
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Load a chunk header
|
||||
//! @param outFile Pointer to the file data - points to the chunk data afterwards
|
||||
//! @return Pointer to the chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline LE_NCONST ChunkHeader* LoadChunk(LE_NCONST uint8_t*& outFile)
|
||||
{
|
||||
LE_NCONST ChunkHeader* head = (LE_NCONST ChunkHeader*) outFile;
|
||||
AI_LSWAP4(head->length);
|
||||
AI_LSWAP4(head->type);
|
||||
outFile += sizeof(ChunkHeader);
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Load a sub chunk header
|
||||
//! @param outFile Pointer to the file data - points to the chunk data afterwards
|
||||
//! @return Pointer to the sub chunk header
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline LE_NCONST SubChunkHeader* LoadSubChunk(LE_NCONST uint8_t*& outFile)
|
||||
{
|
||||
LE_NCONST SubChunkHeader* head = (LE_NCONST SubChunkHeader*) outFile;
|
||||
AI_LSWAP2(head->length);
|
||||
AI_LSWAP4(head->type);
|
||||
outFile += sizeof(SubChunkHeader);
|
||||
return head;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//! Read the file header and return the type of the file and its size
|
||||
//! @param outFile Pointer to the file data. The buffer must at
|
||||
@@ -37,11 +84,9 @@ struct ChunkHeader
|
||||
//! @param fileType Receives the type of the file
|
||||
//! @return 0 if everything was OK, otherwise an error message
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
inline const char* ReadHeader(const uint8_t* outFile,uint32_t& fileType)
|
||||
inline const char* ReadHeader(LE_NCONST uint8_t* outFile,uint32_t& fileType)
|
||||
{
|
||||
LE_NCONST ChunkHeader* head = (LE_NCONST ChunkHeader*) outFile;
|
||||
AI_LSWAP4(head->length);
|
||||
AI_LSWAP4(head->type);
|
||||
LE_NCONST ChunkHeader* head = LoadChunk(outFile);
|
||||
if(AI_IFF_FOURCC_FORM != head->type)
|
||||
{
|
||||
return "The file is not an IFF file: FORM chunk is missing";
|
||||
|
||||
@@ -63,14 +63,11 @@ void LWOImporter::LoadLWOBFile()
|
||||
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);
|
||||
LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
|
||||
|
||||
if (mFileBuffer + head->length > end)
|
||||
{
|
||||
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
|
||||
"a chunk points behind the end of the file");
|
||||
throw new ImportErrorException("LWOB: Invalid chunk length");
|
||||
break;
|
||||
}
|
||||
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
|
||||
@@ -204,104 +201,113 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
|
||||
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;
|
||||
GetS0(surf.mName,size);
|
||||
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)
|
||||
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
|
||||
|
||||
if (mFileBuffer + head->length > end)
|
||||
throw new ImportErrorException("LWOB: Invalid surface chunk length");
|
||||
|
||||
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;
|
||||
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);
|
||||
AI_LSWAP2P(mFileBuffer);
|
||||
surf.mDiffuseValue = *((int16_t*)mFileBuffer) / 255.0f;
|
||||
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);
|
||||
AI_LSWAP2P(mFileBuffer);
|
||||
surf.mSpecularValue = *((int16_t*)mFileBuffer) / 255.0f;
|
||||
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);
|
||||
AI_LSWAP2P(mFileBuffer);
|
||||
surf.mLuminosity = *((int16_t*)mFileBuffer) / 255.0f;
|
||||
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);
|
||||
AI_LSWAP2P(mFileBuffer);
|
||||
surf.mTransparency = *((int16_t*)mFileBuffer) / 255.0f;
|
||||
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 = GetF4();
|
||||
break;
|
||||
}
|
||||
// glossiness
|
||||
case AI_LWO_GLOS:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,GLOS,2);
|
||||
AI_LSWAP2P(mFileBuffer);
|
||||
surf.mGlossiness = float(*((int16_t*)mFileBuffer));
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,2);
|
||||
surf.mGlossiness = (float)GetU2();
|
||||
break;
|
||||
}
|
||||
// color texture
|
||||
case AI_LWO_CTEX:
|
||||
{
|
||||
pTex = &surf.mColorTexture;
|
||||
surf.mColorTextures.push_back(Texture());
|
||||
pTex = &surf.mColorTextures.back();
|
||||
break;
|
||||
}
|
||||
// diffuse texture
|
||||
case AI_LWO_DTEX:
|
||||
{
|
||||
pTex = &surf.mDiffuseTexture;
|
||||
surf.mDiffuseTextures.push_back(Texture());
|
||||
pTex = &surf.mDiffuseTextures.back();
|
||||
break;
|
||||
}
|
||||
// specular texture
|
||||
case AI_LWO_STEX:
|
||||
{
|
||||
pTex = &surf.mSpecularTexture;
|
||||
surf.mSpecularTextures.push_back(Texture());
|
||||
pTex = &surf.mSpecularTextures.back();
|
||||
break;
|
||||
}
|
||||
// bump texture
|
||||
case AI_LWO_BTEX:
|
||||
{
|
||||
pTex = &surf.mBumpTexture;
|
||||
surf.mBumpTextures.push_back(Texture());
|
||||
pTex = &surf.mBumpTextures.back();
|
||||
break;
|
||||
}
|
||||
// transparency texture
|
||||
case AI_LWO_TTEX:
|
||||
{
|
||||
pTex = &surf.mTransparencyTexture;
|
||||
surf.mOpacityTextures.push_back(Texture());
|
||||
pTex = &surf.mOpacityTextures.back();
|
||||
break;
|
||||
}
|
||||
// texture path
|
||||
@@ -309,9 +315,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
|
||||
{
|
||||
if (pTex)
|
||||
{
|
||||
ParseString(pTex->mFileName,head_length);
|
||||
AdjustTexturePath(pTex->mFileName);
|
||||
mFileBuffer += pTex->mFileName.length();
|
||||
GetS0(pTex->mFileName,head->length);
|
||||
}
|
||||
else DefaultLogger::get()->warn("LWOB: TIMG tag was encuntered although "
|
||||
"there was no xTEX tag before");
|
||||
@@ -320,8 +324,8 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
|
||||
// texture strength
|
||||
case AI_LWO_TVAL:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TVAL,1);
|
||||
if (pTex)pTex->mStrength = *mFileBuffer / 255.0f;
|
||||
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");
|
||||
break;
|
||||
|
||||
@@ -40,9 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/** @file Defines chunk constants used by the LWO file format
|
||||
|
||||
The chunks are taken from LWO2.h, found in the sourcecode of
|
||||
a project called Nxabega (http://www.sourceforge.net/projects/nxabega).
|
||||
I assume they are from the official LightWave SDK headers.
|
||||
The chunks are taken from the official LightWave SDK headers.
|
||||
Original copyright notice: "Ernie Wright 17 Sep 00"
|
||||
|
||||
*/
|
||||
@@ -253,12 +251,25 @@ namespace LWO {
|
||||
struct Face : public aiFace
|
||||
{
|
||||
Face()
|
||||
: surfaceIndex(0)
|
||||
, smoothGroup(0)
|
||||
: surfaceIndex (0)
|
||||
, smoothGroup (0)
|
||||
{}
|
||||
|
||||
Face(const Face& f)
|
||||
{
|
||||
*this = f;
|
||||
}
|
||||
|
||||
unsigned int surfaceIndex;
|
||||
unsigned int smoothGroup;
|
||||
|
||||
Face& operator=(const LWO::Face& f)
|
||||
{
|
||||
aiFace::operator =(f);
|
||||
surfaceIndex = f.surfaceIndex;
|
||||
smoothGroup = f.smoothGroup;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -271,11 +282,24 @@ struct VMapEntry
|
||||
: dims(_dims)
|
||||
{}
|
||||
|
||||
~VMapEntry() {delete[] rawData;}
|
||||
virtual ~VMapEntry() {}
|
||||
|
||||
//! allocates memory for the vertex map
|
||||
virtual void Allocate(unsigned int num)
|
||||
{
|
||||
if (!rawData.empty())return; // return if already allocated
|
||||
|
||||
register unsigned int m = num*dims;
|
||||
rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs
|
||||
rawData.resize(m,0.f);
|
||||
abAssigned.resize(num,false);
|
||||
}
|
||||
|
||||
std::string name;
|
||||
float* rawData;
|
||||
unsigned int dims;
|
||||
std::vector<float> rawData;
|
||||
|
||||
std::vector<bool> abAssigned;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -283,16 +307,29 @@ struct VMapEntry
|
||||
*/
|
||||
struct VColorChannel : public VMapEntry
|
||||
{
|
||||
VColorChannel(unsigned int num)
|
||||
VColorChannel()
|
||||
: VMapEntry(4)
|
||||
{
|
||||
data = new aiColor4D[num];
|
||||
for (unsigned int i = 0; i < num;++i)
|
||||
data[i].a = 1.0f;
|
||||
rawData = (float*)data;
|
||||
}
|
||||
{}
|
||||
|
||||
aiColor4D* data;
|
||||
//! need to overwrite this function - the alpha channel must
|
||||
//! be initialized to 1.0 by default
|
||||
virtual void Allocate(unsigned int num)
|
||||
{
|
||||
if (!rawData.empty())return; // return if already allocated
|
||||
|
||||
register unsigned int m = num*dims;
|
||||
rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs
|
||||
rawData.resize(m,0.f);
|
||||
|
||||
for (std::vector<float>::iterator it = rawData.begin(), end = rawData.end();
|
||||
it != end;++it )
|
||||
{
|
||||
for (unsigned int i = 0; i< 3;++i,++it)
|
||||
*it = 0.f;
|
||||
*it = 1.f;
|
||||
}
|
||||
abAssigned.resize(num,false);
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -300,14 +337,9 @@ struct VColorChannel : public VMapEntry
|
||||
*/
|
||||
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;
|
||||
UVChannel()
|
||||
: VMapEntry(2)
|
||||
{}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -315,13 +347,9 @@ struct UVChannel : public VMapEntry
|
||||
*/
|
||||
struct WeightChannel : public VMapEntry
|
||||
{
|
||||
WeightChannel(unsigned int num)
|
||||
WeightChannel()
|
||||
: VMapEntry(1)
|
||||
{
|
||||
rawData = new float[num];
|
||||
for (unsigned int m = 0; m < num;++m)
|
||||
rawData[m] = 0.f;
|
||||
}
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -330,10 +358,59 @@ struct WeightChannel : public VMapEntry
|
||||
*/
|
||||
struct Texture
|
||||
{
|
||||
// we write the enum values out here to make debugging easier ...
|
||||
enum BlendType
|
||||
{
|
||||
Normal = 0,
|
||||
Subtractive = 1,
|
||||
Difference = 2,
|
||||
Multiply = 3,
|
||||
Divide = 4,
|
||||
Alpha = 5,
|
||||
TextureDispl = 6,
|
||||
Additive = 7
|
||||
};
|
||||
|
||||
enum MappingMode
|
||||
{
|
||||
Planar = 0,
|
||||
Cylindrical = 1,
|
||||
Spherical = 2,
|
||||
Cubic = 3,
|
||||
FrontProjection = 4,
|
||||
UV = 5
|
||||
};
|
||||
|
||||
enum Axes
|
||||
{
|
||||
AXIS_X = 0,
|
||||
AXIS_Y = 1,
|
||||
AXIS_Z = 2
|
||||
};
|
||||
|
||||
enum Wrap
|
||||
{
|
||||
RESET = 0,
|
||||
REPEAT = 1,
|
||||
MIRROR = 2,
|
||||
EDGE = 3
|
||||
};
|
||||
|
||||
Texture()
|
||||
: mClipIdx(0xffffffff)
|
||||
, mStrength (1.0f)
|
||||
, mUVChannelIndex ("unknown")
|
||||
, mRealUVIndex (0xffffffff)
|
||||
, enabled (true)
|
||||
, blendType (Additive)
|
||||
, bCanUse (true)
|
||||
, mapMode (UV)
|
||||
, majorAxis (AXIS_X)
|
||||
, wrapAmountH (1.0f)
|
||||
, wrapAmountW (1.0f)
|
||||
, wrapModeWidth (REPEAT)
|
||||
, wrapModeHeight (REPEAT)
|
||||
, ordinal ("\x00")
|
||||
{}
|
||||
|
||||
//! File name of the texture
|
||||
@@ -342,15 +419,38 @@ struct Texture
|
||||
//! Clip index
|
||||
unsigned int mClipIdx;
|
||||
|
||||
//! Strength of the texture
|
||||
//! Strength of the texture - blend factor
|
||||
float mStrength;
|
||||
|
||||
|
||||
/*************** SPECIFIC TO LWO2 *********************/
|
||||
uint32_t type; // type of the texture
|
||||
|
||||
//! Name of the corresponding UV channel
|
||||
std::string mUVChannelIndex;
|
||||
unsigned int mRealUVIndex;
|
||||
|
||||
//! is the texture enabled?
|
||||
bool enabled;
|
||||
|
||||
//! blend type
|
||||
BlendType blendType;
|
||||
|
||||
//! are we able to use the texture?
|
||||
bool bCanUse;
|
||||
|
||||
//! mapping mode
|
||||
MappingMode mapMode;
|
||||
|
||||
//! major axis for planar, cylindrical, spherical projections
|
||||
Axes majorAxis;
|
||||
|
||||
//! wrap amount for cylindrical and spherical projections
|
||||
float wrapAmountH,wrapAmountW;
|
||||
|
||||
//! wrapping mode for the texture
|
||||
Wrap wrapModeWidth,wrapModeHeight;
|
||||
|
||||
//! ordinal string of the texture
|
||||
std::string ordinal;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -358,23 +458,66 @@ struct Texture
|
||||
*/
|
||||
struct Clip
|
||||
{
|
||||
//! path to the base texture
|
||||
enum Type
|
||||
{
|
||||
STILL, SEQ, REF, UNSUPPORTED
|
||||
} type;
|
||||
|
||||
Clip()
|
||||
: type (UNSUPPORTED)
|
||||
, idx (0)
|
||||
{}
|
||||
|
||||
//! path to the base texture -
|
||||
std::string path;
|
||||
|
||||
//! reference to another CLIP
|
||||
unsigned int clipRef;
|
||||
|
||||
//! index of the clip
|
||||
unsigned int idx;
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Data structure for a LWO file shader
|
||||
*
|
||||
* Later
|
||||
*/
|
||||
struct Shader
|
||||
{
|
||||
Shader()
|
||||
: ordinal ("\x00")
|
||||
, functionName ("unknown")
|
||||
, enabled (true)
|
||||
{}
|
||||
|
||||
std::string ordinal;
|
||||
std::string functionName;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
typedef std::list < Texture > TextureList;
|
||||
typedef std::list < Shader > ShaderList;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Data structure for a LWO file surface (= material)
|
||||
*/
|
||||
struct Surface
|
||||
{
|
||||
Surface()
|
||||
: bDoubleSided (false)
|
||||
, mDiffuseValue (1.0f)
|
||||
, mSpecularValue (1.0f)
|
||||
, mTransparency (0.0f)
|
||||
, mGlossiness (0.0f)
|
||||
, mLuminosity (0.0f)
|
||||
, mMaximumSmoothAngle (0.0f) // 0 == not specified
|
||||
: mColor (0.78431f,0.78431f,0.78431f)
|
||||
, bDoubleSided (false)
|
||||
, mDiffuseValue (1.f)
|
||||
, mSpecularValue (0.f)
|
||||
, mTransparency (0.f)
|
||||
, mGlossiness (0.4f)
|
||||
, mLuminosity (0.f)
|
||||
, mColorHighlights (0.f)
|
||||
, mMaximumSmoothAngle (0.f) // 0 == not specified, no smoothing
|
||||
, mVCMap ("")
|
||||
, mIOR (1.f) // vakuum
|
||||
, mBumpIntensity (1.f)
|
||||
{}
|
||||
|
||||
//! Name of the surface
|
||||
@@ -387,23 +530,38 @@ struct Surface
|
||||
bool bDoubleSided;
|
||||
|
||||
//! Various material parameters
|
||||
float mDiffuseValue,mSpecularValue,mTransparency,mGlossiness,mLuminosity;
|
||||
float mDiffuseValue,mSpecularValue,mTransparency,mGlossiness,mLuminosity,mColorHighlights;
|
||||
|
||||
//! Maximum angle between two adjacent triangles
|
||||
//! that they can be smoothed - in degrees
|
||||
float mMaximumSmoothAngle;
|
||||
|
||||
//! Textures
|
||||
Texture mColorTexture,mDiffuseTexture,mSpecularTexture,
|
||||
mBumpTexture,mTransparencyTexture;
|
||||
//! Vertex color map to be used to color the surface
|
||||
std::string mVCMap;
|
||||
|
||||
//! Names of the special shaders to be applied to the surface
|
||||
ShaderList mShaders;
|
||||
|
||||
//! Textures - the first entry in the list is evaluated first
|
||||
TextureList mColorTextures, // color textures are added to both diffuse and specular texture stacks
|
||||
mDiffuseTextures,
|
||||
mSpecularTextures,
|
||||
mOpacityTextures,
|
||||
mBumpTextures,
|
||||
mGlossinessTextures;
|
||||
|
||||
//! Index of refraction
|
||||
float mIOR;
|
||||
|
||||
//! Bump intensity scaling
|
||||
float mBumpIntensity;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
#define AI_LWO_VALIDATE_CHUNK_LENGTH(length,name,size) \
|
||||
if (length < size) \
|
||||
{ \
|
||||
DefaultLogger::get()->warn("LWO: "#name" chunk is too small"); \
|
||||
break; \
|
||||
throw new ImportErrorException("LWO: "#name" chunk is too small"); \
|
||||
} \
|
||||
|
||||
|
||||
@@ -413,6 +571,7 @@ 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 < unsigned int > ReferrerList;
|
||||
typedef std::vector < WeightChannel > WeightChannelList;
|
||||
typedef std::vector < VColorChannel > VColorChannelList;
|
||||
typedef std::vector < UVChannel > UVChannelList;
|
||||
@@ -433,6 +592,11 @@ struct Layer
|
||||
/** Temporary point list from the file */
|
||||
PointList mTempPoints;
|
||||
|
||||
/** Lists for every point the index of another point
|
||||
that has been copied from *this* point or 0xffffffff if
|
||||
no copy of the point has been made */
|
||||
ReferrerList mPointReferrers;
|
||||
|
||||
/** Weight channel list from the file */
|
||||
WeightChannelList mWeightChannels;
|
||||
|
||||
@@ -456,6 +620,9 @@ struct Layer
|
||||
|
||||
/** Name of the layer */
|
||||
std::string mName;
|
||||
|
||||
/** Pivot point of the layer */
|
||||
aiVector3D mPivot;
|
||||
};
|
||||
|
||||
typedef std::list<LWO::Layer> LayerList;
|
||||
|
||||
@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "LWOLoader.h"
|
||||
#include "MaterialSystem.h"
|
||||
#include "StringComparison.h"
|
||||
#include "SGSpatialSort.h"
|
||||
#include "ByteSwap.h"
|
||||
|
||||
// public assimp headers
|
||||
@@ -52,11 +53,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "../include/IOSystem.h"
|
||||
#include "../include/aiScene.h"
|
||||
#include "../include/aiAssert.h"
|
||||
#include "../include/DefaultLogger.h"
|
||||
#include "../include/assimp.hpp"
|
||||
|
||||
// boost headers
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
@@ -91,12 +93,14 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties
|
||||
void LWOImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
// -- no configuration options at the moment
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
@@ -166,7 +170,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
szBuff[3] = (char)(fileType);
|
||||
throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff);
|
||||
}
|
||||
|
||||
// now, as we have loaded all data, we can resolve cross-referenced tags and clips
|
||||
ResolveTags();
|
||||
ResolveClips();
|
||||
|
||||
// now process all layers and build meshes and nodes
|
||||
std::vector<aiMesh*> apcMeshes;
|
||||
@@ -176,10 +183,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
|
||||
|
||||
unsigned int iDefaultSurface = 0xffffffff; // index of the default surface
|
||||
for (LayerList::const_iterator lit = mLayers->begin(), lend = mLayers->end();
|
||||
for (LayerList::iterator lit = mLayers->begin(), lend = mLayers->end();
|
||||
lit != lend;++lit)
|
||||
{
|
||||
const LWO::Layer& layer = *lit;
|
||||
LWO::Layer& layer = *lit;
|
||||
|
||||
// I don't know whether there could be dummy layers, but it would be possible
|
||||
const unsigned int meshStart = (unsigned int)apcMeshes.size();
|
||||
@@ -190,7 +197,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
std::vector<SortedRep> pSorted(mSurfaces->size()+1);
|
||||
|
||||
unsigned int i = 0;
|
||||
for (FaceList::const_iterator it = layer.mFaces.begin(), end = layer.mFaces.end();
|
||||
for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end();
|
||||
it != end;++it,++i)
|
||||
{
|
||||
unsigned int idx = (*it).surfaceIndex;
|
||||
@@ -232,8 +239,9 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
apcMeshes.push_back(mesh);
|
||||
mesh->mNumFaces = (unsigned int)sorted.size();
|
||||
|
||||
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
|
||||
it != end;++it)
|
||||
// count the number of vertices
|
||||
SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
|
||||
for (;it != end;++it)
|
||||
{
|
||||
mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
|
||||
}
|
||||
@@ -275,31 +283,45 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices];
|
||||
}
|
||||
|
||||
// we would not need this extra array, but the code is much cleaner if we use it
|
||||
// FIX: we can use the referrer ID array here. invalidate its contents
|
||||
// before we resize it to avoid a unnecessary memcpy
|
||||
std::vector<unsigned int>& smoothingGroups = layer.mPointReferrers;
|
||||
smoothingGroups.erase (smoothingGroups.begin(),smoothingGroups.end());
|
||||
smoothingGroups.resize(mesh->mNumFaces,0);
|
||||
|
||||
// now convert all faces
|
||||
unsigned int vert = 0;
|
||||
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
|
||||
it != end;++it)
|
||||
std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
|
||||
for (it = sorted.begin(); it != end;++it,++outIt)
|
||||
{
|
||||
const LWO::Face& face = layer.mFaces[*it];
|
||||
*outIt = face.smoothGroup;
|
||||
|
||||
// copy all vertices
|
||||
for (unsigned int q = 0; q < face.mNumIndices;++q)
|
||||
{
|
||||
register unsigned int idx = face.mIndices[q];
|
||||
*pv++ = layer.mTempPoints[idx];
|
||||
*pv = layer.mTempPoints[idx] + layer.mPivot;
|
||||
pv->z *= -1.0f; // DX to OGL
|
||||
pv++;
|
||||
|
||||
// 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];
|
||||
aiVector3D*& pp = pvUV[w];
|
||||
const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
|
||||
pp->x = src.x;
|
||||
pp->y = 1.0f - src.y; // DX to OGL
|
||||
pp++;
|
||||
}
|
||||
|
||||
// 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];
|
||||
*(pvVC[w])++ = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -308,14 +330,20 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
{
|
||||
}
|
||||
#endif
|
||||
face.mIndices[q] = vert++;
|
||||
face.mIndices[q] = vert + (face.mNumIndices-q-1);
|
||||
}
|
||||
vert += face.mNumIndices;
|
||||
|
||||
pf->mIndices = face.mIndices;
|
||||
pf->mNumIndices = face.mNumIndices;
|
||||
unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // make sure it won't be deleted
|
||||
pf++;
|
||||
}
|
||||
|
||||
// compute normal vectors for the mesh - we can't use our GenSmoothNormal-Step here
|
||||
// since it wouldn't handle smoothing groups correctly
|
||||
ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
|
||||
|
||||
++p;
|
||||
}
|
||||
}
|
||||
@@ -352,11 +380,103 @@ void LWOImporter::InternReadFile( const std::string& pFile,
|
||||
GenerateNodeGraph(apcNodes);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>& smoothingGroups,
|
||||
const LWO::Surface& surface)
|
||||
{
|
||||
// allocate output storage
|
||||
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
// First generate per-face normals
|
||||
aiVector3D* out;
|
||||
std::vector<aiVector3D> faceNormals;
|
||||
|
||||
if (!surface.mMaximumSmoothAngle)
|
||||
out = mesh->mNormals;
|
||||
else
|
||||
{
|
||||
faceNormals.resize(mesh->mNumVertices);
|
||||
out = &faceNormals[0];
|
||||
}
|
||||
|
||||
aiFace* begin = mesh->mFaces, *const end = mesh->mFaces+mesh->mNumFaces;
|
||||
for (; begin != end; ++begin)
|
||||
{
|
||||
aiFace& face = *begin;
|
||||
|
||||
// LWO doc: "the normal is defined as the cross product of the first and last edges"
|
||||
aiVector3D* pV1 = mesh->mVertices + face.mIndices[0];
|
||||
aiVector3D* pV2 = mesh->mVertices + face.mIndices[1];
|
||||
aiVector3D* pV3 = mesh->mVertices + face.mIndices[face.mNumIndices-1];
|
||||
|
||||
aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize();
|
||||
for (unsigned int i = 0; i < face.mNumIndices;++i)
|
||||
out[face.mIndices[i]] = vNor;
|
||||
}
|
||||
if (!surface.mMaximumSmoothAngle)return;
|
||||
|
||||
// calculate the position bounds so we have a reliable epsilon to
|
||||
// check position differences against
|
||||
aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
|
||||
for( unsigned int a = 0; a < mesh->mNumVertices; a++)
|
||||
{
|
||||
minVec.x = std::min( minVec.x, mesh->mVertices[a].x);
|
||||
minVec.y = std::min( minVec.y, mesh->mVertices[a].y);
|
||||
minVec.z = std::min( minVec.z, mesh->mVertices[a].z);
|
||||
maxVec.x = std::max( maxVec.x, mesh->mVertices[a].x);
|
||||
maxVec.y = std::max( maxVec.y, mesh->mVertices[a].y);
|
||||
maxVec.z = std::max( maxVec.z, mesh->mVertices[a].z);
|
||||
}
|
||||
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
|
||||
|
||||
// now generate the spatial sort tree
|
||||
SGSpatialSort sSort;
|
||||
std::vector<unsigned int>::const_iterator it = smoothingGroups.begin();
|
||||
for( begin = mesh->mFaces; begin != end; ++begin, ++it)
|
||||
{
|
||||
aiFace& face = *begin;
|
||||
for (unsigned int i = 0; i < face.mNumIndices;++i)
|
||||
{
|
||||
register unsigned int tt = face.mIndices[i];
|
||||
sSort.Add(mesh->mVertices[tt],tt,*it);
|
||||
}
|
||||
}
|
||||
// sort everything - this takes O(logn) time
|
||||
sSort.Prepare();
|
||||
std::vector<unsigned int> poResult;poResult.reserve(20);
|
||||
|
||||
const float fLimit = cos(surface.mMaximumSmoothAngle);
|
||||
|
||||
// generate vertex normals. We have O(logn) for the binary lookup, which we need
|
||||
// for n elements, thus the EXPECTED complexity is O(nlogn)
|
||||
for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it)
|
||||
{
|
||||
register unsigned int sg = *it;
|
||||
|
||||
aiFace& face = *begin;
|
||||
unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
|
||||
for (; beginIdx != endIdx; ++beginIdx)
|
||||
{
|
||||
sSort.FindPositions(mesh->mVertices[*beginIdx],sg,posEpsilon,poResult,true);
|
||||
|
||||
aiVector3D vNormals;
|
||||
for (std::vector<unsigned int>::const_iterator
|
||||
a = poResult.begin(), end = poResult.end();
|
||||
a != end;++a)
|
||||
{
|
||||
const aiVector3D& v = faceNormals[*a];
|
||||
if (v * faceNormals[*beginIdx] < fLimit)continue;
|
||||
vNormals += v;
|
||||
}
|
||||
vNormals.Normalize();
|
||||
mesh->mNormals[*beginIdx] = vNormals;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::AddChildren(aiNode* node, uintptr_t parent, std::vector<aiNode*>& apcNodes)
|
||||
{
|
||||
unsigned int numChilds = 0;
|
||||
|
||||
for (uintptr_t i = 0; i < (uintptr_t)apcNodes.size();++i)
|
||||
{
|
||||
if (i == parent)continue;
|
||||
@@ -454,57 +574,50 @@ void LWOImporter::ResolveTags()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::ParseString(std::string& out,unsigned int max)
|
||||
void LWOImporter::ResolveClips()
|
||||
{
|
||||
// --- this function is used for both LWO2 and LWOB
|
||||
unsigned int iCursor = 0;
|
||||
const char* in = (const char*)mFileBuffer,*sz = in;
|
||||
while (*in)
|
||||
for( unsigned int i = 0; i < mClips.size();++i)
|
||||
{
|
||||
if (++iCursor > max)
|
||||
Clip& clip = mClips[i];
|
||||
if (Clip::REF == clip.type)
|
||||
{
|
||||
DefaultLogger::get()->warn("LWOB: Invalid file, string is is too long");
|
||||
break;
|
||||
if (clip.clipRef >= mClips.size())
|
||||
{
|
||||
DefaultLogger::get()->error("LWO2: Clip referrer index is out of range");
|
||||
clip.clipRef = 0;
|
||||
}
|
||||
Clip& dest = mClips[clip.clipRef];
|
||||
if (Clip::REF == dest.type)
|
||||
{
|
||||
DefaultLogger::get()->error("LWO2: Clip references another clip reference");
|
||||
clip.type = Clip::UNSUPPORTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.path = dest.path;
|
||||
clip.type = dest.type;
|
||||
}
|
||||
}
|
||||
++in;
|
||||
}
|
||||
unsigned int len = (unsigned int) (in-sz);
|
||||
out = std::string(sz,len);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::AdjustTexturePath(std::string& out)
|
||||
{
|
||||
// --- this function is used for both LWO2 and LWOB
|
||||
if (::strstr(out.c_str(), "(sequence)"))
|
||||
if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)"))
|
||||
{
|
||||
// remove the (sequence) and append 000
|
||||
DefaultLogger::get()->info("LWO: Sequence of animated texture found. It will be ignored");
|
||||
DefaultLogger::get()->info("LWOB: Sequence of animated texture found. It will be ignored");
|
||||
out = out.substr(0,out.length()-10) + "000";
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int LWOImporter::ReadVSizedIntLWO2(uint8_t*& inout)
|
||||
{
|
||||
int i;
|
||||
int c = *inout;inout++;
|
||||
if(c != 0xFF)
|
||||
// format: drive:path/file - we need to insert a slash after the drive
|
||||
std::string::size_type n = out.find_first_of(':');
|
||||
if (std::string::npos != n)
|
||||
{
|
||||
i = c << 8;
|
||||
c = *inout;inout++;
|
||||
i |= c;
|
||||
out.insert(n+1,"/");
|
||||
}
|
||||
else
|
||||
{
|
||||
c = *inout;inout++;
|
||||
i = c << 16;
|
||||
c = *inout;inout++;
|
||||
i |= c << 8;
|
||||
c = *inout;inout++;
|
||||
i |= c;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -530,8 +643,20 @@ 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 );
|
||||
// --- this function is used for both LWO2 and LWOB but for
|
||||
// LWO2 we need to allocate 25% more storage - it could be we'll
|
||||
// need to duplicate some points later.
|
||||
register unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
|
||||
if (mIsLWO2)
|
||||
{
|
||||
mCurLayer->mTempPoints.reserve ( regularSize + (regularSize>>2u) );
|
||||
mCurLayer->mTempPoints.resize ( regularSize );
|
||||
|
||||
// initialize all point referrers with the default values
|
||||
mCurLayer->mPointReferrers.reserve ( regularSize + (regularSize>>2u) );
|
||||
mCurLayer->mPointReferrers.resize ( regularSize, 0xffffffff );
|
||||
}
|
||||
else mCurLayer->mTempPoints.resize( regularSize );
|
||||
|
||||
// perform endianess conversions
|
||||
#ifndef AI_BUILD_BIG_ENDIAN
|
||||
@@ -544,17 +669,16 @@ void LWOImporter::LoadLWOPoints(unsigned int length)
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2Polygons(unsigned int length)
|
||||
{
|
||||
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer += 4;length-=4;
|
||||
AI_LSWAP4(type);
|
||||
LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
|
||||
uint32_t type = GetU4();
|
||||
|
||||
if (type != AI_LWO_FACE)
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: Only POLS.FACE chunsk are supported.");
|
||||
DefaultLogger::get()->warn("LWO2: Only POLS.FACE chunks 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;
|
||||
|
||||
unsigned int iNumFaces = 0,iNumVertices = 0;
|
||||
@@ -616,21 +740,22 @@ void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it,
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
|
||||
{
|
||||
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
|
||||
AI_LSWAP4(type);
|
||||
LE_NCONST uint8_t* const end = mFileBuffer+length;
|
||||
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(length,PTAG,4);
|
||||
uint32_t type = GetU4();
|
||||
|
||||
if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
|
||||
return;
|
||||
|
||||
LE_NCONST uint8_t* const end = mFileBuffer+length;
|
||||
while (mFileBuffer <= end)
|
||||
while (mFileBuffer < end)
|
||||
{
|
||||
unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
|
||||
unsigned int j = ReadVSizedIntLWO2(mFileBuffer);
|
||||
unsigned int j = GetU2();
|
||||
|
||||
if (i >= mCurLayer->mFaces.size())
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: face index in ptag list is out of range");
|
||||
DefaultLogger::get()->warn("LWO2: face index in PTAG is out of range");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -646,14 +771,88 @@ void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPoly)
|
||||
{
|
||||
for (typename std::vector< T >::iterator it = list.begin(), end = list.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
if ((*it).name == name)
|
||||
{
|
||||
if (!perPoly)
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: Found two VMAP sections with equal names");
|
||||
}
|
||||
return &(*it);
|
||||
}
|
||||
}
|
||||
list.push_back( T() );
|
||||
VMapEntry* p = &list.back();
|
||||
p->name = name;
|
||||
return p;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx)
|
||||
{
|
||||
for (typename std::vector< T >::iterator
|
||||
it = list.begin(), end = list.end();
|
||||
it != end;++it)
|
||||
{
|
||||
T& chan = *it;
|
||||
for (unsigned int a = 0; a < chan.dims;++a)
|
||||
{
|
||||
chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]);
|
||||
chan.abAssigned[srcIdx] = true;
|
||||
chan.abAssigned.resize(chan.abAssigned.size()+1,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int numRead,
|
||||
unsigned int idx, float* data)
|
||||
{
|
||||
ai_assert(NULL != data);
|
||||
LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
|
||||
unsigned int i;
|
||||
|
||||
base->abAssigned[idx] = true;
|
||||
for (i = 0; i < numRead;++i)
|
||||
base->rawData[idx*base->dims+i]= data[i];
|
||||
|
||||
if (0xffffffff != (i = refList[idx]))
|
||||
DoRecursiveVMAPAssignment(base,numRead,i,data);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void AddToSingleLinkedList(ReferrerList& refList, unsigned int srcIdx, unsigned int destIdx)
|
||||
{
|
||||
if(0xffffffff == refList[srcIdx])
|
||||
{
|
||||
refList[srcIdx] = destIdx;
|
||||
return;
|
||||
}
|
||||
AddToSingleLinkedList(refList,refList[srcIdx],destIdx);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
LE_NCONST uint8_t* const end = mFileBuffer+length;
|
||||
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(length,VMAP,6);
|
||||
unsigned int type = GetU4();
|
||||
unsigned int dims = GetU2();
|
||||
|
||||
VMapEntry* base;
|
||||
|
||||
// read the name of the vertex map
|
||||
std::string name;
|
||||
GetS0(name,length);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case AI_LWO_TXUV:
|
||||
@@ -661,51 +860,139 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: Found UV channel with != 2 components");
|
||||
}
|
||||
mCurLayer->mUVChannels.push_back(UVChannel((unsigned int)mCurLayer->mTempPoints.size()));
|
||||
base = &mCurLayer->mUVChannels.back();
|
||||
base = FindEntry(mCurLayer->mUVChannels,name,perPoly);
|
||||
break;
|
||||
case AI_LWO_WGHT:
|
||||
if (dims != 1)
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: found vertex weight map with != 1 components");
|
||||
}
|
||||
mCurLayer->mWeightChannels.push_back(WeightChannel((unsigned int)mCurLayer->mTempPoints.size()));
|
||||
base = &mCurLayer->mWeightChannels.back();
|
||||
base = FindEntry(mCurLayer->mWeightChannels,name,perPoly);
|
||||
break;
|
||||
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((unsigned int)mCurLayer->mTempPoints.size()));
|
||||
base = &mCurLayer->mVColorChannels.back();
|
||||
base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
|
||||
break;
|
||||
default: return;
|
||||
};
|
||||
|
||||
// read the name of the vertex map
|
||||
ParseString(base->name,length);
|
||||
base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
|
||||
|
||||
// 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;
|
||||
LWO::FaceList& list = mCurLayer->mFaces;
|
||||
LWO::PointList& pointList = mCurLayer->mTempPoints;
|
||||
LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
|
||||
|
||||
float temp[4];
|
||||
|
||||
while (mFileBuffer < end)
|
||||
{
|
||||
unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs;
|
||||
if (idx > mCurLayer->mTempPoints.size())
|
||||
if (idx >= pointList.size())
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: vertex index in vmap/vmad is out of range");
|
||||
continue;
|
||||
mFileBuffer += base->dims*4;continue;
|
||||
}
|
||||
for (unsigned int i = 0; i < type;++i)
|
||||
if (perPoly)
|
||||
{
|
||||
base->rawData[idx*dims+i]= *((float*)mFileBuffer);
|
||||
mFileBuffer += 4;
|
||||
unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
|
||||
if (base->abAssigned[idx])
|
||||
{
|
||||
// we have already a VMAP entry for this vertex - thus
|
||||
// we need to duplicate the corresponding polygon.
|
||||
if (polyIdx >= list.size())
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: VMAD polygon index is out of range");
|
||||
mFileBuffer += base->dims*4;continue;
|
||||
}
|
||||
|
||||
LWO::Face& src = list[polyIdx];
|
||||
|
||||
// generate new vertex positions
|
||||
for (unsigned int i = 0; i < src.mNumIndices;++i)
|
||||
{
|
||||
register unsigned int srcIdx = src.mIndices[i];
|
||||
|
||||
// store the index of the new vertex in the old vertex
|
||||
// so we get a single linked list we can traverse in
|
||||
// only one direction
|
||||
refList.push_back(0xffffffff);
|
||||
AddToSingleLinkedList(refList,srcIdx,(src.mIndices[i] = (unsigned int)pointList.size()));
|
||||
pointList.push_back(pointList[srcIdx]);
|
||||
|
||||
CreateNewEntry(mCurLayer->mVColorChannels, srcIdx );
|
||||
CreateNewEntry(mCurLayer->mUVChannels, srcIdx );
|
||||
CreateNewEntry(mCurLayer->mWeightChannels, srcIdx );
|
||||
}
|
||||
}
|
||||
}
|
||||
for (unsigned int l = 0; l < type;++l)
|
||||
temp[l] = GetF4();
|
||||
|
||||
DoRecursiveVMAPAssignment(base,type,idx, temp);
|
||||
mFileBuffer += diff;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2Clip(unsigned int length)
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(length,CLIP,10);
|
||||
|
||||
mClips.push_back(LWO::Clip());
|
||||
LWO::Clip& clip = mClips.back();
|
||||
|
||||
// first - get the index of the clip
|
||||
clip.idx = GetU4();
|
||||
|
||||
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
|
||||
switch (head->type)
|
||||
{
|
||||
case AI_LWO_STIL:
|
||||
GetS0(clip.path,head->length);
|
||||
clip.type = Clip::STILL;
|
||||
break;
|
||||
|
||||
case AI_LWO_ISEQ:
|
||||
{
|
||||
uint8_t digits = GetU1(); mFileBuffer++;
|
||||
int16_t offset = GetU2(); mFileBuffer+=4;
|
||||
int16_t start = GetU2(); mFileBuffer+=4;
|
||||
|
||||
std::string s;std::stringstream ss;
|
||||
GetS0(s,head->length);head->length -= (unsigned int)s.length()+1;
|
||||
ss << s;
|
||||
ss << std::setw(digits) << offset + start;
|
||||
GetS0(s,head->length);
|
||||
ss << s;
|
||||
clip.path = ss.str();
|
||||
clip.type = Clip::SEQ;
|
||||
}
|
||||
break;
|
||||
|
||||
case AI_LWO_STCC:
|
||||
DefaultLogger::get()->warn("LWO2: Color shifted images are not supported");
|
||||
break;
|
||||
|
||||
case AI_LWO_ANIM:
|
||||
DefaultLogger::get()->warn("LWO2: Animated textures are not supported");
|
||||
break;
|
||||
|
||||
case AI_LWO_XREF:
|
||||
clip.type = Clip::REF;
|
||||
clip.clipRef = GetU4();
|
||||
break;
|
||||
|
||||
default:
|
||||
DefaultLogger::get()->warn("LWO2: Encountered unknown CLIP subchunk");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2File()
|
||||
@@ -714,14 +1001,11 @@ void LWOImporter::LoadLWO2File()
|
||||
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);
|
||||
LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
|
||||
|
||||
if (mFileBuffer + head->length > end)
|
||||
{
|
||||
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
|
||||
"a chunk points behind the end of the file");
|
||||
throw new ImportErrorException("LWO2: Chunk length points behind the file");
|
||||
break;
|
||||
}
|
||||
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
|
||||
@@ -738,9 +1022,13 @@ void LWOImporter::LoadLWO2File()
|
||||
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
|
||||
|
||||
// and parse its properties
|
||||
mFileBuffer += 16;
|
||||
ParseString(layer.mName,head->length-16);
|
||||
// and parse its properties, e.g. the pivot point
|
||||
mFileBuffer += 2;
|
||||
mCurLayer->mPivot.x = GetF4();
|
||||
mCurLayer->mPivot.y = GetF4();
|
||||
mCurLayer->mPivot.z = GetF4();
|
||||
mFileBuffer += 2;
|
||||
GetS0(layer.mName,head->length-16);
|
||||
|
||||
// if the name is empty, generate a default name
|
||||
if (layer.mName.empty())
|
||||
@@ -751,7 +1039,7 @@ void LWOImporter::LoadLWO2File()
|
||||
}
|
||||
|
||||
if (mFileBuffer + 2 <= next)
|
||||
layer.mParent = *((uint16_t*)mFileBuffer);
|
||||
layer.mParent = GetU2();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -765,11 +1053,17 @@ void LWOImporter::LoadLWO2File()
|
||||
break;
|
||||
}
|
||||
// vertex tags
|
||||
//case AI_LWO_VMAD:
|
||||
case AI_LWO_VMAD:
|
||||
if (mCurLayer->mFaces.empty())
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: Unexpected VMAD chunk");
|
||||
break;
|
||||
}
|
||||
// --- intentionally no break here
|
||||
case AI_LWO_VMAP:
|
||||
{
|
||||
if (mCurLayer->mTempPoints.empty())
|
||||
DefaultLogger::get()->warn("LWO2: Unexpected VMAD/VMAP chunk");
|
||||
DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
|
||||
else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
|
||||
break;
|
||||
}
|
||||
@@ -804,6 +1098,13 @@ void LWOImporter::LoadLWO2File()
|
||||
LoadLWO2Surface(head->length);
|
||||
break;
|
||||
}
|
||||
|
||||
// clip chunk
|
||||
case AI_LWO_CLIP:
|
||||
{
|
||||
LoadLWO2Clip(head->length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mFileBuffer = next;
|
||||
}
|
||||
|
||||
159
code/LWOLoader.h
159
code/LWOLoader.h
@@ -43,9 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define AI_LWOLOADER_H_INCLUDED
|
||||
|
||||
#include "../include/aiTypes.h"
|
||||
#include "../include/DefaultLogger.h"
|
||||
|
||||
#include "BaseImporter.h"
|
||||
#include "LWOFileData.h"
|
||||
#include "BaseImporter.h"
|
||||
#include "MaterialSystem.h"
|
||||
|
||||
struct aiTexture;
|
||||
@@ -63,6 +64,7 @@ using namespace LWO;
|
||||
* Methods named "xxx" are used to preprocess the loaded data -
|
||||
* they aren't specific to one format version, either
|
||||
*/
|
||||
// ---------------------------------------------------------------------------
|
||||
class LWOImporter : public BaseImporter
|
||||
{
|
||||
friend class Importer;
|
||||
@@ -120,6 +122,17 @@ private:
|
||||
*/
|
||||
void LoadLWO2File();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parsing functions used for all file format versions
|
||||
*/
|
||||
inline void GetS0(std::string& out,unsigned int max);
|
||||
inline float GetF4();
|
||||
inline uint32_t GetU4();
|
||||
inline uint16_t GetU2();
|
||||
inline uint8_t GetU1();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Loads a surface chunk from an LWOB file
|
||||
* @param size Maximum size to be read, in bytes.
|
||||
@@ -135,9 +148,18 @@ private:
|
||||
// -------------------------------------------------------------------
|
||||
/** Loads a texture block from a LWO2 file.
|
||||
* @param size Maximum size to be read, in bytes.
|
||||
* @param type Type of the texture block - PROC, GRAD or IMAP
|
||||
* @param head Header of the SUF.BLOK header
|
||||
*/
|
||||
void LoadLWO2TextureBlock(uint32_t type, unsigned int size );
|
||||
void LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader* head,
|
||||
unsigned int size );
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Loads a shader block from a LWO2 file.
|
||||
* @param size Maximum size to be read, in bytes.
|
||||
* @param head Header of the SUF.BLOK header
|
||||
*/
|
||||
void LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* head,
|
||||
unsigned int size );
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Loads an image map from a LWO2 file
|
||||
@@ -183,6 +205,12 @@ private:
|
||||
*/
|
||||
void LoadLWOPoints(unsigned int length);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load a clip from a CLIP chunk
|
||||
* @param length Size of the chunk
|
||||
*/
|
||||
void LoadLWO2Clip(unsigned int length);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Count vertices and faces in a LWOB/LWO2 file
|
||||
@@ -206,6 +234,7 @@ private:
|
||||
LE_NCONST uint16_t*& cursor,
|
||||
const uint16_t* const end);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void CopyFaceIndicesLWOB(LWO::FaceList::iterator& it,
|
||||
LE_NCONST uint16_t*& cursor,
|
||||
const uint16_t* const end,
|
||||
@@ -213,14 +242,27 @@ private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Resolve the tag and surface lists that have been loaded.
|
||||
* Generates the mMapping table.
|
||||
* Generates the mMapping table.
|
||||
*/
|
||||
void ResolveTags();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a string from the current file position
|
||||
/** Resolve the clip list that has been loaded.
|
||||
* Replaces clip references with real clips.
|
||||
*/
|
||||
void ParseString(std::string& out,unsigned int max);
|
||||
void ResolveClips();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a texture list to an output material description.
|
||||
*
|
||||
* @param pcMat Output material
|
||||
* @param in Input texture list
|
||||
* @param type Type identifier of the texture list. This is the string
|
||||
* that appears in the middle of all material keys - e.g. "diffuse",
|
||||
* "shininess", "glossiness" or "specular".
|
||||
*/
|
||||
bool HandleTextures(MaterialHelper* pcMat, const TextureList& in,
|
||||
const char* type);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Adjust a texture path
|
||||
@@ -241,10 +283,15 @@ private:
|
||||
* @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,
|
||||
void FindUVChannels(/*const*/ LWO::Surface& surf,
|
||||
/*const*/ LWO::Layer& layer,
|
||||
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void FindUVChannels(LWO::TextureList& list, LWO::Layer& layer,
|
||||
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS], unsigned int& next);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void FindVCChannels(const LWO::Surface& surf,
|
||||
const LWO::Layer& layer,
|
||||
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]);
|
||||
@@ -271,6 +318,27 @@ private:
|
||||
*/
|
||||
int ReadVSizedIntLWO2(uint8_t*& inout);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Assign a value from a VMAP to a vertex and all vertices
|
||||
* attached to it.
|
||||
* @param base VMAP destination data
|
||||
* @param numRead Number of float's to be read
|
||||
* @param idx Absolute index of the first vertex
|
||||
* @param data Value of the VMAP to be assigned - read numRead
|
||||
* floats from this array.
|
||||
*/
|
||||
void DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int numRead,
|
||||
unsigned int idx, float* data);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Compute normal vectors for a mesh
|
||||
* @param mesh Input mesh
|
||||
* @param smoothingGroups Smoothing-groups-per-face array
|
||||
* @param surface Surface for the mesh
|
||||
*/
|
||||
void ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>& smoothingGroups,
|
||||
const LWO::Surface& surface);
|
||||
|
||||
protected:
|
||||
|
||||
/** true if the file is a LWO2 file*/
|
||||
@@ -305,6 +373,81 @@ protected:
|
||||
aiScene* pScene;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline float LWOImporter::GetF4()
|
||||
{
|
||||
float f = *((float*)mFileBuffer);mFileBuffer += 4;
|
||||
AI_LSWAP4(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline uint32_t LWOImporter::GetU4()
|
||||
{
|
||||
uint32_t f = *((uint32_t*)mFileBuffer);mFileBuffer += 4;
|
||||
AI_LSWAP4(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline uint16_t LWOImporter::GetU2()
|
||||
{
|
||||
uint16_t f = *((uint16_t*)mFileBuffer);mFileBuffer += 2;
|
||||
AI_LSWAP2(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline uint8_t LWOImporter::GetU1()
|
||||
{
|
||||
return *mFileBuffer++;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline 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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline void LWOImporter::GetS0(std::string& out,unsigned int max)
|
||||
{
|
||||
unsigned int iCursor = 0;
|
||||
const char*sz = (const char*)mFileBuffer;
|
||||
while (*mFileBuffer)
|
||||
{
|
||||
if (++iCursor > max)
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO: Invalid file, string is is too long");
|
||||
break;
|
||||
}
|
||||
++mFileBuffer;
|
||||
}
|
||||
unsigned int len = (unsigned int) ((const char*)mFileBuffer-sz);
|
||||
out = std::string(sz,len);
|
||||
mFileBuffer += (len&0x1 ? 1 : 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // AI_LWOIMPORTER_H_INCLUDED
|
||||
|
||||
@@ -58,6 +58,142 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
T lerp(const T& one, const T& two, float val)
|
||||
{
|
||||
return one + (two-one)*val;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case LWO::Texture::REPEAT:
|
||||
return aiTextureMapMode_Wrap;
|
||||
case LWO::Texture::MIRROR:
|
||||
return aiTextureMapMode_Mirror;
|
||||
case LWO::Texture::RESET:
|
||||
DefaultLogger::get()->warn("LWO2: Unsupported texture map mode: RESET");
|
||||
case LWO::Texture::EDGE:
|
||||
return aiTextureMapMode_Clamp;
|
||||
}
|
||||
return (aiTextureMapMode)0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, const char* type)
|
||||
{
|
||||
ai_assert(NULL != pcMat && NULL != type);
|
||||
|
||||
unsigned int cur = 0, temp = 0;
|
||||
char buffer[512];
|
||||
aiString s;
|
||||
bool ret = false;
|
||||
|
||||
for (TextureList::const_iterator it = in.begin(), end = in.end();
|
||||
it != end;++it)
|
||||
{
|
||||
if (!(*it).enabled || !(*it).bCanUse || 0xffffffff == (*it).mRealUVIndex)continue;
|
||||
ret = true;
|
||||
|
||||
// add the path to the texture
|
||||
sprintf(buffer,"$tex.file.%s[%i]",type,cur);
|
||||
|
||||
// The older LWOB format does not use indirect references to clips.
|
||||
// The file name of a texture is directly specified in the tex chunk.
|
||||
if (mIsLWO2)
|
||||
{
|
||||
// find the corresponding clip
|
||||
ClipList::iterator clip = mClips.begin();
|
||||
temp = (*it).mClipIdx;
|
||||
for (ClipList::iterator end = mClips.end(); clip != end; ++clip)
|
||||
{
|
||||
if ((*clip).idx == temp)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mClips.end() == clip)
|
||||
{
|
||||
DefaultLogger::get()->error("LWO2: Clip index is out of bounds");
|
||||
temp = 0;
|
||||
}
|
||||
if (Clip::UNSUPPORTED == (*clip).type)
|
||||
{
|
||||
DefaultLogger::get()->error("LWO2: Clip type is not supported");
|
||||
continue;
|
||||
}
|
||||
AdjustTexturePath((*clip).path);
|
||||
s.Set((*clip).path);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string ss = (*it).mFileName;
|
||||
if (!ss.length())
|
||||
{
|
||||
DefaultLogger::get()->error("LWOB: Empty file name");
|
||||
continue;
|
||||
}
|
||||
AdjustTexturePath(ss);
|
||||
s.Set(ss);
|
||||
}
|
||||
pcMat->AddProperty(&s,buffer);
|
||||
|
||||
// add the blend factor
|
||||
sprintf(buffer,"$tex.blend.%s[%i]",type,cur);
|
||||
pcMat->AddProperty(&(*it).mStrength,1,buffer);
|
||||
|
||||
// add the blend operation
|
||||
sprintf(buffer,"$tex.op.%s[%i]",type,cur);
|
||||
switch ((*it).blendType)
|
||||
{
|
||||
case LWO::Texture::Normal:
|
||||
case LWO::Texture::Multiply:
|
||||
temp = (unsigned int)aiTextureOp_Multiply;
|
||||
break;
|
||||
|
||||
case LWO::Texture::Subtractive:
|
||||
case LWO::Texture::Difference:
|
||||
temp = (unsigned int)aiTextureOp_Subtract;
|
||||
break;
|
||||
|
||||
case LWO::Texture::Divide:
|
||||
temp = (unsigned int)aiTextureOp_Divide;
|
||||
break;
|
||||
|
||||
case LWO::Texture::Additive:
|
||||
temp = (unsigned int)aiTextureOp_Add;
|
||||
break;
|
||||
|
||||
default:
|
||||
temp = (unsigned int)aiTextureOp_Multiply;
|
||||
DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement");
|
||||
|
||||
}
|
||||
pcMat->AddProperty<int>((int*)&temp,1,buffer);
|
||||
|
||||
// add the UV source index
|
||||
sprintf(buffer,"$tex.uvw.%s[%i]",type,cur);
|
||||
temp = (*it).mRealUVIndex;
|
||||
pcMat->AddProperty<int>((int*)&temp,1,buffer);
|
||||
|
||||
// add the u-wrapping
|
||||
sprintf(buffer,"$tex.mapmodeu.%s[%i]",type,cur);
|
||||
temp = (unsigned int)GetMapMode((*it).wrapModeWidth);
|
||||
pcMat->AddProperty<int>((int*)&temp,1,buffer);
|
||||
|
||||
// add the v-wrapping
|
||||
sprintf(buffer,"$tex.mapmodev.%s[%i]",type,cur);
|
||||
temp = (unsigned int)GetMapMode((*it).wrapModeHeight);
|
||||
pcMat->AddProperty<int>((int*)&temp,1,buffer);
|
||||
|
||||
++cur;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat)
|
||||
{
|
||||
@@ -68,13 +204,19 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
|
||||
|
||||
int i = surf.bDoubleSided ? 1 : 0;
|
||||
pcMat->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
|
||||
|
||||
// add the refraction index and the bump intensity
|
||||
pcMat->AddProperty<float>(&surf.mIOR,1,AI_MATKEY_REFRACTI);
|
||||
pcMat->AddProperty<float>(&surf.mBumpIntensity,1,AI_MATKEY_BUMPSCALING);
|
||||
|
||||
aiShadingMode m;
|
||||
if (surf.mSpecularValue && surf.mGlossiness)
|
||||
{
|
||||
// this is only an assumption, needs to be confirmed.
|
||||
// the values have been tweaked by hand and seem to be correct.
|
||||
float fGloss;
|
||||
if (mIsLWO2)fGloss = surf.mGlossiness * 50.0f;
|
||||
if (mIsLWO2)
|
||||
{
|
||||
fGloss = pow( surf.mGlossiness*10.0f+2.0f, 2.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (16.0f >= surf.mGlossiness)fGloss = 6.0f;
|
||||
@@ -85,18 +227,14 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
|
||||
|
||||
pcMat->AddProperty<float>(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
|
||||
pcMat->AddProperty<float>(&fGloss,1,AI_MATKEY_SHININESS);
|
||||
m = aiShadingMode_Phong;
|
||||
}
|
||||
|
||||
// (the diffuse value is just a scaling factor)
|
||||
aiColor3D clr = surf.mColor;
|
||||
clr.r *= surf.mDiffuseValue;
|
||||
clr.g *= surf.mDiffuseValue;
|
||||
clr.b *= surf.mDiffuseValue;
|
||||
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
else m = aiShadingMode_Gouraud;
|
||||
|
||||
// specular color
|
||||
clr.b = clr.g = clr.r = surf.mSpecularValue;
|
||||
aiColor3D clr = lerp( aiColor3D(1.f,1.f,1.f), surf.mColor, surf.mColorHighlights );
|
||||
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_SPECULAR);
|
||||
pcMat->AddProperty<float>(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
|
||||
|
||||
// emissive color
|
||||
// (luminosity is not really the same but it affects the surface in
|
||||
@@ -108,15 +246,113 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
|
||||
float f = 1.0f-surf.mTransparency;
|
||||
pcMat->AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
|
||||
|
||||
// now handle all textures ...
|
||||
// TODO
|
||||
// ADD TEXTURES to the material
|
||||
// TODO: find out how we can handle COLOR textures correctly...
|
||||
bool b = HandleTextures(pcMat,surf.mColorTextures,"diffuse");
|
||||
b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,"diffuse"));
|
||||
HandleTextures(pcMat,surf.mSpecularTextures,"specular");
|
||||
HandleTextures(pcMat,surf.mGlossinessTextures,"shininess");
|
||||
HandleTextures(pcMat,surf.mBumpTextures,"height");
|
||||
HandleTextures(pcMat,surf.mOpacityTextures,"opacity");
|
||||
|
||||
// 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
|
||||
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")
|
||||
{
|
||||
m = aiShadingMode_Toon;
|
||||
break;
|
||||
}
|
||||
else if ((*it).functionName == "LW_RealFresnel" ||
|
||||
(*it).functionName == "LW_FastFresnel")
|
||||
{
|
||||
m = aiShadingMode_Fresnel;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultLogger::get()->warn("LWO2: Unknown surface shader: " + (*it).functionName);
|
||||
}
|
||||
}
|
||||
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.r *= surf.mDiffuseValue;
|
||||
clr.g *= surf.mDiffuseValue;
|
||||
clr.b *= surf.mDiffuseValue;
|
||||
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::FindUVChannels(const LWO::Surface& surf, const LWO::Layer& layer,
|
||||
void LWOImporter::FindUVChannels(LWO::TextureList& list, LWO::Layer& layer,
|
||||
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS], unsigned int& next)
|
||||
{
|
||||
for (TextureList::iterator it = list.begin(), end = list.end();
|
||||
it != end;++it)
|
||||
{
|
||||
if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex)continue;
|
||||
switch ((*it).mapMode)
|
||||
{
|
||||
// TODO: implement these special mappings ...
|
||||
case LWO::Texture::Spherical:
|
||||
case LWO::Texture::Cylindrical:
|
||||
case LWO::Texture::Cubic:
|
||||
case LWO::Texture::Planar:
|
||||
case LWO::Texture::FrontProjection:
|
||||
|
||||
DefaultLogger::get()->warn("LWO2: Only UV mapping is currently supported.");
|
||||
continue;
|
||||
|
||||
default: ;
|
||||
}
|
||||
for (unsigned int i = 0; i < layer.mUVChannels.size();++i)
|
||||
{
|
||||
if ((*it).mUVChannelIndex == layer.mUVChannels[i].name)
|
||||
{
|
||||
// check whether we have this channel already
|
||||
for (unsigned int m = 0; m < next;++m)
|
||||
{
|
||||
if (i == out[m])
|
||||
{
|
||||
(*it).mRealUVIndex = m;
|
||||
}
|
||||
}
|
||||
if (0xffffffff == (*it).mRealUVIndex)
|
||||
{
|
||||
(*it).mRealUVIndex = next;
|
||||
out[next++] = i;
|
||||
if (AI_MAX_NUMBER_OF_TEXTURECOORDS != next)
|
||||
out[next] = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (0xffffffff == (*it).mRealUVIndex)
|
||||
DefaultLogger::get()->error("LWO2: Unable to find matching UV channel for a texture");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::FindUVChannels(LWO::Surface& surf, LWO::Layer& layer,
|
||||
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS])
|
||||
{
|
||||
out[0] = 0xffffffff;
|
||||
unsigned int next = 0;
|
||||
|
||||
FindUVChannels(surf.mColorTextures,layer,out,next);
|
||||
FindUVChannels(surf.mDiffuseTextures,layer,out,next);
|
||||
FindUVChannels(surf.mSpecularTextures,layer,out,next);
|
||||
FindUVChannels(surf.mGlossinessTextures,layer,out,next);
|
||||
FindUVChannels(surf.mOpacityTextures,layer,out,next);
|
||||
FindUVChannels(surf.mBumpTextures,layer,out,next);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -124,41 +360,240 @@ void LWOImporter::FindVCChannels(const LWO::Surface& surf, const LWO::Layer& lay
|
||||
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS])
|
||||
{
|
||||
out[0] = 0xffffffff;
|
||||
if (surf.mVCMap.length())
|
||||
{
|
||||
for (unsigned int i = 0; i < layer.mVColorChannels.size();++i)
|
||||
{
|
||||
if (surf.mVCMap == layer.mVColorChannels[i].name)
|
||||
{
|
||||
out[0] = i;
|
||||
out[1] = 0xffffffff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
DefaultLogger::get()->warn("LWO2: Unable to find vertex color channel: " + surf.mVCMap);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
|
||||
{
|
||||
//LE_NCONST uint8_t* const end = mFileBuffer + size;
|
||||
LE_NCONST uint8_t* const end = mFileBuffer + size;
|
||||
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 SURF.BLOCK chunk length");
|
||||
|
||||
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
|
||||
switch (head->type)
|
||||
{
|
||||
case AI_LWO_PROJ:
|
||||
tex.wrapModeWidth = (Texture::Wrap)GetU2();
|
||||
tex.wrapModeHeight = (Texture::Wrap)GetU2();
|
||||
break;
|
||||
case AI_LWO_AXIS:
|
||||
tex.majorAxis = (Texture::Axes)GetU2();
|
||||
break;
|
||||
case AI_LWO_IMAG:
|
||||
tex.mClipIdx = GetU2();
|
||||
break;
|
||||
case AI_LWO_VMAP:
|
||||
GetS0(tex.mUVChannelIndex,head->length);
|
||||
break;
|
||||
case AI_LWO_WRPH:
|
||||
tex.wrapAmountH = GetF4();
|
||||
break;
|
||||
case AI_LWO_WRPW:
|
||||
tex.wrapAmountW = GetF4();
|
||||
break;
|
||||
}
|
||||
mFileBuffer = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2Procedural(unsigned int size, LWO::Texture& tex )
|
||||
{
|
||||
// --- not supported at the moment
|
||||
DefaultLogger::get()->error("LWO2: Found procedural texture, this is not supported");
|
||||
tex.bCanUse = false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2Gradient(unsigned int size, LWO::Texture& tex )
|
||||
{
|
||||
// --- not supported at the moment
|
||||
DefaultLogger::get()->error("LWO2: Found gradient texture, this is not supported");
|
||||
tex.bCanUse = false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture& tex )
|
||||
{
|
||||
//LE_NCONST uint8_t* const end = mFileBuffer + size;
|
||||
LE_NCONST uint8_t* const end = mFileBuffer + size;
|
||||
|
||||
// get the ordinal string
|
||||
GetS0( tex.ordinal, size);
|
||||
|
||||
// we could crash later if this is an empty string ...
|
||||
if (!tex.ordinal.length())
|
||||
{
|
||||
DefaultLogger::get()->error("LWO2: Ill-formed SURF.BLOK ordinal string");
|
||||
tex.ordinal = "\x00";
|
||||
}
|
||||
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 texture header chunk length");
|
||||
|
||||
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
|
||||
switch (head->type)
|
||||
{
|
||||
case AI_LWO_CHAN:
|
||||
tex.type = GetU4();
|
||||
break;
|
||||
case AI_LWO_ENAB:
|
||||
tex.enabled = GetU2() ? true : false;
|
||||
break;
|
||||
case AI_LWO_OPAC:
|
||||
tex.blendType = (Texture::BlendType)GetU2();
|
||||
tex.mStrength = GetF4();
|
||||
break;
|
||||
}
|
||||
mFileBuffer = next;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2TextureBlock(uint32_t type, unsigned int size )
|
||||
void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader* head, unsigned int size )
|
||||
{
|
||||
//LE_NCONST uint8_t* const end = mFileBuffer + size;
|
||||
ai_assert(!mSurfaces->empty());
|
||||
LWO::Surface& surf = mSurfaces->back();
|
||||
LWO::Texture tex;
|
||||
|
||||
//LWO::Surface& surf = mSurfaces->back();
|
||||
//LWO::Texture tex;
|
||||
// load the texture header
|
||||
LoadLWO2TextureHeader(head->length,tex);
|
||||
size -= head->length + 6;
|
||||
|
||||
// now get the exact type of the texture
|
||||
switch (head->type)
|
||||
{
|
||||
case AI_LWO_PROC:
|
||||
LoadLWO2Procedural(size,tex);
|
||||
break;
|
||||
case AI_LWO_GRAD:
|
||||
LoadLWO2Gradient(size,tex);
|
||||
break;
|
||||
case AI_LWO_IMAP:
|
||||
LoadLWO2ImageMap(size,tex);
|
||||
}
|
||||
|
||||
// get the destination channel
|
||||
TextureList* listRef = NULL;
|
||||
switch (tex.type)
|
||||
{
|
||||
case AI_LWO_COLR:
|
||||
listRef = &surf.mColorTextures;break;
|
||||
case AI_LWO_DIFF:
|
||||
listRef = &surf.mDiffuseTextures;break;
|
||||
case AI_LWO_SPEC:
|
||||
listRef = &surf.mSpecularTextures;break;
|
||||
case AI_LWO_GLOS:
|
||||
listRef = &surf.mGlossinessTextures;break;
|
||||
case AI_LWO_BUMP:
|
||||
listRef = &surf.mBumpTextures;break;
|
||||
case AI_LWO_TRAN:
|
||||
listRef = &surf.mOpacityTextures;break;
|
||||
default:
|
||||
DefaultLogger::get()->warn("LWO2: Encountered unknown texture type");
|
||||
return;
|
||||
}
|
||||
|
||||
// now attach the texture to the parent surface - sort by ordinal string
|
||||
for (TextureList::iterator it = listRef->begin();
|
||||
it != listRef->end(); ++it)
|
||||
{
|
||||
if (::strcmp(tex.ordinal.c_str(),(*it).ordinal.c_str()) < 0)
|
||||
{
|
||||
listRef->insert(it,tex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
listRef->push_back(tex);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* head, unsigned int size )
|
||||
{
|
||||
LE_NCONST uint8_t* const end = mFileBuffer + size;
|
||||
|
||||
ai_assert(!mSurfaces->empty());
|
||||
LWO::Surface& surf = mSurfaces->back();
|
||||
LWO::Shader shader;
|
||||
|
||||
// get the ordinal string
|
||||
GetS0( shader.ordinal, size);
|
||||
|
||||
// we could crash later if this is an empty string ...
|
||||
if (!shader.ordinal.length())
|
||||
{
|
||||
DefaultLogger::get()->error("LWO2: Ill-formed SURF.BLOK ordinal string");
|
||||
shader.ordinal = "\x00";
|
||||
}
|
||||
|
||||
// read the header
|
||||
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 shader header chunk length");
|
||||
|
||||
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
|
||||
switch (head->type)
|
||||
{
|
||||
case AI_LWO_ENAB:
|
||||
shader.enabled = GetU2() ? true : false;
|
||||
}
|
||||
mFileBuffer = next;
|
||||
}
|
||||
|
||||
// process other 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 shader data chunk length");
|
||||
|
||||
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
|
||||
switch (head->type)
|
||||
{
|
||||
case AI_LWO_FUNC:
|
||||
GetS0( shader.functionName, head->length );
|
||||
}
|
||||
mFileBuffer = next;
|
||||
}
|
||||
|
||||
// now attach the shader to the parent surface - sort by ordinal string
|
||||
for (ShaderList::iterator it = surf.mShaders.begin();
|
||||
it != surf.mShaders.end(); ++it)
|
||||
{
|
||||
if (::strcmp(shader.ordinal.c_str(),(*it).ordinal.c_str()) < 0)
|
||||
{
|
||||
surf.mShaders.insert(it,shader);
|
||||
return;
|
||||
}
|
||||
}
|
||||
surf.mShaders.push_back(shader);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -169,88 +604,131 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
|
||||
mSurfaces->push_back( LWO::Surface () );
|
||||
LWO::Surface& surf = mSurfaces->back();
|
||||
|
||||
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;
|
||||
mFileBuffer += 2;
|
||||
GetS0(surf.mName,size);
|
||||
|
||||
// check whether this surface was derived from any other surface
|
||||
std::string derived;
|
||||
GetS0(derived,(unsigned int)(end - mFileBuffer));
|
||||
if (derived.length())
|
||||
{
|
||||
|
||||
// yes, find this surface
|
||||
for (SurfaceList::iterator it = mSurfaces->begin(), end = mSurfaces->end()-1;
|
||||
it != end; ++it)
|
||||
{
|
||||
if ((*it).mName == derived)
|
||||
{
|
||||
// we have it ...
|
||||
surf = *it;
|
||||
derived.clear();
|
||||
}
|
||||
}
|
||||
if (!derived.size())
|
||||
DefaultLogger::get()->warn("LWO2: Unable to find source surface: " + derived);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (mFileBuffer + 6 >= end)break;
|
||||
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
|
||||
|
||||
// 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("LWO2: 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)
|
||||
if (mFileBuffer + head->length > end)
|
||||
throw new ImportErrorException("LWO2: Invalid surface chunk length");
|
||||
|
||||
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,12);
|
||||
surf.mColor.r = ((float*)mFileBuffer)[0];
|
||||
surf.mColor.g = ((float*)mFileBuffer)[1];
|
||||
surf.mColor.b = ((float*)mFileBuffer)[2];
|
||||
AI_LSWAP4(surf.mColor.r);
|
||||
AI_LSWAP4(surf.mColor.g);
|
||||
AI_LSWAP4(surf.mColor.b);
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,12);
|
||||
surf.mColor.r = GetF4();
|
||||
surf.mColor.g = GetF4();
|
||||
surf.mColor.b = GetF4();
|
||||
break;
|
||||
}
|
||||
// diffuse strength ... hopefully
|
||||
case AI_LWO_DIFF:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,DIFF,4);
|
||||
surf.mDiffuseValue = *((float*)mFileBuffer);
|
||||
AI_LSWAP4(surf.mDiffuseValue);
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,4);
|
||||
surf.mDiffuseValue = GetF4();
|
||||
break;
|
||||
}
|
||||
// specular strength ... hopefully
|
||||
case AI_LWO_SPEC:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,SPEC,4);
|
||||
surf.mSpecularValue = *((float*)mFileBuffer);
|
||||
AI_LSWAP4(surf.mSpecularValue);
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,4);
|
||||
surf.mSpecularValue = GetF4();
|
||||
break;
|
||||
}
|
||||
// transparency
|
||||
case AI_LWO_TRAN:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TRAN,4);
|
||||
surf.mTransparency = *((float*)mFileBuffer);
|
||||
AI_LSWAP4(surf.mTransparency);
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4);
|
||||
surf.mTransparency = GetF4();
|
||||
break;
|
||||
}
|
||||
// glossiness
|
||||
case AI_LWO_GLOS:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,GLOS,4);
|
||||
surf.mGlossiness = *((float*)mFileBuffer);
|
||||
AI_LSWAP4(surf.mGlossiness);
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,4);
|
||||
surf.mGlossiness = GetF4();
|
||||
break;
|
||||
}
|
||||
// bump intensity
|
||||
case AI_LWO_BUMP:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,BUMP,4);
|
||||
surf.mBumpIntensity = GetF4();
|
||||
break;
|
||||
}
|
||||
// color highlights
|
||||
case AI_LWO_CLRH:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,CLRH,4);
|
||||
surf.mColorHighlights = GetF4();
|
||||
break;
|
||||
}
|
||||
// index of refraction
|
||||
case AI_LWO_RIND:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,RIND,4);
|
||||
surf.mIOR = GetF4();
|
||||
break;
|
||||
}
|
||||
// polygon sidedness
|
||||
case AI_LWO_SIDE:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SIDE,2);
|
||||
surf.bDoubleSided = (3 == GetU2());
|
||||
break;
|
||||
}
|
||||
// maximum smoothing angle
|
||||
case AI_LWO_SMAN:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4);
|
||||
surf.mMaximumSmoothAngle = GetF4();
|
||||
break;
|
||||
}
|
||||
// surface bock entry
|
||||
case AI_LWO_BLOK:
|
||||
{
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,BLOK,4);
|
||||
uint32_t type = *((uint32_t*)mFileBuffer);
|
||||
AI_LSWAP4(type);
|
||||
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,BLOK,4);
|
||||
LE_NCONST IFF::SubChunkHeader* head2 = IFF::LoadSubChunk(mFileBuffer);
|
||||
|
||||
switch (type)
|
||||
switch (head2->type)
|
||||
{
|
||||
case AI_LWO_IMAP:
|
||||
case AI_LWO_PROC:
|
||||
break;
|
||||
case AI_LWO_GRAD:
|
||||
mFileBuffer+=4;
|
||||
LoadLWO2TextureBlock(type,head_length-4);
|
||||
case AI_LWO_IMAP:
|
||||
LoadLWO2TextureBlock(head2, head->length);
|
||||
break;
|
||||
case AI_LWO_SHDR:
|
||||
LoadLWO2ShaderBlock(head2, head->length);
|
||||
break;
|
||||
|
||||
default:
|
||||
DefaultLogger::get()->warn("LWO2: Found an unsupported surface BLOK");
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
@@ -226,7 +226,7 @@ void MDRImporter::InternReadFile(
|
||||
file->Read( &mBuffer2[0], 1, fileSize);
|
||||
mBuffer = &mBuffer2[0];
|
||||
|
||||
// validate the file header
|
||||
// validate the file header and do BigEndian byte swapping for all sub headers
|
||||
this->pcHeader = (BE_NCONST MDR::Header*)this->mBuffer;
|
||||
this->ValidateHeader();
|
||||
}
|
||||
@@ -83,9 +83,10 @@ void SGSpatialSort::Prepare()
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns an iterator for all positions close to the given position.
|
||||
void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||
uint32_t pSG,
|
||||
float pRadius,
|
||||
std::vector<unsigned int>& poResults) const
|
||||
uint32_t pSG,
|
||||
float pRadius,
|
||||
std::vector<unsigned int>& poResults,
|
||||
bool exactMatch /*= false*/) const
|
||||
{
|
||||
float dist = pPosition * mPlaneNormal;
|
||||
float minDist = dist - pRadius, maxDist = dist + pRadius;
|
||||
@@ -126,17 +127,44 @@ void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||
// Add all positions inside the distance range within the given radius to the result aray
|
||||
|
||||
float squareEpsilon = pRadius * pRadius;
|
||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||
while( it->mDistance < maxDist)
|
||||
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
|
||||
std::vector<Entry>::const_iterator end = mPositions.end();
|
||||
|
||||
if (exactMatch)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
|
||||
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups || 0 == pSG))
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon && it->mSmoothGroups == pSG)
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( end == it )break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the given smoothing group is 0, we'll return all surrounding vertices
|
||||
if (!pSG)
|
||||
{
|
||||
while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
|
||||
poResults.push_back( it->mIndex);
|
||||
++it;
|
||||
if( end == it)break;
|
||||
}
|
||||
}
|
||||
else while( it->mDistance < maxDist)
|
||||
{
|
||||
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
|
||||
(it->mSmoothGroups & pSG || !it->mSmoothGroups))
|
||||
{
|
||||
poResults.push_back( it->mIndex);
|
||||
}
|
||||
++it;
|
||||
if( end == it)break;
|
||||
}
|
||||
++it;
|
||||
if( it == mPositions.end())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,13 +46,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <vector>
|
||||
#include "../include/aiTypes.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------------
|
||||
/** Specialized version of SpatialSort to support smoothing groups
|
||||
* This is used in the .3ds loader
|
||||
* This is used in by the 3DS, ASE and LWO loaders. 3DS and ASE share their
|
||||
* normal computation code in SmoothingGroups.inl, the LWO loader has its own
|
||||
* implementation to handle all details of its file format correctly.
|
||||
*/
|
||||
// ----------------------------------------------------------------------------------
|
||||
class SGSpatialSort
|
||||
{
|
||||
public:
|
||||
@@ -60,7 +62,8 @@ public:
|
||||
SGSpatialSort();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Construction from a given face array, handling smoothing groups properly
|
||||
/** Construction from a given face array, handling smoothing groups
|
||||
* properly
|
||||
*/
|
||||
SGSpatialSort(const std::vector<aiVector3D>& vPositions);
|
||||
|
||||
@@ -74,7 +77,7 @@ public:
|
||||
unsigned int smoothingGroup);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Prepare the spatial sorter for use
|
||||
/** Prepare the spatial sorter for use. This step runs in O(logn)
|
||||
*/
|
||||
void Prepare();
|
||||
|
||||
@@ -85,27 +88,35 @@ public:
|
||||
/** Returns an iterator for all positions close to the given position.
|
||||
* @param pPosition The position to look for vertices.
|
||||
* @param pSG Only included vertices with at least one shared smooth group
|
||||
* @param pRadius Maximal distance from the position a vertex may have to be counted in.
|
||||
* @param poResults The container to store the indices of the found positions. Will be emptied
|
||||
* by the call so it may contain anything.
|
||||
* @param pRadius Maximal distance from the position a vertex may have
|
||||
* to be counted in.
|
||||
* @param poResults The container to store the indices of the found
|
||||
* positions. Will be emptied by the call so it may contain anything.
|
||||
* @param exactMatch Specifies whether smoothing groups are bit masks
|
||||
* (false) or integral values (true). In the latter case, a vertex
|
||||
* cannot belong to more than one smoothing group.
|
||||
* @return An iterator to iterate over all vertices in the given area.
|
||||
*/
|
||||
// -------------------------------------------------------------------
|
||||
void FindPositions( const aiVector3D& pPosition, uint32_t pSG,
|
||||
float pRadius, std::vector<unsigned int>& poResults) const;
|
||||
float pRadius, std::vector<unsigned int>& poResults,
|
||||
bool exactMatch = false) const;
|
||||
|
||||
protected:
|
||||
/** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */
|
||||
aiVector3D mPlaneNormal;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** An entry in a spatially sorted position array. Consists of a vertex index,
|
||||
* its position and its precalculated distance from the reference plane */
|
||||
/** An entry in a spatially sorted position array. Consists of a
|
||||
* vertex index, its position and its precalculated distance from
|
||||
* the reference plane */
|
||||
// -------------------------------------------------------------------
|
||||
struct Entry
|
||||
{
|
||||
unsigned int mIndex; ///< The vertex referred by this entry
|
||||
aiVector3D mPosition; ///< Position
|
||||
unsigned int mIndex; ///< The vertex referred by this entry
|
||||
aiVector3D mPosition; ///< Position
|
||||
uint32_t mSmoothGroups;
|
||||
float mDistance; ///< Distance of this vertex to the sorting plane
|
||||
float mDistance; ///< Distance of this vertex to the sorting plane
|
||||
|
||||
Entry() { /** intentionally not initialized.*/ }
|
||||
Entry( unsigned int pIndex, const aiVector3D& pPosition, float pDistance,uint32_t pSG)
|
||||
|
||||
@@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// note - flip the face ordering
|
||||
// note - flip the face order
|
||||
#define ADD_TRIANGLE(n0,n1,n2) \
|
||||
positions.push_back(n2); \
|
||||
positions.push_back(n1); \
|
||||
@@ -291,12 +291,13 @@ void StandardShapes::MakeCone(
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void StandardShapes::MakeCircle(
|
||||
aiVector3D& center,
|
||||
aiVector3D& normal,
|
||||
float radius,
|
||||
unsigned int tess,
|
||||
const aiVector3D& center,
|
||||
const aiVector3D& normal,
|
||||
float radius,
|
||||
unsigned int tess,
|
||||
std::vector<aiVector3D>& positions)
|
||||
{
|
||||
//aiVector3D current = aiVector3D ( normal.x,
|
||||
}
|
||||
|
||||
} // ! Assimp
|
||||
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
* @param tess Number of triangles
|
||||
* @param positions Receives output triangles.
|
||||
*/
|
||||
static void MakeCircle(aiVector3D& center, aiVector3D& normal,
|
||||
static void MakeCircle(const aiVector3D& center, const aiVector3D& normal,
|
||||
float radius, unsigned int tess,
|
||||
std::vector<aiVector3D>& positions);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user