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
pull/1/head
aramis_acg 2008-09-20 15:55:51 +00:00
parent 0d5bb1c427
commit 3e46a0860e
35 changed files with 2099 additions and 435 deletions

20
CREDITS
View File

@ -7,21 +7,29 @@ The following is the list of all constributors.
Thanks for your help! Thanks for your help!
- Alexander Gessler, - Alexander Gessler,
3DS-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL- and LWO-Loader, 3DS-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF- and LWO-Loader,
Configuration-Interface, AssImp-Viewer (Win32), Website (Admin and Design), admin. Configuration-Interface, AssImp-Viewer (Win32), Website (Admin and Design), admin.
-Thomas Schulze, -Thomas Schulze,
X-Loader, Preprocessing framework. X-Loader, Preprocessing framework. Data structure & Interface design, documentation.
-R.Schmidt, -R.Schmidt,
Linux build, eclipse support. Linux build, eclipse support.
- Kim Kulling: - Kim Kulling:
Obj-Loader, Logging, Scons-build enviroment. Obj-Loader, Logging, Scons-build environment.
- Matthias Gubisch, - Matthias Gubisch,
Assimp.net
Visual Studio 9 support, bugfixes. Visual Studio 9 support, bugfixes.
- Sebastian Hempel,
PyAssimp
Compile-Bugfixes for mingw, add enviroment for static library support in make.
- Jonathan Pokrass
supplied a bugfix concerning the scaling in the md3 loader.
- Andrew Galante, - Andrew Galante,
submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace. submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace.
@ -31,11 +39,5 @@ tested Assimp under Windows Vista 64 Bit.
- Marius Schröder - Marius Schröder
allowed us to use many of his models for screenshots and testing. allowed us to use many of his models for screenshots and testing.
- Sebastian Hempel,
Compile-Bugfixes for mingw, add enviroment for static library support in make.
- Jonathan Pokrass
supplied a bugfix concerning the scaling in the md3 loader.
- Christian Schubert - Christian Schubert
supplied various XFiles for testing purposes. supplied various XFiles for testing purposes.

View File

@ -63,6 +63,31 @@ using namespace Assimp;
#define AI_DXF_BINARY_IDENT_LEN (24) #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 // Constructor to be privately used by Importer
DXFImporter::DXFImporter() 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 // ENTITIES and BLOCKS sections - skip the whole rest, no need to waste our time with them
if (!::strcmp(cursor,"ENTITIES") || !::strcmp(cursor,"BLOCKS")) 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 // other sections - skip them to make sure there will be no name conflicts
else else
@ -200,6 +225,21 @@ void DXFImporter::InternReadFile( const std::string& pFile,
// generate the output mesh // generate the output mesh
aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh(); aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh();
const std::vector<aiVector3D>& vPositions = (*it).vPositions; 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->mNumFaces = (unsigned int)vPositions.size() / 4u;
pMesh->mFaces = new aiFace[pMesh->mNumFaces]; 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) for (unsigned int a = 0; a < face.mNumIndices;++a)
{ {
*vpOut++ = vp[a]; *vpOut++ = vp[a];
if (clr)*clrOut++ = clr[a];
face.mIndices[a] = pMesh->mNumVertices++; face.mIndices[a] = pMesh->mNumVertices++;
} }
vp += 4; vp += 4;
@ -333,6 +374,7 @@ bool DXFImporter::ParsePolyLine()
LayerInfo* out = NULL; LayerInfo* out = NULL;
std::vector<aiVector3D> positions; std::vector<aiVector3D> positions;
std::vector<aiColor4D> colors;
std::vector<unsigned int> indices; std::vector<unsigned int> indices;
unsigned int flags = 0; unsigned int flags = 0;
@ -344,10 +386,14 @@ bool DXFImporter::ParsePolyLine()
{ {
if (!::strcmp(cursor,"VERTEX")) if (!::strcmp(cursor,"VERTEX"))
{ {
aiVector3D v; aiVector3D v;aiColor4D clr(g_clrInvalid);
unsigned int idx[4] = {0xffffffff,0xffffffff,0xffffffff,0xffffffff}; unsigned int idx[4] = {0xffffffff,0xffffffff,0xffffffff,0xffffffff};
ParsePolyLineVertex(v, idx); ParsePolyLineVertex(v, clr, idx);
if (0xffffffff == idx[0])positions.push_back(v); if (0xffffffff == idx[0])
{
positions.push_back(v);
colors.push_back(clr);
}
else else
{ {
// check whether we have a fourth coordinate // check whether we have a fourth coordinate
@ -413,6 +459,10 @@ bool DXFImporter::ParsePolyLine()
// use a default layer if necessary // use a default layer if necessary
if (!out)SetDefaultLayer(out); if (!out)SetDefaultLayer(out);
flags = (unsigned int)(out->vPositions.size()+indices.size());
out->vPositions.reserve(flags);
out->vColors.reserve(flags);
// generate unique vertices // generate unique vertices
for (std::vector<unsigned int>::const_iterator it = indices.begin(), end = indices.end(); for (std::vector<unsigned int>::const_iterator it = indices.begin(), end = indices.end();
it != end; ++it) it != end; ++it)
@ -424,13 +474,14 @@ bool DXFImporter::ParsePolyLine()
idx = (unsigned int) positions.size(); idx = (unsigned int) positions.size();
} }
out->vPositions.push_back(positions[idx-1]); // indices are one-based. out->vPositions.push_back(positions[idx-1]); // indices are one-based.
out->vColors.push_back(colors[idx-1]); // indices are one-based.
} }
return ret; return ret;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx) bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned int* outIdx)
{ {
bool ret = false; bool ret = false;
while (GetNextToken()) while (GetNextToken())
@ -455,6 +506,9 @@ bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx)
case 72: outIdx[1] = strtol10(cursor);break; case 72: outIdx[1] = strtol10(cursor);break;
case 73: outIdx[2] = strtol10(cursor);break; case 73: outIdx[2] = strtol10(cursor);break;
case 74: outIdx[3] = 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; if (ret)break;
} }
@ -468,6 +522,7 @@ bool DXFImporter::Parse3DFace()
LayerInfo* out = NULL; LayerInfo* out = NULL;
aiVector3D vip[4]; // -- vectors are initialized to zero aiVector3D vip[4]; // -- vectors are initialized to zero
aiColor4D clr(g_clrInvalid);
while (GetNextToken()) while (GetNextToken())
{ {
switch (groupCode) switch (groupCode)
@ -516,6 +571,9 @@ bool DXFImporter::Parse3DFace()
// z position of the fourth corner // z position of the fourth corner
case 33: vip[3].z = fast_atof(cursor);break; 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; if (ret)break;
} }
@ -528,5 +586,8 @@ bool DXFImporter::Parse3DFace()
out->vPositions.push_back(vip[1]); out->vPositions.push_back(vip[1]);
out->vPositions.push_back(vip[2]); out->vPositions.push_back(vip[2]);
out->vPositions.push_back(vip[3]); // might be equal to the third 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; return ret;
} }

View File

@ -76,6 +76,7 @@ protected:
// face buffer - order is x,y,z,w v1,v2,v3 (w is equal to z if unused) // face buffer - order is x,y,z,w v1,v2,v3 (w is equal to z if unused)
std::vector<aiVector3D> vPositions; std::vector<aiVector3D> vPositions;
std::vector<aiColor4D> vColors;
}; };
@ -149,11 +150,13 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Parses a VERTEX element in a POLYLINE/POLYFACE /** Parses a VERTEX element in a POLYLINE/POLYFACE
* @param out Receives the output vertex. * @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. * @param outIdx Receives the output vertex indices, if present.
* Wont't be modified otherwise. Size must be at least 4. * Wont't be modified otherwise. Size must be at least 4.
* @return false if the end of the file was reached * @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: private:

View File

@ -106,20 +106,11 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[2]]; aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
aiVector3D vNor = (*pV2 - *pV1) ^ (*pV3 - *pV1).Normalize();
aiVector3D pDelta1 = *pV2 - *pV1;
aiVector3D pDelta2 = *pV3 - *pV1;
aiVector3D vNor = pDelta1 ^ pDelta2;
vNor.Normalize();
//if (face.mIndices[1] > face.mIndices[2])
// vNor *= -1.0f;
for (unsigned int i = 0;i < face.mNumIndices;++i) for (unsigned int i = 0;i < face.mNumIndices;++i)
{
pMesh->mNormals[face.mIndices[i]] = vNor; pMesh->mNormals[face.mIndices[i]] = vNor;
}
} }
return true; return true;
} }

View File

@ -116,12 +116,8 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[2]]; aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
aiVector3D vNor = (*pV2 - *pV1) ^ (*pV3 - *pV1).Normalize();
aiVector3D pDelta1 = *pV2 - *pV1;
aiVector3D pDelta2 = *pV3 - *pV1;
aiVector3D vNor = pDelta1 ^ pDelta2;
vNor.Normalize();
for (unsigned int i = 0;i < face.mNumIndices;++i) for (unsigned int i = 0;i < face.mNumIndices;++i)
pMesh->mNormals[face.mIndices[i]] = vNor; pMesh->mNormals[face.mIndices[i]] = vNor;
@ -146,7 +142,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); SpatialSort vertexFinder( pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
std::vector<unsigned int> verticesFound; std::vector<unsigned int> verticesFound;
const float fLimit = cosf(this->configMaxAngle); const float fLimit = cos(this->configMaxAngle);
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices]; aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
for (unsigned int i = 0; i < pMesh->mNumVertices;++i) for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
@ -157,7 +153,6 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
vertexFinder.FindPositions( posThis, posEpsilon, verticesFound); vertexFinder.FindPositions( posThis, posEpsilon, verticesFound);
aiVector3D pcNor; aiVector3D pcNor;
//unsigned int div = 0;
for (unsigned int a = 0; a < verticesFound.size(); ++a) for (unsigned int a = 0; a < verticesFound.size(); ++a)
{ {
unsigned int vidx = verticesFound[a]; unsigned int vidx = verticesFound[a];
@ -167,7 +162,6 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh)
continue; continue;
pcNor += pMesh->mNormals[vidx]; pcNor += pMesh->mNormals[vidx];
//++div;
} }
pcNor.Normalize(); pcNor.Normalize();
pcNew[i] = pcNor; pcNew[i] = pcNor;

View File

@ -2,17 +2,21 @@
// Definitions for the Interchange File Format (IFF) // Definitions for the Interchange File Format (IFF)
// Alexander Gessler, 2006 // Alexander Gessler, 2006
// Adapted for Assimp August 2008 // Adapted to Assimp August 2008
#ifndef AI_IFF_H_INCLUDED #ifndef AI_IFF_H_INCLUDED
#define AI_IFF_H_INCLUDED #define AI_IFF_H_INCLUDED
#include "ByteSwap.h" #include "ByteSwap.h"
namespace Assimp { namespace Assimp {
namespace IFF { namespace IFF {
#include "./../include/Compiler/pushpack1.h"
/////////////////////////////////////////////////////////////////////////////////
//! Describes an IFF chunk header //! Describes an IFF chunk header
/////////////////////////////////////////////////////////////////////////////////
struct ChunkHeader struct ChunkHeader
{ {
//! Type of the chunk header - FourCC //! Type of the chunk header - FourCC
@ -20,7 +24,22 @@ struct ChunkHeader
//! Length of the chunk data, in bytes //! Length of the chunk data, in bytes
uint32_t length; 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) | \ #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') #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 //! 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 //! @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 //! @param fileType Receives the type of the file
//! @return 0 if everything was OK, otherwise an error message //! @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; LE_NCONST ChunkHeader* head = LoadChunk(outFile);
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
if(AI_IFF_FOURCC_FORM != head->type) if(AI_IFF_FOURCC_FORM != head->type)
{ {
return "The file is not an IFF file: FORM chunk is missing"; return "The file is not an IFF file: FORM chunk is missing";

View File

@ -63,14 +63,11 @@ void LWOImporter::LoadLWOBFile()
while (true) while (true)
{ {
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
LE_NCONST IFF::ChunkHeader* const head = (LE_NCONST IFF::ChunkHeader*)mFileBuffer; LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
mFileBuffer += sizeof(IFF::ChunkHeader);
if (mFileBuffer + head->length > end) if (mFileBuffer + head->length > end)
{ {
throw new ImportErrorException("LWOB: Invalid file, the size attribute of " throw new ImportErrorException("LWOB: Invalid chunk length");
"a chunk points behind the end of the file");
break; break;
} }
LE_NCONST uint8_t* const next = mFileBuffer+head->length; 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::Surface& surf = mSurfaces->back();
LWO::Texture* pTex = NULL; LWO::Texture* pTex = NULL;
ParseString(surf.mName,size); GetS0(surf.mName,size);
mFileBuffer+=surf.mName.length()+1;
// skip one byte if the length of the surface name is odd
if (!(surf.mName.length() & 1))++mFileBuffer;
while (true) while (true)
{ {
if (mFileBuffer + 6 > end)break; if (mFileBuffer + 6 > end)break;
// no proper IFF header here - the chunk length is specified as int16 LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
uint32_t head_type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
uint16_t head_length = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2; if (mFileBuffer + head->length > end)
AI_LSWAP4(head_type); throw new ImportErrorException("LWOB: Invalid surface chunk length");
AI_LSWAP2(head_length);
if (mFileBuffer + head_length > end) LE_NCONST uint8_t* const next = mFileBuffer+head->length;
{ switch (head->type)
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
"a surface sub chunk points behind the end of the file");
}
LE_NCONST uint8_t* const next = mFileBuffer+head_length;
switch (head_type)
{ {
// diffuse color // diffuse color
case AI_LWO_COLR: case AI_LWO_COLR:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,COLR,3); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,3);
surf.mColor.r = *mFileBuffer++ / 255.0f; surf.mColor.r = GetU1() / 255.0f;
surf.mColor.g = *mFileBuffer++ / 255.0f; surf.mColor.g = GetU1() / 255.0f;
surf.mColor.b = *mFileBuffer / 255.0f; surf.mColor.b = GetU1() / 255.0f;
break; break;
} }
// diffuse strength ... // diffuse strength ...
case AI_LWO_DIFF: case AI_LWO_DIFF:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,DIFF,2); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,2);
AI_LSWAP2P(mFileBuffer); surf.mDiffuseValue = GetU2() / 255.0f;
surf.mDiffuseValue = *((int16_t*)mFileBuffer) / 255.0f;
break; break;
} }
// specular strength ... // specular strength ...
case AI_LWO_SPEC: case AI_LWO_SPEC:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,SPEC,2); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,2);
AI_LSWAP2P(mFileBuffer); surf.mSpecularValue = GetU2() / 255.0f;
surf.mSpecularValue = *((int16_t*)mFileBuffer) / 255.0f;
break; break;
} }
// luminosity ... // luminosity ...
case AI_LWO_LUMI: case AI_LWO_LUMI:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,LUMI,2); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LUMI,2);
AI_LSWAP2P(mFileBuffer); surf.mLuminosity = GetU2() / 255.0f;
surf.mLuminosity = *((int16_t*)mFileBuffer) / 255.0f;
break; break;
} }
// transparency // transparency
case AI_LWO_TRAN: case AI_LWO_TRAN:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TRAN,2); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,2);
AI_LSWAP2P(mFileBuffer); surf.mTransparency = GetU2() / 255.0f;
surf.mTransparency = *((int16_t*)mFileBuffer) / 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; break;
} }
// glossiness // glossiness
case AI_LWO_GLOS: case AI_LWO_GLOS:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,GLOS,2); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,2);
AI_LSWAP2P(mFileBuffer); surf.mGlossiness = (float)GetU2();
surf.mGlossiness = float(*((int16_t*)mFileBuffer));
break; break;
} }
// color texture // color texture
case AI_LWO_CTEX: case AI_LWO_CTEX:
{ {
pTex = &surf.mColorTexture; surf.mColorTextures.push_back(Texture());
pTex = &surf.mColorTextures.back();
break; break;
} }
// diffuse texture // diffuse texture
case AI_LWO_DTEX: case AI_LWO_DTEX:
{ {
pTex = &surf.mDiffuseTexture; surf.mDiffuseTextures.push_back(Texture());
pTex = &surf.mDiffuseTextures.back();
break; break;
} }
// specular texture // specular texture
case AI_LWO_STEX: case AI_LWO_STEX:
{ {
pTex = &surf.mSpecularTexture; surf.mSpecularTextures.push_back(Texture());
pTex = &surf.mSpecularTextures.back();
break; break;
} }
// bump texture // bump texture
case AI_LWO_BTEX: case AI_LWO_BTEX:
{ {
pTex = &surf.mBumpTexture; surf.mBumpTextures.push_back(Texture());
pTex = &surf.mBumpTextures.back();
break; break;
} }
// transparency texture // transparency texture
case AI_LWO_TTEX: case AI_LWO_TTEX:
{ {
pTex = &surf.mTransparencyTexture; surf.mOpacityTextures.push_back(Texture());
pTex = &surf.mOpacityTextures.back();
break; break;
} }
// texture path // texture path
@ -309,9 +315,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
{ {
if (pTex) if (pTex)
{ {
ParseString(pTex->mFileName,head_length); GetS0(pTex->mFileName,head->length);
AdjustTexturePath(pTex->mFileName);
mFileBuffer += pTex->mFileName.length();
} }
else DefaultLogger::get()->warn("LWOB: TIMG tag was encuntered although " else DefaultLogger::get()->warn("LWOB: TIMG tag was encuntered although "
"there was no xTEX tag before"); "there was no xTEX tag before");
@ -320,8 +324,8 @@ void LWOImporter::LoadLWOBSurface(unsigned int size)
// texture strength // texture strength
case AI_LWO_TVAL: case AI_LWO_TVAL:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TVAL,1); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TVAL,1);
if (pTex)pTex->mStrength = *mFileBuffer / 255.0f; if (pTex)pTex->mStrength = (float)GetU1()/ 255.f;
else DefaultLogger::get()->warn("LWOB: TVAL tag was encuntered " else DefaultLogger::get()->warn("LWOB: TVAL tag was encuntered "
"although there was no xTEX tag before"); "although there was no xTEX tag before");
break; break;

View File

@ -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 /** @file Defines chunk constants used by the LWO file format
The chunks are taken from LWO2.h, found in the sourcecode of The chunks are taken from the official LightWave SDK headers.
a project called Nxabega (http://www.sourceforge.net/projects/nxabega).
I assume they are from the official LightWave SDK headers.
Original copyright notice: "Ernie Wright 17 Sep 00" Original copyright notice: "Ernie Wright 17 Sep 00"
*/ */
@ -253,12 +251,25 @@ namespace LWO {
struct Face : public aiFace struct Face : public aiFace
{ {
Face() Face()
: surfaceIndex(0) : surfaceIndex (0)
, smoothGroup(0) , smoothGroup (0)
{} {}
Face(const Face& f)
{
*this = f;
}
unsigned int surfaceIndex; unsigned int surfaceIndex;
unsigned int smoothGroup; 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) : 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; std::string name;
float* rawData;
unsigned int dims; unsigned int dims;
std::vector<float> rawData;
std::vector<bool> abAssigned;
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -283,16 +307,29 @@ struct VMapEntry
*/ */
struct VColorChannel : public VMapEntry struct VColorChannel : public VMapEntry
{ {
VColorChannel(unsigned int num) VColorChannel()
: VMapEntry(4) : 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 struct UVChannel : public VMapEntry
{ {
UVChannel(unsigned int num) UVChannel()
: VMapEntry(3) : VMapEntry(2)
{ {}
data = new aiVector3D[num]; // to make the final copying easier
rawData = (float*)data;
}
aiVector3D* data;
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -315,13 +347,9 @@ struct UVChannel : public VMapEntry
*/ */
struct WeightChannel : public VMapEntry struct WeightChannel : public VMapEntry
{ {
WeightChannel(unsigned int num) WeightChannel()
: VMapEntry(1) : 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 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() Texture()
: mClipIdx(0xffffffff) : mClipIdx(0xffffffff)
, mStrength (1.0f) , mStrength (1.0f)
, mUVChannelIndex ("unknown") , 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 //! File name of the texture
@ -342,15 +419,38 @@ struct Texture
//! Clip index //! Clip index
unsigned int mClipIdx; unsigned int mClipIdx;
//! Strength of the texture //! Strength of the texture - blend factor
float mStrength; float mStrength;
/*************** SPECIFIC TO LWO2 *********************/
uint32_t type; // type of the texture uint32_t type; // type of the texture
//! Name of the corresponding UV channel //! Name of the corresponding UV channel
std::string mUVChannelIndex; 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 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; 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) /** \brief Data structure for a LWO file surface (= material)
*/ */
struct Surface struct Surface
{ {
Surface() Surface()
: bDoubleSided (false) : mColor (0.78431f,0.78431f,0.78431f)
, mDiffuseValue (1.0f) , bDoubleSided (false)
, mSpecularValue (1.0f) , mDiffuseValue (1.f)
, mTransparency (0.0f) , mSpecularValue (0.f)
, mGlossiness (0.0f) , mTransparency (0.f)
, mLuminosity (0.0f) , mGlossiness (0.4f)
, mMaximumSmoothAngle (0.0f) // 0 == not specified , 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 //! Name of the surface
@ -387,23 +530,38 @@ struct Surface
bool bDoubleSided; bool bDoubleSided;
//! Various material parameters //! Various material parameters
float mDiffuseValue,mSpecularValue,mTransparency,mGlossiness,mLuminosity; float mDiffuseValue,mSpecularValue,mTransparency,mGlossiness,mLuminosity,mColorHighlights;
//! Maximum angle between two adjacent triangles //! Maximum angle between two adjacent triangles
//! that they can be smoothed - in degrees //! that they can be smoothed - in degrees
float mMaximumSmoothAngle; float mMaximumSmoothAngle;
//! Textures //! Vertex color map to be used to color the surface
Texture mColorTexture,mDiffuseTexture,mSpecularTexture, std::string mVCMap;
mBumpTexture,mTransparencyTexture;
//! 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) \ #define AI_LWO_VALIDATE_CHUNK_LENGTH(length,name,size) \
if (length < size) \ if (length < size) \
{ \ { \
DefaultLogger::get()->warn("LWO: "#name" chunk is too small"); \ throw new ImportErrorException("LWO: "#name" chunk is too small"); \
break; \
} \ } \
@ -413,6 +571,7 @@ typedef std::vector < LWO::Face > FaceList;
typedef std::vector < LWO::Surface > SurfaceList; typedef std::vector < LWO::Surface > SurfaceList;
typedef std::vector < std::string > TagList; typedef std::vector < std::string > TagList;
typedef std::vector < unsigned int > TagMappingTable; typedef std::vector < unsigned int > TagMappingTable;
typedef std::vector < unsigned int > ReferrerList;
typedef std::vector < WeightChannel > WeightChannelList; typedef std::vector < WeightChannel > WeightChannelList;
typedef std::vector < VColorChannel > VColorChannelList; typedef std::vector < VColorChannel > VColorChannelList;
typedef std::vector < UVChannel > UVChannelList; typedef std::vector < UVChannel > UVChannelList;
@ -433,6 +592,11 @@ struct Layer
/** Temporary point list from the file */ /** Temporary point list from the file */
PointList mTempPoints; 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 */ /** Weight channel list from the file */
WeightChannelList mWeightChannels; WeightChannelList mWeightChannels;
@ -456,6 +620,9 @@ struct Layer
/** Name of the layer */ /** Name of the layer */
std::string mName; std::string mName;
/** Pivot point of the layer */
aiVector3D mPivot;
}; };
typedef std::list<LWO::Layer> LayerList; typedef std::list<LWO::Layer> LayerList;

View File

@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "LWOLoader.h" #include "LWOLoader.h"
#include "MaterialSystem.h" #include "MaterialSystem.h"
#include "StringComparison.h" #include "StringComparison.h"
#include "SGSpatialSort.h"
#include "ByteSwap.h" #include "ByteSwap.h"
// public assimp headers // 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/IOSystem.h"
#include "../include/aiScene.h" #include "../include/aiScene.h"
#include "../include/aiAssert.h" #include "../include/aiAssert.h"
#include "../include/DefaultLogger.h"
#include "../include/assimp.hpp" #include "../include/assimp.hpp"
// boost headers // boost headers
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <sstream>
#include <iomanip>
using namespace Assimp; using namespace Assimp;
@ -91,12 +93,14 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
return true; return true;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup configuration properties // Setup configuration properties
void LWOImporter::SetupProperties(const Importer* pImp) void LWOImporter::SetupProperties(const Importer* pImp)
{ {
// -- no configuration options at the moment // -- no configuration options at the moment
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void LWOImporter::InternReadFile( const std::string& pFile, void LWOImporter::InternReadFile( const std::string& pFile,
@ -166,7 +170,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
szBuff[3] = (char)(fileType); szBuff[3] = (char)(fileType);
throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff); 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(); ResolveTags();
ResolveClips();
// now process all layers and build meshes and nodes // now process all layers and build meshes and nodes
std::vector<aiMesh*> apcMeshes; std::vector<aiMesh*> apcMeshes;
@ -176,10 +183,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
unsigned int iDefaultSurface = 0xffffffff; // index of the default surface 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) 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 // I don't know whether there could be dummy layers, but it would be possible
const unsigned int meshStart = (unsigned int)apcMeshes.size(); 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); std::vector<SortedRep> pSorted(mSurfaces->size()+1);
unsigned int i = 0; 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) it != end;++it,++i)
{ {
unsigned int idx = (*it).surfaceIndex; unsigned int idx = (*it).surfaceIndex;
@ -232,8 +239,9 @@ void LWOImporter::InternReadFile( const std::string& pFile,
apcMeshes.push_back(mesh); apcMeshes.push_back(mesh);
mesh->mNumFaces = (unsigned int)sorted.size(); mesh->mNumFaces = (unsigned int)sorted.size();
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end(); // count the number of vertices
it != end;++it) SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
for (;it != end;++it)
{ {
mesh->mNumVertices += layer.mFaces[*it].mNumIndices; 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]; 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 // now convert all faces
unsigned int vert = 0; unsigned int vert = 0;
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end(); std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
it != end;++it) for (it = sorted.begin(); it != end;++it,++outIt)
{ {
const LWO::Face& face = layer.mFaces[*it]; const LWO::Face& face = layer.mFaces[*it];
*outIt = face.smoothGroup;
// copy all vertices // copy all vertices
for (unsigned int q = 0; q < face.mNumIndices;++q) for (unsigned int q = 0; q < face.mNumIndices;++q)
{ {
register unsigned int idx = face.mIndices[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 // process UV coordinates
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w)
{ {
if (0xffffffff == vUVChannelIndices[w])break; 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 // process vertex colors
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w)
{ {
if (0xffffffff == vVColorIndices[w])break; 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 #if 0
@ -308,14 +330,20 @@ void LWOImporter::InternReadFile( const std::string& pFile,
{ {
} }
#endif #endif
face.mIndices[q] = vert++; face.mIndices[q] = vert + (face.mNumIndices-q-1);
} }
vert += face.mNumIndices;
pf->mIndices = face.mIndices; pf->mIndices = face.mIndices;
pf->mNumIndices = face.mNumIndices; pf->mNumIndices = face.mNumIndices;
unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // make sure it won't be deleted unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // make sure it won't be deleted
pf++; 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; ++p;
} }
} }
@ -352,11 +380,103 @@ void LWOImporter::InternReadFile( const std::string& pFile,
GenerateNodeGraph(apcNodes); 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) 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) for (uintptr_t i = 0; i < (uintptr_t)apcNodes.size();++i)
{ {
if (i == parent)continue; 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 for( unsigned int i = 0; i < mClips.size();++i)
unsigned int iCursor = 0;
const char* in = (const char*)mFileBuffer,*sz = in;
while (*in)
{ {
if (++iCursor > max) Clip& clip = mClips[i];
if (Clip::REF == clip.type)
{ {
DefaultLogger::get()->warn("LWOB: Invalid file, string is is too long"); if (clip.clipRef >= mClips.size())
break; {
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) void LWOImporter::AdjustTexturePath(std::string& out)
{ {
// --- this function is used for both LWO2 and LWOB // --- 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 // 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"; out = out.substr(0,out.length()-10) + "000";
} }
}
// ------------------------------------------------------------------------------------------------ // format: drive:path/file - we need to insert a slash after the drive
int LWOImporter::ReadVSizedIntLWO2(uint8_t*& inout) std::string::size_type n = out.find_first_of(':');
{ if (std::string::npos != n)
int i;
int c = *inout;inout++;
if(c != 0xFF)
{ {
i = c << 8; out.insert(n+1,"/");
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;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -530,8 +643,20 @@ void LWOImporter::LoadLWOTags(unsigned int size)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOPoints(unsigned int length) void LWOImporter::LoadLWOPoints(unsigned int length)
{ {
// --- this function is used for both LWO2 and LWOB // --- this function is used for both LWO2 and LWOB but for
mCurLayer->mTempPoints.resize( length / 12 ); // 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 // perform endianess conversions
#ifndef AI_BUILD_BIG_ENDIAN #ifndef AI_BUILD_BIG_ENDIAN
@ -544,17 +669,16 @@ void LWOImporter::LoadLWOPoints(unsigned int length)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2Polygons(unsigned int length) void LWOImporter::LoadLWO2Polygons(unsigned int length)
{ {
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer += 4;length-=4; LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
AI_LSWAP4(type); uint32_t type = GetU4();
if (type != AI_LWO_FACE) 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; return;
} }
// first find out how many faces and vertices we'll finally need // 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; LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer;
unsigned int iNumFaces = 0,iNumVertices = 0; unsigned int iNumFaces = 0,iNumVertices = 0;
@ -616,21 +740,22 @@ void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2PolygonTags(unsigned int length) void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
{ {
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4; LE_NCONST uint8_t* const end = mFileBuffer+length;
AI_LSWAP4(type);
AI_LWO_VALIDATE_CHUNK_LENGTH(length,PTAG,4);
uint32_t type = GetU4();
if (type != AI_LWO_SURF && type != AI_LWO_SMGP) if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
return; return;
LE_NCONST uint8_t* const end = mFileBuffer+length; while (mFileBuffer < end)
while (mFileBuffer <= end)
{ {
unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs; unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
unsigned int j = ReadVSizedIntLWO2(mFileBuffer); unsigned int j = GetU2();
if (i >= mCurLayer->mFaces.size()) 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; 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) void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
{ {
unsigned int type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4; LE_NCONST uint8_t* const end = mFileBuffer+length;
unsigned int dims = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2;
AI_LWO_VALIDATE_CHUNK_LENGTH(length,VMAP,6);
unsigned int type = GetU4();
unsigned int dims = GetU2();
VMapEntry* base; VMapEntry* base;
// read the name of the vertex map
std::string name;
GetS0(name,length);
switch (type) switch (type)
{ {
case AI_LWO_TXUV: 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"); DefaultLogger::get()->warn("LWO2: Found UV channel with != 2 components");
} }
mCurLayer->mUVChannels.push_back(UVChannel((unsigned int)mCurLayer->mTempPoints.size())); base = FindEntry(mCurLayer->mUVChannels,name,perPoly);
base = &mCurLayer->mUVChannels.back(); break;
case AI_LWO_WGHT: case AI_LWO_WGHT:
if (dims != 1) if (dims != 1)
{ {
DefaultLogger::get()->warn("LWO2: found vertex weight map with != 1 components"); DefaultLogger::get()->warn("LWO2: found vertex weight map with != 1 components");
} }
mCurLayer->mWeightChannels.push_back(WeightChannel((unsigned int)mCurLayer->mTempPoints.size())); base = FindEntry(mCurLayer->mWeightChannels,name,perPoly);
base = &mCurLayer->mWeightChannels.back(); break;
case AI_LWO_RGB: case AI_LWO_RGB:
case AI_LWO_RGBA: case AI_LWO_RGBA:
if (dims != 3 && dims != 4) if (dims != 3 && dims != 4)
{ {
DefaultLogger::get()->warn("LWO2: found vertex color map with != 3&4 components"); DefaultLogger::get()->warn("LWO2: found vertex color map with != 3&4 components");
} }
mCurLayer->mVColorChannels.push_back(VColorChannel((unsigned int)mCurLayer->mTempPoints.size())); base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
base = &mCurLayer->mVColorChannels.back(); break;
default: return; default: return;
}; };
base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
// read the name of the vertex map
ParseString(base->name,length);
// now read all entries in the map // now read all entries in the map
type = std::min(dims,base->dims); type = std::min(dims,base->dims);
const unsigned int diff = (dims - type)<<2; 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) while (mFileBuffer < end)
{ {
unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs; 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"); 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); unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
mFileBuffer += 4; 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; 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() void LWOImporter::LoadLWO2File()
@ -714,14 +1001,11 @@ void LWOImporter::LoadLWO2File()
while (true) while (true)
{ {
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
LE_NCONST IFF::ChunkHeader* const head = (LE_NCONST IFF::ChunkHeader*)mFileBuffer; LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
mFileBuffer += sizeof(IFF::ChunkHeader);
if (mFileBuffer + head->length > end) if (mFileBuffer + head->length > end)
{ {
throw new ImportErrorException("LWOB: Invalid file, the size attribute of " throw new ImportErrorException("LWO2: Chunk length points behind the file");
"a chunk points behind the end of the file");
break; break;
} }
LE_NCONST uint8_t* const next = mFileBuffer+head->length; 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); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
// and parse its properties // and parse its properties, e.g. the pivot point
mFileBuffer += 16; mFileBuffer += 2;
ParseString(layer.mName,head->length-16); 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 the name is empty, generate a default name
if (layer.mName.empty()) if (layer.mName.empty())
@ -751,7 +1039,7 @@ void LWOImporter::LoadLWO2File()
} }
if (mFileBuffer + 2 <= next) if (mFileBuffer + 2 <= next)
layer.mParent = *((uint16_t*)mFileBuffer); layer.mParent = GetU2();
break; break;
} }
@ -765,11 +1053,17 @@ void LWOImporter::LoadLWO2File()
break; break;
} }
// vertex tags // 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: case AI_LWO_VMAP:
{ {
if (mCurLayer->mTempPoints.empty()) 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); else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
break; break;
} }
@ -804,6 +1098,13 @@ void LWOImporter::LoadLWO2File()
LoadLWO2Surface(head->length); LoadLWO2Surface(head->length);
break; break;
} }
// clip chunk
case AI_LWO_CLIP:
{
LoadLWO2Clip(head->length);
break;
}
} }
mFileBuffer = next; mFileBuffer = next;
} }

View File

@ -43,9 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_LWOLOADER_H_INCLUDED #define AI_LWOLOADER_H_INCLUDED
#include "../include/aiTypes.h" #include "../include/aiTypes.h"
#include "../include/DefaultLogger.h"
#include "BaseImporter.h"
#include "LWOFileData.h" #include "LWOFileData.h"
#include "BaseImporter.h"
#include "MaterialSystem.h" #include "MaterialSystem.h"
struct aiTexture; struct aiTexture;
@ -63,6 +64,7 @@ using namespace LWO;
* Methods named "xxx" are used to preprocess the loaded data - * Methods named "xxx" are used to preprocess the loaded data -
* they aren't specific to one format version, either * they aren't specific to one format version, either
*/ */
// ---------------------------------------------------------------------------
class LWOImporter : public BaseImporter class LWOImporter : public BaseImporter
{ {
friend class Importer; friend class Importer;
@ -120,6 +122,17 @@ private:
*/ */
void LoadLWO2File(); 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 /** Loads a surface chunk from an LWOB file
* @param size Maximum size to be read, in bytes. * @param size Maximum size to be read, in bytes.
@ -135,9 +148,18 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Loads a texture block from a LWO2 file. /** Loads a texture block from a LWO2 file.
* @param size Maximum size to be read, in bytes. * @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 /** Loads an image map from a LWO2 file
@ -183,6 +205,12 @@ private:
*/ */
void LoadLWOPoints(unsigned int length); 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 /** Count vertices and faces in a LWOB/LWO2 file
@ -206,6 +234,7 @@ private:
LE_NCONST uint16_t*& cursor, LE_NCONST uint16_t*& cursor,
const uint16_t* const end); const uint16_t* const end);
// -------------------------------------------------------------------
void CopyFaceIndicesLWOB(LWO::FaceList::iterator& it, void CopyFaceIndicesLWOB(LWO::FaceList::iterator& it,
LE_NCONST uint16_t*& cursor, LE_NCONST uint16_t*& cursor,
const uint16_t* const end, const uint16_t* const end,
@ -213,14 +242,27 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Resolve the tag and surface lists that have been loaded. /** Resolve the tag and surface lists that have been loaded.
* Generates the mMapping table. * Generates the mMapping table.
*/ */
void ResolveTags(); 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 /** Adjust a texture path
@ -241,10 +283,15 @@ private:
* @param out Output list. The members are indices into the * @param out Output list. The members are indices into the
* UV/VC channel lists of the layer * UV/VC channel lists of the layer
*/ */
void FindUVChannels(const LWO::Surface& surf, void FindUVChannels(/*const*/ LWO::Surface& surf,
const LWO::Layer& layer, /*const*/ LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]); 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, void FindVCChannels(const LWO::Surface& surf,
const LWO::Layer& layer, const LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]); unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]);
@ -271,6 +318,27 @@ private:
*/ */
int ReadVSizedIntLWO2(uint8_t*& inout); 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: protected:
/** true if the file is a LWO2 file*/ /** true if the file is a LWO2 file*/
@ -305,6 +373,81 @@ protected:
aiScene* pScene; 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 } // end of namespace Assimp
#endif // AI_LWOIMPORTER_H_INCLUDED #endif // AI_LWOIMPORTER_H_INCLUDED

View File

@ -58,6 +58,142 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; 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) 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; int i = surf.bDoubleSided ? 1 : 0;
pcMat->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED); 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) 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; float fGloss;
if (mIsLWO2)fGloss = surf.mGlossiness * 50.0f; if (mIsLWO2)
{
fGloss = pow( surf.mGlossiness*10.0f+2.0f, 2.0f);
}
else else
{ {
if (16.0f >= surf.mGlossiness)fGloss = 6.0f; 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>(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
pcMat->AddProperty<float>(&fGloss,1,AI_MATKEY_SHININESS); pcMat->AddProperty<float>(&fGloss,1,AI_MATKEY_SHININESS);
m = aiShadingMode_Phong;
} }
else m = aiShadingMode_Gouraud;
// (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);
// specular color // 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<aiColor3D>(&clr,1,AI_MATKEY_COLOR_SPECULAR);
pcMat->AddProperty<float>(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
// emissive color // emissive color
// (luminosity is not really the same but it affects the surface in // (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; float f = 1.0f-surf.mTransparency;
pcMat->AddProperty<float>(&f,1,AI_MATKEY_OPACITY); pcMat->AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
// now handle all textures ... // ADD TEXTURES to the material
// TODO // 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]) unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS])
{ {
out[0] = 0xffffffff; 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]) unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS])
{ {
out[0] = 0xffffffff; 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 ) 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 ) void LWOImporter::LoadLWO2Procedural(unsigned int size, LWO::Texture& tex )
{ {
// --- not supported at the moment // --- 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 ) void LWOImporter::LoadLWO2Gradient(unsigned int size, LWO::Texture& tex )
{ {
// --- not supported at the moment // --- 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 ) 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(); // load the texture header
//LWO::Texture tex; LoadLWO2TextureHeader(head->length,tex);
size -= head->length + 6;
// now get the exact type of the texture // 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 () ); mSurfaces->push_back( LWO::Surface () );
LWO::Surface& surf = mSurfaces->back(); LWO::Surface& surf = mSurfaces->back();
ParseString(surf.mName,size); GetS0(surf.mName,size);
mFileBuffer+=surf.mName.length()+1;
// skip one byte if the length of the surface name is odd // check whether this surface was derived from any other surface
if (!(surf.mName.length() & 1))++mFileBuffer; std::string derived;
mFileBuffer += 2; 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) while (true)
{ {
if (mFileBuffer + 6 >= end)break; 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 if (mFileBuffer + head->length > end)
uint32_t head_type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4; throw new ImportErrorException("LWO2: Invalid surface chunk length");
uint16_t head_length = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2;
AI_LSWAP4(head_type); LE_NCONST uint8_t* const next = mFileBuffer+head->length;
AI_LSWAP2(head_length); switch (head->type)
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)
{ {
// diffuse color // diffuse color
case AI_LWO_COLR: case AI_LWO_COLR:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,COLR,12); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,12);
surf.mColor.r = ((float*)mFileBuffer)[0]; surf.mColor.r = GetF4();
surf.mColor.g = ((float*)mFileBuffer)[1]; surf.mColor.g = GetF4();
surf.mColor.b = ((float*)mFileBuffer)[2]; surf.mColor.b = GetF4();
AI_LSWAP4(surf.mColor.r);
AI_LSWAP4(surf.mColor.g);
AI_LSWAP4(surf.mColor.b);
break; break;
} }
// diffuse strength ... hopefully // diffuse strength ... hopefully
case AI_LWO_DIFF: case AI_LWO_DIFF:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,DIFF,4); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,4);
surf.mDiffuseValue = *((float*)mFileBuffer); surf.mDiffuseValue = GetF4();
AI_LSWAP4(surf.mDiffuseValue);
break; break;
} }
// specular strength ... hopefully // specular strength ... hopefully
case AI_LWO_SPEC: case AI_LWO_SPEC:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,SPEC,4); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,4);
surf.mSpecularValue = *((float*)mFileBuffer); surf.mSpecularValue = GetF4();
AI_LSWAP4(surf.mSpecularValue);
break; break;
} }
// transparency // transparency
case AI_LWO_TRAN: case AI_LWO_TRAN:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TRAN,4); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4);
surf.mTransparency = *((float*)mFileBuffer); surf.mTransparency = GetF4();
AI_LSWAP4(surf.mTransparency);
break; break;
} }
// glossiness // glossiness
case AI_LWO_GLOS: case AI_LWO_GLOS:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,GLOS,4); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,4);
surf.mGlossiness = *((float*)mFileBuffer); surf.mGlossiness = GetF4();
AI_LSWAP4(surf.mGlossiness); 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; break;
} }
// surface bock entry // surface bock entry
case AI_LWO_BLOK: case AI_LWO_BLOK:
{ {
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,BLOK,4); AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,BLOK,4);
uint32_t type = *((uint32_t*)mFileBuffer); LE_NCONST IFF::SubChunkHeader* head2 = IFF::LoadSubChunk(mFileBuffer);
AI_LSWAP4(type);
switch (type) switch (head2->type)
{ {
case AI_LWO_IMAP:
case AI_LWO_PROC: case AI_LWO_PROC:
break;
case AI_LWO_GRAD: case AI_LWO_GRAD:
mFileBuffer+=4; case AI_LWO_IMAP:
LoadLWO2TextureBlock(type,head_length-4); LoadLWO2TextureBlock(head2, head->length);
break; break;
case AI_LWO_SHDR:
LoadLWO2ShaderBlock(head2, head->length);
break;
default:
DefaultLogger::get()->warn("LWO2: Found an unsupported surface BLOK");
}; };
break; break;

View File

@ -226,7 +226,7 @@ void MDRImporter::InternReadFile(
file->Read( &mBuffer2[0], 1, fileSize); file->Read( &mBuffer2[0], 1, fileSize);
mBuffer = &mBuffer2[0]; 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->pcHeader = (BE_NCONST MDR::Header*)this->mBuffer;
this->ValidateHeader(); this->ValidateHeader();
} }

View File

@ -83,9 +83,10 @@ void SGSpatialSort::Prepare()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns an iterator for all positions close to the given position. // Returns an iterator for all positions close to the given position.
void SGSpatialSort::FindPositions( const aiVector3D& pPosition, void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
uint32_t pSG, uint32_t pSG,
float pRadius, float pRadius,
std::vector<unsigned int>& poResults) const std::vector<unsigned int>& poResults,
bool exactMatch /*= false*/) const
{ {
float dist = pPosition * mPlaneNormal; float dist = pPosition * mPlaneNormal;
float minDist = dist - pRadius, maxDist = dist + pRadius; 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 // Add all positions inside the distance range within the given radius to the result aray
float squareEpsilon = pRadius * pRadius; float squareEpsilon = pRadius * pRadius;
std::vector<Entry>::const_iterator it = mPositions.begin() + index; std::vector<Entry>::const_iterator it = mPositions.begin() + index;
while( it->mDistance < maxDist) std::vector<Entry>::const_iterator end = mPositions.end();
if (exactMatch)
{ {
if((it->mPosition - pPosition).SquareLength() < squareEpsilon && while( it->mDistance < maxDist)
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups || 0 == pSG))
{ {
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;
} }
} }

View File

@ -46,13 +46,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector> #include <vector>
#include "../include/aiTypes.h" #include "../include/aiTypes.h"
namespace Assimp namespace Assimp {
{
// ------------------------------------------------------------------------------------------------ // ----------------------------------------------------------------------------------
/** Specialized version of SpatialSort to support smoothing groups /** 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 class SGSpatialSort
{ {
public: public:
@ -60,7 +62,8 @@ public:
SGSpatialSort(); 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); SGSpatialSort(const std::vector<aiVector3D>& vPositions);
@ -74,7 +77,7 @@ public:
unsigned int smoothingGroup); unsigned int smoothingGroup);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Prepare the spatial sorter for use /** Prepare the spatial sorter for use. This step runs in O(logn)
*/ */
void Prepare(); void Prepare();
@ -85,27 +88,35 @@ public:
/** Returns an iterator for all positions close to the given position. /** Returns an iterator for all positions close to the given position.
* @param pPosition The position to look for vertices. * @param pPosition The position to look for vertices.
* @param pSG Only included vertices with at least one shared smooth group * @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 pRadius Maximal distance from the position a vertex may have
* @param poResults The container to store the indices of the found positions. Will be emptied * to be counted in.
* by the call so it may contain anything. * @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. * @return An iterator to iterate over all vertices in the given area.
*/ */
// -------------------------------------------------------------------
void FindPositions( const aiVector3D& pPosition, uint32_t pSG, 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: protected:
/** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */ /** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */
aiVector3D mPlaneNormal; aiVector3D mPlaneNormal;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** An entry in a spatially sorted position array. Consists of a vertex index, /** An entry in a spatially sorted position array. Consists of a
* its position and its precalculated distance from the reference plane */ * vertex index, its position and its precalculated distance from
* the reference plane */
// -------------------------------------------------------------------
struct Entry struct Entry
{ {
unsigned int mIndex; ///< The vertex referred by this entry unsigned int mIndex; ///< The vertex referred by this entry
aiVector3D mPosition; ///< Position aiVector3D mPosition; ///< Position
uint32_t mSmoothGroups; 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() { /** intentionally not initialized.*/ }
Entry( unsigned int pIndex, const aiVector3D& pPosition, float pDistance,uint32_t pSG) Entry( unsigned int pIndex, const aiVector3D& pPosition, float pDistance,uint32_t pSG)

View File

@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
// note - flip the face ordering // note - flip the face order
#define ADD_TRIANGLE(n0,n1,n2) \ #define ADD_TRIANGLE(n0,n1,n2) \
positions.push_back(n2); \ positions.push_back(n2); \
positions.push_back(n1); \ positions.push_back(n1); \
@ -291,12 +291,13 @@ void StandardShapes::MakeCone(
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void StandardShapes::MakeCircle( void StandardShapes::MakeCircle(
aiVector3D& center, const aiVector3D& center,
aiVector3D& normal, const aiVector3D& normal,
float radius, float radius,
unsigned int tess, unsigned int tess,
std::vector<aiVector3D>& positions) std::vector<aiVector3D>& positions)
{ {
//aiVector3D current = aiVector3D ( normal.x,
} }
} // ! Assimp } // ! Assimp

View File

@ -146,7 +146,7 @@ public:
* @param tess Number of triangles * @param tess Number of triangles
* @param positions Receives output 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, float radius, unsigned int tess,
std::vector<aiVector3D>& positions); std::vector<aiVector3D>& positions);

View File

@ -197,7 +197,11 @@ enum aiShadingMode
/** No shading at all /** No shading at all
*/ */
aiShadingMode_NoShading = 0x8 aiShadingMode_NoShading = 0x9,
/** Fresnel shading
*/
aiShadingMode_Fresnel = 0xa
}; };
@ -242,6 +246,7 @@ struct aiMaterialProperty
} // need to end extern C block to allow template member functions } // need to end extern C block to allow template member functions
#endif #endif
// supported texture types
#define AI_TEXTYPE_OPACITY 0x0 #define AI_TEXTYPE_OPACITY 0x0
#define AI_TEXTYPE_SPECULAR 0x1 #define AI_TEXTYPE_SPECULAR 0x1
#define AI_TEXTYPE_AMBIENT 0x2 #define AI_TEXTYPE_AMBIENT 0x2
@ -250,6 +255,7 @@ struct aiMaterialProperty
#define AI_TEXTYPE_NORMALS 0x5 #define AI_TEXTYPE_NORMALS 0x5
#define AI_TEXTYPE_SHININESS 0x6 #define AI_TEXTYPE_SHININESS 0x6
#define AI_TEXTYPE_DIFFUSE 0x7 #define AI_TEXTYPE_DIFFUSE 0x7
#define AI_TEXTYPE_GLOSSINESS 0x8
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** Data structure for a material /** Data structure for a material
@ -339,7 +345,7 @@ extern "C" {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @def AI_BUILD_KEY /** @def AI_BUILD_KEY
* Builds a material texture key with a dynamic index. * Build a material texture key from an index that is not a compile-time constant.
* Applications <b>could</b> do this (C-example): * Applications <b>could</b> do this (C-example):
* @code * @code
* int i; * int i;
@ -352,10 +358,10 @@ extern "C" {
* @endcode * @endcode
* However, this is wrong because AI_MATKEY_TEXTURE_DIFFUSE() builds the key * However, this is wrong because AI_MATKEY_TEXTURE_DIFFUSE() builds the key
* string at <b>compile time</b>. <br> * string at <b>compile time</b>. <br>
* Therefore, the dynamic indexing results in a * Therefore, the indexing results in a
* material key like this : "$tex.file.diffuse[i]" - and it is not very * material key like this : "$tex.file.diffuse[i]" - and it is not very
* propable that there is a key with this name ... (except the programmer * propable that there is a key with this name ... (except the programmer
* of an ASSIMP loader has made the same mistake :-) ).<br> * of an ASSIMP loader has made the same fault :-) ).<br>
* This is the right way: * This is the right way:
* @code * @code
* int i; * int i;
@ -369,8 +375,8 @@ extern "C" {
* } * }
* @endcode * @endcode
* @param base Base material key. This is the same key you'd have used * @param base Base material key. This is the same key you'd have used
* normally with an underscore as suffix (e.g. AI_MATKEY_TEXTURE_DIFFUSE_) * normally with an extra underscore as suffix (e.g. AI_MATKEY_TEXTURE_DIFFUSE_)
* @param index Index to be used. Here you may pass a variable! * @param index Index to be used.
* @param out Array of chars to receive the output value. It must be * @param out Array of chars to receive the output value. It must be
* sufficiently large. This will be checked via a static assertion for * sufficiently large. This will be checked via a static assertion for
* C++0x. For MSVC8 and later versions the security enhanced version of * C++0x. For MSVC8 and later versions the security enhanced version of
@ -469,6 +475,16 @@ extern "C" {
*/ */
#define AI_MATKEY_SHININESS_STRENGTH "$mat.shinpercent" #define AI_MATKEY_SHININESS_STRENGTH "$mat.shinpercent"
/** @def AI_MATKEY_REFRACTI
* Index of refraction of the material. This is used by some shading models,
* e.g. Cook-Torrance. The value is the ratio of the speed of light in a
* vacuum to the speed of light in the material (always >= 1.0 in the real world).
* <br>
* <b>Type:</b> float<br>
* <b>Default value:</b> 1.0f <br>
*/
#define AI_MATKEY_REFRACTI "$mat.refracti"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @def AI_MATKEY_COLOR_DIFFUSE /** @def AI_MATKEY_COLOR_DIFFUSE
* Defines the diffuse base color of the material * Defines the diffuse base color of the material
@ -586,8 +602,12 @@ extern "C" {
#define AI_MATKEY_TEXTURE_HEIGHT_ "$tex.file.height" #define AI_MATKEY_TEXTURE_HEIGHT_ "$tex.file.height"
/** @def AI_MATKEY_TEXTURE_SHININESS /** @def AI_MATKEY_TEXTURE_SHININESS
* Defines a specific shininess texture channel of the material * Defines a specific shininess texture channel of the material.
* <br> * The shininess corresponds to the specular exponent used in the
* phong lighting equation. However, it is undefined how the exponent
* is encoded in the texture. A possible way would be the following:
* pixel value c (0,1), n = 2^(10c+2).
* <br>
* <b>Type:</b> string (aiString)<br> * <b>Type:</b> string (aiString)<br>
* <b>Default value:</b> none <br> * <b>Default value:</b> none <br>
* @note The key string is built at compile time, therefore it is not * @note The key string is built at compile time, therefore it is not
@ -598,6 +618,7 @@ extern "C" {
#define AI_MATKEY_TEXTURE_SHININESS(N) "$tex.file.shininess["#N"]" #define AI_MATKEY_TEXTURE_SHININESS(N) "$tex.file.shininess["#N"]"
#define AI_MATKEY_TEXTURE_SHININESS_ "$tex.file.shininess" #define AI_MATKEY_TEXTURE_SHININESS_ "$tex.file.shininess"
/** @def AI_MATKEY_TEXTURE_OPACITY /** @def AI_MATKEY_TEXTURE_OPACITY
* Defines a specific opacity texture channel of the material * Defines a specific opacity texture channel of the material
* <br> * <br>
@ -626,6 +647,7 @@ extern "C" {
* use the macro suffixed with '_' to build the key dynamically. The * use the macro suffixed with '_' to build the key dynamically. The
* AI_BUILD_KEY()-macro can be used to do this. * AI_BUILD_KEY()-macro can be used to do this.
*/ */
// ---------------------------------------------------------------------------
#define AI_MATKEY_TEXOP_DIFFUSE(N) "$tex.op.diffuse["#N"]" #define AI_MATKEY_TEXOP_DIFFUSE(N) "$tex.op.diffuse["#N"]"
/** @see AI_MATKEY_TEXOP_DIFFUSE */ /** @see AI_MATKEY_TEXOP_DIFFUSE */
#define AI_MATKEY_TEXOP_AMBIENT(N) "$tex.op.ambient["#N"]" #define AI_MATKEY_TEXOP_AMBIENT(N) "$tex.op.ambient["#N"]"
@ -663,6 +685,7 @@ extern "C" {
* use the macro suffixed with '_' to build the key dynamically. The * use the macro suffixed with '_' to build the key dynamically. The
* AI_BUILD_KEY()-macro can be used to do this. * AI_BUILD_KEY()-macro can be used to do this.
*/ */
// ---------------------------------------------------------------------------
#define AI_MATKEY_UVWSRC_DIFFUSE(N) "$tex.uvw.diffuse["#N"]" #define AI_MATKEY_UVWSRC_DIFFUSE(N) "$tex.uvw.diffuse["#N"]"
/** @see AI_MATKEY_UVWSRC_DIFFUSE */ /** @see AI_MATKEY_UVWSRC_DIFFUSE */
#define AI_MATKEY_UVWSRC_AMBIENT(N) "$tex.uvw.ambient["#N"]" #define AI_MATKEY_UVWSRC_AMBIENT(N) "$tex.uvw.ambient["#N"]"
@ -700,6 +723,7 @@ extern "C" {
* use the macro suffixed with '_' to build the key dynamically. The * use the macro suffixed with '_' to build the key dynamically. The
* AI_BUILD_KEY()-macro can be used to do this. * AI_BUILD_KEY()-macro can be used to do this.
*/ */
// ---------------------------------------------------------------------------
#define AI_MATKEY_TEXBLEND_DIFFUSE(N) "$tex.blend.diffuse["#N"]" #define AI_MATKEY_TEXBLEND_DIFFUSE(N) "$tex.blend.diffuse["#N"]"
/** @see AI_MATKEY_TEXBLEND_DIFFUSE */ /** @see AI_MATKEY_TEXBLEND_DIFFUSE */
#define AI_MATKEY_TEXBLEND_AMBIENT(N) "$tex.blend.ambient["#N"]" #define AI_MATKEY_TEXBLEND_AMBIENT(N) "$tex.blend.ambient["#N"]"
@ -738,6 +762,7 @@ extern "C" {
* use the macro suffixed with '_' to build the key dynamically. The * use the macro suffixed with '_' to build the key dynamically. The
* AI_BUILD_KEY()-macro can be used to do this. * AI_BUILD_KEY()-macro can be used to do this.
*/ */
// ---------------------------------------------------------------------------
#define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N) "$tex.mapmodeu.diffuse["#N"]" #define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N) "$tex.mapmodeu.diffuse["#N"]"
/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */ /** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */
#define AI_MATKEY_MAPPINGMODE_U_AMBIENT(N) "$tex.mapmodeu.ambient["#N"]" #define AI_MATKEY_MAPPINGMODE_U_AMBIENT(N) "$tex.mapmodeu.ambient["#N"]"
@ -776,6 +801,7 @@ extern "C" {
* use the macro suffixed with '_' to build the key dynamically. The * use the macro suffixed with '_' to build the key dynamically. The
* AI_BUILD_KEY()-macro can be used to do this. * AI_BUILD_KEY()-macro can be used to do this.
*/ */
// ---------------------------------------------------------------------------
#define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N) "$tex.mapmodev.diffuse["#N"]" #define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N) "$tex.mapmodev.diffuse["#N"]"
/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */ /** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */
#define AI_MATKEY_MAPPINGMODE_V_AMBIENT(N) "$tex.mapmodev.ambient["#N"]" #define AI_MATKEY_MAPPINGMODE_V_AMBIENT(N) "$tex.mapmodev.ambient["#N"]"
@ -814,6 +840,7 @@ extern "C" {
* use the macro suffixed with '_' to build the key dynamically. The * use the macro suffixed with '_' to build the key dynamically. The
* AI_BUILD_KEY()-macro can be used to do this. * AI_BUILD_KEY()-macro can be used to do this.
*/ */
// ---------------------------------------------------------------------------
#define AI_MATKEY_MAPPINGMODE_W_DIFFUSE(N) "$tex.mapmodew.diffuse["#N"]" #define AI_MATKEY_MAPPINGMODE_W_DIFFUSE(N) "$tex.mapmodew.diffuse["#N"]"
/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */ /** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */
#define AI_MATKEY_MAPPINGMODE_W_AMBIENT(N) "$tex.mapmodew.ambient["#N"]" #define AI_MATKEY_MAPPINGMODE_W_AMBIENT(N) "$tex.mapmodew.ambient["#N"]"
@ -841,7 +868,6 @@ extern "C" {
#define AI_MATKEY_ORENNAYAR_ROUGHNESS "$shading.orennayar.roughness" #define AI_MATKEY_ORENNAYAR_ROUGHNESS "$shading.orennayar.roughness"
#define AI_MATKEY_MINNAERT_DARKNESS "$shading.minnaert.darkness" #define AI_MATKEY_MINNAERT_DARKNESS "$shading.minnaert.darkness"
#define AI_MATKEY_COOK_TORRANCE_REFRACTI "$shading.cookt.refracti"
#define AI_MATKEY_COOK_TORRANCE_PARAM "$shading.cookt.param" #define AI_MATKEY_COOK_TORRANCE_PARAM "$shading.cookt.param"
/** @def AI_MATKEY_GLOBAL_BACKGROUND_IMAGE /** @def AI_MATKEY_GLOBAL_BACKGROUND_IMAGE

View File

@ -107,6 +107,16 @@ struct aiColor3D
bool operator != (const aiColor3D& other) const bool operator != (const aiColor3D& other) const
{return r != other.r || g != other.g || b != other.b;} {return r != other.r || g != other.g || b != other.b;}
aiColor3D operator+(const aiColor3D& c) const
{return aiColor3D(r+c.r,g+c.g,b+c.b);}
aiColor3D operator-(const aiColor3D& c) const
{return aiColor3D(r+c.r,g+c.g,b+c.b);}
aiColor3D operator*(const aiColor3D& c) const
{return aiColor3D(r*c.r,g*c.g,b*c.b);}
aiColor3D operator*(float f)
{return aiColor3D(r*f,g*f,b*f);}
#endif // !__cplusplus #endif // !__cplusplus
//! Red, green and blue color values //! Red, green and blue color values

View File

View File

@ -211,7 +211,7 @@ void JNIEnvironment::_assimp::_Mesh::Fill(jobject obj,const aiMesh* pcSrc)
} }
// copy bones // copy bones
if (0 < pcSrc->mNumBones) if (pcSrc->mNumBones)
{ {
// allocate the array // allocate the array
jobjectArray jarr = pc->NewObjectArray(pcSrc->mNumBones, jobjectArray jarr = pc->NewObjectArray(pcSrc->mNumBones,

View File

@ -71,17 +71,17 @@ public class BoneAnim {
/** /**
* Rotation keyframes * Rotation keyframes
*/ */
private KeyFrame<Quaternion>[] mQuatKeys; private KeyFrame<Quaternion>[] mQuatKeys = null;
/** /**
* Position keyframes. Component ordering is x,y,z * Position keyframes. Component order is x,y,z
*/ */
private KeyFrame<float[]>[] mPosKeys; private KeyFrame<float[]>[] mPosKeys = null;
/** /**
* scaling keyframes. Component ordering is x,y,z * scaling keyframes. Component order is x,y,z
*/ */
private KeyFrame<float[]>[] mScalingKeys; private KeyFrame<float[]>[] mScalingKeys = null;
/** /**

View File

@ -196,8 +196,8 @@ public class Importer {
* List of config properties for all supported types: int, float and string * List of config properties for all supported types: int, float and string
*/ */
private PropertyList<Integer> properties = new PropertyList<Integer>(); private PropertyList<Integer> properties = new PropertyList<Integer>();
private PropertyList<Float> propertiesFloat = new PropertyList<Float>(); private PropertyList<Float> propertiesFloat = new PropertyList<Float>();
private PropertyList<String> propertiesString = new PropertyList<String>(); private PropertyList<String> propertiesString = new PropertyList<String>();
/** /**
@ -221,7 +221,7 @@ public class Importer {
* @param iVersion Version of the JNI interface to be used. * @param iVersion Version of the JNI interface to be used.
* @throws NativeException Thrown if the jassimp library could not be loaded * @throws NativeException Thrown if the jassimp library could not be loaded
* or if the entry point to the module wasn't found. if this exception * or if the entry point to the module wasn't found. if this exception
* is not thrown, you can assume that jAssimp is fully available. * is not thrown you can assume that jAssimp is fully available.
*/ */
public Importer(int iVersion) throws NativeException { public Importer(int iVersion) throws NativeException {
@ -390,12 +390,30 @@ public class Importer {
throw new NativeException("Failed to load the mesh"); throw new NativeException("Failed to load the mesh");
} }
if (null == this.scene) { if (null == this.scene) {
throw new NativeException("Failed to copy the data into the Java VM"); throw new NativeException("Failed to copy the data to Java");
} }
return this.scene; return this.scene;
} }
/**
* Get the current scene or <code>null</code> if none is loaded
* @return Hello Amanda, I want to play a game ...
*/
public final Scene getScene() {
return scene;
}
/**
* Get the source path of the current scene or <code>null</code> if none is loaded
* @return Game Over.
*/
public final String getScenePath() {
return path;
}
/** /**
* Implementation of <code>java.lang.Object.equals()</code> * Implementation of <code>java.lang.Object.equals()</code>
* *
@ -555,6 +573,10 @@ public class Importer {
} }
// *********************************************************************************
// JNI INTERNALS
// *********************************************************************************
/** /**
* JNI bridge call. For internal use only * JNI bridge call. For internal use only
* The method initializes the ASSIMP-JNI bridge for use. No native * The method initializes the ASSIMP-JNI bridge for use. No native

View File

@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package assimp; package assimp;
/** /**
* Class to wrap materials. Materials are represented in ASSIMP as a list of * Class to wrap materials. Materials are represented in ASSIMP as a list of
* key/value pairs, the key being a <code>String</code> and the value being * key/value pairs, the key being a <code>String</code> and the value being
@ -80,7 +79,8 @@ public class Material {
/** /**
* Constructs a new exception * Constructs a new exception
* @param message Error message *
* @param message Error message
* @param property_key Name of the property that wasn't found * @param property_key Name of the property that wasn't found
*/ */
public PropertyNotFoundException(String message, String property_key) { public PropertyNotFoundException(String message, String property_key) {
@ -92,27 +92,29 @@ public class Material {
/** /**
* Get a property with a specific name as generic <code>Object</code> * Get a property with a specific name as generic <code>Object</code>
*
* @param key MATKEY_XXX key constant * @param key MATKEY_XXX key constant
* @return null if the property wasn't there or hasn't * @return null if the property wasn't there or hasn't
* the desired output type. The returned <code>Object</code> can be * the desired output type. The returned <code>Object</code> can be
* casted to the expected data type for the property. Primitive * casted to the expected data type for the property. Primitive
* types are represented by their boxed variants. * types are represented by their boxed variants.
*/ */
public Object getProperty(String key) throws PropertyNotFoundException { public Object getProperty(String key) throws PropertyNotFoundException {
for (Property prop : properties) { for (Property prop : properties) {
if (prop.key.equals(key)){ if (prop.key.equals(key)) {
return prop.value; return prop.value;
} }
} }
throw new PropertyNotFoundException("Unable to find material property: ",key); throw new PropertyNotFoundException("Unable to find material property: ", key);
} }
/** /**
* Get a material property as float array * Get a material property as float array
*
* @param key MATKEY_XXX key constant * @param key MATKEY_XXX key constant
* @throws PropertyNotFoundException - if the property can't be found * @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type. * or if it has the wrong data type.
*/ */
public float[] getPropertyAsFloatArray(String key) throws PropertyNotFoundException { public float[] getPropertyAsFloatArray(String key) throws PropertyNotFoundException {
@ -121,18 +123,19 @@ public class Material {
return (float[]) obj; return (float[]) obj;
} }
String msg = "The data type requested (float[]) doesn't match the " + String msg = "The data type requested (float[]) doesn't match the " +
"real data type of the material property"; "real data type of the material property";
DefaultLogger.get().error(msg); DefaultLogger.get().error(msg);
throw new PropertyNotFoundException(msg,key); throw new PropertyNotFoundException(msg, key);
} }
/** /**
* Get a floating-point material property * Get a floating-point material property
*
* @param key MATKEY_XXX key constant * @param key MATKEY_XXX key constant
* @return The value of the property. * @return The value of the property.
* @throws PropertyNotFoundException - if the property can't be found * @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type. * or if it has the wrong data type.
*/ */
public float getPropertyAsFloat(String key) throws PropertyNotFoundException { public float getPropertyAsFloat(String key) throws PropertyNotFoundException {
@ -141,18 +144,19 @@ public class Material {
return (Float) obj; return (Float) obj;
} }
String msg = "The data type requested (Float) doesn't match the " + String msg = "The data type requested (Float) doesn't match the " +
"real data type of the material property"; "real data type of the material property";
DefaultLogger.get().error(msg); DefaultLogger.get().error(msg);
throw new PropertyNotFoundException(msg,key); throw new PropertyNotFoundException(msg, key);
} }
/** /**
* Get an integer material property * Get an integer material property
*
* @param key MATKEY_XXX key constant * @param key MATKEY_XXX key constant
* @return The value of the property. * @return The value of the property.
* @throws PropertyNotFoundException - if the property can't be found * @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type. * or if it has the wrong data type.
*/ */
public int getPropertyAsInt(String key) throws PropertyNotFoundException { public int getPropertyAsInt(String key) throws PropertyNotFoundException {
@ -161,18 +165,19 @@ public class Material {
return (Integer) obj; return (Integer) obj;
} }
String msg = "The data type requested (Integer) doesn't match the " + String msg = "The data type requested (Integer) doesn't match the " +
"real data type of the material property"; "real data type of the material property";
DefaultLogger.get().error(msg); DefaultLogger.get().error(msg);
throw new PropertyNotFoundException(msg,key); throw new PropertyNotFoundException(msg, key);
} }
/** /**
* Get a material property string * Get a material property string
*
* @param key MATKEY_XXX key constant * @param key MATKEY_XXX key constant
* @return The value of the property. * @return The value of the property.
* @throws PropertyNotFoundException - if the property can't be found * @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type. * or if it has the wrong data type.
*/ */
public String getPropertyAsString(String key) throws PropertyNotFoundException { public String getPropertyAsString(String key) throws PropertyNotFoundException {
@ -181,9 +186,9 @@ public class Material {
return (String) obj; return (String) obj;
} }
String msg = "The data type requested (java.lang.String) doesn't match the " + String msg = "The data type requested (java.lang.String) doesn't match the " +
"real data type of the material property"; "real data type of the material property";
DefaultLogger.get().error(msg); DefaultLogger.get().error(msg);
throw new PropertyNotFoundException(msg,key); throw new PropertyNotFoundException(msg, key);
} }
@ -228,7 +233,9 @@ public class Material {
* <br> * <br>
* <b>Type:</b> int (TextureOp)<br> * <b>Type:</b> int (TextureOp)<br>
* <b>Default value:</b> 0<br> * <b>Default value:</b> 0<br>
* <b>Requires:</b> MATKEY_TEXTURE_DIFFUSE(0)<br> * <b>Requires:</b> MATKEY_TEXTURE_DIFFUSE(N)<br>
*
* @param N Index of the texture
*/ */
public static String MATKEY_TEXOP_DIFFUSE(int N) { public static String MATKEY_TEXOP_DIFFUSE(int N) {
return "$tex.op.diffuse[" + N + "]"; return "$tex.op.diffuse[" + N + "]";
@ -284,5 +291,320 @@ public class Material {
} }
/**
* Specifies the blend factor to be multiplied with the value of
* the n'th texture layer before it is combined with the previous
* layer using a specific blend operation.
* <p/>
* <br>
* <b>Type:</b> float<br>
* <b>Default value:</b> 1.0f<br>
* <b>Requires:</b> MATKEY_TEXTURE_DIFFUSE(N)<br>
*
* @param N Index of the texture
*/
public static String MATKEY_TEXBLEND_DIFFUSE(int N) {
return "$tex.blend.diffuse[" + N + "]";
}
/**
* @see <code>MATKEY_TEXBLEND_DIFFUSE</code>
*/
public static String MATKEY_TEXBLEND_SPECULAR(int N) {
return "$tex.blend.specular[" + N + "]";
}
/**
* @see <code>MATKEY_TEXBLEND_DIFFUSE</code>
*/
public static String MATKEY_TEXBLEND_AMBIENT(int N) {
return "$tex.blend.ambient[" + N + "]";
}
/**
* @see <code>MATKEY_TEXBLEND_DIFFUSE</code>
*/
public static String MATKEY_TEXBLEND_EMISSIVE(int N) {
return "$tex.blend.emissive[" + N + "]";
}
/**
* @see <code>MATKEY_TEXBLEND_DIFFUSE</code>
*/
public static String MATKEY_TEXBLEND_SHININESS(int N) {
return "$tex.blend.shininess[" + N + "]";
}
/**
* @see <code>MATKEY_TEXBLEND_DIFFUSE</code>
*/
public static String MATKEY_TEXBLEND_OPACITY(int N) {
return "$tex.blend.opacity[" + N + "]";
}
/**
* @see <code>MATKEY_TEXBLEND_DIFFUSE</code>
*/
public static String MATKEY_TEXBLEND_HEIGHT(int N) {
return "$tex.blend.height[" + N + "]";
}
/**
* @see <code>MATKEY_TEXBLEND_DIFFUSE</code>
*/
public static String MATKEY_TEXBLEND_NORMALS(int N) {
return "$tex.blend.normals[" + N + "]";
}
/**
* Specifies the index of the UV channel to be used for a texture
* <br>
* <b>Type:</b>int<br>
* <b>Default value:</b>0<br>
* <b>Requires:</b> MATKEY_TEXTURE_DIFFUSE(N)<br>
*
* @param N Index of the texture
*/
public static String MATKEY_UVWSRC_DIFFUSE(int N) {
return "$tex.uvw.diffuse[" + N + "]";
}
/**
* @see <code>MATKEY_UVWSRC_DIFFUSE</code>
*/
public static String MATKEY_UVWSRC_SPECULAR(int N) {
return "$tex.uvw.specular[" + N + "]";
}
/**
* @see <code>MATKEY_UVWSRC_DIFFUSE</code>
*/
public static String MATKEY_UVWSRC_AMBIENT(int N) {
return "$tex.uvw.ambient[" + N + "]";
}
/**
* @see <code>MATKEY_UVWSRC_DIFFUSE</code>
*/
public static String MATKEY_UVWSRC_EMISSIVE(int N) {
return "$tex.uvw.emissive[" + N + "]";
}
/**
* @see <code>MATKEY_UVWSRC_DIFFUSE</code>
*/
public static String MATKEY_UVWSRC_SHININESS(int N) {
return "$tex.uvw.shininess[" + N + "]";
}
/**
* @see <code>MATKEY_UVWSRC_DIFFUSE</code>
*/
public static String MATKEY_UVWSRC_OPACITY(int N) {
return "$tex.uvw.opacity[" + N + "]";
}
/**
* @see <code>MATKEY_UVWSRC_DIFFUSE</code>
*/
public static String MATKEY_UVWSRC_HEIGHT(int N) {
return "$tex.uvw.height[" + N + "]";
}
/**
* @see <code>MATKEY_UVWSRC_DIFFUSE</code>
*/
public static String MATKEY_UVWSRC_NORMALS(int N) {
return "$tex.uvw.normals[" + N + "]";
}
/**
* Specifies the texture mapping mode in the v (y) direction.
* <br>
* <b>Type:</b>int<br>
* <b>Default value:</b>TextureMapMode.Wrap<br>
* <b>Requires:</b> MATKEY_TEXTURE_DIFFUSE(N)<br>
*
* @param N Index of the texture
*/
public static String MATKEY_MAPPINGMODE_U_DIFFUSE(int N) {
return "$tex.mapmodeu.diffuse[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_U_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_U_SPECULAR(int N) {
return "$tex.mapmodeu.specular[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_U_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_U_AMBIENT(int N) {
return "$tex.mapmodeu.ambient[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_U_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_U_EMISSIVE(int N) {
return "$tex.mapmodeu.emissive[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_U_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_U_SHININESS(int N) {
return "$tex.mapmodeu.shininess[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_U_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_U_OPACITY(int N) {
return "$tex.mapmodeu.opacity[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_U_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_U_HEIGHT(int N) {
return "$tex.mapmodeu.height[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_U_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_U_NORMALS(int N) {
return "$tex.mapmodeu.normals[" + N + "]";
}
/**
* Specifies the texture mapping mode in the v (y) direction.
* <br>
* <b>Type:</b>int<br>
* <b>Default value:</b>TextureMapMode.Wrap<br>
* <b>Requires:</b> MATKEY_TEXTURE_DIFFUSE(N)<br>
*
* @param N Index of the texture
*/
public static String MATKEY_MAPPINGMODE_V_DIFFUSE(int N) {
return "$tex.mapmodev.diffuse[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_V_SPECULAR(int N) {
return "$tex.mapmodev.specular[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_V_AMBIENT(int N) {
return "$tex.mapmodev.ambient[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_V_EMISSIVE(int N) {
return "$tex.mapmodev.emissive[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_V_SHININESS(int N) {
return "$tex.mapmodev.shininess[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_V_OPACITY(int N) {
return "$tex.mapmodev.opacity[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_V_HEIGHT(int N) {
return "$tex.mapmodev.height[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_V_NORMALS(int N) {
return "$tex.mapmodev.normals[" + N + "]";
}
/**
* Specifies the texture mapping mode in the w (z) direction.
* <br>
* <b>Type:</b>int<br>
* <b>Default value:</b>TextureMapMode.Wrap<br>
* <b>Requires:</b> MATKEY_TEXTURE_DIFFUSE(N)<br>
*
* @param N Index of the texture
*/
public static String MATKEY_MAPPINGMODE_W_DIFFUSE(int N) {
return "$tex.mapmodew.diffuse[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_W_SPECULAR(int N) {
return "$tex.mapmodew.specular[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_W_AMBIENT(int N) {
return "$tex.mapmodew.ambient[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_W_EMISSIVE(int N) {
return "$tex.mapmodew.emissive[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_W_SHININESS(int N) {
return "$tex.mapmodew.shininess[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_W_OPACITY(int N) {
return "$tex.mapmodew.opacity[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_W_HEIGHT(int N) {
return "$tex.mapmodew.height[" + N + "]";
}
/**
* @see <code>MATKEY_MAPPINGMODE_V_DIFFUSE</code>
*/
public static String MATKEY_MAPPINGMODE_W_NORMALS(int N) {
return "$tex.mapmodew.normals[" + N + "]";
}
} }

View File

@ -45,7 +45,7 @@ package assimp;
/** /**
* Enumeration class that defines postprocess steps that can be executed on a model * Enumeration class that defines postprocess steps that can be executed on a model
* after it has been loaded. All PPSteps are implemented in C++, so their performance * after it has been loaded. All PPSteps are implemented in C++, so their performance
* is awesome. Most steps are O(n * log(n)). ;-) * is awesome :-) (*duck*)
* *
* @author Aramis (Alexander Gessler) * @author Aramis (Alexander Gessler)
* @version 1.0 * @version 1.0
@ -186,54 +186,58 @@ public class PostProcessStep {
new PostProcessStep("ValidateDataStructure"); new PostProcessStep("ValidateDataStructure");
/** Reorders triangles for vertex cache locality and thus better performance. /**
* The step tries to improve the ACMR (average post-transform vertex cache * Reorders triangles for vertex cache locality and thus better performance.
* miss ratio) for all meshes. The step runs in O(n) and is roughly * The step tries to improve the ACMR (average post-transform vertex cache
* basing on the algorithm described in this paper: * miss ratio) for all meshes. The step runs in O(n) and is roughly
* <url>http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf</url> * basing on the algorithm described in this paper:
*/ * <url>http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf</url>
public static final PostProcessStep ImproveVertexLocality = */
public static final PostProcessStep ImproveVertexLocality =
new PostProcessStep("ImproveVertexLocality"); new PostProcessStep("ImproveVertexLocality");
/** Searches for redundant materials and removes them. /**
* * Searches for redundant materials and removes them.
* This is especially useful in combination with the PretransformVertices * <p/>
* and OptimizeGraph steps. Both steps join small meshes, but they * This is especially useful in combination with the PretransformVertices
* can't do that if two meshes have different materials. * and OptimizeGraph steps. Both steps join small meshes, but they
*/ * can't do that if two meshes have different materials.
public static final PostProcessStep RemoveRedundantMaterials = */
public static final PostProcessStep RemoveRedundantMaterials =
new PostProcessStep("RemoveRedundantMaterials"); new PostProcessStep("RemoveRedundantMaterials");
/** This step tries to determine which meshes have normal vectors /**
* that are facing inwards. The algorithm is simple but effective: * This step tries to determine which meshes have normal vectors
* the bounding box of all vertices + their normals is compared against * that are facing inwards. The algorithm is simple but effective:
* the volume of the bounding box of all vertices without their normals. * the bounding box of all vertices + their normals is compared against
* This works well for most objects, problems might occur with planar * the volume of the bounding box of all vertices without their normals.
* surfaces. However, the step tries to filter such cases. * This works well for most objects, problems might occur with planar
* The step inverts all infacing normals. Generally it is recommended * surfaces. However, the step tries to filter such cases.
* to enable this step, although the result is not always correct. * The step inverts all infacing normals. Generally it is recommended
*/ * to enable this step, although the result is not always correct.
public static final PostProcessStep FixInfacingNormals = */
public static final PostProcessStep FixInfacingNormals =
new PostProcessStep("FixInfacingNormals"); new PostProcessStep("FixInfacingNormals");
/** This step performs some optimizations on the node graph. /**
* * This step performs some optimizations on the node graph.
* It is incompatible to the PreTransformVertices-Step. Some configuration * <p/>
* options exist, see aiConfig.h for more details. * It is incompatible to the PreTransformVertices-Step. Some configuration
* Generally, two actions are available:<br> * options exist, see aiConfig.h for more details.
* 1. Remove animation nodes and data from the scene. This allows other * Generally, two actions are available:<br>
* steps for further optimizations.<br> * 1. Remove animation nodes and data from the scene. This allows other
* 2. Combine very small meshes to larger ones. Only if the meshes * steps for further optimizations.<br>
* are used by the same node or by nodes on the same hierarchy (with * 2. Combine very small meshes to larger ones. Only if the meshes
* equal local transformations). Unlike PreTransformVertices, the * are used by the same node or by nodes on the same hierarchy (with
* OptimizeGraph-step doesn't transform vertices from one space * equal local transformations). Unlike PreTransformVertices, the
* another.<br> * OptimizeGraph-step doesn't transform vertices from one space
* 3. Remove hierarchy levels<br> * another.<br>
* * 3. Remove hierarchy levels<br>
* It is recommended to have this step run with the default configuration. * <p/>
*/ * It is recommended to have this step run with the default configuration.
public static final PostProcessStep OptimizeGraph = */
public static final PostProcessStep OptimizeGraph =
new PostProcessStep("OptimizeGraph"); new PostProcessStep("OptimizeGraph");
private final String myName; // for debug only private final String myName; // for debug only

View File

@ -42,11 +42,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package assimp; package assimp;
/** /**
* Created by IntelliJ IDEA. * Defines how texture coordinates ! ElemOf [0 ... 1] are handled.
* User: Alex *
* Date: 08.06.2008 * This corresponds to the native <code>aiTextureMapMode</code> enum.
* Time: 17:27:11 *
* To change this template use File | Settings | File Templates. * @author Alexander Gessler (Aramis)
*/ */
public class TextureMapMode { public class TextureMapMode {
/** A texture coordinate u|v is translated to u%1|v%1
*/
public static final int Wrap = 0x0;
/** Texture coordinates outside the area formed by 1|1 and 0|0
* are clamped to the nearest valid value on an axis
*/
public static final int Clamp = 0x1;
/** A texture coordinate u|v becomes u%1|v%1 if (u-(u%1))%2 is zero and
* 1-(u%1)|1-(v%1) otherwise
*/
public static final int Mirror = 0x2;
} }

View File

@ -45,8 +45,14 @@ package assimp.test;
import assimp.*; import assimp.*;
import javax.imageio.ImageWriter;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.File;
import java.awt.image.BufferedImage;
import java.util.Iterator;
/** /**
@ -115,10 +121,34 @@ public class DumpToFile {
* *
* @param texture Texture to be exported * @param texture Texture to be exported
* @param path Output path * @param path Output path
* @throws IOException yes ... sometimes ... :-)
*/ */
public static void SaveTextureToTGA(Texture texture, String path) throws IOException { public static void SaveTextureToTGA(Texture texture, String path) {
BufferedImage bImg = texture.convertToImage();
Iterator writers = ImageIO.getImageWritersBySuffix("tga");
if (!(writers.hasNext())) {
System.out.println("No writer for TGA file format available");
return;
}
ImageWriter w = (ImageWriter) (writers.next());
if (w == null) {
System.out.println("No writer for TGA file format available");
return;
}
File fo = new File(path);
try {
ImageOutputStream ios = ImageIO.createImageOutputStream(fo);
w.setOutput(ios);
w.write(bImg);
}
catch (IOException ex) {
System.out.println("Failed to write " + path);
return;
}
System.out.println(path + " has been written");
} }
@ -390,7 +420,7 @@ public class DumpToFile {
String path = arguments[1].substring(0, arguments[1].length() - 4) + "_tex" + i++ + ".tga"; String path = arguments[1].substring(0, arguments[1].length() - 4) + "_tex" + i++ + ".tga";
stream.write("Emb. Texture\n" + stream.write("Emb. Texture\n" +
"\tExportPath: " + path + "\n\n"); "\tExportPath: " + path + "\n\n");
SaveTextureToTGA(texture, path); SaveTextureToTGA(texture, path);
} }
@ -399,7 +429,6 @@ public class DumpToFile {
/* Now print all materials /* Now print all materials
*/ */
// close the stream again // close the stream again
stream.close(); stream.close();
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -36,9 +36,9 @@
<entry_points /> <entry_points />
</component> </component>
<component name="ExportToHTMLSettings"> <component name="ExportToHTMLSettings">
<option name="PRINT_LINE_NUMBERS" value="false" /> <option name="PRINT_LINE_NUMBERS" value="true" />
<option name="OPEN_IN_BROWSER" value="false" /> <option name="OPEN_IN_BROWSER" value="true" />
<option name="OUTPUT_DIRECTORY" /> <option name="OUTPUT_DIRECTORY" value="J:\Programmieren\ASSIMP\assimp3\trunk\workspaces\jidea5.1\exportToHTML" />
</component> </component>
<component name="GUI Designer component loader factory" /> <component name="GUI Designer component loader factory" />
<component name="JavacSettings"> <component name="JavacSettings">
@ -49,7 +49,7 @@
<option name="MAXIMUM_HEAP_SIZE" value="128" /> <option name="MAXIMUM_HEAP_SIZE" value="128" />
</component> </component>
<component name="JavadocGenerationManager"> <component name="JavadocGenerationManager">
<option name="OUTPUT_DIRECTORY" value="J:/Programmieren/ASSIMP3/assimp/doc/javadoc" /> <option name="OUTPUT_DIRECTORY" value="J:/Programmieren/ASSIMP/assimp3/doc/javadoc" />
<option name="OPTION_SCOPE" value="protected" /> <option name="OPTION_SCOPE" value="protected" />
<option name="OPTION_HIERARCHY" value="true" /> <option name="OPTION_HIERARCHY" value="true" />
<option name="OPTION_NAVIGATOR" value="true" /> <option name="OPTION_NAVIGATOR" value="true" />

View File

@ -1132,6 +1132,10 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="AC"
>
</Filter>
</Filter> </Filter>
</Filter> </Filter>
<Filter <Filter
@ -1468,6 +1472,10 @@
> >
</File> </File>
</Filter> </Filter>
<Filter
Name="AC"
>
</Filter>
</Filter> </Filter>
</Filter> </Filter>
<Filter <Filter