Merge branch 'master' into gltf_binary
commit
90ff723b6c
|
@ -115,15 +115,12 @@ BlenderImporter::~BlenderImporter() {
|
||||||
delete modifier_cache;
|
delete modifier_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * const Tokens[] = { "BLENDER" };
|
static const char Token[] = "BLENDER";
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||||
// note: this won't catch compressed files
|
return ParseMagicToken(pFile, pIOHandler).error.empty();
|
||||||
static const char *tokens[] = { "<BLENDER", "blender" };
|
|
||||||
|
|
||||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -142,63 +139,21 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void BlenderImporter::InternReadFile(const std::string &pFile,
|
void BlenderImporter::InternReadFile(const std::string &pFile,
|
||||||
aiScene *pScene, IOSystem *pIOHandler) {
|
aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
|
||||||
std::vector<char> uncompressed;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FileDatabase file;
|
FileDatabase file;
|
||||||
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
|
||||||
if (!stream) {
|
if (!streamOrError.error.empty()) {
|
||||||
ThrowException("Could not open file for reading");
|
ThrowException(streamOrError.error);
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
|
||||||
|
|
||||||
char magic[8] = { 0 };
|
char version[4] = { 0 };
|
||||||
stream->Read(magic, 7, 1);
|
file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
|
||||||
if (strcmp(magic, Tokens[0])) {
|
file.little = (stream->Read(version, 1, 1), version[0] == 'v');
|
||||||
// Check for presence of the gzip header. If yes, assume it is a
|
|
||||||
// compressed blend file and try uncompressing it, else fail. This is to
|
|
||||||
// avoid uncompressing random files which our loader might end up with.
|
|
||||||
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
|
||||||
ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
|
|
||||||
#else
|
|
||||||
if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
|
|
||||||
ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
|
|
||||||
}
|
|
||||||
|
|
||||||
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
|
stream->Read(version, 3, 1);
|
||||||
if (magic[2] != 8) {
|
version[3] = '\0';
|
||||||
ThrowException("Unsupported GZIP compression method");
|
|
||||||
}
|
|
||||||
|
|
||||||
// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
|
LogInfo("Blender version is ", version[0], ".", version + 1,
|
||||||
stream->Seek(0L, aiOrigin_SET);
|
|
||||||
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
|
|
||||||
|
|
||||||
size_t total = 0;
|
|
||||||
Compression compression;
|
|
||||||
if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
|
|
||||||
total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed);
|
|
||||||
compression.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace the input stream with a memory stream
|
|
||||||
stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed.data()), total);
|
|
||||||
|
|
||||||
// .. and retry
|
|
||||||
stream->Read(magic, 7, 1);
|
|
||||||
if (strcmp(magic, "BLENDER")) {
|
|
||||||
ThrowException("Found no BLENDER magic word in decompressed GZIP file");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
file.i64bit = (stream->Read(magic, 1, 1), magic[0] == '-');
|
|
||||||
file.little = (stream->Read(magic, 1, 1), magic[0] == 'v');
|
|
||||||
|
|
||||||
stream->Read(magic, 3, 1);
|
|
||||||
magic[3] = '\0';
|
|
||||||
|
|
||||||
LogInfo("Blender version is ", magic[0], ".", magic + 1,
|
|
||||||
" (64bit: ", file.i64bit ? "true" : "false",
|
" (64bit: ", file.i64bit ? "true" : "false",
|
||||||
", little endian: ", file.little ? "true" : "false", ")");
|
", little endian: ", file.little ? "true" : "false", ")");
|
||||||
|
|
||||||
|
@ -1338,4 +1293,55 @@ aiNode *BlenderImporter::ConvertNode(const Scene &in, const Object *obj, Convers
|
||||||
return node.release();
|
return node.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlenderImporter::StreamOrError BlenderImporter::ParseMagicToken(const std::string &pFile, IOSystem *pIOHandler) const {
|
||||||
|
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
||||||
|
if (stream == nullptr) {
|
||||||
|
return {{}, {}, "Could not open file for reading"};
|
||||||
|
}
|
||||||
|
|
||||||
|
char magic[8] = { 0 };
|
||||||
|
stream->Read(magic, 7, 1);
|
||||||
|
if (strcmp(magic, Token) == 0) {
|
||||||
|
return {stream, {}, {}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for presence of the gzip header. If yes, assume it is a
|
||||||
|
// compressed blend file and try uncompressing it, else fail. This is to
|
||||||
|
// avoid uncompressing random files which our loader might end up with.
|
||||||
|
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
||||||
|
return {{}, {}, "BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"};
|
||||||
|
#else
|
||||||
|
if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
|
||||||
|
return {{}, {}, "BLENDER magic bytes are missing, couldn't find GZIP header either"};
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
|
||||||
|
if (magic[2] != 8) {
|
||||||
|
return {{}, {}, "Unsupported GZIP compression method"};
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
|
||||||
|
stream->Seek(0L, aiOrigin_SET);
|
||||||
|
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
|
||||||
|
|
||||||
|
size_t total = 0;
|
||||||
|
Compression compression;
|
||||||
|
auto uncompressed = std::make_shared<std::vector<char>>();
|
||||||
|
if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
|
||||||
|
total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), *uncompressed);
|
||||||
|
compression.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace the input stream with a memory stream
|
||||||
|
stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed->data()), total);
|
||||||
|
|
||||||
|
// .. and retry
|
||||||
|
stream->Read(magic, 7, 1);
|
||||||
|
if (strcmp(magic, Token) == 0) {
|
||||||
|
return {stream, uncompressed, {}};
|
||||||
|
}
|
||||||
|
return {{}, {}, "Found no BLENDER magic word in decompressed GZIP file"};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||||
|
|
|
@ -180,6 +180,19 @@ private:
|
||||||
const Blender::MTex *tex,
|
const Blender::MTex *tex,
|
||||||
Blender::ConversionData &conv_data);
|
Blender::ConversionData &conv_data);
|
||||||
|
|
||||||
|
// TODO: Move to a std::variant, once c++17 is supported.
|
||||||
|
struct StreamOrError {
|
||||||
|
std::shared_ptr<IOStream> stream;
|
||||||
|
std::shared_ptr<std::vector<char>> input;
|
||||||
|
std::string error;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns either a stream (and optional input data for the stream) or
|
||||||
|
// an error if it can't parse the magic token.
|
||||||
|
StreamOrError ParseMagicToken(
|
||||||
|
const std::string &pFile,
|
||||||
|
IOSystem *pIOHandler) const;
|
||||||
|
|
||||||
private: // static stuff, mostly logging and error reporting.
|
private: // static stuff, mostly logging and error reporting.
|
||||||
// --------------------
|
// --------------------
|
||||||
static void CheckActualType(const Blender::ElemBase *dt,
|
static void CheckActualType(const Blender::ElemBase *dt,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/StringUtils.h>
|
#include <assimp/StringUtils.h>
|
||||||
#include <assimp/anim.h>
|
#include <assimp/anim.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** Irr importer class.
|
/** Irr importer class.
|
||||||
|
@ -71,13 +71,13 @@ public:
|
||||||
/** Returns whether the class can handle the format of the given file.
|
/** Returns whether the class can handle the format of the given file.
|
||||||
* See BaseImporter::CanRead() for details.
|
* See BaseImporter::CanRead() for details.
|
||||||
*/
|
*/
|
||||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
|
||||||
bool checkSig) const override;
|
bool checkSig) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const aiImporterDesc* GetInfo () const override;
|
const aiImporterDesc *GetInfo() const override;
|
||||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
|
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||||
void SetupProperties(const Importer* pImp) override;
|
void SetupProperties(const Importer *pImp) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Data structure for a scene-graph node animator
|
/** Data structure for a scene-graph node animator
|
||||||
|
@ -85,27 +85,19 @@ private:
|
||||||
struct Animator {
|
struct Animator {
|
||||||
// Type of the animator
|
// Type of the animator
|
||||||
enum AT {
|
enum AT {
|
||||||
UNKNOWN = 0x0,
|
UNKNOWN = 0x0,
|
||||||
ROTATION = 0x1,
|
ROTATION = 0x1,
|
||||||
FLY_CIRCLE = 0x2,
|
FLY_CIRCLE = 0x2,
|
||||||
FLY_STRAIGHT = 0x3,
|
FLY_STRAIGHT = 0x3,
|
||||||
FOLLOW_SPLINE = 0x4,
|
FOLLOW_SPLINE = 0x4,
|
||||||
OTHER = 0x5
|
OTHER = 0x5
|
||||||
|
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
explicit Animator(AT t = UNKNOWN)
|
explicit Animator(AT t = UNKNOWN) :
|
||||||
: type (t)
|
type(t), speed(ai_real(0.001)), direction(ai_real(0.0), ai_real(1.0), ai_real(0.0)), circleRadius(ai_real(1.0)), tightness(ai_real(0.5)), loop(true), timeForWay(100) {
|
||||||
, speed ( ai_real( 0.001 ) )
|
|
||||||
, direction ( ai_real( 0.0 ), ai_real( 1.0 ), ai_real( 0.0 ) )
|
|
||||||
, circleRadius ( ai_real( 1.0) )
|
|
||||||
, tightness ( ai_real( 0.5 ) )
|
|
||||||
, loop (true)
|
|
||||||
, timeForWay (100)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// common parameters
|
// common parameters
|
||||||
ai_real speed;
|
ai_real speed;
|
||||||
aiVector3D direction;
|
aiVector3D direction;
|
||||||
|
@ -128,11 +120,9 @@ private:
|
||||||
|
|
||||||
/** Data structure for a scene-graph node in an IRR file
|
/** Data structure for a scene-graph node in an IRR file
|
||||||
*/
|
*/
|
||||||
struct Node
|
struct Node {
|
||||||
{
|
|
||||||
// Type of the node
|
// Type of the node
|
||||||
enum ET
|
enum ET {
|
||||||
{
|
|
||||||
LIGHT,
|
LIGHT,
|
||||||
CUBE,
|
CUBE,
|
||||||
MESH,
|
MESH,
|
||||||
|
@ -144,21 +134,20 @@ private:
|
||||||
ANIMMESH
|
ANIMMESH
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
explicit Node(ET t)
|
explicit Node(ET t) :
|
||||||
: type (t)
|
type(t), scaling(1.0, 1.0, 1.0) // assume uniform scaling by default
|
||||||
, scaling (1.0,1.0,1.0) // assume uniform scaling by default
|
,
|
||||||
, parent()
|
parent(),
|
||||||
, framesPerSecond (0.0)
|
framesPerSecond(0.0),
|
||||||
, id()
|
id(),
|
||||||
, sphereRadius (1.0)
|
sphereRadius(1.0),
|
||||||
, spherePolyCountX (100)
|
spherePolyCountX(100),
|
||||||
, spherePolyCountY (100)
|
spherePolyCountY(100) {
|
||||||
{
|
|
||||||
|
|
||||||
// Generate a default name for the node
|
// Generate a default name for the node
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
static int cnt;
|
static int cnt;
|
||||||
ai_snprintf(buffer, 128, "IrrNode_%i",cnt++);
|
ai_snprintf(buffer, 128, "IrrNode_%i", cnt++);
|
||||||
name = std::string(buffer);
|
name = std::string(buffer);
|
||||||
|
|
||||||
// reserve space for up to 5 materials
|
// reserve space for up to 5 materials
|
||||||
|
@ -175,10 +164,10 @@ private:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
// List of all child nodes
|
// List of all child nodes
|
||||||
std::vector<Node*> children;
|
std::vector<Node *> children;
|
||||||
|
|
||||||
// Parent node
|
// Parent node
|
||||||
Node* parent;
|
Node *parent;
|
||||||
|
|
||||||
// Animated meshes: frames per second
|
// Animated meshes: frames per second
|
||||||
// 0.f if not specified
|
// 0.f if not specified
|
||||||
|
@ -190,13 +179,13 @@ private:
|
||||||
|
|
||||||
// Meshes: List of materials to be assigned
|
// Meshes: List of materials to be assigned
|
||||||
// along with their corresponding material flags
|
// along with their corresponding material flags
|
||||||
std::vector< std::pair<aiMaterial*, unsigned int> > materials;
|
std::vector<std::pair<aiMaterial *, unsigned int>> materials;
|
||||||
|
|
||||||
// Spheres: radius of the sphere to be generates
|
// Spheres: radius of the sphere to be generates
|
||||||
ai_real sphereRadius;
|
ai_real sphereRadius;
|
||||||
|
|
||||||
// Spheres: Number of polygons in the x,y direction
|
// Spheres: Number of polygons in the x,y direction
|
||||||
unsigned int spherePolyCountX,spherePolyCountY;
|
unsigned int spherePolyCountX, spherePolyCountY;
|
||||||
|
|
||||||
// List of all animators assigned to the node
|
// List of all animators assigned to the node
|
||||||
std::list<Animator> animators;
|
std::list<Animator> animators;
|
||||||
|
@ -204,40 +193,54 @@ private:
|
||||||
|
|
||||||
/** Data structure for a vertex in an IRR skybox
|
/** Data structure for a vertex in an IRR skybox
|
||||||
*/
|
*/
|
||||||
struct SkyboxVertex
|
struct SkyboxVertex {
|
||||||
{
|
|
||||||
SkyboxVertex() = default;
|
SkyboxVertex() = default;
|
||||||
|
|
||||||
//! Construction from single vertex components
|
//! Construction from single vertex components
|
||||||
SkyboxVertex(ai_real px, ai_real py, ai_real pz,
|
SkyboxVertex(ai_real px, ai_real py, ai_real pz,
|
||||||
ai_real nx, ai_real ny, ai_real nz,
|
ai_real nx, ai_real ny, ai_real nz,
|
||||||
ai_real uvx, ai_real uvy)
|
ai_real uvx, ai_real uvy)
|
||||||
|
|
||||||
: position (px,py,pz)
|
:
|
||||||
, normal (nx,ny,nz)
|
position(px, py, pz), normal(nx, ny, nz), uv(uvx, uvy, 0.0) {}
|
||||||
, uv (uvx,uvy,0.0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
aiVector3D position, normal, uv;
|
aiVector3D position, normal, uv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Parse <node> tag from XML file and extract child node
|
||||||
|
// @param node XML node
|
||||||
|
// @param guessedMeshesContained number of extra guessed meshes
|
||||||
|
IRRImporter::Node *ParseNode(pugi::xml_node &node, BatchLoader& batch);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Parse <attributes> tags within <node> tags and apply to scene node
|
||||||
|
// @param attributeNode XML child node
|
||||||
|
// @param nd Attributed scene node
|
||||||
|
void ParseNodeAttributes(pugi::xml_node &attributeNode, IRRImporter::Node *nd, BatchLoader& batch);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Parse an <animator> node and attach an animator to a node
|
||||||
|
// @param animatorNode XML animator node
|
||||||
|
// @param nd Animated scene node
|
||||||
|
void ParseAnimators(pugi::xml_node &animatorNode, IRRImporter::Node *nd);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/// Fill the scene-graph recursively
|
/// Fill the scene-graph recursively
|
||||||
void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
|
void GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
|
||||||
BatchLoader& batch,
|
BatchLoader &batch,
|
||||||
std::vector<aiMesh*>& meshes,
|
std::vector<aiMesh *> &meshes,
|
||||||
std::vector<aiNodeAnim*>& anims,
|
std::vector<aiNodeAnim *> &anims,
|
||||||
std::vector<AttachmentInfo>& attach,
|
std::vector<AttachmentInfo> &attach,
|
||||||
std::vector<aiMaterial*>& materials,
|
std::vector<aiMaterial *> &materials,
|
||||||
unsigned int& defaultMatIdx);
|
unsigned int &defaultMatIdx);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/// Generate a mesh that consists of just a single quad
|
/// Generate a mesh that consists of just a single quad
|
||||||
aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1,
|
aiMesh *BuildSingleQuadMesh(const SkyboxVertex &v1,
|
||||||
const SkyboxVertex& v2,
|
const SkyboxVertex &v2,
|
||||||
const SkyboxVertex& v3,
|
const SkyboxVertex &v3,
|
||||||
const SkyboxVertex& v4);
|
const SkyboxVertex &v4);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/// Build a sky-box
|
/// Build a sky-box
|
||||||
|
@ -245,8 +248,8 @@ private:
|
||||||
/// @param meshes Receives 6 output meshes
|
/// @param meshes Receives 6 output meshes
|
||||||
/// @param materials The last 6 materials are assigned to the newly
|
/// @param materials The last 6 materials are assigned to the newly
|
||||||
/// created meshes. The names of the materials are adjusted.
|
/// created meshes. The names of the materials are adjusted.
|
||||||
void BuildSkybox(std::vector<aiMesh*>& meshes,
|
void BuildSkybox(std::vector<aiMesh *> &meshes,
|
||||||
std::vector<aiMaterial*> materials);
|
std::vector<aiMaterial *> materials);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Copy a material for a mesh to the output material list
|
/** Copy a material for a mesh to the output material list
|
||||||
|
@ -256,10 +259,10 @@ private:
|
||||||
* @param defMatIdx Default material index - UINT_MAX if not present
|
* @param defMatIdx Default material index - UINT_MAX if not present
|
||||||
* @param mesh Mesh to work on
|
* @param mesh Mesh to work on
|
||||||
*/
|
*/
|
||||||
void CopyMaterial(std::vector<aiMaterial*>& materials,
|
void CopyMaterial(std::vector<aiMaterial *> &materials,
|
||||||
std::vector< std::pair<aiMaterial*, unsigned int> >& inmaterials,
|
std::vector<std::pair<aiMaterial *, unsigned int>> &inmaterials,
|
||||||
unsigned int& defMatIdx,
|
unsigned int &defMatIdx,
|
||||||
aiMesh* mesh);
|
aiMesh *mesh);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Compute animations for a specific node
|
/** Compute animations for a specific node
|
||||||
|
@ -267,8 +270,8 @@ private:
|
||||||
* @param root Node to be processed
|
* @param root Node to be processed
|
||||||
* @param anims The list of output animations
|
* @param anims The list of output animations
|
||||||
*/
|
*/
|
||||||
void ComputeAnimations(Node* root, aiNode* real,
|
void ComputeAnimations(Node *root, aiNode *real,
|
||||||
std::vector<aiNodeAnim*>& anims);
|
std::vector<aiNodeAnim *> &anims);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Configuration option: desired output FPS
|
/// Configuration option: desired output FPS
|
||||||
|
@ -276,6 +279,12 @@ private:
|
||||||
|
|
||||||
/// Configuration option: speed flag was set?
|
/// Configuration option: speed flag was set?
|
||||||
bool configSpeedFlag;
|
bool configSpeedFlag;
|
||||||
|
|
||||||
|
std::vector<aiCamera*> cameras;
|
||||||
|
std::vector<aiLight*> lights;
|
||||||
|
unsigned int guessedMeshCnt;
|
||||||
|
unsigned int guessedMatCnt;
|
||||||
|
unsigned int guessedAnimCnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -57,16 +57,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
static const aiImporterDesc desc = {
|
static const aiImporterDesc desc = {
|
||||||
"Irrlicht Mesh Reader",
|
"Irrlicht Mesh Reader",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"http://irrlicht.sourceforge.net/",
|
"http://irrlicht.sourceforge.net/",
|
||||||
aiImporterFlags_SupportTextFlavour,
|
aiImporterFlags_SupportTextFlavour,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
"xml irrmesh"
|
"xml irrmesh"
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -80,419 +80,443 @@ IRRMeshImporter::~IRRMeshImporter() = default;
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Returns whether the class can handle the format of the given file.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||||
/* NOTE: A simple check for the file extension is not enough
|
/* NOTE: A simple check for the file extension is not enough
|
||||||
* here. Irrmesh and irr are easy, but xml is too generic
|
* here. Irrmesh and irr are easy, but xml is too generic
|
||||||
* and could be collada, too. So we need to open the file and
|
* and could be collada, too. So we need to open the file and
|
||||||
* search for typical tokens.
|
* search for typical tokens.
|
||||||
*/
|
*/
|
||||||
static const char *tokens[] = { "irrmesh" };
|
static const char *tokens[] = { "irrmesh" };
|
||||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get a list of all file extensions which are handled by this class
|
// Get a list of all file extensions which are handled by this class
|
||||||
const aiImporterDesc *IRRMeshImporter::GetInfo() const {
|
const aiImporterDesc *IRRMeshImporter::GetInfo() const {
|
||||||
return &desc;
|
return &desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void releaseMaterial(aiMaterial **mat) {
|
static void releaseMaterial(aiMaterial **mat) {
|
||||||
if (*mat != nullptr) {
|
if (*mat != nullptr) {
|
||||||
delete *mat;
|
delete *mat;
|
||||||
*mat = nullptr;
|
*mat = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void releaseMesh(aiMesh **mesh) {
|
static void releaseMesh(aiMesh **mesh) {
|
||||||
if (*mesh != nullptr) {
|
if (*mesh != nullptr) {
|
||||||
delete *mesh;
|
delete *mesh;
|
||||||
*mesh = nullptr;
|
*mesh = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
void IRRMeshImporter::InternReadFile(const std::string &pFile,
|
||||||
aiScene *pScene, IOSystem *pIOHandler) {
|
aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
|
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
if (file == nullptr)
|
if (file == nullptr)
|
||||||
throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
|
throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
|
||||||
|
|
||||||
// Construct the irrXML parser
|
// Construct the irrXML parser
|
||||||
XmlParser parser;
|
XmlParser parser;
|
||||||
if (!parser.parse( file.get() )) {
|
if (!parser.parse(file.get())) {
|
||||||
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
|
throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
|
||||||
}
|
}
|
||||||
XmlNode root = parser.getRootNode();
|
XmlNode root = parser.getRootNode();
|
||||||
|
|
||||||
// final data
|
// final data
|
||||||
std::vector<aiMaterial *> materials;
|
std::vector<aiMaterial *> materials;
|
||||||
std::vector<aiMesh *> meshes;
|
std::vector<aiMesh *> meshes;
|
||||||
materials.reserve(5);
|
materials.reserve(5);
|
||||||
meshes.reserve(5);
|
meshes.reserve(5);
|
||||||
|
|
||||||
// temporary data - current mesh buffer
|
// temporary data - current mesh buffer
|
||||||
aiMaterial *curMat = nullptr;
|
// TODO move all these to inside loop
|
||||||
aiMesh *curMesh = nullptr;
|
aiMaterial *curMat = nullptr;
|
||||||
unsigned int curMatFlags = 0;
|
aiMesh *curMesh = nullptr;
|
||||||
|
unsigned int curMatFlags = 0;
|
||||||
|
|
||||||
std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
|
std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
|
||||||
std::vector<aiColor4D> curColors;
|
std::vector<aiColor4D> curColors;
|
||||||
std::vector<aiVector3D> curUVs, curUV2s;
|
std::vector<aiVector3D> curUVs, curUV2s;
|
||||||
|
|
||||||
// some temporary variables
|
// some temporary variables
|
||||||
int textMeaning = 0;
|
// textMeaning is a 15 year old variable, that could've been an enum
|
||||||
int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
|
// int textMeaning = 0; // 0=none? 1=vertices 2=indices
|
||||||
bool useColors = false;
|
// int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
|
||||||
|
bool useColors = false;
|
||||||
|
|
||||||
// Parse the XML file
|
/*
|
||||||
for (pugi::xml_node child : root.children()) {
|
** irrmesh files have a top level <mesh> owning multiple <buffer> nodes.
|
||||||
if (child.type() == pugi::node_element) {
|
** Each <buffer> contains <material>, <vertices>, and <indices>
|
||||||
if (!ASSIMP_stricmp(child.name(), "buffer") && (curMat || curMesh)) {
|
** <material> tags here directly owns the material data specs
|
||||||
// end of previous buffer. A material and a mesh should be there
|
** <vertices> are a vertex per line, contains position, UV1 coords, maybe UV2, normal, tangent, bitangent
|
||||||
if (!curMat || !curMesh) {
|
** <boundingbox> is ignored, I think assimp recalculates those?
|
||||||
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
|
*/
|
||||||
releaseMaterial(&curMat);
|
|
||||||
releaseMesh(&curMesh);
|
|
||||||
} else {
|
|
||||||
materials.push_back(curMat);
|
|
||||||
meshes.push_back(curMesh);
|
|
||||||
}
|
|
||||||
curMat = nullptr;
|
|
||||||
curMesh = nullptr;
|
|
||||||
|
|
||||||
curVertices.clear();
|
// Parse the XML file
|
||||||
curColors.clear();
|
pugi::xml_node const &meshNode = root.child("mesh");
|
||||||
curNormals.clear();
|
for (pugi::xml_node bufferNode : meshNode.children()) {
|
||||||
curUV2s.clear();
|
if (ASSIMP_stricmp(bufferNode.name(), "buffer")) {
|
||||||
curUVs.clear();
|
// Might be a useless warning
|
||||||
curTangents.clear();
|
ASSIMP_LOG_WARN("IRRMESH: Ignoring non buffer node <", bufferNode.name(), "> in mesh declaration");
|
||||||
curBitangents.clear();
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ASSIMP_stricmp(child.name(), "material")) {
|
curMat = nullptr;
|
||||||
if (curMat) {
|
curMesh = nullptr;
|
||||||
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
|
|
||||||
releaseMaterial(&curMat);
|
|
||||||
}
|
|
||||||
curMat = ParseMaterial(curMatFlags);
|
|
||||||
}
|
|
||||||
/* no else here! */ if (!ASSIMP_stricmp(child.name(), "vertices")) {
|
|
||||||
pugi::xml_attribute attr = child.attribute("vertexCount");
|
|
||||||
int num = attr.as_int();
|
|
||||||
//int num = reader->getAttributeValueAsInt("vertexCount");
|
|
||||||
|
|
||||||
if (!num) {
|
curVertices.clear();
|
||||||
// This is possible ... remove the mesh from the list and skip further reading
|
curColors.clear();
|
||||||
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
|
curNormals.clear();
|
||||||
|
curUV2s.clear();
|
||||||
|
curUVs.clear();
|
||||||
|
curTangents.clear();
|
||||||
|
curBitangents.clear();
|
||||||
|
|
||||||
releaseMaterial(&curMat);
|
// TODO ensure all three nodes are present and populated
|
||||||
releaseMesh(&curMesh);
|
// before allocating everything
|
||||||
textMeaning = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
curVertices.reserve(num);
|
// Get first material node
|
||||||
curNormals.reserve(num);
|
pugi::xml_node materialNode = bufferNode.child("material");
|
||||||
curColors.reserve(num);
|
if (materialNode) {
|
||||||
curUVs.reserve(num);
|
curMat = ParseMaterial(materialNode, curMatFlags);
|
||||||
|
// Warn if there's more materials
|
||||||
|
if (materialNode.next_sibling("material")) {
|
||||||
|
ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ASSIMP_LOG_ERROR("IRRMESH: Buffer must contain one material");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine the file format
|
// Get first vertices node
|
||||||
//const char *t = reader->getAttributeValueSafe("type");
|
pugi::xml_node verticesNode = bufferNode.child("vertices");
|
||||||
pugi::xml_attribute t = child.attribute("type");
|
if (verticesNode) {
|
||||||
if (!ASSIMP_stricmp("2tcoords", t.name())) {
|
pugi::xml_attribute vertexCountAttrib = verticesNode.attribute("vertexCount");
|
||||||
curUV2s.reserve(num);
|
int vertexCount = vertexCountAttrib.as_int();
|
||||||
vertexFormat = 1;
|
if (vertexCount == 0) {
|
||||||
|
// This is possible ... remove the mesh from the list and skip further reading
|
||||||
|
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
|
||||||
|
releaseMaterial(&curMat);
|
||||||
|
// releaseMesh(&curMesh);
|
||||||
|
continue; // Bail out early
|
||||||
|
};
|
||||||
|
|
||||||
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
|
curVertices.reserve(vertexCount);
|
||||||
// *********************************************************
|
curNormals.reserve(vertexCount);
|
||||||
// We have a second texture! So use this UV channel
|
curColors.reserve(vertexCount);
|
||||||
// for it. The 2nd texture can be either a normal
|
curUVs.reserve(vertexCount);
|
||||||
// texture (solid_2layer or lightmap_xxx) or a normal
|
|
||||||
// map (normal_..., parallax_...)
|
|
||||||
// *********************************************************
|
|
||||||
int idx = 1;
|
|
||||||
aiMaterial *mat = (aiMaterial *)curMat;
|
|
||||||
|
|
||||||
if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
|
VertexFormat vertexFormat;
|
||||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
|
// Determine the file format
|
||||||
} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
|
pugi::xml_attribute typeAttrib = verticesNode.attribute("type");
|
||||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
|
if (!ASSIMP_stricmp("2tcoords", typeAttrib.value())) {
|
||||||
} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
|
curUV2s.reserve(vertexCount);
|
||||||
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
|
vertexFormat = VertexFormat::t2coord;
|
||||||
}
|
if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
|
||||||
}
|
// *********************************************************
|
||||||
} else if (!ASSIMP_stricmp("tangents", t.name())) {
|
// We have a second texture! So use this UV channel
|
||||||
curTangents.reserve(num);
|
// for it. The 2nd texture can be either a normal
|
||||||
curBitangents.reserve(num);
|
// texture (solid_2layer or lightmap_xxx) or a normal
|
||||||
vertexFormat = 2;
|
// map (normal_..., parallax_...)
|
||||||
} else if (ASSIMP_stricmp("standard", t.name())) {
|
// *********************************************************
|
||||||
releaseMaterial(&curMat);
|
int idx = 1;
|
||||||
ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format");
|
aiMaterial *mat = (aiMaterial *)curMat;
|
||||||
} else
|
|
||||||
vertexFormat = 0;
|
|
||||||
textMeaning = 1;
|
|
||||||
} else if (!ASSIMP_stricmp(child.name(), "indices")) {
|
|
||||||
if (curVertices.empty() && curMat) {
|
|
||||||
releaseMaterial(&curMat);
|
|
||||||
throw DeadlyImportError("IRRMESH: indices must come after vertices");
|
|
||||||
}
|
|
||||||
|
|
||||||
textMeaning = 2;
|
if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
|
||||||
|
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
|
||||||
|
} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
|
||||||
|
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
|
||||||
|
} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
|
||||||
|
mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!ASSIMP_stricmp("tangents", typeAttrib.value())) {
|
||||||
|
curTangents.reserve(vertexCount);
|
||||||
|
curBitangents.reserve(vertexCount);
|
||||||
|
vertexFormat = VertexFormat::tangent;
|
||||||
|
} else if (!ASSIMP_stricmp("standard", typeAttrib.value())) {
|
||||||
|
vertexFormat = VertexFormat::standard;
|
||||||
|
} else {
|
||||||
|
// Unsupported format, discard whole buffer/mesh
|
||||||
|
// Assuming we have a correct material, then release it
|
||||||
|
// We don't have a correct mesh for sure here
|
||||||
|
releaseMaterial(&curMat);
|
||||||
|
ASSIMP_LOG_ERROR("IRRMESH: Unknown vertex format");
|
||||||
|
continue; // Skip rest of buffer
|
||||||
|
};
|
||||||
|
|
||||||
// start a new mesh
|
// We know what format buffer is, collect numbers
|
||||||
curMesh = new aiMesh();
|
ParseBufferVertices(verticesNode.text().get(), vertexFormat,
|
||||||
|
curVertices, curNormals,
|
||||||
|
curTangents, curBitangents,
|
||||||
|
curUVs, curUV2s, curColors, useColors);
|
||||||
|
}
|
||||||
|
|
||||||
// allocate storage for all faces
|
// Get indices
|
||||||
pugi::xml_attribute attr = child.attribute("indexCount");
|
// At this point we have some vertices and a valid material
|
||||||
curMesh->mNumVertices = attr.as_int();
|
// Collect indices and create aiMesh at the same time
|
||||||
if (!curMesh->mNumVertices) {
|
pugi::xml_node indicesNode = bufferNode.child("indices");
|
||||||
// This is possible ... remove the mesh from the list and skip further reading
|
if (indicesNode) {
|
||||||
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
|
// start a new mesh
|
||||||
|
curMesh = new aiMesh();
|
||||||
|
|
||||||
// mesh - away
|
// allocate storage for all faces
|
||||||
releaseMesh(&curMesh);
|
pugi::xml_attribute attr = indicesNode.attribute("indexCount");
|
||||||
|
curMesh->mNumVertices = attr.as_int();
|
||||||
|
if (!curMesh->mNumVertices) {
|
||||||
|
// This is possible ... remove the mesh from the list and skip further reading
|
||||||
|
ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
|
||||||
|
|
||||||
// material - away
|
// mesh - away
|
||||||
releaseMaterial(&curMat);
|
releaseMesh(&curMesh);
|
||||||
|
|
||||||
textMeaning = 0;
|
// material - away
|
||||||
continue;
|
releaseMaterial(&curMat);
|
||||||
}
|
continue; // Go to next buffer
|
||||||
|
}
|
||||||
|
|
||||||
if (curMesh->mNumVertices % 3) {
|
if (curMesh->mNumVertices % 3) {
|
||||||
ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
|
ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
|
||||||
}
|
}
|
||||||
|
|
||||||
curMesh->mNumFaces = curMesh->mNumVertices / 3;
|
curMesh->mNumFaces = curMesh->mNumVertices / 3;
|
||||||
curMesh->mFaces = new aiFace[curMesh->mNumFaces];
|
curMesh->mFaces = new aiFace[curMesh->mNumFaces];
|
||||||
|
|
||||||
// setup some members
|
// setup some members
|
||||||
curMesh->mMaterialIndex = (unsigned int)materials.size();
|
curMesh->mMaterialIndex = (unsigned int)materials.size();
|
||||||
curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||||
|
|
||||||
// allocate storage for all vertices
|
// allocate storage for all vertices
|
||||||
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
|
curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
|
||||||
|
|
||||||
if (curNormals.size() == curVertices.size()) {
|
if (curNormals.size() == curVertices.size()) {
|
||||||
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
|
curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
if (curTangents.size() == curVertices.size()) {
|
if (curTangents.size() == curVertices.size()) {
|
||||||
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
|
curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
if (curBitangents.size() == curVertices.size()) {
|
if (curBitangents.size() == curVertices.size()) {
|
||||||
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
|
curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
if (curColors.size() == curVertices.size() && useColors) {
|
if (curColors.size() == curVertices.size() && useColors) {
|
||||||
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
|
curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
if (curUVs.size() == curVertices.size()) {
|
if (curUVs.size() == curVertices.size()) {
|
||||||
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
|
curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
if (curUV2s.size() == curVertices.size()) {
|
if (curUV2s.size() == curVertices.size()) {
|
||||||
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
|
curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//break;
|
|
||||||
|
|
||||||
//case EXN_TEXT: {
|
// read indices
|
||||||
const char *sz = child.child_value();
|
aiFace *curFace = curMesh->mFaces;
|
||||||
if (textMeaning == 1) {
|
aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
|
||||||
textMeaning = 0;
|
|
||||||
|
|
||||||
// read vertices
|
aiVector3D *pcV = curMesh->mVertices;
|
||||||
do {
|
aiVector3D *pcN = curMesh->mNormals;
|
||||||
SkipSpacesAndLineEnd(&sz);
|
aiVector3D *pcT = curMesh->mTangents;
|
||||||
aiVector3D temp;
|
aiVector3D *pcB = curMesh->mBitangents;
|
||||||
aiColor4D c;
|
aiColor4D *pcC0 = curMesh->mColors[0];
|
||||||
|
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
|
||||||
|
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
|
||||||
|
|
||||||
// Read the vertex position
|
unsigned int curIdx = 0;
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
unsigned int total = 0;
|
||||||
SkipSpaces(&sz);
|
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
// NOTE this might explode for UTF-16 and wchars
|
||||||
SkipSpaces(&sz);
|
const char *sz = indicesNode.text().get();
|
||||||
|
// For each index loop over aiMesh faces
|
||||||
|
while (SkipSpacesAndLineEnd(&sz)) {
|
||||||
|
if (curFace >= faceEnd) {
|
||||||
|
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// if new face
|
||||||
|
if (!curIdx) {
|
||||||
|
curFace->mNumIndices = 3;
|
||||||
|
curFace->mIndices = new unsigned int[3];
|
||||||
|
}
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
// Read index base 10
|
||||||
SkipSpaces(&sz);
|
// function advances the pointer
|
||||||
curVertices.push_back(temp);
|
unsigned int idx = strtoul10(sz, &sz);
|
||||||
|
if (idx >= curVertices.size()) {
|
||||||
|
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Read the vertex normals
|
// make up our own indices?
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
curFace->mIndices[curIdx] = total++;
|
||||||
SkipSpaces(&sz);
|
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
// Copy over data to aiMesh
|
||||||
SkipSpaces(&sz);
|
*pcV++ = curVertices[idx];
|
||||||
|
if (pcN) *pcN++ = curNormals[idx];
|
||||||
|
if (pcT) *pcT++ = curTangents[idx];
|
||||||
|
if (pcB) *pcB++ = curBitangents[idx];
|
||||||
|
if (pcC0) *pcC0++ = curColors[idx];
|
||||||
|
if (pcT0) *pcT0++ = curUVs[idx];
|
||||||
|
if (pcT1) *pcT1++ = curUV2s[idx];
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
// start new face
|
||||||
SkipSpaces(&sz);
|
if (++curIdx == 3) {
|
||||||
curNormals.push_back(temp);
|
++curFace;
|
||||||
|
curIdx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We should be at the end of mFaces
|
||||||
|
if (curFace != faceEnd)
|
||||||
|
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
|
||||||
|
}
|
||||||
|
|
||||||
// read the vertex colors
|
// Finish processing the mesh - do some small material workarounds
|
||||||
uint32_t clr = strtoul16(sz, &sz);
|
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
|
||||||
ColorFromARGBPacked(clr, c);
|
// Take the opacity value of the current material
|
||||||
|
// from the common vertex color alpha
|
||||||
|
aiMaterial *mat = (aiMaterial *)curMat;
|
||||||
|
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
|
||||||
|
}
|
||||||
|
// textMeaning = 2;
|
||||||
|
|
||||||
if (!curColors.empty() && c != *(curColors.end() - 1))
|
// end of previous buffer. A material and a mesh should be there
|
||||||
useColors = true;
|
if (!curMat || !curMesh) {
|
||||||
|
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
|
||||||
|
releaseMaterial(&curMat);
|
||||||
|
releaseMesh(&curMesh);
|
||||||
|
} else {
|
||||||
|
materials.push_back(curMat);
|
||||||
|
meshes.push_back(curMesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
curColors.push_back(c);
|
// If one is empty then so is the other
|
||||||
SkipSpaces(&sz);
|
if (materials.empty() || meshes.empty()) {
|
||||||
|
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
|
||||||
|
}
|
||||||
|
|
||||||
// read the first UV coordinate set
|
// now generate the output scene
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
pScene->mNumMeshes = (unsigned int)meshes.size();
|
||||||
SkipSpaces(&sz);
|
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
||||||
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||||
|
pScene->mMeshes[i] = meshes[i];
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
// clean this value ...
|
||||||
SkipSpaces(&sz);
|
pScene->mMeshes[i]->mNumUVComponents[3] = 0;
|
||||||
temp.z = 0.f;
|
}
|
||||||
temp.y = 1.f - temp.y; // DX to OGL
|
|
||||||
curUVs.push_back(temp);
|
|
||||||
|
|
||||||
// read the (optional) second UV coordinate set
|
pScene->mNumMaterials = (unsigned int)materials.size();
|
||||||
if (vertexFormat == 1) {
|
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
|
||||||
SkipSpaces(&sz);
|
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
pScene->mRootNode = new aiNode();
|
||||||
temp.y = 1.f - temp.y; // DX to OGL
|
pScene->mRootNode->mName.Set("<IRRMesh>");
|
||||||
curUV2s.push_back(temp);
|
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
|
||||||
}
|
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
|
||||||
// read optional tangent and bitangent vectors
|
|
||||||
else if (vertexFormat == 2) {
|
|
||||||
// tangents
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
|
||||||
SkipSpaces(&sz);
|
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||||
SkipSpaces(&sz);
|
pScene->mRootNode->mMeshes[i] = i;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
void IRRMeshImporter::ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
|
||||||
SkipSpaces(&sz);
|
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
|
||||||
temp.y *= -1.0f;
|
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
|
||||||
curTangents.push_back(temp);
|
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
|
||||||
|
std::vector<aiColor4D> &colors, bool &useColors) {
|
||||||
|
// read vertices
|
||||||
|
do {
|
||||||
|
SkipSpacesAndLineEnd(&sz);
|
||||||
|
aiVector3D temp;
|
||||||
|
aiColor4D c;
|
||||||
|
|
||||||
// bitangents
|
// Read the vertex position
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz);
|
||||||
|
|
||||||
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz);
|
||||||
temp.y *= -1.0f;
|
vertices.push_back(temp);
|
||||||
curBitangents.push_back(temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IMPORTANT: We assume that each vertex is specified in one
|
// Read the vertex normals
|
||||||
line. So we can skip the rest of the line - unknown vertex
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
elements are ignored.
|
SkipSpaces(&sz);
|
||||||
*/
|
|
||||||
|
|
||||||
while (SkipLine(&sz));
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
} else if (textMeaning == 2) {
|
SkipSpaces(&sz);
|
||||||
textMeaning = 0;
|
|
||||||
|
|
||||||
// read indices
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
aiFace *curFace = curMesh->mFaces;
|
SkipSpaces(&sz);
|
||||||
aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
|
normals.push_back(temp);
|
||||||
|
|
||||||
aiVector3D *pcV = curMesh->mVertices;
|
// read the vertex colors
|
||||||
aiVector3D *pcN = curMesh->mNormals;
|
uint32_t clr = strtoul16(sz, &sz);
|
||||||
aiVector3D *pcT = curMesh->mTangents;
|
ColorFromARGBPacked(clr, c);
|
||||||
aiVector3D *pcB = curMesh->mBitangents;
|
|
||||||
aiColor4D *pcC0 = curMesh->mColors[0];
|
|
||||||
aiVector3D *pcT0 = curMesh->mTextureCoords[0];
|
|
||||||
aiVector3D *pcT1 = curMesh->mTextureCoords[1];
|
|
||||||
|
|
||||||
unsigned int curIdx = 0;
|
// If we're pushing more than one distinct color
|
||||||
unsigned int total = 0;
|
if (!colors.empty() && c != *(colors.end() - 1))
|
||||||
while (SkipSpacesAndLineEnd(&sz)) {
|
useColors = true;
|
||||||
if (curFace >= faceEnd) {
|
|
||||||
ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!curIdx) {
|
|
||||||
curFace->mNumIndices = 3;
|
|
||||||
curFace->mIndices = new unsigned int[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int idx = strtoul10(sz, &sz);
|
colors.push_back(c);
|
||||||
if (idx >= curVertices.size()) {
|
SkipSpaces(&sz);
|
||||||
ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
|
|
||||||
idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
curFace->mIndices[curIdx] = total++;
|
// read the first UV coordinate set
|
||||||
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
|
SkipSpaces(&sz);
|
||||||
|
|
||||||
*pcV++ = curVertices[idx];
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
if (pcN) *pcN++ = curNormals[idx];
|
SkipSpaces(&sz);
|
||||||
if (pcT) *pcT++ = curTangents[idx];
|
temp.z = 0.f;
|
||||||
if (pcB) *pcB++ = curBitangents[idx];
|
temp.y = 1.f - temp.y; // DX to OGL
|
||||||
if (pcC0) *pcC0++ = curColors[idx];
|
UVs.push_back(temp);
|
||||||
if (pcT0) *pcT0++ = curUVs[idx];
|
|
||||||
if (pcT1) *pcT1++ = curUV2s[idx];
|
|
||||||
|
|
||||||
if (++curIdx == 3) {
|
// NOTE these correspond to specific S3DVertex* structs in irr sourcecode
|
||||||
++curFace;
|
// So by definition, all buffers have either UV2 or tangents or neither
|
||||||
curIdx = 0;
|
// read the (optional) second UV coordinate set
|
||||||
}
|
if (vertexFormat == VertexFormat::t2coord) {
|
||||||
}
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
|
SkipSpaces(&sz);
|
||||||
|
|
||||||
if (curFace != faceEnd)
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
|
temp.y = 1.f - temp.y; // DX to OGL
|
||||||
|
UV2s.push_back(temp);
|
||||||
|
}
|
||||||
|
// read optional tangent and bitangent vectors
|
||||||
|
else if (vertexFormat == VertexFormat::tangent) {
|
||||||
|
// tangents
|
||||||
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
|
SkipSpaces(&sz);
|
||||||
|
|
||||||
// Finish processing the mesh - do some small material workarounds
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
|
SkipSpaces(&sz);
|
||||||
// Take the opacity value of the current material
|
|
||||||
// from the common vertex color alpha
|
|
||||||
aiMaterial *mat = (aiMaterial *)curMat;
|
|
||||||
mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of the last buffer. A material and a mesh should be there
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
if (curMat || curMesh) {
|
SkipSpaces(&sz);
|
||||||
if (!curMat || !curMesh) {
|
temp.y *= -1.0f;
|
||||||
ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
|
tangents.push_back(temp);
|
||||||
releaseMaterial(&curMat);
|
|
||||||
releaseMesh(&curMesh);
|
|
||||||
} else {
|
|
||||||
materials.push_back(curMat);
|
|
||||||
meshes.push_back(curMesh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (materials.empty()) {
|
// bitangents
|
||||||
throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
|
sz = fast_atoreal_move<float>(sz, (float &)temp.x);
|
||||||
}
|
SkipSpaces(&sz);
|
||||||
|
|
||||||
// now generate the output scene
|
sz = fast_atoreal_move<float>(sz, (float &)temp.z);
|
||||||
pScene->mNumMeshes = (unsigned int)meshes.size();
|
SkipSpaces(&sz);
|
||||||
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
||||||
pScene->mMeshes[i] = meshes[i];
|
|
||||||
|
|
||||||
// clean this value ...
|
sz = fast_atoreal_move<float>(sz, (float &)temp.y);
|
||||||
pScene->mMeshes[i]->mNumUVComponents[3] = 0;
|
SkipSpaces(&sz);
|
||||||
}
|
temp.y *= -1.0f;
|
||||||
|
bitangents.push_back(temp);
|
||||||
pScene->mNumMaterials = (unsigned int)materials.size();
|
}
|
||||||
pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
|
} while (SkipLine(&sz));
|
||||||
::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
|
/* IMPORTANT: We assume that each vertex is specified in one
|
||||||
|
line. So we can skip the rest of the line - unknown vertex
|
||||||
pScene->mRootNode = new aiNode();
|
elements are ignored.
|
||||||
pScene->mRootNode->mName.Set("<IRRMesh>");
|
*/
|
||||||
pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
|
|
||||||
pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
||||||
pScene->mRootNode->mMeshes[i] = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER
|
#endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER
|
||||||
|
|
|
@ -85,6 +85,19 @@ protected:
|
||||||
*/
|
*/
|
||||||
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
void InternReadFile(const std::string &pFile, aiScene *pScene,
|
||||||
IOSystem *pIOHandler) override;
|
IOSystem *pIOHandler) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class VertexFormat {
|
||||||
|
standard = 0, // "standard" - also noted as 'normal' format elsewhere
|
||||||
|
t2coord = 1, // "2tcoord" - standard + 2 UV maps
|
||||||
|
tangent = 2, // "tangents" - standard + tangents and bitangents
|
||||||
|
};
|
||||||
|
|
||||||
|
void ParseBufferVertices(const char *sz, VertexFormat vertexFormat,
|
||||||
|
std::vector<aiVector3D> &vertices, std::vector<aiVector3D> &normals,
|
||||||
|
std::vector<aiVector3D> &tangents, std::vector<aiVector3D> &bitangents,
|
||||||
|
std::vector<aiVector3D> &UVs, std::vector<aiVector3D> &UV2s,
|
||||||
|
std::vector<aiColor4D> &colors, bool &useColors);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -43,302 +43,302 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Shared utilities for the IRR and IRRMESH loaders
|
* @brief Shared utilities for the IRR and IRRMESH loaders
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
|
// This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
|
||||||
#if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
|
#if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
|
||||||
|
|
||||||
#include "IRRShared.h"
|
#include "IRRShared.h"
|
||||||
#include <assimp/ParsingUtils.h>
|
#include <assimp/ParsingUtils.h>
|
||||||
#include <assimp/fast_atof.h>
|
#include <assimp/fast_atof.h>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
|
||||||
#include <assimp/material.h>
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
// Transformation matrix to convert from Assimp to IRR space
|
// Transformation matrix to convert from Assimp to IRR space
|
||||||
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
|
const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4(
|
||||||
1.0f, 0.0f, 0.0f, 0.0f,
|
1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
0.0f, 0.0f, 1.0f, 0.0f,
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
0.0f, 1.0f, 0.0f, 0.0f,
|
0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
0.0f, 0.0f, 0.0f, 1.0f);
|
0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read a property in hexadecimal format (i.e. ffffffff)
|
// read a property in hexadecimal format (i.e. ffffffff)
|
||||||
void IrrlichtBase::ReadHexProperty(HexProperty &out ) {
|
void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
|
||||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
for (pugi::xml_attribute attrib : hexnode.attributes()) {
|
||||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||||
out.name = std::string( attrib.value() );
|
out.name = std::string(attrib.value());
|
||||||
} else if (!ASSIMP_stricmp(attrib.name(),"value")) {
|
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||||
// parse the hexadecimal value
|
// parse the hexadecimal value
|
||||||
out.value = strtoul16(attrib.name());
|
out.value = strtoul16(attrib.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read a decimal property
|
// read a decimal property
|
||||||
void IrrlichtBase::ReadIntProperty(IntProperty & out) {
|
void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
|
||||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
for (pugi::xml_attribute attrib : intnode.attributes()) {
|
||||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||||
out.name = std::string(attrib.value());
|
out.name = std::string(attrib.value());
|
||||||
} else if (!ASSIMP_stricmp(attrib.value(),"value")) {
|
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||||
// parse the int value
|
// parse the int value
|
||||||
out.value = strtol10(attrib.name());
|
out.value = strtol10(attrib.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read a string property
|
// read a string property
|
||||||
void IrrlichtBase::ReadStringProperty( StringProperty& out) {
|
void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
|
||||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
for (pugi::xml_attribute attrib : stringnode.attributes()) {
|
||||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||||
out.name = std::string(attrib.value());
|
out.name = std::string(attrib.value());
|
||||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||||
// simple copy the string
|
// simple copy the string
|
||||||
out.value = std::string(attrib.value());
|
out.value = std::string(attrib.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read a boolean property
|
// read a boolean property
|
||||||
void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
|
void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
|
||||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
for (pugi::xml_attribute attrib : boolnode.attributes()) {
|
||||||
if (!ASSIMP_stricmp(attrib.name(), "name")){
|
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||||
out.name = std::string(attrib.value());
|
out.name = std::string(attrib.value());
|
||||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||||
// true or false, case insensitive
|
// true or false, case insensitive
|
||||||
out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
|
out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read a float property
|
// read a float property
|
||||||
void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
|
void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
|
||||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
for (pugi::xml_attribute attrib : floatnode.attributes()) {
|
||||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||||
out.name = std::string(attrib.value());
|
out.name = std::string(attrib.value());
|
||||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||||
// just parse the float
|
// just parse the float
|
||||||
out.value = fast_atof(attrib.value());
|
out.value = fast_atof(attrib.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// read a vector property
|
// read a vector property
|
||||||
void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) {
|
void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
|
||||||
for (pugi::xml_attribute attrib : mNode->attributes()) {
|
for (pugi::xml_attribute attrib : vectornode.attributes()) {
|
||||||
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
if (!ASSIMP_stricmp(attrib.name(), "name")) {
|
||||||
out.name = std::string(attrib.value());
|
out.name = std::string(attrib.value());
|
||||||
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
|
||||||
// three floats, separated with commas
|
// three floats, separated with commas
|
||||||
const char *ptr = attrib.value();
|
const char *ptr = attrib.value();
|
||||||
|
|
||||||
SkipSpaces(&ptr);
|
SkipSpaces(&ptr);
|
||||||
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x );
|
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
|
||||||
SkipSpaces(&ptr);
|
SkipSpaces(&ptr);
|
||||||
if (',' != *ptr) {
|
if (',' != *ptr) {
|
||||||
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
||||||
} else {
|
} else {
|
||||||
SkipSpaces(ptr + 1, &ptr);
|
SkipSpaces(ptr + 1, &ptr);
|
||||||
}
|
}
|
||||||
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y );
|
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
|
||||||
SkipSpaces(&ptr);
|
SkipSpaces(&ptr);
|
||||||
if (',' != *ptr) {
|
if (',' != *ptr) {
|
||||||
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
|
||||||
} else {
|
} else {
|
||||||
SkipSpaces(ptr + 1, &ptr);
|
SkipSpaces(ptr + 1, &ptr);
|
||||||
}
|
}
|
||||||
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z );
|
ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Convert a string to a proper aiMappingMode
|
// Convert a string to a proper aiMappingMode
|
||||||
int ConvertMappingMode(const std::string& mode) {
|
int ConvertMappingMode(const std::string &mode) {
|
||||||
if (mode == "texture_clamp_repeat") {
|
if (mode == "texture_clamp_repeat") {
|
||||||
return aiTextureMapMode_Wrap;
|
return aiTextureMapMode_Wrap;
|
||||||
} else if (mode == "texture_clamp_mirror") {
|
} else if (mode == "texture_clamp_mirror") {
|
||||||
return aiTextureMapMode_Mirror;
|
return aiTextureMapMode_Mirror;
|
||||||
}
|
}
|
||||||
|
|
||||||
return aiTextureMapMode_Clamp;
|
return aiTextureMapMode_Clamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Parse a material from the XML file
|
// Parse a material from the XML file
|
||||||
aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
|
aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
|
||||||
aiMaterial* mat = new aiMaterial();
|
aiMaterial *mat = new aiMaterial();
|
||||||
aiColor4D clr;
|
aiColor4D clr;
|
||||||
aiString s;
|
aiString s;
|
||||||
|
|
||||||
matFlags = 0; // zero output flags
|
matFlags = 0; // zero output flags
|
||||||
int cnt = 0; // number of used texture channels
|
int cnt = 0; // number of used texture channels
|
||||||
unsigned int nd = 0;
|
unsigned int nd = 0;
|
||||||
|
|
||||||
for (pugi::xml_node child : mNode->children()) {
|
for (pugi::xml_node child : materialNode.children()) {
|
||||||
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
|
if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
|
||||||
HexProperty prop;
|
HexProperty prop;
|
||||||
ReadHexProperty(prop);
|
ReadHexProperty(prop, child);
|
||||||
if (prop.name == "Diffuse") {
|
if (prop.name == "Diffuse") {
|
||||||
ColorFromARGBPacked(prop.value, clr);
|
ColorFromARGBPacked(prop.value, clr);
|
||||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
} else if (prop.name == "Ambient") {
|
} else if (prop.name == "Ambient") {
|
||||||
ColorFromARGBPacked(prop.value, clr);
|
ColorFromARGBPacked(prop.value, clr);
|
||||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
|
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||||
} else if (prop.name == "Specular") {
|
} else if (prop.name == "Specular") {
|
||||||
ColorFromARGBPacked(prop.value, clr);
|
ColorFromARGBPacked(prop.value, clr);
|
||||||
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
|
mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The 'emissive' property causes problems. It is
|
// NOTE: The 'emissive' property causes problems. It is
|
||||||
// often != 0, even if there is obviously no light
|
// often != 0, even if there is obviously no light
|
||||||
// emitted by the described surface. In fact I think
|
// emitted by the described surface. In fact I think
|
||||||
// IRRLICHT ignores this property, too.
|
// IRRLICHT ignores this property, too.
|
||||||
#if 0
|
#if 0
|
||||||
else if (prop.name == "Emissive") {
|
else if (prop.name == "Emissive") {
|
||||||
ColorFromARGBPacked(prop.value,clr);
|
ColorFromARGBPacked(prop.value,clr);
|
||||||
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
|
mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
|
} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
|
||||||
FloatProperty prop;
|
FloatProperty prop;
|
||||||
ReadFloatProperty(prop);
|
ReadFloatProperty(prop, child);
|
||||||
if (prop.name == "Shininess") {
|
if (prop.name == "Shininess") {
|
||||||
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
|
mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
|
||||||
}
|
}
|
||||||
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
|
} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
|
||||||
BoolProperty prop;
|
BoolProperty prop;
|
||||||
ReadBoolProperty(prop);
|
ReadBoolProperty(prop, child);
|
||||||
if (prop.name == "Wireframe") {
|
if (prop.name == "Wireframe") {
|
||||||
int val = (prop.value ? true : false);
|
int val = (prop.value ? true : false);
|
||||||
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
|
||||||
} else if (prop.name == "GouraudShading") {
|
} else if (prop.name == "GouraudShading") {
|
||||||
int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
|
int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
|
||||||
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
|
mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
|
||||||
} else if (prop.name == "BackfaceCulling") {
|
} else if (prop.name == "BackfaceCulling") {
|
||||||
int val = (!prop.value);
|
int val = (!prop.value);
|
||||||
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
|
mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
|
||||||
}
|
}
|
||||||
} else if (!ASSIMP_stricmp(child.name(), "texture") ||
|
} else if (!ASSIMP_stricmp(child.name(), "texture") ||
|
||||||
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
|
!ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
|
||||||
StringProperty prop;
|
StringProperty prop;
|
||||||
ReadStringProperty(prop);
|
ReadStringProperty(prop, child);
|
||||||
if (prop.value.length()) {
|
if (prop.value.length()) {
|
||||||
// material type (shader)
|
// material type (shader)
|
||||||
if (prop.name == "Type") {
|
if (prop.name == "Type") {
|
||||||
if (prop.value == "solid") {
|
if (prop.value == "solid") {
|
||||||
// default material ...
|
// default material ...
|
||||||
} else if (prop.value == "trans_vertex_alpha") {
|
} else if (prop.value == "trans_vertex_alpha") {
|
||||||
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
|
matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
|
||||||
} else if (prop.value == "lightmap") {
|
} else if (prop.value == "lightmap") {
|
||||||
matFlags = AI_IRRMESH_MAT_lightmap;
|
matFlags = AI_IRRMESH_MAT_lightmap;
|
||||||
} else if (prop.value == "solid_2layer") {
|
} else if (prop.value == "solid_2layer") {
|
||||||
matFlags = AI_IRRMESH_MAT_solid_2layer;
|
matFlags = AI_IRRMESH_MAT_solid_2layer;
|
||||||
} else if (prop.value == "lightmap_m2") {
|
} else if (prop.value == "lightmap_m2") {
|
||||||
matFlags = AI_IRRMESH_MAT_lightmap_m2;
|
matFlags = AI_IRRMESH_MAT_lightmap_m2;
|
||||||
} else if (prop.value == "lightmap_m4") {
|
} else if (prop.value == "lightmap_m4") {
|
||||||
matFlags = AI_IRRMESH_MAT_lightmap_m4;
|
matFlags = AI_IRRMESH_MAT_lightmap_m4;
|
||||||
} else if (prop.value == "lightmap_light") {
|
} else if (prop.value == "lightmap_light") {
|
||||||
matFlags = AI_IRRMESH_MAT_lightmap_light;
|
matFlags = AI_IRRMESH_MAT_lightmap_light;
|
||||||
} else if (prop.value == "lightmap_light_m2") {
|
} else if (prop.value == "lightmap_light_m2") {
|
||||||
matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
|
matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
|
||||||
} else if (prop.value == "lightmap_light_m4") {
|
} else if (prop.value == "lightmap_light_m4") {
|
||||||
matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
|
matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
|
||||||
} else if (prop.value == "lightmap_add") {
|
} else if (prop.value == "lightmap_add") {
|
||||||
matFlags = AI_IRRMESH_MAT_lightmap_add;
|
matFlags = AI_IRRMESH_MAT_lightmap_add;
|
||||||
} else if (prop.value == "normalmap_solid" ||
|
} else if (prop.value == "normalmap_solid" ||
|
||||||
prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
|
prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
|
||||||
matFlags = AI_IRRMESH_MAT_normalmap_solid;
|
matFlags = AI_IRRMESH_MAT_normalmap_solid;
|
||||||
} else if (prop.value == "normalmap_trans_vertex_alpha" ||
|
} else if (prop.value == "normalmap_trans_vertex_alpha" ||
|
||||||
prop.value == "parallaxmap_trans_vertex_alpha") {
|
prop.value == "parallaxmap_trans_vertex_alpha") {
|
||||||
matFlags = AI_IRRMESH_MAT_normalmap_tva;
|
matFlags = AI_IRRMESH_MAT_normalmap_tva;
|
||||||
} else if (prop.value == "normalmap_trans_add" ||
|
} else if (prop.value == "normalmap_trans_add" ||
|
||||||
prop.value == "parallaxmap_trans_add") {
|
prop.value == "parallaxmap_trans_add") {
|
||||||
matFlags = AI_IRRMESH_MAT_normalmap_ta;
|
matFlags = AI_IRRMESH_MAT_normalmap_ta;
|
||||||
} else {
|
} else {
|
||||||
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
|
ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Up to 4 texture channels are supported
|
// Up to 4 texture channels are supported
|
||||||
if (prop.name == "Texture1") {
|
if (prop.name == "Texture1") {
|
||||||
// Always accept the primary texture channel
|
// Always accept the primary texture channel
|
||||||
++cnt;
|
++cnt;
|
||||||
s.Set(prop.value);
|
s.Set(prop.value);
|
||||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||||
} else if (prop.name == "Texture2" && cnt == 1) {
|
} else if (prop.name == "Texture2" && cnt == 1) {
|
||||||
// 2-layer material lightmapped?
|
// 2-layer material lightmapped?
|
||||||
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
||||||
++cnt;
|
++cnt;
|
||||||
s.Set(prop.value);
|
s.Set(prop.value);
|
||||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
|
mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
|
||||||
|
|
||||||
// set the corresponding material flag
|
// set the corresponding material flag
|
||||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||||
} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
|
} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
|
||||||
++cnt;
|
++cnt;
|
||||||
s.Set(prop.value);
|
s.Set(prop.value);
|
||||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
|
mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
|
||||||
|
|
||||||
// set the corresponding material flag
|
// set the corresponding material flag
|
||||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||||
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
|
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
|
||||||
++cnt;
|
++cnt;
|
||||||
s.Set(prop.value);
|
s.Set(prop.value);
|
||||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
|
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
|
||||||
++nd;
|
++nd;
|
||||||
|
|
||||||
// set the corresponding material flag
|
// set the corresponding material flag
|
||||||
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
|
||||||
} else {
|
} else {
|
||||||
ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
|
ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
|
||||||
}
|
}
|
||||||
} else if (prop.name == "Texture3" && cnt == 2) {
|
} else if (prop.name == "Texture3" && cnt == 2) {
|
||||||
// Irrlicht does not seem to use these channels.
|
// Irrlicht does not seem to use these channels.
|
||||||
++cnt;
|
++cnt;
|
||||||
s.Set(prop.value);
|
s.Set(prop.value);
|
||||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
|
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
|
||||||
} else if (prop.name == "Texture4" && cnt == 3) {
|
} else if (prop.name == "Texture4" && cnt == 3) {
|
||||||
// Irrlicht does not seem to use these channels.
|
// Irrlicht does not seem to use these channels.
|
||||||
++cnt;
|
++cnt;
|
||||||
s.Set(prop.value);
|
s.Set(prop.value);
|
||||||
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
|
mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture mapping options
|
// Texture mapping options
|
||||||
if (prop.name == "TextureWrap1" && cnt >= 1) {
|
if (prop.name == "TextureWrap1" && cnt >= 1) {
|
||||||
int map = ConvertMappingMode(prop.value);
|
int map = ConvertMappingMode(prop.value);
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
|
||||||
} else if (prop.name == "TextureWrap2" && cnt >= 2) {
|
} else if (prop.name == "TextureWrap2" && cnt >= 2) {
|
||||||
int map = ConvertMappingMode(prop.value);
|
int map = ConvertMappingMode(prop.value);
|
||||||
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
if (matFlags & AI_IRRMESH_MAT_lightmap) {
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
|
||||||
} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
|
} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
|
||||||
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
|
} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
|
||||||
}
|
}
|
||||||
} else if (prop.name == "TextureWrap3" && cnt >= 3) {
|
} else if (prop.name == "TextureWrap3" && cnt >= 3) {
|
||||||
int map = ConvertMappingMode(prop.value);
|
int map = ConvertMappingMode(prop.value);
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
|
||||||
} else if (prop.name == "TextureWrap4" && cnt >= 4) {
|
} else if (prop.name == "TextureWrap4" && cnt >= 4) {
|
||||||
int map = ConvertMappingMode(prop.value);
|
int map = ConvertMappingMode(prop.value);
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
|
||||||
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
|
mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//break;
|
// break;
|
||||||
/*case EXN_ELEMENT_END:
|
/*case EXN_ELEMENT_END:
|
||||||
|
|
||||||
// Assume there are no further nested nodes in <material> elements
|
// Assume there are no further nested nodes in <material> elements
|
||||||
if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
|
if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
|
||||||
|
@ -378,8 +378,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
|
//ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
|
||||||
|
|
||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
|
|
||||||
/** @file IRRShared.h
|
/** @file IRRShared.h
|
||||||
* @brief Shared utilities for the IRR and IRRMESH loaders
|
* @brief Shared utilities for the IRR and IRRMESH loaders
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INCLUDED_AI_IRRSHARED_H
|
#ifndef INCLUDED_AI_IRRSHARED_H
|
||||||
#define INCLUDED_AI_IRRSHARED_H
|
#define INCLUDED_AI_IRRSHARED_H
|
||||||
|
@ -58,8 +58,7 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
|
||||||
*/
|
*/
|
||||||
class IrrlichtBase {
|
class IrrlichtBase {
|
||||||
protected:
|
protected:
|
||||||
IrrlichtBase() :
|
IrrlichtBase() {
|
||||||
mNode(nullptr) {
|
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,25 +81,25 @@ protected:
|
||||||
|
|
||||||
/// XML reader instance
|
/// XML reader instance
|
||||||
XmlParser mParser;
|
XmlParser mParser;
|
||||||
pugi::xml_node *mNode;
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse a material description from the XML
|
/** Parse a material description from the XML
|
||||||
* @return The created material
|
* @return The created material
|
||||||
* @param matFlags Receives AI_IRRMESH_MAT_XX flags
|
* @param matFlags Receives AI_IRRMESH_MAT_XX flags
|
||||||
*/
|
*/
|
||||||
aiMaterial *ParseMaterial(unsigned int &matFlags);
|
aiMaterial *ParseMaterial(pugi::xml_node &materialNode, unsigned int &matFlags);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Read a property of the specified type from the current XML element.
|
/** Read a property of the specified type from the current XML element.
|
||||||
* @param out Receives output data
|
* @param out Receives output data
|
||||||
|
* @param node XML attribute element containing data
|
||||||
*/
|
*/
|
||||||
void ReadHexProperty(HexProperty &out);
|
void ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode);
|
||||||
void ReadStringProperty(StringProperty &out);
|
void ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode);
|
||||||
void ReadBoolProperty(BoolProperty &out);
|
void ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode);
|
||||||
void ReadFloatProperty(FloatProperty &out);
|
void ReadFloatProperty(FloatProperty &out, pugi::xml_node& floatnode);
|
||||||
void ReadVectorProperty(VectorProperty &out);
|
void ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode);
|
||||||
void ReadIntProperty(IntProperty &out);
|
void ReadIntProperty(IntProperty &out, pugi::xml_node& intnode);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -837,7 +837,10 @@ void SMDImporter::ParseNodeInfo(const char* szCurrent, const char** szCurrentOut
|
||||||
unsigned int iBone = 0;
|
unsigned int iBone = 0;
|
||||||
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
SkipSpacesAndLineEnd(szCurrent,&szCurrent);
|
||||||
if ( !ParseUnsignedInt(szCurrent,&szCurrent,iBone) || !SkipSpaces(szCurrent,&szCurrent)) {
|
if ( !ParseUnsignedInt(szCurrent,&szCurrent,iBone) || !SkipSpaces(szCurrent,&szCurrent)) {
|
||||||
LogErrorNoThrow("Unexpected EOF/EOL while parsing bone index");
|
throw DeadlyImportError("Unexpected EOF/EOL while parsing bone index");
|
||||||
|
}
|
||||||
|
if (iBone == UINT_MAX) {
|
||||||
|
LogErrorNoThrow("Invalid bone number while parsing bone index");
|
||||||
SMDI_PARSE_RETURN;
|
SMDI_PARSE_RETURN;
|
||||||
}
|
}
|
||||||
// add our bone to the list
|
// add our bone to the list
|
||||||
|
|
|
@ -391,6 +391,19 @@ def export_blob(scene,
|
||||||
raise AssimpError('Could not export scene to blob!')
|
raise AssimpError('Could not export scene to blob!')
|
||||||
return exportBlobPtr
|
return exportBlobPtr
|
||||||
|
|
||||||
|
def available_formats():
|
||||||
|
"""
|
||||||
|
Return a list of file format extensions supported to import.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
A list of upper-case file extensions, e.g. [3DS, OBJ]
|
||||||
|
"""
|
||||||
|
from ctypes import byref
|
||||||
|
extension_list = structs.String()
|
||||||
|
_assimp_lib.dll.aiGetExtensionList(byref(extension_list))
|
||||||
|
return [e[2:].upper() for e in str(extension_list.data, sys.getfilesystemencoding()).split(";")]
|
||||||
|
|
||||||
def _finalize_texture(tex, target):
|
def _finalize_texture(tex, target):
|
||||||
setattr(target, "achformathint", tex.achFormatHint)
|
setattr(target, "achformathint", tex.achFormatHint)
|
||||||
if numpy:
|
if numpy:
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
FORMATS = ["CSM",
|
|
||||||
"LWS",
|
|
||||||
"B3D",
|
|
||||||
"COB",
|
|
||||||
"PLY",
|
|
||||||
"IFC",
|
|
||||||
"OFF",
|
|
||||||
"SMD",
|
|
||||||
"IRRMESH",
|
|
||||||
"3D",
|
|
||||||
"DAE",
|
|
||||||
"MDL",
|
|
||||||
"HMP",
|
|
||||||
"TER",
|
|
||||||
"WRL",
|
|
||||||
"XML",
|
|
||||||
"NFF",
|
|
||||||
"AC",
|
|
||||||
"OBJ",
|
|
||||||
"3DS",
|
|
||||||
"STL",
|
|
||||||
"IRR",
|
|
||||||
"Q3O",
|
|
||||||
"Q3D",
|
|
||||||
"MS3D",
|
|
||||||
"Q3S",
|
|
||||||
"ZGL",
|
|
||||||
"MD2",
|
|
||||||
"X",
|
|
||||||
"BLEND",
|
|
||||||
"XGL",
|
|
||||||
"MD5MESH",
|
|
||||||
"MAX",
|
|
||||||
"LXO",
|
|
||||||
"DXF",
|
|
||||||
"BVH",
|
|
||||||
"LWO",
|
|
||||||
"NDO"]
|
|
||||||
|
|
||||||
def available_formats():
|
|
||||||
return FORMATS
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
SCEA Shared Source License 1.0
|
||||||
|
|
||||||
|
Terms and Conditions:
|
||||||
|
|
||||||
|
1. Definitions:
|
||||||
|
"Software" shall mean the software and related documentation, whether in Source or Object Form, made available under this SCEA Shared Source license ("License"),
|
||||||
|
that is indicated by a copyright notice file included in the source files or attached or accompanying the source files.
|
||||||
|
|
||||||
|
"Licensor" shall mean Sony Computer Entertainment America, Inc. (herein "SCEA")
|
||||||
|
|
||||||
|
"Object Code" or "Object Form" shall mean any form that results from translation or transformation of Source Code, including but not limited to compiled object code
|
||||||
|
or conversions to other forms intended for machine execution. "Source Code" or "Source Form" shall have the plain meaning generally accepted in the software industry,
|
||||||
|
including but not limited to software source code, documentation source, header and configuration files.
|
||||||
|
|
||||||
|
"You" or "Your" shall mean you as an individual or as a company, or whichever form under which you are exercising rights under this License.
|
||||||
|
|
||||||
|
2. License Grant.
|
||||||
|
Licensor hereby grants to You, free of charge subject to the terms and conditions of this License, an irrevocable, non-exclusive, worldwide, perpetual, and royalty-free
|
||||||
|
license to use, modify, reproduce, distribute, publicly perform or display the Software in Object or Source Form .
|
||||||
|
|
||||||
|
4. No Right to File for Patent.
|
||||||
|
In exchange for the rights that are granted to You free of charge under this License, You agree that You will not file for any patent application, seek copyright
|
||||||
|
protection or take any other action that might otherwise impair the ownership rights in and to the Software that may belong to SCEA or any of the other contributors/authors
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
6. Contributions.
|
||||||
|
SCEA welcomes contributions in form of modifications, optimizations, tools or documentation designed to improve or expand the performance and scope of the Software
|
||||||
|
(collectively "Contributions"). Per the terms of this License You are free to modify the Software and those modifications would belong to You. You may however wish to
|
||||||
|
donate Your Contributions to SCEA for consideration for inclusion into the Software. For the avoidance of doubt, if You elect to send Your Contributions to SCEA, You are
|
||||||
|
doing so voluntarily and are giving the Contributions to SCEA and its parent company Sony Computer Entertainment, Inc., free of charge, to use, modify or distribute in
|
||||||
|
any form or in any manner. SCEA acknowledges that if You make a donation of Your Contributions to SCEA, such Contributions shall not exclusively belong to SCEA or its
|
||||||
|
parent company and such donation shall not be to Your exclusion. SCEA, in its sole discretion, shall determine whether or not to include Your donated Contributions into
|
||||||
|
the Software, in whole, in part, or as modified by SCEA. Should SCEA elect to include any such Contributions into the Software, it shall do so at its own risk and may elect
|
||||||
|
to give credit or special thanks to any such contributors in the attached copyright notice. However, if any of Your contributions are included into the Software, they will
|
||||||
|
become part of the Software and will be distributed under the terms and conditions of this License. Further, if Your donated Contributions are integrated into the Software
|
||||||
|
then Sony Computer Entertainment, Inc. shall become the copyright owner of the Software now containing Your contributions and SCEA would be the Licensor.
|
||||||
|
|
||||||
|
8. Redistribution in Source Form
|
||||||
|
You may redistribute copies of the Software, modifications or derivatives thereof in Source Code Form, provided that You:
|
||||||
|
|
||||||
|
a. Include a copy of this License and any copyright notices with source
|
||||||
|
b. Identify modifications if any were made to the Software
|
||||||
|
c. Include a copy of all documentation accompanying the Software and modifications made by You
|
||||||
|
6. Redistribution in Object Form
|
||||||
|
If You redistribute copies of the Software, modifications or derivatives thereof in Object Form only (as incorporated into finished goods, i.e. end user applications) then
|
||||||
|
You will not have a duty to include any copies of the code, this License, copyright notices, other attributions or documentation.
|
||||||
|
|
||||||
|
7. No Warranty
|
||||||
|
THE SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT ANY REPRESENTATIONS OR WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY
|
||||||
|
WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING,
|
||||||
|
MODIFYING OR REDISTRIBUTING THE SOFTWARE AND ASSUME ANY RISKS ASSOCIATED WITH YOUR EXERCISE OF PERMISSIONS UNDER THIS LICENSE.
|
||||||
|
|
||||||
|
9. Limitation of Liability
|
||||||
|
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY WILL EITHER PARTY BE LIABLE TO THE OTHER PARTY OR ANY THIRD PARTY FOR ANY DIRECT, INDIRECT, CONSEQUENTIAL, SPECIAL,
|
||||||
|
INCIDENTAL, OR EXEMPLARY DAMAGES WITH RESPECT TO ANY INJURY, LOSS, OR DAMAGE, ARISING UNDER OR IN CONNECTION WITH THIS LETTER AGREEMENT, WHETHER FORESEEABLE OR
|
||||||
|
UNFORESEEABLE, EVEN IF SUCH PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH INJURY, LOSS, OR DAMAGE. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION SHALL
|
||||||
|
APPLY TO THE FULLEST EXTENT PERMISSIBLE AT LAW OR ANY GOVERMENTAL REGULATIONS.
|
||||||
|
|
||||||
|
11. Governing Law and Consent to Jurisdiction
|
||||||
|
This Agreement shall be governed by and interpreted in accordance with the laws of the State of California, excluding that body of law related to choice of laws,
|
||||||
|
and of the United States of America. Any action or proceeding brought to enforce the terms of this Agreement or to adjudicate any dispute arising hereunder shall
|
||||||
|
be brought in the Superior Court of the County of San Mateo, State of California or the United States District Court for the Northern District of California. Each
|
||||||
|
of the parties hereby submits itself to the exclusive jurisdiction and venue of such courts for purposes of any such action. In addition, each party hereby waives the
|
||||||
|
right to a jury trial in any action or proceeding related to this Agreement.
|
||||||
|
|
||||||
|
13. Copyright Notice for Redistribution of Source Code
|
||||||
|
Copyright 2005 Sony Computer Entertainment Inc.
|
||||||
|
|
||||||
|
Licensed under the SCEA Shared Source License, Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
http://research.scea.com/scea_shared_source_license.html
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||||
|
ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
@ -48,19 +48,23 @@ using namespace Assimp;
|
||||||
|
|
||||||
class utIrrImportExport : public AbstractImportExportBase {
|
class utIrrImportExport : public AbstractImportExportBase {
|
||||||
public:
|
public:
|
||||||
virtual bool importerTest() {
|
virtual bool importerTest() {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/IRR/box.irr", aiProcess_ValidateDataStructure);
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/IRR/box.irr", aiProcess_ValidateDataStructure);
|
||||||
return nullptr != scene;
|
// Only one box thus only one mesh
|
||||||
}
|
return nullptr != scene && scene->mNumMeshes == 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(utIrrImportExport, importSimpleIrrTest) {
|
TEST_F(utIrrImportExport, importSimpleIrrTest) {
|
||||||
EXPECT_TRUE(importerTest());
|
EXPECT_TRUE(importerTest());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(utIrrImportExport, importSGIrrTest) {
|
TEST_F(utIrrImportExport, importSGIrrTest) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/IRR/dawfInCellar_SameHierarchy.irr", aiProcess_ValidateDataStructure);
|
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/IRR/dawfInCellar_SameHierarchy.irr", aiProcess_ValidateDataStructure);
|
||||||
EXPECT_NE( nullptr,scene);
|
EXPECT_NE(nullptr, scene);
|
||||||
|
EXPECT_EQ(scene->mNumMeshes, 2);
|
||||||
|
EXPECT_EQ(scene->mNumMaterials, 2);
|
||||||
|
EXPECT_GT(scene->mMeshes[0]->mNumVertices, 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue