Merge pull request #4427 from assimp/smartday-master

Smartday master
pull/4203/head^2
Kim Kulling 2022-03-05 23:00:21 +01:00 committed by GitHub
commit 7eb5fd0e4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 660 additions and 15 deletions

View File

@ -64,6 +64,7 @@ namespace LWO {
#define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L', 'W', 'O', 'B') #define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L', 'W', 'O', 'B')
#define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L', 'W', 'O', '2') #define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L', 'W', 'O', '2')
#define AI_LWO_FOURCC_LWO3 AI_IFF_FOURCC('L', 'W', 'O', '3')
#define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L', 'X', 'O', 'B') #define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L', 'X', 'O', 'B')
// chunks specific to the LWOB format // chunks specific to the LWOB format
@ -248,6 +249,57 @@ namespace LWO {
#define AI_LWO_SPOT AI_IFF_FOURCC('S', 'P', 'O', 'T') #define AI_LWO_SPOT AI_IFF_FOURCC('S', 'P', 'O', 'T')
#define AI_LWO_PICK AI_IFF_FOURCC('P', 'I', 'C', 'K') #define AI_LWO_PICK AI_IFF_FOURCC('P', 'I', 'C', 'K')
// Surface Part
#define AI_LWO_NODS AI_IFF_FOURCC('N', 'O', 'D', 'S')
#define AI_LWO_NNDS AI_IFF_FOURCC('N', 'N', 'D', 'S')
#define AI_LWO_NTAG AI_IFF_FOURCC('N', 'T', 'A', 'G')
#define AI_LWO_NRNM AI_IFF_FOURCC('N', 'R', 'N', 'M')
#define AI_LWO_NRME AI_IFF_FOURCC('N', 'R', 'M', 'E')
#define AI_LWO_NDTA AI_IFF_FOURCC('N', 'D', 'T', 'A')
#define AI_LWO_ATTR AI_IFF_FOURCC('A', 'T', 'T', 'R')
#define AI_LWO_VERS AI_IFF_FOURCC('V', 'E', 'R', 'S')
#define AI_LWO_ENUM AI_IFF_FOURCC('E', 'N', 'U', 'M')
#define AI_LWO_ENTR AI_IFF_FOURCC('E', 'N', 'T', 'R')
#define AI_LWO_NAME AI_IFF_FOURCC('N', 'A', 'M', 'E')
#define AI_LWO_FLAG AI_IFF_FOURCC('F', 'L', 'A', 'G')
#define AI_LWO_TAG AI_IFF_FOURCC('T', 'A', 'G', ' ')
#define AI_LWO_VALU AI_IFF_FOURCC('V', 'A', 'L', 'U')
#define AI_LWO_IBGC AI_IFF_FOURCC('I', 'B', 'G', 'C')
#define AI_LWO_IOPC AI_IFF_FOURCC('I', 'O', 'P', 'C')
#define AI_LWO_IIMG AI_IFF_FOURCC('I', 'I', 'M', 'G')
#define AI_LWO_TXTR AI_IFF_FOURCC('T', 'X', 'T', 'R')
#define AI_LWO_IFAL AI_IFF_FOURCC('I', 'F', 'A', 'L')
#define AI_LWO_ISCL AI_IFF_FOURCC('I', 'S', 'C', 'L')
#define AI_LWO_IPOS AI_IFF_FOURCC('I', 'P', 'O', 'S')
#define AI_LWO_IROT AI_IFF_FOURCC('I', 'R', 'O', 'T')
#define AI_LWO_IBMP AI_IFF_FOURCC('I', 'B', 'M', 'P')
#define AI_LWO_IUTD AI_IFF_FOURCC('I', 'U', 'T', 'D')
#define AI_LWO_IVTD AI_IFF_FOURCC('I', 'V', 'T', 'D')
#define AI_LWO_IPIX AI_IFF_FOURCC('I', 'P', 'I', 'X')
#define AI_LWO_IMIP AI_IFF_FOURCC('I', 'M', 'I', 'P')
#define AI_LWO_IMOD AI_IFF_FOURCC('I', 'M', 'O', 'D')
#define AI_LWO_AMOD AI_IFF_FOURCC('A', 'M', 'O', 'D')
#define AI_LWO_IINV AI_IFF_FOURCC('I', 'I', 'N', 'V')
#define AI_LWO_INCR AI_IFF_FOURCC('I', 'N', 'C', 'R')
#define AI_LWO_IAXS AI_IFF_FOURCC('I', 'A', 'X', 'S')
#define AI_LWO_IFOT AI_IFF_FOURCC('I', 'F', 'O', 'T')
#define AI_LWO_ITIM AI_IFF_FOURCC('I', 'T', 'I', 'M')
#define AI_LWO_IWRL AI_IFF_FOURCC('I', 'W', 'R', 'L')
#define AI_LWO_IUTI AI_IFF_FOURCC('I', 'U', 'T', 'I')
#define AI_LWO_IINX AI_IFF_FOURCC('I', 'I', 'N', 'X')
#define AI_LWO_IINY AI_IFF_FOURCC('I', 'I', 'N', 'Y')
#define AI_LWO_IINZ AI_IFF_FOURCC('I', 'I', 'N', 'Z')
#define AI_LWO_IREF AI_IFF_FOURCC('I', 'R', 'E', 'F')
#define AI_LWO_IMST AI_IFF_FOURCC('I', 'M', 'S', 'T')
#define AI_LWO_VPVL AI_IFF_FOURCC('V', 'P', 'V', 'L')
#define AI_LWO_VPRM AI_IFF_FOURCC('V', 'P', 'R', 'M')
#define AI_LWO_IMAP AI_IFF_FOURCC('I', 'M', 'A', 'P')
#define AI_LWO_IUVI AI_IFF_FOURCC('I', 'U', 'V', 'I')
#define AI_LWO_IUTL AI_IFF_FOURCC('I', 'U', 'T', 'L')
#define AI_LWO_IVTL AI_IFF_FOURCC('I', 'V', 'T', 'L')
// MODO extension - per-vertex normal vectors // MODO extension - per-vertex normal vectors
#define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M') #define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M')
@ -555,6 +607,31 @@ struct Surface {
float mAdditiveTransparency; float mAdditiveTransparency;
}; };
// ---------------------------------------------------------------------------
/** \brief Data structure for a LWO node
*/
struct Node {
// Name of node
std::string mName;
// RefName of node
std::string mRefName;
// Ref FileName
std::string fileName;
};
struct NodeAttribute {
//! Color of the surface
aiColor3D mColor;
//! true for two-sided materials
bool bDoubleSided;
//! Various material parameters
float mDiffuseValue, mSpecularValue, mTransparency, mGlossiness, mLuminosity, mColorHighlights;
};
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#define AI_LWO_VALIDATE_CHUNK_LENGTH(length, name, size) \ #define AI_LWO_VALIDATE_CHUNK_LENGTH(length, name, size) \
if (length < size) { \ if (length < size) { \

View File

@ -83,6 +83,7 @@ static const aiImporterDesc desc = {
LWOImporter::LWOImporter() : LWOImporter::LWOImporter() :
mIsLWO2(), mIsLWO2(),
mIsLXOB(), mIsLXOB(),
mIsLWO3(),
mLayers(), mLayers(),
mCurLayer(), mCurLayer(),
mTags(), mTags(),
@ -182,16 +183,19 @@ void LWOImporter::InternReadFile(const std::string &pFile,
mCurLayer->mIndex = (uint16_t) -1; mCurLayer->mIndex = (uint16_t) -1;
// old lightwave file format (prior to v6) // old lightwave file format (prior to v6)
mIsLWO2 = false;
mIsLWO3 = false;
mIsLXOB = false;
if (AI_LWO_FOURCC_LWOB == fileType) { if (AI_LWO_FOURCC_LWOB == fileType) {
ASSIMP_LOG_INFO("LWO file format: LWOB (<= LightWave 5.5)"); ASSIMP_LOG_INFO("LWO file format: LWOB (<= LightWave 5.5)");
mIsLWO2 = false;
mIsLXOB = false;
LoadLWOBFile(); LoadLWOBFile();
} else if (AI_LWO_FOURCC_LWO2 == fileType) { } else if (AI_LWO_FOURCC_LWO2 == fileType) {
// New lightwave format // New lightwave format
mIsLXOB = false;
ASSIMP_LOG_INFO("LWO file format: LWO2 (>= LightWave 6)"); ASSIMP_LOG_INFO("LWO file format: LWO2 (>= LightWave 6)");
} else if ( AI_LWO_FOURCC_LWO3 == fileType ) {
ASSIMP_LOG_INFO("LWO file format: LWO3 (>= LightWave 2018)");
} else if (AI_LWO_FOURCC_LXOB == fileType) { } else if (AI_LWO_FOURCC_LXOB == fileType) {
// MODO file format // MODO file format
mIsLXOB = true; mIsLXOB = true;
@ -207,8 +211,13 @@ void LWOImporter::InternReadFile(const std::string &pFile,
throw DeadlyImportError("Unknown LWO sub format: ", szBuff); throw DeadlyImportError("Unknown LWO sub format: ", szBuff);
} }
if (AI_LWO_FOURCC_LWOB != fileType) { if (AI_LWO_FOURCC_LWOB != fileType) { //
mIsLWO2 = true; if( AI_LWO_FOURCC_LWO3 == fileType ) {
mIsLWO3 = true;
} else {
mIsLWO2 = true;
}
LoadLWO2File(); LoadLWO2File();
// The newer lightwave format allows the user to configure the // The newer lightwave format allows the user to configure the
@ -442,6 +451,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
// The RemoveRedundantMaterials step will clean this up later // The RemoveRedundantMaterials step will clean this up later
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = (unsigned int)mSurfaces->size()]; pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
for (unsigned int mat = 0; mat < pScene->mNumMaterials; ++mat) { for (unsigned int mat = 0; mat < pScene->mNumMaterials; ++mat) {
aiMaterial *pcMat = new aiMaterial(); aiMaterial *pcMat = new aiMaterial();
pScene->mMaterials[mat] = pcMat; pScene->mMaterials[mat] = pcMat;
@ -687,7 +697,7 @@ void LWOImporter::ResolveClips() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::AdjustTexturePath(std::string &out) { void LWOImporter::AdjustTexturePath(std::string &out) {
// --- this function is used for both LWO2 and LWOB // --- this function is used for both LWO2 and LWOB
if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) { if (!mIsLWO2 && !mIsLWO3 && ::strstr(out.c_str(), "(sequence)")) {
// remove the (sequence) and append 000 // remove the (sequence) and append 000
ASSIMP_LOG_INFO("LWOB: Sequence of animated texture found. It will be ignored"); ASSIMP_LOG_INFO("LWOB: Sequence of animated texture found. It will be ignored");
@ -730,7 +740,7 @@ void LWOImporter::LoadLWOPoints(unsigned int length) {
throw DeadlyImportError("LWO2: Points chunk length is not multiple of vertexLen (12)"); throw DeadlyImportError("LWO2: Points chunk length is not multiple of vertexLen (12)");
} }
unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12; unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
if (mIsLWO2) { if (mIsLWO2 || mIsLWO3) {
mCurLayer->mTempPoints.reserve(regularSize + (regularSize >> 2u)); mCurLayer->mTempPoints.reserve(regularSize + (regularSize >> 2u));
mCurLayer->mTempPoints.resize(regularSize); mCurLayer->mTempPoints.resize(regularSize);
@ -1155,6 +1165,76 @@ void LWOImporter::LoadLWO2Clip(unsigned int length) {
} }
} }
void LWOImporter::LoadLWO3Clip(unsigned int length) {
AI_LWO_VALIDATE_CHUNK_LENGTH(length, CLIP, 12);
mClips.push_back(LWO::Clip());
LWO::Clip &clip = mClips.back();
// first - get the index of the clip
clip.idx = GetU4();
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
switch (head.type) {
case AI_LWO_STIL:
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, STIL, 1);
// "Normal" texture
GetS0(clip.path, head.length);
clip.type = Clip::STILL;
break;
case AI_LWO_ISEQ:
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ISEQ, 16);
// Image sequence. We'll later take the first.
{
uint8_t digits = GetU1();
mFileBuffer++;
int16_t offset = GetU2();
mFileBuffer += 4;
int16_t start = GetU2();
mFileBuffer += 4;
std::string s;
std::ostringstream ss;
GetS0(s, head.length);
head.length -= (uint16_t)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:
ASSIMP_LOG_WARN("LWO3: Color shifted images are not supported");
break;
case AI_LWO_ANIM:
ASSIMP_LOG_WARN("LWO3: Animated textures are not supported");
break;
case AI_LWO_XREF:
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, XREF, 4);
// Just a cross-reference to another CLIp
clip.type = Clip::REF;
clip.clipRef = GetU4();
break;
case AI_LWO_NEGA:
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, NEGA, 2);
clip.negate = (0 != GetU2());
break;
default:
ASSIMP_LOG_WARN("LWO3: Encountered unknown CLIP sub-chunk");
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Load envelope description // Load envelope description
void LWOImporter::LoadLWO2Envelope(unsigned int length) { void LWOImporter::LoadLWO2Envelope(unsigned int length) {
@ -1265,6 +1345,104 @@ void LWOImporter::LoadLWO2Envelope(unsigned int length) {
} }
} }
void LWOImporter::LoadLWO3Envelope(unsigned int length) {
LE_NCONST uint8_t *const end = mFileBuffer + length;
AI_LWO_VALIDATE_CHUNK_LENGTH(length, ENVL, 4);
mEnvelopes.push_back(LWO::Envelope());
LWO::Envelope &envelope = mEnvelopes.back();
// Get the index of the envelope
envelope.index = ReadVSizedIntLWO2(mFileBuffer);
// ... and read all blocks
while (true) {
if (mFileBuffer + 8 >= end) break;
LE_NCONST IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
if (mFileBuffer + head.length > end)
throw DeadlyImportError("LWO3: Invalid envelope chunk length");
uint8_t *const next = mFileBuffer + head.length;
switch (head.type) {
// Type & representation of the envelope
case AI_LWO_TYPE:
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, TYPE, 4);
mFileBuffer++; // skip user format
// Determine type of envelope
envelope.type = (LWO::EnvelopeType)*mFileBuffer;
++mFileBuffer;
break;
// precondition
case AI_LWO_PRE:
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, PRE, 4);
envelope.pre = (LWO::PrePostBehaviour)GetU2();
break;
// postcondition
case AI_LWO_POST:
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, POST, 4);
envelope.post = (LWO::PrePostBehaviour)GetU2();
break;
// keyframe
case AI_LWO_KEY: {
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, KEY, 10);
envelope.keys.push_back(LWO::Key());
LWO::Key &key = envelope.keys.back();
key.time = GetF4();
key.value = GetF4();
break;
}
// interval interpolation
case AI_LWO_SPAN: {
AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SPAN, 6);
if (envelope.keys.size() < 2)
ASSIMP_LOG_WARN("LWO3: Unexpected SPAN chunk");
else {
LWO::Key &key = envelope.keys.back();
switch (GetU4()) {
case AI_LWO_STEP:
key.inter = LWO::IT_STEP;
break;
case AI_LWO_LINE:
key.inter = LWO::IT_LINE;
break;
case AI_LWO_TCB:
key.inter = LWO::IT_TCB;
break;
case AI_LWO_HERM:
key.inter = LWO::IT_HERM;
break;
case AI_LWO_BEZI:
key.inter = LWO::IT_BEZI;
break;
case AI_LWO_BEZ2:
key.inter = LWO::IT_BEZ2;
break;
default:
ASSIMP_LOG_WARN("LWO3: Unknown interval interpolation mode");
};
// todo ... read params
}
break;
}
default:
ASSIMP_LOG_WARN("LWO3: Encountered unknown ENVL subchunk");
break;
}
// regardless how much we did actually read, go to the next chunk
mFileBuffer = next;
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Load file - master function // Load file - master function
void LWOImporter::LoadLWO2File() { void LWOImporter::LoadLWO2File() {
@ -1272,16 +1450,25 @@ void LWOImporter::LoadLWO2File() {
LE_NCONST uint8_t *const end = mFileBuffer + fileSize; LE_NCONST uint8_t *const end = mFileBuffer + fileSize;
unsigned int iUnnamed = 0; unsigned int iUnnamed = 0;
while (true) { while (true) {
if (mFileBuffer + sizeof(IFF::ChunkHeader) > end) break; if (mFileBuffer + sizeof(IFF::ChunkHeader) > end) break;
const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
int bufOffset = 0;
if( head.type == AI_IFF_FOURCC_FORM ) { // not chunk, it's a form
mFileBuffer -= 8;
head = IFF::LoadForm(mFileBuffer);
bufOffset = 4;
}
if (mFileBuffer + head.length > end) { if (mFileBuffer + head.length > end) {
throw DeadlyImportError("LWO2: Chunk length points behind the file"); throw DeadlyImportError("LWO2: Chunk length points behind the file");
break; break;
} }
uint8_t *const next = mFileBuffer + head.length; uint8_t *const next = mFileBuffer + head.length;
mFileBuffer += bufOffset;
if (!head.length) { if (!head.length) {
mFileBuffer = next; mFileBuffer = next;
continue; continue;
@ -1337,7 +1524,6 @@ void LWOImporter::LoadLWO2File() {
break; break;
} }
// vertex list // vertex list
case AI_LWO_PNTS: { case AI_LWO_PNTS: {
if (skip) if (skip)
@ -1399,19 +1585,29 @@ void LWOImporter::LoadLWO2File() {
// surface chunk // surface chunk
case AI_LWO_SURF: { case AI_LWO_SURF: {
LoadLWO2Surface(head.length); if( mIsLWO3 )
LoadLWO3Surface(head.length);
else
LoadLWO2Surface(head.length);
break; break;
} }
// clip chunk // clip chunk
case AI_LWO_CLIP: { case AI_LWO_CLIP: {
LoadLWO2Clip(head.length); if( mIsLWO3 )
LoadLWO3Clip(head.length);
else
LoadLWO2Clip(head.length);
break; break;
} }
// envelope chunk // envelope chunk
case AI_LWO_ENVL: { case AI_LWO_ENVL: {
LoadLWO2Envelope(head.length); if( mIsLWO3 )
LoadLWO3Envelope(head.length);
else
LoadLWO2Envelope(head.length);
break; break;
} }
} }

View File

@ -116,6 +116,8 @@ private:
*/ */
inline void GetS0(std::string &out, unsigned int max); inline void GetS0(std::string &out, unsigned int max);
inline float GetF4(); inline float GetF4();
inline float GetF8();
inline uint64_t GetU8();
inline uint32_t GetU4(); inline uint32_t GetU4();
inline uint16_t GetU2(); inline uint16_t GetU2();
inline uint8_t GetU1(); inline uint8_t GetU1();
@ -131,6 +133,7 @@ private:
* @param size Maximum size to be read, in bytes. * @param size Maximum size to be read, in bytes.
*/ */
void LoadLWO2Surface(unsigned int size); void LoadLWO2Surface(unsigned int size);
void LoadLWO3Surface(unsigned int size);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Loads a texture block from a LWO2 file. /** Loads a texture block from a LWO2 file.
@ -197,12 +200,23 @@ private:
* @param length Size of the chunk * @param length Size of the chunk
*/ */
void LoadLWO2Clip(unsigned int length); void LoadLWO2Clip(unsigned int length);
void LoadLWO3Clip(unsigned int length);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Load an envelope from an EVL chunk /** Load an envelope from an EVL chunk
* @param length Size of the chunk * @param length Size of the chunk
*/ */
void LoadLWO2Envelope(unsigned int length); void LoadLWO2Envelope(unsigned int length);
void LoadLWO3Envelope(unsigned int length);
// -------------------------------------------------------------------
/** Load an nodal blocks from surface form
* @param length Size of the chunk
*/
void LoadNodalBlocks(unsigned int length);
void LoadNodes(unsigned int length);
void LoadNodeTag(unsigned int length);
void LoadNodeData(unsigned int length);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Count vertices and faces in a LWOB/LWO2 file /** Count vertices and faces in a LWOB/LWO2 file
@ -347,6 +361,8 @@ protected:
/** true if the file is a LXOB file*/ /** true if the file is a LXOB file*/
bool mIsLXOB; bool mIsLXOB;
bool mIsLWO3;
/** Temporary list of layers from the file */ /** Temporary list of layers from the file */
LayerList *mLayers; LayerList *mLayers;
@ -400,6 +416,22 @@ inline float LWOImporter::GetF4() {
return f; return f;
} }
inline float LWOImporter::GetF8() {
double f;
::memcpy(&f, mFileBuffer, 8);
mFileBuffer += 8;
AI_LSWAP8(f);
return (float)f;
}
inline uint64_t LWOImporter::GetU8() {
uint64_t f;
::memcpy(&f, mFileBuffer, 8);
mFileBuffer += 8;
AI_LSWAP8(f);
return f;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
inline uint32_t LWOImporter::GetU4() { inline uint32_t LWOImporter::GetU4() {
uint32_t f; uint32_t f;

View File

@ -159,7 +159,7 @@ bool LWOImporter::HandleTextures(aiMaterial *pcMat, const TextureList &in, aiTex
// The older LWOB format does not use indirect references to clips. // The older LWOB format does not use indirect references to clips.
// The file name of a texture is directly specified in the tex chunk. // The file name of a texture is directly specified in the tex chunk.
if (mIsLWO2) { if (mIsLWO2 || mIsLWO3) {
// find the corresponding clip (take the last one if multiple // find the corresponding clip (take the last one if multiple
// share the same index) // share the same index)
ClipList::iterator end = mClips.end(), candidate = end; ClipList::iterator end = mClips.end(), candidate = end;
@ -270,7 +270,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) {
aiShadingMode m; aiShadingMode m;
if (surf.mSpecularValue && surf.mGlossiness) { if (surf.mSpecularValue && surf.mGlossiness) {
float fGloss; float fGloss;
if (mIsLWO2) { if (mIsLWO2 || mIsLWO3) {
fGloss = std::pow(surf.mGlossiness * ai_real(10.0) + ai_real(2.0), ai_real(2.0)); fGloss = std::pow(surf.mGlossiness * ai_real(10.0) + ai_real(2.0), ai_real(2.0));
} else { } else {
if (16.0 >= surf.mGlossiness) if (16.0 >= surf.mGlossiness)
@ -688,6 +688,252 @@ void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader * /*head*/,
surf.mShaders.push_back(shader); surf.mShaders.push_back(shader);
} }
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadNodalBlocks(unsigned int size) {
LE_NCONST uint8_t *const end = mFileBuffer + size;
while (true) {
if (mFileBuffer + 8 >= end)
break;
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
int bufOffset = 0;
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
mFileBuffer -= 8;
head = IFF::LoadForm(mFileBuffer);
bufOffset = 4;
}
if (mFileBuffer + head.length > end) {
throw DeadlyImportError("LWO3: cannot read length; LoadNodalBlocks");
}
int node_idx = 0;
uint8_t *const next = mFileBuffer + head.length;
mFileBuffer += bufOffset;
switch (head.type) {
case AI_LWO_NNDS:
node_idx++;
LoadNodes(head.length);
break;
}
mFileBuffer = next;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadNodes(unsigned int size) {
LE_NCONST uint8_t *const end = mFileBuffer + size;
while (true) {
if (mFileBuffer + 8 >= end)
break;
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
int bufOffset = 0;
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
mFileBuffer -= 8;
head = IFF::LoadForm(mFileBuffer);
bufOffset = 4;
}
if (mFileBuffer + head.length > end) {
throw DeadlyImportError("LWO3: cannot read length; LoadNodes");
}
uint8_t *const next = mFileBuffer + head.length;
mFileBuffer += bufOffset;
switch (head.type) {
case AI_LWO_NTAG:
LoadNodeTag(head.length);
break;
}
mFileBuffer = next;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadNodeTag(unsigned int size) {
LE_NCONST uint8_t *const end = mFileBuffer + size;
while (true) {
if (mFileBuffer + 8 >= end)
break;
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
int bufOffset = 0;
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
mFileBuffer -= 8;
head = IFF::LoadForm(mFileBuffer);
bufOffset = 4;
}
if (mFileBuffer + head.length > end) {
throw DeadlyImportError("LWO3: cannot read length; LoadNodeTag");
}
uint8_t *const next = mFileBuffer + head.length;
mFileBuffer += bufOffset;
switch (head.type) {
case AI_LWO_NDTA:
LoadNodeData(head.length);
break;
}
mFileBuffer = next;
}
}
// ------------------------------------------------------------------------------------------------
void LWOImporter::LoadNodeData(unsigned int size) {
LE_NCONST uint8_t *const end = mFileBuffer + size;
LWO::Surface &surf = mSurfaces->back();
while (true) {
if (mFileBuffer + 8 >= end)
break;
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
int bufOffset = 0;
if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
mFileBuffer -= 8;
head = IFF::LoadForm(mFileBuffer);
bufOffset = 4;
}
if (mFileBuffer + head.length > end) {
throw DeadlyImportError("LWO3: INVALID LENGTH; LoadNodeData");
}
uint8_t *const next = mFileBuffer + head.length;
mFileBuffer += bufOffset;
switch (head.type) {
case AI_LWO_VERS:
case AI_LWO_ENUM:
case AI_LWO_IBGC:
case AI_LWO_IOPC:
case AI_LWO_IIMG:
case AI_LWO_TXTR:
case AI_LWO_IFAL:
case AI_LWO_ISCL:
case AI_LWO_IPOS:
case AI_LWO_IROT:
case AI_LWO_IBMP:
case AI_LWO_IUTD:
case AI_LWO_IVTD:
case AI_LWO_IPIX:
case AI_LWO_IMIP:
case AI_LWO_IMOD:
case AI_LWO_AMOD:
case AI_LWO_IINV:
case AI_LWO_INCR:
case AI_LWO_IAXS:
case AI_LWO_IFOT:
case AI_LWO_ITIM:
case AI_LWO_IWRL:
case AI_LWO_IUTI:
case AI_LWO_IUVI:
case AI_LWO_IINX:
case AI_LWO_IINY:
case AI_LWO_IINZ:
case AI_LWO_IREF:
case AI_LWO_IMST:
case AI_LWO_IMAP:
case AI_LWO_IUTL:
case AI_LWO_IVTL:
case AI_LWO_VPVL:
case AI_LWO_VPRM:
mFileBuffer = next;
break;
case AI_LWO_ENTR:
std::string attrName;
while (true) {
if (mFileBuffer + 8 >= next)
break;
IFF::ChunkHeader head1 = IFF::LoadChunk(mFileBuffer);
int bufOffset1 = 0;
if (head1.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form
mFileBuffer -= 8;
head1 = IFF::LoadForm(mFileBuffer);
bufOffset1 = 4;
}
if (mFileBuffer + head1.length > end) {
throw DeadlyImportError("LWO3: cannot read length;");
}
uint8_t *const next1 = mFileBuffer + head1.length;
mFileBuffer += bufOffset1;
switch (head1.type) {
case AI_LWO_FLAG:
case AI_LWO_TAG:
mFileBuffer = next1;
break;
case AI_LWO_NAME:
GetS0(attrName, head1.length);
break;
case AI_LWO_VALU:
mFileBuffer += 8;
std::string valueType;
GetS0(valueType, 8);
if (valueType == "int") {
static_cast<void>(GetU4());
} else if (valueType == "double") {
static_cast<void>(GetU8());
} else if (valueType == "vparam") {
mFileBuffer += 24;
float value = GetF8();
if (attrName == "Diffuse") {
surf.mDiffuseValue = value;
} else if (attrName == "Specular") {
surf.mSpecularValue = value;
} else if (attrName == "Transparency") {
surf.mTransparency = value;
} else if (attrName == "Glossiness") {
surf.mGlossiness = value;
} else if (attrName == "Luminosity") {
surf.mLuminosity = value;
} else if (attrName == "Color Highlight") {
surf.mColorHighlights = value;
} else if (attrName == "Refraction Index") {
surf.mIOR = value;
} else if (attrName == "Bump Height") {
surf.mBumpIntensity = value;
}
} else if (valueType == "vparam3") {
mFileBuffer += 24;
float value1, value2, value3;
value1 = GetF8();
value2 = GetF8();
value3 = GetF8();
if (attrName == "Color") {
surf.mColor.r = value1;
surf.mColor.g = value2;
surf.mColor.b = value3;
}
}
mFileBuffer = next1;
break;
}
}
break;
}
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void LWOImporter::LoadLWO2Surface(unsigned int size) { void LWOImporter::LoadLWO2Surface(unsigned int size) {
LE_NCONST uint8_t *const end = mFileBuffer + size; LE_NCONST uint8_t *const end = mFileBuffer + size;
@ -841,4 +1087,69 @@ void LWOImporter::LoadLWO2Surface(unsigned int size) {
} }
} }
void LWOImporter::LoadLWO3Surface(unsigned int size) {
mFileBuffer += 8;
LE_NCONST uint8_t *const end = mFileBuffer + size - 12;
mSurfaces->push_back(LWO::Surface());
LWO::Surface &surf = mSurfaces->back();
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(), itEnd = mSurfaces->end() - 1; it != itEnd; ++it) {
if ((*it).mName == derived) {
// we have it ...
surf = *it;
derived.clear();
break;
}
}
if (derived.size()) {
ASSIMP_LOG_WARN("LWO3: Unable to find source surface: ", derived);
}
}
while (true) {
if (mFileBuffer + 8 >= end)
break;
IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
int bufOffset = 0;
if( head.type == AI_IFF_FOURCC_FORM ) { // not chunk, it's a form
mFileBuffer -= 8;
head = IFF::LoadForm(mFileBuffer);
bufOffset = 4;
}
if (mFileBuffer + head.length > end) {
throw DeadlyImportError("LWO3: cannot read length; LoadLWO3Surface");
}
uint8_t *const next = mFileBuffer + head.length;
mFileBuffer += bufOffset;
switch (head.type) {
case AI_LWO_NODS:
LoadNodalBlocks(head.length);
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 = std::fabs(GetF4());
break;
}
}
mFileBuffer = next;
}
}
#endif // !! ASSIMP_BUILD_NO_X_IMPORTER #endif // !! ASSIMP_BUILD_NO_X_IMPORTER

View File

@ -35,6 +35,17 @@ struct SubChunkHeader
uint16_t length; uint16_t length;
}; };
/////////////////////////////////////////////////////////////////////////////////
//! Describes an IFF form header
/////////////////////////////////////////////////////////////////////////////////
struct FormHeader
{
//! Length of the chunk data, in bytes
uint32_t length;
//! Type of the chunk header - FourCC
uint32_t type;
};
#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \ #define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d))) ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
@ -77,6 +88,24 @@ inline SubChunkHeader LoadSubChunk(uint8_t*& outFile)
return head; return head;
} }
/////////////////////////////////////////////////////////////////////////////////
//! Load a chunk header
//! @param outFile Pointer to the file data - points to the chunk data afterwards
//! @return Copy of the chunk header
/////////////////////////////////////////////////////////////////////////////////
inline ChunkHeader LoadForm(uint8_t*& outFile)
{
ChunkHeader head;
outFile += 4;
::memcpy(&head.length, outFile, 4);
outFile += 4;
::memcpy(&head.type, outFile, 4);
AI_LSWAP4(head.length);
AI_LSWAP4(head.type);
return head;
}
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
//! Read the file header and return the type of the file and its size //! Read the file header and return the type of the file and its size
//! @param outFile Pointer to the file data. The buffer must at //! @param outFile Pointer to the file data. The buffer must at