assimp/code/AssetLib/ASE/ASEParser.cpp

1896 lines
70 KiB
C++
Raw Normal View History

/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
2024-02-23 21:30:05 +00:00
Copyright (c) 2006-2024, assimp team
2018-01-28 18:42:05 +00:00
All rights reserved.
2015-05-19 03:52:10 +00:00
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
2016-08-29 16:23:41 +00:00
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2015-05-19 03:52:10 +00:00
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2015-05-19 03:52:10 +00:00
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2015-05-19 03:52:10 +00:00
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file ASEParser.cpp
2015-05-19 03:52:10 +00:00
* @brief Implementation of the ASE parser class
*/
#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
// internal headers
#include "ASELoader.h"
#include "PostProcessing/TextureTransform.h"
#include <assimp/fast_atof.h>
2016-06-06 20:04:29 +00:00
#include <assimp/DefaultLogger.hpp>
2023-11-11 20:13:47 +00:00
namespace Assimp {
using namespace Assimp::ASE;
// ------------------------------------------------------------------------------------------------
// Begin an ASE parsing function
#define AI_ASE_PARSER_INIT() \
2015-05-19 03:57:13 +00:00
int iDepth = 0;
// ------------------------------------------------------------------------------------------------
// Handle a "top-level" section in the file. EOF is no error in this case.
#define AI_ASE_HANDLE_TOP_LEVEL_SECTION() \
2024-07-06 08:35:29 +00:00
else if ('{' == *mFilePtr) \
++iDepth; \
else if ('}' == *mFilePtr) { \
if (0 == --iDepth) { \
2024-07-06 08:35:29 +00:00
++mFilePtr; \
SkipToNextToken(); \
return; \
} \
} \
2024-07-06 08:35:29 +00:00
if ('\0' == *mFilePtr) { \
return; \
} \
2024-07-06 08:35:29 +00:00
if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) {\
++iLineNumber; \
bLastWasEndLine = true; \
} else \
bLastWasEndLine = false; \
2024-07-06 08:35:29 +00:00
++mFilePtr;
// ------------------------------------------------------------------------------------------------
// Handle a nested section in the file. EOF is an error in this case
// @param level "Depth" of the section
// @param msg Full name of the section (including the asterisk)
#define AI_ASE_HANDLE_SECTION(level, msg) \
2024-07-06 08:35:29 +00:00
if ('{' == *mFilePtr) \
iDepth++; \
2024-07-06 08:35:29 +00:00
else if ('}' == *mFilePtr) { \
if (0 == --iDepth) { \
2024-07-06 08:35:29 +00:00
++mFilePtr; \
SkipToNextToken(); \
return; \
} \
2024-07-06 08:35:29 +00:00
} else if ('\0' == *mFilePtr) { \
2015-05-19 03:57:13 +00:00
LogError("Encountered unexpected EOL while parsing a " msg \
" chunk (Level " level ")"); \
} \
2024-07-06 08:35:29 +00:00
if (IsLineEnd(*mFilePtr) && !bLastWasEndLine) { \
++iLineNumber; \
bLastWasEndLine = true; \
} else \
bLastWasEndLine = false; \
2024-07-06 08:35:29 +00:00
++mFilePtr;
// ------------------------------------------------------------------------------------------------
2024-07-06 08:35:29 +00:00
Parser::Parser(const char *file, size_t fileLen, unsigned int fileFormatDefault) :
mFilePtr(nullptr), mEnd (nullptr) {
ai_assert(file != nullptr);
2022-01-24 19:05:25 +00:00
2024-07-06 08:35:29 +00:00
mFilePtr = file;
mEnd = mFilePtr + fileLen;
2015-05-19 03:57:13 +00:00
iFileFormat = fileFormatDefault;
// make sure that the color values are invalid
m_clrBackground.r = get_qnan();
m_clrAmbient.r = get_qnan();
2015-05-19 03:57:13 +00:00
// setup some default values
iLineNumber = 0;
iFirstFrame = 0;
iLastFrame = 0;
iFrameSpeed = 30; // use 30 as default value for this property
iTicksPerFrame = 1; // use 1 as default value for this property
2015-05-19 03:57:13 +00:00
bLastWasEndLine = false; // need to handle \r\n seqs due to binary file mapping
}
// ------------------------------------------------------------------------------------------------
void Parser::LogWarning(const char *szWarn) {
ai_assert(nullptr != szWarn);
char szTemp[2048];
#if _MSC_VER >= 1400
sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn);
#else
ai_snprintf(szTemp, sizeof(szTemp), "Line %u: %s", iLineNumber, szWarn);
#endif
2015-05-19 03:57:13 +00:00
// output the warning to the logger ...
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_WARN(szTemp);
}
// ------------------------------------------------------------------------------------------------
void Parser::LogInfo(const char *szWarn) {
ai_assert(nullptr != szWarn);
2015-05-19 03:57:13 +00:00
char szTemp[1024];
#if _MSC_VER >= 1400
sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn);
#else
ai_snprintf(szTemp, 1024, "Line %u: %s", iLineNumber, szWarn);
#endif
2015-05-19 03:57:13 +00:00
// output the information to the logger ...
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_INFO(szTemp);
}
// ------------------------------------------------------------------------------------------------
AI_WONT_RETURN void Parser::LogError(const char *szWarn) {
ai_assert(nullptr != szWarn);
2015-05-19 03:57:13 +00:00
char szTemp[1024];
#if _MSC_VER >= 1400
sprintf_s(szTemp, "Line %u: %s", iLineNumber, szWarn);
#else
ai_snprintf(szTemp, 1024, "Line %u: %s", iLineNumber, szWarn);
#endif
2015-05-19 03:57:13 +00:00
// throw an exception
throw DeadlyImportError(szTemp);
}
// ------------------------------------------------------------------------------------------------
bool Parser::SkipToNextToken() {
while (true) {
2024-07-06 08:35:29 +00:00
char me = *mFilePtr;
2015-05-19 03:57:13 +00:00
2024-07-06 08:35:29 +00:00
if (mFilePtr == mEnd) {
return false;
}
2015-05-19 03:57:13 +00:00
// increase the line number counter if necessary
if (IsLineEnd(me) && !bLastWasEndLine) {
2015-05-19 03:57:13 +00:00
++iLineNumber;
bLastWasEndLine = true;
} else
bLastWasEndLine = false;
if ('*' == me || '}' == me || '{' == me) {
return true;
}
if ('\0' == me) {
return false;
}
2015-05-19 03:57:13 +00:00
2024-07-06 08:35:29 +00:00
++mFilePtr;
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
bool Parser::SkipSection() {
2015-05-19 03:57:13 +00:00
// must handle subsections ...
int iCnt = 0;
while (true) {
2024-07-06 08:35:29 +00:00
if ('}' == *mFilePtr) {
2015-05-19 03:57:13 +00:00
--iCnt;
if (0 == iCnt) {
2015-05-19 03:57:13 +00:00
// go to the next valid token ...
2024-07-06 08:35:29 +00:00
++mFilePtr;
2015-05-19 03:57:13 +00:00
SkipToNextToken();
return true;
}
2024-07-06 08:35:29 +00:00
} else if ('{' == *mFilePtr) {
2015-05-19 03:57:13 +00:00
++iCnt;
2024-07-06 08:35:29 +00:00
} else if ('\0' == *mFilePtr) {
2015-05-19 03:57:13 +00:00
LogWarning("Unable to parse block: Unexpected EOF, closing bracket \'}\' was expected [#1]");
return false;
2024-07-06 08:35:29 +00:00
} else if (IsLineEnd(*mFilePtr))
++iLineNumber;
2024-07-06 08:35:29 +00:00
++mFilePtr;
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::Parse() {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Version should be 200. Validate this ...
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "3DSMAX_ASCIIEXPORT", 18)) {
2015-05-19 03:57:13 +00:00
unsigned int fmt;
ParseLV4MeshLong(fmt);
if (fmt > 200) {
2015-05-19 03:57:13 +00:00
LogWarning("Unknown file format version: *3DSMAX_ASCIIEXPORT should \
be <= 200");
}
// *************************************************************
// - fmt will be 0 if we're unable to read the version number
// there are some faulty files without a version number ...
// in this case we'll guess the exact file format by looking
// at the file extension (ASE, ASK, ASC)
// *************************************************************
if (fmt) {
2018-03-20 17:43:54 +00:00
iFileFormat = fmt;
}
2015-05-19 03:57:13 +00:00
continue;
}
// main scene information
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "SCENE", 5)) {
2015-05-19 03:57:13 +00:00
ParseLV1SceneBlock();
continue;
}
// "group" - no implementation yet, in facte
// we're just ignoring them for the moment
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "GROUP", 5)) {
2015-05-19 03:57:13 +00:00
Parse();
continue;
}
// material list
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_LIST", 13)) {
2015-05-19 03:57:13 +00:00
ParseLV1MaterialListBlock();
continue;
}
// geometric object (mesh)
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "GEOMOBJECT", 10))
2015-05-19 03:57:13 +00:00
{
m_vMeshes.emplace_back("UNNAMED");
2015-05-19 03:57:13 +00:00
ParseLV1ObjectBlock(m_vMeshes.back());
continue;
}
// helper object = dummy in the hierarchy
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "HELPEROBJECT", 12))
2015-05-19 03:57:13 +00:00
{
m_vDummies.emplace_back();
2015-05-19 03:57:13 +00:00
ParseLV1ObjectBlock(m_vDummies.back());
continue;
}
// light object
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "LIGHTOBJECT", 11))
2015-05-19 03:57:13 +00:00
{
m_vLights.emplace_back("UNNAMED");
2015-05-19 03:57:13 +00:00
ParseLV1ObjectBlock(m_vLights.back());
continue;
}
// camera object
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CAMERAOBJECT", 12)) {
m_vCameras.emplace_back("UNNAMED");
2015-05-19 03:57:13 +00:00
ParseLV1ObjectBlock(m_vCameras.back());
continue;
}
// comment - print it on the console
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "COMMENT", 7)) {
2015-05-19 03:57:13 +00:00
std::string out = "<unknown>";
ParseString(out, "*COMMENT");
2015-05-19 03:57:13 +00:00
LogInfo(("Comment: " + out).c_str());
continue;
}
// ASC bone weights
2024-07-06 08:35:29 +00:00
if (AI_ASE_IS_OLD_FILE_FORMAT() && TokenMatch(mFilePtr, "MESH_SOFTSKINVERTS", 18)) {
2015-05-19 03:57:13 +00:00
ParseLV1SoftSkinBlock();
}
}
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV1SoftSkinBlock() {
2015-05-19 03:57:13 +00:00
// TODO: fix line counting here
// **************************************************************
// The soft skin block is formatted differently. There are no
// nested sections supported and the single elements aren't
// marked by keywords starting with an asterisk.
/**
FORMAT BEGIN
*MESH_SOFTSKINVERTS {
<nodename>
<number of vertices>
[for <number of vertices> times:]
<number of weights> [for <number of weights> times:] <bone name> <weight>
}
FORMAT END
*/
// **************************************************************
while (true) {
2024-07-06 08:35:29 +00:00
if (*mFilePtr == '}') {
++mFilePtr;
return;
2024-07-06 08:35:29 +00:00
} else if (*mFilePtr == '\0')
return;
2024-07-06 08:35:29 +00:00
else if (*mFilePtr == '{')
++mFilePtr;
2015-05-19 03:57:13 +00:00
else // if (!IsSpace(*filePtr) && !IsLineEnd(*filePtr))
{
ASE::Mesh *curMesh = nullptr;
unsigned int numVerts = 0;
2015-05-19 03:57:13 +00:00
2024-07-06 08:35:29 +00:00
const char *sz = mFilePtr;
while (!IsSpaceOrNewLine(*mFilePtr)) {
++mFilePtr;
}
2015-05-19 03:57:13 +00:00
2024-07-06 08:35:29 +00:00
const unsigned int diff = (unsigned int)(mFilePtr - sz);
if (diff) {
std::string name = std::string(sz, diff);
2015-05-19 03:57:13 +00:00
for (std::vector<ASE::Mesh>::iterator it = m_vMeshes.begin();
it != m_vMeshes.end(); ++it) {
if ((*it).mName == name) {
curMesh = &(*it);
2015-05-19 03:57:13 +00:00
break;
}
}
if (!curMesh) {
2015-05-19 03:57:13 +00:00
LogWarning("Encountered unknown mesh in *MESH_SOFTSKINVERTS section");
// Skip the mesh data - until we find a new mesh
// or the end of the *MESH_SOFTSKINVERTS section
while (true) {
2024-07-06 08:35:29 +00:00
SkipSpacesAndLineEnd(&mFilePtr, mEnd);
if (*mFilePtr == '}') {
++mFilePtr;
return;
2024-07-06 08:35:29 +00:00
} else if (!IsNumeric(*mFilePtr))
2015-05-19 03:57:13 +00:00
break;
2024-07-06 08:35:29 +00:00
SkipLine(&mFilePtr, mEnd);
2015-05-19 03:57:13 +00:00
}
} else {
2024-07-06 08:35:29 +00:00
SkipSpacesAndLineEnd(&mFilePtr, mEnd);
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(numVerts);
// Reserve enough storage
curMesh->mBoneVertices.reserve(numVerts);
for (unsigned int i = 0; i < numVerts; ++i) {
2024-07-06 08:35:29 +00:00
SkipSpacesAndLineEnd(&mFilePtr, mEnd);
2015-05-19 03:57:13 +00:00
unsigned int numWeights;
ParseLV4MeshLong(numWeights);
curMesh->mBoneVertices.emplace_back();
ASE::BoneVertex &vert = curMesh->mBoneVertices.back();
2015-05-19 03:57:13 +00:00
// Reserve enough storage
vert.mBoneWeights.reserve(numWeights);
2018-03-20 17:43:54 +00:00
std::string bone;
for (unsigned int w = 0; w < numWeights; ++w) {
2018-03-20 17:43:54 +00:00
bone.clear();
ParseString(bone, "*MESH_SOFTSKINVERTS.Bone");
2015-05-19 03:57:13 +00:00
// Find the bone in the mesh's list
std::pair<int, ai_real> me;
2015-05-19 03:57:13 +00:00
me.first = -1;
for (unsigned int n = 0; n < curMesh->mBones.size(); ++n) {
2018-03-20 17:43:54 +00:00
if (curMesh->mBones[n].mName == bone) {
2015-05-19 03:57:13 +00:00
me.first = n;
break;
}
}
2018-03-20 17:43:54 +00:00
if (-1 == me.first) {
2015-05-19 03:57:13 +00:00
// We don't have this bone yet, so add it to the list
me.first = static_cast<int>(curMesh->mBones.size());
curMesh->mBones.emplace_back(bone);
2015-05-19 03:57:13 +00:00
}
ParseLV4MeshFloat(me.second);
2015-05-19 03:57:13 +00:00
// Add the new bone weight to list
vert.mBoneWeights.push_back(me);
}
}
}
}
}
2024-07-06 08:35:29 +00:00
if (*mFilePtr == '\0')
return;
2024-07-06 08:35:29 +00:00
++mFilePtr;
SkipSpacesAndLineEnd(&mFilePtr, mEnd);
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV1SceneBlock() {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
if (TokenMatch(mFilePtr, "SCENE_BACKGROUND_STATIC", 23))
2015-05-19 03:57:13 +00:00
{
// parse a color triple and assume it is really the bg color
ParseLV4MeshFloatTriple(&m_clrBackground.r);
2015-05-19 03:57:13 +00:00
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "SCENE_AMBIENT_STATIC", 20))
2015-05-19 03:57:13 +00:00
{
// parse a color triple and assume it is really the bg color
ParseLV4MeshFloatTriple(&m_clrAmbient.r);
2015-05-19 03:57:13 +00:00
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "SCENE_FIRSTFRAME", 16)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iFirstFrame);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "SCENE_LASTFRAME", 15)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iLastFrame);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "SCENE_FRAMESPEED", 16)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iFrameSpeed);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "SCENE_TICKSPERFRAME", 19)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iTicksPerFrame);
continue;
}
}
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV1MaterialListBlock() {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iMaterialCount = 0;
unsigned int iOldMaterialCount = (unsigned int)m_vMaterials.size();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
if (TokenMatch(mFilePtr, "MATERIAL_COUNT", 14)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iMaterialCount);
if (UINT_MAX - iOldMaterialCount < iMaterialCount) {
LogWarning("Out of range: material index is too large");
return;
}
2015-05-19 03:57:13 +00:00
// now allocate enough storage to hold all materials
m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID"));
2015-05-19 03:57:13 +00:00
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL", 8)) {
// ensure we have at least one material allocated
if (iMaterialCount == 0) {
LogWarning("*MATERIAL_COUNT unspecified or 0");
iMaterialCount = 1;
m_vMaterials.resize(iOldMaterialCount + iMaterialCount, Material("INVALID"));
}
2015-05-19 03:57:13 +00:00
unsigned int iIndex = 0;
ParseLV4MeshLong(iIndex);
if (iIndex >= iMaterialCount) {
2022-01-24 19:05:25 +00:00
LogWarning("Out of range: material index is too large");
iIndex = iMaterialCount - 1;
2015-05-19 03:57:13 +00:00
}
// get a reference to the material
Material &sMat = m_vMaterials[iIndex + iOldMaterialCount];
2015-05-19 03:57:13 +00:00
// parse the material block
ParseLV2MaterialBlock(sMat);
continue;
}
if( iDepth == 1 ){
// CRUDE HACK: support missing brace after "Ascii Scene Exporter v2.51"
LogWarning("Missing closing brace in material list");
2024-07-06 08:35:29 +00:00
--mFilePtr;
return;
}
2015-05-19 03:57:13 +00:00
}
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV2MaterialBlock(ASE::Material &mat) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iNumSubMaterials = 0;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
if (TokenMatch(mFilePtr, "MATERIAL_NAME", 13)) {
if (!ParseString(mat.mName, "*MATERIAL_NAME"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
continue;
}
// ambient material color
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_AMBIENT", 16)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(&mat.mAmbient.r);
continue;
}
// diffuse material color
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_DIFFUSE", 16)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(&mat.mDiffuse.r);
continue;
}
// specular material color
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_SPECULAR", 17)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(&mat.mSpecular.r);
continue;
}
// material shading type
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_SHADING", 16)) {
if (TokenMatch(mFilePtr, "Blinn", 5)) {
2015-05-19 03:57:13 +00:00
mat.mShading = Discreet3DS::Blinn;
2024-07-06 08:35:29 +00:00
} else if (TokenMatch(mFilePtr, "Phong", 5)) {
2015-05-19 03:57:13 +00:00
mat.mShading = Discreet3DS::Phong;
2024-07-06 08:35:29 +00:00
} else if (TokenMatch(mFilePtr, "Flat", 4)) {
2015-05-19 03:57:13 +00:00
mat.mShading = Discreet3DS::Flat;
2024-07-06 08:35:29 +00:00
} else if (TokenMatch(mFilePtr, "Wire", 4)) {
2015-05-19 03:57:13 +00:00
mat.mShading = Discreet3DS::Wire;
} else {
2015-05-19 03:57:13 +00:00
// assume gouraud shading
mat.mShading = Discreet3DS::Gouraud;
SkipToNextToken();
}
continue;
}
// material transparency
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_TRANSPARENCY", 21)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(mat.mTransparency);
mat.mTransparency = ai_real(1.0) - mat.mTransparency;
continue;
2015-05-19 03:57:13 +00:00
}
// material self illumination
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_SELFILLUM", 18)) {
ai_real f = 0.0;
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(f);
mat.mEmissive.r = f;
mat.mEmissive.g = f;
mat.mEmissive.b = f;
continue;
}
// material shininess
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_SHINE", 14)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(mat.mSpecularExponent);
mat.mSpecularExponent *= 15;
continue;
}
// two-sided material
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_TWOSIDED", 17)) {
2015-05-19 03:57:13 +00:00
mat.mTwoSided = true;
continue;
}
// material shininess strength
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_SHINESTRENGTH", 22)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(mat.mShininessStrength);
continue;
}
// diffuse color map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_DIFFUSE", 11)) {
2015-05-19 03:57:13 +00:00
// parse the texture block
ParseLV3MapBlock(mat.sTexDiffuse);
continue;
}
// ambient color map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_AMBIENT", 11)) {
2015-05-19 03:57:13 +00:00
// parse the texture block
ParseLV3MapBlock(mat.sTexAmbient);
continue;
}
// specular color map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_SPECULAR", 12)) {
2015-05-19 03:57:13 +00:00
// parse the texture block
ParseLV3MapBlock(mat.sTexSpecular);
continue;
}
// opacity map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_OPACITY", 11)) {
2015-05-19 03:57:13 +00:00
// parse the texture block
ParseLV3MapBlock(mat.sTexOpacity);
continue;
}
// emissive map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_SELFILLUM", 13)) {
2015-05-19 03:57:13 +00:00
// parse the texture block
ParseLV3MapBlock(mat.sTexEmissive);
continue;
}
// bump map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_BUMP", 8)) {
2015-05-19 03:57:13 +00:00
// parse the texture block
ParseLV3MapBlock(mat.sTexBump);
}
// specular/shininess map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_SHINESTRENGTH", 17)) {
2015-05-19 03:57:13 +00:00
// parse the texture block
ParseLV3MapBlock(mat.sTexShininess);
continue;
}
// number of submaterials
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "NUMSUBMTLS", 10)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumSubMaterials);
// allocate enough storage
mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL"));
2015-05-19 03:57:13 +00:00
}
// submaterial chunks
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "SUBMATERIAL", 11)) {
// ensure we have at least one material allocated
if (iNumSubMaterials == 0) {
LogWarning("*NUMSUBMTLS unspecified or 0");
iNumSubMaterials = 1;
mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL"));
}
2015-05-19 03:57:13 +00:00
unsigned int iIndex = 0;
ParseLV4MeshLong(iIndex);
if (iIndex >= iNumSubMaterials) {
2015-05-19 03:57:13 +00:00
LogWarning("Out of range: submaterial index is too large");
iIndex = iNumSubMaterials - 1;
2015-05-19 03:57:13 +00:00
}
// get a reference to the material
if (iIndex < mat.avSubMaterials.size()) {
Material &sMat = mat.avSubMaterials[iIndex];
2022-04-27 18:21:30 +00:00
// parse the material block
ParseLV2MaterialBlock(sMat);
}
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("2", "*MATERIAL");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MapBlock(Texture &map) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
// ***********************************************************
// *BITMAP should not be there if *MAP_CLASS is not BITMAP,
// but we need to expect that case ... if the path is
// empty the texture won't be used later.
// ***********************************************************
bool parsePath = true;
2018-03-20 17:43:54 +00:00
std::string temp;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// type of map
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_CLASS", 9)) {
2018-03-20 17:43:54 +00:00
temp.clear();
if (!ParseString(temp, "*MAP_CLASS"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
if (temp != "Bitmap" && temp != "Normal Bump") {
ASSIMP_LOG_WARN("ASE: Skipping unknown map type: ", temp);
2015-05-19 03:57:13 +00:00
parsePath = false;
}
continue;
}
// path to the texture
2024-07-06 08:35:29 +00:00
if (parsePath && TokenMatch(mFilePtr, "BITMAP", 6)) {
if (!ParseString(map.mMapName, "*BITMAP"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
if (map.mMapName == "None") {
2015-05-19 03:57:13 +00:00
// Files with 'None' as map name are produced by
// an Maja to ASE exporter which name I forgot ..
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_WARN("ASE: Skipping invalid map entry");
map.mMapName = std::string();
2015-05-19 03:57:13 +00:00
}
continue;
}
// offset on the u axis
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "UVW_U_OFFSET", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(map.mOffsetU);
continue;
}
// offset on the v axis
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "UVW_V_OFFSET", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(map.mOffsetV);
continue;
}
// tiling on the u axis
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "UVW_U_TILING", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(map.mScaleU);
continue;
}
// tiling on the v axis
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "UVW_V_TILING", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(map.mScaleV);
continue;
}
// rotation around the z-axis
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "UVW_ANGLE", 9)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(map.mRotation);
continue;
}
// map blending factor
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MAP_AMOUNT", 10)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(map.mTextureBlend);
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MAP_XXXXXX");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
bool Parser::ParseString(std::string &out, const char *szName) {
2015-05-19 03:57:13 +00:00
char szBuffer[1024];
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Unexpected EOL", szName);
2015-05-19 03:57:13 +00:00
LogWarning(szBuffer);
return false;
}
// there must be '"'
2024-07-06 08:35:29 +00:00
if ('\"' != *mFilePtr) {
2015-05-19 03:57:13 +00:00
ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected "
"to be enclosed in double quotation marks",
szName);
2015-05-19 03:57:13 +00:00
LogWarning(szBuffer);
return false;
}
2024-07-06 08:35:29 +00:00
++mFilePtr;
const char *sz = mFilePtr;
while (true) {
if ('\"' == *sz)
break;
else if ('\0' == *sz) {
ai_snprintf(szBuffer, 1024, "Unable to parse %s block: Strings are expected to "
"be enclosed in double quotation marks but EOF was reached before "
"a closing quotation mark was encountered",
szName);
2015-05-19 03:57:13 +00:00
LogWarning(szBuffer);
return false;
}
sz++;
}
2024-07-06 08:35:29 +00:00
out = std::string(mFilePtr, (uintptr_t)sz - (uintptr_t)mFilePtr);
mFilePtr = sz + 1;
2015-05-19 03:57:13 +00:00
return true;
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV1ObjectBlock(ASE::BaseNode &node) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// first process common tokens such as node name and transform
// name of the mesh/node
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "NODE_NAME", 9)) {
if (!ParseString(node.mName, "*NODE_NAME"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
continue;
}
// name of the parent of the node
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "NODE_PARENT", 11)) {
if (!ParseString(node.mParent, "*NODE_PARENT"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
continue;
}
// transformation matrix of the node
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "NODE_TM", 7)) {
2015-05-19 03:57:13 +00:00
ParseLV2NodeTransformBlock(node);
continue;
}
// animation data of the node
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "TM_ANIMATION", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV2AnimationBlock(node);
continue;
}
if (node.mType == BaseNode::Light) {
2015-05-19 03:57:13 +00:00
// light settings
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "LIGHT_SETTINGS", 14)) {
ParseLV2LightSettingsBlock((ASE::Light &)node);
2015-05-19 03:57:13 +00:00
continue;
}
// type of the light source
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "LIGHT_TYPE", 10)) {
if (!ASSIMP_strincmp("omni", mFilePtr, 4)) {
((ASE::Light &)node).mLightType = ASE::Light::OMNI;
2024-07-06 08:35:29 +00:00
} else if (!ASSIMP_strincmp("target", mFilePtr, 6)) {
((ASE::Light &)node).mLightType = ASE::Light::TARGET;
2024-07-06 08:35:29 +00:00
} else if (!ASSIMP_strincmp("free", mFilePtr, 4)) {
((ASE::Light &)node).mLightType = ASE::Light::FREE;
2024-07-06 08:35:29 +00:00
} else if (!ASSIMP_strincmp("directional", mFilePtr, 11)) {
((ASE::Light &)node).mLightType = ASE::Light::DIRECTIONAL;
} else {
2015-05-19 03:57:13 +00:00
LogWarning("Unknown kind of light source");
}
continue;
}
} else if (node.mType == BaseNode::Camera) {
2015-05-19 03:57:13 +00:00
// Camera settings
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CAMERA_SETTINGS", 15)) {
ParseLV2CameraSettingsBlock((ASE::Camera &)node);
2015-05-19 03:57:13 +00:00
continue;
2024-07-06 08:35:29 +00:00
} else if (TokenMatch(mFilePtr, "CAMERA_TYPE", 11)) {
if (!ASSIMP_strincmp("target", mFilePtr, 6)) {
((ASE::Camera &)node).mCameraType = ASE::Camera::TARGET;
2024-07-06 08:35:29 +00:00
} else if (!ASSIMP_strincmp("free", mFilePtr, 4)) {
((ASE::Camera &)node).mCameraType = ASE::Camera::FREE;
} else {
2015-05-19 03:57:13 +00:00
LogWarning("Unknown kind of camera");
}
continue;
}
} else if (node.mType == BaseNode::Mesh) {
2015-05-19 03:57:13 +00:00
// mesh data
// FIX: Older files use MESH_SOFTSKIN
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH", 4) ||
TokenMatch(mFilePtr, "MESH_SOFTSKIN", 13)) {
ParseLV2MeshBlock((ASE::Mesh &)node);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh material index
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MATERIAL_REF", 12)) {
ParseLV4MeshLong(((ASE::Mesh &)node).iMaterialIndex);
2015-05-19 03:57:13 +00:00
continue;
}
}
}
AI_ASE_HANDLE_TOP_LEVEL_SECTION();
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV2CameraSettingsBlock(ASE::Camera &camera) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
if (TokenMatch(mFilePtr, "CAMERA_NEAR", 11)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(camera.mNear);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CAMERA_FAR", 10)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(camera.mFar);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CAMERA_FOV", 10)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(camera.mFOV);
continue;
}
}
AI_ASE_HANDLE_SECTION("2", "CAMERA_SETTINGS");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV2LightSettingsBlock(ASE::Light &light) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
if (TokenMatch(mFilePtr, "LIGHT_COLOR", 11)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(&light.mColor.r);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "LIGHT_INTENS", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(light.mIntensity);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "LIGHT_HOTSPOT", 13)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(light.mAngle);
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "LIGHT_FALLOFF", 13)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(light.mFalloff);
continue;
}
}
AI_ASE_HANDLE_SECTION("2", "LIGHT_SETTINGS");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV2AnimationBlock(ASE::BaseNode &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
ASE::Animation *anim = &mesh.mAnim;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
if (TokenMatch(mFilePtr, "NODE_NAME", 9)) {
2015-05-19 03:57:13 +00:00
std::string temp;
if (!ParseString(temp, "*NODE_NAME"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
// If the name of the node contains .target it
// represents an animated camera or spot light
// target.
if (std::string::npos != temp.find(".Target")) {
if ((mesh.mType != BaseNode::Camera || ((ASE::Camera &)mesh).mCameraType != ASE::Camera::TARGET) &&
(mesh.mType != BaseNode::Light || ((ASE::Light &)mesh).mLightType != ASE::Light::TARGET)) {
2015-05-19 03:57:13 +00:00
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_ERROR("ASE: Found target animation channel "
"but the node is neither a camera nor a spot light");
anim = nullptr;
} else
anim = &mesh.mTargetAnim;
2015-05-19 03:57:13 +00:00
}
continue;
}
// position keyframes
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_POS_TRACK", 17) ||
TokenMatch(mFilePtr, "CONTROL_POS_BEZIER", 18) ||
TokenMatch(mFilePtr, "CONTROL_POS_TCB", 15)) {
if (!anim)
SkipSection();
else
ParseLV3PosAnimationBlock(*anim);
2015-05-19 03:57:13 +00:00
continue;
}
// scaling keyframes
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_SCALE_TRACK", 19) ||
TokenMatch(mFilePtr, "CONTROL_SCALE_BEZIER", 20) ||
TokenMatch(mFilePtr, "CONTROL_SCALE_TCB", 17)) {
if (!anim || anim == &mesh.mTargetAnim) {
2015-05-19 03:57:13 +00:00
// Target animation channels may have no rotation channels
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_ERROR("ASE: Ignoring scaling channel in target animation");
2015-05-19 03:57:13 +00:00
SkipSection();
} else
ParseLV3ScaleAnimationBlock(*anim);
2015-05-19 03:57:13 +00:00
continue;
}
// rotation keyframes
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_ROT_TRACK", 17) ||
TokenMatch(mFilePtr, "CONTROL_ROT_BEZIER", 18) ||
TokenMatch(mFilePtr, "CONTROL_ROT_TCB", 15)) {
if (!anim || anim == &mesh.mTargetAnim) {
2015-05-19 03:57:13 +00:00
// Target animation channels may have no rotation channels
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_ERROR("ASE: Ignoring rotation channel in target animation");
2015-05-19 03:57:13 +00:00
SkipSection();
} else
ParseLV3RotAnimationBlock(*anim);
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("2", "TM_ANIMATION");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3ScaleAnimationBlock(ASE::Animation &anim) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iIndex;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
bool b = false;
// For the moment we're just reading the three floats -
// we ignore the additional information for bezier's and TCBs
2015-05-19 03:57:13 +00:00
// simple scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_SCALE_SAMPLE", 20)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mScalingType = ASE::Animation::TRACK;
}
// Bezier scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_BEZIER_SCALE_KEY", 24)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mScalingType = ASE::Animation::BEZIER;
}
// TCB scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_TCB_SCALE_KEY", 21)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mScalingType = ASE::Animation::TCB;
}
if (b) {
anim.akeyScaling.emplace_back();
aiVectorKey &key = anim.akeyScaling.back();
ParseLV4MeshFloatTriple(&key.mValue.x, iIndex);
2015-05-19 03:57:13 +00:00
key.mTime = (double)iIndex;
}
}
AI_ASE_HANDLE_SECTION("3", "*CONTROL_POS_TRACK");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3PosAnimationBlock(ASE::Animation &anim) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iIndex;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
bool b = false;
// For the moment we're just reading the three floats -
// we ignore the additional information for bezier's and TCBs
2015-05-19 03:57:13 +00:00
// simple scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_POS_SAMPLE", 18)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mPositionType = ASE::Animation::TRACK;
}
// Bezier scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_BEZIER_POS_KEY", 22)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mPositionType = ASE::Animation::BEZIER;
}
// TCB scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_TCB_POS_KEY", 19)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mPositionType = ASE::Animation::TCB;
}
if (b) {
anim.akeyPositions.emplace_back();
aiVectorKey &key = anim.akeyPositions.back();
ParseLV4MeshFloatTriple(&key.mValue.x, iIndex);
2015-05-19 03:57:13 +00:00
key.mTime = (double)iIndex;
}
}
AI_ASE_HANDLE_SECTION("3", "*CONTROL_POS_TRACK");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3RotAnimationBlock(ASE::Animation &anim) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iIndex;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
bool b = false;
// For the moment we're just reading the floats -
// we ignore the additional information for bezier's and TCBs
2015-05-19 03:57:13 +00:00
// simple scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_ROT_SAMPLE", 18)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mRotationType = ASE::Animation::TRACK;
}
// Bezier scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_BEZIER_ROT_KEY", 22)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mRotationType = ASE::Animation::BEZIER;
}
// TCB scaling keyframe
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "CONTROL_TCB_ROT_KEY", 19)) {
2015-05-19 03:57:13 +00:00
b = true;
anim.mRotationType = ASE::Animation::TCB;
}
if (b) {
anim.akeyRotations.emplace_back();
aiQuatKey &key = anim.akeyRotations.back();
aiVector3D v;
ai_real f;
ParseLV4MeshFloatTriple(&v.x, iIndex);
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(f);
key.mTime = (double)iIndex;
key.mValue = aiQuaternion(v, f);
2015-05-19 03:57:13 +00:00
}
}
AI_ASE_HANDLE_SECTION("3", "*CONTROL_ROT_TRACK");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
int mode = 0;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// name of the node
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "NODE_NAME", 9)) {
2015-05-19 03:57:13 +00:00
std::string temp;
if (!ParseString(temp, "*NODE_NAME"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
std::string::size_type s;
if (temp == mesh.mName) {
2015-05-19 03:57:13 +00:00
mode = 1;
} else if (std::string::npos != (s = temp.find(".Target")) &&
mesh.mName == temp.substr(0, s)) {
2015-05-19 03:57:13 +00:00
// This should be either a target light or a target camera
if ((mesh.mType == BaseNode::Light && ((ASE::Light &)mesh).mLightType == ASE::Light::TARGET) ||
(mesh.mType == BaseNode::Camera && ((ASE::Camera &)mesh).mCameraType == ASE::Camera::TARGET)) {
2015-05-19 03:57:13 +00:00
mode = 2;
} else {
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_ERROR("ASE: Ignoring target transform, "
"this is no spot light or target camera");
2018-04-19 14:48:43 +00:00
}
} else {
2021-05-13 11:05:31 +00:00
ASSIMP_LOG_ERROR("ASE: Unknown node transformation: ", temp);
2015-05-19 03:57:13 +00:00
// mode = 0
}
continue;
}
if (mode) {
2015-05-19 03:57:13 +00:00
// fourth row of the transformation matrix - and also the
// only information here that is interesting for targets
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "TM_ROW3", 7)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple((mode == 1 ? mesh.mTransform[3] : &mesh.mTargetPosition.x));
continue;
}
if (mode == 1) {
2015-05-19 03:57:13 +00:00
// first row of the transformation matrix
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "TM_ROW0", 7)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(mesh.mTransform[0]);
continue;
}
// second row of the transformation matrix
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "TM_ROW1", 7)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(mesh.mTransform[1]);
continue;
}
// third row of the transformation matrix
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "TM_ROW2", 7)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(mesh.mTransform[2]);
continue;
}
// inherited position axes
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "INHERIT_POS", 11)) {
2015-05-19 03:57:13 +00:00
unsigned int aiVal[3];
ParseLV4MeshLongTriple(aiVal);
for (unsigned int i = 0; i < 3; ++i)
2015-05-19 03:57:13 +00:00
mesh.inherit.abInheritPosition[i] = aiVal[i] != 0;
continue;
}
// inherited rotation axes
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "INHERIT_ROT", 11)) {
2015-05-19 03:57:13 +00:00
unsigned int aiVal[3];
ParseLV4MeshLongTriple(aiVal);
for (unsigned int i = 0; i < 3; ++i)
2015-05-19 03:57:13 +00:00
mesh.inherit.abInheritRotation[i] = aiVal[i] != 0;
continue;
}
// inherited scaling axes
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "INHERIT_SCL", 11)) {
2015-05-19 03:57:13 +00:00
unsigned int aiVal[3];
ParseLV4MeshLongTriple(aiVal);
for (unsigned int i = 0; i < 3; ++i)
2015-05-19 03:57:13 +00:00
mesh.inherit.abInheritScaling[i] = aiVal[i] != 0;
continue;
}
}
}
}
AI_ASE_HANDLE_SECTION("2", "*NODE_TM");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV2MeshBlock(ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iNumVertices = 0;
unsigned int iNumFaces = 0;
unsigned int iNumTVertices = 0;
unsigned int iNumTFaces = 0;
unsigned int iNumCVertices = 0;
unsigned int iNumCFaces = 0;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Number of vertices in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMVERTEX", 14)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumVertices);
continue;
}
// Number of texture coordinates in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMTVERTEX", 15)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumTVertices);
continue;
}
// Number of vertex colors in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMCVERTEX", 15)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumCVertices);
continue;
}
// Number of regular faces in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMFACES", 13)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumFaces);
continue;
}
// Number of UVWed faces in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMTVFACES", 15)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumTFaces);
continue;
}
// Number of colored faces in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMCVFACES", 15)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumCFaces);
continue;
}
// mesh vertex list block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_VERTEX_LIST", 16)) {
ParseLV3MeshVertexListBlock(iNumVertices, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh face list block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_FACE_LIST", 14)) {
ParseLV3MeshFaceListBlock(iNumFaces, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh texture vertex list block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_TVERTLIST", 14)) {
ParseLV3MeshTListBlock(iNumTVertices, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh texture face block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_TFACELIST", 14)) {
ParseLV3MeshTFaceListBlock(iNumTFaces, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh color vertex list block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_CVERTLIST", 14)) {
ParseLV3MeshCListBlock(iNumCVertices, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh color face block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_CFACELIST", 14)) {
ParseLV3MeshCFaceListBlock(iNumCFaces, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh normals
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NORMALS", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV3MeshNormalListBlock(mesh);
continue;
}
// another mesh UV channel ...
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_MAPPINGCHANNEL", 19)) {
unsigned int iIndex(0);
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iIndex);
if (0 == iIndex) {
LogWarning("Mapping channel has an invalid index. Skipping UV channel");
2015-05-19 03:57:13 +00:00
// skip it ...
SkipSection();
} else {
if (iIndex < 2) {
LogWarning("Mapping channel has an invalid index. Skipping UV channel");
// skip it ...
SkipSection();
}
if (iIndex > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
LogWarning("Too many UV channels specified. Skipping channel ..");
// skip it ...
SkipSection();
} else {
// parse the mapping channel
ParseLV3MappingChannel(iIndex - 1, mesh);
}
continue;
2015-05-19 03:57:13 +00:00
}
}
// mesh animation keyframe. Not supported
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_ANIMATION", 14)) {
2015-05-19 03:57:13 +00:00
LogWarning("Found *MESH_ANIMATION element in ASE/ASK file. "
"Keyframe animation is not supported by Assimp, this element "
"will be ignored");
2015-05-19 03:57:13 +00:00
//SkipSection();
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_WEIGHTS", 12)) {
ParseLV3MeshWeightsBlock(mesh);
continue;
2015-05-19 03:57:13 +00:00
}
}
AI_ASE_HANDLE_SECTION("2", "*MESH");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iNumVertices = 0, iNumBones = 0;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Number of bone vertices ...
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMVERTEX", 14)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumVertices);
continue;
}
// Number of bones
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMBONE", 12)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumBones);
continue;
}
// parse the list of bones
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_BONE_LIST", 14)) {
ParseLV4MeshBones(iNumBones, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
// parse the list of bones vertices
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_BONE_VERTEX_LIST", 21)) {
ParseLV4MeshBonesVertices(iNumVertices, mesh);
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_WEIGHTS");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshBones(unsigned int iNumBones, ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
mesh.mBones.resize(iNumBones, Bone("UNNAMED"));
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Mesh bone with name ...
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_BONE_NAME", 14)) {
2015-05-19 03:57:13 +00:00
// parse an index ...
2024-07-06 08:35:29 +00:00
if (SkipSpaces(&mFilePtr, mEnd)) {
unsigned int iIndex = strtoul10(mFilePtr, &mFilePtr);
if (iIndex >= iNumBones) {
2015-05-19 03:57:13 +00:00
LogWarning("Bone index is out of bounds");
continue;
}
if (!ParseString(mesh.mBones[iIndex].mName, "*MESH_BONE_NAME"))
2015-05-19 03:57:13 +00:00
SkipToNextToken();
continue;
}
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_BONE_LIST");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshBonesVertices(unsigned int iNumVertices, ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
mesh.mBoneVertices.resize(iNumVertices);
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Mesh bone vertex
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_BONE_VERTEX", 16)) {
2015-05-19 03:57:13 +00:00
// read the vertex index
2024-07-06 08:35:29 +00:00
unsigned int iIndex = strtoul10(mFilePtr, &mFilePtr);
if (iIndex >= mesh.mPositions.size()) {
iIndex = (unsigned int)mesh.mPositions.size() - 1;
2015-05-19 03:57:13 +00:00
LogWarning("Bone vertex index is out of bounds. Using the largest valid "
"bone vertex index instead");
2015-05-19 03:57:13 +00:00
}
// --- ignored
ai_real afVert[3];
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloatTriple(afVert);
std::pair<int, float> pairOut;
while (true) {
2015-05-19 03:57:13 +00:00
// first parse the bone index ...
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) break;
pairOut.first = strtoul10(mFilePtr, &mFilePtr);
2015-05-19 03:57:13 +00:00
// then parse the vertex weight
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) break;
mFilePtr = fast_atoreal_move<float>(mFilePtr, pairOut.second);
2015-05-19 03:57:13 +00:00
// -1 marks unused entries
if (-1 != pairOut.first) {
2015-05-19 03:57:13 +00:00
mesh.mBoneVertices[iIndex].mBoneWeights.push_back(pairOut);
}
}
continue;
}
}
AI_ASE_HANDLE_SECTION("4", "*MESH_BONE_VERTEX");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshVertexListBlock(
unsigned int iNumVertices, ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
// allocate enough storage in the array
mesh.mPositions.resize(iNumVertices);
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Vertex entry
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_VERTEX", 11)) {
2015-05-19 03:57:13 +00:00
aiVector3D vTemp;
unsigned int iIndex;
ParseLV4MeshFloatTriple(&vTemp.x, iIndex);
2015-05-19 03:57:13 +00:00
if (iIndex >= iNumVertices) {
2015-05-19 03:57:13 +00:00
LogWarning("Invalid vertex index. It will be ignored");
} else
mesh.mPositions[iIndex] = vTemp;
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_VERTEX_LIST");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
// allocate enough storage in the face array
mesh.mFaces.resize(iNumFaces);
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Face entry
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_FACE", 9)) {
2015-05-19 03:57:13 +00:00
ASE::Face mFace;
ParseLV4MeshFace(mFace);
if (mFace.iFace >= iNumFaces) {
2015-05-19 03:57:13 +00:00
LogWarning("Face has an invalid index. It will be ignored");
} else
mesh.mFaces[mFace.iFace] = mFace;
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_FACE_LIST");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshTListBlock(unsigned int iNumVertices,
ASE::Mesh &mesh, unsigned int iChannel) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
// allocate enough storage in the array
mesh.amTexCoords[iChannel].resize(iNumVertices);
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Vertex entry
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_TVERT", 10)) {
2015-05-19 03:57:13 +00:00
aiVector3D vTemp;
unsigned int iIndex;
ParseLV4MeshFloatTriple(&vTemp.x, iIndex);
2015-05-19 03:57:13 +00:00
if (iIndex >= iNumVertices) {
2015-05-19 03:57:13 +00:00
LogWarning("Tvertex has an invalid index. It will be ignored");
} else
mesh.amTexCoords[iChannel][iIndex] = vTemp;
2015-05-19 03:57:13 +00:00
if (0.0f != vTemp.z) {
2015-05-19 03:57:13 +00:00
// we need 3 coordinate channels
mesh.mNumUVComponents[iChannel] = 3;
}
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_TVERT_LIST");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshTFaceListBlock(unsigned int iNumFaces,
ASE::Mesh &mesh, unsigned int iChannel) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Face entry
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_TFACE", 10)) {
2015-05-19 03:57:13 +00:00
unsigned int aiValues[3];
unsigned int iIndex = 0;
ParseLV4MeshLongTriple(aiValues, iIndex);
if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) {
2015-05-19 03:57:13 +00:00
LogWarning("UV-Face has an invalid index. It will be ignored");
} else {
2015-05-19 03:57:13 +00:00
// copy UV indices
mesh.mFaces[iIndex].amUVIndices[iChannel][0] = aiValues[0];
mesh.mFaces[iIndex].amUVIndices[iChannel][1] = aiValues[1];
mesh.mFaces[iIndex].amUVIndices[iChannel][2] = aiValues[2];
}
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_TFACE_LIST");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MappingChannel(unsigned int iChannel, ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
unsigned int iNumTVertices = 0;
unsigned int iNumTFaces = 0;
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Number of texture coordinates in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMTVERTEX", 15)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumTVertices);
continue;
}
// Number of UVWed faces in the mesh
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_NUMTVFACES", 15)) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(iNumTFaces);
continue;
}
// mesh texture vertex list block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_TVERTLIST", 14)) {
ParseLV3MeshTListBlock(iNumTVertices, mesh, iChannel);
2015-05-19 03:57:13 +00:00
continue;
}
// mesh texture face block
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_TFACELIST", 14)) {
ParseLV3MeshTFaceListBlock(iNumTFaces, mesh, iChannel);
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_MAPPING_CHANNEL");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshCListBlock(unsigned int iNumVertices, ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
// allocate enough storage in the array
mesh.mVertexColors.resize(iNumVertices);
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Vertex entry
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_VERTCOL", 12)) {
2015-05-19 03:57:13 +00:00
aiColor4D vTemp;
vTemp.a = 1.0f;
unsigned int iIndex;
ParseLV4MeshFloatTriple(&vTemp.r, iIndex);
2015-05-19 03:57:13 +00:00
if (iIndex >= iNumVertices) {
2015-05-19 03:57:13 +00:00
LogWarning("Vertex color has an invalid index. It will be ignored");
} else
mesh.mVertexColors[iIndex] = vTemp;
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_CVERTEX_LIST");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshCFaceListBlock(unsigned int iNumFaces, ASE::Mesh &mesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
2015-05-19 03:57:13 +00:00
// Face entry
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_CFACE", 10)) {
2015-05-19 03:57:13 +00:00
unsigned int aiValues[3];
unsigned int iIndex = 0;
ParseLV4MeshLongTriple(aiValues, iIndex);
if (iIndex >= iNumFaces || iIndex >= mesh.mFaces.size()) {
2015-05-19 03:57:13 +00:00
LogWarning("UV-Face has an invalid index. It will be ignored");
} else {
2015-05-19 03:57:13 +00:00
// copy color indices
mesh.mFaces[iIndex].mColorIndices[0] = aiValues[0];
mesh.mFaces[iIndex].mColorIndices[1] = aiValues[1];
mesh.mFaces[iIndex].mColorIndices[2] = aiValues[2];
}
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_CFACE_LIST");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh &sMesh) {
2015-05-19 03:57:13 +00:00
AI_ASE_PARSER_INIT();
// Allocate enough storage for the normals
sMesh.mNormals.resize(sMesh.mFaces.size() * 3, aiVector3D(0.f, 0.f, 0.f));
2015-05-19 03:57:13 +00:00
unsigned int index, faceIdx = UINT_MAX;
// FIXME: rewrite this and find out how to interpret the normals
// correctly. This is crap.
// Smooth the vertex and face normals together. The result
// will be edgy then, but otherwise everything would be soft ...
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
++mFilePtr;
if (faceIdx != UINT_MAX && TokenMatch(mFilePtr, "MESH_VERTEXNORMAL", 17)) {
2015-05-19 03:57:13 +00:00
aiVector3D vNormal;
ParseLV4MeshFloatTriple(&vNormal.x, index);
if (faceIdx >= sMesh.mFaces.size())
2015-05-19 03:57:13 +00:00
continue;
// Make sure we assign it to the correct face
const ASE::Face &face = sMesh.mFaces[faceIdx];
2015-05-19 03:57:13 +00:00
if (index == face.mIndices[0])
index = 0;
else if (index == face.mIndices[1])
index = 1;
else if (index == face.mIndices[2])
index = 2;
else {
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
2015-05-19 03:57:13 +00:00
continue;
}
// We'll renormalize later
sMesh.mNormals[faceIdx * 3 + index] += vNormal;
2015-05-19 03:57:13 +00:00
continue;
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "MESH_FACENORMAL", 15)) {
2015-05-19 03:57:13 +00:00
aiVector3D vNormal;
ParseLV4MeshFloatTriple(&vNormal.x, faceIdx);
2015-05-19 03:57:13 +00:00
if (faceIdx >= sMesh.mFaces.size()) {
2018-04-19 14:48:43 +00:00
ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_FACENORMAL section");
2015-05-19 03:57:13 +00:00
continue;
}
// We'll renormalize later
sMesh.mNormals[faceIdx * 3] += vNormal;
sMesh.mNormals[faceIdx * 3 + 1] += vNormal;
sMesh.mNormals[faceIdx * 3 + 2] += vNormal;
2015-05-19 03:57:13 +00:00
continue;
}
}
AI_ASE_HANDLE_SECTION("3", "*MESH_NORMALS");
2015-05-19 03:57:13 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFace(ASE::Face &out) {
2015-05-19 03:57:13 +00:00
// skip spaces and tabs
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL [#1]");
SkipToNextToken();
return;
}
// parse the face index
2024-07-06 08:35:29 +00:00
out.iFace = strtoul10(mFilePtr, &mFilePtr);
2015-05-19 03:57:13 +00:00
// next character should be ':'
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
// FIX: there are some ASE files which haven't got : here ....
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. \':\' expected [#2]");
SkipToNextToken();
return;
}
// FIX: There are some ASE files which haven't got ':' here
2024-07-06 08:35:29 +00:00
if (':' == *mFilePtr) ++mFilePtr;
2015-05-19 03:57:13 +00:00
// Parse all mesh indices
for (unsigned int i = 0; i < 3; ++i) {
2015-05-19 03:57:13 +00:00
unsigned int iIndex = 0;
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL");
SkipToNextToken();
return;
}
2024-07-06 08:35:29 +00:00
switch (*mFilePtr) {
2015-05-19 03:57:13 +00:00
case 'A':
case 'a':
break;
case 'B':
case 'b':
iIndex = 1;
break;
case 'C':
case 'c':
iIndex = 2;
break;
default:
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
"A,B or C expected [#3]");
2015-05-19 03:57:13 +00:00
SkipToNextToken();
return;
};
2024-07-06 08:35:29 +00:00
++mFilePtr;
2015-05-19 03:57:13 +00:00
// next character should be ':'
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd) || ':' != *mFilePtr) {
2015-05-19 03:57:13 +00:00
LogWarning("Unable to parse *MESH_FACE Element: "
"Unexpected EOL. \':\' expected [#2]");
2015-05-19 03:57:13 +00:00
SkipToNextToken();
return;
}
2024-07-06 08:35:29 +00:00
++mFilePtr;
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
LogWarning("Unable to parse *MESH_FACE Element: Unexpected EOL. "
"Vertex index expected [#4]");
2015-05-19 03:57:13 +00:00
SkipToNextToken();
return;
}
2024-07-06 08:35:29 +00:00
out.mIndices[iIndex] = strtoul10(mFilePtr, &mFilePtr);
2015-05-19 03:57:13 +00:00
}
// now we need to skip the AB, BC, CA blocks.
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) break;
if (IsLineEnd(*mFilePtr)) {
2015-05-19 03:57:13 +00:00
//iLineNumber++;
return;
}
2024-07-06 08:35:29 +00:00
mFilePtr++;
2015-05-19 03:57:13 +00:00
}
// parse the smoothing group of the face
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "*MESH_SMOOTHING", 15)) {
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
LogWarning("Unable to parse *MESH_SMOOTHING Element: "
"Unexpected EOL. Smoothing group(s) expected [#5]");
2015-05-19 03:57:13 +00:00
SkipToNextToken();
return;
}
// Parse smoothing groups until we don't anymore see commas
// FIX: There needn't always be a value, sad but true
while (true) {
2024-07-06 08:35:29 +00:00
if (*mFilePtr < '9' && *mFilePtr >= '0') {
uint32_t value = strtoul10(mFilePtr, &mFilePtr);
if (value < 32) {
2024-07-06 08:35:29 +00:00
out.iSmoothGroup |= (1 << strtoul10(mFilePtr, &mFilePtr));
} else {
const std::string message = std::string("Unable to set smooth group, value with ") + ai_to_string(value) + std::string(" out of range");
LogWarning(message.c_str());
}
2015-05-19 03:57:13 +00:00
}
2024-07-06 08:35:29 +00:00
SkipSpaces(&mFilePtr, mEnd);
if (',' != *mFilePtr) {
2015-05-19 03:57:13 +00:00
break;
}
2024-07-06 08:35:29 +00:00
++mFilePtr;
SkipSpaces(&mFilePtr, mEnd);
2015-05-19 03:57:13 +00:00
}
}
// *MESH_MTLID is optional, too
while (true) {
2024-07-06 08:35:29 +00:00
if ('*' == *mFilePtr) {
2022-01-24 19:05:25 +00:00
break;
}
2024-07-06 08:35:29 +00:00
if (IsLineEnd(*mFilePtr)) {
2015-05-19 03:57:13 +00:00
return;
}
2024-07-06 08:35:29 +00:00
mFilePtr++;
2015-05-19 03:57:13 +00:00
}
2024-07-06 08:35:29 +00:00
if (TokenMatch(mFilePtr, "*MESH_MTLID", 11)) {
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
LogWarning("Unable to parse *MESH_MTLID Element: Unexpected EOL. "
"Material index expected [#6]");
2015-05-19 03:57:13 +00:00
SkipToNextToken();
return;
}
2024-07-06 08:35:29 +00:00
out.iMaterial = strtoul10(mFilePtr, &mFilePtr);
2015-05-19 03:57:13 +00:00
}
return;
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshLongTriple(unsigned int *apOut) {
ai_assert(nullptr != apOut);
for (unsigned int i = 0; i < 3; ++i)
2015-05-19 03:57:13 +00:00
ParseLV4MeshLong(apOut[i]);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshLongTriple(unsigned int *apOut, unsigned int &rIndexOut) {
ai_assert(nullptr != apOut);
2015-05-19 03:57:13 +00:00
// parse the index
ParseLV4MeshLong(rIndexOut);
2015-05-19 03:57:13 +00:00
// parse the three others
ParseLV4MeshLongTriple(apOut);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut) {
ai_assert(nullptr != apOut);
2015-05-19 03:57:13 +00:00
// parse the index
ParseLV4MeshLong(rIndexOut);
2015-05-19 03:52:10 +00:00
2015-05-19 03:57:13 +00:00
// parse the three others
ParseLV4MeshFloatTriple(apOut);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) {
ai_assert(nullptr != apOut);
2022-01-24 19:05:25 +00:00
for (unsigned int i = 0; i < 3; ++i) {
2015-05-19 03:57:13 +00:00
ParseLV4MeshFloat(apOut[i]);
2022-01-24 19:05:25 +00:00
}
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloat(ai_real &fOut) {
2015-05-19 03:57:13 +00:00
// skip spaces and tabs
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
// LOG
LogWarning("Unable to parse float: unexpected EOL [#1]");
fOut = 0.0;
2015-05-19 03:57:13 +00:00
++iLineNumber;
return;
}
// parse the first float
2024-07-06 08:35:29 +00:00
mFilePtr = fast_atoreal_move<ai_real>(mFilePtr, fOut);
}
// ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshLong(unsigned int &iOut) {
2015-05-19 03:57:13 +00:00
// Skip spaces and tabs
2024-07-06 08:35:29 +00:00
if (!SkipSpaces(&mFilePtr, mEnd)) {
2015-05-19 03:57:13 +00:00
// LOG
LogWarning("Unable to parse long: unexpected EOL [#1]");
iOut = 0;
++iLineNumber;
return;
}
// parse the value
2024-07-06 08:35:29 +00:00
iOut = strtoul10(mFilePtr, &mFilePtr);
}
2023-11-11 20:13:47 +00:00
}
#endif // ASSIMP_BUILD_NO_3DS_IMPORTER
#endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER