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!
- 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.
-Thomas Schulze,
X-Loader, Preprocessing framework.
X-Loader, Preprocessing framework. Data structure & Interface design, documentation.
-R.Schmidt,
Linux build, eclipse support.
- Kim Kulling:
Obj-Loader, Logging, Scons-build enviroment.
Obj-Loader, Logging, Scons-build environment.
- Matthias Gubisch,
Assimp.net
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,
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
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
supplied various XFiles for testing purposes.

View File

@ -63,6 +63,31 @@ using namespace Assimp;
#define AI_DXF_BINARY_IDENT_LEN (24)
// color indices for DXF - 16 are supported
static aiColor4D g_aclrDxfIndexColors[] =
{
aiColor4D (0.6f, 0.6f, 0.6f, 1.0f),
aiColor4D (1.0f, 0.0f, 0.0f, 1.0f), // red
aiColor4D (0.0f, 1.0f, 0.0f, 1.0f), // green
aiColor4D (0.0f, 0.0f, 1.0f, 1.0f), // blue
aiColor4D (0.3f, 1.0f, 0.3f, 1.0f), // light green
aiColor4D (0.3f, 0.3f, 1.0f, 1.0f), // light blue
aiColor4D (1.0f, 0.3f, 0.3f, 1.0f), // light red
aiColor4D (1.0f, 0.0f, 1.0f, 1.0f), // pink
aiColor4D (1.0f, 0.6f, 0.0f, 1.0f), // orange
aiColor4D (0.6f, 0.3f, 0.0f, 1.0f), // dark orange
aiColor4D (1.0f, 1.0f, 0.0f, 1.0f), // yellow
aiColor4D (0.3f, 0.3f, 0.3f, 1.0f), // dark gray
aiColor4D (0.8f, 0.8f, 0.8f, 1.0f), // light gray
aiColor4D (0.0f, 00.f, 0.0f, 1.0f), // black
aiColor4D (1.0f, 1.0f, 1.0f, 1.0f), // white
aiColor4D (0.6f, 0.0f, 1.0f, 1.0f) // violet
};
#define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0]))
// invalid/unassigned color value
aiColor4D g_clrInvalid = aiColor4D(std::numeric_limits<float>::quiet_NaN(),0.f,0.f,1.f);
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
DXFImporter::DXFImporter()
@ -157,7 +182,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
{
// ENTITIES and BLOCKS sections - skip the whole rest, no need to waste our time with them
if (!::strcmp(cursor,"ENTITIES") || !::strcmp(cursor,"BLOCKS"))
if (!ParseEntities())break;
if (!ParseEntities())break; else bRepeat = true;
// other sections - skip them to make sure there will be no name conflicts
else
@ -200,6 +225,21 @@ void DXFImporter::InternReadFile( const std::string& pFile,
// generate the output mesh
aiMesh* pMesh = pScene->mMeshes[m++] = new aiMesh();
const std::vector<aiVector3D>& vPositions = (*it).vPositions;
const std::vector<aiColor4D>& vColors = (*it).vColors;
// check whether we need vertex colors here
aiColor4D* clrOut;
const aiColor4D* clr = NULL;
for (std::vector<aiColor4D>::const_iterator it2 = (*it).vColors.begin(), end2 = (*it).vColors.end();
it2 != end2; ++it2)
{
if (std::numeric_limits<float>::quiet_NaN() != (*it2).r)
{
clrOut = pMesh->mColors[0] = new aiColor4D[vPositions.size()];
clr = &vColors[0];
break;
}
}
pMesh->mNumFaces = (unsigned int)vPositions.size() / 4u;
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
@ -222,6 +262,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
for (unsigned int a = 0; a < face.mNumIndices;++a)
{
*vpOut++ = vp[a];
if (clr)*clrOut++ = clr[a];
face.mIndices[a] = pMesh->mNumVertices++;
}
vp += 4;
@ -333,6 +374,7 @@ bool DXFImporter::ParsePolyLine()
LayerInfo* out = NULL;
std::vector<aiVector3D> positions;
std::vector<aiColor4D> colors;
std::vector<unsigned int> indices;
unsigned int flags = 0;
@ -344,10 +386,14 @@ bool DXFImporter::ParsePolyLine()
{
if (!::strcmp(cursor,"VERTEX"))
{
aiVector3D v;
aiVector3D v;aiColor4D clr(g_clrInvalid);
unsigned int idx[4] = {0xffffffff,0xffffffff,0xffffffff,0xffffffff};
ParsePolyLineVertex(v, idx);
if (0xffffffff == idx[0])positions.push_back(v);
ParsePolyLineVertex(v, clr, idx);
if (0xffffffff == idx[0])
{
positions.push_back(v);
colors.push_back(clr);
}
else
{
// check whether we have a fourth coordinate
@ -413,6 +459,10 @@ bool DXFImporter::ParsePolyLine()
// use a default layer if necessary
if (!out)SetDefaultLayer(out);
flags = (unsigned int)(out->vPositions.size()+indices.size());
out->vPositions.reserve(flags);
out->vColors.reserve(flags);
// generate unique vertices
for (std::vector<unsigned int>::const_iterator it = indices.begin(), end = indices.end();
it != end; ++it)
@ -424,13 +474,14 @@ bool DXFImporter::ParsePolyLine()
idx = (unsigned int) positions.size();
}
out->vPositions.push_back(positions[idx-1]); // indices are one-based.
out->vColors.push_back(colors[idx-1]); // indices are one-based.
}
return ret;
}
// ------------------------------------------------------------------------------------------------
bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx)
bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,aiColor4D& clr, unsigned int* outIdx)
{
bool ret = false;
while (GetNextToken())
@ -455,6 +506,9 @@ bool DXFImporter::ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx)
case 72: outIdx[1] = strtol10(cursor);break;
case 73: outIdx[2] = strtol10(cursor);break;
case 74: outIdx[3] = strtol10(cursor);break;
// color
case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break;
};
if (ret)break;
}
@ -468,6 +522,7 @@ bool DXFImporter::Parse3DFace()
LayerInfo* out = NULL;
aiVector3D vip[4]; // -- vectors are initialized to zero
aiColor4D clr(g_clrInvalid);
while (GetNextToken())
{
switch (groupCode)
@ -516,6 +571,9 @@ bool DXFImporter::Parse3DFace()
// z position of the fourth corner
case 33: vip[3].z = fast_atof(cursor);break;
// color
case 62: clr = g_aclrDxfIndexColors[strtol10(cursor) % AI_DXF_NUM_INDEX_COLORS]; break;
};
if (ret)break;
}
@ -528,5 +586,8 @@ bool DXFImporter::Parse3DFace()
out->vPositions.push_back(vip[1]);
out->vPositions.push_back(vip[2]);
out->vPositions.push_back(vip[3]); // might be equal to the third
for (unsigned int i = 0; i < 4;++i)
out->vColors.push_back(clr);
return ret;
}

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)
std::vector<aiVector3D> vPositions;
std::vector<aiColor4D> vColors;
};
@ -149,11 +150,13 @@ protected:
// -------------------------------------------------------------------
/** Parses a VERTEX element in a POLYLINE/POLYFACE
* @param out Receives the output vertex.
* @param clr Receives the output vertex color - won't be modified
* if it is not existing.
* @param outIdx Receives the output vertex indices, if present.
* Wont't be modified otherwise. Size must be at least 4.
* @return false if the end of the file was reached
*/
bool ParsePolyLineVertex(aiVector3D& out,unsigned int* outIdx);
bool ParsePolyLineVertex(aiVector3D& out, aiColor4D& clr, unsigned int* outIdx);
private:

View File

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

View File

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

View File

@ -2,17 +2,21 @@
// Definitions for the Interchange File Format (IFF)
// Alexander Gessler, 2006
// Adapted for Assimp August 2008
// Adapted to Assimp August 2008
#ifndef AI_IFF_H_INCLUDED
#define AI_IFF_H_INCLUDED
#include "ByteSwap.h"
namespace Assimp {
namespace IFF {
namespace Assimp {
namespace IFF {
#include "./../include/Compiler/pushpack1.h"
/////////////////////////////////////////////////////////////////////////////////
//! Describes an IFF chunk header
/////////////////////////////////////////////////////////////////////////////////
struct ChunkHeader
{
//! Type of the chunk header - FourCC
@ -20,7 +24,22 @@ struct ChunkHeader
//! Length of the chunk data, in bytes
uint32_t length;
};
} PACK_STRUCT;
/////////////////////////////////////////////////////////////////////////////////
//! Describes an IFF sub chunk header
/////////////////////////////////////////////////////////////////////////////////
struct SubChunkHeader
{
//! Type of the chunk header - FourCC
uint32_t type;
//! Length of the chunk data, in bytes
uint16_t length;
} PACK_STRUCT;
#include "./../include/Compiler/poppack1.h"
#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
@ -30,6 +49,34 @@ struct ChunkHeader
#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M')
/////////////////////////////////////////////////////////////////////////////////
//! Load a chunk header
//! @param outFile Pointer to the file data - points to the chunk data afterwards
//! @return Pointer to the chunk header
/////////////////////////////////////////////////////////////////////////////////
inline LE_NCONST ChunkHeader* LoadChunk(LE_NCONST uint8_t*& outFile)
{
LE_NCONST ChunkHeader* head = (LE_NCONST ChunkHeader*) outFile;
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
outFile += sizeof(ChunkHeader);
return head;
}
/////////////////////////////////////////////////////////////////////////////////
//! Load a sub chunk header
//! @param outFile Pointer to the file data - points to the chunk data afterwards
//! @return Pointer to the sub chunk header
/////////////////////////////////////////////////////////////////////////////////
inline LE_NCONST SubChunkHeader* LoadSubChunk(LE_NCONST uint8_t*& outFile)
{
LE_NCONST SubChunkHeader* head = (LE_NCONST SubChunkHeader*) outFile;
AI_LSWAP2(head->length);
AI_LSWAP4(head->type);
outFile += sizeof(SubChunkHeader);
return head;
}
/////////////////////////////////////////////////////////////////////////////////
//! Read the file header and return the type of the file and its size
//! @param outFile Pointer to the file data. The buffer must at
@ -37,11 +84,9 @@ struct ChunkHeader
//! @param fileType Receives the type of the file
//! @return 0 if everything was OK, otherwise an error message
/////////////////////////////////////////////////////////////////////////////////
inline const char* ReadHeader(const uint8_t* outFile,uint32_t& fileType)
inline const char* ReadHeader(LE_NCONST uint8_t* outFile,uint32_t& fileType)
{
LE_NCONST ChunkHeader* head = (LE_NCONST ChunkHeader*) outFile;
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
LE_NCONST ChunkHeader* head = LoadChunk(outFile);
if(AI_IFF_FOURCC_FORM != head->type)
{
return "The file is not an IFF file: FORM chunk is missing";

View File

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

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
The chunks are taken from LWO2.h, found in the sourcecode of
a project called Nxabega (http://www.sourceforge.net/projects/nxabega).
I assume they are from the official LightWave SDK headers.
The chunks are taken from the official LightWave SDK headers.
Original copyright notice: "Ernie Wright 17 Sep 00"
*/
@ -253,12 +251,25 @@ namespace LWO {
struct Face : public aiFace
{
Face()
: surfaceIndex(0)
, smoothGroup(0)
: surfaceIndex (0)
, smoothGroup (0)
{}
Face(const Face& f)
{
*this = f;
}
unsigned int surfaceIndex;
unsigned int smoothGroup;
Face& operator=(const LWO::Face& f)
{
aiFace::operator =(f);
surfaceIndex = f.surfaceIndex;
smoothGroup = f.smoothGroup;
return *this;
}
};
@ -271,11 +282,24 @@ struct VMapEntry
: dims(_dims)
{}
~VMapEntry() {delete[] rawData;}
virtual ~VMapEntry() {}
//! allocates memory for the vertex map
virtual void Allocate(unsigned int num)
{
if (!rawData.empty())return; // return if already allocated
register unsigned int m = num*dims;
rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs
rawData.resize(m,0.f);
abAssigned.resize(num,false);
}
std::string name;
float* rawData;
unsigned int dims;
std::vector<float> rawData;
std::vector<bool> abAssigned;
};
// ---------------------------------------------------------------------------
@ -283,16 +307,29 @@ struct VMapEntry
*/
struct VColorChannel : public VMapEntry
{
VColorChannel(unsigned int num)
VColorChannel()
: VMapEntry(4)
{
data = new aiColor4D[num];
for (unsigned int i = 0; i < num;++i)
data[i].a = 1.0f;
rawData = (float*)data;
}
{}
aiColor4D* data;
//! need to overwrite this function - the alpha channel must
//! be initialized to 1.0 by default
virtual void Allocate(unsigned int num)
{
if (!rawData.empty())return; // return if already allocated
register unsigned int m = num*dims;
rawData.reserve(m + (m>>2u)); // 25% as extra storage for VMADs
rawData.resize(m,0.f);
for (std::vector<float>::iterator it = rawData.begin(), end = rawData.end();
it != end;++it )
{
for (unsigned int i = 0; i< 3;++i,++it)
*it = 0.f;
*it = 1.f;
}
abAssigned.resize(num,false);
}
};
// ---------------------------------------------------------------------------
@ -300,14 +337,9 @@ struct VColorChannel : public VMapEntry
*/
struct UVChannel : public VMapEntry
{
UVChannel(unsigned int num)
: VMapEntry(3)
{
data = new aiVector3D[num]; // to make the final copying easier
rawData = (float*)data;
}
aiVector3D* data;
UVChannel()
: VMapEntry(2)
{}
};
// ---------------------------------------------------------------------------
@ -315,13 +347,9 @@ struct UVChannel : public VMapEntry
*/
struct WeightChannel : public VMapEntry
{
WeightChannel(unsigned int num)
WeightChannel()
: VMapEntry(1)
{
rawData = new float[num];
for (unsigned int m = 0; m < num;++m)
rawData[m] = 0.f;
}
{}
};
@ -330,10 +358,59 @@ struct WeightChannel : public VMapEntry
*/
struct Texture
{
// we write the enum values out here to make debugging easier ...
enum BlendType
{
Normal = 0,
Subtractive = 1,
Difference = 2,
Multiply = 3,
Divide = 4,
Alpha = 5,
TextureDispl = 6,
Additive = 7
};
enum MappingMode
{
Planar = 0,
Cylindrical = 1,
Spherical = 2,
Cubic = 3,
FrontProjection = 4,
UV = 5
};
enum Axes
{
AXIS_X = 0,
AXIS_Y = 1,
AXIS_Z = 2
};
enum Wrap
{
RESET = 0,
REPEAT = 1,
MIRROR = 2,
EDGE = 3
};
Texture()
: mClipIdx(0xffffffff)
, mStrength (1.0f)
, mUVChannelIndex ("unknown")
, mRealUVIndex (0xffffffff)
, enabled (true)
, blendType (Additive)
, bCanUse (true)
, mapMode (UV)
, majorAxis (AXIS_X)
, wrapAmountH (1.0f)
, wrapAmountW (1.0f)
, wrapModeWidth (REPEAT)
, wrapModeHeight (REPEAT)
, ordinal ("\x00")
{}
//! File name of the texture
@ -342,15 +419,38 @@ struct Texture
//! Clip index
unsigned int mClipIdx;
//! Strength of the texture
//! Strength of the texture - blend factor
float mStrength;
/*************** SPECIFIC TO LWO2 *********************/
uint32_t type; // type of the texture
//! Name of the corresponding UV channel
std::string mUVChannelIndex;
unsigned int mRealUVIndex;
//! is the texture enabled?
bool enabled;
//! blend type
BlendType blendType;
//! are we able to use the texture?
bool bCanUse;
//! mapping mode
MappingMode mapMode;
//! major axis for planar, cylindrical, spherical projections
Axes majorAxis;
//! wrap amount for cylindrical and spherical projections
float wrapAmountH,wrapAmountW;
//! wrapping mode for the texture
Wrap wrapModeWidth,wrapModeHeight;
//! ordinal string of the texture
std::string ordinal;
};
// ---------------------------------------------------------------------------
@ -358,23 +458,66 @@ struct Texture
*/
struct Clip
{
//! path to the base texture
enum Type
{
STILL, SEQ, REF, UNSUPPORTED
} type;
Clip()
: type (UNSUPPORTED)
, idx (0)
{}
//! path to the base texture -
std::string path;
//! reference to another CLIP
unsigned int clipRef;
//! index of the clip
unsigned int idx;
};
// ---------------------------------------------------------------------------
/** \brief Data structure for a LWO file shader
*
* Later
*/
struct Shader
{
Shader()
: ordinal ("\x00")
, functionName ("unknown")
, enabled (true)
{}
std::string ordinal;
std::string functionName;
bool enabled;
};
typedef std::list < Texture > TextureList;
typedef std::list < Shader > ShaderList;
// ---------------------------------------------------------------------------
/** \brief Data structure for a LWO file surface (= material)
*/
struct Surface
{
Surface()
: bDoubleSided (false)
, mDiffuseValue (1.0f)
, mSpecularValue (1.0f)
, mTransparency (0.0f)
, mGlossiness (0.0f)
, mLuminosity (0.0f)
, mMaximumSmoothAngle (0.0f) // 0 == not specified
: mColor (0.78431f,0.78431f,0.78431f)
, bDoubleSided (false)
, mDiffuseValue (1.f)
, mSpecularValue (0.f)
, mTransparency (0.f)
, mGlossiness (0.4f)
, mLuminosity (0.f)
, mColorHighlights (0.f)
, mMaximumSmoothAngle (0.f) // 0 == not specified, no smoothing
, mVCMap ("")
, mIOR (1.f) // vakuum
, mBumpIntensity (1.f)
{}
//! Name of the surface
@ -387,23 +530,38 @@ struct Surface
bool bDoubleSided;
//! Various material parameters
float mDiffuseValue,mSpecularValue,mTransparency,mGlossiness,mLuminosity;
float mDiffuseValue,mSpecularValue,mTransparency,mGlossiness,mLuminosity,mColorHighlights;
//! Maximum angle between two adjacent triangles
//! that they can be smoothed - in degrees
float mMaximumSmoothAngle;
//! Textures
Texture mColorTexture,mDiffuseTexture,mSpecularTexture,
mBumpTexture,mTransparencyTexture;
//! Vertex color map to be used to color the surface
std::string mVCMap;
//! Names of the special shaders to be applied to the surface
ShaderList mShaders;
//! Textures - the first entry in the list is evaluated first
TextureList mColorTextures, // color textures are added to both diffuse and specular texture stacks
mDiffuseTextures,
mSpecularTextures,
mOpacityTextures,
mBumpTextures,
mGlossinessTextures;
//! Index of refraction
float mIOR;
//! Bump intensity scaling
float mBumpIntensity;
};
// ---------------------------------------------------------------------------
#define AI_LWO_VALIDATE_CHUNK_LENGTH(length,name,size) \
if (length < size) \
{ \
DefaultLogger::get()->warn("LWO: "#name" chunk is too small"); \
break; \
throw new ImportErrorException("LWO: "#name" chunk is too small"); \
} \
@ -413,6 +571,7 @@ typedef std::vector < LWO::Face > FaceList;
typedef std::vector < LWO::Surface > SurfaceList;
typedef std::vector < std::string > TagList;
typedef std::vector < unsigned int > TagMappingTable;
typedef std::vector < unsigned int > ReferrerList;
typedef std::vector < WeightChannel > WeightChannelList;
typedef std::vector < VColorChannel > VColorChannelList;
typedef std::vector < UVChannel > UVChannelList;
@ -433,6 +592,11 @@ struct Layer
/** Temporary point list from the file */
PointList mTempPoints;
/** Lists for every point the index of another point
that has been copied from *this* point or 0xffffffff if
no copy of the point has been made */
ReferrerList mPointReferrers;
/** Weight channel list from the file */
WeightChannelList mWeightChannels;
@ -456,6 +620,9 @@ struct Layer
/** Name of the layer */
std::string mName;
/** Pivot point of the layer */
aiVector3D mPivot;
};
typedef std::list<LWO::Layer> LayerList;

View File

@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "LWOLoader.h"
#include "MaterialSystem.h"
#include "StringComparison.h"
#include "SGSpatialSort.h"
#include "ByteSwap.h"
// public assimp headers
@ -52,11 +53,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../include/IOSystem.h"
#include "../include/aiScene.h"
#include "../include/aiAssert.h"
#include "../include/DefaultLogger.h"
#include "../include/assimp.hpp"
// boost headers
#include <boost/scoped_ptr.hpp>
#include <sstream>
#include <iomanip>
using namespace Assimp;
@ -91,12 +93,14 @@ bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
return true;
}
// ------------------------------------------------------------------------------------------------
// Setup configuration properties
void LWOImporter::SetupProperties(const Importer* pImp)
{
// -- no configuration options at the moment
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void LWOImporter::InternReadFile( const std::string& pFile,
@ -166,7 +170,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
szBuff[3] = (char)(fileType);
throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff);
}
// now, as we have loaded all data, we can resolve cross-referenced tags and clips
ResolveTags();
ResolveClips();
// now process all layers and build meshes and nodes
std::vector<aiMesh*> apcMeshes;
@ -176,10 +183,10 @@ void LWOImporter::InternReadFile( const std::string& pFile,
unsigned int iDefaultSurface = 0xffffffff; // index of the default surface
for (LayerList::const_iterator lit = mLayers->begin(), lend = mLayers->end();
for (LayerList::iterator lit = mLayers->begin(), lend = mLayers->end();
lit != lend;++lit)
{
const LWO::Layer& layer = *lit;
LWO::Layer& layer = *lit;
// I don't know whether there could be dummy layers, but it would be possible
const unsigned int meshStart = (unsigned int)apcMeshes.size();
@ -190,7 +197,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
std::vector<SortedRep> pSorted(mSurfaces->size()+1);
unsigned int i = 0;
for (FaceList::const_iterator it = layer.mFaces.begin(), end = layer.mFaces.end();
for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end();
it != end;++it,++i)
{
unsigned int idx = (*it).surfaceIndex;
@ -232,8 +239,9 @@ void LWOImporter::InternReadFile( const std::string& pFile,
apcMeshes.push_back(mesh);
mesh->mNumFaces = (unsigned int)sorted.size();
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
it != end;++it)
// count the number of vertices
SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
for (;it != end;++it)
{
mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
}
@ -275,31 +283,45 @@ void LWOImporter::InternReadFile( const std::string& pFile,
pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices];
}
// we would not need this extra array, but the code is much cleaner if we use it
// FIX: we can use the referrer ID array here. invalidate its contents
// before we resize it to avoid a unnecessary memcpy
std::vector<unsigned int>& smoothingGroups = layer.mPointReferrers;
smoothingGroups.erase (smoothingGroups.begin(),smoothingGroups.end());
smoothingGroups.resize(mesh->mNumFaces,0);
// now convert all faces
unsigned int vert = 0;
for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
it != end;++it)
std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
for (it = sorted.begin(); it != end;++it,++outIt)
{
const LWO::Face& face = layer.mFaces[*it];
*outIt = face.smoothGroup;
// copy all vertices
for (unsigned int q = 0; q < face.mNumIndices;++q)
{
register unsigned int idx = face.mIndices[q];
*pv++ = layer.mTempPoints[idx];
*pv = layer.mTempPoints[idx] + layer.mPivot;
pv->z *= -1.0f; // DX to OGL
pv++;
// process UV coordinates
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w)
{
if (0xffffffff == vUVChannelIndices[w])break;
*(pvUV[w])++ = layer.mUVChannels[vUVChannelIndices[w]].data[idx];
aiVector3D*& pp = pvUV[w];
const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
pp->x = src.x;
pp->y = 1.0f - src.y; // DX to OGL
pp++;
}
// process vertex colors
for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w)
{
if (0xffffffff == vVColorIndices[w])break;
*(pvVC[w])++ = layer.mVColorChannels[vVColorIndices[w]].data[idx];
*(pvVC[w])++ = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
}
#if 0
@ -308,14 +330,20 @@ void LWOImporter::InternReadFile( const std::string& pFile,
{
}
#endif
face.mIndices[q] = vert++;
face.mIndices[q] = vert + (face.mNumIndices-q-1);
}
vert += face.mNumIndices;
pf->mIndices = face.mIndices;
pf->mNumIndices = face.mNumIndices;
unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // make sure it won't be deleted
pf++;
}
// compute normal vectors for the mesh - we can't use our GenSmoothNormal-Step here
// since it wouldn't handle smoothing groups correctly
ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
++p;
}
}
@ -352,11 +380,103 @@ void LWOImporter::InternReadFile( const std::string& pFile,
GenerateNodeGraph(apcNodes);
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>& smoothingGroups,
const LWO::Surface& surface)
{
// allocate output storage
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
// First generate per-face normals
aiVector3D* out;
std::vector<aiVector3D> faceNormals;
if (!surface.mMaximumSmoothAngle)
out = mesh->mNormals;
else
{
faceNormals.resize(mesh->mNumVertices);
out = &faceNormals[0];
}
aiFace* begin = mesh->mFaces, *const end = mesh->mFaces+mesh->mNumFaces;
for (; begin != end; ++begin)
{
aiFace& face = *begin;
// LWO doc: "the normal is defined as the cross product of the first and last edges"
aiVector3D* pV1 = mesh->mVertices + face.mIndices[0];
aiVector3D* pV2 = mesh->mVertices + face.mIndices[1];
aiVector3D* pV3 = mesh->mVertices + face.mIndices[face.mNumIndices-1];
aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize();
for (unsigned int i = 0; i < face.mNumIndices;++i)
out[face.mIndices[i]] = vNor;
}
if (!surface.mMaximumSmoothAngle)return;
// calculate the position bounds so we have a reliable epsilon to
// check position differences against
aiVector3D minVec( 1e10f, 1e10f, 1e10f), maxVec( -1e10f, -1e10f, -1e10f);
for( unsigned int a = 0; a < mesh->mNumVertices; a++)
{
minVec.x = std::min( minVec.x, mesh->mVertices[a].x);
minVec.y = std::min( minVec.y, mesh->mVertices[a].y);
minVec.z = std::min( minVec.z, mesh->mVertices[a].z);
maxVec.x = std::max( maxVec.x, mesh->mVertices[a].x);
maxVec.y = std::max( maxVec.y, mesh->mVertices[a].y);
maxVec.z = std::max( maxVec.z, mesh->mVertices[a].z);
}
const float posEpsilon = (maxVec - minVec).Length() * 1e-5f;
// now generate the spatial sort tree
SGSpatialSort sSort;
std::vector<unsigned int>::const_iterator it = smoothingGroups.begin();
for( begin = mesh->mFaces; begin != end; ++begin, ++it)
{
aiFace& face = *begin;
for (unsigned int i = 0; i < face.mNumIndices;++i)
{
register unsigned int tt = face.mIndices[i];
sSort.Add(mesh->mVertices[tt],tt,*it);
}
}
// sort everything - this takes O(logn) time
sSort.Prepare();
std::vector<unsigned int> poResult;poResult.reserve(20);
const float fLimit = cos(surface.mMaximumSmoothAngle);
// generate vertex normals. We have O(logn) for the binary lookup, which we need
// for n elements, thus the EXPECTED complexity is O(nlogn)
for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it)
{
register unsigned int sg = *it;
aiFace& face = *begin;
unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
for (; beginIdx != endIdx; ++beginIdx)
{
sSort.FindPositions(mesh->mVertices[*beginIdx],sg,posEpsilon,poResult,true);
aiVector3D vNormals;
for (std::vector<unsigned int>::const_iterator
a = poResult.begin(), end = poResult.end();
a != end;++a)
{
const aiVector3D& v = faceNormals[*a];
if (v * faceNormals[*beginIdx] < fLimit)continue;
vNormals += v;
}
vNormals.Normalize();
mesh->mNormals[*beginIdx] = vNormals;
}
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::AddChildren(aiNode* node, uintptr_t parent, std::vector<aiNode*>& apcNodes)
{
unsigned int numChilds = 0;
for (uintptr_t i = 0; i < (uintptr_t)apcNodes.size();++i)
{
if (i == parent)continue;
@ -454,57 +574,50 @@ void LWOImporter::ResolveTags()
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::ParseString(std::string& out,unsigned int max)
void LWOImporter::ResolveClips()
{
// --- this function is used for both LWO2 and LWOB
unsigned int iCursor = 0;
const char* in = (const char*)mFileBuffer,*sz = in;
while (*in)
for( unsigned int i = 0; i < mClips.size();++i)
{
if (++iCursor > max)
Clip& clip = mClips[i];
if (Clip::REF == clip.type)
{
DefaultLogger::get()->warn("LWOB: Invalid file, string is is too long");
break;
if (clip.clipRef >= mClips.size())
{
DefaultLogger::get()->error("LWO2: Clip referrer index is out of range");
clip.clipRef = 0;
}
Clip& dest = mClips[clip.clipRef];
if (Clip::REF == dest.type)
{
DefaultLogger::get()->error("LWO2: Clip references another clip reference");
clip.type = Clip::UNSUPPORTED;
}
else
{
clip.path = dest.path;
clip.type = dest.type;
}
}
++in;
}
unsigned int len = (unsigned int) (in-sz);
out = std::string(sz,len);
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::AdjustTexturePath(std::string& out)
{
// --- this function is used for both LWO2 and LWOB
if (::strstr(out.c_str(), "(sequence)"))
if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)"))
{
// remove the (sequence) and append 000
DefaultLogger::get()->info("LWO: Sequence of animated texture found. It will be ignored");
DefaultLogger::get()->info("LWOB: Sequence of animated texture found. It will be ignored");
out = out.substr(0,out.length()-10) + "000";
}
}
// ------------------------------------------------------------------------------------------------
int LWOImporter::ReadVSizedIntLWO2(uint8_t*& inout)
{
int i;
int c = *inout;inout++;
if(c != 0xFF)
// format: drive:path/file - we need to insert a slash after the drive
std::string::size_type n = out.find_first_of(':');
if (std::string::npos != n)
{
i = c << 8;
c = *inout;inout++;
i |= c;
out.insert(n+1,"/");
}
else
{
c = *inout;inout++;
i = c << 16;
c = *inout;inout++;
i |= c << 8;
c = *inout;inout++;
i |= c;
}
return i;
}
// ------------------------------------------------------------------------------------------------
@ -530,8 +643,20 @@ void LWOImporter::LoadLWOTags(unsigned int size)
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWOPoints(unsigned int length)
{
// --- this function is used for both LWO2 and LWOB
mCurLayer->mTempPoints.resize( length / 12 );
// --- this function is used for both LWO2 and LWOB but for
// LWO2 we need to allocate 25% more storage - it could be we'll
// need to duplicate some points later.
register unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
if (mIsLWO2)
{
mCurLayer->mTempPoints.reserve ( regularSize + (regularSize>>2u) );
mCurLayer->mTempPoints.resize ( regularSize );
// initialize all point referrers with the default values
mCurLayer->mPointReferrers.reserve ( regularSize + (regularSize>>2u) );
mCurLayer->mPointReferrers.resize ( regularSize, 0xffffffff );
}
else mCurLayer->mTempPoints.resize( regularSize );
// perform endianess conversions
#ifndef AI_BUILD_BIG_ENDIAN
@ -544,17 +669,16 @@ void LWOImporter::LoadLWOPoints(unsigned int length)
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2Polygons(unsigned int length)
{
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer += 4;length-=4;
AI_LSWAP4(type);
LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
uint32_t type = GetU4();
if (type != AI_LWO_FACE)
{
DefaultLogger::get()->warn("LWO2: Only POLS.FACE chunsk are supported.");
DefaultLogger::get()->warn("LWO2: Only POLS.FACE chunks are supported.");
return;
}
// first find out how many faces and vertices we'll finally need
LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer;
unsigned int iNumFaces = 0,iNumVertices = 0;
@ -616,21 +740,22 @@ void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it,
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
{
uint32_t type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
AI_LSWAP4(type);
LE_NCONST uint8_t* const end = mFileBuffer+length;
AI_LWO_VALIDATE_CHUNK_LENGTH(length,PTAG,4);
uint32_t type = GetU4();
if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
return;
LE_NCONST uint8_t* const end = mFileBuffer+length;
while (mFileBuffer <= end)
while (mFileBuffer < end)
{
unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
unsigned int j = ReadVSizedIntLWO2(mFileBuffer);
unsigned int j = GetU2();
if (i >= mCurLayer->mFaces.size())
{
DefaultLogger::get()->warn("LWO2: face index in ptag list is out of range");
DefaultLogger::get()->warn("LWO2: face index in PTAG is out of range");
continue;
}
@ -646,14 +771,88 @@ void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
}
}
// ------------------------------------------------------------------------------------------------
template <class T>
VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPoly)
{
for (typename std::vector< T >::iterator it = list.begin(), end = list.end();
it != end; ++it)
{
if ((*it).name == name)
{
if (!perPoly)
{
DefaultLogger::get()->warn("LWO2: Found two VMAP sections with equal names");
}
return &(*it);
}
}
list.push_back( T() );
VMapEntry* p = &list.back();
p->name = name;
return p;
}
// ------------------------------------------------------------------------------------------------
template <class T>
void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx)
{
for (typename std::vector< T >::iterator
it = list.begin(), end = list.end();
it != end;++it)
{
T& chan = *it;
for (unsigned int a = 0; a < chan.dims;++a)
{
chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]);
chan.abAssigned[srcIdx] = true;
chan.abAssigned.resize(chan.abAssigned.size()+1,false);
}
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int numRead,
unsigned int idx, float* data)
{
ai_assert(NULL != data);
LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
unsigned int i;
base->abAssigned[idx] = true;
for (i = 0; i < numRead;++i)
base->rawData[idx*base->dims+i]= data[i];
if (0xffffffff != (i = refList[idx]))
DoRecursiveVMAPAssignment(base,numRead,i,data);
}
// ------------------------------------------------------------------------------------------------
void AddToSingleLinkedList(ReferrerList& refList, unsigned int srcIdx, unsigned int destIdx)
{
if(0xffffffff == refList[srcIdx])
{
refList[srcIdx] = destIdx;
return;
}
AddToSingleLinkedList(refList,refList[srcIdx],destIdx);
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
{
unsigned int type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
unsigned int dims = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2;
LE_NCONST uint8_t* const end = mFileBuffer+length;
AI_LWO_VALIDATE_CHUNK_LENGTH(length,VMAP,6);
unsigned int type = GetU4();
unsigned int dims = GetU2();
VMapEntry* base;
// read the name of the vertex map
std::string name;
GetS0(name,length);
switch (type)
{
case AI_LWO_TXUV:
@ -661,51 +860,139 @@ void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
{
DefaultLogger::get()->warn("LWO2: Found UV channel with != 2 components");
}
mCurLayer->mUVChannels.push_back(UVChannel((unsigned int)mCurLayer->mTempPoints.size()));
base = &mCurLayer->mUVChannels.back();
base = FindEntry(mCurLayer->mUVChannels,name,perPoly);
break;
case AI_LWO_WGHT:
if (dims != 1)
{
DefaultLogger::get()->warn("LWO2: found vertex weight map with != 1 components");
}
mCurLayer->mWeightChannels.push_back(WeightChannel((unsigned int)mCurLayer->mTempPoints.size()));
base = &mCurLayer->mWeightChannels.back();
base = FindEntry(mCurLayer->mWeightChannels,name,perPoly);
break;
case AI_LWO_RGB:
case AI_LWO_RGBA:
if (dims != 3 && dims != 4)
{
DefaultLogger::get()->warn("LWO2: found vertex color map with != 3&4 components");
}
mCurLayer->mVColorChannels.push_back(VColorChannel((unsigned int)mCurLayer->mTempPoints.size()));
base = &mCurLayer->mVColorChannels.back();
base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
break;
default: return;
};
// read the name of the vertex map
ParseString(base->name,length);
base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
// now read all entries in the map
type = std::min(dims,base->dims);
const unsigned int diff = (dims - type)<<2;
LE_NCONST uint8_t* const end = mFileBuffer+length;
LWO::FaceList& list = mCurLayer->mFaces;
LWO::PointList& pointList = mCurLayer->mTempPoints;
LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
float temp[4];
while (mFileBuffer < end)
{
unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs;
if (idx > mCurLayer->mTempPoints.size())
if (idx >= pointList.size())
{
DefaultLogger::get()->warn("LWO2: vertex index in vmap/vmad is out of range");
continue;
mFileBuffer += base->dims*4;continue;
}
for (unsigned int i = 0; i < type;++i)
if (perPoly)
{
base->rawData[idx*dims+i]= *((float*)mFileBuffer);
mFileBuffer += 4;
unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
if (base->abAssigned[idx])
{
// we have already a VMAP entry for this vertex - thus
// we need to duplicate the corresponding polygon.
if (polyIdx >= list.size())
{
DefaultLogger::get()->warn("LWO2: VMAD polygon index is out of range");
mFileBuffer += base->dims*4;continue;
}
LWO::Face& src = list[polyIdx];
// generate new vertex positions
for (unsigned int i = 0; i < src.mNumIndices;++i)
{
register unsigned int srcIdx = src.mIndices[i];
// store the index of the new vertex in the old vertex
// so we get a single linked list we can traverse in
// only one direction
refList.push_back(0xffffffff);
AddToSingleLinkedList(refList,srcIdx,(src.mIndices[i] = (unsigned int)pointList.size()));
pointList.push_back(pointList[srcIdx]);
CreateNewEntry(mCurLayer->mVColorChannels, srcIdx );
CreateNewEntry(mCurLayer->mUVChannels, srcIdx );
CreateNewEntry(mCurLayer->mWeightChannels, srcIdx );
}
}
}
for (unsigned int l = 0; l < type;++l)
temp[l] = GetF4();
DoRecursiveVMAPAssignment(base,type,idx, temp);
mFileBuffer += diff;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2Clip(unsigned int length)
{
AI_LWO_VALIDATE_CHUNK_LENGTH(length,CLIP,10);
mClips.push_back(LWO::Clip());
LWO::Clip& clip = mClips.back();
// first - get the index of the clip
clip.idx = GetU4();
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
switch (head->type)
{
case AI_LWO_STIL:
GetS0(clip.path,head->length);
clip.type = Clip::STILL;
break;
case AI_LWO_ISEQ:
{
uint8_t digits = GetU1(); mFileBuffer++;
int16_t offset = GetU2(); mFileBuffer+=4;
int16_t start = GetU2(); mFileBuffer+=4;
std::string s;std::stringstream ss;
GetS0(s,head->length);head->length -= (unsigned int)s.length()+1;
ss << s;
ss << std::setw(digits) << offset + start;
GetS0(s,head->length);
ss << s;
clip.path = ss.str();
clip.type = Clip::SEQ;
}
break;
case AI_LWO_STCC:
DefaultLogger::get()->warn("LWO2: Color shifted images are not supported");
break;
case AI_LWO_ANIM:
DefaultLogger::get()->warn("LWO2: Animated textures are not supported");
break;
case AI_LWO_XREF:
clip.type = Clip::REF;
clip.clipRef = GetU4();
break;
default:
DefaultLogger::get()->warn("LWO2: Encountered unknown CLIP subchunk");
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2File()
@ -714,14 +1001,11 @@ void LWOImporter::LoadLWO2File()
while (true)
{
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
LE_NCONST IFF::ChunkHeader* const head = (LE_NCONST IFF::ChunkHeader*)mFileBuffer;
AI_LSWAP4(head->length);
AI_LSWAP4(head->type);
mFileBuffer += sizeof(IFF::ChunkHeader);
LE_NCONST IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
if (mFileBuffer + head->length > end)
{
throw new ImportErrorException("LWOB: Invalid file, the size attribute of "
"a chunk points behind the end of the file");
throw new ImportErrorException("LWO2: Chunk length points behind the file");
break;
}
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
@ -738,9 +1022,13 @@ void LWOImporter::LoadLWO2File()
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
// and parse its properties
mFileBuffer += 16;
ParseString(layer.mName,head->length-16);
// and parse its properties, e.g. the pivot point
mFileBuffer += 2;
mCurLayer->mPivot.x = GetF4();
mCurLayer->mPivot.y = GetF4();
mCurLayer->mPivot.z = GetF4();
mFileBuffer += 2;
GetS0(layer.mName,head->length-16);
// if the name is empty, generate a default name
if (layer.mName.empty())
@ -751,7 +1039,7 @@ void LWOImporter::LoadLWO2File()
}
if (mFileBuffer + 2 <= next)
layer.mParent = *((uint16_t*)mFileBuffer);
layer.mParent = GetU2();
break;
}
@ -765,11 +1053,17 @@ void LWOImporter::LoadLWO2File()
break;
}
// vertex tags
//case AI_LWO_VMAD:
case AI_LWO_VMAD:
if (mCurLayer->mFaces.empty())
{
DefaultLogger::get()->warn("LWO2: Unexpected VMAD chunk");
break;
}
// --- intentionally no break here
case AI_LWO_VMAP:
{
if (mCurLayer->mTempPoints.empty())
DefaultLogger::get()->warn("LWO2: Unexpected VMAD/VMAP chunk");
DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
break;
}
@ -804,6 +1098,13 @@ void LWOImporter::LoadLWO2File()
LoadLWO2Surface(head->length);
break;
}
// clip chunk
case AI_LWO_CLIP:
{
LoadLWO2Clip(head->length);
break;
}
}
mFileBuffer = next;
}

View File

@ -43,9 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_LWOLOADER_H_INCLUDED
#include "../include/aiTypes.h"
#include "../include/DefaultLogger.h"
#include "BaseImporter.h"
#include "LWOFileData.h"
#include "BaseImporter.h"
#include "MaterialSystem.h"
struct aiTexture;
@ -63,6 +64,7 @@ using namespace LWO;
* Methods named "xxx" are used to preprocess the loaded data -
* they aren't specific to one format version, either
*/
// ---------------------------------------------------------------------------
class LWOImporter : public BaseImporter
{
friend class Importer;
@ -120,6 +122,17 @@ private:
*/
void LoadLWO2File();
// -------------------------------------------------------------------
/** Parsing functions used for all file format versions
*/
inline void GetS0(std::string& out,unsigned int max);
inline float GetF4();
inline uint32_t GetU4();
inline uint16_t GetU2();
inline uint8_t GetU1();
// -------------------------------------------------------------------
/** Loads a surface chunk from an LWOB file
* @param size Maximum size to be read, in bytes.
@ -135,9 +148,18 @@ private:
// -------------------------------------------------------------------
/** Loads a texture block from a LWO2 file.
* @param size Maximum size to be read, in bytes.
* @param type Type of the texture block - PROC, GRAD or IMAP
* @param head Header of the SUF.BLOK header
*/
void LoadLWO2TextureBlock(uint32_t type, unsigned int size );
void LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader* head,
unsigned int size );
// -------------------------------------------------------------------
/** Loads a shader block from a LWO2 file.
* @param size Maximum size to be read, in bytes.
* @param head Header of the SUF.BLOK header
*/
void LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* head,
unsigned int size );
// -------------------------------------------------------------------
/** Loads an image map from a LWO2 file
@ -183,6 +205,12 @@ private:
*/
void LoadLWOPoints(unsigned int length);
// -------------------------------------------------------------------
/** Load a clip from a CLIP chunk
* @param length Size of the chunk
*/
void LoadLWO2Clip(unsigned int length);
// -------------------------------------------------------------------
/** Count vertices and faces in a LWOB/LWO2 file
@ -206,6 +234,7 @@ private:
LE_NCONST uint16_t*& cursor,
const uint16_t* const end);
// -------------------------------------------------------------------
void CopyFaceIndicesLWOB(LWO::FaceList::iterator& it,
LE_NCONST uint16_t*& cursor,
const uint16_t* const end,
@ -213,14 +242,27 @@ private:
// -------------------------------------------------------------------
/** Resolve the tag and surface lists that have been loaded.
* Generates the mMapping table.
* Generates the mMapping table.
*/
void ResolveTags();
// -------------------------------------------------------------------
/** Parse a string from the current file position
/** Resolve the clip list that has been loaded.
* Replaces clip references with real clips.
*/
void ParseString(std::string& out,unsigned int max);
void ResolveClips();
// -------------------------------------------------------------------
/** Add a texture list to an output material description.
*
* @param pcMat Output material
* @param in Input texture list
* @param type Type identifier of the texture list. This is the string
* that appears in the middle of all material keys - e.g. "diffuse",
* "shininess", "glossiness" or "specular".
*/
bool HandleTextures(MaterialHelper* pcMat, const TextureList& in,
const char* type);
// -------------------------------------------------------------------
/** Adjust a texture path
@ -241,10 +283,15 @@ private:
* @param out Output list. The members are indices into the
* UV/VC channel lists of the layer
*/
void FindUVChannels(const LWO::Surface& surf,
const LWO::Layer& layer,
void FindUVChannels(/*const*/ LWO::Surface& surf,
/*const*/ LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]);
// -------------------------------------------------------------------
void FindUVChannels(LWO::TextureList& list, LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS], unsigned int& next);
// -------------------------------------------------------------------
void FindVCChannels(const LWO::Surface& surf,
const LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]);
@ -271,6 +318,27 @@ private:
*/
int ReadVSizedIntLWO2(uint8_t*& inout);
// -------------------------------------------------------------------
/** Assign a value from a VMAP to a vertex and all vertices
* attached to it.
* @param base VMAP destination data
* @param numRead Number of float's to be read
* @param idx Absolute index of the first vertex
* @param data Value of the VMAP to be assigned - read numRead
* floats from this array.
*/
void DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int numRead,
unsigned int idx, float* data);
// -------------------------------------------------------------------
/** Compute normal vectors for a mesh
* @param mesh Input mesh
* @param smoothingGroups Smoothing-groups-per-face array
* @param surface Surface for the mesh
*/
void ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>& smoothingGroups,
const LWO::Surface& surface);
protected:
/** true if the file is a LWO2 file*/
@ -305,6 +373,81 @@ protected:
aiScene* pScene;
};
// ------------------------------------------------------------------------------------------------
inline float LWOImporter::GetF4()
{
float f = *((float*)mFileBuffer);mFileBuffer += 4;
AI_LSWAP4(f);
return f;
}
// ------------------------------------------------------------------------------------------------
inline uint32_t LWOImporter::GetU4()
{
uint32_t f = *((uint32_t*)mFileBuffer);mFileBuffer += 4;
AI_LSWAP4(f);
return f;
}
// ------------------------------------------------------------------------------------------------
inline uint16_t LWOImporter::GetU2()
{
uint16_t f = *((uint16_t*)mFileBuffer);mFileBuffer += 2;
AI_LSWAP2(f);
return f;
}
// ------------------------------------------------------------------------------------------------
inline uint8_t LWOImporter::GetU1()
{
return *mFileBuffer++;
}
// ------------------------------------------------------------------------------------------------
inline int LWOImporter::ReadVSizedIntLWO2(uint8_t*& inout)
{
int i;
int c = *inout;inout++;
if(c != 0xFF)
{
i = c << 8;
c = *inout;inout++;
i |= c;
}
else
{
c = *inout;inout++;
i = c << 16;
c = *inout;inout++;
i |= c << 8;
c = *inout;inout++;
i |= c;
}
return i;
}
// ------------------------------------------------------------------------------------------------
inline void LWOImporter::GetS0(std::string& out,unsigned int max)
{
unsigned int iCursor = 0;
const char*sz = (const char*)mFileBuffer;
while (*mFileBuffer)
{
if (++iCursor > max)
{
DefaultLogger::get()->warn("LWO: Invalid file, string is is too long");
break;
}
++mFileBuffer;
}
unsigned int len = (unsigned int) ((const char*)mFileBuffer-sz);
out = std::string(sz,len);
mFileBuffer += (len&0x1 ? 1 : 2);
}
} // end of namespace Assimp
#endif // AI_LWOIMPORTER_H_INCLUDED

View File

@ -58,6 +58,142 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
template <class T>
T lerp(const T& one, const T& two, float val)
{
return one + (two-one)*val;
}
// ------------------------------------------------------------------------------------------------
inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
{
switch (in)
{
case LWO::Texture::REPEAT:
return aiTextureMapMode_Wrap;
case LWO::Texture::MIRROR:
return aiTextureMapMode_Mirror;
case LWO::Texture::RESET:
DefaultLogger::get()->warn("LWO2: Unsupported texture map mode: RESET");
case LWO::Texture::EDGE:
return aiTextureMapMode_Clamp;
}
return (aiTextureMapMode)0;
}
// ------------------------------------------------------------------------------------------------
bool LWOImporter::HandleTextures(MaterialHelper* pcMat, const TextureList& in, const char* type)
{
ai_assert(NULL != pcMat && NULL != type);
unsigned int cur = 0, temp = 0;
char buffer[512];
aiString s;
bool ret = false;
for (TextureList::const_iterator it = in.begin(), end = in.end();
it != end;++it)
{
if (!(*it).enabled || !(*it).bCanUse || 0xffffffff == (*it).mRealUVIndex)continue;
ret = true;
// add the path to the texture
sprintf(buffer,"$tex.file.%s[%i]",type,cur);
// The older LWOB format does not use indirect references to clips.
// The file name of a texture is directly specified in the tex chunk.
if (mIsLWO2)
{
// find the corresponding clip
ClipList::iterator clip = mClips.begin();
temp = (*it).mClipIdx;
for (ClipList::iterator end = mClips.end(); clip != end; ++clip)
{
if ((*clip).idx == temp)
{
break;
}
}
if (mClips.end() == clip)
{
DefaultLogger::get()->error("LWO2: Clip index is out of bounds");
temp = 0;
}
if (Clip::UNSUPPORTED == (*clip).type)
{
DefaultLogger::get()->error("LWO2: Clip type is not supported");
continue;
}
AdjustTexturePath((*clip).path);
s.Set((*clip).path);
}
else
{
std::string ss = (*it).mFileName;
if (!ss.length())
{
DefaultLogger::get()->error("LWOB: Empty file name");
continue;
}
AdjustTexturePath(ss);
s.Set(ss);
}
pcMat->AddProperty(&s,buffer);
// add the blend factor
sprintf(buffer,"$tex.blend.%s[%i]",type,cur);
pcMat->AddProperty(&(*it).mStrength,1,buffer);
// add the blend operation
sprintf(buffer,"$tex.op.%s[%i]",type,cur);
switch ((*it).blendType)
{
case LWO::Texture::Normal:
case LWO::Texture::Multiply:
temp = (unsigned int)aiTextureOp_Multiply;
break;
case LWO::Texture::Subtractive:
case LWO::Texture::Difference:
temp = (unsigned int)aiTextureOp_Subtract;
break;
case LWO::Texture::Divide:
temp = (unsigned int)aiTextureOp_Divide;
break;
case LWO::Texture::Additive:
temp = (unsigned int)aiTextureOp_Add;
break;
default:
temp = (unsigned int)aiTextureOp_Multiply;
DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement");
}
pcMat->AddProperty<int>((int*)&temp,1,buffer);
// add the UV source index
sprintf(buffer,"$tex.uvw.%s[%i]",type,cur);
temp = (*it).mRealUVIndex;
pcMat->AddProperty<int>((int*)&temp,1,buffer);
// add the u-wrapping
sprintf(buffer,"$tex.mapmodeu.%s[%i]",type,cur);
temp = (unsigned int)GetMapMode((*it).wrapModeWidth);
pcMat->AddProperty<int>((int*)&temp,1,buffer);
// add the v-wrapping
sprintf(buffer,"$tex.mapmodev.%s[%i]",type,cur);
temp = (unsigned int)GetMapMode((*it).wrapModeHeight);
pcMat->AddProperty<int>((int*)&temp,1,buffer);
++cur;
}
return ret;
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat)
{
@ -69,12 +205,18 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
int i = surf.bDoubleSided ? 1 : 0;
pcMat->AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED);
// add the refraction index and the bump intensity
pcMat->AddProperty<float>(&surf.mIOR,1,AI_MATKEY_REFRACTI);
pcMat->AddProperty<float>(&surf.mBumpIntensity,1,AI_MATKEY_BUMPSCALING);
aiShadingMode m;
if (surf.mSpecularValue && surf.mGlossiness)
{
// this is only an assumption, needs to be confirmed.
// the values have been tweaked by hand and seem to be correct.
float fGloss;
if (mIsLWO2)fGloss = surf.mGlossiness * 50.0f;
if (mIsLWO2)
{
fGloss = pow( surf.mGlossiness*10.0f+2.0f, 2.0f);
}
else
{
if (16.0f >= surf.mGlossiness)fGloss = 6.0f;
@ -85,18 +227,14 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
pcMat->AddProperty<float>(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
pcMat->AddProperty<float>(&fGloss,1,AI_MATKEY_SHININESS);
m = aiShadingMode_Phong;
}
// (the diffuse value is just a scaling factor)
aiColor3D clr = surf.mColor;
clr.r *= surf.mDiffuseValue;
clr.g *= surf.mDiffuseValue;
clr.b *= surf.mDiffuseValue;
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
else m = aiShadingMode_Gouraud;
// specular color
clr.b = clr.g = clr.r = surf.mSpecularValue;
aiColor3D clr = lerp( aiColor3D(1.f,1.f,1.f), surf.mColor, surf.mColorHighlights );
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_SPECULAR);
pcMat->AddProperty<float>(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
// emissive color
// (luminosity is not really the same but it affects the surface in
@ -108,15 +246,113 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,MaterialHelper* pcMat
float f = 1.0f-surf.mTransparency;
pcMat->AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
// now handle all textures ...
// TODO
// ADD TEXTURES to the material
// TODO: find out how we can handle COLOR textures correctly...
bool b = HandleTextures(pcMat,surf.mColorTextures,"diffuse");
b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,"diffuse"));
HandleTextures(pcMat,surf.mSpecularTextures,"specular");
HandleTextures(pcMat,surf.mGlossinessTextures,"shininess");
HandleTextures(pcMat,surf.mBumpTextures,"height");
HandleTextures(pcMat,surf.mOpacityTextures,"opacity");
// now we need to know which shader we must use
// iterate through the shader list of the surface and
// search for a name we know
for (ShaderList::const_iterator it = surf.mShaders.begin(), end = surf.mShaders.end();
it != end;++it)
{
if (!(*it).enabled)continue;
if ((*it).functionName == "LW_SuperCelShader" ||
(*it).functionName == "AH_CelShader")
{
m = aiShadingMode_Toon;
break;
}
else if ((*it).functionName == "LW_RealFresnel" ||
(*it).functionName == "LW_FastFresnel")
{
m = aiShadingMode_Fresnel;
break;
}
else
{
DefaultLogger::get()->warn("LWO2: Unknown surface shader: " + (*it).functionName);
}
}
if (surf.mMaximumSmoothAngle <= 0.0f)m = aiShadingMode_Flat;
pcMat->AddProperty((int*)&m,1,AI_MATKEY_SHADING_MODEL);
// (the diffuse value is just a scaling factor)
// If a diffuse texture is set, we set this value to 1.0
clr = (b ? aiColor3D(1.f,1.f,1.f) : surf.mColor);
clr.r *= surf.mDiffuseValue;
clr.g *= surf.mDiffuseValue;
clr.b *= surf.mDiffuseValue;
pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::FindUVChannels(const LWO::Surface& surf, const LWO::Layer& layer,
void LWOImporter::FindUVChannels(LWO::TextureList& list, LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS], unsigned int& next)
{
for (TextureList::iterator it = list.begin(), end = list.end();
it != end;++it)
{
if (!(*it).enabled || !(*it).bCanUse || 0xffffffff != (*it).mRealUVIndex)continue;
switch ((*it).mapMode)
{
// TODO: implement these special mappings ...
case LWO::Texture::Spherical:
case LWO::Texture::Cylindrical:
case LWO::Texture::Cubic:
case LWO::Texture::Planar:
case LWO::Texture::FrontProjection:
DefaultLogger::get()->warn("LWO2: Only UV mapping is currently supported.");
continue;
default: ;
}
for (unsigned int i = 0; i < layer.mUVChannels.size();++i)
{
if ((*it).mUVChannelIndex == layer.mUVChannels[i].name)
{
// check whether we have this channel already
for (unsigned int m = 0; m < next;++m)
{
if (i == out[m])
{
(*it).mRealUVIndex = m;
}
}
if (0xffffffff == (*it).mRealUVIndex)
{
(*it).mRealUVIndex = next;
out[next++] = i;
if (AI_MAX_NUMBER_OF_TEXTURECOORDS != next)
out[next] = 0xffffffff;
break;
}
}
}
if (0xffffffff == (*it).mRealUVIndex)
DefaultLogger::get()->error("LWO2: Unable to find matching UV channel for a texture");
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::FindUVChannels(LWO::Surface& surf, LWO::Layer& layer,
unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS])
{
out[0] = 0xffffffff;
unsigned int next = 0;
FindUVChannels(surf.mColorTextures,layer,out,next);
FindUVChannels(surf.mDiffuseTextures,layer,out,next);
FindUVChannels(surf.mSpecularTextures,layer,out,next);
FindUVChannels(surf.mGlossinessTextures,layer,out,next);
FindUVChannels(surf.mOpacityTextures,layer,out,next);
FindUVChannels(surf.mBumpTextures,layer,out,next);
}
// ------------------------------------------------------------------------------------------------
@ -124,41 +360,240 @@ void LWOImporter::FindVCChannels(const LWO::Surface& surf, const LWO::Layer& lay
unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS])
{
out[0] = 0xffffffff;
if (surf.mVCMap.length())
{
for (unsigned int i = 0; i < layer.mVColorChannels.size();++i)
{
if (surf.mVCMap == layer.mVColorChannels[i].name)
{
out[0] = i;
out[1] = 0xffffffff;
return;
}
}
DefaultLogger::get()->warn("LWO2: Unable to find vertex color channel: " + surf.mVCMap);
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
{
//LE_NCONST uint8_t* const end = mFileBuffer + size;
LE_NCONST uint8_t* const end = mFileBuffer + size;
while (true)
{
if (mFileBuffer + 6 >= end)break;
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
if (mFileBuffer + head->length > end)
throw new ImportErrorException("LWO2: Invalid SURF.BLOCK chunk length");
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
switch (head->type)
{
case AI_LWO_PROJ:
tex.wrapModeWidth = (Texture::Wrap)GetU2();
tex.wrapModeHeight = (Texture::Wrap)GetU2();
break;
case AI_LWO_AXIS:
tex.majorAxis = (Texture::Axes)GetU2();
break;
case AI_LWO_IMAG:
tex.mClipIdx = GetU2();
break;
case AI_LWO_VMAP:
GetS0(tex.mUVChannelIndex,head->length);
break;
case AI_LWO_WRPH:
tex.wrapAmountH = GetF4();
break;
case AI_LWO_WRPW:
tex.wrapAmountW = GetF4();
break;
}
mFileBuffer = next;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2Procedural(unsigned int size, LWO::Texture& tex )
{
// --- not supported at the moment
DefaultLogger::get()->error("LWO2: Found procedural texture, this is not supported");
tex.bCanUse = false;
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2Gradient(unsigned int size, LWO::Texture& tex )
{
// --- not supported at the moment
DefaultLogger::get()->error("LWO2: Found gradient texture, this is not supported");
tex.bCanUse = false;
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture& tex )
{
//LE_NCONST uint8_t* const end = mFileBuffer + size;
LE_NCONST uint8_t* const end = mFileBuffer + size;
// get the ordinal string
GetS0( tex.ordinal, size);
// we could crash later if this is an empty string ...
if (!tex.ordinal.length())
{
DefaultLogger::get()->error("LWO2: Ill-formed SURF.BLOK ordinal string");
tex.ordinal = "\x00";
}
while (true)
{
if (mFileBuffer + 6 >= end)break;
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
if (mFileBuffer + head->length > end)
throw new ImportErrorException("LWO2: Invalid texture header chunk length");
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
switch (head->type)
{
case AI_LWO_CHAN:
tex.type = GetU4();
break;
case AI_LWO_ENAB:
tex.enabled = GetU2() ? true : false;
break;
case AI_LWO_OPAC:
tex.blendType = (Texture::BlendType)GetU2();
tex.mStrength = GetF4();
break;
}
mFileBuffer = next;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2TextureBlock(uint32_t type, unsigned int size )
void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader* head, unsigned int size )
{
//LE_NCONST uint8_t* const end = mFileBuffer + size;
ai_assert(!mSurfaces->empty());
LWO::Surface& surf = mSurfaces->back();
LWO::Texture tex;
//LWO::Surface& surf = mSurfaces->back();
//LWO::Texture tex;
// load the texture header
LoadLWO2TextureHeader(head->length,tex);
size -= head->length + 6;
// now get the exact type of the texture
switch (head->type)
{
case AI_LWO_PROC:
LoadLWO2Procedural(size,tex);
break;
case AI_LWO_GRAD:
LoadLWO2Gradient(size,tex);
break;
case AI_LWO_IMAP:
LoadLWO2ImageMap(size,tex);
}
// get the destination channel
TextureList* listRef = NULL;
switch (tex.type)
{
case AI_LWO_COLR:
listRef = &surf.mColorTextures;break;
case AI_LWO_DIFF:
listRef = &surf.mDiffuseTextures;break;
case AI_LWO_SPEC:
listRef = &surf.mSpecularTextures;break;
case AI_LWO_GLOS:
listRef = &surf.mGlossinessTextures;break;
case AI_LWO_BUMP:
listRef = &surf.mBumpTextures;break;
case AI_LWO_TRAN:
listRef = &surf.mOpacityTextures;break;
default:
DefaultLogger::get()->warn("LWO2: Encountered unknown texture type");
return;
}
// now attach the texture to the parent surface - sort by ordinal string
for (TextureList::iterator it = listRef->begin();
it != listRef->end(); ++it)
{
if (::strcmp(tex.ordinal.c_str(),(*it).ordinal.c_str()) < 0)
{
listRef->insert(it,tex);
return;
}
}
listRef->push_back(tex);
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* head, unsigned int size )
{
LE_NCONST uint8_t* const end = mFileBuffer + size;
ai_assert(!mSurfaces->empty());
LWO::Surface& surf = mSurfaces->back();
LWO::Shader shader;
// get the ordinal string
GetS0( shader.ordinal, size);
// we could crash later if this is an empty string ...
if (!shader.ordinal.length())
{
DefaultLogger::get()->error("LWO2: Ill-formed SURF.BLOK ordinal string");
shader.ordinal = "\x00";
}
// read the header
while (true)
{
if (mFileBuffer + 6 >= end)break;
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
if (mFileBuffer + head->length > end)
throw new ImportErrorException("LWO2: Invalid shader header chunk length");
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
switch (head->type)
{
case AI_LWO_ENAB:
shader.enabled = GetU2() ? true : false;
}
mFileBuffer = next;
}
// process other subchunks ...
while (true)
{
if (mFileBuffer + 6 >= end)break;
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
if (mFileBuffer + head->length > end)
throw new ImportErrorException("LWO2: Invalid shader data chunk length");
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
switch (head->type)
{
case AI_LWO_FUNC:
GetS0( shader.functionName, head->length );
}
mFileBuffer = next;
}
// now attach the shader to the parent surface - sort by ordinal string
for (ShaderList::iterator it = surf.mShaders.begin();
it != surf.mShaders.end(); ++it)
{
if (::strcmp(shader.ordinal.c_str(),(*it).ordinal.c_str()) < 0)
{
surf.mShaders.insert(it,shader);
return;
}
}
surf.mShaders.push_back(shader);
}
// ------------------------------------------------------------------------------------------------
@ -169,88 +604,131 @@ void LWOImporter::LoadLWO2Surface(unsigned int size)
mSurfaces->push_back( LWO::Surface () );
LWO::Surface& surf = mSurfaces->back();
ParseString(surf.mName,size);
mFileBuffer+=surf.mName.length()+1;
// skip one byte if the length of the surface name is odd
if (!(surf.mName.length() & 1))++mFileBuffer;
mFileBuffer += 2;
GetS0(surf.mName,size);
// check whether this surface was derived from any other surface
std::string derived;
GetS0(derived,(unsigned int)(end - mFileBuffer));
if (derived.length())
{
// yes, find this surface
for (SurfaceList::iterator it = mSurfaces->begin(), end = mSurfaces->end()-1;
it != end; ++it)
{
if ((*it).mName == derived)
{
// we have it ...
surf = *it;
derived.clear();
}
}
if (!derived.size())
DefaultLogger::get()->warn("LWO2: Unable to find source surface: " + derived);
}
while (true)
{
if (mFileBuffer + 6 >= end)break;
LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
// no proper IFF header here - the chunk length is specified as int16
uint32_t head_type = *((LE_NCONST uint32_t*)mFileBuffer);mFileBuffer+=4;
uint16_t head_length = *((LE_NCONST uint16_t*)mFileBuffer);mFileBuffer+=2;
AI_LSWAP4(head_type);
AI_LSWAP2(head_length);
if (mFileBuffer + head_length > end)
{
throw new ImportErrorException("LWO2: Invalid file, the size attribute of "
"a surface sub chunk points behind the end of the file");
}
LE_NCONST uint8_t* const next = mFileBuffer+head_length;
switch (head_type)
if (mFileBuffer + head->length > end)
throw new ImportErrorException("LWO2: Invalid surface chunk length");
LE_NCONST uint8_t* const next = mFileBuffer+head->length;
switch (head->type)
{
// diffuse color
case AI_LWO_COLR:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,COLR,12);
surf.mColor.r = ((float*)mFileBuffer)[0];
surf.mColor.g = ((float*)mFileBuffer)[1];
surf.mColor.b = ((float*)mFileBuffer)[2];
AI_LSWAP4(surf.mColor.r);
AI_LSWAP4(surf.mColor.g);
AI_LSWAP4(surf.mColor.b);
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,COLR,12);
surf.mColor.r = GetF4();
surf.mColor.g = GetF4();
surf.mColor.b = GetF4();
break;
}
// diffuse strength ... hopefully
case AI_LWO_DIFF:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,DIFF,4);
surf.mDiffuseValue = *((float*)mFileBuffer);
AI_LSWAP4(surf.mDiffuseValue);
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,DIFF,4);
surf.mDiffuseValue = GetF4();
break;
}
// specular strength ... hopefully
case AI_LWO_SPEC:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,SPEC,4);
surf.mSpecularValue = *((float*)mFileBuffer);
AI_LSWAP4(surf.mSpecularValue);
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPEC,4);
surf.mSpecularValue = GetF4();
break;
}
// transparency
case AI_LWO_TRAN:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,TRAN,4);
surf.mTransparency = *((float*)mFileBuffer);
AI_LSWAP4(surf.mTransparency);
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TRAN,4);
surf.mTransparency = GetF4();
break;
}
// glossiness
case AI_LWO_GLOS:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,GLOS,4);
surf.mGlossiness = *((float*)mFileBuffer);
AI_LSWAP4(surf.mGlossiness);
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,GLOS,4);
surf.mGlossiness = GetF4();
break;
}
// bump intensity
case AI_LWO_BUMP:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,BUMP,4);
surf.mBumpIntensity = GetF4();
break;
}
// color highlights
case AI_LWO_CLRH:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,CLRH,4);
surf.mColorHighlights = GetF4();
break;
}
// index of refraction
case AI_LWO_RIND:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,RIND,4);
surf.mIOR = GetF4();
break;
}
// polygon sidedness
case AI_LWO_SIDE:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SIDE,2);
surf.bDoubleSided = (3 == GetU2());
break;
}
// maximum smoothing angle
case AI_LWO_SMAN:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SMAN,4);
surf.mMaximumSmoothAngle = GetF4();
break;
}
// surface bock entry
case AI_LWO_BLOK:
{
AI_LWO_VALIDATE_CHUNK_LENGTH(head_length,BLOK,4);
uint32_t type = *((uint32_t*)mFileBuffer);
AI_LSWAP4(type);
AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,BLOK,4);
LE_NCONST IFF::SubChunkHeader* head2 = IFF::LoadSubChunk(mFileBuffer);
switch (type)
switch (head2->type)
{
case AI_LWO_IMAP:
case AI_LWO_PROC:
break;
case AI_LWO_GRAD:
mFileBuffer+=4;
LoadLWO2TextureBlock(type,head_length-4);
case AI_LWO_IMAP:
LoadLWO2TextureBlock(head2, head->length);
break;
case AI_LWO_SHDR:
LoadLWO2ShaderBlock(head2, head->length);
break;
default:
DefaultLogger::get()->warn("LWO2: Found an unsupported surface BLOK");
};
break;

View File

@ -226,7 +226,7 @@ void MDRImporter::InternReadFile(
file->Read( &mBuffer2[0], 1, fileSize);
mBuffer = &mBuffer2[0];
// validate the file header
// validate the file header and do BigEndian byte swapping for all sub headers
this->pcHeader = (BE_NCONST MDR::Header*)this->mBuffer;
this->ValidateHeader();
}

View File

@ -83,9 +83,10 @@ void SGSpatialSort::Prepare()
// ------------------------------------------------------------------------------------------------
// Returns an iterator for all positions close to the given position.
void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
uint32_t pSG,
float pRadius,
std::vector<unsigned int>& poResults) const
uint32_t pSG,
float pRadius,
std::vector<unsigned int>& poResults,
bool exactMatch /*= false*/) const
{
float dist = pPosition * mPlaneNormal;
float minDist = dist - pRadius, maxDist = dist + pRadius;
@ -126,17 +127,44 @@ void SGSpatialSort::FindPositions( const aiVector3D& pPosition,
// Add all positions inside the distance range within the given radius to the result aray
float squareEpsilon = pRadius * pRadius;
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
while( it->mDistance < maxDist)
std::vector<Entry>::const_iterator it = mPositions.begin() + index;
std::vector<Entry>::const_iterator end = mPositions.end();
if (exactMatch)
{
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
(it->mSmoothGroups & pSG || 0 == it->mSmoothGroups || 0 == pSG))
while( it->mDistance < maxDist)
{
poResults.push_back( it->mIndex);
if((it->mPosition - pPosition).SquareLength() < squareEpsilon && it->mSmoothGroups == pSG)
{
poResults.push_back( it->mIndex);
}
++it;
if( end == it )break;
}
}
else
{
// if the given smoothing group is 0, we'll return all surrounding vertices
if (!pSG)
{
while( it->mDistance < maxDist)
{
if((it->mPosition - pPosition).SquareLength() < squareEpsilon)
poResults.push_back( it->mIndex);
++it;
if( end == it)break;
}
}
else while( it->mDistance < maxDist)
{
if((it->mPosition - pPosition).SquareLength() < squareEpsilon &&
(it->mSmoothGroups & pSG || !it->mSmoothGroups))
{
poResults.push_back( it->mIndex);
}
++it;
if( end == it)break;
}
++it;
if( it == mPositions.end())
break;
}
}

View File

@ -46,13 +46,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector>
#include "../include/aiTypes.h"
namespace Assimp
{
namespace Assimp {
// ------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
/** Specialized version of SpatialSort to support smoothing groups
* This is used in the .3ds loader
* This is used in by the 3DS, ASE and LWO loaders. 3DS and ASE share their
* normal computation code in SmoothingGroups.inl, the LWO loader has its own
* implementation to handle all details of its file format correctly.
*/
// ----------------------------------------------------------------------------------
class SGSpatialSort
{
public:
@ -60,7 +62,8 @@ public:
SGSpatialSort();
// -------------------------------------------------------------------
/** Construction from a given face array, handling smoothing groups properly
/** Construction from a given face array, handling smoothing groups
* properly
*/
SGSpatialSort(const std::vector<aiVector3D>& vPositions);
@ -74,7 +77,7 @@ public:
unsigned int smoothingGroup);
// -------------------------------------------------------------------
/** Prepare the spatial sorter for use
/** Prepare the spatial sorter for use. This step runs in O(logn)
*/
void Prepare();
@ -85,27 +88,35 @@ public:
/** Returns an iterator for all positions close to the given position.
* @param pPosition The position to look for vertices.
* @param pSG Only included vertices with at least one shared smooth group
* @param pRadius Maximal distance from the position a vertex may have to be counted in.
* @param poResults The container to store the indices of the found positions. Will be emptied
* by the call so it may contain anything.
* @param pRadius Maximal distance from the position a vertex may have
* to be counted in.
* @param poResults The container to store the indices of the found
* positions. Will be emptied by the call so it may contain anything.
* @param exactMatch Specifies whether smoothing groups are bit masks
* (false) or integral values (true). In the latter case, a vertex
* cannot belong to more than one smoothing group.
* @return An iterator to iterate over all vertices in the given area.
*/
// -------------------------------------------------------------------
void FindPositions( const aiVector3D& pPosition, uint32_t pSG,
float pRadius, std::vector<unsigned int>& poResults) const;
float pRadius, std::vector<unsigned int>& poResults,
bool exactMatch = false) const;
protected:
/** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */
aiVector3D mPlaneNormal;
// -------------------------------------------------------------------
/** An entry in a spatially sorted position array. Consists of a vertex index,
* its position and its precalculated distance from the reference plane */
/** An entry in a spatially sorted position array. Consists of a
* vertex index, its position and its precalculated distance from
* the reference plane */
// -------------------------------------------------------------------
struct Entry
{
unsigned int mIndex; ///< The vertex referred by this entry
aiVector3D mPosition; ///< Position
unsigned int mIndex; ///< The vertex referred by this entry
aiVector3D mPosition; ///< Position
uint32_t mSmoothGroups;
float mDistance; ///< Distance of this vertex to the sorting plane
float mDistance; ///< Distance of this vertex to the sorting plane
Entry() { /** intentionally not initialized.*/ }
Entry( unsigned int pIndex, const aiVector3D& pPosition, float pDistance,uint32_t pSG)

View File

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

View File

@ -146,7 +146,7 @@ public:
* @param tess Number of triangles
* @param positions Receives output triangles.
*/
static void MakeCircle(aiVector3D& center, aiVector3D& normal,
static void MakeCircle(const aiVector3D& center, const aiVector3D& normal,
float radius, unsigned int tess,
std::vector<aiVector3D>& positions);

View File

@ -197,7 +197,11 @@ enum aiShadingMode
/** 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
#endif
// supported texture types
#define AI_TEXTYPE_OPACITY 0x0
#define AI_TEXTYPE_SPECULAR 0x1
#define AI_TEXTYPE_AMBIENT 0x2
@ -250,6 +255,7 @@ struct aiMaterialProperty
#define AI_TEXTYPE_NORMALS 0x5
#define AI_TEXTYPE_SHININESS 0x6
#define AI_TEXTYPE_DIFFUSE 0x7
#define AI_TEXTYPE_GLOSSINESS 0x8
// ---------------------------------------------------------------------------
/** Data structure for a material
@ -339,7 +345,7 @@ extern "C" {
// ---------------------------------------------------------------------------
/** @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):
* @code
* int i;
@ -352,10 +358,10 @@ extern "C" {
* @endcode
* However, this is wrong because AI_MATKEY_TEXTURE_DIFFUSE() builds the key
* 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
* 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:
* @code
* int i;
@ -369,8 +375,8 @@ extern "C" {
* }
* @endcode
* @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_)
* @param index Index to be used. Here you may pass a variable!
* normally with an extra underscore as suffix (e.g. AI_MATKEY_TEXTURE_DIFFUSE_)
* @param index Index to be used.
* @param out Array of chars to receive the output value. It must be
* sufficiently large. This will be checked via a static assertion for
* 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"
/** @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
* Defines the diffuse base color of the material
@ -586,8 +602,12 @@ extern "C" {
#define AI_MATKEY_TEXTURE_HEIGHT_ "$tex.file.height"
/** @def AI_MATKEY_TEXTURE_SHININESS
* Defines a specific shininess texture channel of the material
* <br>
* Defines a specific shininess texture channel of the material.
* 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>Default value:</b> none <br>
* @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_ "$tex.file.shininess"
/** @def AI_MATKEY_TEXTURE_OPACITY
* Defines a specific opacity texture channel of the material
* <br>
@ -626,6 +647,7 @@ extern "C" {
* use the macro suffixed with '_' to build the key dynamically. The
* AI_BUILD_KEY()-macro can be used to do this.
*/
// ---------------------------------------------------------------------------
#define AI_MATKEY_TEXOP_DIFFUSE(N) "$tex.op.diffuse["#N"]"
/** @see AI_MATKEY_TEXOP_DIFFUSE */
#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
* AI_BUILD_KEY()-macro can be used to do this.
*/
// ---------------------------------------------------------------------------
#define AI_MATKEY_UVWSRC_DIFFUSE(N) "$tex.uvw.diffuse["#N"]"
/** @see AI_MATKEY_UVWSRC_DIFFUSE */
#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
* AI_BUILD_KEY()-macro can be used to do this.
*/
// ---------------------------------------------------------------------------
#define AI_MATKEY_TEXBLEND_DIFFUSE(N) "$tex.blend.diffuse["#N"]"
/** @see AI_MATKEY_TEXBLEND_DIFFUSE */
#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
* AI_BUILD_KEY()-macro can be used to do this.
*/
// ---------------------------------------------------------------------------
#define AI_MATKEY_MAPPINGMODE_U_DIFFUSE(N) "$tex.mapmodeu.diffuse["#N"]"
/** @see AI_MATKEY_MAPPINGMODE_U_DIFFUSE */
#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
* AI_BUILD_KEY()-macro can be used to do this.
*/
// ---------------------------------------------------------------------------
#define AI_MATKEY_MAPPINGMODE_V_DIFFUSE(N) "$tex.mapmodev.diffuse["#N"]"
/** @see AI_MATKEY_MAPPINGMODE_V_DIFFUSE */
#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
* AI_BUILD_KEY()-macro can be used to do this.
*/
// ---------------------------------------------------------------------------
#define AI_MATKEY_MAPPINGMODE_W_DIFFUSE(N) "$tex.mapmodew.diffuse["#N"]"
/** @see AI_MATKEY_MAPPINGMODE_W_DIFFUSE */
#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_MINNAERT_DARKNESS "$shading.minnaert.darkness"
#define AI_MATKEY_COOK_TORRANCE_REFRACTI "$shading.cookt.refracti"
#define AI_MATKEY_COOK_TORRANCE_PARAM "$shading.cookt.param"
/** @def AI_MATKEY_GLOBAL_BACKGROUND_IMAGE

View File

@ -107,6 +107,16 @@ struct aiColor3D
bool operator != (const aiColor3D& other) const
{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
//! 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
if (0 < pcSrc->mNumBones)
if (pcSrc->mNumBones)
{
// allocate the array
jobjectArray jarr = pc->NewObjectArray(pcSrc->mNumBones,

View File

@ -71,17 +71,17 @@ public class BoneAnim {
/**
* 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
*/
private PropertyList<Integer> properties = new PropertyList<Integer>();
private PropertyList<Float> propertiesFloat = new PropertyList<Float>();
private PropertyList<String> propertiesString = new PropertyList<String>();
private PropertyList<Float> propertiesFloat = new PropertyList<Float>();
private PropertyList<String> propertiesString = new PropertyList<String>();
/**
@ -221,7 +221,7 @@ public class Importer {
* @param iVersion Version of the JNI interface to be used.
* @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
* 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 {
@ -390,12 +390,30 @@ public class Importer {
throw new NativeException("Failed to load the mesh");
}
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;
}
/**
* 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>
*
@ -555,6 +573,10 @@ public class Importer {
}
// *********************************************************************************
// JNI INTERNALS
// *********************************************************************************
/**
* JNI bridge call. For internal use only
* 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;
/**
* 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
@ -80,7 +79,8 @@ public class Material {
/**
* Constructs a new exception
* @param message Error message
*
* @param message Error message
* @param property_key Name of the property that wasn't found
*/
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>
*
* @param key MATKEY_XXX key constant
* @return null if the property wasn't there or hasn't
* the desired output type. The returned <code>Object</code> can be
* casted to the expected data type for the property. Primitive
* types are represented by their boxed variants.
* @return null if the property wasn't there or hasn't
* the desired output type. The returned <code>Object</code> can be
* casted to the expected data type for the property. Primitive
* types are represented by their boxed variants.
*/
public Object getProperty(String key) throws PropertyNotFoundException {
for (Property prop : properties) {
if (prop.key.equals(key)){
for (Property prop : properties) {
if (prop.key.equals(key)) {
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
*
* @param key MATKEY_XXX key constant
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
*/
public float[] getPropertyAsFloatArray(String key) throws PropertyNotFoundException {
@ -121,18 +123,19 @@ public class Material {
return (float[]) obj;
}
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);
throw new PropertyNotFoundException(msg,key);
throw new PropertyNotFoundException(msg, key);
}
/**
/**
* Get a floating-point material property
*
* @param key MATKEY_XXX key constant
* @return The value of the property.
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
*/
public float getPropertyAsFloat(String key) throws PropertyNotFoundException {
@ -141,18 +144,19 @@ public class Material {
return (Float) obj;
}
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);
throw new PropertyNotFoundException(msg,key);
throw new PropertyNotFoundException(msg, key);
}
/**
* Get an integer material property
*
* @param key MATKEY_XXX key constant
* @return The value of the property.
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
*/
public int getPropertyAsInt(String key) throws PropertyNotFoundException {
@ -161,18 +165,19 @@ public class Material {
return (Integer) obj;
}
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);
throw new PropertyNotFoundException(msg,key);
throw new PropertyNotFoundException(msg, key);
}
/**
* Get a material property string
*
* @param key MATKEY_XXX key constant
* @return The value of the property.
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
* @throws PropertyNotFoundException - if the property can't be found
* or if it has the wrong data type.
*/
public String getPropertyAsString(String key) throws PropertyNotFoundException {
@ -181,9 +186,9 @@ public class Material {
return (String) obj;
}
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);
throw new PropertyNotFoundException(msg,key);
throw new PropertyNotFoundException(msg, key);
}
@ -228,7 +233,9 @@ public class Material {
* <br>
* <b>Type:</b> int (TextureOp)<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) {
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
* 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)
* @version 1.0
@ -186,54 +186,58 @@ public class PostProcessStep {
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
* miss ratio) for all meshes. The step runs in O(n) and is roughly
* 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 =
/**
* Reorders triangles for vertex cache locality and thus better performance.
* The step tries to improve the ACMR (average post-transform vertex cache
* miss ratio) for all meshes. The step runs in O(n) and is roughly
* 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 =
new PostProcessStep("ImproveVertexLocality");
/** Searches for redundant materials and removes them.
*
* This is especially useful in combination with the PretransformVertices
* 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 =
/**
* Searches for redundant materials and removes them.
* <p/>
* This is especially useful in combination with the PretransformVertices
* 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 =
new PostProcessStep("RemoveRedundantMaterials");
/** This step tries to determine which meshes have normal vectors
* that are facing inwards. The algorithm is simple but effective:
* the bounding box of all vertices + their normals is compared against
* the volume of the bounding box of all vertices without their normals.
* This works well for most objects, problems might occur with planar
* surfaces. However, the step tries to filter such cases.
* 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 =
/**
* This step tries to determine which meshes have normal vectors
* that are facing inwards. The algorithm is simple but effective:
* the bounding box of all vertices + their normals is compared against
* the volume of the bounding box of all vertices without their normals.
* This works well for most objects, problems might occur with planar
* surfaces. However, the step tries to filter such cases.
* 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 =
new PostProcessStep("FixInfacingNormals");
/** This step performs some optimizations on the node graph.
*
* It is incompatible to the PreTransformVertices-Step. Some configuration
* options exist, see aiConfig.h for more details.
* Generally, two actions are available:<br>
* 1. Remove animation nodes and data from the scene. This allows other
* steps for further optimizations.<br>
* 2. Combine very small meshes to larger ones. Only if the meshes
* are used by the same node or by nodes on the same hierarchy (with
* equal local transformations). Unlike PreTransformVertices, the
* OptimizeGraph-step doesn't transform vertices from one space
* another.<br>
* 3. Remove hierarchy levels<br>
*
* It is recommended to have this step run with the default configuration.
*/
public static final PostProcessStep OptimizeGraph =
/**
* This step performs some optimizations on the node graph.
* <p/>
* It is incompatible to the PreTransformVertices-Step. Some configuration
* options exist, see aiConfig.h for more details.
* Generally, two actions are available:<br>
* 1. Remove animation nodes and data from the scene. This allows other
* steps for further optimizations.<br>
* 2. Combine very small meshes to larger ones. Only if the meshes
* are used by the same node or by nodes on the same hierarchy (with
* equal local transformations). Unlike PreTransformVertices, the
* OptimizeGraph-step doesn't transform vertices from one space
* another.<br>
* 3. Remove hierarchy levels<br>
* <p/>
* It is recommended to have this step run with the default configuration.
*/
public static final PostProcessStep OptimizeGraph =
new PostProcessStep("OptimizeGraph");
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;
/**
* Created by IntelliJ IDEA.
* User: Alex
* Date: 08.06.2008
* Time: 17:27:11
* To change this template use File | Settings | File Templates.
* Defines how texture coordinates ! ElemOf [0 ... 1] are handled.
*
* This corresponds to the native <code>aiTextureMapMode</code> enum.
*
* @author Alexander Gessler (Aramis)
*/
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 javax.imageio.ImageWriter;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.io.FileWriter;
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 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";
stream.write("Emb. Texture\n" +
"\tExportPath: " + path + "\n\n");
"\tExportPath: " + path + "\n\n");
SaveTextureToTGA(texture, path);
}
@ -399,7 +429,6 @@ public class DumpToFile {
/* Now print all materials
*/
// close the stream again
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 />
</component>
<component name="ExportToHTMLSettings">
<option name="PRINT_LINE_NUMBERS" value="false" />
<option name="OPEN_IN_BROWSER" value="false" />
<option name="OUTPUT_DIRECTORY" />
<option name="PRINT_LINE_NUMBERS" value="true" />
<option name="OPEN_IN_BROWSER" value="true" />
<option name="OUTPUT_DIRECTORY" value="J:\Programmieren\ASSIMP\assimp3\trunk\workspaces\jidea5.1\exportToHTML" />
</component>
<component name="GUI Designer component loader factory" />
<component name="JavacSettings">
@ -49,7 +49,7 @@
<option name="MAXIMUM_HEAP_SIZE" value="128" />
</component>
<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_HIERARCHY" value="true" />
<option name="OPTION_NAVIGATOR" value="true" />

View File

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