Refactor: Expand tabs to 4 spaces
parent
a96a595a7a
commit
83de707587
File diff suppressed because it is too large
Load Diff
|
@ -53,129 +53,129 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
namespace {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Scope utility to write a 3DS file chunk.
|
||||
//
|
||||
// Upon construction, the chunk header is written with the chunk type (flags)
|
||||
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
|
||||
// size based on the then-position of the output stream cursor is filled in.
|
||||
class ChunkWriter {
|
||||
enum {
|
||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef
|
||||
, SIZE_OFFSET = 2
|
||||
};
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Scope utility to write a 3DS file chunk.
|
||||
//
|
||||
// Upon construction, the chunk header is written with the chunk type (flags)
|
||||
// filled out, but the chunk size left empty. Upon destruction, the correct chunk
|
||||
// size based on the then-position of the output stream cursor is filled in.
|
||||
class ChunkWriter {
|
||||
enum {
|
||||
CHUNK_SIZE_NOT_SET = 0xdeadbeef
|
||||
, SIZE_OFFSET = 2
|
||||
};
|
||||
public:
|
||||
|
||||
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
|
||||
: writer(writer)
|
||||
{
|
||||
chunk_start_pos = writer.GetCurrentPos();
|
||||
writer.PutU2(chunk_type);
|
||||
writer.PutU4(CHUNK_SIZE_NOT_SET);
|
||||
}
|
||||
ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
|
||||
: writer(writer)
|
||||
{
|
||||
chunk_start_pos = writer.GetCurrentPos();
|
||||
writer.PutU2(chunk_type);
|
||||
writer.PutU4(CHUNK_SIZE_NOT_SET);
|
||||
}
|
||||
|
||||
~ChunkWriter() {
|
||||
std::size_t head_pos = writer.GetCurrentPos();
|
||||
~ChunkWriter() {
|
||||
std::size_t head_pos = writer.GetCurrentPos();
|
||||
|
||||
ai_assert(head_pos > chunk_start_pos);
|
||||
const std::size_t chunk_size = head_pos - chunk_start_pos;
|
||||
ai_assert(head_pos > chunk_start_pos);
|
||||
const std::size_t chunk_size = head_pos - chunk_start_pos;
|
||||
|
||||
writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
|
||||
writer.PutU4(chunk_size);
|
||||
writer.SetCurrentPos(head_pos);
|
||||
}
|
||||
writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
|
||||
writer.PutU4(chunk_size);
|
||||
writer.SetCurrentPos(head_pos);
|
||||
}
|
||||
|
||||
private:
|
||||
StreamWriterLE& writer;
|
||||
std::size_t chunk_start_pos;
|
||||
};
|
||||
private:
|
||||
StreamWriterLE& writer;
|
||||
std::size_t chunk_start_pos;
|
||||
};
|
||||
|
||||
|
||||
// Return an unique name for a given |mesh| attached to |node| that
|
||||
// preserves the mesh's given name if it has one. |index| is the index
|
||||
// of the mesh in |aiScene::mMeshes|.
|
||||
std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
|
||||
static const std::string underscore = "_";
|
||||
char postfix[10] = {0};
|
||||
ASSIMP_itoa10(postfix, index);
|
||||
// Return an unique name for a given |mesh| attached to |node| that
|
||||
// preserves the mesh's given name if it has one. |index| is the index
|
||||
// of the mesh in |aiScene::mMeshes|.
|
||||
std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
|
||||
static const std::string underscore = "_";
|
||||
char postfix[10] = {0};
|
||||
ASSIMP_itoa10(postfix, index);
|
||||
|
||||
std::string result = node.mName.C_Str();
|
||||
if (mesh.mName.length > 0) {
|
||||
result += underscore + mesh.mName.C_Str();
|
||||
}
|
||||
return result + underscore + postfix;
|
||||
}
|
||||
std::string result = node.mName.C_Str();
|
||||
if (mesh.mName.length > 0) {
|
||||
result += underscore + mesh.mName.C_Str();
|
||||
}
|
||||
return result + underscore + postfix;
|
||||
}
|
||||
|
||||
// Return an unique name for a given |mat| with original position |index|
|
||||
// in |aiScene::mMaterials|. The name preserves the original material
|
||||
// name if possible.
|
||||
std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
|
||||
static const std::string underscore = "_";
|
||||
char postfix[10] = {0};
|
||||
ASSIMP_itoa10(postfix, index);
|
||||
// Return an unique name for a given |mat| with original position |index|
|
||||
// in |aiScene::mMaterials|. The name preserves the original material
|
||||
// name if possible.
|
||||
std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
|
||||
static const std::string underscore = "_";
|
||||
char postfix[10] = {0};
|
||||
ASSIMP_itoa10(postfix, index);
|
||||
|
||||
aiString mat_name;
|
||||
if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
|
||||
return mat_name.C_Str() + underscore + postfix;
|
||||
}
|
||||
aiString mat_name;
|
||||
if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
|
||||
return mat_name.C_Str() + underscore + postfix;
|
||||
}
|
||||
|
||||
return "Material" + underscore + postfix;
|
||||
}
|
||||
return "Material" + underscore + postfix;
|
||||
}
|
||||
|
||||
// Collect world transformations for each node
|
||||
void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
|
||||
const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
|
||||
trafos[node] = parent * node->mTransformation;
|
||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||
CollectTrafos(node->mChildren[i], trafos);
|
||||
}
|
||||
}
|
||||
// Collect world transformations for each node
|
||||
void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
|
||||
const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
|
||||
trafos[node] = parent * node->mTransformation;
|
||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||
CollectTrafos(node->mChildren[i], trafos);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a flat list of the meshes (by index) assigned to each node
|
||||
void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
|
||||
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
||||
meshes.insert(std::make_pair(node, node->mMeshes[i]));
|
||||
}
|
||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||
CollectMeshes(node->mChildren[i], meshes);
|
||||
}
|
||||
}
|
||||
// Generate a flat list of the meshes (by index) assigned to each node
|
||||
void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
|
||||
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
||||
meshes.insert(std::make_pair(node, node->mMeshes[i]));
|
||||
}
|
||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||
CollectMeshes(node->mChildren[i], meshes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
|
||||
void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
|
||||
{
|
||||
boost::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
|
||||
if(!outfile) {
|
||||
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
|
||||
}
|
||||
boost::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
|
||||
if(!outfile) {
|
||||
throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
|
||||
}
|
||||
|
||||
// TODO: This extra copy should be avoided and all of this made a preprocess
|
||||
// requirement of the 3DS exporter.
|
||||
//
|
||||
// 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively.
|
||||
// SplitLargeMeshes can do this, but it requires the correct limit to be set
|
||||
// which is not possible with the current way of specifying preprocess steps
|
||||
// in |Exporter::ExportFormatEntry|.
|
||||
aiScene* scenecopy_tmp;
|
||||
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
|
||||
std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
|
||||
// TODO: This extra copy should be avoided and all of this made a preprocess
|
||||
// requirement of the 3DS exporter.
|
||||
//
|
||||
// 3DS meshes can be max 0xffff (16 Bit) vertices and faces, respectively.
|
||||
// SplitLargeMeshes can do this, but it requires the correct limit to be set
|
||||
// which is not possible with the current way of specifying preprocess steps
|
||||
// in |Exporter::ExportFormatEntry|.
|
||||
aiScene* scenecopy_tmp;
|
||||
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
|
||||
std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
|
||||
|
||||
SplitLargeMeshesProcess_Triangle tri_splitter;
|
||||
tri_splitter.SetLimit(0xffff);
|
||||
tri_splitter.Execute(scenecopy.get());
|
||||
SplitLargeMeshesProcess_Triangle tri_splitter;
|
||||
tri_splitter.SetLimit(0xffff);
|
||||
tri_splitter.Execute(scenecopy.get());
|
||||
|
||||
SplitLargeMeshesProcess_Vertex vert_splitter;
|
||||
vert_splitter.SetLimit(0xffff);
|
||||
vert_splitter.Execute(scenecopy.get());
|
||||
SplitLargeMeshesProcess_Vertex vert_splitter;
|
||||
vert_splitter.SetLimit(0xffff);
|
||||
vert_splitter.Execute(scenecopy.get());
|
||||
|
||||
// Invoke the actual exporter
|
||||
Discreet3DSExporter exporter(outfile, scenecopy.get());
|
||||
// Invoke the actual exporter
|
||||
Discreet3DSExporter exporter(outfile, scenecopy.get());
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
@ -185,379 +185,379 @@ Discreet3DSExporter:: Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, c
|
|||
: scene(scene)
|
||||
, writer(outfile)
|
||||
{
|
||||
CollectTrafos(scene->mRootNode, trafos);
|
||||
CollectMeshes(scene->mRootNode, meshes);
|
||||
CollectTrafos(scene->mRootNode, trafos);
|
||||
CollectMeshes(scene->mRootNode, meshes);
|
||||
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN);
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
|
||||
WriteMaterials();
|
||||
WriteMeshes();
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
|
||||
WriteMaterials();
|
||||
WriteMeshes();
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
|
||||
writer.PutF4(1.0f);
|
||||
}
|
||||
}
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);
|
||||
writer.PutF4(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
|
||||
WriteHierarchy(*scene->mRootNode, -1, -1);
|
||||
}
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER);
|
||||
WriteHierarchy(*scene->mRootNode, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
|
||||
{
|
||||
// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||
// 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||
|
||||
// Assimp node names are unique and distinct from all mesh-node
|
||||
// names we generate; thus we can use them as-is
|
||||
WriteString(node.mName);
|
||||
// Assimp node names are unique and distinct from all mesh-node
|
||||
// names we generate; thus we can use them as-is
|
||||
WriteString(node.mName);
|
||||
|
||||
// Two unknown int16 values - it is even unclear if 0 is a safe value
|
||||
// but luckily importers do not know better either.
|
||||
writer.PutI4(0);
|
||||
// Two unknown int16 values - it is even unclear if 0 is a safe value
|
||||
// but luckily importers do not know better either.
|
||||
writer.PutI4(0);
|
||||
|
||||
int16_t hierarchy_pos = static_cast<int16_t>(seq);
|
||||
if (sibling_level != -1) {
|
||||
hierarchy_pos = sibling_level;
|
||||
}
|
||||
int16_t hierarchy_pos = static_cast<int16_t>(seq);
|
||||
if (sibling_level != -1) {
|
||||
hierarchy_pos = sibling_level;
|
||||
}
|
||||
|
||||
// Write the hierarchy position
|
||||
writer.PutI2(hierarchy_pos);
|
||||
}
|
||||
}
|
||||
// Write the hierarchy position
|
||||
writer.PutI2(hierarchy_pos);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: write transformation chunks
|
||||
// TODO: write transformation chunks
|
||||
|
||||
++seq;
|
||||
sibling_level = seq;
|
||||
++seq;
|
||||
sibling_level = seq;
|
||||
|
||||
// Write all children
|
||||
for (unsigned int i = 0; i < node.mNumChildren; ++i) {
|
||||
seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level);
|
||||
}
|
||||
// Write all children
|
||||
for (unsigned int i = 0; i < node.mNumChildren; ++i) {
|
||||
seq = WriteHierarchy(*node.mChildren[i], seq, i == 0 ? -1 : sibling_level);
|
||||
}
|
||||
|
||||
// Write all meshes as separate nodes to be able to reference the meshes by name
|
||||
for (unsigned int i = 0; i < node.mNumMeshes; ++i) {
|
||||
const bool first_child = node.mNumChildren == 0 && i == 0;
|
||||
// Write all meshes as separate nodes to be able to reference the meshes by name
|
||||
for (unsigned int i = 0; i < node.mNumMeshes; ++i) {
|
||||
const bool first_child = node.mNumChildren == 0 && i == 0;
|
||||
|
||||
const unsigned int mesh_idx = node.mMeshes[i];
|
||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
||||
const unsigned int mesh_idx = node.mMeshes[i];
|
||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
||||
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||
WriteString(GetMeshName(mesh, mesh_idx, node));
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME);
|
||||
WriteString(GetMeshName(mesh, mesh_idx, node));
|
||||
|
||||
writer.PutI4(0);
|
||||
writer.PutI2(static_cast<int16_t>(first_child ? seq : sibling_level));
|
||||
++seq;
|
||||
}
|
||||
}
|
||||
return seq;
|
||||
writer.PutI4(0);
|
||||
writer.PutI2(static_cast<int16_t>(first_child ? seq : sibling_level));
|
||||
++seq;
|
||||
}
|
||||
}
|
||||
return seq;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteMaterials()
|
||||
{
|
||||
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
|
||||
const aiMaterial& mat = *scene->mMaterials[i];
|
||||
for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
|
||||
const aiMaterial& mat = *scene->mMaterials[i];
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
|
||||
const std::string& name = GetMaterialName(mat, i);
|
||||
WriteString(name);
|
||||
}
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
|
||||
const std::string& name = GetMaterialName(mat, i);
|
||||
WriteString(name);
|
||||
}
|
||||
|
||||
aiColor3D color;
|
||||
if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
|
||||
WriteColor(color);
|
||||
}
|
||||
aiColor3D color;
|
||||
if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
|
||||
WriteColor(color);
|
||||
}
|
||||
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
|
||||
WriteColor(color);
|
||||
}
|
||||
if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
|
||||
WriteColor(color);
|
||||
}
|
||||
if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
|
||||
WriteColor(color);
|
||||
}
|
||||
|
||||
aiShadingMode shading_mode = aiShadingMode_Flat;
|
||||
if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
|
||||
aiShadingMode shading_mode = aiShadingMode_Flat;
|
||||
if (mat.Get(AI_MATKEY_SHADING_MODEL, shading_mode) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
|
||||
|
||||
Discreet3DS::shadetype3ds shading_mode_out;
|
||||
switch(shading_mode) {
|
||||
case aiShadingMode_Flat:
|
||||
case aiShadingMode_NoShading:
|
||||
shading_mode_out = Discreet3DS::Flat;
|
||||
break;
|
||||
Discreet3DS::shadetype3ds shading_mode_out;
|
||||
switch(shading_mode) {
|
||||
case aiShadingMode_Flat:
|
||||
case aiShadingMode_NoShading:
|
||||
shading_mode_out = Discreet3DS::Flat;
|
||||
break;
|
||||
|
||||
case aiShadingMode_Gouraud:
|
||||
case aiShadingMode_Toon:
|
||||
case aiShadingMode_OrenNayar:
|
||||
case aiShadingMode_Minnaert:
|
||||
shading_mode_out = Discreet3DS::Gouraud;
|
||||
break;
|
||||
case aiShadingMode_Gouraud:
|
||||
case aiShadingMode_Toon:
|
||||
case aiShadingMode_OrenNayar:
|
||||
case aiShadingMode_Minnaert:
|
||||
shading_mode_out = Discreet3DS::Gouraud;
|
||||
break;
|
||||
|
||||
case aiShadingMode_Phong:
|
||||
case aiShadingMode_Blinn:
|
||||
case aiShadingMode_CookTorrance:
|
||||
case aiShadingMode_Fresnel:
|
||||
shading_mode_out = Discreet3DS::Phong;
|
||||
break;
|
||||
case aiShadingMode_Phong:
|
||||
case aiShadingMode_Blinn:
|
||||
case aiShadingMode_CookTorrance:
|
||||
case aiShadingMode_Fresnel:
|
||||
shading_mode_out = Discreet3DS::Phong;
|
||||
break;
|
||||
|
||||
default:
|
||||
shading_mode_out = Discreet3DS::Flat;
|
||||
ai_assert(false);
|
||||
};
|
||||
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
|
||||
}
|
||||
default:
|
||||
shading_mode_out = Discreet3DS::Flat;
|
||||
ai_assert(false);
|
||||
};
|
||||
writer.PutU2(static_cast<uint16_t>(shading_mode_out));
|
||||
}
|
||||
|
||||
|
||||
float f;
|
||||
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
|
||||
WritePercentChunk(f);
|
||||
}
|
||||
float f;
|
||||
if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
|
||||
WritePercentChunk(f);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT);
|
||||
WritePercentChunk(f);
|
||||
}
|
||||
if (mat.Get(AI_MATKEY_SHININESS_STRENGTH, f) == AI_SUCCESS) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS_PERCENT);
|
||||
WritePercentChunk(f);
|
||||
}
|
||||
|
||||
int twosided;
|
||||
if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE);
|
||||
writer.PutI2(1);
|
||||
}
|
||||
int twosided;
|
||||
if (mat.Get(AI_MATKEY_TWOSIDED, twosided) == AI_SUCCESS && twosided != 0) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TWO_SIDE);
|
||||
writer.PutI2(1);
|
||||
}
|
||||
|
||||
WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
|
||||
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
|
||||
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
|
||||
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
|
||||
WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP);
|
||||
WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP);
|
||||
WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP);
|
||||
}
|
||||
WriteTexture(mat, aiTextureType_DIFFUSE, Discreet3DS::CHUNK_MAT_TEXTURE);
|
||||
WriteTexture(mat, aiTextureType_HEIGHT, Discreet3DS::CHUNK_MAT_BUMPMAP);
|
||||
WriteTexture(mat, aiTextureType_OPACITY, Discreet3DS::CHUNK_MAT_OPACMAP);
|
||||
WriteTexture(mat, aiTextureType_SHININESS, Discreet3DS::CHUNK_MAT_MAT_SHINMAP);
|
||||
WriteTexture(mat, aiTextureType_SPECULAR, Discreet3DS::CHUNK_MAT_SPECMAP);
|
||||
WriteTexture(mat, aiTextureType_EMISSIVE, Discreet3DS::CHUNK_MAT_SELFIMAP);
|
||||
WriteTexture(mat, aiTextureType_REFLECTION, Discreet3DS::CHUNK_MAT_REFLMAP);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
|
||||
{
|
||||
aiString path;
|
||||
aiTextureMapMode map_mode[2] = {
|
||||
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
||||
};
|
||||
float blend = 1.0f;
|
||||
if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
|
||||
return;
|
||||
}
|
||||
aiString path;
|
||||
aiTextureMapMode map_mode[2] = {
|
||||
aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
|
||||
};
|
||||
float blend = 1.0f;
|
||||
if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: handle embedded textures properly
|
||||
if (path.data[0] == '*') {
|
||||
DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str()));
|
||||
return;
|
||||
}
|
||||
// TODO: handle embedded textures properly
|
||||
if (path.data[0] == '*') {
|
||||
DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str()));
|
||||
return;
|
||||
}
|
||||
|
||||
ChunkWriter chunk(writer, chunk_flags);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
|
||||
WriteString(path);
|
||||
}
|
||||
ChunkWriter chunk(writer, chunk_flags);
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE);
|
||||
WriteString(path);
|
||||
}
|
||||
|
||||
WritePercentChunk(blend);
|
||||
WritePercentChunk(blend);
|
||||
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
|
||||
uint16_t val = 0; // WRAP
|
||||
if (map_mode[0] == aiTextureMapMode_Mirror) {
|
||||
val = 0x2;
|
||||
}
|
||||
else if (map_mode[0] == aiTextureMapMode_Decal) {
|
||||
val = 0x10;
|
||||
}
|
||||
writer.PutU2(val);
|
||||
}
|
||||
// TODO: export texture transformation (i.e. UV offset, scale, rotation)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING);
|
||||
uint16_t val = 0; // WRAP
|
||||
if (map_mode[0] == aiTextureMapMode_Mirror) {
|
||||
val = 0x2;
|
||||
}
|
||||
else if (map_mode[0] == aiTextureMapMode_Decal) {
|
||||
val = 0x10;
|
||||
}
|
||||
writer.PutU2(val);
|
||||
}
|
||||
// TODO: export texture transformation (i.e. UV offset, scale, rotation)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteMeshes()
|
||||
{
|
||||
// NOTE: 3DS allows for instances. However:
|
||||
// i) not all importers support reading them
|
||||
// ii) instances are not as flexible as they are in assimp, in particular,
|
||||
// nodes can carry (and instance) only one mesh.
|
||||
//
|
||||
// This exporter currently deep clones all instanced meshes, i.e. for each mesh
|
||||
// attached to a node a full TRIMESH chunk is written to the file.
|
||||
//
|
||||
// Furthermore, the TRIMESH is transformed into world space so that it will
|
||||
// appear correctly if importers don't read the scene hierarchy at all.
|
||||
for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
|
||||
const aiNode& node = *(*it).first;
|
||||
const unsigned int mesh_idx = (*it).second;
|
||||
// NOTE: 3DS allows for instances. However:
|
||||
// i) not all importers support reading them
|
||||
// ii) instances are not as flexible as they are in assimp, in particular,
|
||||
// nodes can carry (and instance) only one mesh.
|
||||
//
|
||||
// This exporter currently deep clones all instanced meshes, i.e. for each mesh
|
||||
// attached to a node a full TRIMESH chunk is written to the file.
|
||||
//
|
||||
// Furthermore, the TRIMESH is transformed into world space so that it will
|
||||
// appear correctly if importers don't read the scene hierarchy at all.
|
||||
for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
|
||||
const aiNode& node = *(*it).first;
|
||||
const unsigned int mesh_idx = (*it).second;
|
||||
|
||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
||||
const aiMesh& mesh = *scene->mMeshes[mesh_idx];
|
||||
|
||||
// This should not happen if the SLM step is correctly executed
|
||||
// before the scene is handed to the exporter
|
||||
ai_assert(mesh.mNumVertices <= 0xffff);
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
// This should not happen if the SLM step is correctly executed
|
||||
// before the scene is handed to the exporter
|
||||
ai_assert(mesh.mNumVertices <= 0xffff);
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
|
||||
const aiMatrix4x4& trafo = trafos[&node];
|
||||
const aiMatrix4x4& trafo = trafos[&node];
|
||||
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
|
||||
|
||||
// Mesh name is tied to the node it is attached to so it can later be referenced
|
||||
const std::string& name = GetMeshName(mesh, mesh_idx, node);
|
||||
WriteString(name);
|
||||
// Mesh name is tied to the node it is attached to so it can later be referenced
|
||||
const std::string& name = GetMeshName(mesh, mesh_idx, node);
|
||||
WriteString(name);
|
||||
|
||||
|
||||
// TRIMESH chunk
|
||||
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
|
||||
// TRIMESH chunk
|
||||
ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
|
||||
|
||||
// Vertices in world space
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
|
||||
// Vertices in world space
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST);
|
||||
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||
writer.PutU2(count);
|
||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||
const aiVector3D& v = trafo * mesh.mVertices[i];
|
||||
writer.PutF4(v.x);
|
||||
writer.PutF4(v.y);
|
||||
writer.PutF4(v.z);
|
||||
}
|
||||
}
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||
writer.PutU2(count);
|
||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||
const aiVector3D& v = trafo * mesh.mVertices[i];
|
||||
writer.PutF4(v.x);
|
||||
writer.PutF4(v.y);
|
||||
writer.PutF4(v.z);
|
||||
}
|
||||
}
|
||||
|
||||
// UV coordinates
|
||||
if (mesh.HasTextureCoords(0)) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||
writer.PutU2(count);
|
||||
// UV coordinates
|
||||
if (mesh.HasTextureCoords(0)) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST);
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
|
||||
writer.PutU2(count);
|
||||
|
||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||
const aiVector3D& v = mesh.mTextureCoords[0][i];
|
||||
writer.PutF4(v.x);
|
||||
writer.PutF4(v.y);
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
|
||||
const aiVector3D& v = mesh.mTextureCoords[0][i];
|
||||
writer.PutF4(v.x);
|
||||
writer.PutF4(v.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Faces (indices)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
|
||||
// Faces (indices)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST);
|
||||
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
|
||||
// Count triangles, discard lines and points
|
||||
uint16_t count = 0;
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
const aiFace& f = mesh.mFaces[i];
|
||||
if (f.mNumIndices < 3) {
|
||||
continue;
|
||||
}
|
||||
// TRIANGULATE step is a pre-requisite so we should not see polys here
|
||||
ai_assert(f.mNumIndices == 3);
|
||||
++count;
|
||||
}
|
||||
// Count triangles, discard lines and points
|
||||
uint16_t count = 0;
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
const aiFace& f = mesh.mFaces[i];
|
||||
if (f.mNumIndices < 3) {
|
||||
continue;
|
||||
}
|
||||
// TRIANGULATE step is a pre-requisite so we should not see polys here
|
||||
ai_assert(f.mNumIndices == 3);
|
||||
++count;
|
||||
}
|
||||
|
||||
writer.PutU2(count);
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
const aiFace& f = mesh.mFaces[i];
|
||||
if (f.mNumIndices < 3) {
|
||||
continue;
|
||||
}
|
||||
writer.PutU2(count);
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
const aiFace& f = mesh.mFaces[i];
|
||||
if (f.mNumIndices < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
ai_assert(f.mIndices[j] <= 0xffff);
|
||||
writer.PutI2(static_cast<uint16_t>(f.mIndices[j]));
|
||||
}
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
ai_assert(f.mIndices[j] <= 0xffff);
|
||||
writer.PutI2(static_cast<uint16_t>(f.mIndices[j]));
|
||||
}
|
||||
|
||||
// Edge visibility flag
|
||||
writer.PutI2(0x0);
|
||||
}
|
||||
// Edge visibility flag
|
||||
writer.PutI2(0x0);
|
||||
}
|
||||
|
||||
// TODO: write smoothing groups (CHUNK_SMOOLIST)
|
||||
// TODO: write smoothing groups (CHUNK_SMOOLIST)
|
||||
|
||||
WriteFaceMaterialChunk(mesh);
|
||||
}
|
||||
WriteFaceMaterialChunk(mesh);
|
||||
}
|
||||
|
||||
// Transformation matrix by which the mesh vertices have been pre-transformed with.
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
|
||||
for (unsigned int r = 0; r < 4; ++r) {
|
||||
for (unsigned int c = 0; c < 3; ++c) {
|
||||
writer.PutF4(trafo[r][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Transformation matrix by which the mesh vertices have been pre-transformed with.
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX);
|
||||
for (unsigned int r = 0; r < 4; ++r) {
|
||||
for (unsigned int c = 0; c < 3; ++c) {
|
||||
writer.PutF4(trafo[r][c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
|
||||
{
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
|
||||
const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
|
||||
WriteString(name);
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT);
|
||||
const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
|
||||
WriteString(name);
|
||||
|
||||
// Because assimp splits meshes by material, only a single
|
||||
// FACEMAT chunk needs to be written
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumFaces);
|
||||
writer.PutU2(count);
|
||||
// Because assimp splits meshes by material, only a single
|
||||
// FACEMAT chunk needs to be written
|
||||
ai_assert(mesh.mNumFaces <= 0xffff);
|
||||
const uint16_t count = static_cast<uint16_t>(mesh.mNumFaces);
|
||||
writer.PutU2(count);
|
||||
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
writer.PutU2(static_cast<uint16_t>(i));
|
||||
}
|
||||
for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
|
||||
writer.PutU2(static_cast<uint16_t>(i));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteString(const std::string& s) {
|
||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
writer.PutI1(*it);
|
||||
}
|
||||
writer.PutI1('\0');
|
||||
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
|
||||
writer.PutI1(*it);
|
||||
}
|
||||
writer.PutI1('\0');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteString(const aiString& s) {
|
||||
for (std::size_t i = 0; i < s.length; ++i) {
|
||||
writer.PutI1(s.data[i]);
|
||||
}
|
||||
writer.PutI1('\0');
|
||||
for (std::size_t i = 0; i < s.length; ++i) {
|
||||
writer.PutI1(s.data[i]);
|
||||
}
|
||||
writer.PutI1('\0');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
|
||||
writer.PutF4(color.r);
|
||||
writer.PutF4(color.g);
|
||||
writer.PutF4(color.b);
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF);
|
||||
writer.PutF4(color.r);
|
||||
writer.PutF4(color.g);
|
||||
writer.PutF4(color.b);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Discreet3DSExporter::WritePercentChunk(float f) {
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
|
||||
writer.PutF4(f);
|
||||
ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF);
|
||||
writer.PutF4(f);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -64,32 +64,32 @@ namespace Assimp
|
|||
class Discreet3DSExporter
|
||||
{
|
||||
public:
|
||||
Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, const aiScene* pScene);
|
||||
Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, const aiScene* pScene);
|
||||
|
||||
private:
|
||||
|
||||
void WriteMeshes();
|
||||
void WriteMaterials();
|
||||
void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
|
||||
void WriteMeshes();
|
||||
void WriteMaterials();
|
||||
void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
|
||||
|
||||
void WriteFaceMaterialChunk(const aiMesh& mesh);
|
||||
void WriteFaceMaterialChunk(const aiMesh& mesh);
|
||||
|
||||
int WriteHierarchy(const aiNode& node, int level, int sibling_level);
|
||||
int WriteHierarchy(const aiNode& node, int level, int sibling_level);
|
||||
|
||||
void WriteString(const std::string& s);
|
||||
void WriteString(const aiString& s);
|
||||
void WriteColor(const aiColor3D& color);
|
||||
void WritePercentChunk(float f);
|
||||
void WriteString(const std::string& s);
|
||||
void WriteString(const aiString& s);
|
||||
void WriteColor(const aiColor3D& color);
|
||||
void WritePercentChunk(float f);
|
||||
|
||||
private:
|
||||
|
||||
const aiScene* const scene;
|
||||
StreamWriterLE writer;
|
||||
const aiScene* const scene;
|
||||
StreamWriterLE writer;
|
||||
|
||||
std::map<const aiNode*, aiMatrix4x4> trafos;
|
||||
std::map<const aiNode*, aiMatrix4x4> trafos;
|
||||
|
||||
typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap;
|
||||
MeshesByNodeMap meshes;
|
||||
typedef std::multimap<const aiNode*, unsigned int> MeshesByNodeMap;
|
||||
MeshesByNodeMap meshes;
|
||||
|
||||
};
|
||||
|
||||
|
|
758
code/3DSHelper.h
758
code/3DSHelper.h
|
@ -53,8 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "./../include/assimp/anim.h"
|
||||
#include <stdio.h> //sprintf
|
||||
|
||||
namespace Assimp {
|
||||
namespace D3DS {
|
||||
namespace Assimp {
|
||||
namespace D3DS {
|
||||
|
||||
#include "./../include/assimp/Compiler/pushpack1.h"
|
||||
|
||||
|
@ -65,253 +65,253 @@ namespace D3DS {
|
|||
class Discreet3DS
|
||||
{
|
||||
private:
|
||||
inline Discreet3DS() {}
|
||||
inline Discreet3DS() {}
|
||||
|
||||
public:
|
||||
|
||||
//! data structure for a single chunk in a .3ds file
|
||||
struct Chunk
|
||||
{
|
||||
uint16_t Flag;
|
||||
uint32_t Size;
|
||||
} PACK_STRUCT;
|
||||
//! data structure for a single chunk in a .3ds file
|
||||
struct Chunk
|
||||
{
|
||||
uint16_t Flag;
|
||||
uint32_t Size;
|
||||
} PACK_STRUCT;
|
||||
|
||||
|
||||
//! Used for shading field in material3ds structure
|
||||
//! From AutoDesk 3ds SDK
|
||||
typedef enum
|
||||
{
|
||||
// translated to gouraud shading with wireframe active
|
||||
Wire = 0x0,
|
||||
//! Used for shading field in material3ds structure
|
||||
//! From AutoDesk 3ds SDK
|
||||
typedef enum
|
||||
{
|
||||
// translated to gouraud shading with wireframe active
|
||||
Wire = 0x0,
|
||||
|
||||
// if this material is set, no vertex normals will
|
||||
// be calculated for the model. Face normals + gouraud
|
||||
Flat = 0x1,
|
||||
// if this material is set, no vertex normals will
|
||||
// be calculated for the model. Face normals + gouraud
|
||||
Flat = 0x1,
|
||||
|
||||
// standard gouraud shading
|
||||
Gouraud = 0x2,
|
||||
// standard gouraud shading
|
||||
Gouraud = 0x2,
|
||||
|
||||
// phong shading
|
||||
Phong = 0x3,
|
||||
// phong shading
|
||||
Phong = 0x3,
|
||||
|
||||
// cooktorrance or anistropic phong shading ...
|
||||
// the exact meaning is unknown, if you know it
|
||||
// feel free to tell me ;-)
|
||||
Metal = 0x4,
|
||||
// cooktorrance or anistropic phong shading ...
|
||||
// the exact meaning is unknown, if you know it
|
||||
// feel free to tell me ;-)
|
||||
Metal = 0x4,
|
||||
|
||||
// required by the ASE loader
|
||||
Blinn = 0x5
|
||||
} shadetype3ds;
|
||||
// required by the ASE loader
|
||||
Blinn = 0x5
|
||||
} shadetype3ds;
|
||||
|
||||
// Flags for animated keys
|
||||
enum
|
||||
{
|
||||
KEY_USE_TENS = 0x1,
|
||||
KEY_USE_CONT = 0x2,
|
||||
KEY_USE_BIAS = 0x4,
|
||||
KEY_USE_EASE_TO = 0x8,
|
||||
KEY_USE_EASE_FROM = 0x10
|
||||
} ;
|
||||
// Flags for animated keys
|
||||
enum
|
||||
{
|
||||
KEY_USE_TENS = 0x1,
|
||||
KEY_USE_CONT = 0x2,
|
||||
KEY_USE_BIAS = 0x4,
|
||||
KEY_USE_EASE_TO = 0x8,
|
||||
KEY_USE_EASE_FROM = 0x10
|
||||
} ;
|
||||
|
||||
enum
|
||||
{
|
||||
enum
|
||||
{
|
||||
|
||||
// ********************************************************************
|
||||
// Basic chunks which can be found everywhere in the file
|
||||
CHUNK_VERSION = 0x0002,
|
||||
CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B
|
||||
CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B
|
||||
// ********************************************************************
|
||||
// Basic chunks which can be found everywhere in the file
|
||||
CHUNK_VERSION = 0x0002,
|
||||
CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B
|
||||
CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B
|
||||
|
||||
// Linear color values (gamma = 2.2?)
|
||||
CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B
|
||||
CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B
|
||||
// Linear color values (gamma = 2.2?)
|
||||
CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B
|
||||
CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B
|
||||
|
||||
CHUNK_PERCENTW = 0x0030, // int2 percentage
|
||||
CHUNK_PERCENTF = 0x0031, // float4 percentage
|
||||
// ********************************************************************
|
||||
CHUNK_PERCENTW = 0x0030, // int2 percentage
|
||||
CHUNK_PERCENTF = 0x0031, // float4 percentage
|
||||
// ********************************************************************
|
||||
|
||||
// Prj master chunk
|
||||
CHUNK_PRJ = 0xC23D,
|
||||
// Prj master chunk
|
||||
CHUNK_PRJ = 0xC23D,
|
||||
|
||||
// MDLI master chunk
|
||||
CHUNK_MLI = 0x3DAA,
|
||||
// MDLI master chunk
|
||||
CHUNK_MLI = 0x3DAA,
|
||||
|
||||
// Primary main chunk of the .3ds file
|
||||
CHUNK_MAIN = 0x4D4D,
|
||||
// Primary main chunk of the .3ds file
|
||||
CHUNK_MAIN = 0x4D4D,
|
||||
|
||||
// Mesh main chunk
|
||||
CHUNK_OBJMESH = 0x3D3D,
|
||||
// Mesh main chunk
|
||||
CHUNK_OBJMESH = 0x3D3D,
|
||||
|
||||
// Specifies the background color of the .3ds file
|
||||
// This is passed through the material system for
|
||||
// viewing purposes.
|
||||
CHUNK_BKGCOLOR = 0x1200,
|
||||
// Specifies the background color of the .3ds file
|
||||
// This is passed through the material system for
|
||||
// viewing purposes.
|
||||
CHUNK_BKGCOLOR = 0x1200,
|
||||
|
||||
// Specifies the ambient base color of the scene.
|
||||
// This is added to all materials in the file
|
||||
CHUNK_AMBCOLOR = 0x2100,
|
||||
// Specifies the ambient base color of the scene.
|
||||
// This is added to all materials in the file
|
||||
CHUNK_AMBCOLOR = 0x2100,
|
||||
|
||||
// Specifies the background image for the whole scene
|
||||
// This value is passed through the material system
|
||||
// to the viewer
|
||||
CHUNK_BIT_MAP = 0x1100,
|
||||
CHUNK_BIT_MAP_EXISTS = 0x1101,
|
||||
// Specifies the background image for the whole scene
|
||||
// This value is passed through the material system
|
||||
// to the viewer
|
||||
CHUNK_BIT_MAP = 0x1100,
|
||||
CHUNK_BIT_MAP_EXISTS = 0x1101,
|
||||
|
||||
// ********************************************************************
|
||||
// Viewport related stuff. Ignored
|
||||
CHUNK_DEFAULT_VIEW = 0x3000,
|
||||
CHUNK_VIEW_TOP = 0x3010,
|
||||
CHUNK_VIEW_BOTTOM = 0x3020,
|
||||
CHUNK_VIEW_LEFT = 0x3030,
|
||||
CHUNK_VIEW_RIGHT = 0x3040,
|
||||
CHUNK_VIEW_FRONT = 0x3050,
|
||||
CHUNK_VIEW_BACK = 0x3060,
|
||||
CHUNK_VIEW_USER = 0x3070,
|
||||
CHUNK_VIEW_CAMERA = 0x3080,
|
||||
// ********************************************************************
|
||||
// ********************************************************************
|
||||
// Viewport related stuff. Ignored
|
||||
CHUNK_DEFAULT_VIEW = 0x3000,
|
||||
CHUNK_VIEW_TOP = 0x3010,
|
||||
CHUNK_VIEW_BOTTOM = 0x3020,
|
||||
CHUNK_VIEW_LEFT = 0x3030,
|
||||
CHUNK_VIEW_RIGHT = 0x3040,
|
||||
CHUNK_VIEW_FRONT = 0x3050,
|
||||
CHUNK_VIEW_BACK = 0x3060,
|
||||
CHUNK_VIEW_USER = 0x3070,
|
||||
CHUNK_VIEW_CAMERA = 0x3080,
|
||||
// ********************************************************************
|
||||
|
||||
// Mesh chunks
|
||||
CHUNK_OBJBLOCK = 0x4000,
|
||||
CHUNK_TRIMESH = 0x4100,
|
||||
CHUNK_VERTLIST = 0x4110,
|
||||
CHUNK_VERTFLAGS = 0x4111,
|
||||
CHUNK_FACELIST = 0x4120,
|
||||
CHUNK_FACEMAT = 0x4130,
|
||||
CHUNK_MAPLIST = 0x4140,
|
||||
CHUNK_SMOOLIST = 0x4150,
|
||||
CHUNK_TRMATRIX = 0x4160,
|
||||
CHUNK_MESHCOLOR = 0x4165,
|
||||
CHUNK_TXTINFO = 0x4170,
|
||||
CHUNK_LIGHT = 0x4600,
|
||||
CHUNK_CAMERA = 0x4700,
|
||||
CHUNK_HIERARCHY = 0x4F00,
|
||||
// Mesh chunks
|
||||
CHUNK_OBJBLOCK = 0x4000,
|
||||
CHUNK_TRIMESH = 0x4100,
|
||||
CHUNK_VERTLIST = 0x4110,
|
||||
CHUNK_VERTFLAGS = 0x4111,
|
||||
CHUNK_FACELIST = 0x4120,
|
||||
CHUNK_FACEMAT = 0x4130,
|
||||
CHUNK_MAPLIST = 0x4140,
|
||||
CHUNK_SMOOLIST = 0x4150,
|
||||
CHUNK_TRMATRIX = 0x4160,
|
||||
CHUNK_MESHCOLOR = 0x4165,
|
||||
CHUNK_TXTINFO = 0x4170,
|
||||
CHUNK_LIGHT = 0x4600,
|
||||
CHUNK_CAMERA = 0x4700,
|
||||
CHUNK_HIERARCHY = 0x4F00,
|
||||
|
||||
// Specifies the global scaling factor. This is applied
|
||||
// to the root node's transformation matrix
|
||||
CHUNK_MASTER_SCALE = 0x0100,
|
||||
// Specifies the global scaling factor. This is applied
|
||||
// to the root node's transformation matrix
|
||||
CHUNK_MASTER_SCALE = 0x0100,
|
||||
|
||||
// ********************************************************************
|
||||
// Material chunks
|
||||
CHUNK_MAT_MATERIAL = 0xAFFF,
|
||||
// ********************************************************************
|
||||
// Material chunks
|
||||
CHUNK_MAT_MATERIAL = 0xAFFF,
|
||||
|
||||
// asciiz containing the name of the material
|
||||
CHUNK_MAT_MATNAME = 0xA000,
|
||||
CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk
|
||||
CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk
|
||||
CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk
|
||||
// asciiz containing the name of the material
|
||||
CHUNK_MAT_MATNAME = 0xA000,
|
||||
CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk
|
||||
CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk
|
||||
CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk
|
||||
|
||||
// Specifies the shininess of the material
|
||||
// followed by percentage chunk
|
||||
CHUNK_MAT_SHININESS = 0xA040,
|
||||
CHUNK_MAT_SHININESS_PERCENT = 0xA041 ,
|
||||
// Specifies the shininess of the material
|
||||
// followed by percentage chunk
|
||||
CHUNK_MAT_SHININESS = 0xA040,
|
||||
CHUNK_MAT_SHININESS_PERCENT = 0xA041 ,
|
||||
|
||||
// Specifies the shading mode to be used
|
||||
// followed by a short
|
||||
CHUNK_MAT_SHADING = 0xA100,
|
||||
// Specifies the shading mode to be used
|
||||
// followed by a short
|
||||
CHUNK_MAT_SHADING = 0xA100,
|
||||
|
||||
// NOTE: Emissive color (self illumination) seems not
|
||||
// to be a color but a single value, type is unknown.
|
||||
// Make the parser accept both of them.
|
||||
// followed by percentage chunk (?)
|
||||
CHUNK_MAT_SELF_ILLUM = 0xA080,
|
||||
// NOTE: Emissive color (self illumination) seems not
|
||||
// to be a color but a single value, type is unknown.
|
||||
// Make the parser accept both of them.
|
||||
// followed by percentage chunk (?)
|
||||
CHUNK_MAT_SELF_ILLUM = 0xA080,
|
||||
|
||||
// Always followed by percentage chunk (?)
|
||||
CHUNK_MAT_SELF_ILPCT = 0xA084,
|
||||
// Always followed by percentage chunk (?)
|
||||
CHUNK_MAT_SELF_ILPCT = 0xA084,
|
||||
|
||||
// Always followed by percentage chunk
|
||||
CHUNK_MAT_TRANSPARENCY = 0xA050,
|
||||
// Always followed by percentage chunk
|
||||
CHUNK_MAT_TRANSPARENCY = 0xA050,
|
||||
|
||||
// Diffuse texture channel 0
|
||||
CHUNK_MAT_TEXTURE = 0xA200,
|
||||
// Diffuse texture channel 0
|
||||
CHUNK_MAT_TEXTURE = 0xA200,
|
||||
|
||||
// Contains opacity information for each texel
|
||||
CHUNK_MAT_OPACMAP = 0xA210,
|
||||
// Contains opacity information for each texel
|
||||
CHUNK_MAT_OPACMAP = 0xA210,
|
||||
|
||||
// Contains a reflection map to be used to reflect
|
||||
// the environment. This is partially supported.
|
||||
CHUNK_MAT_REFLMAP = 0xA220,
|
||||
// Contains a reflection map to be used to reflect
|
||||
// the environment. This is partially supported.
|
||||
CHUNK_MAT_REFLMAP = 0xA220,
|
||||
|
||||
// Self Illumination map (emissive colors)
|
||||
CHUNK_MAT_SELFIMAP = 0xA33d,
|
||||
// Self Illumination map (emissive colors)
|
||||
CHUNK_MAT_SELFIMAP = 0xA33d,
|
||||
|
||||
// Bumpmap. Not specified whether it is a heightmap
|
||||
// or a normal map. Assme it is a heightmap since
|
||||
// artist normally prefer this format.
|
||||
CHUNK_MAT_BUMPMAP = 0xA230,
|
||||
// Bumpmap. Not specified whether it is a heightmap
|
||||
// or a normal map. Assme it is a heightmap since
|
||||
// artist normally prefer this format.
|
||||
CHUNK_MAT_BUMPMAP = 0xA230,
|
||||
|
||||
// Specular map. Seems to influence the specular color
|
||||
CHUNK_MAT_SPECMAP = 0xA204,
|
||||
// Specular map. Seems to influence the specular color
|
||||
CHUNK_MAT_SPECMAP = 0xA204,
|
||||
|
||||
// Holds shininess data.
|
||||
CHUNK_MAT_MAT_SHINMAP = 0xA33C,
|
||||
// Holds shininess data.
|
||||
CHUNK_MAT_MAT_SHINMAP = 0xA33C,
|
||||
|
||||
// Scaling in U/V direction.
|
||||
// (need to gen separate UV coordinate set
|
||||
// and do this by hand)
|
||||
CHUNK_MAT_MAP_USCALE = 0xA354,
|
||||
CHUNK_MAT_MAP_VSCALE = 0xA356,
|
||||
// Scaling in U/V direction.
|
||||
// (need to gen separate UV coordinate set
|
||||
// and do this by hand)
|
||||
CHUNK_MAT_MAP_USCALE = 0xA354,
|
||||
CHUNK_MAT_MAP_VSCALE = 0xA356,
|
||||
|
||||
// Translation in U/V direction.
|
||||
// (need to gen separate UV coordinate set
|
||||
// and do this by hand)
|
||||
CHUNK_MAT_MAP_UOFFSET = 0xA358,
|
||||
CHUNK_MAT_MAP_VOFFSET = 0xA35a,
|
||||
// Translation in U/V direction.
|
||||
// (need to gen separate UV coordinate set
|
||||
// and do this by hand)
|
||||
CHUNK_MAT_MAP_UOFFSET = 0xA358,
|
||||
CHUNK_MAT_MAP_VOFFSET = 0xA35a,
|
||||
|
||||
// UV-coordinates rotation around the z-axis
|
||||
// Assumed to be in radians.
|
||||
CHUNK_MAT_MAP_ANG = 0xA35C,
|
||||
// UV-coordinates rotation around the z-axis
|
||||
// Assumed to be in radians.
|
||||
CHUNK_MAT_MAP_ANG = 0xA35C,
|
||||
|
||||
// Tiling flags for 3DS files
|
||||
CHUNK_MAT_MAP_TILING = 0xa351,
|
||||
// Tiling flags for 3DS files
|
||||
CHUNK_MAT_MAP_TILING = 0xa351,
|
||||
|
||||
// Specifies the file name of a texture
|
||||
CHUNK_MAPFILE = 0xA300,
|
||||
// Specifies the file name of a texture
|
||||
CHUNK_MAPFILE = 0xA300,
|
||||
|
||||
// Specifies whether a materail requires two-sided rendering
|
||||
CHUNK_MAT_TWO_SIDE = 0xA081,
|
||||
// ********************************************************************
|
||||
// Specifies whether a materail requires two-sided rendering
|
||||
CHUNK_MAT_TWO_SIDE = 0xA081,
|
||||
// ********************************************************************
|
||||
|
||||
// Main keyframer chunk. Contains translation/rotation/scaling data
|
||||
CHUNK_KEYFRAMER = 0xB000,
|
||||
// Main keyframer chunk. Contains translation/rotation/scaling data
|
||||
CHUNK_KEYFRAMER = 0xB000,
|
||||
|
||||
// Supported sub chunks
|
||||
CHUNK_TRACKINFO = 0xB002,
|
||||
CHUNK_TRACKOBJNAME = 0xB010,
|
||||
CHUNK_TRACKDUMMYOBJNAME = 0xB011,
|
||||
CHUNK_TRACKPIVOT = 0xB013,
|
||||
CHUNK_TRACKPOS = 0xB020,
|
||||
CHUNK_TRACKROTATE = 0xB021,
|
||||
CHUNK_TRACKSCALE = 0xB022,
|
||||
// Supported sub chunks
|
||||
CHUNK_TRACKINFO = 0xB002,
|
||||
CHUNK_TRACKOBJNAME = 0xB010,
|
||||
CHUNK_TRACKDUMMYOBJNAME = 0xB011,
|
||||
CHUNK_TRACKPIVOT = 0xB013,
|
||||
CHUNK_TRACKPOS = 0xB020,
|
||||
CHUNK_TRACKROTATE = 0xB021,
|
||||
CHUNK_TRACKSCALE = 0xB022,
|
||||
|
||||
// ********************************************************************
|
||||
// Keyframes for various other stuff in the file
|
||||
// Partially ignored
|
||||
CHUNK_AMBIENTKEY = 0xB001,
|
||||
CHUNK_TRACKMORPH = 0xB026,
|
||||
CHUNK_TRACKHIDE = 0xB029,
|
||||
CHUNK_OBJNUMBER = 0xB030,
|
||||
CHUNK_TRACKCAMERA = 0xB003,
|
||||
CHUNK_TRACKFOV = 0xB023,
|
||||
CHUNK_TRACKROLL = 0xB024,
|
||||
CHUNK_TRACKCAMTGT = 0xB004,
|
||||
CHUNK_TRACKLIGHT = 0xB005,
|
||||
CHUNK_TRACKLIGTGT = 0xB006,
|
||||
CHUNK_TRACKSPOTL = 0xB007,
|
||||
CHUNK_FRAMES = 0xB008,
|
||||
// ********************************************************************
|
||||
// ********************************************************************
|
||||
// Keyframes for various other stuff in the file
|
||||
// Partially ignored
|
||||
CHUNK_AMBIENTKEY = 0xB001,
|
||||
CHUNK_TRACKMORPH = 0xB026,
|
||||
CHUNK_TRACKHIDE = 0xB029,
|
||||
CHUNK_OBJNUMBER = 0xB030,
|
||||
CHUNK_TRACKCAMERA = 0xB003,
|
||||
CHUNK_TRACKFOV = 0xB023,
|
||||
CHUNK_TRACKROLL = 0xB024,
|
||||
CHUNK_TRACKCAMTGT = 0xB004,
|
||||
CHUNK_TRACKLIGHT = 0xB005,
|
||||
CHUNK_TRACKLIGTGT = 0xB006,
|
||||
CHUNK_TRACKSPOTL = 0xB007,
|
||||
CHUNK_FRAMES = 0xB008,
|
||||
// ********************************************************************
|
||||
|
||||
// light sub-chunks
|
||||
CHUNK_DL_OFF = 0x4620,
|
||||
CHUNK_DL_OUTER_RANGE = 0x465A,
|
||||
CHUNK_DL_INNER_RANGE = 0x4659,
|
||||
CHUNK_DL_MULTIPLIER = 0x465B,
|
||||
CHUNK_DL_EXCLUDE = 0x4654,
|
||||
CHUNK_DL_ATTENUATE = 0x4625,
|
||||
CHUNK_DL_SPOTLIGHT = 0x4610,
|
||||
// light sub-chunks
|
||||
CHUNK_DL_OFF = 0x4620,
|
||||
CHUNK_DL_OUTER_RANGE = 0x465A,
|
||||
CHUNK_DL_INNER_RANGE = 0x4659,
|
||||
CHUNK_DL_MULTIPLIER = 0x465B,
|
||||
CHUNK_DL_EXCLUDE = 0x4654,
|
||||
CHUNK_DL_ATTENUATE = 0x4625,
|
||||
CHUNK_DL_SPOTLIGHT = 0x4610,
|
||||
|
||||
// camera sub-chunks
|
||||
CHUNK_CAM_RANGES = 0x4720
|
||||
};
|
||||
// camera sub-chunks
|
||||
CHUNK_CAM_RANGES = 0x4720
|
||||
};
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -324,38 +324,38 @@ struct Face : public FaceWithSmoothingGroup
|
|||
/** Helper structure representing a texture */
|
||||
struct Texture
|
||||
{
|
||||
//! Default constructor
|
||||
Texture()
|
||||
: mOffsetU (0.0f)
|
||||
, mOffsetV (0.0f)
|
||||
, mScaleU (1.0f)
|
||||
, mScaleV (1.0f)
|
||||
, mRotation (0.0f)
|
||||
, mMapMode (aiTextureMapMode_Wrap)
|
||||
, iUVSrc (0)
|
||||
{
|
||||
mTextureBlend = get_qnan();
|
||||
}
|
||||
//! Default constructor
|
||||
Texture()
|
||||
: mOffsetU (0.0f)
|
||||
, mOffsetV (0.0f)
|
||||
, mScaleU (1.0f)
|
||||
, mScaleV (1.0f)
|
||||
, mRotation (0.0f)
|
||||
, mMapMode (aiTextureMapMode_Wrap)
|
||||
, iUVSrc (0)
|
||||
{
|
||||
mTextureBlend = get_qnan();
|
||||
}
|
||||
|
||||
//! Specifies the blend factor for the texture
|
||||
float mTextureBlend;
|
||||
//! Specifies the blend factor for the texture
|
||||
float mTextureBlend;
|
||||
|
||||
//! Specifies the filename of the texture
|
||||
std::string mMapName;
|
||||
//! Specifies the filename of the texture
|
||||
std::string mMapName;
|
||||
|
||||
//! Specifies texture coordinate offsets/scaling/rotations
|
||||
float mOffsetU;
|
||||
float mOffsetV;
|
||||
float mScaleU;
|
||||
float mScaleV;
|
||||
float mRotation;
|
||||
//! Specifies texture coordinate offsets/scaling/rotations
|
||||
float mOffsetU;
|
||||
float mOffsetV;
|
||||
float mScaleU;
|
||||
float mScaleV;
|
||||
float mRotation;
|
||||
|
||||
//! Specifies the mapping mode to be used for the texture
|
||||
aiTextureMapMode mMapMode;
|
||||
//! Specifies the mapping mode to be used for the texture
|
||||
aiTextureMapMode mMapMode;
|
||||
|
||||
//! Used internally
|
||||
bool bPrivate;
|
||||
int iUVSrc;
|
||||
//! Used internally
|
||||
bool bPrivate;
|
||||
int iUVSrc;
|
||||
};
|
||||
|
||||
#include "./../include/assimp/Compiler/poppack1.h"
|
||||
|
@ -364,91 +364,91 @@ struct Texture
|
|||
/** Helper structure representing a 3ds material */
|
||||
struct Material
|
||||
{
|
||||
//! Default constructor. Builds a default name for the material
|
||||
Material()
|
||||
:
|
||||
mDiffuse (0.6f,0.6f,0.6f), // FIX ... we won't want object to be black
|
||||
mSpecularExponent (0.0f),
|
||||
mShininessStrength (1.0f),
|
||||
mShading(Discreet3DS::Gouraud),
|
||||
mTransparency (1.0f),
|
||||
mBumpHeight (1.0f),
|
||||
mTwoSided (false)
|
||||
{
|
||||
static int iCnt = 0;
|
||||
//! Default constructor. Builds a default name for the material
|
||||
Material()
|
||||
:
|
||||
mDiffuse (0.6f,0.6f,0.6f), // FIX ... we won't want object to be black
|
||||
mSpecularExponent (0.0f),
|
||||
mShininessStrength (1.0f),
|
||||
mShading(Discreet3DS::Gouraud),
|
||||
mTransparency (1.0f),
|
||||
mBumpHeight (1.0f),
|
||||
mTwoSided (false)
|
||||
{
|
||||
static int iCnt = 0;
|
||||
|
||||
char szTemp[128];
|
||||
sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||
mName = szTemp;
|
||||
}
|
||||
char szTemp[128];
|
||||
sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||
mName = szTemp;
|
||||
}
|
||||
|
||||
//! Name of the material
|
||||
std::string mName;
|
||||
//! Diffuse color of the material
|
||||
aiColor3D mDiffuse;
|
||||
//! Specular exponent
|
||||
float mSpecularExponent;
|
||||
//! Shininess strength, in percent
|
||||
float mShininessStrength;
|
||||
//! Specular color of the material
|
||||
aiColor3D mSpecular;
|
||||
//! Ambient color of the material
|
||||
aiColor3D mAmbient;
|
||||
//! Shading type to be used
|
||||
Discreet3DS::shadetype3ds mShading;
|
||||
//! Opacity of the material
|
||||
float mTransparency;
|
||||
//! Diffuse texture channel
|
||||
Texture sTexDiffuse;
|
||||
//! Opacity texture channel
|
||||
Texture sTexOpacity;
|
||||
//! Specular texture channel
|
||||
Texture sTexSpecular;
|
||||
//! Reflective texture channel
|
||||
Texture sTexReflective;
|
||||
//! Bump texture channel
|
||||
Texture sTexBump;
|
||||
//! Emissive texture channel
|
||||
Texture sTexEmissive;
|
||||
//! Shininess texture channel
|
||||
Texture sTexShininess;
|
||||
//! Scaling factor for the bump values
|
||||
float mBumpHeight;
|
||||
//! Emissive color
|
||||
aiColor3D mEmissive;
|
||||
//! Ambient texture channel
|
||||
//! (used by the ASE format)
|
||||
Texture sTexAmbient;
|
||||
//! True if the material must be rendered from two sides
|
||||
bool mTwoSided;
|
||||
//! Name of the material
|
||||
std::string mName;
|
||||
//! Diffuse color of the material
|
||||
aiColor3D mDiffuse;
|
||||
//! Specular exponent
|
||||
float mSpecularExponent;
|
||||
//! Shininess strength, in percent
|
||||
float mShininessStrength;
|
||||
//! Specular color of the material
|
||||
aiColor3D mSpecular;
|
||||
//! Ambient color of the material
|
||||
aiColor3D mAmbient;
|
||||
//! Shading type to be used
|
||||
Discreet3DS::shadetype3ds mShading;
|
||||
//! Opacity of the material
|
||||
float mTransparency;
|
||||
//! Diffuse texture channel
|
||||
Texture sTexDiffuse;
|
||||
//! Opacity texture channel
|
||||
Texture sTexOpacity;
|
||||
//! Specular texture channel
|
||||
Texture sTexSpecular;
|
||||
//! Reflective texture channel
|
||||
Texture sTexReflective;
|
||||
//! Bump texture channel
|
||||
Texture sTexBump;
|
||||
//! Emissive texture channel
|
||||
Texture sTexEmissive;
|
||||
//! Shininess texture channel
|
||||
Texture sTexShininess;
|
||||
//! Scaling factor for the bump values
|
||||
float mBumpHeight;
|
||||
//! Emissive color
|
||||
aiColor3D mEmissive;
|
||||
//! Ambient texture channel
|
||||
//! (used by the ASE format)
|
||||
Texture sTexAmbient;
|
||||
//! True if the material must be rendered from two sides
|
||||
bool mTwoSided;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure to represent a 3ds file mesh */
|
||||
struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
|
||||
{
|
||||
//! Default constructor
|
||||
Mesh()
|
||||
{
|
||||
static int iCnt = 0;
|
||||
//! Default constructor
|
||||
Mesh()
|
||||
{
|
||||
static int iCnt = 0;
|
||||
|
||||
// Generate a default name for the mesh
|
||||
char szTemp[128];
|
||||
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||
mName = szTemp;
|
||||
}
|
||||
// Generate a default name for the mesh
|
||||
char szTemp[128];
|
||||
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||
mName = szTemp;
|
||||
}
|
||||
|
||||
//! Name of the mesh
|
||||
std::string mName;
|
||||
//! Name of the mesh
|
||||
std::string mName;
|
||||
|
||||
//! Texture coordinates
|
||||
std::vector<aiVector3D> mTexCoords;
|
||||
//! Texture coordinates
|
||||
std::vector<aiVector3D> mTexCoords;
|
||||
|
||||
//! Face materials
|
||||
std::vector<unsigned int> mFaceMaterials;
|
||||
//! Face materials
|
||||
std::vector<unsigned int> mFaceMaterials;
|
||||
|
||||
//! Local transformation matrix
|
||||
aiMatrix4x4 mMat;
|
||||
//! Local transformation matrix
|
||||
aiMatrix4x4 mMat;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -456,25 +456,25 @@ struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
|
|||
C-API, so it would be difficult to make them a template. */
|
||||
struct aiFloatKey
|
||||
{
|
||||
double mTime; ///< The time of this key
|
||||
float mValue; ///< The value of this key
|
||||
double mTime; ///< The time of this key
|
||||
float mValue; ///< The value of this key
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// time is not compared
|
||||
bool operator == (const aiFloatKey& o) const
|
||||
{return o.mValue == this->mValue;}
|
||||
// time is not compared
|
||||
bool operator == (const aiFloatKey& o) const
|
||||
{return o.mValue == this->mValue;}
|
||||
|
||||
bool operator != (const aiFloatKey& o) const
|
||||
{return o.mValue != this->mValue;}
|
||||
bool operator != (const aiFloatKey& o) const
|
||||
{return o.mValue != this->mValue;}
|
||||
|
||||
// Only time is compared. This operator is defined
|
||||
// for use with std::sort
|
||||
bool operator < (const aiFloatKey& o) const
|
||||
{return mTime < o.mTime;}
|
||||
// Only time is compared. This operator is defined
|
||||
// for use with std::sort
|
||||
bool operator < (const aiFloatKey& o) const
|
||||
{return mTime < o.mTime;}
|
||||
|
||||
bool operator > (const aiFloatKey& o) const
|
||||
{return mTime > o.mTime;}
|
||||
bool operator > (const aiFloatKey& o) const
|
||||
{return mTime > o.mTime;}
|
||||
|
||||
#endif
|
||||
};
|
||||
|
@ -483,104 +483,104 @@ struct aiFloatKey
|
|||
/** Helper structure to represent a 3ds file node */
|
||||
struct Node
|
||||
{
|
||||
Node()
|
||||
Node()
|
||||
|
||||
: mHierarchyPos (0)
|
||||
, mHierarchyIndex (0)
|
||||
, mInstanceCount (1)
|
||||
: mHierarchyPos (0)
|
||||
, mHierarchyIndex (0)
|
||||
, mInstanceCount (1)
|
||||
|
||||
{
|
||||
static int iCnt = 0;
|
||||
{
|
||||
static int iCnt = 0;
|
||||
|
||||
// Generate a default name for the node
|
||||
char szTemp[128];
|
||||
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||
mName = szTemp;
|
||||
// Generate a default name for the node
|
||||
char szTemp[128];
|
||||
::sprintf(szTemp,"UNNAMED_%i",iCnt++);
|
||||
mName = szTemp;
|
||||
|
||||
aRotationKeys.reserve (20);
|
||||
aPositionKeys.reserve (20);
|
||||
aScalingKeys.reserve (20);
|
||||
}
|
||||
aRotationKeys.reserve (20);
|
||||
aPositionKeys.reserve (20);
|
||||
aScalingKeys.reserve (20);
|
||||
}
|
||||
|
||||
~Node()
|
||||
{
|
||||
for (unsigned int i = 0; i < mChildren.size();++i)
|
||||
delete mChildren[i];
|
||||
}
|
||||
~Node()
|
||||
{
|
||||
for (unsigned int i = 0; i < mChildren.size();++i)
|
||||
delete mChildren[i];
|
||||
}
|
||||
|
||||
//! Pointer to the parent node
|
||||
Node* mParent;
|
||||
//! Pointer to the parent node
|
||||
Node* mParent;
|
||||
|
||||
//! Holds all child nodes
|
||||
std::vector<Node*> mChildren;
|
||||
//! Holds all child nodes
|
||||
std::vector<Node*> mChildren;
|
||||
|
||||
//! Name of the node
|
||||
std::string mName;
|
||||
//! Name of the node
|
||||
std::string mName;
|
||||
|
||||
//! InstanceNumber of the node
|
||||
int32_t mInstanceNumber;
|
||||
//! InstanceNumber of the node
|
||||
int32_t mInstanceNumber;
|
||||
|
||||
//! Dummy nodes: real name to be combined with the $$$DUMMY
|
||||
std::string mDummyName;
|
||||
//! Dummy nodes: real name to be combined with the $$$DUMMY
|
||||
std::string mDummyName;
|
||||
|
||||
//! Position of the node in the hierarchy (tree depth)
|
||||
int16_t mHierarchyPos;
|
||||
//! Position of the node in the hierarchy (tree depth)
|
||||
int16_t mHierarchyPos;
|
||||
|
||||
//! Index of the node
|
||||
int16_t mHierarchyIndex;
|
||||
//! Index of the node
|
||||
int16_t mHierarchyIndex;
|
||||
|
||||
//! Rotation keys loaded from the file
|
||||
std::vector<aiQuatKey> aRotationKeys;
|
||||
//! Rotation keys loaded from the file
|
||||
std::vector<aiQuatKey> aRotationKeys;
|
||||
|
||||
//! Position keys loaded from the file
|
||||
std::vector<aiVectorKey> aPositionKeys;
|
||||
//! Position keys loaded from the file
|
||||
std::vector<aiVectorKey> aPositionKeys;
|
||||
|
||||
//! Scaling keys loaded from the file
|
||||
std::vector<aiVectorKey> aScalingKeys;
|
||||
//! Scaling keys loaded from the file
|
||||
std::vector<aiVectorKey> aScalingKeys;
|
||||
|
||||
|
||||
// For target lights (spot lights and directional lights):
|
||||
// The position of the target
|
||||
std::vector< aiVectorKey > aTargetPositionKeys;
|
||||
// For target lights (spot lights and directional lights):
|
||||
// The position of the target
|
||||
std::vector< aiVectorKey > aTargetPositionKeys;
|
||||
|
||||
// For cameras: the camera roll angle
|
||||
std::vector< aiFloatKey > aCameraRollKeys;
|
||||
// For cameras: the camera roll angle
|
||||
std::vector< aiFloatKey > aCameraRollKeys;
|
||||
|
||||
//! Pivot position loaded from the file
|
||||
aiVector3D vPivot;
|
||||
//! Pivot position loaded from the file
|
||||
aiVector3D vPivot;
|
||||
|
||||
//instance count, will be kept only for the first node
|
||||
int32_t mInstanceCount;
|
||||
//instance count, will be kept only for the first node
|
||||
int32_t mInstanceCount;
|
||||
|
||||
//! Add a child node, setup the right parent node for it
|
||||
//! \param pc Node to be 'adopted'
|
||||
inline Node& push_back(Node* pc)
|
||||
{
|
||||
mChildren.push_back(pc);
|
||||
pc->mParent = this;
|
||||
return *this;
|
||||
}
|
||||
//! Add a child node, setup the right parent node for it
|
||||
//! \param pc Node to be 'adopted'
|
||||
inline Node& push_back(Node* pc)
|
||||
{
|
||||
mChildren.push_back(pc);
|
||||
pc->mParent = this;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Helper structure analogue to aiScene */
|
||||
struct Scene
|
||||
{
|
||||
//! List of all materials loaded
|
||||
//! NOTE: 3ds references materials globally
|
||||
std::vector<Material> mMaterials;
|
||||
//! List of all materials loaded
|
||||
//! NOTE: 3ds references materials globally
|
||||
std::vector<Material> mMaterials;
|
||||
|
||||
//! List of all meshes loaded
|
||||
std::vector<Mesh> mMeshes;
|
||||
//! List of all meshes loaded
|
||||
std::vector<Mesh> mMeshes;
|
||||
|
||||
//! List of all cameras loaded
|
||||
std::vector<aiCamera*> mCameras;
|
||||
//! List of all cameras loaded
|
||||
std::vector<aiCamera*> mCameras;
|
||||
|
||||
//! List of all lights loaded
|
||||
std::vector<aiLight*> mLights;
|
||||
//! List of all lights loaded
|
||||
std::vector<aiLight*> mLights;
|
||||
|
||||
//! Pointer to the root node of the scene
|
||||
// --- moved to main class
|
||||
// Node* pcRootNode;
|
||||
//! Pointer to the root node of the scene
|
||||
// --- moved to main class
|
||||
// Node* pcRootNode;
|
||||
};
|
||||
|
||||
|
||||
|
|
2012
code/3DSLoader.cpp
2012
code/3DSLoader.cpp
File diff suppressed because it is too large
Load Diff
322
code/3DSLoader.h
322
code/3DSLoader.h
|
@ -55,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
|
||||
using namespace D3DS;
|
||||
|
@ -67,212 +67,212 @@ class Discreet3DSImporter : public BaseImporter
|
|||
{
|
||||
public:
|
||||
|
||||
Discreet3DSImporter();
|
||||
~Discreet3DSImporter();
|
||||
Discreet3DSImporter();
|
||||
~Discreet3DSImporter();
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a temporary material to the outer representation
|
||||
*/
|
||||
void ConvertMaterial(D3DS::Material& p_cMat,
|
||||
aiMaterial& p_pcOut);
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a temporary material to the outer representation
|
||||
*/
|
||||
void ConvertMaterial(D3DS::Material& p_cMat,
|
||||
aiMaterial& p_pcOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Read a chunk
|
||||
*
|
||||
* @param pcOut Receives the current chunk
|
||||
*/
|
||||
void ReadChunk(Discreet3DS::Chunk* pcOut);
|
||||
// -------------------------------------------------------------------
|
||||
/** Read a chunk
|
||||
*
|
||||
* @param pcOut Receives the current chunk
|
||||
*/
|
||||
void ReadChunk(Discreet3DS::Chunk* pcOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a percentage chunk. mCurrent will point to the next
|
||||
* chunk behind afterwards. If no percentage chunk is found
|
||||
* QNAN is returned.
|
||||
*/
|
||||
float ParsePercentageChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a percentage chunk. mCurrent will point to the next
|
||||
* chunk behind afterwards. If no percentage chunk is found
|
||||
* QNAN is returned.
|
||||
*/
|
||||
float ParsePercentageChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a color chunk. mCurrent will point to the next
|
||||
* chunk behind afterwards. If no color chunk is found
|
||||
* QNAN is returned in all members.
|
||||
*/
|
||||
void ParseColorChunk(aiColor3D* p_pcOut,
|
||||
bool p_bAcceptPercent = true);
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a color chunk. mCurrent will point to the next
|
||||
* chunk behind afterwards. If no color chunk is found
|
||||
* QNAN is returned in all members.
|
||||
*/
|
||||
void ParseColorChunk(aiColor3D* p_pcOut,
|
||||
bool p_bAcceptPercent = true);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Skip a chunk in the file
|
||||
*/
|
||||
void SkipChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Skip a chunk in the file
|
||||
*/
|
||||
void SkipChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate the nodegraph
|
||||
*/
|
||||
void GenerateNodeGraph(aiScene* pcOut);
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate the nodegraph
|
||||
*/
|
||||
void GenerateNodeGraph(aiScene* pcOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a main top-level chunk in the file
|
||||
*/
|
||||
void ParseMainChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a main top-level chunk in the file
|
||||
*/
|
||||
void ParseMainChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a top-level chunk in the file
|
||||
*/
|
||||
void ParseChunk(const char* name, unsigned int num);
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a top-level chunk in the file
|
||||
*/
|
||||
void ParseChunk(const char* name, unsigned int num);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a top-level editor chunk in the file
|
||||
*/
|
||||
void ParseEditorChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a top-level editor chunk in the file
|
||||
*/
|
||||
void ParseEditorChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a top-level object chunk in the file
|
||||
*/
|
||||
void ParseObjectChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a top-level object chunk in the file
|
||||
*/
|
||||
void ParseObjectChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a material chunk in the file
|
||||
*/
|
||||
void ParseMaterialChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a material chunk in the file
|
||||
*/
|
||||
void ParseMaterialChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a mesh chunk in the file
|
||||
*/
|
||||
void ParseMeshChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a mesh chunk in the file
|
||||
*/
|
||||
void ParseMeshChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a light chunk in the file
|
||||
*/
|
||||
void ParseLightChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a light chunk in the file
|
||||
*/
|
||||
void ParseLightChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a camera chunk in the file
|
||||
*/
|
||||
void ParseCameraChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a camera chunk in the file
|
||||
*/
|
||||
void ParseCameraChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a face list chunk in the file
|
||||
*/
|
||||
void ParseFaceChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a face list chunk in the file
|
||||
*/
|
||||
void ParseFaceChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a keyframe chunk in the file
|
||||
*/
|
||||
void ParseKeyframeChunk();
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a keyframe chunk in the file
|
||||
*/
|
||||
void ParseKeyframeChunk();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a hierarchy chunk in the file
|
||||
*/
|
||||
void ParseHierarchyChunk(uint16_t parent);
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a hierarchy chunk in the file
|
||||
*/
|
||||
void ParseHierarchyChunk(uint16_t parent);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a texture chunk in the file
|
||||
*/
|
||||
void ParseTextureChunk(D3DS::Texture* pcOut);
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a texture chunk in the file
|
||||
*/
|
||||
void ParseTextureChunk(D3DS::Texture* pcOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert the meshes in the file
|
||||
*/
|
||||
void ConvertMeshes(aiScene* pcOut);
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert the meshes in the file
|
||||
*/
|
||||
void ConvertMeshes(aiScene* pcOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Replace the default material in the scene
|
||||
*/
|
||||
void ReplaceDefaultMaterial();
|
||||
// -------------------------------------------------------------------
|
||||
/** Replace the default material in the scene
|
||||
*/
|
||||
void ReplaceDefaultMaterial();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert the whole scene
|
||||
*/
|
||||
void ConvertScene(aiScene* pcOut);
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert the whole scene
|
||||
*/
|
||||
void ConvertScene(aiScene* pcOut);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** generate unique vertices for a mesh
|
||||
*/
|
||||
void MakeUnique(D3DS::Mesh& sMesh);
|
||||
// -------------------------------------------------------------------
|
||||
/** generate unique vertices for a mesh
|
||||
*/
|
||||
void MakeUnique(D3DS::Mesh& sMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a node to the node graph
|
||||
*/
|
||||
void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn,
|
||||
aiMatrix4x4& absTrafo);
|
||||
// -------------------------------------------------------------------
|
||||
/** Add a node to the node graph
|
||||
*/
|
||||
void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn,
|
||||
aiMatrix4x4& absTrafo);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Search for a node in the graph.
|
||||
* Called recursively
|
||||
*/
|
||||
void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent);
|
||||
// -------------------------------------------------------------------
|
||||
/** Search for a node in the graph.
|
||||
* Called recursively
|
||||
*/
|
||||
void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Apply the master scaling factor to the mesh
|
||||
*/
|
||||
void ApplyMasterScale(aiScene* pScene);
|
||||
// -------------------------------------------------------------------
|
||||
/** Apply the master scaling factor to the mesh
|
||||
*/
|
||||
void ApplyMasterScale(aiScene* pScene);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Clamp all indices in the file to a valid range
|
||||
*/
|
||||
void CheckIndices(D3DS::Mesh& sMesh);
|
||||
// -------------------------------------------------------------------
|
||||
/** Clamp all indices in the file to a valid range
|
||||
*/
|
||||
void CheckIndices(D3DS::Mesh& sMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Skip the TCB info in a track key
|
||||
*/
|
||||
void SkipTCBInfo();
|
||||
// -------------------------------------------------------------------
|
||||
/** Skip the TCB info in a track key
|
||||
*/
|
||||
void SkipTCBInfo();
|
||||
|
||||
protected:
|
||||
|
||||
/** Stream to read from */
|
||||
StreamReaderLE* stream;
|
||||
/** Stream to read from */
|
||||
StreamReaderLE* stream;
|
||||
|
||||
/** Last touched node index */
|
||||
short mLastNodeIndex;
|
||||
/** Last touched node index */
|
||||
short mLastNodeIndex;
|
||||
|
||||
/** Current node, root node */
|
||||
D3DS::Node* mCurrentNode, *mRootNode;
|
||||
/** Current node, root node */
|
||||
D3DS::Node* mCurrentNode, *mRootNode;
|
||||
|
||||
/** Scene under construction */
|
||||
D3DS::Scene* mScene;
|
||||
/** Scene under construction */
|
||||
D3DS::Scene* mScene;
|
||||
|
||||
/** Ambient base color of the scene */
|
||||
aiColor3D mClrAmbient;
|
||||
/** Ambient base color of the scene */
|
||||
aiColor3D mClrAmbient;
|
||||
|
||||
/** Master scaling factor of the scene */
|
||||
float mMasterScale;
|
||||
/** Master scaling factor of the scene */
|
||||
float mMasterScale;
|
||||
|
||||
/** Path to the background image of the scene */
|
||||
std::string mBackgroundImage;
|
||||
bool bHasBG;
|
||||
/** Path to the background image of the scene */
|
||||
std::string mBackgroundImage;
|
||||
bool bHasBG;
|
||||
|
||||
/** true if PRJ file */
|
||||
bool bIsPrj;
|
||||
/** true if PRJ file */
|
||||
bool bIsPrj;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
1302
code/ACLoader.cpp
1302
code/ACLoader.cpp
File diff suppressed because it is too large
Load Diff
308
code/ACLoader.h
308
code/ACLoader.h
|
@ -55,7 +55,7 @@ struct aiMaterial;
|
|||
struct aiLight;
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** AC3D (*.ac) importer class
|
||||
|
@ -63,209 +63,209 @@ namespace Assimp {
|
|||
class AC3DImporter : public BaseImporter
|
||||
{
|
||||
public:
|
||||
AC3DImporter();
|
||||
~AC3DImporter();
|
||||
AC3DImporter();
|
||||
~AC3DImporter();
|
||||
|
||||
|
||||
|
||||
// Represents an AC3D material
|
||||
struct Material
|
||||
{
|
||||
Material()
|
||||
: rgb (0.6f,0.6f,0.6f)
|
||||
, spec (1.f,1.f,1.f)
|
||||
, shin (0.f)
|
||||
, trans (0.f)
|
||||
{}
|
||||
// Represents an AC3D material
|
||||
struct Material
|
||||
{
|
||||
Material()
|
||||
: rgb (0.6f,0.6f,0.6f)
|
||||
, spec (1.f,1.f,1.f)
|
||||
, shin (0.f)
|
||||
, trans (0.f)
|
||||
{}
|
||||
|
||||
// base color of the material
|
||||
aiColor3D rgb;
|
||||
// base color of the material
|
||||
aiColor3D rgb;
|
||||
|
||||
// ambient color of the material
|
||||
aiColor3D amb;
|
||||
// ambient color of the material
|
||||
aiColor3D amb;
|
||||
|
||||
// emissive color of the material
|
||||
aiColor3D emis;
|
||||
// emissive color of the material
|
||||
aiColor3D emis;
|
||||
|
||||
// specular color of the material
|
||||
aiColor3D spec;
|
||||
// specular color of the material
|
||||
aiColor3D spec;
|
||||
|
||||
// shininess exponent
|
||||
float shin;
|
||||
// shininess exponent
|
||||
float shin;
|
||||
|
||||
// transparency. 0 == opaque
|
||||
float trans;
|
||||
// transparency. 0 == opaque
|
||||
float trans;
|
||||
|
||||
// name of the material. optional.
|
||||
std::string name;
|
||||
};
|
||||
// name of the material. optional.
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// Represents an AC3D surface
|
||||
struct Surface
|
||||
{
|
||||
Surface()
|
||||
: mat (0)
|
||||
, flags (0)
|
||||
{}
|
||||
// Represents an AC3D surface
|
||||
struct Surface
|
||||
{
|
||||
Surface()
|
||||
: mat (0)
|
||||
, flags (0)
|
||||
{}
|
||||
|
||||
unsigned int mat,flags;
|
||||
unsigned int mat,flags;
|
||||
|
||||
typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
|
||||
std::vector< SurfaceEntry > entries;
|
||||
};
|
||||
typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
|
||||
std::vector< SurfaceEntry > entries;
|
||||
};
|
||||
|
||||
// Represents an AC3D object
|
||||
struct Object
|
||||
{
|
||||
Object()
|
||||
: type (World)
|
||||
, name( "" )
|
||||
, children()
|
||||
, texture( "" )
|
||||
, texRepeat( 1.f, 1.f )
|
||||
, texOffset( 0.0f, 0.0f )
|
||||
, rotation()
|
||||
, translation()
|
||||
, vertices()
|
||||
, surfaces()
|
||||
, numRefs (0)
|
||||
, subDiv (0)
|
||||
{}
|
||||
// Represents an AC3D object
|
||||
struct Object
|
||||
{
|
||||
Object()
|
||||
: type (World)
|
||||
, name( "" )
|
||||
, children()
|
||||
, texture( "" )
|
||||
, texRepeat( 1.f, 1.f )
|
||||
, texOffset( 0.0f, 0.0f )
|
||||
, rotation()
|
||||
, translation()
|
||||
, vertices()
|
||||
, surfaces()
|
||||
, numRefs (0)
|
||||
, subDiv (0)
|
||||
{}
|
||||
|
||||
// Type description
|
||||
enum Type
|
||||
{
|
||||
World = 0x0,
|
||||
Poly = 0x1,
|
||||
Group = 0x2,
|
||||
Light = 0x4
|
||||
} type;
|
||||
// Type description
|
||||
enum Type
|
||||
{
|
||||
World = 0x0,
|
||||
Poly = 0x1,
|
||||
Group = 0x2,
|
||||
Light = 0x4
|
||||
} type;
|
||||
|
||||
// name of the object
|
||||
std::string name;
|
||||
// name of the object
|
||||
std::string name;
|
||||
|
||||
// object children
|
||||
std::vector<Object> children;
|
||||
// object children
|
||||
std::vector<Object> children;
|
||||
|
||||
// texture to be assigned to all surfaces of the object
|
||||
std::string texture;
|
||||
// texture to be assigned to all surfaces of the object
|
||||
std::string texture;
|
||||
|
||||
// texture repat factors (scaling for all coordinates)
|
||||
aiVector2D texRepeat, texOffset;
|
||||
// texture repat factors (scaling for all coordinates)
|
||||
aiVector2D texRepeat, texOffset;
|
||||
|
||||
// rotation matrix
|
||||
aiMatrix3x3 rotation;
|
||||
// rotation matrix
|
||||
aiMatrix3x3 rotation;
|
||||
|
||||
// translation vector
|
||||
aiVector3D translation;
|
||||
// translation vector
|
||||
aiVector3D translation;
|
||||
|
||||
// vertices
|
||||
std::vector<aiVector3D> vertices;
|
||||
// vertices
|
||||
std::vector<aiVector3D> vertices;
|
||||
|
||||
// surfaces
|
||||
std::vector<Surface> surfaces;
|
||||
// surfaces
|
||||
std::vector<Surface> surfaces;
|
||||
|
||||
// number of indices (= num verts in verbose format)
|
||||
unsigned int numRefs;
|
||||
// number of indices (= num verts in verbose format)
|
||||
unsigned int numRefs;
|
||||
|
||||
// number of subdivisions to be performed on the
|
||||
// imported data
|
||||
unsigned int subDiv;
|
||||
// number of subdivisions to be performed on the
|
||||
// imported data
|
||||
unsigned int subDiv;
|
||||
|
||||
// max angle limit for smoothing
|
||||
float crease;
|
||||
};
|
||||
// max angle limit for smoothing
|
||||
float crease;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details */
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details */
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the next line from the file.
|
||||
* @return false if the end of the file was reached*/
|
||||
bool GetNextLine();
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the next line from the file.
|
||||
* @return false if the end of the file was reached*/
|
||||
bool GetNextLine();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load the object section. This method is called recursively to
|
||||
* load subobjects, the method returns after a 'kids 0' was
|
||||
* encountered.
|
||||
* @objects List of output objects*/
|
||||
void LoadObjectSection(std::vector<Object>& objects);
|
||||
// -------------------------------------------------------------------
|
||||
/** Load the object section. This method is called recursively to
|
||||
* load subobjects, the method returns after a 'kids 0' was
|
||||
* encountered.
|
||||
* @objects List of output objects*/
|
||||
void LoadObjectSection(std::vector<Object>& objects);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert all objects into meshes and nodes.
|
||||
* @param object Current object to work on
|
||||
* @param meshes Pointer to the list of output meshes
|
||||
* @param outMaterials List of output materials
|
||||
* @param materials Material list
|
||||
* @param Scenegraph node for the object */
|
||||
aiNode* ConvertObjectSection(Object& object,
|
||||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<aiMaterial*>& outMaterials,
|
||||
const std::vector<Material>& materials,
|
||||
aiNode* parent = NULL);
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert all objects into meshes and nodes.
|
||||
* @param object Current object to work on
|
||||
* @param meshes Pointer to the list of output meshes
|
||||
* @param outMaterials List of output materials
|
||||
* @param materials Material list
|
||||
* @param Scenegraph node for the object */
|
||||
aiNode* ConvertObjectSection(Object& object,
|
||||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<aiMaterial*>& outMaterials,
|
||||
const std::vector<Material>& materials,
|
||||
aiNode* parent = NULL);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material
|
||||
* @param object Current object
|
||||
* @param matSrc Source material description
|
||||
* @param matDest Destination material to be filled */
|
||||
void ConvertMaterial(const Object& object,
|
||||
const Material& matSrc,
|
||||
aiMaterial& matDest);
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material
|
||||
* @param object Current object
|
||||
* @param matSrc Source material description
|
||||
* @param matDest Destination material to be filled */
|
||||
void ConvertMaterial(const Object& object,
|
||||
const Material& matSrc,
|
||||
aiMaterial& matDest);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
// points to the next data line
|
||||
const char* buffer;
|
||||
// points to the next data line
|
||||
const char* buffer;
|
||||
|
||||
// Configuration option: if enabled, up to two meshes
|
||||
// are generated per material: those faces who have
|
||||
// their bf cull flags set are separated.
|
||||
bool configSplitBFCull;
|
||||
// Configuration option: if enabled, up to two meshes
|
||||
// are generated per material: those faces who have
|
||||
// their bf cull flags set are separated.
|
||||
bool configSplitBFCull;
|
||||
|
||||
// Configuration switch: subdivision surfaces are only
|
||||
// evaluated if the value is true.
|
||||
bool configEvalSubdivision;
|
||||
// Configuration switch: subdivision surfaces are only
|
||||
// evaluated if the value is true.
|
||||
bool configEvalSubdivision;
|
||||
|
||||
// counts how many objects we have in the tree.
|
||||
// basing on this information we can find a
|
||||
// good estimate how many meshes we'll have in the final scene.
|
||||
unsigned int mNumMeshes;
|
||||
// counts how many objects we have in the tree.
|
||||
// basing on this information we can find a
|
||||
// good estimate how many meshes we'll have in the final scene.
|
||||
unsigned int mNumMeshes;
|
||||
|
||||
// current list of light sources
|
||||
std::vector<aiLight*>* mLights;
|
||||
// current list of light sources
|
||||
std::vector<aiLight*>* mLights;
|
||||
|
||||
// name counters
|
||||
unsigned int lights, groups, polys, worlds;
|
||||
// name counters
|
||||
unsigned int lights, groups, polys, worlds;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
1942
code/ASELoader.cpp
1942
code/ASELoader.cpp
File diff suppressed because it is too large
Load Diff
196
code/ASELoader.h
196
code/ASELoader.h
|
@ -57,147 +57,147 @@ namespace Assimp {
|
|||
/** Importer class for the 3DS ASE ASCII format.
|
||||
*
|
||||
*/
|
||||
class ASEImporter : public BaseImporter {
|
||||
class ASEImporter : public BaseImporter {
|
||||
public:
|
||||
ASEImporter();
|
||||
~ASEImporter();
|
||||
ASEImporter();
|
||||
~ASEImporter();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details.
|
||||
*/
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate normal vectors basing on smoothing groups
|
||||
* (in some cases the normal are already contained in the file)
|
||||
* \param mesh Mesh to work on
|
||||
* \return false if the normals have been recomputed
|
||||
*/
|
||||
bool GenerateNormals(ASE::Mesh& mesh);
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate normal vectors basing on smoothing groups
|
||||
* (in some cases the normal are already contained in the file)
|
||||
* \param mesh Mesh to work on
|
||||
* \return false if the normals have been recomputed
|
||||
*/
|
||||
bool GenerateNormals(ASE::Mesh& mesh);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Create valid vertex/normal/UV/color/face lists.
|
||||
* All elements are unique, faces have only one set of indices
|
||||
* after this step occurs.
|
||||
* \param mesh Mesh to work on
|
||||
*/
|
||||
void BuildUniqueRepresentation(ASE::Mesh& mesh);
|
||||
// -------------------------------------------------------------------
|
||||
/** Create valid vertex/normal/UV/color/face lists.
|
||||
* All elements are unique, faces have only one set of indices
|
||||
* after this step occurs.
|
||||
* \param mesh Mesh to work on
|
||||
*/
|
||||
void BuildUniqueRepresentation(ASE::Mesh& mesh);
|
||||
|
||||
|
||||
/** Create one-material-per-mesh meshes ;-)
|
||||
* \param mesh Mesh to work with
|
||||
* \param Receives the list of all created meshes
|
||||
*/
|
||||
void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut);
|
||||
/** Create one-material-per-mesh meshes ;-)
|
||||
* \param mesh Mesh to work with
|
||||
* \param Receives the list of all created meshes
|
||||
*/
|
||||
void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material to a aiMaterial object
|
||||
* \param mat Input material
|
||||
*/
|
||||
void ConvertMaterial(ASE::Material& mat);
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material to a aiMaterial object
|
||||
* \param mat Input material
|
||||
*/
|
||||
void ConvertMaterial(ASE::Material& mat);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Setup the final material indices for each mesh
|
||||
*/
|
||||
void BuildMaterialIndices();
|
||||
// -------------------------------------------------------------------
|
||||
/** Setup the final material indices for each mesh
|
||||
*/
|
||||
void BuildMaterialIndices();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Build the node graph
|
||||
*/
|
||||
void BuildNodes(std::vector<ASE::BaseNode*>& nodes);
|
||||
// -------------------------------------------------------------------
|
||||
/** Build the node graph
|
||||
*/
|
||||
void BuildNodes(std::vector<ASE::BaseNode*>& nodes);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Build output cameras
|
||||
*/
|
||||
void BuildCameras();
|
||||
// -------------------------------------------------------------------
|
||||
/** Build output cameras
|
||||
*/
|
||||
void BuildCameras();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Build output lights
|
||||
*/
|
||||
void BuildLights();
|
||||
// -------------------------------------------------------------------
|
||||
/** Build output lights
|
||||
*/
|
||||
void BuildLights();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Build output animations
|
||||
*/
|
||||
void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes);
|
||||
// -------------------------------------------------------------------
|
||||
/** Build output animations
|
||||
*/
|
||||
void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Add sub nodes to a node
|
||||
* \param pcParent parent node to be filled
|
||||
* \param szName Name of the parent node
|
||||
* \param matrix Current transform
|
||||
*/
|
||||
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
|
||||
aiNode* pcParent,const char* szName);
|
||||
// -------------------------------------------------------------------
|
||||
/** Add sub nodes to a node
|
||||
* \param pcParent parent node to be filled
|
||||
* \param szName Name of the parent node
|
||||
* \param matrix Current transform
|
||||
*/
|
||||
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
|
||||
aiNode* pcParent,const char* szName);
|
||||
|
||||
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
|
||||
aiNode* pcParent,const char* szName,
|
||||
const aiMatrix4x4& matrix);
|
||||
void AddNodes(const std::vector<ASE::BaseNode*>& nodes,
|
||||
aiNode* pcParent,const char* szName,
|
||||
const aiMatrix4x4& matrix);
|
||||
|
||||
void AddMeshes(const ASE::BaseNode* snode,aiNode* node);
|
||||
void AddMeshes(const ASE::BaseNode* snode,aiNode* node);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate a default material and add it to the parser's list
|
||||
* Called if no material has been found in the file (rare for ASE,
|
||||
* but not impossible)
|
||||
*/
|
||||
void GenerateDefaultMaterial();
|
||||
// -------------------------------------------------------------------
|
||||
/** Generate a default material and add it to the parser's list
|
||||
* Called if no material has been found in the file (rare for ASE,
|
||||
* but not impossible)
|
||||
*/
|
||||
void GenerateDefaultMaterial();
|
||||
|
||||
protected:
|
||||
|
||||
/** Parser instance */
|
||||
ASE::Parser* mParser;
|
||||
/** Parser instance */
|
||||
ASE::Parser* mParser;
|
||||
|
||||
/** Buffer to hold the loaded file */
|
||||
char* mBuffer;
|
||||
/** Buffer to hold the loaded file */
|
||||
char* mBuffer;
|
||||
|
||||
/** Scene to be filled */
|
||||
aiScene* pcScene;
|
||||
/** Scene to be filled */
|
||||
aiScene* pcScene;
|
||||
|
||||
/** Config options: Recompute the normals in every case - WA
|
||||
for 3DS Max broken ASE normal export */
|
||||
bool configRecomputeNormals;
|
||||
bool noSkeletonMesh;
|
||||
/** Config options: Recompute the normals in every case - WA
|
||||
for 3DS Max broken ASE normal export */
|
||||
bool configRecomputeNormals;
|
||||
bool noSkeletonMesh;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
3522
code/ASEParser.cpp
3522
code/ASEParser.cpp
File diff suppressed because it is too large
Load Diff
826
code/ASEParser.h
826
code/ASEParser.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -61,7 +61,7 @@ struct aiCamera;
|
|||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
/** Importer class for 3D Studio r3 and r4 3DS files
|
||||
|
|
586
code/Assimp.cpp
586
code/Assimp.cpp
|
@ -59,39 +59,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
# include <boost/thread/thread.hpp>
|
||||
# include <boost/thread/mutex.hpp>
|
||||
# include <boost/thread/thread.hpp>
|
||||
# include <boost/thread/mutex.hpp>
|
||||
#endif
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
using namespace Assimp;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
// underlying structure for aiPropertyStore
|
||||
typedef BatchLoader::PropertyMap PropertyMap;
|
||||
// underlying structure for aiPropertyStore
|
||||
typedef BatchLoader::PropertyMap PropertyMap;
|
||||
|
||||
/** Stores the LogStream objects for all active C log streams */
|
||||
struct mpred {
|
||||
bool operator () (const aiLogStream& s0, const aiLogStream& s1) const {
|
||||
return s0.callback<s1.callback&&s0.user<s1.user;
|
||||
}
|
||||
};
|
||||
typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
|
||||
/** Stores the LogStream objects for all active C log streams */
|
||||
struct mpred {
|
||||
bool operator () (const aiLogStream& s0, const aiLogStream& s1) const {
|
||||
return s0.callback<s1.callback&&s0.user<s1.user;
|
||||
}
|
||||
};
|
||||
typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
|
||||
|
||||
/** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
|
||||
typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
|
||||
/** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
|
||||
typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
|
||||
|
||||
/** Local storage of all active log streams */
|
||||
static LogStreamMap gActiveLogStreams;
|
||||
/** Local storage of all active log streams */
|
||||
static LogStreamMap gActiveLogStreams;
|
||||
|
||||
/** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
|
||||
static PredefLogStreamMap gPredefinedStreams;
|
||||
/** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
|
||||
static PredefLogStreamMap gPredefinedStreams;
|
||||
|
||||
/** Error message of the last failed import process */
|
||||
static std::string gLastErrorString;
|
||||
/** Error message of the last failed import process */
|
||||
static std::string gLastErrorString;
|
||||
|
||||
/** Verbose logging active or not? */
|
||||
static aiBool gVerboseLogging = false;
|
||||
/** Verbose logging active or not? */
|
||||
static aiBool gVerboseLogging = false;
|
||||
|
||||
/** will return all registered importers. */
|
||||
void GetImporterInstanceList(std::vector< BaseImporter* >& out);
|
||||
|
@ -110,331 +110,331 @@ static boost::mutex gLogStreamMutex;
|
|||
class LogToCallbackRedirector : public LogStream
|
||||
{
|
||||
public:
|
||||
LogToCallbackRedirector(const aiLogStream& s)
|
||||
: stream (s) {
|
||||
ai_assert(NULL != s.callback);
|
||||
}
|
||||
LogToCallbackRedirector(const aiLogStream& s)
|
||||
: stream (s) {
|
||||
ai_assert(NULL != s.callback);
|
||||
}
|
||||
|
||||
~LogToCallbackRedirector() {
|
||||
~LogToCallbackRedirector() {
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
#endif
|
||||
// (HACK) Check whether the 'stream.user' pointer points to a
|
||||
// custom LogStream allocated by #aiGetPredefinedLogStream.
|
||||
// In this case, we need to delete it, too. Of course, this
|
||||
// might cause strange problems, but the chance is quite low.
|
||||
// (HACK) Check whether the 'stream.user' pointer points to a
|
||||
// custom LogStream allocated by #aiGetPredefinedLogStream.
|
||||
// In this case, we need to delete it, too. Of course, this
|
||||
// might cause strange problems, but the chance is quite low.
|
||||
|
||||
PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
|
||||
gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
|
||||
PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
|
||||
gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
|
||||
|
||||
if (it != gPredefinedStreams.end()) {
|
||||
delete *it;
|
||||
gPredefinedStreams.erase(it);
|
||||
}
|
||||
}
|
||||
if (it != gPredefinedStreams.end()) {
|
||||
delete *it;
|
||||
gPredefinedStreams.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/** @copydoc LogStream::write */
|
||||
void write(const char* message) {
|
||||
stream.callback(message,stream.user);
|
||||
}
|
||||
/** @copydoc LogStream::write */
|
||||
void write(const char* message) {
|
||||
stream.callback(message,stream.user);
|
||||
}
|
||||
|
||||
private:
|
||||
aiLogStream stream;
|
||||
aiLogStream stream;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ReportSceneNotFoundError()
|
||||
{
|
||||
DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
|
||||
"The C-API does not accept scenes produced by the C++ API and vice versa");
|
||||
DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
|
||||
"The C-API does not accept scenes produced by the C++ API and vice versa");
|
||||
|
||||
assert(false);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the given file and returns its content.
|
||||
const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
|
||||
{
|
||||
return aiImportFileEx(pFile,pFlags,NULL);
|
||||
return aiImportFileEx(pFile,pFlags,NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS)
|
||||
{
|
||||
return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
|
||||
return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
|
||||
aiFileIO* pFS,
|
||||
const aiPropertyStore* props)
|
||||
aiFileIO* pFS,
|
||||
const aiPropertyStore* props)
|
||||
{
|
||||
ai_assert(NULL != pFile);
|
||||
ai_assert(NULL != pFile);
|
||||
|
||||
const aiScene* scene = NULL;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
const aiScene* scene = NULL;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// create an Importer for this file
|
||||
Assimp::Importer* imp = new Assimp::Importer();
|
||||
// create an Importer for this file
|
||||
Assimp::Importer* imp = new Assimp::Importer();
|
||||
|
||||
// copy properties
|
||||
if(props) {
|
||||
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
|
||||
ImporterPimpl* pimpl = imp->Pimpl();
|
||||
pimpl->mIntProperties = pp->ints;
|
||||
pimpl->mFloatProperties = pp->floats;
|
||||
pimpl->mStringProperties = pp->strings;
|
||||
pimpl->mMatrixProperties = pp->matrices;
|
||||
}
|
||||
// setup a custom IO system if necessary
|
||||
if (pFS) {
|
||||
imp->SetIOHandler( new CIOSystemWrapper (pFS) );
|
||||
}
|
||||
// copy properties
|
||||
if(props) {
|
||||
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
|
||||
ImporterPimpl* pimpl = imp->Pimpl();
|
||||
pimpl->mIntProperties = pp->ints;
|
||||
pimpl->mFloatProperties = pp->floats;
|
||||
pimpl->mStringProperties = pp->strings;
|
||||
pimpl->mMatrixProperties = pp->matrices;
|
||||
}
|
||||
// setup a custom IO system if necessary
|
||||
if (pFS) {
|
||||
imp->SetIOHandler( new CIOSystemWrapper (pFS) );
|
||||
}
|
||||
|
||||
// and have it read the file
|
||||
scene = imp->ReadFile( pFile, pFlags);
|
||||
// and have it read the file
|
||||
scene = imp->ReadFile( pFile, pFlags);
|
||||
|
||||
// if succeeded, store the importer in the scene and keep it alive
|
||||
if( scene) {
|
||||
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
|
||||
priv->mOrigImporter = imp;
|
||||
}
|
||||
else {
|
||||
// if failed, extract error code and destroy the import
|
||||
gLastErrorString = imp->GetErrorString();
|
||||
delete imp;
|
||||
}
|
||||
// if succeeded, store the importer in the scene and keep it alive
|
||||
if( scene) {
|
||||
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
|
||||
priv->mOrigImporter = imp;
|
||||
}
|
||||
else {
|
||||
// if failed, extract error code and destroy the import
|
||||
gLastErrorString = imp->GetErrorString();
|
||||
delete imp;
|
||||
}
|
||||
|
||||
// return imported data. If the import failed the pointer is NULL anyways
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return scene;
|
||||
// return imported data. If the import failed the pointer is NULL anyways
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return scene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileFromMemory(
|
||||
const char* pBuffer,
|
||||
unsigned int pLength,
|
||||
unsigned int pFlags,
|
||||
const char* pHint)
|
||||
const char* pBuffer,
|
||||
unsigned int pLength,
|
||||
unsigned int pFlags,
|
||||
const char* pHint)
|
||||
{
|
||||
return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
|
||||
return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* aiImportFileFromMemoryWithProperties(
|
||||
const char* pBuffer,
|
||||
unsigned int pLength,
|
||||
unsigned int pFlags,
|
||||
const char* pHint,
|
||||
const aiPropertyStore* props)
|
||||
const char* pBuffer,
|
||||
unsigned int pLength,
|
||||
unsigned int pFlags,
|
||||
const char* pHint,
|
||||
const aiPropertyStore* props)
|
||||
{
|
||||
ai_assert(NULL != pBuffer && 0 != pLength);
|
||||
ai_assert(NULL != pBuffer && 0 != pLength);
|
||||
|
||||
const aiScene* scene = NULL;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
const aiScene* scene = NULL;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// create an Importer for this file
|
||||
Assimp::Importer* imp = new Assimp::Importer();
|
||||
// create an Importer for this file
|
||||
Assimp::Importer* imp = new Assimp::Importer();
|
||||
|
||||
// copy properties
|
||||
if(props) {
|
||||
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
|
||||
ImporterPimpl* pimpl = imp->Pimpl();
|
||||
pimpl->mIntProperties = pp->ints;
|
||||
pimpl->mFloatProperties = pp->floats;
|
||||
pimpl->mStringProperties = pp->strings;
|
||||
pimpl->mMatrixProperties = pp->matrices;
|
||||
}
|
||||
// copy properties
|
||||
if(props) {
|
||||
const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
|
||||
ImporterPimpl* pimpl = imp->Pimpl();
|
||||
pimpl->mIntProperties = pp->ints;
|
||||
pimpl->mFloatProperties = pp->floats;
|
||||
pimpl->mStringProperties = pp->strings;
|
||||
pimpl->mMatrixProperties = pp->matrices;
|
||||
}
|
||||
|
||||
// and have it read the file from the memory buffer
|
||||
scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
|
||||
// and have it read the file from the memory buffer
|
||||
scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
|
||||
|
||||
// if succeeded, store the importer in the scene and keep it alive
|
||||
if( scene) {
|
||||
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
|
||||
priv->mOrigImporter = imp;
|
||||
}
|
||||
else {
|
||||
// if failed, extract error code and destroy the import
|
||||
gLastErrorString = imp->GetErrorString();
|
||||
delete imp;
|
||||
}
|
||||
// return imported data. If the import failed the pointer is NULL anyways
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return scene;
|
||||
// if succeeded, store the importer in the scene and keep it alive
|
||||
if( scene) {
|
||||
ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
|
||||
priv->mOrigImporter = imp;
|
||||
}
|
||||
else {
|
||||
// if failed, extract error code and destroy the import
|
||||
gLastErrorString = imp->GetErrorString();
|
||||
delete imp;
|
||||
}
|
||||
// return imported data. If the import failed the pointer is NULL anyways
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return scene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Releases all resources associated with the given import process.
|
||||
void aiReleaseImport( const aiScene* pScene)
|
||||
{
|
||||
if (!pScene) {
|
||||
return;
|
||||
}
|
||||
if (!pScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pScene);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
delete pScene;
|
||||
}
|
||||
else {
|
||||
// deleting the Importer also deletes the scene
|
||||
// Note: the reason that this is not written as 'delete priv->mOrigImporter'
|
||||
// is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
|
||||
Importer* importer = priv->mOrigImporter;
|
||||
delete importer;
|
||||
}
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pScene);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
delete pScene;
|
||||
}
|
||||
else {
|
||||
// deleting the Importer also deletes the scene
|
||||
// Note: the reason that this is not written as 'delete priv->mOrigImporter'
|
||||
// is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
|
||||
Importer* importer = priv->mOrigImporter;
|
||||
delete importer;
|
||||
}
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
|
||||
unsigned int pFlags)
|
||||
unsigned int pFlags)
|
||||
{
|
||||
const aiScene* sc = NULL;
|
||||
const aiScene* sc = NULL;
|
||||
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pScene);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
ReportSceneNotFoundError();
|
||||
return NULL;
|
||||
}
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pScene);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
ReportSceneNotFoundError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
|
||||
sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
|
||||
|
||||
if (!sc) {
|
||||
aiReleaseImport(pScene);
|
||||
return NULL;
|
||||
}
|
||||
if (!sc) {
|
||||
aiReleaseImport(pScene);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return sc;
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
return sc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CallbackToLogRedirector (const char* msg, char* dt)
|
||||
{
|
||||
ai_assert(NULL != msg && NULL != dt);
|
||||
LogStream* s = (LogStream*)dt;
|
||||
ai_assert(NULL != msg && NULL != dt);
|
||||
LogStream* s = (LogStream*)dt;
|
||||
|
||||
s->write(msg);
|
||||
s->write(msg);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
|
||||
{
|
||||
aiLogStream sout;
|
||||
aiLogStream sout;
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
LogStream* stream = LogStream::createDefaultStream(pStream,file);
|
||||
if (!stream) {
|
||||
sout.callback = NULL;
|
||||
sout.user = NULL;
|
||||
}
|
||||
else {
|
||||
sout.callback = &CallbackToLogRedirector;
|
||||
sout.user = (char*)stream;
|
||||
}
|
||||
gPredefinedStreams.push_back(stream);
|
||||
ASSIMP_END_EXCEPTION_REGION(aiLogStream);
|
||||
return sout;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
LogStream* stream = LogStream::createDefaultStream(pStream,file);
|
||||
if (!stream) {
|
||||
sout.callback = NULL;
|
||||
sout.user = NULL;
|
||||
}
|
||||
else {
|
||||
sout.callback = &CallbackToLogRedirector;
|
||||
sout.user = (char*)stream;
|
||||
}
|
||||
gPredefinedStreams.push_back(stream);
|
||||
ASSIMP_END_EXCEPTION_REGION(aiLogStream);
|
||||
return sout;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
#endif
|
||||
|
||||
LogStream* lg = new LogToCallbackRedirector(*stream);
|
||||
gActiveLogStreams[*stream] = lg;
|
||||
LogStream* lg = new LogToCallbackRedirector(*stream);
|
||||
gActiveLogStreams[*stream] = lg;
|
||||
|
||||
if (DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
|
||||
}
|
||||
DefaultLogger::get()->attachStream(lg);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
if (DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
|
||||
}
|
||||
DefaultLogger::get()->attachStream(lg);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
#endif
|
||||
// find the logstream associated with this data
|
||||
LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
|
||||
// it should be there... else the user is playing fools with us
|
||||
if( it == gActiveLogStreams.end()) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
DefaultLogger::get()->detatchStream( it->second );
|
||||
delete it->second;
|
||||
// find the logstream associated with this data
|
||||
LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
|
||||
// it should be there... else the user is playing fools with us
|
||||
if( it == gActiveLogStreams.end()) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
DefaultLogger::get()->detatchStream( it->second );
|
||||
delete it->second;
|
||||
|
||||
gActiveLogStreams.erase( it);
|
||||
gActiveLogStreams.erase( it);
|
||||
|
||||
if (gActiveLogStreams.empty()) {
|
||||
DefaultLogger::kill();
|
||||
}
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
return AI_SUCCESS;
|
||||
if (gActiveLogStreams.empty()) {
|
||||
DefaultLogger::kill();
|
||||
}
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiDetachAllLogStreams(void)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
boost::mutex::scoped_lock lock(gLogStreamMutex);
|
||||
#endif
|
||||
for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
|
||||
DefaultLogger::get()->detatchStream( it->second );
|
||||
delete it->second;
|
||||
}
|
||||
gActiveLogStreams.clear();
|
||||
DefaultLogger::kill();
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
|
||||
DefaultLogger::get()->detatchStream( it->second );
|
||||
delete it->second;
|
||||
}
|
||||
gActiveLogStreams.clear();
|
||||
DefaultLogger::kill();
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiEnableVerboseLogging(aiBool d)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
|
||||
}
|
||||
gVerboseLogging = d;
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
|
||||
}
|
||||
gVerboseLogging = d;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns the error text of the last failed import process.
|
||||
const char* aiGetErrorString()
|
||||
{
|
||||
return gLastErrorString.c_str();
|
||||
return gLastErrorString.c_str();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Return the description of a importer given its index
|
||||
const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex)
|
||||
{
|
||||
return Importer().GetImporterInfo(pIndex);
|
||||
return Importer().GetImporterInfo(pIndex);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Return the number of importers
|
||||
size_t aiGetImportFormatCount(void)
|
||||
{
|
||||
return Importer().GetImporterCount();
|
||||
return Importer().GetImporterCount();
|
||||
}
|
||||
|
||||
|
||||
|
@ -442,195 +442,195 @@ size_t aiGetImportFormatCount(void)
|
|||
// Returns the error text of the last failed import process.
|
||||
aiBool aiIsExtensionSupported(const char* szExtension)
|
||||
{
|
||||
ai_assert(NULL != szExtension);
|
||||
aiBool candoit=AI_FALSE;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ai_assert(NULL != szExtension);
|
||||
aiBool candoit=AI_FALSE;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// FIXME: no need to create a temporary Importer instance just for that ..
|
||||
Assimp::Importer tmp;
|
||||
candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
|
||||
// FIXME: no need to create a temporary Importer instance just for that ..
|
||||
Assimp::Importer tmp;
|
||||
candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(aiBool);
|
||||
return candoit;
|
||||
ASSIMP_END_EXCEPTION_REGION(aiBool);
|
||||
return candoit;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a list of all file extensions supported by ASSIMP
|
||||
void aiGetExtensionList(aiString* szOut)
|
||||
{
|
||||
ai_assert(NULL != szOut);
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ai_assert(NULL != szOut);
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// FIXME: no need to create a temporary Importer instance just for that ..
|
||||
Assimp::Importer tmp;
|
||||
tmp.GetExtensionList(*szOut);
|
||||
// FIXME: no need to create a temporary Importer instance just for that ..
|
||||
Assimp::Importer tmp;
|
||||
tmp.GetExtensionList(*szOut);
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the memory requirements for a particular import.
|
||||
void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
|
||||
C_STRUCT aiMemoryInfo* in)
|
||||
C_STRUCT aiMemoryInfo* in)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pIn);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
ReportSceneNotFoundError();
|
||||
return;
|
||||
}
|
||||
// find the importer associated with this data
|
||||
const ScenePrivateData* priv = ScenePriv(pIn);
|
||||
if( !priv || !priv->mOrigImporter) {
|
||||
ReportSceneNotFoundError();
|
||||
return;
|
||||
}
|
||||
|
||||
return priv->mOrigImporter->GetMemoryRequirements(*in);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
return priv->mOrigImporter->GetMemoryRequirements(*in);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
|
||||
{
|
||||
return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
|
||||
return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
|
||||
{
|
||||
delete reinterpret_cast<PropertyMap*>(p);
|
||||
delete reinterpret_cast<PropertyMap*>(p);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyInteger
|
||||
ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<int>(pp->ints,szName,value);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<int>(pp->ints,szName,value);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyFloat
|
||||
ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<float>(pp->floats,szName,value);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<float>(pp->floats,szName,value);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyString
|
||||
ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
|
||||
const C_STRUCT aiString* st)
|
||||
const C_STRUCT aiString* st)
|
||||
{
|
||||
if (!st) {
|
||||
return;
|
||||
}
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
if (!st) {
|
||||
return;
|
||||
}
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Importer::SetPropertyMatrix
|
||||
ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
|
||||
const C_STRUCT aiMatrix4x4* mat)
|
||||
const C_STRUCT aiMatrix4x4* mat)
|
||||
{
|
||||
if (!mat) {
|
||||
return;
|
||||
}
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
if (!mat) {
|
||||
return;
|
||||
}
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
|
||||
SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Rotation matrix to quaternion
|
||||
ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert(NULL != quat && NULL != mat);
|
||||
*quat = aiQuaternion(*mat);
|
||||
ai_assert(NULL != quat && NULL != mat);
|
||||
*quat = aiQuaternion(*mat);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix decomposition
|
||||
ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
|
||||
aiQuaternion* rotation,
|
||||
aiVector3D* position)
|
||||
aiQuaternion* rotation,
|
||||
aiVector3D* position)
|
||||
{
|
||||
ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat);
|
||||
mat->Decompose(*scaling,*rotation,*position);
|
||||
ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat);
|
||||
mat->Decompose(*scaling,*rotation,*position);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix transpose
|
||||
ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
mat->Transpose();
|
||||
ai_assert(NULL != mat);
|
||||
mat->Transpose();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
mat->Transpose();
|
||||
ai_assert(NULL != mat);
|
||||
mat->Transpose();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Vector transformation
|
||||
ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
|
||||
const aiMatrix3x3* mat)
|
||||
const aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert(NULL != mat && NULL != vec);
|
||||
*vec *= (*mat);
|
||||
ai_assert(NULL != mat && NULL != vec);
|
||||
*vec *= (*mat);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
|
||||
const aiMatrix4x4* mat)
|
||||
const aiMatrix4x4* mat)
|
||||
{
|
||||
ai_assert(NULL != mat && NULL != vec);
|
||||
*vec *= (*mat);
|
||||
ai_assert(NULL != mat && NULL != vec);
|
||||
*vec *= (*mat);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix multiplication
|
||||
ASSIMP_API void aiMultiplyMatrix4(
|
||||
aiMatrix4x4* dst,
|
||||
const aiMatrix4x4* src)
|
||||
aiMatrix4x4* dst,
|
||||
const aiMatrix4x4* src)
|
||||
{
|
||||
ai_assert(NULL != dst && NULL != src);
|
||||
*dst = (*dst) * (*src);
|
||||
ai_assert(NULL != dst && NULL != src);
|
||||
*dst = (*dst) * (*src);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiMultiplyMatrix3(
|
||||
aiMatrix3x3* dst,
|
||||
const aiMatrix3x3* src)
|
||||
aiMatrix3x3* dst,
|
||||
const aiMatrix3x3* src)
|
||||
{
|
||||
ai_assert(NULL != dst && NULL != src);
|
||||
*dst = (*dst) * (*src);
|
||||
ai_assert(NULL != dst && NULL != src);
|
||||
*dst = (*dst) * (*src);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Matrix identity
|
||||
ASSIMP_API void aiIdentityMatrix3(
|
||||
aiMatrix3x3* mat)
|
||||
aiMatrix3x3* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
*mat = aiMatrix3x3();
|
||||
ai_assert(NULL != mat);
|
||||
*mat = aiMatrix3x3();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiIdentityMatrix4(
|
||||
aiMatrix4x4* mat)
|
||||
aiMatrix4x4* mat)
|
||||
{
|
||||
ai_assert(NULL != mat);
|
||||
*mat = aiMatrix4x4();
|
||||
ai_assert(NULL != mat);
|
||||
*mat = aiMatrix4x4();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -54,76 +54,76 @@ using namespace Assimp;
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API size_t aiGetExportFormatCount(void)
|
||||
{
|
||||
return Exporter().GetExportFormatCount();
|
||||
return Exporter().GetExportFormatCount();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
|
||||
{
|
||||
// Note: this is valid as the index always pertains to a builtin exporter,
|
||||
// for which the returned structure is guaranteed to be of static storage duration.
|
||||
return Exporter().GetExportFormatDescription(pIndex);
|
||||
// Note: this is valid as the index always pertains to a builtin exporter,
|
||||
// for which the returned structure is guaranteed to be of static storage duration.
|
||||
return Exporter().GetExportFormatDescription(pIndex);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)
|
||||
{
|
||||
if (!pOut || !pIn) {
|
||||
return;
|
||||
}
|
||||
if (!pOut || !pIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
SceneCombiner::CopyScene(pOut,pIn,true);
|
||||
ScenePriv(*pOut)->mIsCopy = true;
|
||||
SceneCombiner::CopyScene(pOut,pIn,true);
|
||||
ScenePriv(*pOut)->mIsCopy = true;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn)
|
||||
{
|
||||
// note: aiReleaseImport() is also able to delete scene copies, but in addition
|
||||
// it also handles scenes with import metadata.
|
||||
delete pIn;
|
||||
// note: aiReleaseImport() is also able to delete scene copies, but in addition
|
||||
// it also handles scenes with import metadata.
|
||||
delete pIn;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing )
|
||||
{
|
||||
return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing);
|
||||
return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing )
|
||||
{
|
||||
Exporter exp;
|
||||
Exporter exp;
|
||||
|
||||
if (pIO) {
|
||||
exp.SetIOHandler(new CIOSystemWrapper(pIO));
|
||||
}
|
||||
return exp.Export(pScene,pFormatId,pFileName,pPreprocessing);
|
||||
if (pIO) {
|
||||
exp.SetIOHandler(new CIOSystemWrapper(pIO));
|
||||
}
|
||||
return exp.Export(pScene,pFormatId,pFileName,pPreprocessing);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing )
|
||||
{
|
||||
Exporter exp;
|
||||
if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) {
|
||||
return NULL;
|
||||
}
|
||||
const aiExportDataBlob* blob = exp.GetOrphanedBlob();
|
||||
ai_assert(blob);
|
||||
Exporter exp;
|
||||
if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) {
|
||||
return NULL;
|
||||
}
|
||||
const aiExportDataBlob* blob = exp.GetOrphanedBlob();
|
||||
ai_assert(blob);
|
||||
|
||||
return blob;
|
||||
return blob;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData )
|
||||
{
|
||||
delete pData;
|
||||
delete pData;
|
||||
}
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_EXPORT
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -60,69 +60,69 @@ namespace Assimp{
|
|||
class B3DImporter : public BaseImporter{
|
||||
public:
|
||||
|
||||
virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
|
||||
virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual const aiImporterDesc* GetInfo () const;
|
||||
virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
virtual const aiImporterDesc* GetInfo () const;
|
||||
virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
|
||||
private:
|
||||
|
||||
int ReadByte();
|
||||
int ReadInt();
|
||||
float ReadFloat();
|
||||
aiVector2D ReadVec2();
|
||||
aiVector3D ReadVec3();
|
||||
aiQuaternion ReadQuat();
|
||||
std::string ReadString();
|
||||
std::string ReadChunk();
|
||||
void ExitChunk();
|
||||
unsigned ChunkSize();
|
||||
int ReadByte();
|
||||
int ReadInt();
|
||||
float ReadFloat();
|
||||
aiVector2D ReadVec2();
|
||||
aiVector3D ReadVec3();
|
||||
aiQuaternion ReadQuat();
|
||||
std::string ReadString();
|
||||
std::string ReadChunk();
|
||||
void ExitChunk();
|
||||
unsigned ChunkSize();
|
||||
|
||||
template<class T>
|
||||
T *to_array( const std::vector<T> &v );
|
||||
template<class T>
|
||||
T *to_array( const std::vector<T> &v );
|
||||
|
||||
struct Vertex{
|
||||
aiVector3D vertex;
|
||||
aiVector3D normal;
|
||||
aiVector3D texcoords;
|
||||
unsigned char bones[4];
|
||||
float weights[4];
|
||||
};
|
||||
struct Vertex{
|
||||
aiVector3D vertex;
|
||||
aiVector3D normal;
|
||||
aiVector3D texcoords;
|
||||
unsigned char bones[4];
|
||||
float weights[4];
|
||||
};
|
||||
|
||||
AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Oops() AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void Fail( std::string str ) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
void ReadTEXS();
|
||||
void ReadBRUS();
|
||||
void ReadTEXS();
|
||||
void ReadBRUS();
|
||||
|
||||
void ReadVRTS();
|
||||
void ReadTRIS( int v0 );
|
||||
void ReadMESH();
|
||||
void ReadBONE( int id );
|
||||
void ReadKEYS( aiNodeAnim *nodeAnim );
|
||||
void ReadANIM();
|
||||
void ReadVRTS();
|
||||
void ReadTRIS( int v0 );
|
||||
void ReadMESH();
|
||||
void ReadBONE( int id );
|
||||
void ReadKEYS( aiNodeAnim *nodeAnim );
|
||||
void ReadANIM();
|
||||
|
||||
aiNode *ReadNODE( aiNode *parent );
|
||||
aiNode *ReadNODE( aiNode *parent );
|
||||
|
||||
void ReadBB3D( aiScene *scene );
|
||||
void ReadBB3D( aiScene *scene );
|
||||
|
||||
unsigned _pos;
|
||||
// unsigned _size;
|
||||
std::vector<unsigned char> _buf;
|
||||
std::vector<unsigned> _stack;
|
||||
unsigned _pos;
|
||||
// unsigned _size;
|
||||
std::vector<unsigned char> _buf;
|
||||
std::vector<unsigned> _stack;
|
||||
|
||||
std::vector<std::string> _textures;
|
||||
std::vector<aiMaterial*> _materials;
|
||||
std::vector<std::string> _textures;
|
||||
std::vector<aiMaterial*> _materials;
|
||||
|
||||
int _vflags,_tcsets,_tcsize;
|
||||
std::vector<Vertex> _vertices;
|
||||
int _vflags,_tcsets,_tcsize;
|
||||
std::vector<Vertex> _vertices;
|
||||
|
||||
std::vector<aiNode*> _nodes;
|
||||
std::vector<aiMesh*> _meshes;
|
||||
std::vector<aiNodeAnim*> _nodeAnims;
|
||||
std::vector<aiAnimation*> _animations;
|
||||
std::vector<aiNode*> _nodes;
|
||||
std::vector<aiMesh*> _meshes;
|
||||
std::vector<aiNodeAnim*> _nodeAnims;
|
||||
std::vector<aiAnimation*> _animations;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -55,16 +55,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"BVH Importer (MoCap)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"bvh"
|
||||
"BVH Importer (MoCap)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"bvh"
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -82,458 +82,458 @@ BVHLoader::~BVHLoader()
|
|||
// Returns whether the class can handle the format of the given file.
|
||||
bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
|
||||
{
|
||||
// check file extension
|
||||
const std::string extension = GetExtension(pFile);
|
||||
// check file extension
|
||||
const std::string extension = GetExtension(pFile);
|
||||
|
||||
if( extension == "bvh")
|
||||
return true;
|
||||
if( extension == "bvh")
|
||||
return true;
|
||||
|
||||
if ((!extension.length() || cs) && pIOHandler) {
|
||||
const char* tokens[] = {"HIERARCHY"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
if ((!extension.length() || cs) && pIOHandler) {
|
||||
const char* tokens[] = {"HIERARCHY"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BVHLoader::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Loader meta information
|
||||
const aiImporterDesc* BVHLoader::GetInfo () const
|
||||
{
|
||||
return &desc;
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
mFileName = pFile;
|
||||
mFileName = pFile;
|
||||
|
||||
// read file into memory
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||
if( file.get() == NULL)
|
||||
throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
||||
// read file into memory
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||
if( file.get() == NULL)
|
||||
throw DeadlyImportError( "Failed to open file " + pFile + ".");
|
||||
|
||||
size_t fileSize = file->FileSize();
|
||||
if( fileSize == 0)
|
||||
throw DeadlyImportError( "File is too small.");
|
||||
size_t fileSize = file->FileSize();
|
||||
if( fileSize == 0)
|
||||
throw DeadlyImportError( "File is too small.");
|
||||
|
||||
mBuffer.resize( fileSize);
|
||||
file->Read( &mBuffer.front(), 1, fileSize);
|
||||
mBuffer.resize( fileSize);
|
||||
file->Read( &mBuffer.front(), 1, fileSize);
|
||||
|
||||
// start reading
|
||||
mReader = mBuffer.begin();
|
||||
mLine = 1;
|
||||
ReadStructure( pScene);
|
||||
// start reading
|
||||
mReader = mBuffer.begin();
|
||||
mLine = 1;
|
||||
ReadStructure( pScene);
|
||||
|
||||
if (!noSkeletonMesh) {
|
||||
// build a dummy mesh for the skeleton so that we see something at least
|
||||
SkeletonMeshBuilder meshBuilder( pScene);
|
||||
}
|
||||
if (!noSkeletonMesh) {
|
||||
// build a dummy mesh for the skeleton so that we see something at least
|
||||
SkeletonMeshBuilder meshBuilder( pScene);
|
||||
}
|
||||
|
||||
// construct an animation from all the motion data we read
|
||||
CreateAnimation( pScene);
|
||||
// construct an animation from all the motion data we read
|
||||
CreateAnimation( pScene);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the file
|
||||
void BVHLoader::ReadStructure( aiScene* pScene)
|
||||
{
|
||||
// first comes hierarchy
|
||||
std::string header = GetNextToken();
|
||||
if( header != "HIERARCHY")
|
||||
ThrowException( "Expected header string \"HIERARCHY\".");
|
||||
ReadHierarchy( pScene);
|
||||
// first comes hierarchy
|
||||
std::string header = GetNextToken();
|
||||
if( header != "HIERARCHY")
|
||||
ThrowException( "Expected header string \"HIERARCHY\".");
|
||||
ReadHierarchy( pScene);
|
||||
|
||||
// then comes the motion data
|
||||
std::string motion = GetNextToken();
|
||||
if( motion != "MOTION")
|
||||
ThrowException( "Expected beginning of motion data \"MOTION\".");
|
||||
ReadMotion( pScene);
|
||||
// then comes the motion data
|
||||
std::string motion = GetNextToken();
|
||||
if( motion != "MOTION")
|
||||
ThrowException( "Expected beginning of motion data \"MOTION\".");
|
||||
ReadMotion( pScene);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the hierarchy
|
||||
void BVHLoader::ReadHierarchy( aiScene* pScene)
|
||||
{
|
||||
std::string root = GetNextToken();
|
||||
if( root != "ROOT")
|
||||
ThrowException( "Expected root node \"ROOT\".");
|
||||
std::string root = GetNextToken();
|
||||
if( root != "ROOT")
|
||||
ThrowException( "Expected root node \"ROOT\".");
|
||||
|
||||
// Go read the hierarchy from here
|
||||
pScene->mRootNode = ReadNode();
|
||||
// Go read the hierarchy from here
|
||||
pScene->mRootNode = ReadNode();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a node and recursively its childs and returns the created node;
|
||||
aiNode* BVHLoader::ReadNode()
|
||||
{
|
||||
// first token is name
|
||||
std::string nodeName = GetNextToken();
|
||||
if( nodeName.empty() || nodeName == "{")
|
||||
ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
|
||||
// first token is name
|
||||
std::string nodeName = GetNextToken();
|
||||
if( nodeName.empty() || nodeName == "{")
|
||||
ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
|
||||
|
||||
// then an opening brace should follow
|
||||
std::string openBrace = GetNextToken();
|
||||
if( openBrace != "{")
|
||||
ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
|
||||
// then an opening brace should follow
|
||||
std::string openBrace = GetNextToken();
|
||||
if( openBrace != "{")
|
||||
ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
|
||||
|
||||
// Create a node
|
||||
aiNode* node = new aiNode( nodeName);
|
||||
std::vector<aiNode*> childNodes;
|
||||
// Create a node
|
||||
aiNode* node = new aiNode( nodeName);
|
||||
std::vector<aiNode*> childNodes;
|
||||
|
||||
// and create an bone entry for it
|
||||
mNodes.push_back( Node( node));
|
||||
Node& internNode = mNodes.back();
|
||||
// and create an bone entry for it
|
||||
mNodes.push_back( Node( node));
|
||||
Node& internNode = mNodes.back();
|
||||
|
||||
// now read the node's contents
|
||||
while( 1)
|
||||
{
|
||||
std::string token = GetNextToken();
|
||||
// now read the node's contents
|
||||
while( 1)
|
||||
{
|
||||
std::string token = GetNextToken();
|
||||
|
||||
// node offset to parent node
|
||||
if( token == "OFFSET")
|
||||
ReadNodeOffset( node);
|
||||
else if( token == "CHANNELS")
|
||||
ReadNodeChannels( internNode);
|
||||
else if( token == "JOINT")
|
||||
{
|
||||
// child node follows
|
||||
aiNode* child = ReadNode();
|
||||
child->mParent = node;
|
||||
childNodes.push_back( child);
|
||||
}
|
||||
else if( token == "End")
|
||||
{
|
||||
// The real symbol is "End Site". Second part comes in a separate token
|
||||
std::string siteToken = GetNextToken();
|
||||
if( siteToken != "Site")
|
||||
ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken));
|
||||
// node offset to parent node
|
||||
if( token == "OFFSET")
|
||||
ReadNodeOffset( node);
|
||||
else if( token == "CHANNELS")
|
||||
ReadNodeChannels( internNode);
|
||||
else if( token == "JOINT")
|
||||
{
|
||||
// child node follows
|
||||
aiNode* child = ReadNode();
|
||||
child->mParent = node;
|
||||
childNodes.push_back( child);
|
||||
}
|
||||
else if( token == "End")
|
||||
{
|
||||
// The real symbol is "End Site". Second part comes in a separate token
|
||||
std::string siteToken = GetNextToken();
|
||||
if( siteToken != "Site")
|
||||
ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken));
|
||||
|
||||
aiNode* child = ReadEndSite( nodeName);
|
||||
child->mParent = node;
|
||||
childNodes.push_back( child);
|
||||
}
|
||||
else if( token == "}")
|
||||
{
|
||||
// we're done with that part of the hierarchy
|
||||
break;
|
||||
} else
|
||||
{
|
||||
// everything else is a parse error
|
||||
ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
|
||||
}
|
||||
}
|
||||
aiNode* child = ReadEndSite( nodeName);
|
||||
child->mParent = node;
|
||||
childNodes.push_back( child);
|
||||
}
|
||||
else if( token == "}")
|
||||
{
|
||||
// we're done with that part of the hierarchy
|
||||
break;
|
||||
} else
|
||||
{
|
||||
// everything else is a parse error
|
||||
ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
|
||||
}
|
||||
}
|
||||
|
||||
// add the child nodes if there are any
|
||||
if( childNodes.size() > 0)
|
||||
{
|
||||
node->mNumChildren = childNodes.size();
|
||||
node->mChildren = new aiNode*[node->mNumChildren];
|
||||
std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
|
||||
}
|
||||
// add the child nodes if there are any
|
||||
if( childNodes.size() > 0)
|
||||
{
|
||||
node->mNumChildren = childNodes.size();
|
||||
node->mChildren = new aiNode*[node->mNumChildren];
|
||||
std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
|
||||
}
|
||||
|
||||
// and return the sub-hierarchy we built here
|
||||
return node;
|
||||
// and return the sub-hierarchy we built here
|
||||
return node;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads an end node and returns the created node.
|
||||
aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
|
||||
{
|
||||
// check opening brace
|
||||
std::string openBrace = GetNextToken();
|
||||
if( openBrace != "{")
|
||||
ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
|
||||
// check opening brace
|
||||
std::string openBrace = GetNextToken();
|
||||
if( openBrace != "{")
|
||||
ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
|
||||
|
||||
// Create a node
|
||||
aiNode* node = new aiNode( "EndSite_" + pParentName);
|
||||
// Create a node
|
||||
aiNode* node = new aiNode( "EndSite_" + pParentName);
|
||||
|
||||
// now read the node's contents. Only possible entry is "OFFSET"
|
||||
while( 1)
|
||||
{
|
||||
std::string token = GetNextToken();
|
||||
// now read the node's contents. Only possible entry is "OFFSET"
|
||||
while( 1)
|
||||
{
|
||||
std::string token = GetNextToken();
|
||||
|
||||
// end node's offset
|
||||
if( token == "OFFSET")
|
||||
{
|
||||
ReadNodeOffset( node);
|
||||
}
|
||||
else if( token == "}")
|
||||
{
|
||||
// we're done with the end node
|
||||
break;
|
||||
} else
|
||||
{
|
||||
// everything else is a parse error
|
||||
ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
|
||||
}
|
||||
}
|
||||
// end node's offset
|
||||
if( token == "OFFSET")
|
||||
{
|
||||
ReadNodeOffset( node);
|
||||
}
|
||||
else if( token == "}")
|
||||
{
|
||||
// we're done with the end node
|
||||
break;
|
||||
} else
|
||||
{
|
||||
// everything else is a parse error
|
||||
ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
|
||||
}
|
||||
}
|
||||
|
||||
// and return the sub-hierarchy we built here
|
||||
return node;
|
||||
// and return the sub-hierarchy we built here
|
||||
return node;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a node offset for the given node
|
||||
void BVHLoader::ReadNodeOffset( aiNode* pNode)
|
||||
{
|
||||
// Offset consists of three floats to read
|
||||
aiVector3D offset;
|
||||
offset.x = GetNextTokenAsFloat();
|
||||
offset.y = GetNextTokenAsFloat();
|
||||
offset.z = GetNextTokenAsFloat();
|
||||
// Offset consists of three floats to read
|
||||
aiVector3D offset;
|
||||
offset.x = GetNextTokenAsFloat();
|
||||
offset.y = GetNextTokenAsFloat();
|
||||
offset.z = GetNextTokenAsFloat();
|
||||
|
||||
// build a transformation matrix from it
|
||||
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
|
||||
0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
// build a transformation matrix from it
|
||||
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
|
||||
0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the animation channels for the given node
|
||||
void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
|
||||
{
|
||||
// number of channels. Use the float reader because we're lazy
|
||||
float numChannelsFloat = GetNextTokenAsFloat();
|
||||
unsigned int numChannels = (unsigned int) numChannelsFloat;
|
||||
// number of channels. Use the float reader because we're lazy
|
||||
float numChannelsFloat = GetNextTokenAsFloat();
|
||||
unsigned int numChannels = (unsigned int) numChannelsFloat;
|
||||
|
||||
for( unsigned int a = 0; a < numChannels; a++)
|
||||
{
|
||||
std::string channelToken = GetNextToken();
|
||||
for( unsigned int a = 0; a < numChannels; a++)
|
||||
{
|
||||
std::string channelToken = GetNextToken();
|
||||
|
||||
if( channelToken == "Xposition")
|
||||
pNode.mChannels.push_back( Channel_PositionX);
|
||||
else if( channelToken == "Yposition")
|
||||
pNode.mChannels.push_back( Channel_PositionY);
|
||||
else if( channelToken == "Zposition")
|
||||
pNode.mChannels.push_back( Channel_PositionZ);
|
||||
else if( channelToken == "Xrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationX);
|
||||
else if( channelToken == "Yrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationY);
|
||||
else if( channelToken == "Zrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationZ);
|
||||
else
|
||||
ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken));
|
||||
}
|
||||
if( channelToken == "Xposition")
|
||||
pNode.mChannels.push_back( Channel_PositionX);
|
||||
else if( channelToken == "Yposition")
|
||||
pNode.mChannels.push_back( Channel_PositionY);
|
||||
else if( channelToken == "Zposition")
|
||||
pNode.mChannels.push_back( Channel_PositionZ);
|
||||
else if( channelToken == "Xrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationX);
|
||||
else if( channelToken == "Yrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationY);
|
||||
else if( channelToken == "Zrotation")
|
||||
pNode.mChannels.push_back( Channel_RotationZ);
|
||||
else
|
||||
ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the motion data
|
||||
void BVHLoader::ReadMotion( aiScene* /*pScene*/)
|
||||
{
|
||||
// Read number of frames
|
||||
std::string tokenFrames = GetNextToken();
|
||||
if( tokenFrames != "Frames:")
|
||||
ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
|
||||
// Read number of frames
|
||||
std::string tokenFrames = GetNextToken();
|
||||
if( tokenFrames != "Frames:")
|
||||
ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
|
||||
|
||||
float numFramesFloat = GetNextTokenAsFloat();
|
||||
mAnimNumFrames = (unsigned int) numFramesFloat;
|
||||
float numFramesFloat = GetNextTokenAsFloat();
|
||||
mAnimNumFrames = (unsigned int) numFramesFloat;
|
||||
|
||||
// Read frame duration
|
||||
std::string tokenDuration1 = GetNextToken();
|
||||
std::string tokenDuration2 = GetNextToken();
|
||||
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
||||
ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
|
||||
// Read frame duration
|
||||
std::string tokenDuration1 = GetNextToken();
|
||||
std::string tokenDuration2 = GetNextToken();
|
||||
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
|
||||
ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
|
||||
|
||||
mAnimTickDuration = GetNextTokenAsFloat();
|
||||
mAnimTickDuration = GetNextTokenAsFloat();
|
||||
|
||||
// resize value vectors for each node
|
||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||
it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
|
||||
// resize value vectors for each node
|
||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||
it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
|
||||
|
||||
// now read all the data and store it in the corresponding node's value vector
|
||||
for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
|
||||
{
|
||||
// on each line read the values for all nodes
|
||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||
{
|
||||
// get as many values as the node has channels
|
||||
for( unsigned int c = 0; c < it->mChannels.size(); ++c)
|
||||
it->mChannelValues.push_back( GetNextTokenAsFloat());
|
||||
}
|
||||
// now read all the data and store it in the corresponding node's value vector
|
||||
for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
|
||||
{
|
||||
// on each line read the values for all nodes
|
||||
for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
|
||||
{
|
||||
// get as many values as the node has channels
|
||||
for( unsigned int c = 0; c < it->mChannels.size(); ++c)
|
||||
it->mChannelValues.push_back( GetNextTokenAsFloat());
|
||||
}
|
||||
|
||||
// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
|
||||
}
|
||||
// after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Retrieves the next token
|
||||
std::string BVHLoader::GetNextToken()
|
||||
{
|
||||
// skip any preceeding whitespace
|
||||
while( mReader != mBuffer.end())
|
||||
{
|
||||
if( !isspace( *mReader))
|
||||
break;
|
||||
// skip any preceeding whitespace
|
||||
while( mReader != mBuffer.end())
|
||||
{
|
||||
if( !isspace( *mReader))
|
||||
break;
|
||||
|
||||
// count lines
|
||||
if( *mReader == '\n')
|
||||
mLine++;
|
||||
// count lines
|
||||
if( *mReader == '\n')
|
||||
mLine++;
|
||||
|
||||
++mReader;
|
||||
}
|
||||
++mReader;
|
||||
}
|
||||
|
||||
// collect all chars till the next whitespace. BVH is easy in respect to that.
|
||||
std::string token;
|
||||
while( mReader != mBuffer.end())
|
||||
{
|
||||
if( isspace( *mReader))
|
||||
break;
|
||||
// collect all chars till the next whitespace. BVH is easy in respect to that.
|
||||
std::string token;
|
||||
while( mReader != mBuffer.end())
|
||||
{
|
||||
if( isspace( *mReader))
|
||||
break;
|
||||
|
||||
token.push_back( *mReader);
|
||||
++mReader;
|
||||
token.push_back( *mReader);
|
||||
++mReader;
|
||||
|
||||
// little extra logic to make sure braces are counted correctly
|
||||
if( token == "{" || token == "}")
|
||||
break;
|
||||
}
|
||||
// little extra logic to make sure braces are counted correctly
|
||||
if( token == "{" || token == "}")
|
||||
break;
|
||||
}
|
||||
|
||||
// empty token means end of file, which is just fine
|
||||
return token;
|
||||
// empty token means end of file, which is just fine
|
||||
return token;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the next token as a float
|
||||
float BVHLoader::GetNextTokenAsFloat()
|
||||
{
|
||||
std::string token = GetNextToken();
|
||||
if( token.empty())
|
||||
ThrowException( "Unexpected end of file while trying to read a float");
|
||||
std::string token = GetNextToken();
|
||||
if( token.empty())
|
||||
ThrowException( "Unexpected end of file while trying to read a float");
|
||||
|
||||
// check if the float is valid by testing if the atof() function consumed every char of the token
|
||||
const char* ctoken = token.c_str();
|
||||
float result = 0.0f;
|
||||
ctoken = fast_atoreal_move<float>( ctoken, result);
|
||||
// check if the float is valid by testing if the atof() function consumed every char of the token
|
||||
const char* ctoken = token.c_str();
|
||||
float result = 0.0f;
|
||||
ctoken = fast_atoreal_move<float>( ctoken, result);
|
||||
|
||||
if( ctoken != token.c_str() + token.length())
|
||||
ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token));
|
||||
if( ctoken != token.c_str() + token.length())
|
||||
ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token));
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Aborts the file reading with an exception
|
||||
AI_WONT_RETURN void BVHLoader::ThrowException( const std::string& pError)
|
||||
{
|
||||
throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
|
||||
throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructs an animation for the motion data and stores it in the given scene
|
||||
void BVHLoader::CreateAnimation( aiScene* pScene)
|
||||
{
|
||||
// create the animation
|
||||
pScene->mNumAnimations = 1;
|
||||
pScene->mAnimations = new aiAnimation*[1];
|
||||
aiAnimation* anim = new aiAnimation;
|
||||
pScene->mAnimations[0] = anim;
|
||||
// create the animation
|
||||
pScene->mNumAnimations = 1;
|
||||
pScene->mAnimations = new aiAnimation*[1];
|
||||
aiAnimation* anim = new aiAnimation;
|
||||
pScene->mAnimations[0] = anim;
|
||||
|
||||
// put down the basic parameters
|
||||
anim->mName.Set( "Motion");
|
||||
anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
|
||||
anim->mDuration = double( mAnimNumFrames - 1);
|
||||
// put down the basic parameters
|
||||
anim->mName.Set( "Motion");
|
||||
anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
|
||||
anim->mDuration = double( mAnimNumFrames - 1);
|
||||
|
||||
// now generate the tracks for all nodes
|
||||
anim->mNumChannels = mNodes.size();
|
||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
||||
// now generate the tracks for all nodes
|
||||
anim->mNumChannels = mNodes.size();
|
||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
||||
|
||||
// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i)
|
||||
anim->mChannels[i] = NULL;
|
||||
// FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i)
|
||||
anim->mChannels[i] = NULL;
|
||||
|
||||
for( unsigned int a = 0; a < anim->mNumChannels; a++)
|
||||
{
|
||||
const Node& node = mNodes[a];
|
||||
const std::string nodeName = std::string( node.mNode->mName.data );
|
||||
aiNodeAnim* nodeAnim = new aiNodeAnim;
|
||||
anim->mChannels[a] = nodeAnim;
|
||||
nodeAnim->mNodeName.Set( nodeName);
|
||||
for( unsigned int a = 0; a < anim->mNumChannels; a++)
|
||||
{
|
||||
const Node& node = mNodes[a];
|
||||
const std::string nodeName = std::string( node.mNode->mName.data );
|
||||
aiNodeAnim* nodeAnim = new aiNodeAnim;
|
||||
anim->mChannels[a] = nodeAnim;
|
||||
nodeAnim->mNodeName.Set( nodeName);
|
||||
|
||||
// translational part, if given
|
||||
if( node.mChannels.size() == 6)
|
||||
{
|
||||
nodeAnim->mNumPositionKeys = mAnimNumFrames;
|
||||
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
|
||||
aiVectorKey* poskey = nodeAnim->mPositionKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
poskey->mTime = double( fr);
|
||||
// translational part, if given
|
||||
if( node.mChannels.size() == 6)
|
||||
{
|
||||
nodeAnim->mNumPositionKeys = mAnimNumFrames;
|
||||
nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
|
||||
aiVectorKey* poskey = nodeAnim->mPositionKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
poskey->mTime = double( fr);
|
||||
|
||||
// Now compute all translations in the right order
|
||||
for( unsigned int channel = 0; channel < 3; ++channel)
|
||||
{
|
||||
switch( node.mChannels[channel])
|
||||
{
|
||||
case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
|
||||
case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
|
||||
case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
|
||||
default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
|
||||
}
|
||||
}
|
||||
++poskey;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// if no translation part is given, put a default sequence
|
||||
aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
|
||||
nodeAnim->mNumPositionKeys = 1;
|
||||
nodeAnim->mPositionKeys = new aiVectorKey[1];
|
||||
nodeAnim->mPositionKeys[0].mTime = 0.0;
|
||||
nodeAnim->mPositionKeys[0].mValue = nodePos;
|
||||
}
|
||||
// Now compute all translations in the right order
|
||||
for( unsigned int channel = 0; channel < 3; ++channel)
|
||||
{
|
||||
switch( node.mChannels[channel])
|
||||
{
|
||||
case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
|
||||
case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
|
||||
case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
|
||||
default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
|
||||
}
|
||||
}
|
||||
++poskey;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// if no translation part is given, put a default sequence
|
||||
aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
|
||||
nodeAnim->mNumPositionKeys = 1;
|
||||
nodeAnim->mPositionKeys = new aiVectorKey[1];
|
||||
nodeAnim->mPositionKeys[0].mTime = 0.0;
|
||||
nodeAnim->mPositionKeys[0].mValue = nodePos;
|
||||
}
|
||||
|
||||
// rotation part. Always present. First find value offsets
|
||||
{
|
||||
unsigned int rotOffset = 0;
|
||||
if( node.mChannels.size() == 6)
|
||||
{
|
||||
// Offset all further calculations
|
||||
rotOffset = 3;
|
||||
}
|
||||
// rotation part. Always present. First find value offsets
|
||||
{
|
||||
unsigned int rotOffset = 0;
|
||||
if( node.mChannels.size() == 6)
|
||||
{
|
||||
// Offset all further calculations
|
||||
rotOffset = 3;
|
||||
}
|
||||
|
||||
// Then create the number of rotation keys
|
||||
nodeAnim->mNumRotationKeys = mAnimNumFrames;
|
||||
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
|
||||
aiQuatKey* rotkey = nodeAnim->mRotationKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
aiMatrix4x4 temp;
|
||||
aiMatrix3x3 rotMatrix;
|
||||
// Then create the number of rotation keys
|
||||
nodeAnim->mNumRotationKeys = mAnimNumFrames;
|
||||
nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
|
||||
aiQuatKey* rotkey = nodeAnim->mRotationKeys;
|
||||
for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
|
||||
{
|
||||
aiMatrix4x4 temp;
|
||||
aiMatrix3x3 rotMatrix;
|
||||
|
||||
for( unsigned int channel = 0; channel < 3; ++channel)
|
||||
{
|
||||
// translate ZXY euler angels into a quaternion
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
|
||||
for( unsigned int channel = 0; channel < 3; ++channel)
|
||||
{
|
||||
// translate ZXY euler angels into a quaternion
|
||||
const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
|
||||
|
||||
// Compute rotation transformations in the right order
|
||||
switch (node.mChannels[rotOffset+channel])
|
||||
{
|
||||
case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
|
||||
case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
|
||||
case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
|
||||
default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
|
||||
}
|
||||
}
|
||||
// Compute rotation transformations in the right order
|
||||
switch (node.mChannels[rotOffset+channel])
|
||||
{
|
||||
case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
|
||||
case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
|
||||
case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
|
||||
default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
|
||||
}
|
||||
}
|
||||
|
||||
rotkey->mTime = double( fr);
|
||||
rotkey->mValue = aiQuaternion( rotMatrix);
|
||||
++rotkey;
|
||||
}
|
||||
}
|
||||
rotkey->mTime = double( fr);
|
||||
rotkey->mValue = aiQuaternion( rotMatrix);
|
||||
++rotkey;
|
||||
}
|
||||
}
|
||||
|
||||
// scaling part. Always just a default track
|
||||
{
|
||||
nodeAnim->mNumScalingKeys = 1;
|
||||
nodeAnim->mScalingKeys = new aiVectorKey[1];
|
||||
nodeAnim->mScalingKeys[0].mTime = 0.0;
|
||||
nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
// scaling part. Always just a default track
|
||||
{
|
||||
nodeAnim->mNumScalingKeys = 1;
|
||||
nodeAnim->mScalingKeys = new aiVectorKey[1];
|
||||
nodeAnim->mScalingKeys[0].mTime = 0.0;
|
||||
nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER
|
||||
|
|
136
code/BVHLoader.h
136
code/BVHLoader.h
|
@ -64,106 +64,106 @@ namespace Assimp
|
|||
class BVHLoader : public BaseImporter
|
||||
{
|
||||
|
||||
/** Possible animation channels for which the motion data holds the values */
|
||||
enum ChannelType
|
||||
{
|
||||
Channel_PositionX,
|
||||
Channel_PositionY,
|
||||
Channel_PositionZ,
|
||||
Channel_RotationX,
|
||||
Channel_RotationY,
|
||||
Channel_RotationZ
|
||||
};
|
||||
/** Possible animation channels for which the motion data holds the values */
|
||||
enum ChannelType
|
||||
{
|
||||
Channel_PositionX,
|
||||
Channel_PositionY,
|
||||
Channel_PositionZ,
|
||||
Channel_RotationX,
|
||||
Channel_RotationY,
|
||||
Channel_RotationZ
|
||||
};
|
||||
|
||||
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
|
||||
struct Node
|
||||
{
|
||||
const aiNode* mNode;
|
||||
std::vector<ChannelType> mChannels;
|
||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||
/** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
|
||||
struct Node
|
||||
{
|
||||
const aiNode* mNode;
|
||||
std::vector<ChannelType> mChannels;
|
||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||
|
||||
Node() { }
|
||||
Node( const aiNode* pNode) : mNode( pNode) { }
|
||||
};
|
||||
Node() { }
|
||||
Node( const aiNode* pNode) : mNode( pNode) { }
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
BVHLoader();
|
||||
~BVHLoader();
|
||||
BVHLoader();
|
||||
~BVHLoader();
|
||||
|
||||
public:
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
|
||||
|
||||
void SetupProperties(const Importer* pImp);
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
void SetupProperties(const Importer* pImp);
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
|
||||
protected:
|
||||
/** Reads the file */
|
||||
void ReadStructure( aiScene* pScene);
|
||||
/** Reads the file */
|
||||
void ReadStructure( aiScene* pScene);
|
||||
|
||||
/** Reads the hierarchy */
|
||||
void ReadHierarchy( aiScene* pScene);
|
||||
/** Reads the hierarchy */
|
||||
void ReadHierarchy( aiScene* pScene);
|
||||
|
||||
/** Reads a node and recursively its childs and returns the created node. */
|
||||
aiNode* ReadNode();
|
||||
/** Reads a node and recursively its childs and returns the created node. */
|
||||
aiNode* ReadNode();
|
||||
|
||||
/** Reads an end node and returns the created node. */
|
||||
aiNode* ReadEndSite( const std::string& pParentName);
|
||||
/** Reads an end node and returns the created node. */
|
||||
aiNode* ReadEndSite( const std::string& pParentName);
|
||||
|
||||
/** Reads a node offset for the given node */
|
||||
void ReadNodeOffset( aiNode* pNode);
|
||||
/** Reads a node offset for the given node */
|
||||
void ReadNodeOffset( aiNode* pNode);
|
||||
|
||||
/** Reads the animation channels into the given node */
|
||||
void ReadNodeChannels( BVHLoader::Node& pNode);
|
||||
/** Reads the animation channels into the given node */
|
||||
void ReadNodeChannels( BVHLoader::Node& pNode);
|
||||
|
||||
/** Reads the motion data */
|
||||
void ReadMotion( aiScene* pScene);
|
||||
/** Reads the motion data */
|
||||
void ReadMotion( aiScene* pScene);
|
||||
|
||||
/** Retrieves the next token */
|
||||
std::string GetNextToken();
|
||||
/** Retrieves the next token */
|
||||
std::string GetNextToken();
|
||||
|
||||
/** Reads the next token as a float */
|
||||
float GetNextTokenAsFloat();
|
||||
/** Reads the next token as a float */
|
||||
float GetNextTokenAsFloat();
|
||||
|
||||
/** Aborts the file reading with an exception */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
|
||||
/** Aborts the file reading with an exception */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
/** Constructs an animation for the motion data and stores it in the given scene */
|
||||
void CreateAnimation( aiScene* pScene);
|
||||
/** Constructs an animation for the motion data and stores it in the given scene */
|
||||
void CreateAnimation( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
|
||||
/** Buffer to hold the loaded file */
|
||||
std::vector<char> mBuffer;
|
||||
/** Buffer to hold the loaded file */
|
||||
std::vector<char> mBuffer;
|
||||
|
||||
/** Next char to read from the buffer */
|
||||
std::vector<char>::const_iterator mReader;
|
||||
/** Next char to read from the buffer */
|
||||
std::vector<char>::const_iterator mReader;
|
||||
|
||||
/** Current line, for error messages */
|
||||
unsigned int mLine;
|
||||
/** Current line, for error messages */
|
||||
unsigned int mLine;
|
||||
|
||||
/** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index.
|
||||
* Also contain the motion data for the node's channels
|
||||
*/
|
||||
std::vector<Node> mNodes;
|
||||
/** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index.
|
||||
* Also contain the motion data for the node's channels
|
||||
*/
|
||||
std::vector<Node> mNodes;
|
||||
|
||||
/** basic Animation parameters */
|
||||
float mAnimTickDuration;
|
||||
unsigned int mAnimNumFrames;
|
||||
/** basic Animation parameters */
|
||||
float mAnimTickDuration;
|
||||
unsigned int mAnimNumFrames;
|
||||
|
||||
bool noSkeletonMesh;
|
||||
bool noSkeletonMesh;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -65,100 +65,100 @@ using namespace Assimp;
|
|||
BaseImporter::BaseImporter()
|
||||
: progress()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
BaseImporter::~BaseImporter()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file and returns the imported data.
|
||||
aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
|
||||
{
|
||||
progress = pImp->GetProgressHandler();
|
||||
ai_assert(progress);
|
||||
progress = pImp->GetProgressHandler();
|
||||
ai_assert(progress);
|
||||
|
||||
// Gather configuration properties for this run
|
||||
SetupProperties( pImp );
|
||||
// Gather configuration properties for this run
|
||||
SetupProperties( pImp );
|
||||
|
||||
// Construct a file system filter to improve our success ratio at reading external files
|
||||
FileSystemFilter filter(pFile,pIOHandler);
|
||||
// Construct a file system filter to improve our success ratio at reading external files
|
||||
FileSystemFilter filter(pFile,pIOHandler);
|
||||
|
||||
// create a scene object to hold the data
|
||||
ScopeGuard<aiScene> sc(new aiScene());
|
||||
// create a scene object to hold the data
|
||||
ScopeGuard<aiScene> sc(new aiScene());
|
||||
|
||||
// dispatch importing
|
||||
try
|
||||
{
|
||||
InternReadFile( pFile, sc, &filter);
|
||||
// dispatch importing
|
||||
try
|
||||
{
|
||||
InternReadFile( pFile, sc, &filter);
|
||||
|
||||
} catch( const std::exception& err ) {
|
||||
// extract error description
|
||||
mErrorText = err.what();
|
||||
DefaultLogger::get()->error(mErrorText);
|
||||
return NULL;
|
||||
}
|
||||
} catch( const std::exception& err ) {
|
||||
// extract error description
|
||||
mErrorText = err.what();
|
||||
DefaultLogger::get()->error(mErrorText);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// return what we gathered from the import.
|
||||
sc.dismiss();
|
||||
return sc;
|
||||
// return what we gathered from the import.
|
||||
sc.dismiss();
|
||||
return sc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
// the default implementation does nothing
|
||||
// the default implementation does nothing
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
||||
{
|
||||
const aiImporterDesc* desc = GetInfo();
|
||||
ai_assert(desc != NULL);
|
||||
const aiImporterDesc* desc = GetInfo();
|
||||
ai_assert(desc != NULL);
|
||||
|
||||
const char* ext = desc->mFileExtensions;
|
||||
ai_assert(ext != NULL);
|
||||
const char* ext = desc->mFileExtensions;
|
||||
ai_assert(ext != NULL);
|
||||
|
||||
const char* last = ext;
|
||||
do {
|
||||
if (!*ext || *ext == ' ') {
|
||||
extensions.insert(std::string(last,ext-last));
|
||||
ai_assert(ext-last > 0);
|
||||
last = ext;
|
||||
while(*last == ' ') {
|
||||
++last;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(*ext++);
|
||||
const char* last = ext;
|
||||
do {
|
||||
if (!*ext || *ext == ' ') {
|
||||
extensions.insert(std::string(last,ext-last));
|
||||
ai_assert(ext-last > 0);
|
||||
last = ext;
|
||||
while(*last == ' ') {
|
||||
++last;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(*ext++);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler,
|
||||
const std::string& pFile,
|
||||
const char** tokens,
|
||||
unsigned int numTokens,
|
||||
unsigned int searchBytes /* = 200 */,
|
||||
bool tokensSol /* false */)
|
||||
const std::string& pFile,
|
||||
const char** tokens,
|
||||
unsigned int numTokens,
|
||||
unsigned int searchBytes /* = 200 */,
|
||||
bool tokensSol /* false */)
|
||||
{
|
||||
ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes);
|
||||
if (!pIOHandler)
|
||||
return false;
|
||||
ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes);
|
||||
if (!pIOHandler)
|
||||
return false;
|
||||
|
||||
boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
||||
if (pStream.get() ) {
|
||||
// read 200 characters from the file
|
||||
boost::scoped_array<char> _buffer (new char[searchBytes+1 /* for the '\0' */]);
|
||||
char* buffer = _buffer.get();
|
||||
boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
||||
if (pStream.get() ) {
|
||||
// read 200 characters from the file
|
||||
boost::scoped_array<char> _buffer (new char[searchBytes+1 /* for the '\0' */]);
|
||||
char* buffer = _buffer.get();
|
||||
if( NULL == buffer ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t read = pStream->Read(buffer,1,searchBytes);
|
||||
const size_t read = pStream->Read(buffer,1,searchBytes);
|
||||
if( !read ) {
|
||||
return false;
|
||||
}
|
||||
|
@ -167,139 +167,139 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
|||
buffer[ i ] = ::tolower( buffer[ i ] );
|
||||
}
|
||||
|
||||
// It is not a proper handling of unicode files here ...
|
||||
// ehm ... but it works in most cases.
|
||||
char* cur = buffer,*cur2 = buffer,*end = &buffer[read];
|
||||
while (cur != end) {
|
||||
// It is not a proper handling of unicode files here ...
|
||||
// ehm ... but it works in most cases.
|
||||
char* cur = buffer,*cur2 = buffer,*end = &buffer[read];
|
||||
while (cur != end) {
|
||||
if( *cur ) {
|
||||
*cur2++ = *cur;
|
||||
}
|
||||
++cur;
|
||||
}
|
||||
*cur2 = '\0';
|
||||
++cur;
|
||||
}
|
||||
*cur2 = '\0';
|
||||
|
||||
for (unsigned int i = 0; i < numTokens;++i) {
|
||||
ai_assert(NULL != tokens[i]);
|
||||
for (unsigned int i = 0; i < numTokens;++i) {
|
||||
ai_assert(NULL != tokens[i]);
|
||||
|
||||
|
||||
const char* r = strstr(buffer,tokens[i]);
|
||||
const char* r = strstr(buffer,tokens[i]);
|
||||
if( !r ) {
|
||||
continue;
|
||||
}
|
||||
// We got a match, either we don't care where it is, or it happens to
|
||||
// be in the beginning of the file / line
|
||||
if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
|
||||
DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We got a match, either we don't care where it is, or it happens to
|
||||
// be in the beginning of the file / line
|
||||
if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
|
||||
DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Simple check for file extension
|
||||
/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile,
|
||||
const char* ext0,
|
||||
const char* ext1,
|
||||
const char* ext2)
|
||||
const char* ext0,
|
||||
const char* ext1,
|
||||
const char* ext2)
|
||||
{
|
||||
std::string::size_type pos = pFile.find_last_of('.');
|
||||
std::string::size_type pos = pFile.find_last_of('.');
|
||||
|
||||
// no file extension - can't read
|
||||
if( pos == std::string::npos)
|
||||
return false;
|
||||
// no file extension - can't read
|
||||
if( pos == std::string::npos)
|
||||
return false;
|
||||
|
||||
const char* ext_real = & pFile[ pos+1 ];
|
||||
if( !ASSIMP_stricmp(ext_real,ext0) )
|
||||
return true;
|
||||
const char* ext_real = & pFile[ pos+1 ];
|
||||
if( !ASSIMP_stricmp(ext_real,ext0) )
|
||||
return true;
|
||||
|
||||
// check for other, optional, file extensions
|
||||
if (ext1 && !ASSIMP_stricmp(ext_real,ext1))
|
||||
return true;
|
||||
// check for other, optional, file extensions
|
||||
if (ext1 && !ASSIMP_stricmp(ext_real,ext1))
|
||||
return true;
|
||||
|
||||
if (ext2 && !ASSIMP_stricmp(ext_real,ext2))
|
||||
return true;
|
||||
if (ext2 && !ASSIMP_stricmp(ext_real,ext2))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get file extension from path
|
||||
/*static*/ std::string BaseImporter::GetExtension (const std::string& pFile)
|
||||
{
|
||||
std::string::size_type pos = pFile.find_last_of('.');
|
||||
std::string::size_type pos = pFile.find_last_of('.');
|
||||
|
||||
// no file extension at all
|
||||
if( pos == std::string::npos)
|
||||
return "";
|
||||
// no file extension at all
|
||||
if( pos == std::string::npos)
|
||||
return "";
|
||||
|
||||
std::string ret = pFile.substr(pos+1);
|
||||
std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
|
||||
return ret;
|
||||
std::string ret = pFile.substr(pos+1);
|
||||
std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check for magic bytes at the beginning of the file.
|
||||
/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
|
||||
const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
|
||||
const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
|
||||
{
|
||||
ai_assert(size <= 16 && _magic);
|
||||
ai_assert(size <= 16 && _magic);
|
||||
|
||||
if (!pIOHandler) {
|
||||
return false;
|
||||
}
|
||||
union {
|
||||
const char* magic;
|
||||
const uint16_t* magic_u16;
|
||||
const uint32_t* magic_u32;
|
||||
};
|
||||
magic = reinterpret_cast<const char*>(_magic);
|
||||
boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
||||
if (pStream.get() ) {
|
||||
if (!pIOHandler) {
|
||||
return false;
|
||||
}
|
||||
union {
|
||||
const char* magic;
|
||||
const uint16_t* magic_u16;
|
||||
const uint32_t* magic_u32;
|
||||
};
|
||||
magic = reinterpret_cast<const char*>(_magic);
|
||||
boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
||||
if (pStream.get() ) {
|
||||
|
||||
// skip to offset
|
||||
pStream->Seek(offset,aiOrigin_SET);
|
||||
// skip to offset
|
||||
pStream->Seek(offset,aiOrigin_SET);
|
||||
|
||||
// read 'size' characters from the file
|
||||
union {
|
||||
char data[16];
|
||||
uint16_t data_u16[8];
|
||||
uint32_t data_u32[4];
|
||||
};
|
||||
if(size != pStream->Read(data,1,size)) {
|
||||
return false;
|
||||
}
|
||||
// read 'size' characters from the file
|
||||
union {
|
||||
char data[16];
|
||||
uint16_t data_u16[8];
|
||||
uint32_t data_u32[4];
|
||||
};
|
||||
if(size != pStream->Read(data,1,size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num; ++i) {
|
||||
// also check against big endian versions of tokens with size 2,4
|
||||
// that's just for convinience, the chance that we cause conflicts
|
||||
// is quite low and it can save some lines and prevent nasty bugs
|
||||
if (2 == size) {
|
||||
uint16_t rev = *magic_u16;
|
||||
ByteSwap::Swap(&rev);
|
||||
if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (4 == size) {
|
||||
uint32_t rev = *magic_u32;
|
||||
ByteSwap::Swap(&rev);
|
||||
if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// any length ... just compare
|
||||
if(!memcmp(magic,data,size)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
magic += size;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
for (unsigned int i = 0; i < num; ++i) {
|
||||
// also check against big endian versions of tokens with size 2,4
|
||||
// that's just for convinience, the chance that we cause conflicts
|
||||
// is quite low and it can save some lines and prevent nasty bugs
|
||||
if (2 == size) {
|
||||
uint16_t rev = *magic_u16;
|
||||
ByteSwap::Swap(&rev);
|
||||
if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (4 == size) {
|
||||
uint32_t rev = *magic_u32;
|
||||
ByteSwap::Swap(&rev);
|
||||
if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// any length ... just compare
|
||||
if(!memcmp(magic,data,size)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
magic += size;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "../contrib/ConvertUTF/ConvertUTF.h"
|
||||
|
@ -307,311 +307,307 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void ReportResult(ConversionResult res)
|
||||
{
|
||||
if(res == sourceExhausted) {
|
||||
DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails");
|
||||
}
|
||||
else if(res == sourceIllegal) {
|
||||
DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails");
|
||||
}
|
||||
if(res == sourceExhausted) {
|
||||
DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails");
|
||||
}
|
||||
else if(res == sourceIllegal) {
|
||||
DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert to UTF8 data
|
||||
void BaseImporter::ConvertToUTF8(std::vector<char>& data)
|
||||
{
|
||||
ConversionResult result;
|
||||
if(data.size() < 8) {
|
||||
throw DeadlyImportError("File is too small");
|
||||
}
|
||||
ConversionResult result;
|
||||
if(data.size() < 8) {
|
||||
throw DeadlyImportError("File is too small");
|
||||
}
|
||||
|
||||
// UTF 8 with BOM
|
||||
if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
|
||||
DefaultLogger::get()->debug("Found UTF-8 BOM ...");
|
||||
// UTF 8 with BOM
|
||||
if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
|
||||
DefaultLogger::get()->debug("Found UTF-8 BOM ...");
|
||||
|
||||
std::copy(data.begin()+3,data.end(),data.begin());
|
||||
data.resize(data.size()-3);
|
||||
return;
|
||||
}
|
||||
std::copy(data.begin()+3,data.end(),data.begin());
|
||||
data.resize(data.size()-3);
|
||||
return;
|
||||
}
|
||||
|
||||
// UTF 32 BE with BOM
|
||||
if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
|
||||
// UTF 32 BE with BOM
|
||||
if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
|
||||
|
||||
// swap the endianess ..
|
||||
for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) {
|
||||
AI_SWAP4P(p);
|
||||
}
|
||||
}
|
||||
// swap the endianess ..
|
||||
for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) {
|
||||
AI_SWAP4P(p);
|
||||
}
|
||||
}
|
||||
|
||||
// UTF 32 LE with BOM
|
||||
if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
|
||||
DefaultLogger::get()->debug("Found UTF-32 BOM ...");
|
||||
// UTF 32 LE with BOM
|
||||
if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
|
||||
DefaultLogger::get()->debug("Found UTF-32 BOM ...");
|
||||
|
||||
const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
|
||||
char* dstart,*dend;
|
||||
std::vector<char> output;
|
||||
do {
|
||||
output.resize(output.size()?output.size()*3/2:data.size()/2);
|
||||
dstart = &output.front(),dend = &output.back()+1;
|
||||
const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
|
||||
char* dstart,*dend;
|
||||
std::vector<char> output;
|
||||
do {
|
||||
output.resize(output.size()?output.size()*3/2:data.size()/2);
|
||||
dstart = &output.front(),dend = &output.back()+1;
|
||||
|
||||
result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
|
||||
} while(result == targetExhausted);
|
||||
result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
|
||||
} while(result == targetExhausted);
|
||||
|
||||
ReportResult(result);
|
||||
ReportResult(result);
|
||||
|
||||
// copy to output buffer.
|
||||
const size_t outlen = (size_t)(dstart-&output.front());
|
||||
data.assign(output.begin(),output.begin()+outlen);
|
||||
return;
|
||||
}
|
||||
// copy to output buffer.
|
||||
const size_t outlen = (size_t)(dstart-&output.front());
|
||||
data.assign(output.begin(),output.begin()+outlen);
|
||||
return;
|
||||
}
|
||||
|
||||
// UTF 16 BE with BOM
|
||||
if(*((uint16_t*)&data.front()) == 0xFFFE) {
|
||||
// UTF 16 BE with BOM
|
||||
if(*((uint16_t*)&data.front()) == 0xFFFE) {
|
||||
|
||||
// swap the endianess ..
|
||||
for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) {
|
||||
ByteSwap::Swap2(p);
|
||||
}
|
||||
}
|
||||
// swap the endianess ..
|
||||
for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) {
|
||||
ByteSwap::Swap2(p);
|
||||
}
|
||||
}
|
||||
|
||||
// UTF 16 LE with BOM
|
||||
if(*((uint16_t*)&data.front()) == 0xFEFF) {
|
||||
DefaultLogger::get()->debug("Found UTF-16 BOM ...");
|
||||
// UTF 16 LE with BOM
|
||||
if(*((uint16_t*)&data.front()) == 0xFEFF) {
|
||||
DefaultLogger::get()->debug("Found UTF-16 BOM ...");
|
||||
|
||||
const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
|
||||
char* dstart,*dend;
|
||||
std::vector<char> output;
|
||||
do {
|
||||
output.resize(output.size()?output.size()*3/2:data.size()*3/4);
|
||||
dstart = &output.front(),dend = &output.back()+1;
|
||||
const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
|
||||
char* dstart,*dend;
|
||||
std::vector<char> output;
|
||||
do {
|
||||
output.resize(output.size()?output.size()*3/2:data.size()*3/4);
|
||||
dstart = &output.front(),dend = &output.back()+1;
|
||||
|
||||
result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
|
||||
} while(result == targetExhausted);
|
||||
result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
|
||||
} while(result == targetExhausted);
|
||||
|
||||
ReportResult(result);
|
||||
ReportResult(result);
|
||||
|
||||
// copy to output buffer.
|
||||
const size_t outlen = (size_t)(dstart-&output.front());
|
||||
data.assign(output.begin(),output.begin()+outlen);
|
||||
return;
|
||||
}
|
||||
// copy to output buffer.
|
||||
const size_t outlen = (size_t)(dstart-&output.front());
|
||||
data.assign(output.begin(),output.begin()+outlen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert to UTF8 data to ISO-8859-1
|
||||
void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
|
||||
{
|
||||
size_t size = data.size();
|
||||
size_t i = 0, j = 0;
|
||||
size_t size = data.size();
|
||||
size_t i = 0, j = 0;
|
||||
|
||||
while(i < size) {
|
||||
if ((unsigned char) data[i] < (size_t) 0x80) {
|
||||
data[j] = data[i];
|
||||
} else if(i < size - 1) {
|
||||
if((unsigned char) data[i] == 0xC2) {
|
||||
data[j] = data[++i];
|
||||
} else if((unsigned char) data[i] == 0xC3) {
|
||||
data[j] = ((unsigned char) data[++i] + 0x40);
|
||||
} else {
|
||||
std::stringstream stream;
|
||||
while(i < size) {
|
||||
if ((unsigned char) data[i] < (size_t) 0x80) {
|
||||
data[j] = data[i];
|
||||
} else if(i < size - 1) {
|
||||
if((unsigned char) data[i] == 0xC2) {
|
||||
data[j] = data[++i];
|
||||
} else if((unsigned char) data[i] == 0xC3) {
|
||||
data[j] = ((unsigned char) data[++i] + 0x40);
|
||||
} else {
|
||||
std::stringstream stream;
|
||||
|
||||
stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
|
||||
stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
|
||||
|
||||
DefaultLogger::get()->error(stream.str());
|
||||
DefaultLogger::get()->error(stream.str());
|
||||
|
||||
data[j++] = data[i++];
|
||||
data[j] = data[i];
|
||||
}
|
||||
} else {
|
||||
DefaultLogger::get()->error("UTF8 code but only one character remaining");
|
||||
data[j++] = data[i++];
|
||||
data[j] = data[i];
|
||||
}
|
||||
} else {
|
||||
DefaultLogger::get()->error("UTF8 code but only one character remaining");
|
||||
|
||||
data[j] = data[i];
|
||||
}
|
||||
data[j] = data[i];
|
||||
}
|
||||
|
||||
i++; j++;
|
||||
}
|
||||
i++; j++;
|
||||
}
|
||||
|
||||
data.resize(j);
|
||||
data.resize(j);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::TextFileToBuffer(IOStream* stream,
|
||||
std::vector<char>& data)
|
||||
std::vector<char>& data)
|
||||
{
|
||||
ai_assert(NULL != stream);
|
||||
ai_assert(NULL != stream);
|
||||
|
||||
const size_t fileSize = stream->FileSize();
|
||||
if(!fileSize) {
|
||||
throw DeadlyImportError("File is empty");
|
||||
}
|
||||
const size_t fileSize = stream->FileSize();
|
||||
if(!fileSize) {
|
||||
throw DeadlyImportError("File is empty");
|
||||
}
|
||||
|
||||
data.reserve(fileSize+1);
|
||||
data.resize(fileSize);
|
||||
if(fileSize != stream->Read( &data[0], 1, fileSize)) {
|
||||
throw DeadlyImportError("File read error");
|
||||
}
|
||||
data.reserve(fileSize+1);
|
||||
data.resize(fileSize);
|
||||
if(fileSize != stream->Read( &data[0], 1, fileSize)) {
|
||||
throw DeadlyImportError("File read error");
|
||||
}
|
||||
|
||||
ConvertToUTF8(data);
|
||||
ConvertToUTF8(data);
|
||||
|
||||
// append a binary zero to simplify string parsing
|
||||
data.push_back(0);
|
||||
// append a binary zero to simplify string parsing
|
||||
data.push_back(0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
namespace Assimp
|
||||
{
|
||||
// Represents an import request
|
||||
struct LoadRequest
|
||||
{
|
||||
LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id)
|
||||
: file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id)
|
||||
{
|
||||
if (_map)
|
||||
map = *_map;
|
||||
}
|
||||
// Represents an import request
|
||||
struct LoadRequest
|
||||
{
|
||||
LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id)
|
||||
: file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id)
|
||||
{
|
||||
if (_map)
|
||||
map = *_map;
|
||||
}
|
||||
|
||||
const std::string file;
|
||||
unsigned int flags;
|
||||
unsigned int refCnt;
|
||||
aiScene* scene;
|
||||
bool loaded;
|
||||
BatchLoader::PropertyMap map;
|
||||
unsigned int id;
|
||||
const std::string file;
|
||||
unsigned int flags;
|
||||
unsigned int refCnt;
|
||||
aiScene* scene;
|
||||
bool loaded;
|
||||
BatchLoader::PropertyMap map;
|
||||
unsigned int id;
|
||||
|
||||
bool operator== (const std::string& f) {
|
||||
return file == f;
|
||||
}
|
||||
};
|
||||
bool operator== (const std::string& f) {
|
||||
return file == f;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// BatchLoader::pimpl data structure
|
||||
struct Assimp::BatchData
|
||||
{
|
||||
BatchData()
|
||||
BatchData()
|
||||
: pIOSystem()
|
||||
, pImporter()
|
||||
, next_id(0xffff)
|
||||
{}
|
||||
{}
|
||||
|
||||
// IO system to be used for all imports
|
||||
IOSystem* pIOSystem;
|
||||
// IO system to be used for all imports
|
||||
IOSystem* pIOSystem;
|
||||
|
||||
// Importer used to load all meshes
|
||||
Importer* pImporter;
|
||||
// Importer used to load all meshes
|
||||
Importer* pImporter;
|
||||
|
||||
// List of all imports
|
||||
std::list<LoadRequest> requests;
|
||||
// List of all imports
|
||||
std::list<LoadRequest> requests;
|
||||
|
||||
// Base path
|
||||
std::string pathBase;
|
||||
// Base path
|
||||
std::string pathBase;
|
||||
|
||||
// Id for next item
|
||||
unsigned int next_id;
|
||||
// Id for next item
|
||||
unsigned int next_id;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BatchLoader::BatchLoader(IOSystem* pIO)
|
||||
{
|
||||
ai_assert(NULL != pIO);
|
||||
ai_assert(NULL != pIO);
|
||||
|
||||
data = new BatchData();
|
||||
data->pIOSystem = pIO;
|
||||
data = new BatchData();
|
||||
data->pIOSystem = pIO;
|
||||
|
||||
data->pImporter = new Importer();
|
||||
data->pImporter->SetIOHandler(data->pIOSystem);
|
||||
data->pImporter = new Importer();
|
||||
data->pImporter->SetIOHandler(data->pIOSystem);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BatchLoader::~BatchLoader()
|
||||
{
|
||||
// delete all scenes wthat have not been polled by the user
|
||||
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
// delete all scenes wthat have not been polled by the user
|
||||
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
|
||||
delete (*it).scene;
|
||||
}
|
||||
data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */
|
||||
delete data->pImporter;
|
||||
delete data;
|
||||
delete (*it).scene;
|
||||
}
|
||||
data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */
|
||||
delete data->pImporter;
|
||||
delete data;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int BatchLoader::AddLoadRequest (const std::string& file,
|
||||
unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
|
||||
unsigned int BatchLoader::AddLoadRequest (const std::string& file,
|
||||
unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
|
||||
{
|
||||
ai_assert(!file.empty());
|
||||
ai_assert(!file.empty());
|
||||
|
||||
// check whether we have this loading request already
|
||||
std::list<LoadRequest>::iterator it;
|
||||
for (it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
// check whether we have this loading request already
|
||||
std::list<LoadRequest>::iterator it;
|
||||
for (it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
|
||||
// Call IOSystem's path comparison function here
|
||||
if (data->pIOSystem->ComparePaths((*it).file,file)) {
|
||||
// Call IOSystem's path comparison function here
|
||||
if (data->pIOSystem->ComparePaths((*it).file,file)) {
|
||||
|
||||
if (map) {
|
||||
if (!((*it).map == *map))
|
||||
continue;
|
||||
}
|
||||
else if (!(*it).map.empty())
|
||||
continue;
|
||||
if (map) {
|
||||
if (!((*it).map == *map))
|
||||
continue;
|
||||
}
|
||||
else if (!(*it).map.empty())
|
||||
continue;
|
||||
|
||||
(*it).refCnt++;
|
||||
return (*it).id;
|
||||
}
|
||||
}
|
||||
(*it).refCnt++;
|
||||
return (*it).id;
|
||||
}
|
||||
}
|
||||
|
||||
// no, we don't have it. So add it to the queue ...
|
||||
data->requests.push_back(LoadRequest(file,steps,map,data->next_id));
|
||||
return data->next_id++;
|
||||
// no, we don't have it. So add it to the queue ...
|
||||
data->requests.push_back(LoadRequest(file,steps,map,data->next_id));
|
||||
return data->next_id++;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiScene* BatchLoader::GetImport (unsigned int which)
|
||||
aiScene* BatchLoader::GetImport (unsigned int which)
|
||||
{
|
||||
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
|
||||
if ((*it).id == which && (*it).loaded) {
|
||||
if ((*it).id == which && (*it).loaded) {
|
||||
|
||||
aiScene* sc = (*it).scene;
|
||||
if (!(--(*it).refCnt)) {
|
||||
data->requests.erase(it);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
aiScene* sc = (*it).scene;
|
||||
if (!(--(*it).refCnt)) {
|
||||
data->requests.erase(it);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BatchLoader::LoadAll()
|
||||
{
|
||||
// no threaded implementation for the moment
|
||||
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
// force validation in debug builds
|
||||
unsigned int pp = (*it).flags;
|
||||
// no threaded implementation for the moment
|
||||
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
||||
// force validation in debug builds
|
||||
unsigned int pp = (*it).flags;
|
||||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
pp |= aiProcess_ValidateDataStructure;
|
||||
pp |= aiProcess_ValidateDataStructure;
|
||||
#endif
|
||||
// setup config properties if necessary
|
||||
ImporterPimpl* pimpl = data->pImporter->Pimpl();
|
||||
pimpl->mFloatProperties = (*it).map.floats;
|
||||
pimpl->mIntProperties = (*it).map.ints;
|
||||
pimpl->mStringProperties = (*it).map.strings;
|
||||
pimpl->mMatrixProperties = (*it).map.matrices;
|
||||
// setup config properties if necessary
|
||||
ImporterPimpl* pimpl = data->pImporter->Pimpl();
|
||||
pimpl->mFloatProperties = (*it).map.floats;
|
||||
pimpl->mIntProperties = (*it).map.ints;
|
||||
pimpl->mStringProperties = (*it).map.strings;
|
||||
pimpl->mMatrixProperties = (*it).map.matrices;
|
||||
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
|
||||
DefaultLogger::get()->info("File: " + (*it).file);
|
||||
}
|
||||
data->pImporter->ReadFile((*it).file,pp);
|
||||
(*it).scene = data->pImporter->GetOrphanedScene();
|
||||
(*it).loaded = true;
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
|
||||
DefaultLogger::get()->info("File: " + (*it).file);
|
||||
}
|
||||
data->pImporter->ReadFile((*it).file,pp);
|
||||
(*it).scene = data->pImporter->GetOrphanedScene();
|
||||
(*it).loaded = true;
|
||||
|
||||
DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
|
||||
}
|
||||
DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiScene;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
class Importer;
|
||||
class IOSystem;
|
||||
|
@ -64,32 +64,32 @@ class IOStream;
|
|||
|
||||
// utility to do char4 to uint32 in a portable manner
|
||||
#define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
|
||||
(string[1] << 16) + (string[2] << 8) + string[3]))
|
||||
(string[1] << 16) + (string[2] << 8) + string[3]))
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct ScopeGuard
|
||||
{
|
||||
ScopeGuard(T* obj) : obj(obj), mdismiss() {}
|
||||
~ScopeGuard () throw() {
|
||||
if (!mdismiss) {
|
||||
delete obj;
|
||||
}
|
||||
obj = NULL;
|
||||
}
|
||||
ScopeGuard(T* obj) : obj(obj), mdismiss() {}
|
||||
~ScopeGuard () throw() {
|
||||
if (!mdismiss) {
|
||||
delete obj;
|
||||
}
|
||||
obj = NULL;
|
||||
}
|
||||
|
||||
T* dismiss() {
|
||||
mdismiss=true;
|
||||
return obj;
|
||||
}
|
||||
T* dismiss() {
|
||||
mdismiss=true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
operator T*() {
|
||||
return obj;
|
||||
}
|
||||
operator T*() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
T* operator -> () {
|
||||
return obj;
|
||||
}
|
||||
T* operator -> () {
|
||||
return obj;
|
||||
}
|
||||
|
||||
private:
|
||||
// no copying allowed.
|
||||
|
@ -97,8 +97,8 @@ private:
|
|||
ScopeGuard( const ScopeGuard & );
|
||||
ScopeGuard &operator = ( const ScopeGuard & );
|
||||
|
||||
T* obj;
|
||||
bool mdismiss;
|
||||
T* obj;
|
||||
bool mdismiss;
|
||||
};
|
||||
|
||||
|
||||
|
@ -115,257 +115,257 @@ private:
|
|||
*/
|
||||
class ASSIMP_API BaseImporter
|
||||
{
|
||||
friend class Importer;
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor to be privately used by #Importer */
|
||||
BaseImporter();
|
||||
/** Constructor to be privately used by #Importer */
|
||||
BaseImporter();
|
||||
|
||||
/** Destructor, private as well */
|
||||
virtual ~BaseImporter();
|
||||
/** Destructor, private as well */
|
||||
virtual ~BaseImporter();
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
*
|
||||
* The implementation should be as quick as possible. A check for
|
||||
* the file extension is enough. If no suitable loader is found with
|
||||
* this strategy, CanRead() is called again, the 'checkSig' parameter
|
||||
* set to true this time. Now the implementation is expected to
|
||||
* perform a full check of the file structure, possibly searching the
|
||||
* first bytes of the file for magic identifiers or keywords.
|
||||
*
|
||||
* @param pFile Path and file name of the file to be examined.
|
||||
* @param pIOHandler The IO handler to use for accessing any file.
|
||||
* @param checkSig Set to true if this method is called a second time.
|
||||
* This time, the implementation may take more time to examine the
|
||||
* contents of the file to be loaded for magic bytes, keywords, etc
|
||||
* to be able to load files with unknown/not existent file extensions.
|
||||
* @return true if the class can read this file, false if not.
|
||||
*/
|
||||
virtual bool CanRead(
|
||||
const std::string& pFile,
|
||||
IOSystem* pIOHandler,
|
||||
bool checkSig
|
||||
) const = 0;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
*
|
||||
* The implementation should be as quick as possible. A check for
|
||||
* the file extension is enough. If no suitable loader is found with
|
||||
* this strategy, CanRead() is called again, the 'checkSig' parameter
|
||||
* set to true this time. Now the implementation is expected to
|
||||
* perform a full check of the file structure, possibly searching the
|
||||
* first bytes of the file for magic identifiers or keywords.
|
||||
*
|
||||
* @param pFile Path and file name of the file to be examined.
|
||||
* @param pIOHandler The IO handler to use for accessing any file.
|
||||
* @param checkSig Set to true if this method is called a second time.
|
||||
* This time, the implementation may take more time to examine the
|
||||
* contents of the file to be loaded for magic bytes, keywords, etc
|
||||
* to be able to load files with unknown/not existent file extensions.
|
||||
* @return true if the class can read this file, false if not.
|
||||
*/
|
||||
virtual bool CanRead(
|
||||
const std::string& pFile,
|
||||
IOSystem* pIOHandler,
|
||||
bool checkSig
|
||||
) const = 0;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file and returns the imported data.
|
||||
* If the import succeeds, ownership of the data is transferred to
|
||||
* the caller. If the import fails, NULL is returned. The function
|
||||
* takes care that any partially constructed data is destroyed
|
||||
* beforehand.
|
||||
*
|
||||
* @param pImp #Importer object hosting this loader.
|
||||
* @param pFile Path of the file to be imported.
|
||||
* @param pIOHandler IO-Handler used to open this and possible other files.
|
||||
* @return The imported data or NULL if failed. If it failed a
|
||||
* human-readable error description can be retrieved by calling
|
||||
* GetErrorText()
|
||||
*
|
||||
* @note This function is not intended to be overridden. Implement
|
||||
* InternReadFile() to do the import. If an exception is thrown somewhere
|
||||
* in InternReadFile(), this function will catch it and transform it into
|
||||
* a suitable response to the caller.
|
||||
*/
|
||||
aiScene* ReadFile(
|
||||
const Importer* pImp,
|
||||
const std::string& pFile,
|
||||
IOSystem* pIOHandler
|
||||
);
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file and returns the imported data.
|
||||
* If the import succeeds, ownership of the data is transferred to
|
||||
* the caller. If the import fails, NULL is returned. The function
|
||||
* takes care that any partially constructed data is destroyed
|
||||
* beforehand.
|
||||
*
|
||||
* @param pImp #Importer object hosting this loader.
|
||||
* @param pFile Path of the file to be imported.
|
||||
* @param pIOHandler IO-Handler used to open this and possible other files.
|
||||
* @return The imported data or NULL if failed. If it failed a
|
||||
* human-readable error description can be retrieved by calling
|
||||
* GetErrorText()
|
||||
*
|
||||
* @note This function is not intended to be overridden. Implement
|
||||
* InternReadFile() to do the import. If an exception is thrown somewhere
|
||||
* in InternReadFile(), this function will catch it and transform it into
|
||||
* a suitable response to the caller.
|
||||
*/
|
||||
aiScene* ReadFile(
|
||||
const Importer* pImp,
|
||||
const std::string& pFile,
|
||||
IOSystem* pIOHandler
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the error description of the last error that occured.
|
||||
* @return A description of the last error that occured. An empty
|
||||
* string if there was no error.
|
||||
*/
|
||||
const std::string& GetErrorText() const {
|
||||
return mErrorText;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the error description of the last error that occured.
|
||||
* @return A description of the last error that occured. An empty
|
||||
* string if there was no error.
|
||||
*/
|
||||
const std::string& GetErrorText() const {
|
||||
return mErrorText;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
* @param pImp Importer instance
|
||||
*/
|
||||
virtual void SetupProperties(
|
||||
const Importer* pImp
|
||||
);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
* @param pImp Importer instance
|
||||
*/
|
||||
virtual void SetupProperties(
|
||||
const Importer* pImp
|
||||
);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called by #Importer::GetImporterInfo to get a description of
|
||||
* some loader features. Importers must provide this information. */
|
||||
virtual const aiImporterDesc* GetInfo() const = 0;
|
||||
// -------------------------------------------------------------------
|
||||
/** Called by #Importer::GetImporterInfo to get a description of
|
||||
* some loader features. Importers must provide this information. */
|
||||
virtual const aiImporterDesc* GetInfo() const = 0;
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called by #Importer::GetExtensionList for each loaded importer.
|
||||
* Take the extension list contained in the structure returned by
|
||||
* #GetInfo and insert all file extensions into the given set.
|
||||
* @param extension set to collect file extensions in*/
|
||||
void GetExtensionList(std::set<std::string>& extensions);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called by #Importer::GetExtensionList for each loaded importer.
|
||||
* Take the extension list contained in the structure returned by
|
||||
* #GetInfo and insert all file extensions into the given set.
|
||||
* @param extension set to collect file extensions in*/
|
||||
void GetExtensionList(std::set<std::string>& extensions);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure. The
|
||||
* function is expected to throw an ImportErrorException if there is
|
||||
* an error. If it terminates normally, the data in aiScene is
|
||||
* expected to be correct. Override this function to implement the
|
||||
* actual importing.
|
||||
* <br>
|
||||
* The output scene must meet the following requirements:<br>
|
||||
* <ul>
|
||||
* <li>At least a root node must be there, even if its only purpose
|
||||
* is to reference one mesh.</li>
|
||||
* <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives
|
||||
* in the mesh are determined automatically in this case.</li>
|
||||
* <li>the vertex data is stored in a pseudo-indexed "verbose" format.
|
||||
* In fact this means that every vertex that is referenced by
|
||||
* a face is unique. Or the other way round: a vertex index may
|
||||
* not occur twice in a single aiMesh.</li>
|
||||
* <li>aiAnimation::mDuration may be -1. Assimp determines the length
|
||||
* of the animation automatically in this case as the length of
|
||||
* the longest animation channel.</li>
|
||||
* <li>aiMesh::mBitangents may be NULL if tangents and normals are
|
||||
* given. In this case bitangents are computed as the cross product
|
||||
* between normal and tangent.</li>
|
||||
* <li>There needn't be a material. If none is there a default material
|
||||
* is generated. However, it is recommended practice for loaders
|
||||
* to generate a default material for yourself that matches the
|
||||
* default material setting for the file format better than Assimp's
|
||||
* generic default material. Note that default materials *should*
|
||||
* be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded
|
||||
* or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy)
|
||||
* texture. </li>
|
||||
* </ul>
|
||||
* If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul>
|
||||
* <li> at least one mesh must be there</li>
|
||||
* <li> there may be no meshes with 0 vertices or faces</li>
|
||||
* </ul>
|
||||
* This won't be checked (except by the validation step): Assimp will
|
||||
* crash if one of the conditions is not met!
|
||||
*
|
||||
* @param pFile Path of the file to be imported.
|
||||
* @param pScene The scene object to hold the imported data.
|
||||
* NULL is not a valid parameter.
|
||||
* @param pIOHandler The IO handler to use for any file access.
|
||||
* NULL is not a valid parameter. */
|
||||
virtual void InternReadFile(
|
||||
const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler
|
||||
) = 0;
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure. The
|
||||
* function is expected to throw an ImportErrorException if there is
|
||||
* an error. If it terminates normally, the data in aiScene is
|
||||
* expected to be correct. Override this function to implement the
|
||||
* actual importing.
|
||||
* <br>
|
||||
* The output scene must meet the following requirements:<br>
|
||||
* <ul>
|
||||
* <li>At least a root node must be there, even if its only purpose
|
||||
* is to reference one mesh.</li>
|
||||
* <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives
|
||||
* in the mesh are determined automatically in this case.</li>
|
||||
* <li>the vertex data is stored in a pseudo-indexed "verbose" format.
|
||||
* In fact this means that every vertex that is referenced by
|
||||
* a face is unique. Or the other way round: a vertex index may
|
||||
* not occur twice in a single aiMesh.</li>
|
||||
* <li>aiAnimation::mDuration may be -1. Assimp determines the length
|
||||
* of the animation automatically in this case as the length of
|
||||
* the longest animation channel.</li>
|
||||
* <li>aiMesh::mBitangents may be NULL if tangents and normals are
|
||||
* given. In this case bitangents are computed as the cross product
|
||||
* between normal and tangent.</li>
|
||||
* <li>There needn't be a material. If none is there a default material
|
||||
* is generated. However, it is recommended practice for loaders
|
||||
* to generate a default material for yourself that matches the
|
||||
* default material setting for the file format better than Assimp's
|
||||
* generic default material. Note that default materials *should*
|
||||
* be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded
|
||||
* or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy)
|
||||
* texture. </li>
|
||||
* </ul>
|
||||
* If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul>
|
||||
* <li> at least one mesh must be there</li>
|
||||
* <li> there may be no meshes with 0 vertices or faces</li>
|
||||
* </ul>
|
||||
* This won't be checked (except by the validation step): Assimp will
|
||||
* crash if one of the conditions is not met!
|
||||
*
|
||||
* @param pFile Path of the file to be imported.
|
||||
* @param pScene The scene object to hold the imported data.
|
||||
* NULL is not a valid parameter.
|
||||
* @param pIOHandler The IO handler to use for any file access.
|
||||
* NULL is not a valid parameter. */
|
||||
virtual void InternReadFile(
|
||||
const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler
|
||||
) = 0;
|
||||
|
||||
public: // static utilities
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** A utility for CanRead().
|
||||
*
|
||||
* The function searches the header of a file for a specific token
|
||||
* and returns true if this token is found. This works for text
|
||||
* files only. There is a rudimentary handling of UNICODE files.
|
||||
* The comparison is case independent.
|
||||
*
|
||||
* @param pIOSystem IO System to work with
|
||||
* @param file File name of the file
|
||||
* @param tokens List of tokens to search for
|
||||
* @param numTokens Size of the token array
|
||||
* @param searchBytes Number of bytes to be searched for the tokens.
|
||||
*/
|
||||
static bool SearchFileHeaderForToken(
|
||||
IOSystem* pIOSystem,
|
||||
const std::string& file,
|
||||
const char** tokens,
|
||||
unsigned int numTokens,
|
||||
unsigned int searchBytes = 200,
|
||||
bool tokensSol = false);
|
||||
// -------------------------------------------------------------------
|
||||
/** A utility for CanRead().
|
||||
*
|
||||
* The function searches the header of a file for a specific token
|
||||
* and returns true if this token is found. This works for text
|
||||
* files only. There is a rudimentary handling of UNICODE files.
|
||||
* The comparison is case independent.
|
||||
*
|
||||
* @param pIOSystem IO System to work with
|
||||
* @param file File name of the file
|
||||
* @param tokens List of tokens to search for
|
||||
* @param numTokens Size of the token array
|
||||
* @param searchBytes Number of bytes to be searched for the tokens.
|
||||
*/
|
||||
static bool SearchFileHeaderForToken(
|
||||
IOSystem* pIOSystem,
|
||||
const std::string& file,
|
||||
const char** tokens,
|
||||
unsigned int numTokens,
|
||||
unsigned int searchBytes = 200,
|
||||
bool tokensSol = false);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Check whether a file has a specific file extension
|
||||
* @param pFile Input file
|
||||
* @param ext0 Extension to check for. Lowercase characters only, no dot!
|
||||
* @param ext1 Optional second extension
|
||||
* @param ext2 Optional third extension
|
||||
* @note Case-insensitive
|
||||
*/
|
||||
static bool SimpleExtensionCheck (
|
||||
const std::string& pFile,
|
||||
const char* ext0,
|
||||
const char* ext1 = NULL,
|
||||
const char* ext2 = NULL);
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Check whether a file has a specific file extension
|
||||
* @param pFile Input file
|
||||
* @param ext0 Extension to check for. Lowercase characters only, no dot!
|
||||
* @param ext1 Optional second extension
|
||||
* @param ext2 Optional third extension
|
||||
* @note Case-insensitive
|
||||
*/
|
||||
static bool SimpleExtensionCheck (
|
||||
const std::string& pFile,
|
||||
const char* ext0,
|
||||
const char* ext1 = NULL,
|
||||
const char* ext2 = NULL);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Extract file extension from a string
|
||||
* @param pFile Input file
|
||||
* @return Extension without trailing dot, all lowercase
|
||||
*/
|
||||
static std::string GetExtension (
|
||||
const std::string& pFile);
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Extract file extension from a string
|
||||
* @param pFile Input file
|
||||
* @return Extension without trailing dot, all lowercase
|
||||
*/
|
||||
static std::string GetExtension (
|
||||
const std::string& pFile);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Check whether a file starts with one or more magic tokens
|
||||
* @param pFile Input file
|
||||
* @param pIOHandler IO system to be used
|
||||
* @param magic n magic tokens
|
||||
* @params num Size of magic
|
||||
* @param offset Offset from file start where tokens are located
|
||||
* @param Size of one token, in bytes. Maximally 16 bytes.
|
||||
* @return true if one of the given tokens was found
|
||||
*
|
||||
* @note For convinence, the check is also performed for the
|
||||
* byte-swapped variant of all tokens (big endian). Only for
|
||||
* tokens of size 2,4.
|
||||
*/
|
||||
static bool CheckMagicToken(
|
||||
IOSystem* pIOHandler,
|
||||
const std::string& pFile,
|
||||
const void* magic,
|
||||
unsigned int num,
|
||||
unsigned int offset = 0,
|
||||
unsigned int size = 4);
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Check whether a file starts with one or more magic tokens
|
||||
* @param pFile Input file
|
||||
* @param pIOHandler IO system to be used
|
||||
* @param magic n magic tokens
|
||||
* @params num Size of magic
|
||||
* @param offset Offset from file start where tokens are located
|
||||
* @param Size of one token, in bytes. Maximally 16 bytes.
|
||||
* @return true if one of the given tokens was found
|
||||
*
|
||||
* @note For convinence, the check is also performed for the
|
||||
* byte-swapped variant of all tokens (big endian). Only for
|
||||
* tokens of size 2,4.
|
||||
*/
|
||||
static bool CheckMagicToken(
|
||||
IOSystem* pIOHandler,
|
||||
const std::string& pFile,
|
||||
const void* magic,
|
||||
unsigned int num,
|
||||
unsigned int offset = 0,
|
||||
unsigned int size = 4);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** An utility for all text file loaders. It converts a file to our
|
||||
* UTF8 character set. Errors are reported, but ignored.
|
||||
*
|
||||
* @param data File buffer to be converted to UTF8 data. The buffer
|
||||
* is resized as appropriate. */
|
||||
static void ConvertToUTF8(
|
||||
std::vector<char>& data);
|
||||
// -------------------------------------------------------------------
|
||||
/** An utility for all text file loaders. It converts a file to our
|
||||
* UTF8 character set. Errors are reported, but ignored.
|
||||
*
|
||||
* @param data File buffer to be converted to UTF8 data. The buffer
|
||||
* is resized as appropriate. */
|
||||
static void ConvertToUTF8(
|
||||
std::vector<char>& data);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** An utility for all text file loaders. It converts a file from our
|
||||
* UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
|
||||
*
|
||||
* @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
|
||||
* is resized as appropriate. */
|
||||
static void ConvertUTF8toISO8859_1(
|
||||
std::string& data);
|
||||
// -------------------------------------------------------------------
|
||||
/** An utility for all text file loaders. It converts a file from our
|
||||
* UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
|
||||
*
|
||||
* @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
|
||||
* is resized as appropriate. */
|
||||
static void ConvertUTF8toISO8859_1(
|
||||
std::string& data);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Utility for text file loaders which copies the contents of the
|
||||
* file into a memory buffer and converts it to our UTF8
|
||||
* representation.
|
||||
* @param stream Stream to read from.
|
||||
* @param data Output buffer to be resized and filled with the
|
||||
* converted text file data. The buffer is terminated with
|
||||
* a binary 0. */
|
||||
static void TextFileToBuffer(
|
||||
IOStream* stream,
|
||||
std::vector<char>& data);
|
||||
// -------------------------------------------------------------------
|
||||
/** Utility for text file loaders which copies the contents of the
|
||||
* file into a memory buffer and converts it to our UTF8
|
||||
* representation.
|
||||
* @param stream Stream to read from.
|
||||
* @param data Output buffer to be resized and filled with the
|
||||
* converted text file data. The buffer is terminated with
|
||||
* a binary 0. */
|
||||
static void TextFileToBuffer(
|
||||
IOStream* stream,
|
||||
std::vector<char>& data);
|
||||
|
||||
protected:
|
||||
|
||||
/** Error description in case there was one. */
|
||||
std::string mErrorText;
|
||||
/** Error description in case there was one. */
|
||||
std::string mErrorText;
|
||||
|
||||
/** Currently set progress handler */
|
||||
ProgressHandler* progress;
|
||||
/** Currently set progress handler */
|
||||
ProgressHandler* progress;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -61,45 +61,45 @@ BaseProcess::BaseProcess()
|
|||
// Destructor, private as well
|
||||
BaseProcess::~BaseProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseProcess::ExecuteOnScene( Importer* pImp)
|
||||
{
|
||||
ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene);
|
||||
ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene);
|
||||
|
||||
progress = pImp->GetProgressHandler();
|
||||
ai_assert(progress);
|
||||
progress = pImp->GetProgressHandler();
|
||||
ai_assert(progress);
|
||||
|
||||
SetupProperties( pImp );
|
||||
SetupProperties( pImp );
|
||||
|
||||
// catch exceptions thrown inside the PostProcess-Step
|
||||
try
|
||||
{
|
||||
Execute(pImp->Pimpl()->mScene);
|
||||
// catch exceptions thrown inside the PostProcess-Step
|
||||
try
|
||||
{
|
||||
Execute(pImp->Pimpl()->mScene);
|
||||
|
||||
} catch( const std::exception& err ) {
|
||||
} catch( const std::exception& err ) {
|
||||
|
||||
// extract error description
|
||||
pImp->Pimpl()->mErrorString = err.what();
|
||||
DefaultLogger::get()->error(pImp->Pimpl()->mErrorString);
|
||||
// extract error description
|
||||
pImp->Pimpl()->mErrorString = err.what();
|
||||
DefaultLogger::get()->error(pImp->Pimpl()->mErrorString);
|
||||
|
||||
// and kill the partially imported data
|
||||
delete pImp->Pimpl()->mScene;
|
||||
pImp->Pimpl()->mScene = NULL;
|
||||
}
|
||||
// and kill the partially imported data
|
||||
delete pImp->Pimpl()->mScene;
|
||||
pImp->Pimpl()->mScene = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseProcess::SetupProperties(const Importer* /*pImp*/)
|
||||
{
|
||||
// the default implementation does nothing
|
||||
// the default implementation does nothing
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool BaseProcess::RequireVerboseFormat() const
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiScene;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
class Importer;
|
||||
|
||||
|
@ -64,121 +64,121 @@ class SharedPostProcessInfo
|
|||
{
|
||||
public:
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual ~Base()
|
||||
{}
|
||||
};
|
||||
struct Base
|
||||
{
|
||||
virtual ~Base()
|
||||
{}
|
||||
};
|
||||
|
||||
//! Represents data that is allocated on the heap, thus needs to be deleted
|
||||
template <typename T>
|
||||
struct THeapData : public Base
|
||||
{
|
||||
THeapData(T* in)
|
||||
: data (in)
|
||||
{}
|
||||
//! Represents data that is allocated on the heap, thus needs to be deleted
|
||||
template <typename T>
|
||||
struct THeapData : public Base
|
||||
{
|
||||
THeapData(T* in)
|
||||
: data (in)
|
||||
{}
|
||||
|
||||
~THeapData()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
T* data;
|
||||
};
|
||||
~THeapData()
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
T* data;
|
||||
};
|
||||
|
||||
//! Represents static, by-value data not allocated on the heap
|
||||
template <typename T>
|
||||
struct TStaticData : public Base
|
||||
{
|
||||
TStaticData(T in)
|
||||
: data (in)
|
||||
{}
|
||||
//! Represents static, by-value data not allocated on the heap
|
||||
template <typename T>
|
||||
struct TStaticData : public Base
|
||||
{
|
||||
TStaticData(T in)
|
||||
: data (in)
|
||||
{}
|
||||
|
||||
~TStaticData()
|
||||
{}
|
||||
~TStaticData()
|
||||
{}
|
||||
|
||||
T data;
|
||||
};
|
||||
T data;
|
||||
};
|
||||
|
||||
// some typedefs for cleaner code
|
||||
typedef unsigned int KeyType;
|
||||
typedef std::map<KeyType, Base*> PropertyMap;
|
||||
// some typedefs for cleaner code
|
||||
typedef unsigned int KeyType;
|
||||
typedef std::map<KeyType, Base*> PropertyMap;
|
||||
|
||||
public:
|
||||
|
||||
//! Destructor
|
||||
~SharedPostProcessInfo()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
//! Destructor
|
||||
~SharedPostProcessInfo()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
//! Remove all stored properties from the table
|
||||
void Clean()
|
||||
{
|
||||
// invoke the virtual destructor for all stored properties
|
||||
for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
delete (*it).second;
|
||||
}
|
||||
pmap.clear();
|
||||
}
|
||||
//! Remove all stored properties from the table
|
||||
void Clean()
|
||||
{
|
||||
// invoke the virtual destructor for all stored properties
|
||||
for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
delete (*it).second;
|
||||
}
|
||||
pmap.clear();
|
||||
}
|
||||
|
||||
//! Add a heap property to the list
|
||||
template <typename T>
|
||||
void AddProperty( const char* name, T* in ){
|
||||
AddProperty(name,(Base*)new THeapData<T>(in));
|
||||
}
|
||||
//! Add a heap property to the list
|
||||
template <typename T>
|
||||
void AddProperty( const char* name, T* in ){
|
||||
AddProperty(name,(Base*)new THeapData<T>(in));
|
||||
}
|
||||
|
||||
//! Add a static by-value property to the list
|
||||
template <typename T>
|
||||
void AddProperty( const char* name, T in ){
|
||||
AddProperty(name,(Base*)new TStaticData<T>(in));
|
||||
}
|
||||
//! Add a static by-value property to the list
|
||||
template <typename T>
|
||||
void AddProperty( const char* name, T in ){
|
||||
AddProperty(name,(Base*)new TStaticData<T>(in));
|
||||
}
|
||||
|
||||
|
||||
//! Get a heap property
|
||||
template <typename T>
|
||||
bool GetProperty( const char* name, T*& out ) const
|
||||
{
|
||||
THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
|
||||
if(!t)
|
||||
{
|
||||
out = NULL;
|
||||
return false;
|
||||
}
|
||||
out = t->data;
|
||||
return true;
|
||||
}
|
||||
//! Get a heap property
|
||||
template <typename T>
|
||||
bool GetProperty( const char* name, T*& out ) const
|
||||
{
|
||||
THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name);
|
||||
if(!t)
|
||||
{
|
||||
out = NULL;
|
||||
return false;
|
||||
}
|
||||
out = t->data;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Get a static, by-value property
|
||||
template <typename T>
|
||||
bool GetProperty( const char* name, T& out ) const
|
||||
{
|
||||
TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
|
||||
if(!t)return false;
|
||||
out = t->data;
|
||||
return true;
|
||||
}
|
||||
//! Get a static, by-value property
|
||||
template <typename T>
|
||||
bool GetProperty( const char* name, T& out ) const
|
||||
{
|
||||
TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name);
|
||||
if(!t)return false;
|
||||
out = t->data;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Remove a property of a specific type
|
||||
void RemoveProperty( const char* name) {
|
||||
SetGenericPropertyPtr<Base>(pmap,name,NULL);
|
||||
}
|
||||
//! Remove a property of a specific type
|
||||
void RemoveProperty( const char* name) {
|
||||
SetGenericPropertyPtr<Base>(pmap,name,NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void AddProperty( const char* name, Base* data) {
|
||||
SetGenericPropertyPtr<Base>(pmap,name,data);
|
||||
}
|
||||
void AddProperty( const char* name, Base* data) {
|
||||
SetGenericPropertyPtr<Base>(pmap,name,data);
|
||||
}
|
||||
|
||||
Base* GetPropertyInternal( const char* name) const {
|
||||
return GetGenericProperty<Base*>(pmap,name,NULL);
|
||||
}
|
||||
Base* GetPropertyInternal( const char* name) const {
|
||||
return GetGenericProperty<Base*>(pmap,name,NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Map of all stored properties
|
||||
PropertyMap pmap;
|
||||
//! Map of all stored properties
|
||||
PropertyMap pmap;
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
@ -190,10 +190,10 @@ private:
|
|||
*/
|
||||
struct PPDependencyTable
|
||||
{
|
||||
unsigned int execute_me_before_these;
|
||||
unsigned int execute_me_after_these;
|
||||
unsigned int only_if_these_are_not_specified;
|
||||
unsigned int mutually_exclusive_with;
|
||||
unsigned int execute_me_before_these;
|
||||
unsigned int execute_me_after_these;
|
||||
unsigned int only_if_these_are_not_specified;
|
||||
unsigned int mutually_exclusive_with;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -213,79 +213,79 @@ private:
|
|||
*/
|
||||
class ASSIMP_API_WINONLY BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor to be privately used by Importer */
|
||||
BaseProcess();
|
||||
/** Constructor to be privately used by Importer */
|
||||
BaseProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
virtual ~BaseProcess();
|
||||
/** Destructor, private as well */
|
||||
virtual ~BaseProcess();
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with. A
|
||||
* bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
virtual bool IsActive( unsigned int pFlags) const = 0;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with. A
|
||||
* bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
virtual bool IsActive( unsigned int pFlags) const = 0;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Check whether this step expects its input vertex data to be
|
||||
* in verbose format. */
|
||||
virtual bool RequireVerboseFormat() const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Check whether this step expects its input vertex data to be
|
||||
* in verbose format. */
|
||||
virtual bool RequireVerboseFormat() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* The function deletes the scene if the postprocess step fails (
|
||||
* the object pointer will be set to NULL).
|
||||
* @param pImp Importer instance (pImp->mScene must be valid)
|
||||
*/
|
||||
void ExecuteOnScene( Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* The function deletes the scene if the postprocess step fails (
|
||||
* the object pointer will be set to NULL).
|
||||
* @param pImp Importer instance (pImp->mScene must be valid)
|
||||
*/
|
||||
void ExecuteOnScene( Importer* pImp);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
virtual void SetupProperties(const Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
virtual void SetupProperties(const Importer* pImp);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* A process should throw an ImportErrorException* if it fails.
|
||||
* This method must be implemented by deriving classes.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
virtual void Execute( aiScene* pScene) = 0;
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* A process should throw an ImportErrorException* if it fails.
|
||||
* This method must be implemented by deriving classes.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
virtual void Execute( aiScene* pScene) = 0;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Assign a new SharedPostProcessInfo to the step. This object
|
||||
* allows multiple postprocess steps to share data.
|
||||
* @param sh May be NULL
|
||||
*/
|
||||
inline void SetSharedData(SharedPostProcessInfo* sh) {
|
||||
shared = sh;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
/** Assign a new SharedPostProcessInfo to the step. This object
|
||||
* allows multiple postprocess steps to share data.
|
||||
* @param sh May be NULL
|
||||
*/
|
||||
inline void SetSharedData(SharedPostProcessInfo* sh) {
|
||||
shared = sh;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the shared data that is assigned to the step.
|
||||
*/
|
||||
inline SharedPostProcessInfo* GetSharedData() {
|
||||
return shared;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the shared data that is assigned to the step.
|
||||
*/
|
||||
inline SharedPostProcessInfo* GetSharedData() {
|
||||
return shared;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/** See the doc of #SharedPostProcessInfo for more details */
|
||||
SharedPostProcessInfo* shared;
|
||||
/** See the doc of #SharedPostProcessInfo for more details */
|
||||
SharedPostProcessInfo* shared;
|
||||
|
||||
/** Currently active progress handler */
|
||||
ProgressHandler* progress;
|
||||
/** Currently active progress handler */
|
||||
ProgressHandler* progress;
|
||||
};
|
||||
|
||||
|
||||
|
|
144
code/Bitmap.cpp
144
code/Bitmap.cpp
|
@ -53,95 +53,95 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp {
|
||||
|
||||
void Bitmap::Save(aiTexture* texture, IOStream* file) {
|
||||
if(file != NULL) {
|
||||
Header header;
|
||||
DIB dib;
|
||||
void Bitmap::Save(aiTexture* texture, IOStream* file) {
|
||||
if(file != NULL) {
|
||||
Header header;
|
||||
DIB dib;
|
||||
|
||||
dib.size = DIB::dib_size;
|
||||
dib.width = texture->mWidth;
|
||||
dib.height = texture->mHeight;
|
||||
dib.planes = 1;
|
||||
dib.bits_per_pixel = 8 * mBytesPerPixel;
|
||||
dib.compression = 0;
|
||||
dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
|
||||
dib.x_resolution = 0;
|
||||
dib.y_resolution = 0;
|
||||
dib.nb_colors = 0;
|
||||
dib.nb_important_colors = 0;
|
||||
dib.size = DIB::dib_size;
|
||||
dib.width = texture->mWidth;
|
||||
dib.height = texture->mHeight;
|
||||
dib.planes = 1;
|
||||
dib.bits_per_pixel = 8 * mBytesPerPixel;
|
||||
dib.compression = 0;
|
||||
dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
|
||||
dib.x_resolution = 0;
|
||||
dib.y_resolution = 0;
|
||||
dib.nb_colors = 0;
|
||||
dib.nb_important_colors = 0;
|
||||
|
||||
header.type = 0x4D42; // 'BM'
|
||||
header.offset = Header::header_size + DIB::dib_size;
|
||||
header.size = header.offset + dib.image_size;
|
||||
header.reserved1 = 0;
|
||||
header.reserved2 = 0;
|
||||
header.type = 0x4D42; // 'BM'
|
||||
header.offset = Header::header_size + DIB::dib_size;
|
||||
header.size = header.offset + dib.image_size;
|
||||
header.reserved1 = 0;
|
||||
header.reserved2 = 0;
|
||||
|
||||
WriteHeader(header, file);
|
||||
WriteDIB(dib, file);
|
||||
WriteData(texture, file);
|
||||
}
|
||||
}
|
||||
WriteHeader(header, file);
|
||||
WriteDIB(dib, file);
|
||||
WriteData(texture, file);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::size_t Copy(uint8_t* data, T& field) {
|
||||
std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
|
||||
}
|
||||
template<typename T>
|
||||
inline std::size_t Copy(uint8_t* data, T& field) {
|
||||
std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
|
||||
}
|
||||
|
||||
void Bitmap::WriteHeader(Header& header, IOStream* file) {
|
||||
uint8_t data[Header::header_size];
|
||||
void Bitmap::WriteHeader(Header& header, IOStream* file) {
|
||||
uint8_t data[Header::header_size];
|
||||
|
||||
std::size_t offset = 0;
|
||||
std::size_t offset = 0;
|
||||
|
||||
offset += Copy(&data[offset], header.type);
|
||||
offset += Copy(&data[offset], header.size);
|
||||
offset += Copy(&data[offset], header.reserved1);
|
||||
offset += Copy(&data[offset], header.reserved2);
|
||||
offset += Copy(&data[offset], header.offset);
|
||||
offset += Copy(&data[offset], header.type);
|
||||
offset += Copy(&data[offset], header.size);
|
||||
offset += Copy(&data[offset], header.reserved1);
|
||||
offset += Copy(&data[offset], header.reserved2);
|
||||
offset += Copy(&data[offset], header.offset);
|
||||
|
||||
file->Write(data, Header::header_size, 1);
|
||||
}
|
||||
file->Write(data, Header::header_size, 1);
|
||||
}
|
||||
|
||||
void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
|
||||
uint8_t data[DIB::dib_size];
|
||||
void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
|
||||
uint8_t data[DIB::dib_size];
|
||||
|
||||
std::size_t offset = 0;
|
||||
std::size_t offset = 0;
|
||||
|
||||
offset += Copy(&data[offset], dib.size);
|
||||
offset += Copy(&data[offset], dib.width);
|
||||
offset += Copy(&data[offset], dib.height);
|
||||
offset += Copy(&data[offset], dib.planes);
|
||||
offset += Copy(&data[offset], dib.bits_per_pixel);
|
||||
offset += Copy(&data[offset], dib.compression);
|
||||
offset += Copy(&data[offset], dib.image_size);
|
||||
offset += Copy(&data[offset], dib.x_resolution);
|
||||
offset += Copy(&data[offset], dib.y_resolution);
|
||||
offset += Copy(&data[offset], dib.nb_colors);
|
||||
offset += Copy(&data[offset], dib.nb_important_colors);
|
||||
offset += Copy(&data[offset], dib.size);
|
||||
offset += Copy(&data[offset], dib.width);
|
||||
offset += Copy(&data[offset], dib.height);
|
||||
offset += Copy(&data[offset], dib.planes);
|
||||
offset += Copy(&data[offset], dib.bits_per_pixel);
|
||||
offset += Copy(&data[offset], dib.compression);
|
||||
offset += Copy(&data[offset], dib.image_size);
|
||||
offset += Copy(&data[offset], dib.x_resolution);
|
||||
offset += Copy(&data[offset], dib.y_resolution);
|
||||
offset += Copy(&data[offset], dib.nb_colors);
|
||||
offset += Copy(&data[offset], dib.nb_important_colors);
|
||||
|
||||
file->Write(data, DIB::dib_size, 1);
|
||||
}
|
||||
file->Write(data, DIB::dib_size, 1);
|
||||
}
|
||||
|
||||
void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
|
||||
static const std::size_t padding_offset = 4;
|
||||
static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
|
||||
void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
|
||||
static const std::size_t padding_offset = 4;
|
||||
static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
|
||||
|
||||
unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
|
||||
uint8_t pixel[mBytesPerPixel];
|
||||
unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
|
||||
uint8_t pixel[mBytesPerPixel];
|
||||
|
||||
for(std::size_t i = 0; i < texture->mHeight; ++i) {
|
||||
for(std::size_t j = 0; j < texture->mWidth; ++j) {
|
||||
const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
|
||||
for(std::size_t i = 0; i < texture->mHeight; ++i) {
|
||||
for(std::size_t j = 0; j < texture->mWidth; ++j) {
|
||||
const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
|
||||
|
||||
pixel[0] = texel.r;
|
||||
pixel[1] = texel.g;
|
||||
pixel[2] = texel.b;
|
||||
pixel[3] = texel.a;
|
||||
pixel[0] = texel.r;
|
||||
pixel[1] = texel.g;
|
||||
pixel[2] = texel.b;
|
||||
pixel[3] = texel.a;
|
||||
|
||||
file->Write(pixel, mBytesPerPixel, 1);
|
||||
}
|
||||
file->Write(pixel, mBytesPerPixel, 1);
|
||||
}
|
||||
|
||||
file->Write(padding_data, padding, 1);
|
||||
}
|
||||
}
|
||||
file->Write(padding_data, padding, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
100
code/Bitmap.h
100
code/Bitmap.h
|
@ -57,85 +57,85 @@ namespace Assimp {
|
|||
class IOStream;
|
||||
class Bitmap {
|
||||
|
||||
protected:
|
||||
protected:
|
||||
|
||||
struct Header {
|
||||
struct Header {
|
||||
|
||||
uint16_t type;
|
||||
uint16_t type;
|
||||
|
||||
uint32_t size;
|
||||
uint32_t size;
|
||||
|
||||
uint16_t reserved1;
|
||||
uint16_t reserved1;
|
||||
|
||||
uint16_t reserved2;
|
||||
uint16_t reserved2;
|
||||
|
||||
uint32_t offset;
|
||||
uint32_t offset;
|
||||
|
||||
// We define the struct size because sizeof(Header) might return a wrong result because of structure padding.
|
||||
// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
|
||||
static const std::size_t header_size =
|
||||
sizeof(uint16_t) + // type
|
||||
sizeof(uint32_t) + // size
|
||||
sizeof(uint16_t) + // reserved1
|
||||
sizeof(uint16_t) + // reserved2
|
||||
sizeof(uint32_t); // offset
|
||||
// We define the struct size because sizeof(Header) might return a wrong result because of structure padding.
|
||||
// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
|
||||
static const std::size_t header_size =
|
||||
sizeof(uint16_t) + // type
|
||||
sizeof(uint32_t) + // size
|
||||
sizeof(uint16_t) + // reserved1
|
||||
sizeof(uint16_t) + // reserved2
|
||||
sizeof(uint32_t); // offset
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
struct DIB {
|
||||
struct DIB {
|
||||
|
||||
uint32_t size;
|
||||
uint32_t size;
|
||||
|
||||
int32_t width;
|
||||
int32_t width;
|
||||
|
||||
int32_t height;
|
||||
int32_t height;
|
||||
|
||||
uint16_t planes;
|
||||
uint16_t planes;
|
||||
|
||||
uint16_t bits_per_pixel;
|
||||
uint16_t bits_per_pixel;
|
||||
|
||||
uint32_t compression;
|
||||
uint32_t compression;
|
||||
|
||||
uint32_t image_size;
|
||||
uint32_t image_size;
|
||||
|
||||
int32_t x_resolution;
|
||||
int32_t x_resolution;
|
||||
|
||||
int32_t y_resolution;
|
||||
int32_t y_resolution;
|
||||
|
||||
uint32_t nb_colors;
|
||||
uint32_t nb_colors;
|
||||
|
||||
uint32_t nb_important_colors;
|
||||
uint32_t nb_important_colors;
|
||||
|
||||
// We define the struct size because sizeof(DIB) might return a wrong result because of structure padding.
|
||||
// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
|
||||
static const std::size_t dib_size =
|
||||
sizeof(uint32_t) + // size
|
||||
sizeof(int32_t) + // width
|
||||
sizeof(int32_t) + // height
|
||||
sizeof(uint16_t) + // planes
|
||||
sizeof(uint16_t) + // bits_per_pixel
|
||||
sizeof(uint32_t) + // compression
|
||||
sizeof(uint32_t) + // image_size
|
||||
sizeof(int32_t) + // x_resolution
|
||||
sizeof(int32_t) + // y_resolution
|
||||
sizeof(uint32_t) + // nb_colors
|
||||
sizeof(uint32_t); // nb_important_colors
|
||||
// We define the struct size because sizeof(DIB) might return a wrong result because of structure padding.
|
||||
// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
|
||||
static const std::size_t dib_size =
|
||||
sizeof(uint32_t) + // size
|
||||
sizeof(int32_t) + // width
|
||||
sizeof(int32_t) + // height
|
||||
sizeof(uint16_t) + // planes
|
||||
sizeof(uint16_t) + // bits_per_pixel
|
||||
sizeof(uint32_t) + // compression
|
||||
sizeof(uint32_t) + // image_size
|
||||
sizeof(int32_t) + // x_resolution
|
||||
sizeof(int32_t) + // y_resolution
|
||||
sizeof(uint32_t) + // nb_colors
|
||||
sizeof(uint32_t); // nb_important_colors
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
static const std::size_t mBytesPerPixel = 4;
|
||||
static const std::size_t mBytesPerPixel = 4;
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
static void Save(aiTexture* texture, IOStream* file);
|
||||
static void Save(aiTexture* texture, IOStream* file);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
|
||||
static void WriteHeader(Header& header, IOStream* file);
|
||||
static void WriteHeader(Header& header, IOStream* file);
|
||||
|
||||
static void WriteDIB(DIB& dib, IOStream* file);
|
||||
static void WriteDIB(DIB& dib, IOStream* file);
|
||||
|
||||
static void WriteData(aiTexture* texture, IOStream* file);
|
||||
static void WriteData(aiTexture* texture, IOStream* file);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp
|
||||
{
|
||||
template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: ";
|
||||
template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: ";
|
||||
}
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -61,142 +61,142 @@ using namespace Assimp::Formatter;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
|
||||
BMesh( mesh ),
|
||||
triMesh( NULL )
|
||||
BMesh( mesh ),
|
||||
triMesh( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderBMeshConverter::~BlenderBMeshConverter( )
|
||||
{
|
||||
DestroyTriMesh( );
|
||||
DestroyTriMesh( );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool BlenderBMeshConverter::ContainsBMesh( ) const
|
||||
{
|
||||
// TODO - Should probably do some additional verification here
|
||||
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
|
||||
// TODO - Should probably do some additional verification here
|
||||
return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
|
||||
{
|
||||
AssertValidMesh( );
|
||||
AssertValidSizes( );
|
||||
PrepareTriMesh( );
|
||||
AssertValidMesh( );
|
||||
AssertValidSizes( );
|
||||
PrepareTriMesh( );
|
||||
|
||||
for ( int i = 0; i < BMesh->totpoly; ++i )
|
||||
{
|
||||
const MPoly& poly = BMesh->mpoly[ i ];
|
||||
ConvertPolyToFaces( poly );
|
||||
}
|
||||
for ( int i = 0; i < BMesh->totpoly; ++i )
|
||||
{
|
||||
const MPoly& poly = BMesh->mpoly[ i ];
|
||||
ConvertPolyToFaces( poly );
|
||||
}
|
||||
|
||||
return triMesh;
|
||||
return triMesh;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AssertValidMesh( )
|
||||
{
|
||||
if ( !ContainsBMesh( ) )
|
||||
{
|
||||
ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
|
||||
}
|
||||
if ( !ContainsBMesh( ) )
|
||||
{
|
||||
ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AssertValidSizes( )
|
||||
{
|
||||
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
|
||||
{
|
||||
ThrowException( "BMesh poly array has incorrect size" );
|
||||
}
|
||||
if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
|
||||
{
|
||||
ThrowException( "BMesh loop array has incorrect size" );
|
||||
}
|
||||
if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
|
||||
{
|
||||
ThrowException( "BMesh poly array has incorrect size" );
|
||||
}
|
||||
if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
|
||||
{
|
||||
ThrowException( "BMesh loop array has incorrect size" );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::PrepareTriMesh( )
|
||||
{
|
||||
if ( triMesh )
|
||||
{
|
||||
DestroyTriMesh( );
|
||||
}
|
||||
if ( triMesh )
|
||||
{
|
||||
DestroyTriMesh( );
|
||||
}
|
||||
|
||||
triMesh = new Mesh( *BMesh );
|
||||
triMesh->totface = 0;
|
||||
triMesh->mface.clear( );
|
||||
triMesh = new Mesh( *BMesh );
|
||||
triMesh->totface = 0;
|
||||
triMesh->mface.clear( );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::DestroyTriMesh( )
|
||||
{
|
||||
delete triMesh;
|
||||
triMesh = NULL;
|
||||
delete triMesh;
|
||||
triMesh = NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
|
||||
{
|
||||
const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
|
||||
const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
|
||||
|
||||
if ( poly.totloop == 3 || poly.totloop == 4 )
|
||||
{
|
||||
AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
|
||||
if ( poly.totloop == 3 || poly.totloop == 4 )
|
||||
{
|
||||
AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
|
||||
|
||||
// UVs are optional, so only convert when present.
|
||||
if ( BMesh->mloopuv.size() )
|
||||
{
|
||||
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
|
||||
{
|
||||
ThrowException( "BMesh uv loop array has incorrect size" );
|
||||
}
|
||||
const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
|
||||
AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
|
||||
}
|
||||
}
|
||||
else if ( poly.totloop > 4 )
|
||||
{
|
||||
// UVs are optional, so only convert when present.
|
||||
if ( BMesh->mloopuv.size() )
|
||||
{
|
||||
if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
|
||||
{
|
||||
ThrowException( "BMesh uv loop array has incorrect size" );
|
||||
}
|
||||
const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
|
||||
AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
|
||||
}
|
||||
}
|
||||
else if ( poly.totloop > 4 )
|
||||
{
|
||||
#if ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
||||
BlenderTessellatorGL tessGL( *this );
|
||||
tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
||||
BlenderTessellatorGL tessGL( *this );
|
||||
tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
||||
#elif ASSIMP_BLEND_WITH_POLY_2_TRI
|
||||
BlenderTessellatorP2T tessP2T( *this );
|
||||
tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
||||
BlenderTessellatorP2T tessP2T( *this );
|
||||
tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
|
||||
{
|
||||
MFace face;
|
||||
face.v1 = v1;
|
||||
face.v2 = v2;
|
||||
face.v3 = v3;
|
||||
face.v4 = v4;
|
||||
// TODO - Work out how materials work
|
||||
face.mat_nr = 0;
|
||||
triMesh->mface.push_back( face );
|
||||
triMesh->totface = triMesh->mface.size( );
|
||||
MFace face;
|
||||
face.v1 = v1;
|
||||
face.v2 = v2;
|
||||
face.v3 = v3;
|
||||
face.v4 = v4;
|
||||
// TODO - Work out how materials work
|
||||
face.mat_nr = 0;
|
||||
triMesh->mface.push_back( face );
|
||||
triMesh->totface = triMesh->mface.size( );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
|
||||
{
|
||||
MTFace mtface;
|
||||
memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
|
||||
memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
|
||||
memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
|
||||
MTFace mtface;
|
||||
memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
|
||||
memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
|
||||
memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
|
||||
|
||||
if ( uv4 )
|
||||
{
|
||||
memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
|
||||
}
|
||||
if ( uv4 )
|
||||
{
|
||||
memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
|
||||
}
|
||||
|
||||
triMesh->mtface.push_back( mtface );
|
||||
triMesh->mtface.push_back( mtface );
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||
|
|
|
@ -48,46 +48,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp
|
||||
{
|
||||
// TinyFormatter.h
|
||||
namespace Formatter
|
||||
{
|
||||
template < typename T,typename TR, typename A > class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
|
||||
}
|
||||
// TinyFormatter.h
|
||||
namespace Formatter
|
||||
{
|
||||
template < typename T,typename TR, typename A > class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
|
||||
}
|
||||
|
||||
// BlenderScene.h
|
||||
namespace Blender
|
||||
{
|
||||
struct Mesh;
|
||||
struct MPoly;
|
||||
struct MLoop;
|
||||
}
|
||||
// BlenderScene.h
|
||||
namespace Blender
|
||||
{
|
||||
struct Mesh;
|
||||
struct MPoly;
|
||||
struct MLoop;
|
||||
}
|
||||
|
||||
class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter >
|
||||
{
|
||||
public:
|
||||
BlenderBMeshConverter( const Blender::Mesh* mesh );
|
||||
~BlenderBMeshConverter( );
|
||||
class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter >
|
||||
{
|
||||
public:
|
||||
BlenderBMeshConverter( const Blender::Mesh* mesh );
|
||||
~BlenderBMeshConverter( );
|
||||
|
||||
bool ContainsBMesh( ) const;
|
||||
bool ContainsBMesh( ) const;
|
||||
|
||||
const Blender::Mesh* TriangulateBMesh( );
|
||||
const Blender::Mesh* TriangulateBMesh( );
|
||||
|
||||
private:
|
||||
void AssertValidMesh( );
|
||||
void AssertValidSizes( );
|
||||
void PrepareTriMesh( );
|
||||
void DestroyTriMesh( );
|
||||
void ConvertPolyToFaces( const Blender::MPoly& poly );
|
||||
void AddFace( int v1, int v2, int v3, int v4 = 0 );
|
||||
void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 );
|
||||
private:
|
||||
void AssertValidMesh( );
|
||||
void AssertValidSizes( );
|
||||
void PrepareTriMesh( );
|
||||
void DestroyTriMesh( );
|
||||
void ConvertPolyToFaces( const Blender::MPoly& poly );
|
||||
void AddFace( int v1, int v2, int v3, int v4 = 0 );
|
||||
void AddTFace( const float* uv1, const float* uv2, const float *uv3, const float* uv4 = 0 );
|
||||
|
||||
const Blender::Mesh* BMesh;
|
||||
Blender::Mesh* triMesh;
|
||||
const Blender::Mesh* BMesh;
|
||||
Blender::Mesh* triMesh;
|
||||
|
||||
friend class BlenderTessellatorGL;
|
||||
friend class BlenderTessellatorP2T;
|
||||
};
|
||||
friend class BlenderTessellatorGL;
|
||||
friend class BlenderTessellatorP2T;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
|
|
|
@ -56,168 +56,168 @@ using namespace Assimp::Formatter;
|
|||
|
||||
#define for_each BOOST_FOREACH
|
||||
bool match4(StreamReaderAny& stream, const char* string) {
|
||||
char tmp[] = {
|
||||
(stream).GetI1(),
|
||||
(stream).GetI1(),
|
||||
(stream).GetI1(),
|
||||
(stream).GetI1()
|
||||
};
|
||||
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
|
||||
char tmp[] = {
|
||||
(stream).GetI1(),
|
||||
(stream).GetI1(),
|
||||
(stream).GetI1(),
|
||||
(stream).GetI1()
|
||||
};
|
||||
return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
|
||||
}
|
||||
|
||||
struct Type {
|
||||
size_t size;
|
||||
std::string name;
|
||||
size_t size;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNAParser :: Parse ()
|
||||
{
|
||||
StreamReaderAny& stream = *db.reader.get();
|
||||
DNA& dna = db.dna;
|
||||
StreamReaderAny& stream = *db.reader.get();
|
||||
DNA& dna = db.dna;
|
||||
|
||||
if(!match4(stream,"SDNA")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
|
||||
}
|
||||
if(!match4(stream,"SDNA")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
|
||||
}
|
||||
|
||||
// name dictionary
|
||||
if(!match4(stream,"NAME")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected NAME field");
|
||||
}
|
||||
// name dictionary
|
||||
if(!match4(stream,"NAME")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected NAME field");
|
||||
}
|
||||
|
||||
std::vector<std::string> names (stream.GetI4());
|
||||
for_each(std::string& s, names) {
|
||||
while (char c = stream.GetI1()) {
|
||||
s += c;
|
||||
}
|
||||
}
|
||||
std::vector<std::string> names (stream.GetI4());
|
||||
for_each(std::string& s, names) {
|
||||
while (char c = stream.GetI1()) {
|
||||
s += c;
|
||||
}
|
||||
}
|
||||
|
||||
// type dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"TYPE")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
|
||||
}
|
||||
// type dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"TYPE")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TYPE field");
|
||||
}
|
||||
|
||||
std::vector<Type> types (stream.GetI4());
|
||||
for_each(Type& s, types) {
|
||||
while (char c = stream.GetI1()) {
|
||||
s.name += c;
|
||||
}
|
||||
}
|
||||
std::vector<Type> types (stream.GetI4());
|
||||
for_each(Type& s, types) {
|
||||
while (char c = stream.GetI1()) {
|
||||
s.name += c;
|
||||
}
|
||||
}
|
||||
|
||||
// type length dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"TLEN")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
|
||||
}
|
||||
// type length dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"TLEN")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected TLEN field");
|
||||
}
|
||||
|
||||
for_each(Type& s, types) {
|
||||
s.size = stream.GetI2();
|
||||
}
|
||||
for_each(Type& s, types) {
|
||||
s.size = stream.GetI2();
|
||||
}
|
||||
|
||||
// structures dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"STRC")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected STRC field");
|
||||
}
|
||||
// structures dictionary
|
||||
for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
|
||||
if(!match4(stream,"STRC")) {
|
||||
throw DeadlyImportError("BlenderDNA: Expected STRC field");
|
||||
}
|
||||
|
||||
size_t end = stream.GetI4(), fields = 0;
|
||||
size_t end = stream.GetI4(), fields = 0;
|
||||
|
||||
dna.structures.reserve(end);
|
||||
for(size_t i = 0; i != end; ++i) {
|
||||
dna.structures.reserve(end);
|
||||
for(size_t i = 0; i != end; ++i) {
|
||||
|
||||
uint16_t n = stream.GetI2();
|
||||
if (n >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure name" ,n,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
}
|
||||
uint16_t n = stream.GetI2();
|
||||
if (n >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure name" ,n,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
}
|
||||
|
||||
// maintain separate indexes
|
||||
dna.indices[types[n].name] = dna.structures.size();
|
||||
// maintain separate indexes
|
||||
dna.indices[types[n].name] = dna.structures.size();
|
||||
|
||||
dna.structures.push_back(Structure());
|
||||
Structure& s = dna.structures.back();
|
||||
s.name = types[n].name;
|
||||
//s.index = dna.structures.size()-1;
|
||||
dna.structures.push_back(Structure());
|
||||
Structure& s = dna.structures.back();
|
||||
s.name = types[n].name;
|
||||
//s.index = dna.structures.size()-1;
|
||||
|
||||
n = stream.GetI2();
|
||||
s.fields.reserve(n);
|
||||
n = stream.GetI2();
|
||||
s.fields.reserve(n);
|
||||
|
||||
size_t offset = 0;
|
||||
for (size_t m = 0; m < n; ++m, ++fields) {
|
||||
size_t offset = 0;
|
||||
for (size_t m = 0; m < n; ++m, ++fields) {
|
||||
|
||||
uint16_t j = stream.GetI2();
|
||||
if (j >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure field ", j,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
}
|
||||
s.fields.push_back(Field());
|
||||
Field& f = s.fields.back();
|
||||
f.offset = offset;
|
||||
uint16_t j = stream.GetI2();
|
||||
if (j >= types.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid type index in structure field ", j,
|
||||
" (there are only ", types.size(), " entries)"
|
||||
));
|
||||
}
|
||||
s.fields.push_back(Field());
|
||||
Field& f = s.fields.back();
|
||||
f.offset = offset;
|
||||
|
||||
f.type = types[j].name;
|
||||
f.size = types[j].size;
|
||||
f.type = types[j].name;
|
||||
f.size = types[j].size;
|
||||
|
||||
j = stream.GetI2();
|
||||
if (j >= names.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid name index in structure field ", j,
|
||||
" (there are only ", names.size(), " entries)"
|
||||
));
|
||||
}
|
||||
j = stream.GetI2();
|
||||
if (j >= names.size()) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Invalid name index in structure field ", j,
|
||||
" (there are only ", names.size(), " entries)"
|
||||
));
|
||||
}
|
||||
|
||||
f.name = names[j];
|
||||
f.flags = 0u;
|
||||
f.name = names[j];
|
||||
f.flags = 0u;
|
||||
|
||||
// pointers always specify the size of the pointee instead of their own.
|
||||
// The pointer asterisk remains a property of the lookup name.
|
||||
if (f.name[0] == '*') {
|
||||
f.size = db.i64bit ? 8 : 4;
|
||||
f.flags |= FieldFlag_Pointer;
|
||||
}
|
||||
// pointers always specify the size of the pointee instead of their own.
|
||||
// The pointer asterisk remains a property of the lookup name.
|
||||
if (f.name[0] == '*') {
|
||||
f.size = db.i64bit ? 8 : 4;
|
||||
f.flags |= FieldFlag_Pointer;
|
||||
}
|
||||
|
||||
// arrays, however, specify the size of a single element so we
|
||||
// need to parse the (possibly multi-dimensional) array declaration
|
||||
// in order to obtain the actual size of the array in the file.
|
||||
// Also we need to alter the lookup name to include no array
|
||||
// brackets anymore or size fixup won't work (if our size does
|
||||
// not match the size read from the DNA).
|
||||
if (*f.name.rbegin() == ']') {
|
||||
const std::string::size_type rb = f.name.find('[');
|
||||
if (rb == std::string::npos) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Encountered invalid array declaration ",
|
||||
f.name
|
||||
));
|
||||
}
|
||||
// arrays, however, specify the size of a single element so we
|
||||
// need to parse the (possibly multi-dimensional) array declaration
|
||||
// in order to obtain the actual size of the array in the file.
|
||||
// Also we need to alter the lookup name to include no array
|
||||
// brackets anymore or size fixup won't work (if our size does
|
||||
// not match the size read from the DNA).
|
||||
if (*f.name.rbegin() == ']') {
|
||||
const std::string::size_type rb = f.name.find('[');
|
||||
if (rb == std::string::npos) {
|
||||
throw DeadlyImportError((format(),
|
||||
"BlenderDNA: Encountered invalid array declaration ",
|
||||
f.name
|
||||
));
|
||||
}
|
||||
|
||||
f.flags |= FieldFlag_Array;
|
||||
DNA::ExtractArraySize(f.name,f.array_sizes);
|
||||
f.name = f.name.substr(0,rb);
|
||||
f.flags |= FieldFlag_Array;
|
||||
DNA::ExtractArraySize(f.name,f.array_sizes);
|
||||
f.name = f.name.substr(0,rb);
|
||||
|
||||
f.size *= f.array_sizes[0] * f.array_sizes[1];
|
||||
}
|
||||
f.size *= f.array_sizes[0] * f.array_sizes[1];
|
||||
}
|
||||
|
||||
// maintain separate indexes
|
||||
s.indices[f.name] = s.fields.size()-1;
|
||||
offset += f.size;
|
||||
}
|
||||
s.size = offset;
|
||||
}
|
||||
// maintain separate indexes
|
||||
s.indices[f.name] = s.fields.size()-1;
|
||||
offset += f.size;
|
||||
}
|
||||
s.size = offset;
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
|
||||
" structures with totally ",fields," fields"));
|
||||
DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
|
||||
" structures with totally ",fields," fields"));
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
dna.DumpToFile();
|
||||
dna.DumpToFile();
|
||||
#endif
|
||||
|
||||
dna.AddPrimitiveStructures();
|
||||
dna.RegisterConverters();
|
||||
dna.AddPrimitiveStructures();
|
||||
dna.RegisterConverters();
|
||||
}
|
||||
|
||||
|
||||
|
@ -227,144 +227,144 @@ void DNAParser :: Parse ()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void DNA :: DumpToFile()
|
||||
{
|
||||
// we dont't bother using the VFS here for this is only for debugging.
|
||||
// (and all your bases are belong to us).
|
||||
// we dont't bother using the VFS here for this is only for debugging.
|
||||
// (and all your bases are belong to us).
|
||||
|
||||
std::ofstream f("dna.txt");
|
||||
if (f.fail()) {
|
||||
DefaultLogger::get()->error("Could not dump dna to dna.txt");
|
||||
return;
|
||||
}
|
||||
f << "Field format: type name offset size" << "\n";
|
||||
f << "Structure format: name size" << "\n";
|
||||
std::ofstream f("dna.txt");
|
||||
if (f.fail()) {
|
||||
DefaultLogger::get()->error("Could not dump dna to dna.txt");
|
||||
return;
|
||||
}
|
||||
f << "Field format: type name offset size" << "\n";
|
||||
f << "Structure format: name size" << "\n";
|
||||
|
||||
for_each(const Structure& s, structures) {
|
||||
f << s.name << " " << s.size << "\n\n";
|
||||
for_each(const Field& ff, s.fields) {
|
||||
f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
|
||||
}
|
||||
f << std::endl;
|
||||
}
|
||||
DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
|
||||
for_each(const Structure& s, structures) {
|
||||
f << s.name << " " << s.size << "\n\n";
|
||||
for_each(const Field& ff, s.fields) {
|
||||
f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
|
||||
}
|
||||
f << std::endl;
|
||||
}
|
||||
DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/*static*/ void DNA :: ExtractArraySize(
|
||||
const std::string& out,
|
||||
size_t array_sizes[2]
|
||||
const std::string& out,
|
||||
size_t array_sizes[2]
|
||||
)
|
||||
{
|
||||
array_sizes[0] = array_sizes[1] = 1;
|
||||
std::string::size_type pos = out.find('[');
|
||||
if (pos++ == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
array_sizes[0] = strtoul10(&out[pos]);
|
||||
array_sizes[0] = array_sizes[1] = 1;
|
||||
std::string::size_type pos = out.find('[');
|
||||
if (pos++ == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
array_sizes[0] = strtoul10(&out[pos]);
|
||||
|
||||
pos = out.find('[',pos);
|
||||
if (pos++ == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
array_sizes[1] = strtoul10(&out[pos]);
|
||||
pos = out.find('[',pos);
|
||||
if (pos++ == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
array_sizes[1] = strtoul10(&out[pos]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
|
||||
const Structure& structure,
|
||||
const FileDatabase& db
|
||||
const Structure& structure,
|
||||
const FileDatabase& db
|
||||
) const
|
||||
{
|
||||
std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
|
||||
if (it == converters.end()) {
|
||||
return boost::shared_ptr< ElemBase >();
|
||||
}
|
||||
std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
|
||||
if (it == converters.end()) {
|
||||
return boost::shared_ptr< ElemBase >();
|
||||
}
|
||||
|
||||
boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
|
||||
(structure.*((*it).second.second))(ret,db);
|
||||
boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
|
||||
(structure.*((*it).second.second))(ret,db);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
DNA::FactoryPair DNA :: GetBlobToStructureConverter(
|
||||
const Structure& structure,
|
||||
const FileDatabase& /*db*/
|
||||
const Structure& structure,
|
||||
const FileDatabase& /*db*/
|
||||
) const
|
||||
{
|
||||
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||
return it == converters.end() ? FactoryPair() : (*it).second;
|
||||
std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
|
||||
return it == converters.end() ? FactoryPair() : (*it).second;
|
||||
}
|
||||
|
||||
// basing on http://www.blender.org/development/architecture/notes-on-sdna/
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DNA :: AddPrimitiveStructures()
|
||||
{
|
||||
// NOTE: these are just dummies. Their presence enforces
|
||||
// Structure::Convert<target_type> to be called on these
|
||||
// empty structures. These converters are special
|
||||
// overloads which scan the name of the structure and
|
||||
// perform the required data type conversion if one
|
||||
// of these special names is found in the structure
|
||||
// in question.
|
||||
// NOTE: these are just dummies. Their presence enforces
|
||||
// Structure::Convert<target_type> to be called on these
|
||||
// empty structures. These converters are special
|
||||
// overloads which scan the name of the structure and
|
||||
// perform the required data type conversion if one
|
||||
// of these special names is found in the structure
|
||||
// in question.
|
||||
|
||||
indices["int"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "int";
|
||||
structures.back().size = 4;
|
||||
indices["int"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "int";
|
||||
structures.back().size = 4;
|
||||
|
||||
indices["short"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "short";
|
||||
structures.back().size = 2;
|
||||
indices["short"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "short";
|
||||
structures.back().size = 2;
|
||||
|
||||
|
||||
indices["char"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "char";
|
||||
structures.back().size = 1;
|
||||
indices["char"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "char";
|
||||
structures.back().size = 1;
|
||||
|
||||
|
||||
indices["float"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "float";
|
||||
structures.back().size = 4;
|
||||
indices["float"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "float";
|
||||
structures.back().size = 4;
|
||||
|
||||
|
||||
indices["double"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "double";
|
||||
structures.back().size = 8;
|
||||
indices["double"] = structures.size();
|
||||
structures.push_back( Structure() );
|
||||
structures.back().name = "double";
|
||||
structures.back().size = 8;
|
||||
|
||||
// no long, seemingly.
|
||||
// no long, seemingly.
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SectionParser :: Next()
|
||||
{
|
||||
stream.SetCurrentPos(current.start + current.size);
|
||||
stream.SetCurrentPos(current.start + current.size);
|
||||
|
||||
const char tmp[] = {
|
||||
stream.GetI1(),
|
||||
stream.GetI1(),
|
||||
stream.GetI1(),
|
||||
stream.GetI1()
|
||||
};
|
||||
current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
|
||||
const char tmp[] = {
|
||||
stream.GetI1(),
|
||||
stream.GetI1(),
|
||||
stream.GetI1(),
|
||||
stream.GetI1()
|
||||
};
|
||||
current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
|
||||
|
||||
current.size = stream.GetI4();
|
||||
current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
|
||||
current.size = stream.GetI4();
|
||||
current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
|
||||
|
||||
current.dna_index = stream.GetI4();
|
||||
current.num = stream.GetI4();
|
||||
current.dna_index = stream.GetI4();
|
||||
current.num = stream.GetI4();
|
||||
|
||||
current.start = stream.GetCurrentPos();
|
||||
if (stream.GetRemainingSizeToLimit() < current.size) {
|
||||
throw DeadlyImportError("BLEND: invalid size of file block");
|
||||
}
|
||||
current.start = stream.GetCurrentPos();
|
||||
if (stream.GetRemainingSizeToLimit() < current.size) {
|
||||
throw DeadlyImportError("BLEND: invalid size of file block");
|
||||
}
|
||||
|
||||
#ifdef ASSIMP_BUILD_BLENDER_DEBUG
|
||||
DefaultLogger::get()->debug(current.id);
|
||||
DefaultLogger::get()->debug(current.id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -60,142 +60,142 @@ struct aiTexture;
|
|||
namespace Assimp {
|
||||
namespace Blender {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */
|
||||
// --------------------------------------------------------------------
|
||||
template <template <typename,typename> class TCLASS, typename T>
|
||||
struct TempArray {
|
||||
typedef TCLASS< T*,std::allocator<T*> > mywrap;
|
||||
// --------------------------------------------------------------------
|
||||
/** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */
|
||||
// --------------------------------------------------------------------
|
||||
template <template <typename,typename> class TCLASS, typename T>
|
||||
struct TempArray {
|
||||
typedef TCLASS< T*,std::allocator<T*> > mywrap;
|
||||
|
||||
TempArray() {
|
||||
}
|
||||
TempArray() {
|
||||
}
|
||||
|
||||
~TempArray () {
|
||||
for_each(T* elem, arr) {
|
||||
delete elem;
|
||||
}
|
||||
}
|
||||
~TempArray () {
|
||||
for_each(T* elem, arr) {
|
||||
delete elem;
|
||||
}
|
||||
}
|
||||
|
||||
void dismiss() {
|
||||
arr.clear();
|
||||
}
|
||||
void dismiss() {
|
||||
arr.clear();
|
||||
}
|
||||
|
||||
mywrap* operator -> () {
|
||||
return &arr;
|
||||
}
|
||||
mywrap* operator -> () {
|
||||
return &arr;
|
||||
}
|
||||
|
||||
operator mywrap& () {
|
||||
return arr;
|
||||
}
|
||||
operator mywrap& () {
|
||||
return arr;
|
||||
}
|
||||
|
||||
operator const mywrap& () const {
|
||||
return arr;
|
||||
}
|
||||
operator const mywrap& () const {
|
||||
return arr;
|
||||
}
|
||||
|
||||
mywrap& get () {
|
||||
return arr;
|
||||
}
|
||||
mywrap& get () {
|
||||
return arr;
|
||||
}
|
||||
|
||||
const mywrap& get () const {
|
||||
return arr;
|
||||
}
|
||||
const mywrap& get () const {
|
||||
return arr;
|
||||
}
|
||||
|
||||
T* operator[] (size_t idx) const {
|
||||
return arr[idx];
|
||||
}
|
||||
T* operator[] (size_t idx) const {
|
||||
return arr[idx];
|
||||
}
|
||||
|
||||
T*& operator[] (size_t idx) {
|
||||
return arr[idx];
|
||||
}
|
||||
T*& operator[] (size_t idx) {
|
||||
return arr[idx];
|
||||
}
|
||||
|
||||
private:
|
||||
// no copy semantics
|
||||
void operator= (const TempArray&) {
|
||||
}
|
||||
private:
|
||||
// no copy semantics
|
||||
void operator= (const TempArray&) {
|
||||
}
|
||||
|
||||
TempArray(const TempArray& arr) {
|
||||
}
|
||||
TempArray(const TempArray& arr) {
|
||||
}
|
||||
|
||||
private:
|
||||
mywrap arr;
|
||||
};
|
||||
private:
|
||||
mywrap arr;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable:4351)
|
||||
# pragma warning(disable:4351)
|
||||
#endif
|
||||
|
||||
struct ObjectCompare {
|
||||
bool operator() (const Object* left, const Object* right) const {
|
||||
return strcmp(left->id.name, right->id.name) == -1;
|
||||
}
|
||||
};
|
||||
struct ObjectCompare {
|
||||
bool operator() (const Object* left, const Object* right) const {
|
||||
return strcmp(left->id.name, right->id.name) == -1;
|
||||
}
|
||||
};
|
||||
|
||||
// When keeping objects in sets, sort them by their name.
|
||||
typedef std::set<const Object*, ObjectCompare> ObjectSet;
|
||||
// When keeping objects in sets, sort them by their name.
|
||||
typedef std::set<const Object*, ObjectCompare> ObjectSet;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/** ConversionData acts as intermediate storage location for
|
||||
* the various ConvertXXX routines in BlenderImporter.*/
|
||||
// --------------------------------------------------------------------
|
||||
struct ConversionData
|
||||
{
|
||||
ConversionData(const FileDatabase& db)
|
||||
: sentinel_cnt()
|
||||
, next_texture()
|
||||
, db(db)
|
||||
{}
|
||||
// --------------------------------------------------------------------
|
||||
/** ConversionData acts as intermediate storage location for
|
||||
* the various ConvertXXX routines in BlenderImporter.*/
|
||||
// --------------------------------------------------------------------
|
||||
struct ConversionData
|
||||
{
|
||||
ConversionData(const FileDatabase& db)
|
||||
: sentinel_cnt()
|
||||
, next_texture()
|
||||
, db(db)
|
||||
{}
|
||||
|
||||
struct ObjectCompare {
|
||||
bool operator() (const Object* left, const Object* right) const {
|
||||
return strcmp(left->id.name, right->id.name) == -1;
|
||||
}
|
||||
};
|
||||
struct ObjectCompare {
|
||||
bool operator() (const Object* left, const Object* right) const {
|
||||
return strcmp(left->id.name, right->id.name) == -1;
|
||||
}
|
||||
};
|
||||
|
||||
ObjectSet objects;
|
||||
ObjectSet objects;
|
||||
|
||||
TempArray <std::vector, aiMesh> meshes;
|
||||
TempArray <std::vector, aiCamera> cameras;
|
||||
TempArray <std::vector, aiLight> lights;
|
||||
TempArray <std::vector, aiMaterial> materials;
|
||||
TempArray <std::vector, aiTexture> textures;
|
||||
TempArray <std::vector, aiMesh> meshes;
|
||||
TempArray <std::vector, aiCamera> cameras;
|
||||
TempArray <std::vector, aiLight> lights;
|
||||
TempArray <std::vector, aiMaterial> materials;
|
||||
TempArray <std::vector, aiTexture> textures;
|
||||
|
||||
// set of all materials referenced by at least one mesh in the scene
|
||||
std::deque< boost::shared_ptr< Material > > materials_raw;
|
||||
// set of all materials referenced by at least one mesh in the scene
|
||||
std::deque< boost::shared_ptr< Material > > materials_raw;
|
||||
|
||||
// counter to name sentinel textures inserted as substitutes for procedural textures.
|
||||
unsigned int sentinel_cnt;
|
||||
// counter to name sentinel textures inserted as substitutes for procedural textures.
|
||||
unsigned int sentinel_cnt;
|
||||
|
||||
// next texture ID for each texture type, respectively
|
||||
unsigned int next_texture[aiTextureType_UNKNOWN+1];
|
||||
// next texture ID for each texture type, respectively
|
||||
unsigned int next_texture[aiTextureType_UNKNOWN+1];
|
||||
|
||||
// original file data
|
||||
const FileDatabase& db;
|
||||
};
|
||||
// original file data
|
||||
const FileDatabase& db;
|
||||
};
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(default:4351)
|
||||
# pragma warning(default:4351)
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline const char* GetTextureTypeDisplayString(Tex::Type t)
|
||||
{
|
||||
switch (t) {
|
||||
case Tex::Type_CLOUDS : return "Clouds";
|
||||
case Tex::Type_WOOD : return "Wood";
|
||||
case Tex::Type_MARBLE : return "Marble";
|
||||
case Tex::Type_MAGIC : return "Magic";
|
||||
case Tex::Type_BLEND : return "Blend";
|
||||
case Tex::Type_STUCCI : return "Stucci";
|
||||
case Tex::Type_NOISE : return "Noise";
|
||||
case Tex::Type_PLUGIN : return "Plugin";
|
||||
case Tex::Type_MUSGRAVE : return "Musgrave";
|
||||
case Tex::Type_VORONOI : return "Voronoi";
|
||||
case Tex::Type_DISTNOISE : return "DistortedNoise";
|
||||
case Tex::Type_ENVMAP : return "EnvMap";
|
||||
case Tex::Type_IMAGE : return "Image";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "<Unknown>";
|
||||
switch (t) {
|
||||
case Tex::Type_CLOUDS : return "Clouds";
|
||||
case Tex::Type_WOOD : return "Wood";
|
||||
case Tex::Type_MARBLE : return "Marble";
|
||||
case Tex::Type_MAGIC : return "Magic";
|
||||
case Tex::Type_BLEND : return "Blend";
|
||||
case Tex::Type_STUCCI : return "Stucci";
|
||||
case Tex::Type_NOISE : return "Noise";
|
||||
case Tex::Type_PLUGIN : return "Plugin";
|
||||
case Tex::Type_MUSGRAVE : return "Musgrave";
|
||||
case Tex::Type_VORONOI : return "Voronoi";
|
||||
case Tex::Type_DISTNOISE : return "DistortedNoise";
|
||||
case Tex::Type_ENVMAP : return "EnvMap";
|
||||
case Tex::Type_IMAGE : return "Image";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "<Unknown>";
|
||||
}
|
||||
|
||||
} // ! Blender
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -54,43 +54,43 @@ struct aiLight;
|
|||
struct aiCamera;
|
||||
struct aiMaterial;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
|
||||
// BlenderDNA.h
|
||||
namespace Blender {
|
||||
class FileDatabase;
|
||||
struct ElemBase;
|
||||
}
|
||||
// BlenderDNA.h
|
||||
namespace Blender {
|
||||
class FileDatabase;
|
||||
struct ElemBase;
|
||||
}
|
||||
|
||||
// BlenderScene.h
|
||||
namespace Blender {
|
||||
struct Scene;
|
||||
struct Object;
|
||||
struct Mesh;
|
||||
struct Camera;
|
||||
struct Lamp;
|
||||
struct MTex;
|
||||
struct Image;
|
||||
struct Material;
|
||||
}
|
||||
// BlenderScene.h
|
||||
namespace Blender {
|
||||
struct Scene;
|
||||
struct Object;
|
||||
struct Mesh;
|
||||
struct Camera;
|
||||
struct Lamp;
|
||||
struct MTex;
|
||||
struct Image;
|
||||
struct Material;
|
||||
}
|
||||
|
||||
// BlenderIntermediate.h
|
||||
namespace Blender {
|
||||
struct ConversionData;
|
||||
template <template <typename,typename> class TCLASS, typename T> struct TempArray;
|
||||
}
|
||||
// BlenderIntermediate.h
|
||||
namespace Blender {
|
||||
struct ConversionData;
|
||||
template <template <typename,typename> class TCLASS, typename T> struct TempArray;
|
||||
}
|
||||
|
||||
// BlenderModifier.h
|
||||
namespace Blender {
|
||||
class BlenderModifierShowcase;
|
||||
class BlenderModifier;
|
||||
}
|
||||
// BlenderModifier.h
|
||||
namespace Blender {
|
||||
class BlenderModifierShowcase;
|
||||
class BlenderModifier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -102,127 +102,127 @@ namespace Assimp {
|
|||
class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter>
|
||||
{
|
||||
public:
|
||||
BlenderImporter();
|
||||
~BlenderImporter();
|
||||
BlenderImporter();
|
||||
~BlenderImporter();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile,
|
||||
IOSystem* pIOHandler,
|
||||
bool checkSig
|
||||
) const;
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile,
|
||||
IOSystem* pIOHandler,
|
||||
bool checkSig
|
||||
) const;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// --------------------
|
||||
void GetExtensionList(std::set<std::string>& app);
|
||||
// --------------------
|
||||
void GetExtensionList(std::set<std::string>& app);
|
||||
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler
|
||||
);
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler
|
||||
);
|
||||
|
||||
// --------------------
|
||||
void ParseBlendFile(Blender::FileDatabase& out,
|
||||
boost::shared_ptr<IOStream> stream
|
||||
);
|
||||
// --------------------
|
||||
void ParseBlendFile(Blender::FileDatabase& out,
|
||||
boost::shared_ptr<IOStream> stream
|
||||
);
|
||||
|
||||
// --------------------
|
||||
void ExtractScene(Blender::Scene& out,
|
||||
const Blender::FileDatabase& file
|
||||
);
|
||||
// --------------------
|
||||
void ExtractScene(Blender::Scene& out,
|
||||
const Blender::FileDatabase& file
|
||||
);
|
||||
|
||||
// --------------------
|
||||
void ConvertBlendFile(aiScene* out,
|
||||
const Blender::Scene& in,
|
||||
const Blender::FileDatabase& file
|
||||
);
|
||||
// --------------------
|
||||
void ConvertBlendFile(aiScene* out,
|
||||
const Blender::Scene& in,
|
||||
const Blender::FileDatabase& file
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
// --------------------
|
||||
aiNode* ConvertNode(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
Blender::ConversionData& conv_info,
|
||||
const aiMatrix4x4& parentTransform
|
||||
);
|
||||
// --------------------
|
||||
aiNode* ConvertNode(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
Blender::ConversionData& conv_info,
|
||||
const aiMatrix4x4& parentTransform
|
||||
);
|
||||
|
||||
// --------------------
|
||||
void ConvertMesh(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
const Blender::Mesh* mesh,
|
||||
Blender::ConversionData& conv_data,
|
||||
Blender::TempArray<std::vector,aiMesh>& temp
|
||||
);
|
||||
// --------------------
|
||||
void ConvertMesh(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
const Blender::Mesh* mesh,
|
||||
Blender::ConversionData& conv_data,
|
||||
Blender::TempArray<std::vector,aiMesh>& temp
|
||||
);
|
||||
|
||||
// --------------------
|
||||
aiLight* ConvertLight(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
const Blender::Lamp* mesh,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
// --------------------
|
||||
aiLight* ConvertLight(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
const Blender::Lamp* mesh,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
|
||||
// --------------------
|
||||
aiCamera* ConvertCamera(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
const Blender::Camera* mesh,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
// --------------------
|
||||
aiCamera* ConvertCamera(const Blender::Scene& in,
|
||||
const Blender::Object* obj,
|
||||
const Blender::Camera* mesh,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
|
||||
// --------------------
|
||||
void BuildMaterials(
|
||||
Blender::ConversionData& conv_data
|
||||
) ;
|
||||
// --------------------
|
||||
void BuildMaterials(
|
||||
Blender::ConversionData& conv_data
|
||||
) ;
|
||||
|
||||
// --------------------
|
||||
void ResolveTexture(
|
||||
aiMaterial* out,
|
||||
const Blender::Material* mat,
|
||||
const Blender::MTex* tex,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
// --------------------
|
||||
void ResolveTexture(
|
||||
aiMaterial* out,
|
||||
const Blender::Material* mat,
|
||||
const Blender::MTex* tex,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
|
||||
// --------------------
|
||||
void ResolveImage(
|
||||
aiMaterial* out,
|
||||
const Blender::Material* mat,
|
||||
const Blender::MTex* tex,
|
||||
const Blender::Image* img,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
// --------------------
|
||||
void ResolveImage(
|
||||
aiMaterial* out,
|
||||
const Blender::Material* mat,
|
||||
const Blender::MTex* tex,
|
||||
const Blender::Image* img,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
|
||||
void AddSentinelTexture(
|
||||
aiMaterial* out,
|
||||
const Blender::Material* mat,
|
||||
const Blender::MTex* tex,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
void AddSentinelTexture(
|
||||
aiMaterial* out,
|
||||
const Blender::Material* mat,
|
||||
const Blender::MTex* tex,
|
||||
Blender::ConversionData& conv_data
|
||||
);
|
||||
|
||||
private: // static stuff, mostly logging and error reporting.
|
||||
|
||||
// --------------------
|
||||
static void CheckActualType(const Blender::ElemBase* dt,
|
||||
const char* check
|
||||
);
|
||||
// --------------------
|
||||
static void CheckActualType(const Blender::ElemBase* dt,
|
||||
const char* check
|
||||
);
|
||||
|
||||
// --------------------
|
||||
static void NotSupportedObjectType(const Blender::Object* obj,
|
||||
const char* type
|
||||
);
|
||||
// --------------------
|
||||
static void NotSupportedObjectType(const Blender::Object* obj,
|
||||
const char* type
|
||||
);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Blender::BlenderModifierShowcase* modifier_cache;
|
||||
Blender::BlenderModifierShowcase* modifier_cache;
|
||||
|
||||
}; // !class BlenderImporter
|
||||
|
||||
|
|
|
@ -58,120 +58,120 @@ using namespace Assimp;
|
|||
using namespace Assimp::Blender;
|
||||
|
||||
template <typename T> BlenderModifier* god() {
|
||||
return new T();
|
||||
return new T();
|
||||
}
|
||||
|
||||
// add all available modifiers here
|
||||
typedef BlenderModifier* (*fpCreateModifier)();
|
||||
static const fpCreateModifier creators[] = {
|
||||
&god<BlenderModifier_Mirror>,
|
||||
&god<BlenderModifier_Subdivision>,
|
||||
&god<BlenderModifier_Mirror>,
|
||||
&god<BlenderModifier_Subdivision>,
|
||||
|
||||
NULL // sentinel
|
||||
NULL // sentinel
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// just testing out some new macros to simplify logging
|
||||
#define ASSIMP_LOG_WARN_F(string,...)\
|
||||
DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
|
||||
DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
|
||||
|
||||
#define ASSIMP_LOG_ERROR_F(string,...)\
|
||||
DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
|
||||
DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
|
||||
|
||||
#define ASSIMP_LOG_DEBUG_F(string,...)\
|
||||
DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
|
||||
DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
|
||||
|
||||
#define ASSIMP_LOG_INFO_F(string,...)\
|
||||
DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
|
||||
DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
|
||||
|
||||
|
||||
#define ASSIMP_LOG_WARN(string)\
|
||||
DefaultLogger::get()->warn(string)
|
||||
DefaultLogger::get()->warn(string)
|
||||
|
||||
#define ASSIMP_LOG_ERROR(string)\
|
||||
DefaultLogger::get()->error(string)
|
||||
DefaultLogger::get()->error(string)
|
||||
|
||||
#define ASSIMP_LOG_DEBUG(string)\
|
||||
DefaultLogger::get()->debug(string)
|
||||
DefaultLogger::get()->debug(string)
|
||||
|
||||
#define ASSIMP_LOG_INFO(string)\
|
||||
DefaultLogger::get()->info(string)
|
||||
DefaultLogger::get()->info(string)
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
struct SharedModifierData : ElemBase
|
||||
{
|
||||
ModifierData modifier;
|
||||
ModifierData modifier;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object )
|
||||
{
|
||||
size_t cnt = 0u, ful = 0u;
|
||||
size_t cnt = 0u, ful = 0u;
|
||||
|
||||
// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
|
||||
// we're allowed to dereference the pointers without risking to crash. We might still be
|
||||
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
|
||||
// structures is at offset sizeof(vftable) with no padding.
|
||||
const SharedModifierData* cur = boost::static_pointer_cast<const SharedModifierData> ( orig_object.modifiers.first.get() );
|
||||
for (; cur; cur = boost::static_pointer_cast<const SharedModifierData> ( cur->modifier.next.get() ), ++ful) {
|
||||
ai_assert(cur->dna_type);
|
||||
// NOTE: this cast is potentially unsafe by design, so we need to perform type checks before
|
||||
// we're allowed to dereference the pointers without risking to crash. We might still be
|
||||
// invoking UB btw - we're assuming that the ModifierData member of the respective modifier
|
||||
// structures is at offset sizeof(vftable) with no padding.
|
||||
const SharedModifierData* cur = boost::static_pointer_cast<const SharedModifierData> ( orig_object.modifiers.first.get() );
|
||||
for (; cur; cur = boost::static_pointer_cast<const SharedModifierData> ( cur->modifier.next.get() ), ++ful) {
|
||||
ai_assert(cur->dna_type);
|
||||
|
||||
const Structure* s = conv_data.db.dna.Get( cur->dna_type );
|
||||
if (!s) {
|
||||
ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
|
||||
continue;
|
||||
}
|
||||
const Structure* s = conv_data.db.dna.Get( cur->dna_type );
|
||||
if (!s) {
|
||||
ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
// this is a common trait of all XXXMirrorData structures in BlenderDNA
|
||||
const Field* f = s->Get("modifier");
|
||||
if (!f || f->offset != 0) {
|
||||
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
|
||||
continue;
|
||||
}
|
||||
// this is a common trait of all XXXMirrorData structures in BlenderDNA
|
||||
const Field* f = s->Get("modifier");
|
||||
if (!f || f->offset != 0) {
|
||||
ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0");
|
||||
continue;
|
||||
}
|
||||
|
||||
s = conv_data.db.dna.Get( f->type );
|
||||
if (!s || s->name != "ModifierData") {
|
||||
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
|
||||
continue;
|
||||
}
|
||||
s = conv_data.db.dna.Get( f->type );
|
||||
if (!s || s->name != "ModifierData") {
|
||||
ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member");
|
||||
continue;
|
||||
}
|
||||
|
||||
// now, we can be sure that we should be fine to dereference *cur* as
|
||||
// ModifierData (with the above note).
|
||||
const ModifierData& dat = cur->modifier;
|
||||
// now, we can be sure that we should be fine to dereference *cur* as
|
||||
// ModifierData (with the above note).
|
||||
const ModifierData& dat = cur->modifier;
|
||||
|
||||
const fpCreateModifier* curgod = creators;
|
||||
std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
|
||||
const fpCreateModifier* curgod = creators;
|
||||
std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end();
|
||||
|
||||
for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
|
||||
if (curmod == endmod) {
|
||||
cached_modifiers->push_back((*curgod)());
|
||||
for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly
|
||||
if (curmod == endmod) {
|
||||
cached_modifiers->push_back((*curgod)());
|
||||
|
||||
endmod = cached_modifiers->end();
|
||||
curmod = endmod-1;
|
||||
}
|
||||
endmod = cached_modifiers->end();
|
||||
curmod = endmod-1;
|
||||
}
|
||||
|
||||
BlenderModifier* const modifier = *curmod;
|
||||
if(modifier->IsActive(dat)) {
|
||||
modifier->DoIt(out,conv_data,*boost::static_pointer_cast<const ElemBase>(cur),in,orig_object);
|
||||
cnt++;
|
||||
BlenderModifier* const modifier = *curmod;
|
||||
if(modifier->IsActive(dat)) {
|
||||
modifier->DoIt(out,conv_data,*boost::static_pointer_cast<const ElemBase>(cur),in,orig_object);
|
||||
cnt++;
|
||||
|
||||
curgod = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curgod) {
|
||||
ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
|
||||
}
|
||||
}
|
||||
curgod = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curgod) {
|
||||
ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name);
|
||||
}
|
||||
}
|
||||
|
||||
// Even though we managed to resolve some or all of the modifiers on this
|
||||
// object, we still can't say whether our modifier implementations were
|
||||
// able to fully do their job.
|
||||
if (ful) {
|
||||
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
|
||||
"`, check log messages above for errors");
|
||||
}
|
||||
// Even though we managed to resolve some or all of the modifiers on this
|
||||
// object, we still can't say whether our modifier implementations were
|
||||
// able to fully do their job.
|
||||
if (ful) {
|
||||
ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name,
|
||||
"`, check log messages above for errors");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -179,102 +179,102 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin)
|
||||
{
|
||||
return modin.type == ModifierData::eModifierType_Mirror;
|
||||
return modin.type == ModifierData::eModifierType_Mirror;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
||||
const Scene& /*in*/,
|
||||
const Object& orig_object )
|
||||
const Scene& /*in*/,
|
||||
const Object& orig_object )
|
||||
{
|
||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||
const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
|
||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
|
||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||
const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier);
|
||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror);
|
||||
|
||||
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
|
||||
conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes);
|
||||
|
||||
// XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
|
||||
// XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ...
|
||||
|
||||
// take all input meshes and clone them
|
||||
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
|
||||
aiMesh* mesh;
|
||||
SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
|
||||
// take all input meshes and clone them
|
||||
for (unsigned int i = 0; i < out.mNumMeshes; ++i) {
|
||||
aiMesh* mesh;
|
||||
SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]);
|
||||
|
||||
const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
|
||||
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
|
||||
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
|
||||
const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f;
|
||||
const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f;
|
||||
const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f;
|
||||
|
||||
if (mir.mirror_ob) {
|
||||
const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mVertices[i];
|
||||
if (mir.mirror_ob) {
|
||||
const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] );
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mVertices[i];
|
||||
|
||||
v.x = center.x + xs*(center.x - v.x);
|
||||
v.y = center.y + ys*(center.y - v.y);
|
||||
v.z = center.z + zs*(center.z - v.z);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mVertices[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
v.x = center.x + xs*(center.x - v.x);
|
||||
v.y = center.y + ys*(center.y - v.y);
|
||||
v.z = center.z + zs*(center.z - v.z);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mVertices[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->mNormals) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mNormals[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
if (mesh->mNormals) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mNormals[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->mTangents) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mTangents[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
if (mesh->mTangents) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mTangents[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->mBitangents) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mBitangents[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
if (mesh->mBitangents) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mBitangents[i];
|
||||
v.x *= xs;v.y *= ys;v.z *= zs;
|
||||
}
|
||||
}
|
||||
|
||||
const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
|
||||
const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
|
||||
const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f;
|
||||
const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f;
|
||||
|
||||
for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mTextureCoords[n][i];
|
||||
v.x *= us;v.y *= vs;
|
||||
}
|
||||
}
|
||||
for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D& v = mesh->mTextureCoords[n][i];
|
||||
v.x *= us;v.y *= vs;
|
||||
}
|
||||
}
|
||||
|
||||
// Only reverse the winding order if an odd number of axes were mirrored.
|
||||
if (xs * ys * zs < 0) {
|
||||
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
||||
aiFace& face = mesh->mFaces[i];
|
||||
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
||||
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
||||
}
|
||||
}
|
||||
// Only reverse the winding order if an odd number of axes were mirrored.
|
||||
if (xs * ys * zs < 0) {
|
||||
for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
|
||||
aiFace& face = mesh->mFaces[i];
|
||||
for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
|
||||
std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
|
||||
}
|
||||
}
|
||||
|
||||
conv_data.meshes->push_back(mesh);
|
||||
}
|
||||
unsigned int* nind = new unsigned int[out.mNumMeshes*2];
|
||||
conv_data.meshes->push_back(mesh);
|
||||
}
|
||||
unsigned int* nind = new unsigned int[out.mNumMeshes*2];
|
||||
|
||||
std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
|
||||
std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
|
||||
std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
|
||||
std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind);
|
||||
std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes,
|
||||
std::bind1st(std::plus< unsigned int >(),out.mNumMeshes));
|
||||
|
||||
delete[] out.mMeshes;
|
||||
out.mMeshes = nind;
|
||||
out.mNumMeshes *= 2;
|
||||
delete[] out.mMeshes;
|
||||
out.mMeshes = nind;
|
||||
out.mNumMeshes *= 2;
|
||||
|
||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
|
||||
orig_object.id.name,"`");
|
||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `",
|
||||
orig_object.id.name,"`");
|
||||
}
|
||||
|
||||
|
||||
|
@ -283,46 +283,46 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin)
|
||||
{
|
||||
return modin.type == ModifierData::eModifierType_Subsurf;
|
||||
return modin.type == ModifierData::eModifierType_Subsurf;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier,
|
||||
const Scene& /*in*/,
|
||||
const Object& orig_object )
|
||||
const Scene& /*in*/,
|
||||
const Object& orig_object )
|
||||
{
|
||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||
const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
|
||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
|
||||
// hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers()
|
||||
const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier);
|
||||
ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf);
|
||||
|
||||
Subdivider::Algorithm algo;
|
||||
switch (mir.subdivType)
|
||||
{
|
||||
case SubsurfModifierData::TYPE_CatmullClarke:
|
||||
algo = Subdivider::CATMULL_CLARKE;
|
||||
break;
|
||||
Subdivider::Algorithm algo;
|
||||
switch (mir.subdivType)
|
||||
{
|
||||
case SubsurfModifierData::TYPE_CatmullClarke:
|
||||
algo = Subdivider::CATMULL_CLARKE;
|
||||
break;
|
||||
|
||||
case SubsurfModifierData::TYPE_Simple:
|
||||
ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
|
||||
algo = Subdivider::CATMULL_CLARKE;
|
||||
break;
|
||||
case SubsurfModifierData::TYPE_Simple:
|
||||
ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
|
||||
algo = Subdivider::CATMULL_CLARKE;
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
|
||||
return;
|
||||
};
|
||||
default:
|
||||
ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType);
|
||||
return;
|
||||
};
|
||||
|
||||
boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo));
|
||||
ai_assert(subd);
|
||||
boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo));
|
||||
ai_assert(subd);
|
||||
|
||||
aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
|
||||
boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]());
|
||||
aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
|
||||
boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]());
|
||||
|
||||
subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
|
||||
std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
|
||||
subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true);
|
||||
std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes);
|
||||
|
||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
|
||||
orig_object.id.name,"`");
|
||||
ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `",
|
||||
orig_object.id.name,"`");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "BlenderIntermediate.h"
|
||||
#include "TinyFormatter.h"
|
||||
namespace Assimp {
|
||||
namespace Blender {
|
||||
namespace Blender {
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
/** Dummy base class for all blender modifiers. Modifiers are reused between imports, so
|
||||
|
@ -57,30 +57,30 @@ class BlenderModifier
|
|||
{
|
||||
public:
|
||||
|
||||
virtual ~BlenderModifier() {
|
||||
}
|
||||
virtual ~BlenderModifier() {
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
/** Check if *this* modifier is active, given a ModifierData& block.*/
|
||||
virtual bool IsActive( const ModifierData& /*modin*/) {
|
||||
return false;
|
||||
}
|
||||
// --------------------
|
||||
/** Check if *this* modifier is active, given a ModifierData& block.*/
|
||||
virtual bool IsActive( const ModifierData& /*modin*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------
|
||||
/** Apply the modifier to a given output node. The original data used
|
||||
* to construct the node is given as well. Not called unless IsActive()
|
||||
* was called and gave positive response. */
|
||||
virtual void DoIt(aiNode& /*out*/,
|
||||
ConversionData& /*conv_data*/,
|
||||
const ElemBase& orig_modifier,
|
||||
const Scene& /*in*/,
|
||||
const Object& /*orig_object*/
|
||||
) {
|
||||
DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type));
|
||||
return;
|
||||
}
|
||||
// --------------------
|
||||
/** Apply the modifier to a given output node. The original data used
|
||||
* to construct the node is given as well. Not called unless IsActive()
|
||||
* was called and gave positive response. */
|
||||
virtual void DoIt(aiNode& /*out*/,
|
||||
ConversionData& /*conv_data*/,
|
||||
const ElemBase& orig_modifier,
|
||||
const Scene& /*in*/,
|
||||
const Object& /*orig_object*/
|
||||
) {
|
||||
DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -91,17 +91,17 @@ class BlenderModifierShowcase
|
|||
{
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
/** Apply all requested modifiers provided we support them. */
|
||||
void ApplyModifiers(aiNode& out,
|
||||
ConversionData& conv_data,
|
||||
const Scene& in,
|
||||
const Object& orig_object
|
||||
);
|
||||
// --------------------
|
||||
/** Apply all requested modifiers provided we support them. */
|
||||
void ApplyModifiers(aiNode& out,
|
||||
ConversionData& conv_data,
|
||||
const Scene& in,
|
||||
const Object& orig_object
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
TempArray< std::vector,BlenderModifier > cached_modifiers;
|
||||
TempArray< std::vector,BlenderModifier > cached_modifiers;
|
||||
};
|
||||
|
||||
|
||||
|
@ -119,16 +119,16 @@ class BlenderModifier_Mirror : public BlenderModifier
|
|||
{
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
virtual bool IsActive( const ModifierData& modin);
|
||||
// --------------------
|
||||
virtual bool IsActive( const ModifierData& modin);
|
||||
|
||||
// --------------------
|
||||
virtual void DoIt(aiNode& out,
|
||||
ConversionData& conv_data,
|
||||
const ElemBase& orig_modifier,
|
||||
const Scene& in,
|
||||
const Object& orig_object
|
||||
) ;
|
||||
// --------------------
|
||||
virtual void DoIt(aiNode& out,
|
||||
ConversionData& conv_data,
|
||||
const ElemBase& orig_modifier,
|
||||
const Scene& in,
|
||||
const Object& orig_object
|
||||
) ;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
@ -138,16 +138,16 @@ class BlenderModifier_Subdivision : public BlenderModifier
|
|||
{
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
virtual bool IsActive( const ModifierData& modin);
|
||||
// --------------------
|
||||
virtual bool IsActive( const ModifierData& modin);
|
||||
|
||||
// --------------------
|
||||
virtual void DoIt(aiNode& out,
|
||||
ConversionData& conv_data,
|
||||
const ElemBase& orig_modifier,
|
||||
const Scene& in,
|
||||
const Object& orig_object
|
||||
) ;
|
||||
// --------------------
|
||||
virtual void DoIt(aiNode& out,
|
||||
ConversionData& conv_data,
|
||||
const ElemBase& orig_modifier,
|
||||
const Scene& in,
|
||||
const Object& orig_object
|
||||
) ;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ template <> void Structure :: Convert<Object> (
|
|||
ReadFieldPtr<ErrorPolicy_Fail>(dest.data,"*data",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.modifiers,"modifiers",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -90,7 +90,7 @@ template <> void Structure :: Convert<Group> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.layer,"layer",db);
|
||||
ReadFieldPtr<ErrorPolicy_Igno>(dest.gobject,"*gobject",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -129,7 +129,7 @@ template <> void Structure :: Convert<MTex> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.hardfac,"hardfac",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.norfac,"norfac",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -146,7 +146,7 @@ template <> void Structure :: Convert<TFace> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -162,7 +162,7 @@ template <> void Structure :: Convert<SubsurfModifierData> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.renderLevels,"renderLevels",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -179,7 +179,7 @@ template <> void Structure :: Convert<MFace> (
|
|||
ReadField<ErrorPolicy_Fail>(dest.mat_nr,"mat_nr",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -207,7 +207,7 @@ template <> void Structure :: Convert<Lamp> (
|
|||
ReadField<ErrorPolicy_Igno>((int&)dest.falloff_type,"falloff_type",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.sun_brightness,"sun_brightness",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -220,7 +220,7 @@ template <> void Structure :: Convert<MDeformWeight> (
|
|||
ReadField<ErrorPolicy_Fail>(dest.def_nr,"def_nr",db);
|
||||
ReadField<ErrorPolicy_Fail>(dest.weight,"weight",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -234,7 +234,7 @@ template <> void Structure :: Convert<PackedFile> (
|
|||
ReadField<ErrorPolicy_Warn>(dest.seek,"seek",db);
|
||||
ReadFieldPtr<ErrorPolicy_Warn>(dest.data,"*data",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -243,36 +243,36 @@ template <> void Structure :: Convert<Base> (
|
|||
const FileDatabase& db
|
||||
) const
|
||||
{
|
||||
// note: as per https://github.com/assimp/assimp/issues/128,
|
||||
// reading the Object linked list recursively is prone to stack overflow.
|
||||
// This structure converter is therefore an hand-written exception that
|
||||
// does it iteratively.
|
||||
// note: as per https://github.com/assimp/assimp/issues/128,
|
||||
// reading the Object linked list recursively is prone to stack overflow.
|
||||
// This structure converter is therefore an hand-written exception that
|
||||
// does it iteratively.
|
||||
|
||||
const int initial_pos = db.reader->GetCurrentPos();
|
||||
const int initial_pos = db.reader->GetCurrentPos();
|
||||
|
||||
std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
|
||||
for ( ;; ) {
|
||||
std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
|
||||
for ( ;; ) {
|
||||
|
||||
Base& cur_dest = *todo.first;
|
||||
db.reader->SetCurrentPos(todo.second);
|
||||
Base& cur_dest = *todo.first;
|
||||
db.reader->SetCurrentPos(todo.second);
|
||||
|
||||
// we know that this is a double-linked, circular list which we never
|
||||
// traverse backwards, so don't bother resolving the back links.
|
||||
cur_dest.prev = NULL;
|
||||
// we know that this is a double-linked, circular list which we never
|
||||
// traverse backwards, so don't bother resolving the back links.
|
||||
cur_dest.prev = NULL;
|
||||
|
||||
ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
|
||||
ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
|
||||
|
||||
// the return value of ReadFieldPtr indicates whether the object
|
||||
// was already cached. In this case, we don't need to resolve
|
||||
// it again.
|
||||
if(!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next,"*next",db, true) && cur_dest.next) {
|
||||
todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// the return value of ReadFieldPtr indicates whether the object
|
||||
// was already cached. In this case, we don't need to resolve
|
||||
// it again.
|
||||
if(!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next,"*next",db, true) && cur_dest.next) {
|
||||
todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
db.reader->SetCurrentPos(initial_pos + size);
|
||||
db.reader->SetCurrentPos(initial_pos + size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -288,7 +288,7 @@ template <> void Structure :: Convert<MTFace> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -324,7 +324,7 @@ template <> void Structure :: Convert<Material> (
|
|||
ReadField<ErrorPolicy_Warn>(dest.spec_shader,"spec_shader",db);
|
||||
ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex,"*mtex",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -345,7 +345,7 @@ template <> void Structure :: Convert<MTexPoly> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.pad,"pad",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -379,7 +379,7 @@ template <> void Structure :: Convert<Mesh> (
|
|||
ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db);
|
||||
ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -392,7 +392,7 @@ template <> void Structure :: Convert<MDeformVert> (
|
|||
ReadFieldPtr<ErrorPolicy_Warn>(dest.dw,"*dw",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.totweight,"totweight",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -404,7 +404,7 @@ template <> void Structure :: Convert<World> (
|
|||
|
||||
ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -419,7 +419,7 @@ template <> void Structure :: Convert<MLoopCol> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.b,"b",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.a,"a",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -435,7 +435,7 @@ template <> void Structure :: Convert<MVert> (
|
|||
ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -451,7 +451,7 @@ template <> void Structure :: Convert<MEdge> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -464,7 +464,7 @@ template <> void Structure :: Convert<MLoopUV> (
|
|||
ReadFieldArray<ErrorPolicy_Igno>(dest.uv,"uv",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -478,7 +478,7 @@ template <> void Structure :: Convert<GroupObject> (
|
|||
ReadFieldPtr<ErrorPolicy_Fail>(dest.next,"*next",db);
|
||||
ReadFieldPtr<ErrorPolicy_Igno>(dest.ob,"*ob",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -491,7 +491,7 @@ template <> void Structure :: Convert<ListBase> (
|
|||
ReadFieldPtr<ErrorPolicy_Igno>(dest.first,"*first",db);
|
||||
ReadFieldPtr<ErrorPolicy_Igno>(dest.last,"*last",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -504,7 +504,7 @@ template <> void Structure :: Convert<MLoop> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.v,"v",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.e,"e",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -520,7 +520,7 @@ template <> void Structure :: Convert<ModifierData> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db);
|
||||
ReadFieldArray<ErrorPolicy_Igno>(dest.name,"name",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -533,7 +533,7 @@ template <> void Structure :: Convert<ID> (
|
|||
ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -548,7 +548,7 @@ template <> void Structure :: Convert<MCol> (
|
|||
ReadField<ErrorPolicy_Fail>(dest.b,"b",db);
|
||||
ReadField<ErrorPolicy_Fail>(dest.a,"a",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -563,7 +563,7 @@ template <> void Structure :: Convert<MPoly> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.mat_nr,"mat_nr",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -579,7 +579,7 @@ template <> void Structure :: Convert<Scene> (
|
|||
ReadFieldPtr<ErrorPolicy_Warn>(dest.basact,"*basact",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.base,"base",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -594,7 +594,7 @@ template <> void Structure :: Convert<Library> (
|
|||
ReadFieldArray<ErrorPolicy_Fail>(dest.filename,"filename",db);
|
||||
ReadFieldPtr<ErrorPolicy_Warn>(dest.parent,"*parent",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -607,7 +607,7 @@ template <> void Structure :: Convert<Tex> (
|
|||
ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
|
||||
ReadFieldPtr<ErrorPolicy_Warn>(dest.ima,"*ima",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -622,7 +622,7 @@ template <> void Structure :: Convert<Camera> (
|
|||
ReadField<ErrorPolicy_Warn>((int&)dest.flag,"flag",db);
|
||||
ReadField<ErrorPolicy_Warn>(dest.angle,"angle",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -638,7 +638,7 @@ template <> void Structure :: Convert<MirrorModifierData> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.tolerance,"tolerance",db);
|
||||
ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob,"*mirror_ob",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@ -671,7 +671,7 @@ template <> void Structure :: Convert<Image> (
|
|||
ReadField<ErrorPolicy_Igno>(dest.gen_y,"gen_y",db);
|
||||
ReadField<ErrorPolicy_Igno>(dest.gen_type,"gen_type",db);
|
||||
|
||||
db.reader->IncPtr(size);
|
||||
db.reader->IncPtr(size);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
|
|
@ -46,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "BlenderDNA.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Blender {
|
||||
namespace Assimp {
|
||||
namespace Blender {
|
||||
|
||||
// Minor parts of this file are extracts from blender data structures,
|
||||
// declared in the ./source/blender/makesdna directory.
|
||||
|
@ -65,7 +65,7 @@ namespace Assimp {
|
|||
//
|
||||
// * Structures may include the primitive types char, int, short,
|
||||
// float, double. Signedness specifiers are not allowed on
|
||||
// integers. Enum types are allowed, but they must have been
|
||||
// integers. Enum types are allowed, but they must have been
|
||||
// defined in this header.
|
||||
//
|
||||
// * Structures may aggregate other structures, unless not defined
|
||||
|
@ -103,15 +103,15 @@ struct Image;
|
|||
// -------------------------------------------------------------------------------
|
||||
struct ID : ElemBase {
|
||||
|
||||
char name[24] WARN;
|
||||
short flag;
|
||||
char name[24] WARN;
|
||||
short flag;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct ListBase : ElemBase {
|
||||
|
||||
boost::shared_ptr<ElemBase> first;
|
||||
boost::shared_ptr<ElemBase> last;
|
||||
boost::shared_ptr<ElemBase> first;
|
||||
boost::shared_ptr<ElemBase> last;
|
||||
};
|
||||
|
||||
|
||||
|
@ -119,37 +119,37 @@ struct ListBase : ElemBase {
|
|||
struct PackedFile : ElemBase {
|
||||
int size WARN;
|
||||
int seek WARN;
|
||||
boost::shared_ptr< FileOffset > data WARN;
|
||||
boost::shared_ptr< FileOffset > data WARN;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct GroupObject : ElemBase {
|
||||
|
||||
boost::shared_ptr<GroupObject> prev,next FAIL;
|
||||
boost::shared_ptr<Object> ob;
|
||||
boost::shared_ptr<GroupObject> prev,next FAIL;
|
||||
boost::shared_ptr<Object> ob;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Group : ElemBase {
|
||||
ID id FAIL;
|
||||
int layer;
|
||||
ID id FAIL;
|
||||
int layer;
|
||||
|
||||
boost::shared_ptr<GroupObject> gobject;
|
||||
boost::shared_ptr<GroupObject> gobject;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct World : ElemBase {
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MVert : ElemBase {
|
||||
float co[3] FAIL;
|
||||
float no[3] FAIL;
|
||||
char flag;
|
||||
int mat_nr WARN;
|
||||
int bweight;
|
||||
float co[3] FAIL;
|
||||
float no[3] FAIL;
|
||||
char flag;
|
||||
int mat_nr WARN;
|
||||
int bweight;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -161,68 +161,68 @@ struct MEdge : ElemBase {
|
|||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MLoop : ElemBase {
|
||||
int v, e;
|
||||
int v, e;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MLoopUV : ElemBase {
|
||||
float uv[2];
|
||||
int flag;
|
||||
float uv[2];
|
||||
int flag;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Note that red and blue are not swapped, as with MCol
|
||||
struct MLoopCol : ElemBase {
|
||||
char r, g, b, a;
|
||||
char r, g, b, a;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MPoly : ElemBase {
|
||||
int loopstart;
|
||||
int totloop;
|
||||
short mat_nr;
|
||||
char flag;
|
||||
int loopstart;
|
||||
int totloop;
|
||||
short mat_nr;
|
||||
char flag;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MTexPoly : ElemBase {
|
||||
Image* tpage;
|
||||
char flag, transp;
|
||||
short mode, tile, pad;
|
||||
Image* tpage;
|
||||
char flag, transp;
|
||||
short mode, tile, pad;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MCol : ElemBase {
|
||||
char r,g,b,a FAIL;
|
||||
char r,g,b,a FAIL;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MFace : ElemBase {
|
||||
int v1,v2,v3,v4 FAIL;
|
||||
int mat_nr FAIL;
|
||||
char flag;
|
||||
int v1,v2,v3,v4 FAIL;
|
||||
int mat_nr FAIL;
|
||||
char flag;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct TFace : ElemBase {
|
||||
float uv[4][2] FAIL;
|
||||
int col[4] FAIL;
|
||||
char flag;
|
||||
short mode;
|
||||
short tile;
|
||||
short unwrap;
|
||||
float uv[4][2] FAIL;
|
||||
int col[4] FAIL;
|
||||
char flag;
|
||||
short mode;
|
||||
short tile;
|
||||
short unwrap;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MTFace : ElemBase {
|
||||
|
||||
float uv[4][2] FAIL;
|
||||
char flag;
|
||||
short mode;
|
||||
short tile;
|
||||
short unwrap;
|
||||
float uv[4][2] FAIL;
|
||||
char flag;
|
||||
short mode;
|
||||
short tile;
|
||||
short unwrap;
|
||||
|
||||
// boost::shared_ptr<Image> tpage;
|
||||
// boost::shared_ptr<Image> tpage;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
@ -234,124 +234,124 @@ struct MDeformWeight : ElemBase {
|
|||
// -------------------------------------------------------------------------------
|
||||
struct MDeformVert : ElemBase {
|
||||
|
||||
vector<MDeformWeight> dw WARN;
|
||||
int totweight;
|
||||
vector<MDeformWeight> dw WARN;
|
||||
int totweight;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Material : ElemBase {
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
float r,g,b WARN;
|
||||
float specr,specg,specb WARN;
|
||||
short har;
|
||||
float ambr,ambg,ambb WARN;
|
||||
float mirr,mirg,mirb;
|
||||
float emit WARN;
|
||||
float alpha WARN;
|
||||
float ref;
|
||||
float translucency;
|
||||
float roughness;
|
||||
float darkness;
|
||||
float refrac;
|
||||
float r,g,b WARN;
|
||||
float specr,specg,specb WARN;
|
||||
short har;
|
||||
float ambr,ambg,ambb WARN;
|
||||
float mirr,mirg,mirb;
|
||||
float emit WARN;
|
||||
float alpha WARN;
|
||||
float ref;
|
||||
float translucency;
|
||||
float roughness;
|
||||
float darkness;
|
||||
float refrac;
|
||||
|
||||
boost::shared_ptr<Group> group;
|
||||
boost::shared_ptr<Group> group;
|
||||
|
||||
short diff_shader WARN;
|
||||
short spec_shader WARN;
|
||||
short diff_shader WARN;
|
||||
short spec_shader WARN;
|
||||
|
||||
boost::shared_ptr<MTex> mtex[18];
|
||||
boost::shared_ptr<MTex> mtex[18];
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Mesh : ElemBase {
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
int totface FAIL;
|
||||
int totedge FAIL;
|
||||
int totvert FAIL;
|
||||
int totloop;
|
||||
int totpoly;
|
||||
int totface FAIL;
|
||||
int totedge FAIL;
|
||||
int totvert FAIL;
|
||||
int totloop;
|
||||
int totpoly;
|
||||
|
||||
short subdiv;
|
||||
short subdivr;
|
||||
short subsurftype;
|
||||
short smoothresh;
|
||||
short subdiv;
|
||||
short subdivr;
|
||||
short subsurftype;
|
||||
short smoothresh;
|
||||
|
||||
vector<MFace> mface FAIL;
|
||||
vector<MTFace> mtface;
|
||||
vector<TFace> tface;
|
||||
vector<MVert> mvert FAIL;
|
||||
vector<MEdge> medge WARN;
|
||||
vector<MLoop> mloop;
|
||||
vector<MLoopUV> mloopuv;
|
||||
vector<MLoopCol> mloopcol;
|
||||
vector<MPoly> mpoly;
|
||||
vector<MTexPoly> mtpoly;
|
||||
vector<MDeformVert> dvert;
|
||||
vector<MCol> mcol;
|
||||
vector<MFace> mface FAIL;
|
||||
vector<MTFace> mtface;
|
||||
vector<TFace> tface;
|
||||
vector<MVert> mvert FAIL;
|
||||
vector<MEdge> medge WARN;
|
||||
vector<MLoop> mloop;
|
||||
vector<MLoopUV> mloopuv;
|
||||
vector<MLoopCol> mloopcol;
|
||||
vector<MPoly> mpoly;
|
||||
vector<MTexPoly> mtpoly;
|
||||
vector<MDeformVert> dvert;
|
||||
vector<MCol> mcol;
|
||||
|
||||
vector< boost::shared_ptr<Material> > mat FAIL;
|
||||
vector< boost::shared_ptr<Material> > mat FAIL;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Library : ElemBase {
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
char name[240] WARN;
|
||||
char filename[240] FAIL;
|
||||
boost::shared_ptr<Library> parent WARN;
|
||||
char name[240] WARN;
|
||||
char filename[240] FAIL;
|
||||
boost::shared_ptr<Library> parent WARN;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Camera : ElemBase {
|
||||
enum Type {
|
||||
Type_PERSP = 0
|
||||
,Type_ORTHO = 1
|
||||
};
|
||||
enum Type {
|
||||
Type_PERSP = 0
|
||||
,Type_ORTHO = 1
|
||||
};
|
||||
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
// struct AnimData *adt;
|
||||
// struct AnimData *adt;
|
||||
|
||||
Type type,flag WARN;
|
||||
float angle WARN;
|
||||
//float passepartalpha, angle;
|
||||
//float clipsta, clipend;
|
||||
//float lens, ortho_scale, drawsize;
|
||||
//float shiftx, shifty;
|
||||
Type type,flag WARN;
|
||||
float angle WARN;
|
||||
//float passepartalpha, angle;
|
||||
//float clipsta, clipend;
|
||||
//float lens, ortho_scale, drawsize;
|
||||
//float shiftx, shifty;
|
||||
|
||||
//float YF_dofdist, YF_aperture;
|
||||
//short YF_bkhtype, YF_bkhbias;
|
||||
//float YF_bkhrot;
|
||||
//float YF_dofdist, YF_aperture;
|
||||
//short YF_bkhtype, YF_bkhbias;
|
||||
//float YF_bkhrot;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Lamp : ElemBase {
|
||||
|
||||
enum FalloffType {
|
||||
FalloffType_Constant = 0x0
|
||||
,FalloffType_InvLinear = 0x1
|
||||
,FalloffType_InvSquare = 0x2
|
||||
//,FalloffType_Curve = 0x3
|
||||
//,FalloffType_Sliders = 0x4
|
||||
};
|
||||
enum FalloffType {
|
||||
FalloffType_Constant = 0x0
|
||||
,FalloffType_InvLinear = 0x1
|
||||
,FalloffType_InvSquare = 0x2
|
||||
//,FalloffType_Curve = 0x3
|
||||
//,FalloffType_Sliders = 0x4
|
||||
};
|
||||
|
||||
enum Type {
|
||||
Type_Local = 0x0
|
||||
,Type_Sun = 0x1
|
||||
,Type_Spot = 0x2
|
||||
,Type_Hemi = 0x3
|
||||
,Type_Area = 0x4
|
||||
//,Type_YFPhoton = 0x5
|
||||
};
|
||||
enum Type {
|
||||
Type_Local = 0x0
|
||||
,Type_Sun = 0x1
|
||||
,Type_Spot = 0x2
|
||||
,Type_Hemi = 0x3
|
||||
,Type_Area = 0x4
|
||||
//,Type_YFPhoton = 0x5
|
||||
};
|
||||
|
||||
ID id FAIL;
|
||||
//AnimData *adt;
|
||||
|
||||
Type type FAIL;
|
||||
short flags;
|
||||
short flags;
|
||||
|
||||
//int mode;
|
||||
|
||||
|
@ -374,33 +374,33 @@ struct Lamp : ElemBase {
|
|||
//short ray_samp, ray_sampy, ray_sampz;
|
||||
//short ray_samp_type;
|
||||
//short area_shape;
|
||||
//float area_size, area_sizey, area_sizez;
|
||||
//float adapt_thresh;
|
||||
//short ray_samp_method;
|
||||
//float area_size, area_sizey, area_sizez;
|
||||
//float adapt_thresh;
|
||||
//short ray_samp_method;
|
||||
|
||||
//short texact, shadhalostep;
|
||||
//short texact, shadhalostep;
|
||||
|
||||
//short sun_effect_type;
|
||||
//short skyblendtype;
|
||||
//float horizon_brightness;
|
||||
//float spread;
|
||||
float sun_brightness;
|
||||
//float sun_size;
|
||||
//float backscattered_light;
|
||||
//float sun_intensity;
|
||||
//float atm_turbidity;
|
||||
//float atm_inscattering_factor;
|
||||
//float atm_extinction_factor;
|
||||
//float atm_distance_factor;
|
||||
//float skyblendfac;
|
||||
//float sky_exposure;
|
||||
//short sky_colorspace;
|
||||
//short sun_effect_type;
|
||||
//short skyblendtype;
|
||||
//float horizon_brightness;
|
||||
//float spread;
|
||||
float sun_brightness;
|
||||
//float sun_size;
|
||||
//float backscattered_light;
|
||||
//float sun_intensity;
|
||||
//float atm_turbidity;
|
||||
//float atm_inscattering_factor;
|
||||
//float atm_extinction_factor;
|
||||
//float atm_distance_factor;
|
||||
//float skyblendfac;
|
||||
//float sky_exposure;
|
||||
//short sky_colorspace;
|
||||
|
||||
// int YF_numphotons, YF_numsearch;
|
||||
// short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
|
||||
// float YF_causticblur, YF_ltradius;
|
||||
// int YF_numphotons, YF_numsearch;
|
||||
// short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
|
||||
// float YF_causticblur, YF_ltradius;
|
||||
|
||||
// float YF_glowint, YF_glowofs;
|
||||
// float YF_glowint, YF_glowofs;
|
||||
// short YF_glowtype, YF_pad2;
|
||||
|
||||
//struct Ipo *ipo;
|
||||
|
@ -412,7 +412,7 @@ struct Lamp : ElemBase {
|
|||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct ModifierData : ElemBase {
|
||||
enum ModifierType {
|
||||
enum ModifierType {
|
||||
eModifierType_None = 0,
|
||||
eModifierType_Subsurf,
|
||||
eModifierType_Lattice,
|
||||
|
@ -446,314 +446,314 @@ struct ModifierData : ElemBase {
|
|||
eModifierType_Surface,
|
||||
eModifierType_Smoke,
|
||||
eModifierType_ShapeKey
|
||||
};
|
||||
};
|
||||
|
||||
boost::shared_ptr<ElemBase> next WARN;
|
||||
boost::shared_ptr<ElemBase> prev WARN;
|
||||
boost::shared_ptr<ElemBase> next WARN;
|
||||
boost::shared_ptr<ElemBase> prev WARN;
|
||||
|
||||
int type, mode;
|
||||
char name[32];
|
||||
int type, mode;
|
||||
char name[32];
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct SubsurfModifierData : ElemBase {
|
||||
|
||||
enum Type {
|
||||
enum Type {
|
||||
|
||||
TYPE_CatmullClarke = 0x0,
|
||||
TYPE_Simple = 0x1
|
||||
};
|
||||
TYPE_CatmullClarke = 0x0,
|
||||
TYPE_Simple = 0x1
|
||||
};
|
||||
|
||||
enum Flags {
|
||||
// some omitted
|
||||
FLAGS_SubsurfUV =1<<3
|
||||
};
|
||||
enum Flags {
|
||||
// some omitted
|
||||
FLAGS_SubsurfUV =1<<3
|
||||
};
|
||||
|
||||
ModifierData modifier FAIL;
|
||||
short subdivType WARN;
|
||||
short levels FAIL;
|
||||
short renderLevels ;
|
||||
short flags;
|
||||
ModifierData modifier FAIL;
|
||||
short subdivType WARN;
|
||||
short levels FAIL;
|
||||
short renderLevels ;
|
||||
short flags;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MirrorModifierData : ElemBase {
|
||||
|
||||
enum Flags {
|
||||
Flags_CLIPPING =1<<0,
|
||||
Flags_MIRROR_U =1<<1,
|
||||
Flags_MIRROR_V =1<<2,
|
||||
Flags_AXIS_X =1<<3,
|
||||
Flags_AXIS_Y =1<<4,
|
||||
Flags_AXIS_Z =1<<5,
|
||||
Flags_VGROUP =1<<6
|
||||
};
|
||||
enum Flags {
|
||||
Flags_CLIPPING =1<<0,
|
||||
Flags_MIRROR_U =1<<1,
|
||||
Flags_MIRROR_V =1<<2,
|
||||
Flags_AXIS_X =1<<3,
|
||||
Flags_AXIS_Y =1<<4,
|
||||
Flags_AXIS_Z =1<<5,
|
||||
Flags_VGROUP =1<<6
|
||||
};
|
||||
|
||||
ModifierData modifier FAIL;
|
||||
ModifierData modifier FAIL;
|
||||
|
||||
short axis, flag;
|
||||
float tolerance;
|
||||
boost::shared_ptr<Object> mirror_ob;
|
||||
short axis, flag;
|
||||
float tolerance;
|
||||
boost::shared_ptr<Object> mirror_ob;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Object : ElemBase {
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
enum Type {
|
||||
Type_EMPTY = 0
|
||||
,Type_MESH = 1
|
||||
,Type_CURVE = 2
|
||||
,Type_SURF = 3
|
||||
,Type_FONT = 4
|
||||
,Type_MBALL = 5
|
||||
enum Type {
|
||||
Type_EMPTY = 0
|
||||
,Type_MESH = 1
|
||||
,Type_CURVE = 2
|
||||
,Type_SURF = 3
|
||||
,Type_FONT = 4
|
||||
,Type_MBALL = 5
|
||||
|
||||
,Type_LAMP = 10
|
||||
,Type_CAMERA = 11
|
||||
,Type_LAMP = 10
|
||||
,Type_CAMERA = 11
|
||||
|
||||
,Type_WAVE = 21
|
||||
,Type_LATTICE = 22
|
||||
};
|
||||
,Type_WAVE = 21
|
||||
,Type_LATTICE = 22
|
||||
};
|
||||
|
||||
Type type FAIL;
|
||||
float obmat[4][4] WARN;
|
||||
float parentinv[4][4] WARN;
|
||||
char parsubstr[32] WARN;
|
||||
Type type FAIL;
|
||||
float obmat[4][4] WARN;
|
||||
float parentinv[4][4] WARN;
|
||||
char parsubstr[32] WARN;
|
||||
|
||||
Object* parent WARN;
|
||||
boost::shared_ptr<Object> track WARN;
|
||||
Object* parent WARN;
|
||||
boost::shared_ptr<Object> track WARN;
|
||||
|
||||
boost::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
|
||||
boost::shared_ptr<Group> dup_group WARN;
|
||||
boost::shared_ptr<ElemBase> data FAIL;
|
||||
boost::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
|
||||
boost::shared_ptr<Group> dup_group WARN;
|
||||
boost::shared_ptr<ElemBase> data FAIL;
|
||||
|
||||
ListBase modifiers;
|
||||
ListBase modifiers;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Base : ElemBase {
|
||||
Base* prev WARN;
|
||||
boost::shared_ptr<Base> next WARN;
|
||||
boost::shared_ptr<Object> object WARN;
|
||||
Base* prev WARN;
|
||||
boost::shared_ptr<Base> next WARN;
|
||||
boost::shared_ptr<Object> object WARN;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Scene : ElemBase {
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
boost::shared_ptr<Object> camera WARN;
|
||||
boost::shared_ptr<World> world WARN;
|
||||
boost::shared_ptr<Base> basact WARN;
|
||||
boost::shared_ptr<Object> camera WARN;
|
||||
boost::shared_ptr<World> world WARN;
|
||||
boost::shared_ptr<Base> basact WARN;
|
||||
|
||||
ListBase base;
|
||||
ListBase base;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Image : ElemBase {
|
||||
ID id FAIL;
|
||||
ID id FAIL;
|
||||
|
||||
char name[240] WARN;
|
||||
char name[240] WARN;
|
||||
|
||||
//struct anim *anim;
|
||||
//struct anim *anim;
|
||||
|
||||
short ok, flag;
|
||||
short source, type, pad, pad1;
|
||||
int lastframe;
|
||||
short ok, flag;
|
||||
short source, type, pad, pad1;
|
||||
int lastframe;
|
||||
|
||||
short tpageflag, totbind;
|
||||
short xrep, yrep;
|
||||
short twsta, twend;
|
||||
//unsigned int bindcode;
|
||||
//unsigned int *repbind;
|
||||
short tpageflag, totbind;
|
||||
short xrep, yrep;
|
||||
short twsta, twend;
|
||||
//unsigned int bindcode;
|
||||
//unsigned int *repbind;
|
||||
|
||||
boost::shared_ptr<PackedFile> packedfile;
|
||||
//struct PreviewImage * preview;
|
||||
boost::shared_ptr<PackedFile> packedfile;
|
||||
//struct PreviewImage * preview;
|
||||
|
||||
float lastupdate;
|
||||
int lastused;
|
||||
short animspeed;
|
||||
float lastupdate;
|
||||
int lastused;
|
||||
short animspeed;
|
||||
|
||||
short gen_x, gen_y, gen_type;
|
||||
short gen_x, gen_y, gen_type;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct Tex : ElemBase {
|
||||
|
||||
// actually, the only texture type we support is Type_IMAGE
|
||||
enum Type {
|
||||
Type_CLOUDS = 1
|
||||
,Type_WOOD = 2
|
||||
,Type_MARBLE = 3
|
||||
,Type_MAGIC = 4
|
||||
,Type_BLEND = 5
|
||||
,Type_STUCCI = 6
|
||||
,Type_NOISE = 7
|
||||
,Type_IMAGE = 8
|
||||
,Type_PLUGIN = 9
|
||||
,Type_ENVMAP = 10
|
||||
,Type_MUSGRAVE = 11
|
||||
,Type_VORONOI = 12
|
||||
,Type_DISTNOISE = 13
|
||||
,Type_POINTDENSITY = 14
|
||||
,Type_VOXELDATA = 15
|
||||
};
|
||||
// actually, the only texture type we support is Type_IMAGE
|
||||
enum Type {
|
||||
Type_CLOUDS = 1
|
||||
,Type_WOOD = 2
|
||||
,Type_MARBLE = 3
|
||||
,Type_MAGIC = 4
|
||||
,Type_BLEND = 5
|
||||
,Type_STUCCI = 6
|
||||
,Type_NOISE = 7
|
||||
,Type_IMAGE = 8
|
||||
,Type_PLUGIN = 9
|
||||
,Type_ENVMAP = 10
|
||||
,Type_MUSGRAVE = 11
|
||||
,Type_VORONOI = 12
|
||||
,Type_DISTNOISE = 13
|
||||
,Type_POINTDENSITY = 14
|
||||
,Type_VOXELDATA = 15
|
||||
};
|
||||
|
||||
enum ImageFlags {
|
||||
ImageFlags_INTERPOL = 1
|
||||
,ImageFlags_USEALPHA = 2
|
||||
,ImageFlags_MIPMAP = 4
|
||||
,ImageFlags_IMAROT = 16
|
||||
,ImageFlags_CALCALPHA = 32
|
||||
,ImageFlags_NORMALMAP = 2048
|
||||
,ImageFlags_GAUSS_MIP = 4096
|
||||
,ImageFlags_FILTER_MIN = 8192
|
||||
,ImageFlags_DERIVATIVEMAP = 16384
|
||||
};
|
||||
enum ImageFlags {
|
||||
ImageFlags_INTERPOL = 1
|
||||
,ImageFlags_USEALPHA = 2
|
||||
,ImageFlags_MIPMAP = 4
|
||||
,ImageFlags_IMAROT = 16
|
||||
,ImageFlags_CALCALPHA = 32
|
||||
,ImageFlags_NORMALMAP = 2048
|
||||
,ImageFlags_GAUSS_MIP = 4096
|
||||
,ImageFlags_FILTER_MIN = 8192
|
||||
,ImageFlags_DERIVATIVEMAP = 16384
|
||||
};
|
||||
|
||||
ID id FAIL;
|
||||
// AnimData *adt;
|
||||
ID id FAIL;
|
||||
// AnimData *adt;
|
||||
|
||||
//float noisesize, turbul;
|
||||
//float bright, contrast, rfac, gfac, bfac;
|
||||
//float filtersize;
|
||||
//float noisesize, turbul;
|
||||
//float bright, contrast, rfac, gfac, bfac;
|
||||
//float filtersize;
|
||||
|
||||
//float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain;
|
||||
//float dist_amount, ns_outscale;
|
||||
//float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain;
|
||||
//float dist_amount, ns_outscale;
|
||||
|
||||
//float vn_w1;
|
||||
//float vn_w2;
|
||||
//float vn_w3;
|
||||
//float vn_w4;
|
||||
//float vn_mexp;
|
||||
//short vn_distm, vn_coltype;
|
||||
//float vn_w1;
|
||||
//float vn_w2;
|
||||
//float vn_w3;
|
||||
//float vn_w4;
|
||||
//float vn_mexp;
|
||||
//short vn_distm, vn_coltype;
|
||||
|
||||
//short noisedepth, noisetype;
|
||||
//short noisebasis, noisebasis2;
|
||||
//short noisedepth, noisetype;
|
||||
//short noisebasis, noisebasis2;
|
||||
|
||||
//short flag;
|
||||
ImageFlags imaflag;
|
||||
Type type FAIL;
|
||||
//short stype;
|
||||
//short flag;
|
||||
ImageFlags imaflag;
|
||||
Type type FAIL;
|
||||
//short stype;
|
||||
|
||||
//float cropxmin, cropymin, cropxmax, cropymax;
|
||||
//int texfilter;
|
||||
//int afmax;
|
||||
//short xrepeat, yrepeat;
|
||||
//short extend;
|
||||
//float cropxmin, cropymin, cropxmax, cropymax;
|
||||
//int texfilter;
|
||||
//int afmax;
|
||||
//short xrepeat, yrepeat;
|
||||
//short extend;
|
||||
|
||||
//short fie_ima;
|
||||
//int len;
|
||||
//int frames, offset, sfra;
|
||||
//short fie_ima;
|
||||
//int len;
|
||||
//int frames, offset, sfra;
|
||||
|
||||
//float checkerdist, nabla;
|
||||
//float norfac;
|
||||
//float checkerdist, nabla;
|
||||
//float norfac;
|
||||
|
||||
//ImageUser iuser;
|
||||
//ImageUser iuser;
|
||||
|
||||
//bNodeTree *nodetree;
|
||||
//Ipo *ipo;
|
||||
boost::shared_ptr<Image> ima WARN;
|
||||
//PluginTex *plugin;
|
||||
//ColorBand *coba;
|
||||
//EnvMap *env;
|
||||
//PreviewImage * preview;
|
||||
//PointDensity *pd;
|
||||
//VoxelData *vd;
|
||||
//bNodeTree *nodetree;
|
||||
//Ipo *ipo;
|
||||
boost::shared_ptr<Image> ima WARN;
|
||||
//PluginTex *plugin;
|
||||
//ColorBand *coba;
|
||||
//EnvMap *env;
|
||||
//PreviewImage * preview;
|
||||
//PointDensity *pd;
|
||||
//VoxelData *vd;
|
||||
|
||||
//char use_nodes;
|
||||
//char use_nodes;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
struct MTex : ElemBase {
|
||||
|
||||
enum Projection {
|
||||
Proj_N = 0
|
||||
,Proj_X = 1
|
||||
,Proj_Y = 2
|
||||
,Proj_Z = 3
|
||||
};
|
||||
enum Projection {
|
||||
Proj_N = 0
|
||||
,Proj_X = 1
|
||||
,Proj_Y = 2
|
||||
,Proj_Z = 3
|
||||
};
|
||||
|
||||
enum Flag {
|
||||
Flag_RGBTOINT = 0x1
|
||||
,Flag_STENCIL = 0x2
|
||||
,Flag_NEGATIVE = 0x4
|
||||
,Flag_ALPHAMIX = 0x8
|
||||
,Flag_VIEWSPACE = 0x10
|
||||
};
|
||||
enum Flag {
|
||||
Flag_RGBTOINT = 0x1
|
||||
,Flag_STENCIL = 0x2
|
||||
,Flag_NEGATIVE = 0x4
|
||||
,Flag_ALPHAMIX = 0x8
|
||||
,Flag_VIEWSPACE = 0x10
|
||||
};
|
||||
|
||||
enum BlendType {
|
||||
BlendType_BLEND = 0
|
||||
,BlendType_MUL = 1
|
||||
,BlendType_ADD = 2
|
||||
,BlendType_SUB = 3
|
||||
,BlendType_DIV = 4
|
||||
,BlendType_DARK = 5
|
||||
,BlendType_DIFF = 6
|
||||
,BlendType_LIGHT = 7
|
||||
,BlendType_SCREEN = 8
|
||||
,BlendType_OVERLAY = 9
|
||||
,BlendType_BLEND_HUE = 10
|
||||
,BlendType_BLEND_SAT = 11
|
||||
,BlendType_BLEND_VAL = 12
|
||||
,BlendType_BLEND_COLOR = 13
|
||||
};
|
||||
enum BlendType {
|
||||
BlendType_BLEND = 0
|
||||
,BlendType_MUL = 1
|
||||
,BlendType_ADD = 2
|
||||
,BlendType_SUB = 3
|
||||
,BlendType_DIV = 4
|
||||
,BlendType_DARK = 5
|
||||
,BlendType_DIFF = 6
|
||||
,BlendType_LIGHT = 7
|
||||
,BlendType_SCREEN = 8
|
||||
,BlendType_OVERLAY = 9
|
||||
,BlendType_BLEND_HUE = 10
|
||||
,BlendType_BLEND_SAT = 11
|
||||
,BlendType_BLEND_VAL = 12
|
||||
,BlendType_BLEND_COLOR = 13
|
||||
};
|
||||
|
||||
enum MapType {
|
||||
MapType_COL = 1
|
||||
,MapType_NORM = 2
|
||||
,MapType_COLSPEC = 4
|
||||
,MapType_COLMIR = 8
|
||||
,MapType_REF = 16
|
||||
,MapType_SPEC = 32
|
||||
,MapType_EMIT = 64
|
||||
,MapType_ALPHA = 128
|
||||
,MapType_HAR = 256
|
||||
,MapType_RAYMIRR = 512
|
||||
,MapType_TRANSLU = 1024
|
||||
,MapType_AMB = 2048
|
||||
,MapType_DISPLACE = 4096
|
||||
,MapType_WARP = 8192
|
||||
};
|
||||
enum MapType {
|
||||
MapType_COL = 1
|
||||
,MapType_NORM = 2
|
||||
,MapType_COLSPEC = 4
|
||||
,MapType_COLMIR = 8
|
||||
,MapType_REF = 16
|
||||
,MapType_SPEC = 32
|
||||
,MapType_EMIT = 64
|
||||
,MapType_ALPHA = 128
|
||||
,MapType_HAR = 256
|
||||
,MapType_RAYMIRR = 512
|
||||
,MapType_TRANSLU = 1024
|
||||
,MapType_AMB = 2048
|
||||
,MapType_DISPLACE = 4096
|
||||
,MapType_WARP = 8192
|
||||
};
|
||||
|
||||
// short texco, maptoneg;
|
||||
MapType mapto;
|
||||
// short texco, maptoneg;
|
||||
MapType mapto;
|
||||
|
||||
BlendType blendtype;
|
||||
boost::shared_ptr<Object> object;
|
||||
boost::shared_ptr<Tex> tex;
|
||||
char uvname[32];
|
||||
BlendType blendtype;
|
||||
boost::shared_ptr<Object> object;
|
||||
boost::shared_ptr<Tex> tex;
|
||||
char uvname[32];
|
||||
|
||||
Projection projx,projy,projz;
|
||||
char mapping;
|
||||
float ofs[3], size[3], rot;
|
||||
Projection projx,projy,projz;
|
||||
char mapping;
|
||||
float ofs[3], size[3], rot;
|
||||
|
||||
int texflag;
|
||||
short colormodel, pmapto, pmaptoneg;
|
||||
//short normapspace, which_output;
|
||||
//char brush_map_mode;
|
||||
float r,g,b,k WARN;
|
||||
//float def_var, rt;
|
||||
int texflag;
|
||||
short colormodel, pmapto, pmaptoneg;
|
||||
//short normapspace, which_output;
|
||||
//char brush_map_mode;
|
||||
float r,g,b,k WARN;
|
||||
//float def_var, rt;
|
||||
|
||||
//float colfac, varfac;
|
||||
//float colfac, varfac;
|
||||
|
||||
float norfac;
|
||||
//float dispfac, warpfac;
|
||||
float colspecfac, mirrfac, alphafac;
|
||||
float difffac, specfac, emitfac, hardfac;
|
||||
//float raymirrfac, translfac, ambfac;
|
||||
//float colemitfac, colreflfac, coltransfac;
|
||||
//float densfac, scatterfac, reflfac;
|
||||
float norfac;
|
||||
//float dispfac, warpfac;
|
||||
float colspecfac, mirrfac, alphafac;
|
||||
float difffac, specfac, emitfac, hardfac;
|
||||
//float raymirrfac, translfac, ambfac;
|
||||
//float colemitfac, colreflfac, coltransfac;
|
||||
//float densfac, scatterfac, reflfac;
|
||||
|
||||
//float timefac, lengthfac, clumpfac;
|
||||
//float kinkfac, roughfac, padensfac;
|
||||
//float lifefac, sizefac, ivelfac, pvelfac;
|
||||
//float shadowfac;
|
||||
//float zenupfac, zendownfac, blendfac;
|
||||
//float timefac, lengthfac, clumpfac;
|
||||
//float kinkfac, roughfac, padensfac;
|
||||
//float lifefac, sizefac, ivelfac, pvelfac;
|
||||
//float shadowfac;
|
||||
//float zenupfac, zendownfac, blendfac;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -47,8 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "BlenderDNA.h"
|
||||
#include "BlenderScene.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Blender {
|
||||
namespace Assimp {
|
||||
namespace Blender {
|
||||
|
||||
|
||||
template <> void Structure :: Convert<Object> (
|
||||
|
@ -250,7 +250,7 @@ template <> void Structure :: Convert<Image> (
|
|||
;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -56,7 +56,7 @@ static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3;
|
|||
|
||||
namspace Assimp
|
||||
{
|
||||
template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
|
||||
template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
|
||||
}
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -68,7 +68,7 @@ using namespace Assimp::Blender;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderTessellatorGL::BlenderTessellatorGL( BlenderBMeshConverter& converter ):
|
||||
converter( &converter )
|
||||
converter( &converter )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -80,167 +80,167 @@ BlenderTessellatorGL::~BlenderTessellatorGL( )
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
|
||||
{
|
||||
AssertVertexCount( vertexCount );
|
||||
AssertVertexCount( vertexCount );
|
||||
|
||||
std::vector< VertexGL > polyLoopGL;
|
||||
GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices );
|
||||
std::vector< VertexGL > polyLoopGL;
|
||||
GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices );
|
||||
|
||||
TessDataGL tessData;
|
||||
Tesssellate( polyLoopGL, tessData );
|
||||
TessDataGL tessData;
|
||||
Tesssellate( polyLoopGL, tessData );
|
||||
|
||||
TriangulateDrawCalls( tessData );
|
||||
TriangulateDrawCalls( tessData );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::AssertVertexCount( int vertexCount )
|
||||
{
|
||||
if ( vertexCount <= 4 )
|
||||
{
|
||||
ThrowException( "Expected more than 4 vertices for tessellation" );
|
||||
}
|
||||
if ( vertexCount <= 4 )
|
||||
{
|
||||
ThrowException( "Expected more than 4 vertices for tessellation" );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::GenerateLoopVerts( std::vector< VertexGL >& polyLoopGL, const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
|
||||
{
|
||||
for ( int i = 0; i < vertexCount; ++i )
|
||||
{
|
||||
const MLoop& loopItem = polyLoop[ i ];
|
||||
const MVert& vertex = vertices[ loopItem.v ];
|
||||
polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) );
|
||||
}
|
||||
for ( int i = 0; i < vertexCount; ++i )
|
||||
{
|
||||
const MLoop& loopItem = polyLoop[ i ];
|
||||
const MVert& vertex = vertices[ loopItem.v ];
|
||||
polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::Tesssellate( std::vector< VertexGL >& polyLoopGL, TessDataGL& tessData )
|
||||
{
|
||||
GLUtesselator* tessellator = gluNewTess( );
|
||||
gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) );
|
||||
gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO );
|
||||
GLUtesselator* tessellator = gluNewTess( );
|
||||
gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) );
|
||||
gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) );
|
||||
gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO );
|
||||
|
||||
gluTessBeginPolygon( tessellator, &tessData );
|
||||
gluTessBeginContour( tessellator );
|
||||
gluTessBeginPolygon( tessellator, &tessData );
|
||||
gluTessBeginContour( tessellator );
|
||||
|
||||
for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i )
|
||||
{
|
||||
gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] );
|
||||
}
|
||||
for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i )
|
||||
{
|
||||
gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] );
|
||||
}
|
||||
|
||||
gluTessEndContour( tessellator );
|
||||
gluTessEndPolygon( tessellator );
|
||||
gluTessEndContour( tessellator );
|
||||
gluTessEndPolygon( tessellator );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::TriangulateDrawCalls( const TessDataGL& tessData )
|
||||
{
|
||||
// NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically
|
||||
// need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case
|
||||
// GLU tessellate changes or tristrips and fans are wanted.
|
||||
// See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml
|
||||
for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i )
|
||||
{
|
||||
const DrawCallGL& drawCallGL = tessData.drawCalls[ i ];
|
||||
const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ];
|
||||
if ( drawCallGL.drawMode == GL_TRIANGLES )
|
||||
{
|
||||
MakeFacesFromTris( vertices, drawCallGL.vertexCount );
|
||||
}
|
||||
else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP )
|
||||
{
|
||||
MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount );
|
||||
}
|
||||
else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN )
|
||||
{
|
||||
MakeFacesFromTriFan( vertices, drawCallGL.vertexCount );
|
||||
}
|
||||
}
|
||||
// NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically
|
||||
// need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case
|
||||
// GLU tessellate changes or tristrips and fans are wanted.
|
||||
// See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml
|
||||
for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i )
|
||||
{
|
||||
const DrawCallGL& drawCallGL = tessData.drawCalls[ i ];
|
||||
const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ];
|
||||
if ( drawCallGL.drawMode == GL_TRIANGLES )
|
||||
{
|
||||
MakeFacesFromTris( vertices, drawCallGL.vertexCount );
|
||||
}
|
||||
else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP )
|
||||
{
|
||||
MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount );
|
||||
}
|
||||
else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN )
|
||||
{
|
||||
MakeFacesFromTriFan( vertices, drawCallGL.vertexCount );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::MakeFacesFromTris( const VertexGL* vertices, int vertexCount )
|
||||
{
|
||||
int triangleCount = vertexCount / 3;
|
||||
for ( int i = 0; i < triangleCount; ++i )
|
||||
{
|
||||
int vertexBase = i * 3;
|
||||
converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
||||
}
|
||||
int triangleCount = vertexCount / 3;
|
||||
for ( int i = 0; i < triangleCount; ++i )
|
||||
{
|
||||
int vertexBase = i * 3;
|
||||
converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::MakeFacesFromTriStrip( const VertexGL* vertices, int vertexCount )
|
||||
{
|
||||
int triangleCount = vertexCount - 2;
|
||||
for ( int i = 0; i < triangleCount; ++i )
|
||||
{
|
||||
int vertexBase = i;
|
||||
converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
||||
}
|
||||
int triangleCount = vertexCount - 2;
|
||||
for ( int i = 0; i < triangleCount; ++i )
|
||||
{
|
||||
int vertexBase = i;
|
||||
converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::MakeFacesFromTriFan( const VertexGL* vertices, int vertexCount )
|
||||
{
|
||||
int triangleCount = vertexCount - 2;
|
||||
for ( int i = 0; i < triangleCount; ++i )
|
||||
{
|
||||
int vertexBase = i;
|
||||
converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
||||
}
|
||||
int triangleCount = vertexCount - 2;
|
||||
for ( int i = 0; i < triangleCount; ++i )
|
||||
{
|
||||
int vertexBase = i;
|
||||
converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::TessellateBegin( GLenum drawModeGL, void* userData )
|
||||
{
|
||||
TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
|
||||
tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) );
|
||||
TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
|
||||
tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::TessellateEnd( void* )
|
||||
{
|
||||
// Do nothing
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::TessellateVertex( const void* vtxData, void* userData )
|
||||
{
|
||||
TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
|
||||
TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData );
|
||||
|
||||
const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData );
|
||||
if ( vertex.magic != BLEND_TESS_MAGIC )
|
||||
{
|
||||
ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" );
|
||||
}
|
||||
tessData.vertices.push_back( vertex );
|
||||
if ( tessData.drawCalls.size( ) == 0 )
|
||||
{
|
||||
ThrowException( "\"Vertex\" callback received before \"Begin\"" );
|
||||
}
|
||||
++( tessData.drawCalls.back( ).vertexCount );
|
||||
const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData );
|
||||
if ( vertex.magic != BLEND_TESS_MAGIC )
|
||||
{
|
||||
ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" );
|
||||
}
|
||||
tessData.vertices.push_back( vertex );
|
||||
if ( tessData.drawCalls.size( ) == 0 )
|
||||
{
|
||||
ThrowException( "\"Vertex\" callback received before \"Begin\"" );
|
||||
}
|
||||
++( tessData.drawCalls.back( ).vertexCount );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData )
|
||||
{
|
||||
ThrowException( "Intersected polygon loops are not yet supported" );
|
||||
ThrowException( "Intersected polygon loops are not yet supported" );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::TessellateEdgeFlag( GLboolean, void* )
|
||||
{
|
||||
// Do nothing
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
|
||||
{
|
||||
ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) );
|
||||
ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) );
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
||||
|
@ -249,7 +249,7 @@ void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
|
|||
|
||||
namespace Assimp
|
||||
{
|
||||
template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
|
||||
template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
|
||||
}
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -257,7 +257,7 @@ using namespace Assimp::Blender;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BlenderTessellatorP2T::BlenderTessellatorP2T( BlenderBMeshConverter& converter ):
|
||||
converter( &converter )
|
||||
converter( &converter )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -269,178 +269,178 @@ BlenderTessellatorP2T::~BlenderTessellatorP2T( )
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorP2T::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices )
|
||||
{
|
||||
AssertVertexCount( vertexCount );
|
||||
AssertVertexCount( vertexCount );
|
||||
|
||||
// NOTE - We have to hope that points in a Blender polygon are roughly on the same plane.
|
||||
// There may be some triangulation artifacts if they are wildly different.
|
||||
// NOTE - We have to hope that points in a Blender polygon are roughly on the same plane.
|
||||
// There may be some triangulation artifacts if they are wildly different.
|
||||
|
||||
std::vector< PointP2T > points;
|
||||
Copy3DVertices( polyLoop, vertexCount, vertices, points );
|
||||
std::vector< PointP2T > points;
|
||||
Copy3DVertices( polyLoop, vertexCount, vertices, points );
|
||||
|
||||
PlaneP2T plane = FindLLSQPlane( points );
|
||||
PlaneP2T plane = FindLLSQPlane( points );
|
||||
|
||||
aiMatrix4x4 transform = GeneratePointTransformMatrix( plane );
|
||||
aiMatrix4x4 transform = GeneratePointTransformMatrix( plane );
|
||||
|
||||
TransformAndFlattenVectices( transform, points );
|
||||
TransformAndFlattenVectices( transform, points );
|
||||
|
||||
std::vector< p2t::Point* > pointRefs;
|
||||
ReferencePoints( points, pointRefs );
|
||||
std::vector< p2t::Point* > pointRefs;
|
||||
ReferencePoints( points, pointRefs );
|
||||
|
||||
p2t::CDT cdt( pointRefs );
|
||||
p2t::CDT cdt( pointRefs );
|
||||
|
||||
cdt.Triangulate( );
|
||||
std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( );
|
||||
cdt.Triangulate( );
|
||||
std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( );
|
||||
|
||||
MakeFacesFromTriangles( triangles );
|
||||
MakeFacesFromTriangles( triangles );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorP2T::AssertVertexCount( int vertexCount )
|
||||
{
|
||||
if ( vertexCount <= 4 )
|
||||
{
|
||||
ThrowException( "Expected more than 4 vertices for tessellation" );
|
||||
}
|
||||
if ( vertexCount <= 4 )
|
||||
{
|
||||
ThrowException( "Expected more than 4 vertices for tessellation" );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorP2T::Copy3DVertices( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices, std::vector< PointP2T >& points ) const
|
||||
{
|
||||
points.resize( vertexCount );
|
||||
for ( int i = 0; i < vertexCount; ++i )
|
||||
{
|
||||
const MLoop& loop = polyLoop[ i ];
|
||||
const MVert& vert = vertices[ loop.v ];
|
||||
points.resize( vertexCount );
|
||||
for ( int i = 0; i < vertexCount; ++i )
|
||||
{
|
||||
const MLoop& loop = polyLoop[ i ];
|
||||
const MVert& vert = vertices[ loop.v ];
|
||||
|
||||
PointP2T& point = points[ i ];
|
||||
point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] );
|
||||
point.index = loop.v;
|
||||
point.magic = BLEND_TESS_MAGIC;
|
||||
}
|
||||
PointP2T& point = points[ i ];
|
||||
point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] );
|
||||
point.index = loop.v;
|
||||
point.magic = BLEND_TESS_MAGIC;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const
|
||||
{
|
||||
aiVector3D sideA( 1.0f, 0.0f, 0.0f );
|
||||
if ( std::fabs( plane.normal * sideA ) > 0.999f )
|
||||
{
|
||||
sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
|
||||
}
|
||||
aiVector3D sideA( 1.0f, 0.0f, 0.0f );
|
||||
if ( std::fabs( plane.normal * sideA ) > 0.999f )
|
||||
{
|
||||
sideA = aiVector3D( 0.0f, 1.0f, 0.0f );
|
||||
}
|
||||
|
||||
aiVector3D sideB( plane.normal ^ sideA );
|
||||
sideB.Normalize( );
|
||||
sideA = sideB ^ plane.normal;
|
||||
aiVector3D sideB( plane.normal ^ sideA );
|
||||
sideB.Normalize( );
|
||||
sideA = sideB ^ plane.normal;
|
||||
|
||||
aiMatrix4x4 result;
|
||||
result.a1 = sideA.x;
|
||||
result.a2 = sideA.y;
|
||||
result.a3 = sideA.z;
|
||||
result.b1 = sideB.x;
|
||||
result.b2 = sideB.y;
|
||||
result.b3 = sideB.z;
|
||||
result.c1 = plane.normal.x;
|
||||
result.c2 = plane.normal.y;
|
||||
result.c3 = plane.normal.z;
|
||||
result.a4 = plane.centre.x;
|
||||
result.b4 = plane.centre.y;
|
||||
result.c4 = plane.centre.z;
|
||||
result.Inverse( );
|
||||
aiMatrix4x4 result;
|
||||
result.a1 = sideA.x;
|
||||
result.a2 = sideA.y;
|
||||
result.a3 = sideA.z;
|
||||
result.b1 = sideB.x;
|
||||
result.b2 = sideB.y;
|
||||
result.b3 = sideB.z;
|
||||
result.c1 = plane.normal.x;
|
||||
result.c2 = plane.normal.y;
|
||||
result.c3 = plane.normal.z;
|
||||
result.a4 = plane.centre.x;
|
||||
result.b4 = plane.centre.y;
|
||||
result.c4 = plane.centre.z;
|
||||
result.Inverse( );
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorP2T::TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const
|
||||
{
|
||||
for ( unsigned int i = 0; i < vertices.size( ); ++i )
|
||||
{
|
||||
PointP2T& point = vertices[ i ];
|
||||
point.point3D = transform * point.point3D;
|
||||
point.point2D.set( point.point3D.y, point.point3D.z );
|
||||
}
|
||||
for ( unsigned int i = 0; i < vertices.size( ); ++i )
|
||||
{
|
||||
PointP2T& point = vertices[ i ];
|
||||
point.point3D = transform * point.point3D;
|
||||
point.point2D.set( point.point3D.y, point.point3D.z );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const
|
||||
{
|
||||
pointRefs.resize( points.size( ) );
|
||||
for ( unsigned int i = 0; i < points.size( ); ++i )
|
||||
{
|
||||
pointRefs[ i ] = &points[ i ].point2D;
|
||||
}
|
||||
pointRefs.resize( points.size( ) );
|
||||
for ( unsigned int i = 0; i < points.size( ); ++i )
|
||||
{
|
||||
pointRefs[ i ] = &points[ i ].point2D;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Yes this is filthy... but we have no choice
|
||||
#define OffsetOf( Class, Member ) ( static_cast< unsigned int >( \
|
||||
reinterpret_cast<uint8_t*>(&( reinterpret_cast< Class* >( NULL )->*( &Class::Member ) )) - \
|
||||
static_cast<uint8_t*>(NULL) ) )
|
||||
reinterpret_cast<uint8_t*>(&( reinterpret_cast< Class* >( NULL )->*( &Class::Member ) )) - \
|
||||
static_cast<uint8_t*>(NULL) ) )
|
||||
|
||||
inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
|
||||
{
|
||||
unsigned int pointOffset = OffsetOf( PointP2T, point2D );
|
||||
PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
|
||||
if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
|
||||
{
|
||||
ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
|
||||
}
|
||||
return pointStruct;
|
||||
unsigned int pointOffset = OffsetOf( PointP2T, point2D );
|
||||
PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
|
||||
if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
|
||||
{
|
||||
ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
|
||||
}
|
||||
return pointStruct;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
|
||||
{
|
||||
for ( unsigned int i = 0; i < triangles.size( ); ++i )
|
||||
{
|
||||
p2t::Triangle& Triangle = *triangles[ i ];
|
||||
for ( unsigned int i = 0; i < triangles.size( ); ++i )
|
||||
{
|
||||
p2t::Triangle& Triangle = *triangles[ i ];
|
||||
|
||||
PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) );
|
||||
PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) );
|
||||
PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) );
|
||||
PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) );
|
||||
PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) );
|
||||
PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) );
|
||||
|
||||
converter->AddFace( pointA.index, pointB.index, pointC.index );
|
||||
}
|
||||
converter->AddFace( pointA.index, pointB.index, pointC.index );
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline float p2tMax( float a, float b )
|
||||
{
|
||||
return a > b ? a : b;
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
||||
float BlenderTessellatorP2T::FindLargestMatrixElem( const aiMatrix3x3& mtx ) const
|
||||
{
|
||||
float result = 0.0f;
|
||||
float result = 0.0f;
|
||||
|
||||
for ( int x = 0; x < 3; ++x )
|
||||
{
|
||||
for ( int y = 0; y < 3; ++y )
|
||||
{
|
||||
result = p2tMax( std::fabs( mtx[ x ][ y ] ), result );
|
||||
}
|
||||
}
|
||||
for ( int x = 0; x < 3; ++x )
|
||||
{
|
||||
for ( int y = 0; y < 3; ++y )
|
||||
{
|
||||
result = p2tMax( std::fabs( mtx[ x ][ y ] ), result );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Aparently Assimp doesn't have matrix scaling
|
||||
aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const
|
||||
{
|
||||
aiMatrix3x3 result;
|
||||
aiMatrix3x3 result;
|
||||
|
||||
for ( int x = 0; x < 3; ++x )
|
||||
{
|
||||
for ( int y = 0; y < 3; ++y )
|
||||
{
|
||||
result[ x ][ y ] = mtx[ x ][ y ] * scale;
|
||||
}
|
||||
}
|
||||
for ( int x = 0; x < 3; ++x )
|
||||
{
|
||||
for ( int y = 0; y < 3; ++y )
|
||||
{
|
||||
result[ x ][ y ] = mtx[ x ][ y ] * scale;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -448,70 +448,70 @@ aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float sc
|
|||
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
||||
aiVector3D BlenderTessellatorP2T::GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const
|
||||
{
|
||||
float scale = FindLargestMatrixElem( mtx );
|
||||
aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale );
|
||||
mc = mc * mc * mc;
|
||||
float scale = FindLargestMatrixElem( mtx );
|
||||
aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale );
|
||||
mc = mc * mc * mc;
|
||||
|
||||
aiVector3D v( 1.0f );
|
||||
aiVector3D lastV = v;
|
||||
for ( int i = 0; i < 100; ++i )
|
||||
{
|
||||
v = mc * v;
|
||||
v.Normalize( );
|
||||
if ( ( v - lastV ).SquareLength( ) < 1e-16f )
|
||||
{
|
||||
break;
|
||||
}
|
||||
lastV = v;
|
||||
}
|
||||
return v;
|
||||
aiVector3D v( 1.0f );
|
||||
aiVector3D lastV = v;
|
||||
for ( int i = 0; i < 100; ++i )
|
||||
{
|
||||
v = mc * v;
|
||||
v.Normalize( );
|
||||
if ( ( v - lastV ).SquareLength( ) < 1e-16f )
|
||||
{
|
||||
break;
|
||||
}
|
||||
lastV = v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
||||
PlaneP2T BlenderTessellatorP2T::FindLLSQPlane( const std::vector< PointP2T >& points ) const
|
||||
{
|
||||
PlaneP2T result;
|
||||
PlaneP2T result;
|
||||
|
||||
aiVector3D sum( 0.0f );
|
||||
for ( unsigned int i = 0; i < points.size( ); ++i )
|
||||
{
|
||||
sum += points[ i ].point3D;
|
||||
}
|
||||
result.centre = sum * ( 1.0f / points.size( ) );
|
||||
aiVector3D sum( 0.0f );
|
||||
for ( unsigned int i = 0; i < points.size( ); ++i )
|
||||
{
|
||||
sum += points[ i ].point3D;
|
||||
}
|
||||
result.centre = sum * ( 1.0f / points.size( ) );
|
||||
|
||||
float sumXX = 0.0f;
|
||||
float sumXY = 0.0f;
|
||||
float sumXZ = 0.0f;
|
||||
float sumYY = 0.0f;
|
||||
float sumYZ = 0.0f;
|
||||
float sumZZ = 0.0f;
|
||||
for ( unsigned int i = 0; i < points.size( ); ++i )
|
||||
{
|
||||
aiVector3D offset = points[ i ].point3D - result.centre;
|
||||
sumXX += offset.x * offset.x;
|
||||
sumXY += offset.x * offset.y;
|
||||
sumXZ += offset.x * offset.z;
|
||||
sumYY += offset.y * offset.y;
|
||||
sumYZ += offset.y * offset.z;
|
||||
sumZZ += offset.z * offset.z;
|
||||
}
|
||||
float sumXX = 0.0f;
|
||||
float sumXY = 0.0f;
|
||||
float sumXZ = 0.0f;
|
||||
float sumYY = 0.0f;
|
||||
float sumYZ = 0.0f;
|
||||
float sumZZ = 0.0f;
|
||||
for ( unsigned int i = 0; i < points.size( ); ++i )
|
||||
{
|
||||
aiVector3D offset = points[ i ].point3D - result.centre;
|
||||
sumXX += offset.x * offset.x;
|
||||
sumXY += offset.x * offset.y;
|
||||
sumXZ += offset.x * offset.z;
|
||||
sumYY += offset.y * offset.y;
|
||||
sumYZ += offset.y * offset.z;
|
||||
sumZZ += offset.z * offset.z;
|
||||
}
|
||||
|
||||
aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ );
|
||||
aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ );
|
||||
|
||||
float det = mtx.Determinant( );
|
||||
if ( det == 0.0f )
|
||||
{
|
||||
result.normal = aiVector3D( 0.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
aiMatrix3x3 invMtx = mtx;
|
||||
invMtx.Inverse( );
|
||||
result.normal = GetEigenVectorFromLargestEigenValue( invMtx );
|
||||
}
|
||||
float det = mtx.Determinant( );
|
||||
if ( det == 0.0f )
|
||||
{
|
||||
result.normal = aiVector3D( 0.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
aiMatrix3x3 invMtx = mtx;
|
||||
invMtx.Inverse( );
|
||||
result.normal = GetEigenVectorFromLargestEigenValue( invMtx );
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BLEND_WITH_POLY_2_TRI
|
||||
|
|
|
@ -50,11 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// made configurable in CMake and potentially not wanted by most users
|
||||
// as it requires a Gl environment.
|
||||
#ifndef ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
||||
# define ASSIMP_BLEND_WITH_GLU_TESSELLATE 0
|
||||
# define ASSIMP_BLEND_WITH_GLU_TESSELLATE 0
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BLEND_WITH_POLY_2_TRI
|
||||
# define ASSIMP_BLEND_WITH_POLY_2_TRI 1
|
||||
# define ASSIMP_BLEND_WITH_POLY_2_TRI 1
|
||||
#endif
|
||||
|
||||
#include "LogAux.h"
|
||||
|
@ -68,74 +68,74 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace Assimp
|
||||
{
|
||||
class BlenderBMeshConverter;
|
||||
class BlenderBMeshConverter;
|
||||
|
||||
// TinyFormatter.h
|
||||
namespace Formatter
|
||||
{
|
||||
template < typename T,typename TR, typename A > class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
|
||||
}
|
||||
// TinyFormatter.h
|
||||
namespace Formatter
|
||||
{
|
||||
template < typename T,typename TR, typename A > class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
|
||||
}
|
||||
|
||||
// BlenderScene.h
|
||||
namespace Blender
|
||||
{
|
||||
struct MLoop;
|
||||
struct MVert;
|
||||
// BlenderScene.h
|
||||
namespace Blender
|
||||
{
|
||||
struct MLoop;
|
||||
struct MVert;
|
||||
|
||||
struct VertexGL
|
||||
{
|
||||
GLdouble X;
|
||||
GLdouble Y;
|
||||
GLdouble Z;
|
||||
int index;
|
||||
int magic;
|
||||
struct VertexGL
|
||||
{
|
||||
GLdouble X;
|
||||
GLdouble Y;
|
||||
GLdouble Z;
|
||||
int index;
|
||||
int magic;
|
||||
|
||||
VertexGL( GLdouble X, GLdouble Y, GLdouble Z, int index, int magic ): X( X ), Y( Y ), Z( Z ), index( index ), magic( magic ) { }
|
||||
};
|
||||
VertexGL( GLdouble X, GLdouble Y, GLdouble Z, int index, int magic ): X( X ), Y( Y ), Z( Z ), index( index ), magic( magic ) { }
|
||||
};
|
||||
|
||||
struct DrawCallGL
|
||||
{
|
||||
GLenum drawMode;
|
||||
int baseVertex;
|
||||
int vertexCount;
|
||||
struct DrawCallGL
|
||||
{
|
||||
GLenum drawMode;
|
||||
int baseVertex;
|
||||
int vertexCount;
|
||||
|
||||
DrawCallGL( GLenum drawMode, int baseVertex ): drawMode( drawMode ), baseVertex( baseVertex ), vertexCount( 0 ) { }
|
||||
};
|
||||
DrawCallGL( GLenum drawMode, int baseVertex ): drawMode( drawMode ), baseVertex( baseVertex ), vertexCount( 0 ) { }
|
||||
};
|
||||
|
||||
struct TessDataGL
|
||||
{
|
||||
std::vector< DrawCallGL > drawCalls;
|
||||
std::vector< VertexGL > vertices;
|
||||
};
|
||||
}
|
||||
struct TessDataGL
|
||||
{
|
||||
std::vector< DrawCallGL > drawCalls;
|
||||
std::vector< VertexGL > vertices;
|
||||
};
|
||||
}
|
||||
|
||||
class BlenderTessellatorGL: public LogFunctions< BlenderTessellatorGL >
|
||||
{
|
||||
public:
|
||||
BlenderTessellatorGL( BlenderBMeshConverter& converter );
|
||||
~BlenderTessellatorGL( );
|
||||
class BlenderTessellatorGL: public LogFunctions< BlenderTessellatorGL >
|
||||
{
|
||||
public:
|
||||
BlenderTessellatorGL( BlenderBMeshConverter& converter );
|
||||
~BlenderTessellatorGL( );
|
||||
|
||||
void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
|
||||
void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
|
||||
|
||||
private:
|
||||
void AssertVertexCount( int vertexCount );
|
||||
void GenerateLoopVerts( std::vector< Blender::VertexGL >& polyLoopGL, const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
|
||||
void Tesssellate( std::vector< Blender::VertexGL >& polyLoopGL, Blender::TessDataGL& tessData );
|
||||
void TriangulateDrawCalls( const Blender::TessDataGL& tessData );
|
||||
void MakeFacesFromTris( const Blender::VertexGL* vertices, int vertexCount );
|
||||
void MakeFacesFromTriStrip( const Blender::VertexGL* vertices, int vertexCount );
|
||||
void MakeFacesFromTriFan( const Blender::VertexGL* vertices, int vertexCount );
|
||||
private:
|
||||
void AssertVertexCount( int vertexCount );
|
||||
void GenerateLoopVerts( std::vector< Blender::VertexGL >& polyLoopGL, const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
|
||||
void Tesssellate( std::vector< Blender::VertexGL >& polyLoopGL, Blender::TessDataGL& tessData );
|
||||
void TriangulateDrawCalls( const Blender::TessDataGL& tessData );
|
||||
void MakeFacesFromTris( const Blender::VertexGL* vertices, int vertexCount );
|
||||
void MakeFacesFromTriStrip( const Blender::VertexGL* vertices, int vertexCount );
|
||||
void MakeFacesFromTriFan( const Blender::VertexGL* vertices, int vertexCount );
|
||||
|
||||
static void TessellateBegin( GLenum drawModeGL, void* userData );
|
||||
static void TessellateEnd( void* userData );
|
||||
static void TessellateVertex( const void* vtxData, void* userData );
|
||||
static void TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData );
|
||||
static void TessellateEdgeFlag( GLboolean edgeFlag, void* userData );
|
||||
static void TessellateError( GLenum errorCode, void* userData );
|
||||
static void TessellateBegin( GLenum drawModeGL, void* userData );
|
||||
static void TessellateEnd( void* userData );
|
||||
static void TessellateVertex( const void* vtxData, void* userData );
|
||||
static void TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData );
|
||||
static void TessellateEdgeFlag( GLboolean edgeFlag, void* userData );
|
||||
static void TessellateError( GLenum errorCode, void* userData );
|
||||
|
||||
BlenderBMeshConverter* converter;
|
||||
};
|
||||
BlenderBMeshConverter* converter;
|
||||
};
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE
|
||||
|
@ -146,61 +146,61 @@ namespace Assimp
|
|||
|
||||
namespace Assimp
|
||||
{
|
||||
class BlenderBMeshConverter;
|
||||
class BlenderBMeshConverter;
|
||||
|
||||
// TinyFormatter.h
|
||||
namespace Formatter
|
||||
{
|
||||
template < typename T,typename TR, typename A > class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
|
||||
}
|
||||
// TinyFormatter.h
|
||||
namespace Formatter
|
||||
{
|
||||
template < typename T,typename TR, typename A > class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format;
|
||||
}
|
||||
|
||||
// BlenderScene.h
|
||||
namespace Blender
|
||||
{
|
||||
struct MLoop;
|
||||
struct MVert;
|
||||
// BlenderScene.h
|
||||
namespace Blender
|
||||
{
|
||||
struct MLoop;
|
||||
struct MVert;
|
||||
|
||||
struct PointP2T
|
||||
{
|
||||
aiVector3D point3D;
|
||||
p2t::Point point2D;
|
||||
int magic;
|
||||
int index;
|
||||
};
|
||||
struct PointP2T
|
||||
{
|
||||
aiVector3D point3D;
|
||||
p2t::Point point2D;
|
||||
int magic;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct PlaneP2T
|
||||
{
|
||||
aiVector3D centre;
|
||||
aiVector3D normal;
|
||||
};
|
||||
}
|
||||
struct PlaneP2T
|
||||
{
|
||||
aiVector3D centre;
|
||||
aiVector3D normal;
|
||||
};
|
||||
}
|
||||
|
||||
class BlenderTessellatorP2T: public LogFunctions< BlenderTessellatorP2T >
|
||||
{
|
||||
public:
|
||||
BlenderTessellatorP2T( BlenderBMeshConverter& converter );
|
||||
~BlenderTessellatorP2T( );
|
||||
class BlenderTessellatorP2T: public LogFunctions< BlenderTessellatorP2T >
|
||||
{
|
||||
public:
|
||||
BlenderTessellatorP2T( BlenderBMeshConverter& converter );
|
||||
~BlenderTessellatorP2T( );
|
||||
|
||||
void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
|
||||
void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices );
|
||||
|
||||
private:
|
||||
void AssertVertexCount( int vertexCount );
|
||||
void Copy3DVertices( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices, std::vector< Blender::PointP2T >& targetVertices ) const;
|
||||
aiMatrix4x4 GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const;
|
||||
void TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const;
|
||||
void ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const;
|
||||
inline Blender::PointP2T& GetActualPointStructure( p2t::Point& point ) const;
|
||||
void MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const;
|
||||
private:
|
||||
void AssertVertexCount( int vertexCount );
|
||||
void Copy3DVertices( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices, std::vector< Blender::PointP2T >& targetVertices ) const;
|
||||
aiMatrix4x4 GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const;
|
||||
void TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const;
|
||||
void ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const;
|
||||
inline Blender::PointP2T& GetActualPointStructure( p2t::Point& point ) const;
|
||||
void MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const;
|
||||
|
||||
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
||||
float FindLargestMatrixElem( const aiMatrix3x3& mtx ) const;
|
||||
aiMatrix3x3 ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const;
|
||||
aiVector3D GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const;
|
||||
Blender::PlaneP2T FindLLSQPlane( const std::vector< Blender::PointP2T >& points ) const;
|
||||
// Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html
|
||||
float FindLargestMatrixElem( const aiMatrix3x3& mtx ) const;
|
||||
aiMatrix3x3 ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const;
|
||||
aiVector3D GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const;
|
||||
Blender::PlaneP2T FindLLSQPlane( const std::vector< Blender::PointP2T >& points ) const;
|
||||
|
||||
BlenderBMeshConverter* converter;
|
||||
};
|
||||
BlenderBMeshConverter* converter;
|
||||
};
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BLEND_WITH_POLY_2_TRI
|
||||
|
|
|
@ -54,8 +54,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace Assimp {
|
||||
class BlobIOSystem;
|
||||
namespace Assimp {
|
||||
class BlobIOSystem;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
/** Redirect IOStream to a blob */
|
||||
|
@ -64,144 +64,144 @@ class BlobIOStream : public IOStream
|
|||
{
|
||||
public:
|
||||
|
||||
BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096)
|
||||
: buffer()
|
||||
, cur_size()
|
||||
, file_size()
|
||||
, cursor()
|
||||
, initial(initial)
|
||||
, file(file)
|
||||
, creator(creator)
|
||||
{
|
||||
}
|
||||
BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096)
|
||||
: buffer()
|
||||
, cur_size()
|
||||
, file_size()
|
||||
, cursor()
|
||||
, initial(initial)
|
||||
, file(file)
|
||||
, creator(creator)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual ~BlobIOStream();
|
||||
virtual ~BlobIOStream();
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
aiExportDataBlob* GetBlob()
|
||||
{
|
||||
aiExportDataBlob* blob = new aiExportDataBlob();
|
||||
blob->size = file_size;
|
||||
blob->data = buffer;
|
||||
// -------------------------------------------------------------------
|
||||
aiExportDataBlob* GetBlob()
|
||||
{
|
||||
aiExportDataBlob* blob = new aiExportDataBlob();
|
||||
blob->size = file_size;
|
||||
blob->data = buffer;
|
||||
|
||||
buffer = NULL;
|
||||
buffer = NULL;
|
||||
|
||||
return blob;
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------
|
||||
virtual size_t Read( void *,
|
||||
size_t,
|
||||
size_t )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
size_t,
|
||||
size_t )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------
|
||||
virtual size_t Write(const void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
pSize *= pCount;
|
||||
if (cursor + pSize > cur_size) {
|
||||
Grow(cursor + pSize);
|
||||
}
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
pSize *= pCount;
|
||||
if (cursor + pSize > cur_size) {
|
||||
Grow(cursor + pSize);
|
||||
}
|
||||
|
||||
memcpy(buffer+cursor, pvBuffer, pSize);
|
||||
cursor += pSize;
|
||||
memcpy(buffer+cursor, pvBuffer, pSize);
|
||||
cursor += pSize;
|
||||
|
||||
file_size = std::max(file_size,cursor);
|
||||
return pCount;
|
||||
}
|
||||
file_size = std::max(file_size,cursor);
|
||||
return pCount;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
virtual aiReturn Seek(size_t pOffset,
|
||||
aiOrigin pOrigin)
|
||||
{
|
||||
switch(pOrigin)
|
||||
{
|
||||
case aiOrigin_CUR:
|
||||
cursor += pOffset;
|
||||
break;
|
||||
// -------------------------------------------------------------------
|
||||
virtual aiReturn Seek(size_t pOffset,
|
||||
aiOrigin pOrigin)
|
||||
{
|
||||
switch(pOrigin)
|
||||
{
|
||||
case aiOrigin_CUR:
|
||||
cursor += pOffset;
|
||||
break;
|
||||
|
||||
case aiOrigin_END:
|
||||
cursor = file_size - pOffset;
|
||||
break;
|
||||
case aiOrigin_END:
|
||||
cursor = file_size - pOffset;
|
||||
break;
|
||||
|
||||
case aiOrigin_SET:
|
||||
cursor = pOffset;
|
||||
break;
|
||||
case aiOrigin_SET:
|
||||
cursor = pOffset;
|
||||
break;
|
||||
|
||||
default:
|
||||
return AI_FAILURE;
|
||||
}
|
||||
default:
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
if (cursor > file_size) {
|
||||
Grow(cursor);
|
||||
}
|
||||
if (cursor > file_size) {
|
||||
Grow(cursor);
|
||||
}
|
||||
|
||||
file_size = std::max(cursor,file_size);
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
file_size = std::max(cursor,file_size);
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------
|
||||
virtual size_t Tell() const
|
||||
{
|
||||
return cursor;
|
||||
}
|
||||
{
|
||||
return cursor;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
virtual size_t FileSize() const
|
||||
{
|
||||
return file_size;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
virtual size_t FileSize() const
|
||||
{
|
||||
return file_size;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
virtual void Flush()
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
virtual void Flush()
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Grow(size_t need = 0)
|
||||
{
|
||||
// 1.5 and phi are very heap-friendly growth factors (the first
|
||||
// allows for frequent re-use of heap blocks, the second
|
||||
// forms a fibonacci sequence with similar characteristics -
|
||||
// since this heavily depends on the heap implementation
|
||||
// and other factors as well, i'll just go with 1.5 since
|
||||
// it is quicker to compute).
|
||||
size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
|
||||
// -------------------------------------------------------------------
|
||||
void Grow(size_t need = 0)
|
||||
{
|
||||
// 1.5 and phi are very heap-friendly growth factors (the first
|
||||
// allows for frequent re-use of heap blocks, the second
|
||||
// forms a fibonacci sequence with similar characteristics -
|
||||
// since this heavily depends on the heap implementation
|
||||
// and other factors as well, i'll just go with 1.5 since
|
||||
// it is quicker to compute).
|
||||
size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
|
||||
|
||||
const uint8_t* const old = buffer;
|
||||
buffer = new uint8_t[new_size];
|
||||
const uint8_t* const old = buffer;
|
||||
buffer = new uint8_t[new_size];
|
||||
|
||||
if (old) {
|
||||
memcpy(buffer,old,cur_size);
|
||||
delete[] old;
|
||||
}
|
||||
if (old) {
|
||||
memcpy(buffer,old,cur_size);
|
||||
delete[] old;
|
||||
}
|
||||
|
||||
cur_size = new_size;
|
||||
}
|
||||
cur_size = new_size;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint8_t* buffer;
|
||||
size_t cur_size,file_size, cursor, initial;
|
||||
uint8_t* buffer;
|
||||
size_t cur_size,file_size, cursor, initial;
|
||||
|
||||
const std::string file;
|
||||
BlobIOSystem* const creator;
|
||||
const std::string file;
|
||||
BlobIOSystem* const creator;
|
||||
};
|
||||
|
||||
|
||||
|
@ -213,122 +213,122 @@ private:
|
|||
class BlobIOSystem : public IOSystem
|
||||
{
|
||||
|
||||
friend class BlobIOStream;
|
||||
typedef std::pair<std::string, aiExportDataBlob*> BlobEntry;
|
||||
friend class BlobIOStream;
|
||||
typedef std::pair<std::string, aiExportDataBlob*> BlobEntry;
|
||||
|
||||
public:
|
||||
|
||||
BlobIOSystem()
|
||||
{
|
||||
}
|
||||
BlobIOSystem()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BlobIOSystem()
|
||||
{
|
||||
BOOST_FOREACH(BlobEntry& blobby, blobs) {
|
||||
delete blobby.second;
|
||||
}
|
||||
}
|
||||
virtual ~BlobIOSystem()
|
||||
{
|
||||
BOOST_FOREACH(BlobEntry& blobby, blobs) {
|
||||
delete blobby.second;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
const char* GetMagicFileName() const
|
||||
{
|
||||
return AI_BLOBIO_MAGIC;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
const char* GetMagicFileName() const
|
||||
{
|
||||
return AI_BLOBIO_MAGIC;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
aiExportDataBlob* GetBlobChain()
|
||||
{
|
||||
// one must be the master
|
||||
aiExportDataBlob* master = NULL, *cur;
|
||||
BOOST_FOREACH(const BlobEntry& blobby, blobs) {
|
||||
if (blobby.first == AI_BLOBIO_MAGIC) {
|
||||
master = blobby.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!master) {
|
||||
DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly.");
|
||||
return NULL;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
aiExportDataBlob* GetBlobChain()
|
||||
{
|
||||
// one must be the master
|
||||
aiExportDataBlob* master = NULL, *cur;
|
||||
BOOST_FOREACH(const BlobEntry& blobby, blobs) {
|
||||
if (blobby.first == AI_BLOBIO_MAGIC) {
|
||||
master = blobby.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!master) {
|
||||
DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
master->name.Set("");
|
||||
master->name.Set("");
|
||||
|
||||
cur = master;
|
||||
BOOST_FOREACH(const BlobEntry& blobby, blobs) {
|
||||
if (blobby.second == master) {
|
||||
continue;
|
||||
}
|
||||
cur = master;
|
||||
BOOST_FOREACH(const BlobEntry& blobby, blobs) {
|
||||
if (blobby.second == master) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->next = blobby.second;
|
||||
cur = cur->next;
|
||||
cur->next = blobby.second;
|
||||
cur = cur->next;
|
||||
|
||||
// extract the file extension from the file written
|
||||
const std::string::size_type s = blobby.first.find_first_of('.');
|
||||
cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1));
|
||||
}
|
||||
// extract the file extension from the file written
|
||||
const std::string::size_type s = blobby.first.find_first_of('.');
|
||||
cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1));
|
||||
}
|
||||
|
||||
// give up blob ownership
|
||||
blobs.clear();
|
||||
return master;
|
||||
}
|
||||
// give up blob ownership
|
||||
blobs.clear();
|
||||
return master;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
virtual bool Exists( const char* pFile) const {
|
||||
return created.find(std::string(pFile)) != created.end();
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
virtual bool Exists( const char* pFile) const {
|
||||
return created.find(std::string(pFile)) != created.end();
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
virtual char getOsSeparator() const {
|
||||
return '/';
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
virtual char getOsSeparator() const {
|
||||
return '/';
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
virtual IOStream* Open(const char* pFile,
|
||||
const char* pMode)
|
||||
{
|
||||
if (pMode[0] != 'w') {
|
||||
return NULL;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
virtual IOStream* Open(const char* pFile,
|
||||
const char* pMode)
|
||||
{
|
||||
if (pMode[0] != 'w') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
created.insert(std::string(pFile));
|
||||
return new BlobIOStream(this,std::string(pFile));
|
||||
}
|
||||
created.insert(std::string(pFile));
|
||||
return new BlobIOStream(this,std::string(pFile));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
virtual void Close( IOStream* pFile)
|
||||
{
|
||||
delete pFile;
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
virtual void Close( IOStream* pFile)
|
||||
{
|
||||
delete pFile;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void OnDestruct(const std::string& filename, BlobIOStream* child)
|
||||
{
|
||||
// we don't know in which the files are closed, so we
|
||||
// can't reliably say that the first must be the master
|
||||
// file ...
|
||||
blobs.push_back( BlobEntry(filename,child->GetBlob()) );
|
||||
}
|
||||
// -------------------------------------------------------------------
|
||||
void OnDestruct(const std::string& filename, BlobIOStream* child)
|
||||
{
|
||||
// we don't know in which the files are closed, so we
|
||||
// can't reliably say that the first must be the master
|
||||
// file ...
|
||||
blobs.push_back( BlobEntry(filename,child->GetBlob()) );
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::string> created;
|
||||
std::vector< BlobEntry > blobs;
|
||||
std::set<std::string> created;
|
||||
std::vector< BlobEntry > blobs;
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
BlobIOStream :: ~BlobIOStream()
|
||||
{
|
||||
creator->OnDestruct(file,this);
|
||||
delete[] buffer;
|
||||
creator->OnDestruct(file,this);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
// --------------------------------------------------------------------------------------
|
||||
/** Defines some useful byte order swap routines.
|
||||
*
|
||||
|
@ -60,143 +60,143 @@ namespace Assimp {
|
|||
// --------------------------------------------------------------------------------------
|
||||
class ByteSwap
|
||||
{
|
||||
ByteSwap() {}
|
||||
ByteSwap() {}
|
||||
|
||||
public:
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap two bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap2(void* _szOut)
|
||||
{
|
||||
ai_assert(_szOut);
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap two bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap2(void* _szOut)
|
||||
{
|
||||
ai_assert(_szOut);
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
uint16_t* const szOut = reinterpret_cast<uint16_t*>(_szOut);
|
||||
*szOut = _byteswap_ushort(*szOut);
|
||||
uint16_t* const szOut = reinterpret_cast<uint16_t*>(_szOut);
|
||||
*szOut = _byteswap_ushort(*szOut);
|
||||
#else
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[1]);
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[1]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap four bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap4(void* _szOut)
|
||||
{
|
||||
ai_assert(_szOut);
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap four bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap4(void* _szOut)
|
||||
{
|
||||
ai_assert(_szOut);
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
uint32_t* const szOut = reinterpret_cast<uint32_t*>(_szOut);
|
||||
*szOut = _byteswap_ulong(*szOut);
|
||||
uint32_t* const szOut = reinterpret_cast<uint32_t*>(_szOut);
|
||||
*szOut = _byteswap_ulong(*szOut);
|
||||
#else
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[3]);
|
||||
std::swap(szOut[1],szOut[2]);
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[3]);
|
||||
std::swap(szOut[1],szOut[2]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap eight bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap8(void* _szOut)
|
||||
{
|
||||
ai_assert(_szOut);
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap eight bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap8(void* _szOut)
|
||||
{
|
||||
ai_assert(_szOut);
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
uint64_t* const szOut = reinterpret_cast<uint64_t*>(_szOut);
|
||||
*szOut = _byteswap_uint64(*szOut);
|
||||
uint64_t* const szOut = reinterpret_cast<uint64_t*>(_szOut);
|
||||
*szOut = _byteswap_uint64(*szOut);
|
||||
#else
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[7]);
|
||||
std::swap(szOut[1],szOut[6]);
|
||||
std::swap(szOut[2],szOut[5]);
|
||||
std::swap(szOut[3],szOut[4]);
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[7]);
|
||||
std::swap(szOut[1],szOut[6]);
|
||||
std::swap(szOut[2],szOut[5]);
|
||||
std::swap(szOut[3],szOut[4]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a float. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(float* fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a float. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(float* fOut) {
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a double. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(double* fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a double. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(double* fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int16t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int16_t* fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int16t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int16_t* fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint16_t* fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
static inline void Swap(uint16_t* fOut) {
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int32t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int32_t* fOut){
|
||||
Swap4(fOut);
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int32t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int32_t* fOut){
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint32_t* fOut){
|
||||
Swap4(fOut);
|
||||
}
|
||||
static inline void Swap(uint32_t* fOut){
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int64t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int64_t* fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int64t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int64_t* fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
static inline void Swap(uint64_t* fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
static inline void Swap(uint64_t* fOut) {
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
//! Templatized ByteSwap
|
||||
//! \returns param tOut as swapped
|
||||
template<typename Type>
|
||||
static inline Type Swapped(Type tOut)
|
||||
{
|
||||
return _swapper<Type,sizeof(Type)>()(tOut);
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
//! Templatized ByteSwap
|
||||
//! \returns param tOut as swapped
|
||||
template<typename Type>
|
||||
static inline Type Swapped(Type tOut)
|
||||
{
|
||||
return _swapper<Type,sizeof(Type)>()(tOut);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <typename T, size_t size> struct _swapper;
|
||||
template <typename T, size_t size> struct _swapper;
|
||||
};
|
||||
|
||||
template <typename T> struct ByteSwap::_swapper<T,2> {
|
||||
T operator() (T tOut) {
|
||||
Swap2(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
T operator() (T tOut) {
|
||||
Swap2(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct ByteSwap::_swapper<T,4> {
|
||||
T operator() (T tOut) {
|
||||
Swap4(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
T operator() (T tOut) {
|
||||
Swap4(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct ByteSwap::_swapper<T,8> {
|
||||
T operator() (T tOut) {
|
||||
Swap8(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
T operator() (T tOut) {
|
||||
Swap8(&tOut);
|
||||
return tOut;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -204,39 +204,39 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
|
|||
// ByteSwap macros for BigEndian/LittleEndian support
|
||||
// --------------------------------------------------------------------------------------
|
||||
#if (defined AI_BUILD_BIG_ENDIAN)
|
||||
# define AI_LE(t) (t)
|
||||
# define AI_BE(t) ByteSwap::Swapped(t)
|
||||
# define AI_LSWAP2(p)
|
||||
# define AI_LSWAP4(p)
|
||||
# define AI_LSWAP8(p)
|
||||
# define AI_LSWAP2P(p)
|
||||
# define AI_LSWAP4P(p)
|
||||
# define AI_LSWAP8P(p)
|
||||
# define LE_NCONST const
|
||||
# define AI_SWAP2(p) ByteSwap::Swap2(&(p))
|
||||
# define AI_SWAP4(p) ByteSwap::Swap4(&(p))
|
||||
# define AI_SWAP8(p) ByteSwap::Swap8(&(p))
|
||||
# define AI_SWAP2P(p) ByteSwap::Swap2((p))
|
||||
# define AI_SWAP4P(p) ByteSwap::Swap4((p))
|
||||
# define AI_SWAP8P(p) ByteSwap::Swap8((p))
|
||||
# define BE_NCONST
|
||||
# define AI_LE(t) (t)
|
||||
# define AI_BE(t) ByteSwap::Swapped(t)
|
||||
# define AI_LSWAP2(p)
|
||||
# define AI_LSWAP4(p)
|
||||
# define AI_LSWAP8(p)
|
||||
# define AI_LSWAP2P(p)
|
||||
# define AI_LSWAP4P(p)
|
||||
# define AI_LSWAP8P(p)
|
||||
# define LE_NCONST const
|
||||
# define AI_SWAP2(p) ByteSwap::Swap2(&(p))
|
||||
# define AI_SWAP4(p) ByteSwap::Swap4(&(p))
|
||||
# define AI_SWAP8(p) ByteSwap::Swap8(&(p))
|
||||
# define AI_SWAP2P(p) ByteSwap::Swap2((p))
|
||||
# define AI_SWAP4P(p) ByteSwap::Swap4((p))
|
||||
# define AI_SWAP8P(p) ByteSwap::Swap8((p))
|
||||
# define BE_NCONST
|
||||
#else
|
||||
# define AI_BE(t) (t)
|
||||
# define AI_LE(t) ByteSwap::Swapped(t)
|
||||
# define AI_SWAP2(p)
|
||||
# define AI_SWAP4(p)
|
||||
# define AI_SWAP8(p)
|
||||
# define AI_SWAP2P(p)
|
||||
# define AI_SWAP4P(p)
|
||||
# define AI_SWAP8P(p)
|
||||
# define BE_NCONST const
|
||||
# define AI_LSWAP2(p) ByteSwap::Swap2(&(p))
|
||||
# define AI_LSWAP4(p) ByteSwap::Swap4(&(p))
|
||||
# define AI_LSWAP8(p) ByteSwap::Swap8(&(p))
|
||||
# define AI_LSWAP2P(p) ByteSwap::Swap2((p))
|
||||
# define AI_LSWAP4P(p) ByteSwap::Swap4((p))
|
||||
# define AI_LSWAP8P(p) ByteSwap::Swap8((p))
|
||||
# define LE_NCONST
|
||||
# define AI_BE(t) (t)
|
||||
# define AI_LE(t) ByteSwap::Swapped(t)
|
||||
# define AI_SWAP2(p)
|
||||
# define AI_SWAP4(p)
|
||||
# define AI_SWAP8(p)
|
||||
# define AI_SWAP2P(p)
|
||||
# define AI_SWAP4P(p)
|
||||
# define AI_SWAP8P(p)
|
||||
# define BE_NCONST const
|
||||
# define AI_LSWAP2(p) ByteSwap::Swap2(&(p))
|
||||
# define AI_LSWAP4(p) ByteSwap::Swap4(&(p))
|
||||
# define AI_LSWAP8(p) ByteSwap::Swap8(&(p))
|
||||
# define AI_LSWAP2P(p) ByteSwap::Swap2((p))
|
||||
# define AI_LSWAP4P(p) ByteSwap::Swap4((p))
|
||||
# define AI_LSWAP8P(p) ByteSwap::Swap8((p))
|
||||
# define LE_NCONST
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -244,41 +244,41 @@ namespace Intern {
|
|||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <typename T, bool doit>
|
||||
struct ByteSwapper {
|
||||
void operator() (T* inout) {
|
||||
ByteSwap::Swap(inout);
|
||||
}
|
||||
struct ByteSwapper {
|
||||
void operator() (T* inout) {
|
||||
ByteSwap::Swap(inout);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ByteSwapper<T,false> {
|
||||
void operator() (T*) {
|
||||
}
|
||||
struct ByteSwapper<T,false> {
|
||||
void operator() (T*) {
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
template <bool SwapEndianess, typename T, bool RuntimeSwitch>
|
||||
struct Getter {
|
||||
void operator() (T* inout, bool le) {
|
||||
void operator() (T* inout, bool le) {
|
||||
#ifdef AI_BUILD_BIG_ENDIAN
|
||||
le = le;
|
||||
le = le;
|
||||
#else
|
||||
le = !le;
|
||||
le = !le;
|
||||
#endif
|
||||
if (le) {
|
||||
ByteSwapper<T,(sizeof(T)>1?true:false)> () (inout);
|
||||
}
|
||||
else ByteSwapper<T,false> () (inout);
|
||||
}
|
||||
if (le) {
|
||||
ByteSwapper<T,(sizeof(T)>1?true:false)> () (inout);
|
||||
}
|
||||
else ByteSwapper<T,false> () (inout);
|
||||
}
|
||||
};
|
||||
|
||||
template <bool SwapEndianess, typename T>
|
||||
struct Getter<SwapEndianess,T,false> {
|
||||
|
||||
void operator() (T* inout, bool /*le*/) {
|
||||
// static branch
|
||||
ByteSwapper<T,(SwapEndianess && sizeof(T)>1)> () (inout);
|
||||
}
|
||||
void operator() (T* inout, bool /*le*/) {
|
||||
// static branch
|
||||
ByteSwapper<T,(SwapEndianess && sizeof(T)>1)> () (inout);
|
||||
}
|
||||
};
|
||||
} // end Intern
|
||||
} // end Assimp
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -55,19 +55,19 @@ struct aiMaterial;
|
|||
struct aiImporterDesc;
|
||||
|
||||
namespace _melange_ {
|
||||
class BaseObject; // c4d_file.h
|
||||
class PolygonObject;
|
||||
class BaseMaterial;
|
||||
class BaseShader;
|
||||
class BaseObject; // c4d_file.h
|
||||
class PolygonObject;
|
||||
class BaseMaterial;
|
||||
class BaseShader;
|
||||
}
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
/** Importer class to load Cinema4D files using the Melange library to be obtained from
|
||||
|
@ -79,42 +79,42 @@ class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter>
|
|||
{
|
||||
public:
|
||||
|
||||
C4DImporter();
|
||||
~C4DImporter();
|
||||
C4DImporter();
|
||||
~C4DImporter();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
private:
|
||||
|
||||
void ReadMaterials(_melange_::BaseMaterial* mat);
|
||||
void RecurseHierarchy(_melange_::BaseObject* object, aiNode* parent);
|
||||
aiMesh* ReadMesh(_melange_::BaseObject* object);
|
||||
unsigned int ResolveMaterial(_melange_::PolygonObject* obj);
|
||||
void ReadMaterials(_melange_::BaseMaterial* mat);
|
||||
void RecurseHierarchy(_melange_::BaseObject* object, aiNode* parent);
|
||||
aiMesh* ReadMesh(_melange_::BaseObject* object);
|
||||
unsigned int ResolveMaterial(_melange_::PolygonObject* obj);
|
||||
|
||||
bool ReadShader(aiMaterial* out, _melange_::BaseShader* shader);
|
||||
bool ReadShader(aiMaterial* out, _melange_::BaseShader* shader);
|
||||
|
||||
std::vector<aiMesh*> meshes;
|
||||
std::vector<aiMaterial*> materials;
|
||||
std::vector<aiMesh*> meshes;
|
||||
std::vector<aiMaterial*> materials;
|
||||
|
||||
typedef std::map<_melange_::BaseMaterial*, unsigned int> MaterialMap;
|
||||
MaterialMap material_mapping;
|
||||
typedef std::map<_melange_::BaseMaterial*, unsigned int> MaterialMap;
|
||||
MaterialMap material_mapping;
|
||||
|
||||
}; // !class C4DImporter
|
||||
|
||||
|
|
|
@ -48,61 +48,61 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/assimp/IOStream.hpp"
|
||||
#include "../include/assimp/IOSystem.hpp"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Custom IOStream implementation for the C-API
|
||||
class CIOStreamWrapper : public IOStream
|
||||
{
|
||||
friend class CIOSystemWrapper;
|
||||
friend class CIOSystemWrapper;
|
||||
public:
|
||||
|
||||
CIOStreamWrapper(aiFile* pFile)
|
||||
: mFile(pFile)
|
||||
{}
|
||||
CIOStreamWrapper(aiFile* pFile)
|
||||
: mFile(pFile)
|
||||
{}
|
||||
|
||||
// ...................................................................
|
||||
size_t Read(void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount
|
||||
){
|
||||
// need to typecast here as C has no void*
|
||||
return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
|
||||
}
|
||||
// ...................................................................
|
||||
size_t Read(void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount
|
||||
){
|
||||
// need to typecast here as C has no void*
|
||||
return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
size_t Write(const void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount
|
||||
){
|
||||
// need to typecast here as C has no void*
|
||||
return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
|
||||
}
|
||||
// ...................................................................
|
||||
size_t Write(const void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount
|
||||
){
|
||||
// need to typecast here as C has no void*
|
||||
return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
aiReturn Seek(size_t pOffset,
|
||||
aiOrigin pOrigin
|
||||
){
|
||||
return mFile->SeekProc(mFile,pOffset,pOrigin);
|
||||
}
|
||||
// ...................................................................
|
||||
aiReturn Seek(size_t pOffset,
|
||||
aiOrigin pOrigin
|
||||
){
|
||||
return mFile->SeekProc(mFile,pOffset,pOrigin);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
size_t Tell(void) const {
|
||||
return mFile->TellProc(mFile);
|
||||
}
|
||||
// ...................................................................
|
||||
size_t Tell(void) const {
|
||||
return mFile->TellProc(mFile);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
size_t FileSize() const {
|
||||
return mFile->FileSizeProc(mFile);
|
||||
}
|
||||
// ...................................................................
|
||||
size_t FileSize() const {
|
||||
return mFile->FileSizeProc(mFile);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
void Flush () {
|
||||
return mFile->FlushProc(mFile);
|
||||
}
|
||||
// ...................................................................
|
||||
void Flush () {
|
||||
return mFile->FlushProc(mFile);
|
||||
}
|
||||
|
||||
private:
|
||||
aiFile* mFile;
|
||||
aiFile* mFile;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -110,48 +110,48 @@ private:
|
|||
class CIOSystemWrapper : public IOSystem
|
||||
{
|
||||
public:
|
||||
CIOSystemWrapper(aiFileIO* pFile)
|
||||
: mFileSystem(pFile)
|
||||
{}
|
||||
CIOSystemWrapper(aiFileIO* pFile)
|
||||
: mFileSystem(pFile)
|
||||
{}
|
||||
|
||||
// ...................................................................
|
||||
bool Exists( const char* pFile) const {
|
||||
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb");
|
||||
if (p){
|
||||
mFileSystem->CloseProc(mFileSystem,p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// ...................................................................
|
||||
bool Exists( const char* pFile) const {
|
||||
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb");
|
||||
if (p){
|
||||
mFileSystem->CloseProc(mFileSystem,p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
char getOsSeparator() const {
|
||||
// ...................................................................
|
||||
char getOsSeparator() const {
|
||||
#ifndef _WIN32
|
||||
return '/';
|
||||
return '/';
|
||||
#else
|
||||
return '\\';
|
||||
return '\\';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
IOStream* Open(const char* pFile,const char* pMode = "rb") {
|
||||
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
return new CIOStreamWrapper(p);
|
||||
}
|
||||
// ...................................................................
|
||||
IOStream* Open(const char* pFile,const char* pMode = "rb") {
|
||||
aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
return new CIOStreamWrapper(p);
|
||||
}
|
||||
|
||||
// ...................................................................
|
||||
void Close( IOStream* pFile) {
|
||||
if (!pFile) {
|
||||
return;
|
||||
}
|
||||
mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
|
||||
delete pFile;
|
||||
}
|
||||
// ...................................................................
|
||||
void Close( IOStream* pFile) {
|
||||
if (!pFile) {
|
||||
return;
|
||||
}
|
||||
mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile);
|
||||
delete pFile;
|
||||
}
|
||||
private:
|
||||
aiFileIO* mFileSystem;
|
||||
aiFileIO* mFileSystem;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
1736
code/COBLoader.cpp
1736
code/COBLoader.cpp
File diff suppressed because it is too large
Load Diff
148
code/COBLoader.h
148
code/COBLoader.h
|
@ -49,21 +49,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiNode;
|
||||
|
||||
namespace Assimp {
|
||||
class LineSplitter;
|
||||
namespace Assimp {
|
||||
class LineSplitter;
|
||||
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
|
||||
// COBScene.h
|
||||
namespace COB {
|
||||
struct ChunkInfo;
|
||||
struct Node;
|
||||
struct Scene;
|
||||
}
|
||||
// COBScene.h
|
||||
namespace COB {
|
||||
struct ChunkInfo;
|
||||
struct Node;
|
||||
struct Scene;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
/** Importer class to load TrueSpace files (cob,scn) up to v6.
|
||||
|
@ -73,99 +73,99 @@ namespace Assimp {
|
|||
class COBImporter : public BaseImporter
|
||||
{
|
||||
public:
|
||||
COBImporter();
|
||||
~COBImporter();
|
||||
COBImporter();
|
||||
~COBImporter();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Prepend 'COB: ' and throw msg.*/
|
||||
AI_WONT_RETURN static void ThrowException(const std::string& msg) AI_WONT_RETURN_SUFFIX;
|
||||
// -------------------------------------------------------------------
|
||||
/** Prepend 'COB: ' and throw msg.*/
|
||||
AI_WONT_RETURN static void ThrowException(const std::string& msg) AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Read from an ascii scene/object file
|
||||
* @param out Receives output data.
|
||||
* @param stream Stream to read from. */
|
||||
void ReadAsciiFile(COB::Scene& out, StreamReaderLE* stream);
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Read from an ascii scene/object file
|
||||
* @param out Receives output data.
|
||||
* @param stream Stream to read from. */
|
||||
void ReadAsciiFile(COB::Scene& out, StreamReaderLE* stream);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Read from a binary scene/object file
|
||||
* @param out Receives output data.
|
||||
* @param stream Stream to read from. */
|
||||
void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream);
|
||||
// -------------------------------------------------------------------
|
||||
/** @brief Read from a binary scene/object file
|
||||
* @param out Receives output data.
|
||||
* @param stream Stream to read from. */
|
||||
void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Conversion to Assimp output format
|
||||
// Conversion to Assimp output format
|
||||
|
||||
aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill);
|
||||
aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill);
|
||||
|
||||
private:
|
||||
|
||||
// ASCII file support
|
||||
// ASCII file support
|
||||
|
||||
void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name);
|
||||
void ReadChunkInfo_Ascii(COB::ChunkInfo& out, const LineSplitter& splitter);
|
||||
void ReadBasicNodeInfo_Ascii(COB::Node& msh, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
template <typename T> void ReadFloat3Tuple_Ascii(T& fill, const char** in);
|
||||
void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name);
|
||||
void ReadChunkInfo_Ascii(COB::ChunkInfo& out, const LineSplitter& splitter);
|
||||
void ReadBasicNodeInfo_Ascii(COB::Node& msh, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
template <typename T> void ReadFloat3Tuple_Ascii(T& fill, const char** in);
|
||||
|
||||
void ReadPolH_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadBitM_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadMat1_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadGrou_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadBone_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadCame_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadLght_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadUnit_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadPolH_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadBitM_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadMat1_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadGrou_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadBone_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadCame_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadLght_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadUnit_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
|
||||
|
||||
|
||||
// ASCII file logging stuff to add proper line numbers to messages
|
||||
// ASCII file logging stuff to add proper line numbers to messages
|
||||
|
||||
static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message);
|
||||
static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message);
|
||||
static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message);
|
||||
static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message);
|
||||
static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message);
|
||||
static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message);
|
||||
static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message);
|
||||
static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message);
|
||||
|
||||
static void LogWarn_Ascii (const Formatter::format& message);
|
||||
static void LogError_Ascii (const Formatter::format& message);
|
||||
static void LogInfo_Ascii (const Formatter::format& message);
|
||||
static void LogDebug_Ascii (const Formatter::format& message);
|
||||
static void LogWarn_Ascii (const Formatter::format& message);
|
||||
static void LogError_Ascii (const Formatter::format& message);
|
||||
static void LogInfo_Ascii (const Formatter::format& message);
|
||||
static void LogDebug_Ascii (const Formatter::format& message);
|
||||
|
||||
|
||||
// Binary file support
|
||||
// Binary file support
|
||||
|
||||
void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name);
|
||||
void ReadString_Binary(std::string& out, StreamReaderLE& reader);
|
||||
void ReadBasicNodeInfo_Binary(COB::Node& msh, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name);
|
||||
void ReadString_Binary(std::string& out, StreamReaderLE& reader);
|
||||
void ReadBasicNodeInfo_Binary(COB::Node& msh, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
|
||||
void ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadBitM_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadBitM_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
void ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo);
|
||||
|
||||
|
||||
}; // !class COBImporter
|
||||
|
|
218
code/COBScene.h
218
code/COBScene.h
|
@ -50,208 +50,208 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "BaseImporter.h"
|
||||
#include "./../include/assimp/material.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace COB {
|
||||
namespace Assimp {
|
||||
namespace COB {
|
||||
|
||||
// ------------------
|
||||
/** Represents a single vertex index in a face */
|
||||
struct VertexIndex
|
||||
{
|
||||
// intentionally uninitialized
|
||||
unsigned int pos_idx,uv_idx;
|
||||
// intentionally uninitialized
|
||||
unsigned int pos_idx,uv_idx;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Face data structure */
|
||||
struct Face
|
||||
{
|
||||
// intentionally uninitialized
|
||||
unsigned int material, flags;
|
||||
std::vector<VertexIndex> indices;
|
||||
// intentionally uninitialized
|
||||
unsigned int material, flags;
|
||||
std::vector<VertexIndex> indices;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB chunk header information */
|
||||
struct ChunkInfo
|
||||
{
|
||||
enum {NO_SIZE=UINT_MAX};
|
||||
enum {NO_SIZE=UINT_MAX};
|
||||
|
||||
ChunkInfo ()
|
||||
: id (0)
|
||||
, parent_id (0)
|
||||
, version (0)
|
||||
, size (NO_SIZE)
|
||||
{}
|
||||
ChunkInfo ()
|
||||
: id (0)
|
||||
, parent_id (0)
|
||||
, version (0)
|
||||
, size (NO_SIZE)
|
||||
{}
|
||||
|
||||
// Id of this chunk, unique within file
|
||||
unsigned int id;
|
||||
// Id of this chunk, unique within file
|
||||
unsigned int id;
|
||||
|
||||
// and the corresponding parent
|
||||
unsigned int parent_id;
|
||||
// and the corresponding parent
|
||||
unsigned int parent_id;
|
||||
|
||||
// version. v1.23 becomes 123
|
||||
unsigned int version;
|
||||
// version. v1.23 becomes 123
|
||||
unsigned int version;
|
||||
|
||||
// chunk size in bytes, only relevant for binary files
|
||||
// NO_SIZE is also valid.
|
||||
unsigned int size;
|
||||
// chunk size in bytes, only relevant for binary files
|
||||
// NO_SIZE is also valid.
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** A node in the scenegraph */
|
||||
struct Node : public ChunkInfo
|
||||
{
|
||||
enum Type {
|
||||
TYPE_MESH,TYPE_GROUP,TYPE_LIGHT,TYPE_CAMERA,TYPE_BONE
|
||||
};
|
||||
enum Type {
|
||||
TYPE_MESH,TYPE_GROUP,TYPE_LIGHT,TYPE_CAMERA,TYPE_BONE
|
||||
};
|
||||
|
||||
virtual ~Node() {}
|
||||
Node(Type type) : type(type), unit_scale(1.f){}
|
||||
virtual ~Node() {}
|
||||
Node(Type type) : type(type), unit_scale(1.f){}
|
||||
|
||||
Type type;
|
||||
Type type;
|
||||
|
||||
// used during resolving
|
||||
typedef std::deque<const Node*> ChildList;
|
||||
mutable ChildList temp_children;
|
||||
// used during resolving
|
||||
typedef std::deque<const Node*> ChildList;
|
||||
mutable ChildList temp_children;
|
||||
|
||||
// unique name
|
||||
std::string name;
|
||||
// unique name
|
||||
std::string name;
|
||||
|
||||
// local mesh transformation
|
||||
aiMatrix4x4 transform;
|
||||
// local mesh transformation
|
||||
aiMatrix4x4 transform;
|
||||
|
||||
// scaling for this node to get to the metric system
|
||||
float unit_scale;
|
||||
// scaling for this node to get to the metric system
|
||||
float unit_scale;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Mesh data structure */
|
||||
struct Mesh : public Node
|
||||
{
|
||||
using ChunkInfo::operator=;
|
||||
enum DrawFlags {
|
||||
SOLID = 0x1,
|
||||
TRANS = 0x2,
|
||||
WIRED = 0x4,
|
||||
BBOX = 0x8,
|
||||
HIDE = 0x10
|
||||
};
|
||||
using ChunkInfo::operator=;
|
||||
enum DrawFlags {
|
||||
SOLID = 0x1,
|
||||
TRANS = 0x2,
|
||||
WIRED = 0x4,
|
||||
BBOX = 0x8,
|
||||
HIDE = 0x10
|
||||
};
|
||||
|
||||
Mesh()
|
||||
: Node(TYPE_MESH)
|
||||
, draw_flags(SOLID)
|
||||
{}
|
||||
Mesh()
|
||||
: Node(TYPE_MESH)
|
||||
, draw_flags(SOLID)
|
||||
{}
|
||||
|
||||
// vertex elements
|
||||
std::vector<aiVector2D> texture_coords;
|
||||
std::vector<aiVector3D> vertex_positions;
|
||||
// vertex elements
|
||||
std::vector<aiVector2D> texture_coords;
|
||||
std::vector<aiVector3D> vertex_positions;
|
||||
|
||||
// face data
|
||||
std::vector<Face> faces;
|
||||
// face data
|
||||
std::vector<Face> faces;
|
||||
|
||||
// misc. drawing flags
|
||||
unsigned int draw_flags;
|
||||
// misc. drawing flags
|
||||
unsigned int draw_flags;
|
||||
|
||||
// used during resolving
|
||||
typedef std::deque<Face*> FaceRefList;
|
||||
typedef std::map< unsigned int,FaceRefList > TempMap;
|
||||
TempMap temp_map;
|
||||
// used during resolving
|
||||
typedef std::deque<Face*> FaceRefList;
|
||||
typedef std::map< unsigned int,FaceRefList > TempMap;
|
||||
TempMap temp_map;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Group data structure */
|
||||
struct Group : public Node
|
||||
{
|
||||
using ChunkInfo::operator=;
|
||||
Group() : Node(TYPE_GROUP) {}
|
||||
using ChunkInfo::operator=;
|
||||
Group() : Node(TYPE_GROUP) {}
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Bone data structure */
|
||||
struct Bone : public Node
|
||||
{
|
||||
using ChunkInfo::operator=;
|
||||
Bone() : Node(TYPE_BONE) {}
|
||||
using ChunkInfo::operator=;
|
||||
Bone() : Node(TYPE_BONE) {}
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Light data structure */
|
||||
struct Light : public Node
|
||||
{
|
||||
enum LightType {
|
||||
SPOT,LOCAL,INFINITE
|
||||
};
|
||||
enum LightType {
|
||||
SPOT,LOCAL,INFINITE
|
||||
};
|
||||
|
||||
using ChunkInfo::operator=;
|
||||
Light() : Node(TYPE_LIGHT),angle(),inner_angle(),ltype(SPOT) {}
|
||||
using ChunkInfo::operator=;
|
||||
Light() : Node(TYPE_LIGHT),angle(),inner_angle(),ltype(SPOT) {}
|
||||
|
||||
aiColor3D color;
|
||||
float angle,inner_angle;
|
||||
aiColor3D color;
|
||||
float angle,inner_angle;
|
||||
|
||||
LightType ltype;
|
||||
LightType ltype;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Camera data structure */
|
||||
struct Camera : public Node
|
||||
{
|
||||
using ChunkInfo::operator=;
|
||||
Camera() : Node(TYPE_CAMERA) {}
|
||||
using ChunkInfo::operator=;
|
||||
Camera() : Node(TYPE_CAMERA) {}
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Texture data structure */
|
||||
struct Texture
|
||||
{
|
||||
std::string path;
|
||||
aiUVTransform transform;
|
||||
std::string path;
|
||||
aiUVTransform transform;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** COB Material data structure */
|
||||
struct Material : ChunkInfo
|
||||
{
|
||||
using ChunkInfo::operator=;
|
||||
enum Shader {
|
||||
FLAT,PHONG,METAL
|
||||
};
|
||||
using ChunkInfo::operator=;
|
||||
enum Shader {
|
||||
FLAT,PHONG,METAL
|
||||
};
|
||||
|
||||
enum AutoFacet {
|
||||
FACETED,AUTOFACETED,SMOOTH
|
||||
};
|
||||
enum AutoFacet {
|
||||
FACETED,AUTOFACETED,SMOOTH
|
||||
};
|
||||
|
||||
Material() : alpha(),exp(),ior(),ka(),ks(1.f),
|
||||
matnum(UINT_MAX),
|
||||
shader(FLAT),autofacet(FACETED),
|
||||
autofacet_angle()
|
||||
{}
|
||||
Material() : alpha(),exp(),ior(),ka(),ks(1.f),
|
||||
matnum(UINT_MAX),
|
||||
shader(FLAT),autofacet(FACETED),
|
||||
autofacet_angle()
|
||||
{}
|
||||
|
||||
std::string type;
|
||||
std::string type;
|
||||
|
||||
aiColor3D rgb;
|
||||
float alpha, exp, ior,ka,ks;
|
||||
aiColor3D rgb;
|
||||
float alpha, exp, ior,ka,ks;
|
||||
|
||||
unsigned int matnum;
|
||||
Shader shader;
|
||||
unsigned int matnum;
|
||||
Shader shader;
|
||||
|
||||
AutoFacet autofacet;
|
||||
float autofacet_angle;
|
||||
AutoFacet autofacet;
|
||||
float autofacet_angle;
|
||||
|
||||
boost::shared_ptr<Texture> tex_env,tex_bump,tex_color;
|
||||
boost::shared_ptr<Texture> tex_env,tex_bump,tex_color;
|
||||
};
|
||||
|
||||
// ------------------
|
||||
/** Embedded bitmap, for instance for the thumbnail image */
|
||||
struct Bitmap : ChunkInfo
|
||||
{
|
||||
Bitmap() : orig_size() {}
|
||||
struct BitmapHeader
|
||||
{
|
||||
};
|
||||
Bitmap() : orig_size() {}
|
||||
struct BitmapHeader
|
||||
{
|
||||
};
|
||||
|
||||
BitmapHeader head;
|
||||
size_t orig_size;
|
||||
std::vector<char> buff_zipped;
|
||||
BitmapHeader head;
|
||||
size_t orig_size;
|
||||
std::vector<char> buff_zipped;
|
||||
};
|
||||
|
||||
typedef std::deque< boost::shared_ptr<Node> > NodeList;
|
||||
|
@ -261,14 +261,14 @@ typedef std::vector< Material > MaterialList;
|
|||
/** Represents a master COB scene, even if we loaded just a single COB file */
|
||||
struct Scene
|
||||
{
|
||||
NodeList nodes;
|
||||
MaterialList materials;
|
||||
NodeList nodes;
|
||||
MaterialList materials;
|
||||
|
||||
// becomes *0 later
|
||||
Bitmap thumbnail;
|
||||
// becomes *0 later
|
||||
Bitmap thumbnail;
|
||||
};
|
||||
|
||||
} // end COB
|
||||
} // end COB
|
||||
} // end Assimp
|
||||
|
||||
#endif
|
||||
|
|
|
@ -62,16 +62,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"CharacterStudio Motion Importer (MoCap)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"csm"
|
||||
"CharacterStudio Motion Importer (MoCap)",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"csm"
|
||||
};
|
||||
|
||||
|
||||
|
@ -90,217 +90,217 @@ CSMImporter::~CSMImporter()
|
|||
// Returns whether the class can handle the format of the given file.
|
||||
bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
// check file extension
|
||||
const std::string extension = GetExtension(pFile);
|
||||
// check file extension
|
||||
const std::string extension = GetExtension(pFile);
|
||||
|
||||
if( extension == "csm")
|
||||
return true;
|
||||
if( extension == "csm")
|
||||
return true;
|
||||
|
||||
if ((checkSig || !extension.length()) && pIOHandler) {
|
||||
const char* tokens[] = {"$Filename"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
if ((checkSig || !extension.length()) && pIOHandler) {
|
||||
const char* tokens[] = {"$Filename"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Build a string of all file extensions supported
|
||||
const aiImporterDesc* CSMImporter::GetInfo () const
|
||||
{
|
||||
return &desc;
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void CSMImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||
noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void CSMImporter::InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL) {
|
||||
throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
|
||||
}
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL) {
|
||||
throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
|
||||
}
|
||||
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
std::vector<char> mBuffer2;
|
||||
TextFileToBuffer(file.get(),mBuffer2);
|
||||
const char* buffer = &mBuffer2[0];
|
||||
// allocate storage and copy the contents of the file to a memory buffer
|
||||
std::vector<char> mBuffer2;
|
||||
TextFileToBuffer(file.get(),mBuffer2);
|
||||
const char* buffer = &mBuffer2[0];
|
||||
|
||||
aiAnimation* anim = new aiAnimation();
|
||||
int first = 0, last = 0x00ffffff;
|
||||
aiAnimation* anim = new aiAnimation();
|
||||
int first = 0, last = 0x00ffffff;
|
||||
|
||||
// now process the file and look out for '$' sections
|
||||
while (1) {
|
||||
SkipSpaces(&buffer);
|
||||
if ('\0' == *buffer)
|
||||
break;
|
||||
// now process the file and look out for '$' sections
|
||||
while (1) {
|
||||
SkipSpaces(&buffer);
|
||||
if ('\0' == *buffer)
|
||||
break;
|
||||
|
||||
if ('$' == *buffer) {
|
||||
++buffer;
|
||||
if (TokenMatchI(buffer,"firstframe",10)) {
|
||||
SkipSpaces(&buffer);
|
||||
first = strtol10(buffer,&buffer);
|
||||
}
|
||||
else if (TokenMatchI(buffer,"lastframe",9)) {
|
||||
SkipSpaces(&buffer);
|
||||
last = strtol10(buffer,&buffer);
|
||||
}
|
||||
else if (TokenMatchI(buffer,"rate",4)) {
|
||||
SkipSpaces(&buffer);
|
||||
float d;
|
||||
buffer = fast_atoreal_move<float>(buffer,d);
|
||||
anim->mTicksPerSecond = d;
|
||||
}
|
||||
else if (TokenMatchI(buffer,"order",5)) {
|
||||
std::vector< aiNodeAnim* > anims_temp;
|
||||
anims_temp.reserve(30);
|
||||
while (1) {
|
||||
SkipSpaces(&buffer);
|
||||
if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
|
||||
break; // next section
|
||||
if ('$' == *buffer) {
|
||||
++buffer;
|
||||
if (TokenMatchI(buffer,"firstframe",10)) {
|
||||
SkipSpaces(&buffer);
|
||||
first = strtol10(buffer,&buffer);
|
||||
}
|
||||
else if (TokenMatchI(buffer,"lastframe",9)) {
|
||||
SkipSpaces(&buffer);
|
||||
last = strtol10(buffer,&buffer);
|
||||
}
|
||||
else if (TokenMatchI(buffer,"rate",4)) {
|
||||
SkipSpaces(&buffer);
|
||||
float d;
|
||||
buffer = fast_atoreal_move<float>(buffer,d);
|
||||
anim->mTicksPerSecond = d;
|
||||
}
|
||||
else if (TokenMatchI(buffer,"order",5)) {
|
||||
std::vector< aiNodeAnim* > anims_temp;
|
||||
anims_temp.reserve(30);
|
||||
while (1) {
|
||||
SkipSpaces(&buffer);
|
||||
if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$')
|
||||
break; // next section
|
||||
|
||||
// Construct a new node animation channel and setup its name
|
||||
anims_temp.push_back(new aiNodeAnim());
|
||||
aiNodeAnim* nda = anims_temp.back();
|
||||
// Construct a new node animation channel and setup its name
|
||||
anims_temp.push_back(new aiNodeAnim());
|
||||
aiNodeAnim* nda = anims_temp.back();
|
||||
|
||||
char* ot = nda->mNodeName.data;
|
||||
while (!IsSpaceOrNewLine(*buffer))
|
||||
*ot++ = *buffer++;
|
||||
char* ot = nda->mNodeName.data;
|
||||
while (!IsSpaceOrNewLine(*buffer))
|
||||
*ot++ = *buffer++;
|
||||
|
||||
*ot = '\0';
|
||||
nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
|
||||
}
|
||||
*ot = '\0';
|
||||
nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
|
||||
}
|
||||
|
||||
anim->mNumChannels = anims_temp.size();
|
||||
if (!anim->mNumChannels)
|
||||
throw DeadlyImportError("CSM: Empty $order section");
|
||||
anim->mNumChannels = anims_temp.size();
|
||||
if (!anim->mNumChannels)
|
||||
throw DeadlyImportError("CSM: Empty $order section");
|
||||
|
||||
// copy over to the output animation
|
||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
||||
::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
|
||||
}
|
||||
else if (TokenMatchI(buffer,"points",6)) {
|
||||
if (!anim->mNumChannels)
|
||||
throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
|
||||
// copy over to the output animation
|
||||
anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
|
||||
::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels);
|
||||
}
|
||||
else if (TokenMatchI(buffer,"points",6)) {
|
||||
if (!anim->mNumChannels)
|
||||
throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'");
|
||||
|
||||
// If we know how many frames we'll read, we can preallocate some storage
|
||||
unsigned int alloc = 100;
|
||||
if (last != 0x00ffffff)
|
||||
{
|
||||
alloc = last-first;
|
||||
alloc += alloc>>2u; // + 25%
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i)
|
||||
anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
|
||||
}
|
||||
// If we know how many frames we'll read, we can preallocate some storage
|
||||
unsigned int alloc = 100;
|
||||
if (last != 0x00ffffff)
|
||||
{
|
||||
alloc = last-first;
|
||||
alloc += alloc>>2u; // + 25%
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i)
|
||||
anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc];
|
||||
}
|
||||
|
||||
unsigned int filled = 0;
|
||||
unsigned int filled = 0;
|
||||
|
||||
// Now read all point data.
|
||||
while (1) {
|
||||
SkipSpaces(&buffer);
|
||||
if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) {
|
||||
break; // next section
|
||||
}
|
||||
// Now read all point data.
|
||||
while (1) {
|
||||
SkipSpaces(&buffer);
|
||||
if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) {
|
||||
break; // next section
|
||||
}
|
||||
|
||||
// read frame
|
||||
const int frame = ::strtoul10(buffer,&buffer);
|
||||
last = std::max(frame,last);
|
||||
first = std::min(frame,last);
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
// read frame
|
||||
const int frame = ::strtoul10(buffer,&buffer);
|
||||
last = std::max(frame,last);
|
||||
first = std::min(frame,last);
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
|
||||
aiNodeAnim* s = anim->mChannels[i];
|
||||
if (s->mNumPositionKeys == alloc) { /* need to reallocate? */
|
||||
aiNodeAnim* s = anim->mChannels[i];
|
||||
if (s->mNumPositionKeys == alloc) { /* need to reallocate? */
|
||||
|
||||
aiVectorKey* old = s->mPositionKeys;
|
||||
s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
|
||||
::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
|
||||
delete[] old;
|
||||
}
|
||||
aiVectorKey* old = s->mPositionKeys;
|
||||
s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2];
|
||||
::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc);
|
||||
delete[] old;
|
||||
}
|
||||
|
||||
// read x,y,z
|
||||
if(!SkipSpacesAndLineEnd(&buffer))
|
||||
throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord");
|
||||
// read x,y,z
|
||||
if(!SkipSpacesAndLineEnd(&buffer))
|
||||
throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord");
|
||||
|
||||
if (TokenMatchI(buffer, "DROPOUT", 7)) {
|
||||
// seems this is invalid marker data; at least the doc says it's possible
|
||||
DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)");
|
||||
}
|
||||
else {
|
||||
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
|
||||
sub->mTime = (double)frame;
|
||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
|
||||
if (TokenMatchI(buffer, "DROPOUT", 7)) {
|
||||
// seems this is invalid marker data; at least the doc says it's possible
|
||||
DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)");
|
||||
}
|
||||
else {
|
||||
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
|
||||
sub->mTime = (double)frame;
|
||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x);
|
||||
|
||||
if(!SkipSpacesAndLineEnd(&buffer))
|
||||
throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord");
|
||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
|
||||
if(!SkipSpacesAndLineEnd(&buffer))
|
||||
throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord");
|
||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y);
|
||||
|
||||
if(!SkipSpacesAndLineEnd(&buffer))
|
||||
throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord");
|
||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
|
||||
if(!SkipSpacesAndLineEnd(&buffer))
|
||||
throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord");
|
||||
buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z);
|
||||
|
||||
++s->mNumPositionKeys;
|
||||
}
|
||||
}
|
||||
++s->mNumPositionKeys;
|
||||
}
|
||||
}
|
||||
|
||||
// update allocation granularity
|
||||
if (filled == alloc)
|
||||
alloc *= 2;
|
||||
// update allocation granularity
|
||||
if (filled == alloc)
|
||||
alloc *= 2;
|
||||
|
||||
++filled;
|
||||
}
|
||||
// all channels must be complete in order to continue safely.
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
++filled;
|
||||
}
|
||||
// all channels must be complete in order to continue safely.
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
|
||||
if (!anim->mChannels[i]->mNumPositionKeys)
|
||||
throw DeadlyImportError("CSM: Invalid marker track");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// advance to the next line
|
||||
SkipLine(&buffer);
|
||||
}
|
||||
}
|
||||
if (!anim->mChannels[i]->mNumPositionKeys)
|
||||
throw DeadlyImportError("CSM: Invalid marker track");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// advance to the next line
|
||||
SkipLine(&buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup a proper animation duration
|
||||
anim->mDuration = last - std::min( first, 0 );
|
||||
// Setup a proper animation duration
|
||||
anim->mDuration = last - std::min( first, 0 );
|
||||
|
||||
// build a dummy root node with the tiny markers as children
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mName.Set("$CSM_DummyRoot");
|
||||
// build a dummy root node with the tiny markers as children
|
||||
pScene->mRootNode = new aiNode();
|
||||
pScene->mRootNode->mName.Set("$CSM_DummyRoot");
|
||||
|
||||
pScene->mRootNode->mNumChildren = anim->mNumChannels;
|
||||
pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels];
|
||||
pScene->mRootNode->mNumChildren = anim->mNumChannels;
|
||||
pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels];
|
||||
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
aiNodeAnim* na = anim->mChannels[i];
|
||||
for (unsigned int i = 0; i < anim->mNumChannels;++i) {
|
||||
aiNodeAnim* na = anim->mChannels[i];
|
||||
|
||||
aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode();
|
||||
nd->mName = anim->mChannels[i]->mNodeName;
|
||||
nd->mParent = pScene->mRootNode;
|
||||
aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode();
|
||||
nd->mName = anim->mChannels[i]->mNodeName;
|
||||
nd->mParent = pScene->mRootNode;
|
||||
|
||||
aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation);
|
||||
}
|
||||
aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation);
|
||||
}
|
||||
|
||||
// Store the one and only animation in the scene
|
||||
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1];
|
||||
pScene->mAnimations[0] = anim;
|
||||
anim->mName.Set("$CSM_MasterAnim");
|
||||
// Store the one and only animation in the scene
|
||||
pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1];
|
||||
pScene->mAnimations[0] = anim;
|
||||
anim->mName.Set("$CSM_MasterAnim");
|
||||
|
||||
// mark the scene as incomplete and run SkeletonMeshBuilder on it
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||
// mark the scene as incomplete and run SkeletonMeshBuilder on it
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||
|
||||
if (!noSkeletonMesh) {
|
||||
SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true);
|
||||
}
|
||||
if (!noSkeletonMesh) {
|
||||
SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_CSM_IMPORTER
|
||||
|
|
|
@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "BaseImporter.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Importer class to load MOCAPs in CharacterStudio Motion format.
|
||||
|
@ -60,30 +60,30 @@ namespace Assimp {
|
|||
class CSMImporter : public BaseImporter
|
||||
{
|
||||
public:
|
||||
CSMImporter();
|
||||
~CSMImporter();
|
||||
CSMImporter();
|
||||
~CSMImporter();
|
||||
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
// -------------------------------------------------------------------
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// -------------------------------------------------------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
// -------------------------------------------------------------------
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
private:
|
||||
|
||||
bool noSkeletonMesh;
|
||||
bool noSkeletonMesh;
|
||||
|
||||
}; // end of class CSMImporter
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -56,21 +56,21 @@ using namespace Assimp;
|
|||
CalcTangentsProcess::CalcTangentsProcess()
|
||||
: configMaxAngle( AI_DEG_TO_RAD(45.f) )
|
||||
, configSourceUV( 0 ) {
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
CalcTangentsProcess::~CalcTangentsProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_CalcTangentSpace) != 0;
|
||||
return (pFlags & aiProcess_CalcTangentSpace) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -79,12 +79,12 @@ void CalcTangentsProcess::SetupProperties(const Importer* pImp)
|
|||
{
|
||||
ai_assert( NULL != pImp );
|
||||
|
||||
// get the current value of the property
|
||||
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
|
||||
configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
|
||||
configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
|
||||
// get the current value of the property
|
||||
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
|
||||
configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
|
||||
configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
|
||||
|
||||
configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0);
|
||||
configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -95,12 +95,12 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
|
|||
|
||||
DefaultLogger::get()->debug("CalcTangentsProcess begin");
|
||||
|
||||
bool bHas = false;
|
||||
for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
|
||||
if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
|
||||
bool bHas = false;
|
||||
for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
|
||||
if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
|
||||
}
|
||||
|
||||
if ( bHas ) {
|
||||
if ( bHas ) {
|
||||
DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated");
|
||||
} else {
|
||||
DefaultLogger::get()->debug("CalcTangentsProcess finished");
|
||||
|
@ -111,106 +111,106 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
|
|||
// Calculates tangents and bitangents for the given mesh
|
||||
bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
||||
{
|
||||
// we assume that the mesh is still in the verbose vertex format where each face has its own set
|
||||
// of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
|
||||
// assert() it here.
|
||||
// we assume that the mesh is still in the verbose vertex format where each face has its own set
|
||||
// of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
|
||||
// assert() it here.
|
||||
// assert( must be verbose, dammit);
|
||||
|
||||
if (pMesh->mTangents) // this implies that mBitangents is also there
|
||||
return false;
|
||||
if (pMesh->mTangents) // this implies that mBitangents is also there
|
||||
return false;
|
||||
|
||||
// If the mesh consists of lines and/or points but not of
|
||||
// triangles or higher-order polygons the normal vectors
|
||||
// are undefined.
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
|
||||
{
|
||||
DefaultLogger::get()->info("Tangents are undefined for line and point meshes");
|
||||
return false;
|
||||
}
|
||||
// If the mesh consists of lines and/or points but not of
|
||||
// triangles or higher-order polygons the normal vectors
|
||||
// are undefined.
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
|
||||
{
|
||||
DefaultLogger::get()->info("Tangents are undefined for line and point meshes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
|
||||
if( pMesh->mNormals == NULL)
|
||||
{
|
||||
DefaultLogger::get()->error("Failed to compute tangents; need normals");
|
||||
return false;
|
||||
}
|
||||
if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
|
||||
{
|
||||
DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
|
||||
return false;
|
||||
}
|
||||
// what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
|
||||
if( pMesh->mNormals == NULL)
|
||||
{
|
||||
DefaultLogger::get()->error("Failed to compute tangents; need normals");
|
||||
return false;
|
||||
}
|
||||
if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
|
||||
{
|
||||
DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
|
||||
return false;
|
||||
}
|
||||
|
||||
const float angleEpsilon = 0.9999f;
|
||||
const float angleEpsilon = 0.9999f;
|
||||
|
||||
std::vector<bool> vertexDone( pMesh->mNumVertices, false);
|
||||
const float qnan = get_qnan();
|
||||
std::vector<bool> vertexDone( pMesh->mNumVertices, false);
|
||||
const float qnan = get_qnan();
|
||||
|
||||
// create space for the tangents and bitangents
|
||||
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
|
||||
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
|
||||
// create space for the tangents and bitangents
|
||||
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
|
||||
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
|
||||
|
||||
const aiVector3D* meshPos = pMesh->mVertices;
|
||||
const aiVector3D* meshNorm = pMesh->mNormals;
|
||||
const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV];
|
||||
aiVector3D* meshTang = pMesh->mTangents;
|
||||
aiVector3D* meshBitang = pMesh->mBitangents;
|
||||
const aiVector3D* meshPos = pMesh->mVertices;
|
||||
const aiVector3D* meshNorm = pMesh->mNormals;
|
||||
const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV];
|
||||
aiVector3D* meshTang = pMesh->mTangents;
|
||||
aiVector3D* meshBitang = pMesh->mBitangents;
|
||||
|
||||
// calculate the tangent and bitangent for every face
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3)
|
||||
{
|
||||
// There are less than three indices, thus the tangent vector
|
||||
// is not defined. We are finished with these vertices now,
|
||||
// their tangent vectors are set to qnan.
|
||||
for (unsigned int i = 0; i < face.mNumIndices;++i)
|
||||
{
|
||||
unsigned int idx = face.mIndices[i];
|
||||
vertexDone [idx] = true;
|
||||
meshTang [idx] = aiVector3D(qnan);
|
||||
meshBitang [idx] = aiVector3D(qnan);
|
||||
}
|
||||
// calculate the tangent and bitangent for every face
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3)
|
||||
{
|
||||
// There are less than three indices, thus the tangent vector
|
||||
// is not defined. We are finished with these vertices now,
|
||||
// their tangent vectors are set to qnan.
|
||||
for (unsigned int i = 0; i < face.mNumIndices;++i)
|
||||
{
|
||||
unsigned int idx = face.mIndices[i];
|
||||
vertexDone [idx] = true;
|
||||
meshTang [idx] = aiVector3D(qnan);
|
||||
meshBitang [idx] = aiVector3D(qnan);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// triangle or polygon... we always use only the first three indices. A polygon
|
||||
// is supposed to be planar anyways....
|
||||
// FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
|
||||
const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
|
||||
// triangle or polygon... we always use only the first three indices. A polygon
|
||||
// is supposed to be planar anyways....
|
||||
// FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
|
||||
const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
|
||||
|
||||
// position differences p1->p2 and p1->p3
|
||||
aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
|
||||
// position differences p1->p2 and p1->p3
|
||||
aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
|
||||
|
||||
// texture offset p1->p2 and p1->p3
|
||||
float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
|
||||
// texture offset p1->p2 and p1->p3
|
||||
float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
|
||||
float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
|
||||
float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
|
||||
float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
|
||||
// when t1, t2, t3 in same position in UV space, just use default UV direction.
|
||||
if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) {
|
||||
sx = 0.0; sy = 1.0;
|
||||
tx = 1.0; ty = 0.0;
|
||||
}
|
||||
|
||||
// tangent points in the direction where to positive X axis of the texture coord's would point in model space
|
||||
// bitangent's points along the positive Y axis of the texture coord's, respectively
|
||||
aiVector3D tangent, bitangent;
|
||||
tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
|
||||
// tangent points in the direction where to positive X axis of the texture coord's would point in model space
|
||||
// bitangent's points along the positive Y axis of the texture coord's, respectively
|
||||
aiVector3D tangent, bitangent;
|
||||
tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
|
||||
tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
|
||||
tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
|
||||
bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
|
||||
bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
|
||||
bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
|
||||
|
||||
// store for every vertex of that face
|
||||
for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
|
||||
unsigned int p = face.mIndices[b];
|
||||
// store for every vertex of that face
|
||||
for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
|
||||
unsigned int p = face.mIndices[b];
|
||||
|
||||
// project tangent and bitangent into the plane formed by the vertex' normal
|
||||
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
|
||||
localTangent.Normalize(); localBitangent.Normalize();
|
||||
// project tangent and bitangent into the plane formed by the vertex' normal
|
||||
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
|
||||
localTangent.Normalize(); localBitangent.Normalize();
|
||||
|
||||
// reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
|
||||
bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
|
||||
|
@ -226,92 +226,92 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
}
|
||||
|
||||
// and write it into the mesh.
|
||||
meshTang[ p ] = localTangent;
|
||||
meshBitang[ p ] = localBitangent;
|
||||
}
|
||||
meshTang[ p ] = localTangent;
|
||||
meshBitang[ p ] = localBitangent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// create a helper to quickly find locally close vertices among the vertex array
|
||||
// FIX: check whether we can reuse the SpatialSort of a previous step
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort _vertexFinder;
|
||||
float posEpsilon;
|
||||
if (shared)
|
||||
{
|
||||
std::vector<std::pair<SpatialSort,float> >* avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
||||
if (avf)
|
||||
{
|
||||
std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
|
||||
vertexFinder = &blubb.first;
|
||||
posEpsilon = blubb.second;;
|
||||
}
|
||||
}
|
||||
if (!vertexFinder)
|
||||
{
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
vertexFinder = &_vertexFinder;
|
||||
posEpsilon = ComputePositionEpsilon(pMesh);
|
||||
}
|
||||
std::vector<unsigned int> verticesFound;
|
||||
// create a helper to quickly find locally close vertices among the vertex array
|
||||
// FIX: check whether we can reuse the SpatialSort of a previous step
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort _vertexFinder;
|
||||
float posEpsilon;
|
||||
if (shared)
|
||||
{
|
||||
std::vector<std::pair<SpatialSort,float> >* avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
||||
if (avf)
|
||||
{
|
||||
std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
|
||||
vertexFinder = &blubb.first;
|
||||
posEpsilon = blubb.second;;
|
||||
}
|
||||
}
|
||||
if (!vertexFinder)
|
||||
{
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
vertexFinder = &_vertexFinder;
|
||||
posEpsilon = ComputePositionEpsilon(pMesh);
|
||||
}
|
||||
std::vector<unsigned int> verticesFound;
|
||||
|
||||
const float fLimit = cosf(configMaxAngle);
|
||||
std::vector<unsigned int> closeVertices;
|
||||
const float fLimit = cosf(configMaxAngle);
|
||||
std::vector<unsigned int> closeVertices;
|
||||
|
||||
// in the second pass we now smooth out all tangents and bitangents at the same local position
|
||||
// if they are not too far off.
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
{
|
||||
if( vertexDone[a])
|
||||
continue;
|
||||
// in the second pass we now smooth out all tangents and bitangents at the same local position
|
||||
// if they are not too far off.
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
{
|
||||
if( vertexDone[a])
|
||||
continue;
|
||||
|
||||
const aiVector3D& origPos = pMesh->mVertices[a];
|
||||
const aiVector3D& origNorm = pMesh->mNormals[a];
|
||||
const aiVector3D& origTang = pMesh->mTangents[a];
|
||||
const aiVector3D& origBitang = pMesh->mBitangents[a];
|
||||
closeVertices.resize( 0 );
|
||||
const aiVector3D& origPos = pMesh->mVertices[a];
|
||||
const aiVector3D& origNorm = pMesh->mNormals[a];
|
||||
const aiVector3D& origTang = pMesh->mTangents[a];
|
||||
const aiVector3D& origBitang = pMesh->mBitangents[a];
|
||||
closeVertices.resize( 0 );
|
||||
|
||||
// find all vertices close to that position
|
||||
vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
|
||||
// find all vertices close to that position
|
||||
vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
|
||||
|
||||
closeVertices.reserve (verticesFound.size()+5);
|
||||
closeVertices.push_back( a);
|
||||
closeVertices.reserve (verticesFound.size()+5);
|
||||
closeVertices.push_back( a);
|
||||
|
||||
// look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
|
||||
for( unsigned int b = 0; b < verticesFound.size(); b++)
|
||||
{
|
||||
unsigned int idx = verticesFound[b];
|
||||
if( vertexDone[idx])
|
||||
continue;
|
||||
if( meshNorm[idx] * origNorm < angleEpsilon)
|
||||
continue;
|
||||
if( meshTang[idx] * origTang < fLimit)
|
||||
continue;
|
||||
if( meshBitang[idx] * origBitang < fLimit)
|
||||
continue;
|
||||
// look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
|
||||
for( unsigned int b = 0; b < verticesFound.size(); b++)
|
||||
{
|
||||
unsigned int idx = verticesFound[b];
|
||||
if( vertexDone[idx])
|
||||
continue;
|
||||
if( meshNorm[idx] * origNorm < angleEpsilon)
|
||||
continue;
|
||||
if( meshTang[idx] * origTang < fLimit)
|
||||
continue;
|
||||
if( meshBitang[idx] * origBitang < fLimit)
|
||||
continue;
|
||||
|
||||
// it's similar enough -> add it to the smoothing group
|
||||
closeVertices.push_back( idx);
|
||||
vertexDone[idx] = true;
|
||||
}
|
||||
// it's similar enough -> add it to the smoothing group
|
||||
closeVertices.push_back( idx);
|
||||
vertexDone[idx] = true;
|
||||
}
|
||||
|
||||
// smooth the tangents and bitangents of all vertices that were found to be close enough
|
||||
aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
smoothTangent += meshTang[ closeVertices[b] ];
|
||||
smoothBitangent += meshBitang[ closeVertices[b] ];
|
||||
}
|
||||
smoothTangent.Normalize();
|
||||
smoothBitangent.Normalize();
|
||||
// smooth the tangents and bitangents of all vertices that were found to be close enough
|
||||
aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
smoothTangent += meshTang[ closeVertices[b] ];
|
||||
smoothBitangent += meshBitang[ closeVertices[b] ];
|
||||
}
|
||||
smoothTangent.Normalize();
|
||||
smoothBitangent.Normalize();
|
||||
|
||||
// and write it back into all affected tangents
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
meshTang[ closeVertices[b] ] = smoothTangent;
|
||||
meshBitang[ closeVertices[b] ] = smoothBitangent;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
// and write it back into all affected tangents
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
meshTang[ closeVertices[b] ] = smoothTangent;
|
||||
meshBitang[ closeVertices[b] ] = smoothBitangent;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -61,53 +61,53 @@ class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess
|
|||
{
|
||||
public:
|
||||
|
||||
CalcTangentsProcess();
|
||||
~CalcTangentsProcess();
|
||||
CalcTangentsProcess();
|
||||
~CalcTangentsProcess();
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with.
|
||||
* A bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with.
|
||||
* A bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
|
||||
// setter for configMaxAngle
|
||||
inline void SetMaxSmoothAngle(float f)
|
||||
{
|
||||
configMaxAngle =f;
|
||||
}
|
||||
// setter for configMaxAngle
|
||||
inline void SetMaxSmoothAngle(float f)
|
||||
{
|
||||
configMaxAngle =f;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Calculates tangents and bitangents for a specific mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
* @param meshIndex Index of the mesh
|
||||
*/
|
||||
bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
|
||||
// -------------------------------------------------------------------
|
||||
/** Calculates tangents and bitangents for a specific mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
* @param meshIndex Index of the mesh
|
||||
*/
|
||||
bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
private:
|
||||
|
||||
/** Configuration option: maximum smoothing angle, in radians*/
|
||||
float configMaxAngle;
|
||||
unsigned int configSourceUV;
|
||||
/** Configuration option: maximum smoothing angle, in radians*/
|
||||
float configMaxAngle;
|
||||
unsigned int configSourceUV;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -65,88 +65,88 @@ namespace Assimp
|
|||
class ColladaExporter
|
||||
{
|
||||
public:
|
||||
/// Constructor for a specific scene to export
|
||||
ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
|
||||
/// Constructor for a specific scene to export
|
||||
ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
|
||||
|
||||
/// Destructor
|
||||
virtual ~ColladaExporter();
|
||||
/// Destructor
|
||||
virtual ~ColladaExporter();
|
||||
|
||||
protected:
|
||||
/// Starts writing the contents
|
||||
void WriteFile();
|
||||
/// Starts writing the contents
|
||||
void WriteFile();
|
||||
|
||||
/// Writes the asset header
|
||||
void WriteHeader();
|
||||
/// Writes the asset header
|
||||
void WriteHeader();
|
||||
|
||||
/// Writes the embedded textures
|
||||
void WriteTextures();
|
||||
/// Writes the embedded textures
|
||||
void WriteTextures();
|
||||
|
||||
/// Writes the material setup
|
||||
void WriteMaterials();
|
||||
/// Writes the material setup
|
||||
void WriteMaterials();
|
||||
|
||||
/// Writes the cameras library
|
||||
void WriteCamerasLibrary();
|
||||
/// Writes the cameras library
|
||||
void WriteCamerasLibrary();
|
||||
|
||||
// Write a camera entry
|
||||
void WriteCamera(size_t pIndex);
|
||||
// Write a camera entry
|
||||
void WriteCamera(size_t pIndex);
|
||||
|
||||
/// Writes the cameras library
|
||||
void WriteLightsLibrary();
|
||||
/// Writes the cameras library
|
||||
void WriteLightsLibrary();
|
||||
|
||||
// Write a camera entry
|
||||
void WriteLight(size_t pIndex);
|
||||
void WritePointLight(const aiLight *const light);
|
||||
void WriteDirectionalLight(const aiLight *const light);
|
||||
void WriteSpotLight(const aiLight *const light);
|
||||
void WriteAmbienttLight(const aiLight *const light);
|
||||
// Write a camera entry
|
||||
void WriteLight(size_t pIndex);
|
||||
void WritePointLight(const aiLight *const light);
|
||||
void WriteDirectionalLight(const aiLight *const light);
|
||||
void WriteSpotLight(const aiLight *const light);
|
||||
void WriteAmbienttLight(const aiLight *const light);
|
||||
|
||||
/// Writes the geometry library
|
||||
void WriteGeometryLibrary();
|
||||
/// Writes the geometry library
|
||||
void WriteGeometryLibrary();
|
||||
|
||||
/// Writes the given mesh
|
||||
void WriteGeometry( size_t pIndex);
|
||||
/// Writes the given mesh
|
||||
void WriteGeometry( size_t pIndex);
|
||||
|
||||
enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color };
|
||||
enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color };
|
||||
|
||||
/// Writes a float array of the given type
|
||||
void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount);
|
||||
/// Writes a float array of the given type
|
||||
void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount);
|
||||
|
||||
/// Writes the scene library
|
||||
void WriteSceneLibrary();
|
||||
/// Writes the scene library
|
||||
void WriteSceneLibrary();
|
||||
|
||||
/// Recursively writes the given node
|
||||
void WriteNode( aiNode* pNode);
|
||||
/// Recursively writes the given node
|
||||
void WriteNode( aiNode* pNode);
|
||||
|
||||
/// Enters a new xml element, which increases the indentation
|
||||
void PushTag() { startstr.append( " "); }
|
||||
/// Leaves an element, decreasing the indentation
|
||||
void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); }
|
||||
/// Enters a new xml element, which increases the indentation
|
||||
void PushTag() { startstr.append( " "); }
|
||||
/// Leaves an element, decreasing the indentation
|
||||
void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); }
|
||||
|
||||
/// Creates a mesh ID for the given mesh
|
||||
std::string GetMeshId( size_t pIndex) const { return std::string( "meshId" ) + boost::lexical_cast<std::string> (pIndex); }
|
||||
/// Creates a mesh ID for the given mesh
|
||||
std::string GetMeshId( size_t pIndex) const { return std::string( "meshId" ) + boost::lexical_cast<std::string> (pIndex); }
|
||||
|
||||
public:
|
||||
/// Stringstream to write all output into
|
||||
std::stringstream mOutput;
|
||||
/// Stringstream to write all output into
|
||||
std::stringstream mOutput;
|
||||
|
||||
protected:
|
||||
/// The IOSystem for output
|
||||
IOSystem* mIOSystem;
|
||||
/// The IOSystem for output
|
||||
IOSystem* mIOSystem;
|
||||
|
||||
/// Path of the directory where the scene will be exported
|
||||
const std::string mPath;
|
||||
/// Path of the directory where the scene will be exported
|
||||
const std::string mPath;
|
||||
|
||||
/// Name of the file (without extension) where the scene will be exported
|
||||
const std::string mFile;
|
||||
/// Name of the file (without extension) where the scene will be exported
|
||||
const std::string mFile;
|
||||
|
||||
/// The scene to be written
|
||||
const aiScene* mScene;
|
||||
bool mSceneOwned;
|
||||
/// The scene to be written
|
||||
const aiScene* mScene;
|
||||
bool mSceneOwned;
|
||||
|
||||
/// current line start string, contains the current indentation for simple stream insertion
|
||||
std::string startstr;
|
||||
/// current line end string for simple stream insertion
|
||||
std::string endstr;
|
||||
/// current line start string, contains the current indentation for simple stream insertion
|
||||
std::string startstr;
|
||||
/// current line end string for simple stream insertion
|
||||
std::string endstr;
|
||||
|
||||
// pair of color and texture - texture precedences color
|
||||
struct Surface
|
||||
|
@ -161,8 +161,8 @@ protected:
|
|||
struct Property
|
||||
{
|
||||
bool exist;
|
||||
float value;
|
||||
Property()
|
||||
float value;
|
||||
Property()
|
||||
: exist(false)
|
||||
, value(0.0f)
|
||||
{}
|
||||
|
@ -174,7 +174,7 @@ protected:
|
|||
std::string name;
|
||||
std::string shading_model;
|
||||
Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
|
||||
Property shininess, transparency, index_refraction;
|
||||
Property shininess, transparency, index_refraction;
|
||||
|
||||
Material() {}
|
||||
};
|
||||
|
|
|
@ -53,79 +53,79 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiMaterial;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Collada {
|
||||
namespace Assimp {
|
||||
namespace Collada {
|
||||
|
||||
/** Collada file versions which evolved during the years ... */
|
||||
enum FormatVersion
|
||||
{
|
||||
FV_1_5_n,
|
||||
FV_1_4_n,
|
||||
FV_1_3_n
|
||||
FV_1_5_n,
|
||||
FV_1_4_n,
|
||||
FV_1_3_n
|
||||
};
|
||||
|
||||
|
||||
/** Transformation types that can be applied to a node */
|
||||
enum TransformType
|
||||
{
|
||||
TF_LOOKAT,
|
||||
TF_ROTATE,
|
||||
TF_TRANSLATE,
|
||||
TF_SCALE,
|
||||
TF_SKEW,
|
||||
TF_MATRIX
|
||||
TF_LOOKAT,
|
||||
TF_ROTATE,
|
||||
TF_TRANSLATE,
|
||||
TF_SCALE,
|
||||
TF_SKEW,
|
||||
TF_MATRIX
|
||||
};
|
||||
|
||||
/** Different types of input data to a vertex or face */
|
||||
enum InputType
|
||||
{
|
||||
IT_Invalid,
|
||||
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
|
||||
IT_Position,
|
||||
IT_Normal,
|
||||
IT_Texcoord,
|
||||
IT_Color,
|
||||
IT_Tangent,
|
||||
IT_Bitangent
|
||||
IT_Invalid,
|
||||
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
|
||||
IT_Position,
|
||||
IT_Normal,
|
||||
IT_Texcoord,
|
||||
IT_Color,
|
||||
IT_Tangent,
|
||||
IT_Bitangent
|
||||
};
|
||||
|
||||
/** Contains all data for one of the different transformation types */
|
||||
struct Transform
|
||||
{
|
||||
std::string mID; ///< SID of the transform step, by which anim channels address their target node
|
||||
TransformType mType;
|
||||
float f[16]; ///< Interpretation of data depends on the type of the transformation
|
||||
std::string mID; ///< SID of the transform step, by which anim channels address their target node
|
||||
TransformType mType;
|
||||
float f[16]; ///< Interpretation of data depends on the type of the transformation
|
||||
};
|
||||
|
||||
/** A collada camera. */
|
||||
struct Camera
|
||||
{
|
||||
Camera()
|
||||
: mOrtho (false)
|
||||
, mHorFov (10e10f)
|
||||
, mVerFov (10e10f)
|
||||
, mAspect (10e10f)
|
||||
, mZNear (0.1f)
|
||||
, mZFar (1000.f)
|
||||
{}
|
||||
Camera()
|
||||
: mOrtho (false)
|
||||
, mHorFov (10e10f)
|
||||
, mVerFov (10e10f)
|
||||
, mAspect (10e10f)
|
||||
, mZNear (0.1f)
|
||||
, mZFar (1000.f)
|
||||
{}
|
||||
|
||||
// Name of camera
|
||||
std::string mName;
|
||||
// Name of camera
|
||||
std::string mName;
|
||||
|
||||
// True if it is an orthografic camera
|
||||
bool mOrtho;
|
||||
// True if it is an orthografic camera
|
||||
bool mOrtho;
|
||||
|
||||
//! Horizontal field of view in degrees
|
||||
float mHorFov;
|
||||
//! Horizontal field of view in degrees
|
||||
float mHorFov;
|
||||
|
||||
//! Vertical field of view in degrees
|
||||
float mVerFov;
|
||||
//! Vertical field of view in degrees
|
||||
float mVerFov;
|
||||
|
||||
//! Screen aspect
|
||||
float mAspect;
|
||||
//! Screen aspect
|
||||
float mAspect;
|
||||
|
||||
//! Near& far z
|
||||
float mZNear, mZFar;
|
||||
//! Near& far z
|
||||
float mZNear, mZFar;
|
||||
};
|
||||
|
||||
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
|
||||
|
@ -133,70 +133,70 @@ struct Camera
|
|||
/** A collada light source. */
|
||||
struct Light
|
||||
{
|
||||
Light()
|
||||
: mType (aiLightSource_UNDEFINED)
|
||||
, mAttConstant (1.f)
|
||||
, mAttLinear (0.f)
|
||||
, mAttQuadratic (0.f)
|
||||
, mFalloffAngle (180.f)
|
||||
, mFalloffExponent (0.f)
|
||||
, mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
||||
, mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
||||
, mIntensity (1.f)
|
||||
{}
|
||||
Light()
|
||||
: mType (aiLightSource_UNDEFINED)
|
||||
, mAttConstant (1.f)
|
||||
, mAttLinear (0.f)
|
||||
, mAttQuadratic (0.f)
|
||||
, mFalloffAngle (180.f)
|
||||
, mFalloffExponent (0.f)
|
||||
, mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
||||
, mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
|
||||
, mIntensity (1.f)
|
||||
{}
|
||||
|
||||
//! Type of the light source aiLightSourceType + ambient
|
||||
unsigned int mType;
|
||||
//! Type of the light source aiLightSourceType + ambient
|
||||
unsigned int mType;
|
||||
|
||||
//! Color of the light
|
||||
aiColor3D mColor;
|
||||
//! Color of the light
|
||||
aiColor3D mColor;
|
||||
|
||||
//! Light attenuation
|
||||
float mAttConstant,mAttLinear,mAttQuadratic;
|
||||
//! Light attenuation
|
||||
float mAttConstant,mAttLinear,mAttQuadratic;
|
||||
|
||||
//! Spot light falloff
|
||||
float mFalloffAngle;
|
||||
float mFalloffExponent;
|
||||
//! Spot light falloff
|
||||
float mFalloffAngle;
|
||||
float mFalloffExponent;
|
||||
|
||||
// -----------------------------------------------------
|
||||
// FCOLLADA extension from here
|
||||
// -----------------------------------------------------
|
||||
// FCOLLADA extension from here
|
||||
|
||||
//! ... related stuff from maja and max extensions
|
||||
float mPenumbraAngle;
|
||||
float mOuterAngle;
|
||||
//! ... related stuff from maja and max extensions
|
||||
float mPenumbraAngle;
|
||||
float mOuterAngle;
|
||||
|
||||
//! Common light intensity
|
||||
float mIntensity;
|
||||
//! Common light intensity
|
||||
float mIntensity;
|
||||
};
|
||||
|
||||
/** Short vertex index description */
|
||||
struct InputSemanticMapEntry
|
||||
{
|
||||
InputSemanticMapEntry()
|
||||
: mSet(0)
|
||||
, mType(IT_Invalid)
|
||||
{}
|
||||
InputSemanticMapEntry()
|
||||
: mSet(0)
|
||||
, mType(IT_Invalid)
|
||||
{}
|
||||
|
||||
//! Index of set, optional
|
||||
unsigned int mSet;
|
||||
//! Index of set, optional
|
||||
unsigned int mSet;
|
||||
|
||||
//! Type of referenced vertex input
|
||||
InputType mType;
|
||||
//! Type of referenced vertex input
|
||||
InputType mType;
|
||||
};
|
||||
|
||||
/** Table to map from effect to vertex input semantics */
|
||||
struct SemanticMappingTable
|
||||
{
|
||||
//! Name of material
|
||||
std::string mMatName;
|
||||
//! Name of material
|
||||
std::string mMatName;
|
||||
|
||||
//! List of semantic map commands, grouped by effect semantic name
|
||||
std::map<std::string, InputSemanticMapEntry> mMap;
|
||||
//! List of semantic map commands, grouped by effect semantic name
|
||||
std::map<std::string, InputSemanticMapEntry> mMap;
|
||||
|
||||
//! For std::find
|
||||
bool operator == (const std::string& s) const {
|
||||
return s == mMatName;
|
||||
}
|
||||
//! For std::find
|
||||
bool operator == (const std::string& s) const {
|
||||
return s == mMatName;
|
||||
}
|
||||
};
|
||||
|
||||
/** A reference to a mesh inside a node, including materials assigned to the various subgroups.
|
||||
|
@ -204,414 +204,414 @@ struct SemanticMappingTable
|
|||
*/
|
||||
struct MeshInstance
|
||||
{
|
||||
///< ID of the mesh or controller to be instanced
|
||||
std::string mMeshOrController;
|
||||
///< ID of the mesh or controller to be instanced
|
||||
std::string mMeshOrController;
|
||||
|
||||
///< Map of materials by the subgroup ID they're applied to
|
||||
std::map<std::string, SemanticMappingTable> mMaterials;
|
||||
///< Map of materials by the subgroup ID they're applied to
|
||||
std::map<std::string, SemanticMappingTable> mMaterials;
|
||||
};
|
||||
|
||||
/** A reference to a camera inside a node*/
|
||||
struct CameraInstance
|
||||
{
|
||||
///< ID of the camera
|
||||
std::string mCamera;
|
||||
///< ID of the camera
|
||||
std::string mCamera;
|
||||
};
|
||||
|
||||
/** A reference to a light inside a node*/
|
||||
struct LightInstance
|
||||
{
|
||||
///< ID of the camera
|
||||
std::string mLight;
|
||||
///< ID of the camera
|
||||
std::string mLight;
|
||||
};
|
||||
|
||||
/** A reference to a node inside a node*/
|
||||
struct NodeInstance
|
||||
{
|
||||
///< ID of the node
|
||||
std::string mNode;
|
||||
///< ID of the node
|
||||
std::string mNode;
|
||||
};
|
||||
|
||||
/** A node in a scene hierarchy */
|
||||
struct Node
|
||||
{
|
||||
std::string mName;
|
||||
std::string mID;
|
||||
std::string mName;
|
||||
std::string mID;
|
||||
std::string mSID;
|
||||
Node* mParent;
|
||||
std::vector<Node*> mChildren;
|
||||
Node* mParent;
|
||||
std::vector<Node*> mChildren;
|
||||
|
||||
/** Operations in order to calculate the resulting transformation to parent. */
|
||||
std::vector<Transform> mTransforms;
|
||||
/** Operations in order to calculate the resulting transformation to parent. */
|
||||
std::vector<Transform> mTransforms;
|
||||
|
||||
/** Meshes at this node */
|
||||
std::vector<MeshInstance> mMeshes;
|
||||
/** Meshes at this node */
|
||||
std::vector<MeshInstance> mMeshes;
|
||||
|
||||
/** Lights at this node */
|
||||
std::vector<LightInstance> mLights;
|
||||
/** Lights at this node */
|
||||
std::vector<LightInstance> mLights;
|
||||
|
||||
/** Cameras at this node */
|
||||
std::vector<CameraInstance> mCameras;
|
||||
/** Cameras at this node */
|
||||
std::vector<CameraInstance> mCameras;
|
||||
|
||||
/** Node instances at this node */
|
||||
std::vector<NodeInstance> mNodeInstances;
|
||||
/** Node instances at this node */
|
||||
std::vector<NodeInstance> mNodeInstances;
|
||||
|
||||
/** Rootnodes: Name of primary camera, if any */
|
||||
std::string mPrimaryCamera;
|
||||
/** Rootnodes: Name of primary camera, if any */
|
||||
std::string mPrimaryCamera;
|
||||
|
||||
//! Constructor. Begin with a zero parent
|
||||
Node() {
|
||||
mParent = NULL;
|
||||
}
|
||||
//! Constructor. Begin with a zero parent
|
||||
Node() {
|
||||
mParent = NULL;
|
||||
}
|
||||
|
||||
//! Destructor: delete all children subsequently
|
||||
~Node() {
|
||||
for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
//! Destructor: delete all children subsequently
|
||||
~Node() {
|
||||
for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
};
|
||||
|
||||
/** Data source array: either floats or strings */
|
||||
struct Data
|
||||
{
|
||||
bool mIsStringArray;
|
||||
std::vector<float> mValues;
|
||||
std::vector<std::string> mStrings;
|
||||
bool mIsStringArray;
|
||||
std::vector<float> mValues;
|
||||
std::vector<std::string> mStrings;
|
||||
};
|
||||
|
||||
/** Accessor to a data array */
|
||||
struct Accessor
|
||||
{
|
||||
size_t mCount; // in number of objects
|
||||
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
|
||||
size_t mOffset; // in number of values
|
||||
size_t mStride; // Stride in number of values
|
||||
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
|
||||
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
|
||||
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
|
||||
std::string mSource; // URL of the source array
|
||||
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
|
||||
size_t mCount; // in number of objects
|
||||
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
|
||||
size_t mOffset; // in number of values
|
||||
size_t mStride; // Stride in number of values
|
||||
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
|
||||
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
|
||||
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
|
||||
std::string mSource; // URL of the source array
|
||||
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
|
||||
|
||||
Accessor()
|
||||
{
|
||||
mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
|
||||
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
|
||||
}
|
||||
Accessor()
|
||||
{
|
||||
mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
|
||||
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/** A single face in a mesh */
|
||||
struct Face
|
||||
{
|
||||
std::vector<size_t> mIndices;
|
||||
std::vector<size_t> mIndices;
|
||||
};
|
||||
|
||||
/** An input channel for mesh data, referring to a single accessor */
|
||||
struct InputChannel
|
||||
{
|
||||
InputType mType; // Type of the data
|
||||
size_t mIndex; // Optional index, if multiple sets of the same data type are given
|
||||
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
|
||||
std::string mAccessor; // ID of the accessor where to read the actual values from.
|
||||
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
|
||||
InputType mType; // Type of the data
|
||||
size_t mIndex; // Optional index, if multiple sets of the same data type are given
|
||||
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
|
||||
std::string mAccessor; // ID of the accessor where to read the actual values from.
|
||||
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
|
||||
|
||||
InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
|
||||
InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
|
||||
};
|
||||
|
||||
/** Subset of a mesh with a certain material */
|
||||
struct SubMesh
|
||||
{
|
||||
std::string mMaterial; ///< subgroup identifier
|
||||
size_t mNumFaces; ///< number of faces in this submesh
|
||||
std::string mMaterial; ///< subgroup identifier
|
||||
size_t mNumFaces; ///< number of faces in this submesh
|
||||
};
|
||||
|
||||
/** Contains data for a single mesh */
|
||||
struct Mesh
|
||||
{
|
||||
Mesh()
|
||||
{
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
mNumUVComponents[i] = 2;
|
||||
}
|
||||
Mesh()
|
||||
{
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
|
||||
mNumUVComponents[i] = 2;
|
||||
}
|
||||
|
||||
std::string mName;
|
||||
|
||||
// just to check if there's some sophisticated addressing involved...
|
||||
// which we don't support, and therefore should warn about.
|
||||
std::string mVertexID;
|
||||
// just to check if there's some sophisticated addressing involved...
|
||||
// which we don't support, and therefore should warn about.
|
||||
std::string mVertexID;
|
||||
|
||||
// Vertex data addressed by vertex indices
|
||||
std::vector<InputChannel> mPerVertexData;
|
||||
// Vertex data addressed by vertex indices
|
||||
std::vector<InputChannel> mPerVertexData;
|
||||
|
||||
// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
|
||||
std::vector<aiVector3D> mPositions;
|
||||
std::vector<aiVector3D> mNormals;
|
||||
std::vector<aiVector3D> mTangents;
|
||||
std::vector<aiVector3D> mBitangents;
|
||||
std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
|
||||
std::vector<aiVector3D> mPositions;
|
||||
std::vector<aiVector3D> mNormals;
|
||||
std::vector<aiVector3D> mTangents;
|
||||
std::vector<aiVector3D> mBitangents;
|
||||
std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
|
||||
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
|
||||
// Faces. Stored are only the number of vertices for each face.
|
||||
// 1 == point, 2 == line, 3 == triangle, 4+ == poly
|
||||
std::vector<size_t> mFaceSize;
|
||||
// Faces. Stored are only the number of vertices for each face.
|
||||
// 1 == point, 2 == line, 3 == triangle, 4+ == poly
|
||||
std::vector<size_t> mFaceSize;
|
||||
|
||||
// Position indices for all faces in the sequence given in mFaceSize -
|
||||
// necessary for bone weight assignment
|
||||
std::vector<size_t> mFacePosIndices;
|
||||
// Position indices for all faces in the sequence given in mFaceSize -
|
||||
// necessary for bone weight assignment
|
||||
std::vector<size_t> mFacePosIndices;
|
||||
|
||||
// Submeshes in this mesh, each with a given material
|
||||
std::vector<SubMesh> mSubMeshes;
|
||||
// Submeshes in this mesh, each with a given material
|
||||
std::vector<SubMesh> mSubMeshes;
|
||||
};
|
||||
|
||||
/** Which type of primitives the ReadPrimitives() function is going to read */
|
||||
enum PrimitiveType
|
||||
{
|
||||
Prim_Invalid,
|
||||
Prim_Lines,
|
||||
Prim_LineStrip,
|
||||
Prim_Triangles,
|
||||
Prim_TriStrips,
|
||||
Prim_TriFans,
|
||||
Prim_Polylist,
|
||||
Prim_Polygon
|
||||
Prim_Invalid,
|
||||
Prim_Lines,
|
||||
Prim_LineStrip,
|
||||
Prim_Triangles,
|
||||
Prim_TriStrips,
|
||||
Prim_TriFans,
|
||||
Prim_Polylist,
|
||||
Prim_Polygon
|
||||
};
|
||||
|
||||
/** A skeleton controller to deform a mesh with the use of joints */
|
||||
struct Controller
|
||||
{
|
||||
// the URL of the mesh deformed by the controller.
|
||||
std::string mMeshId;
|
||||
// the URL of the mesh deformed by the controller.
|
||||
std::string mMeshId;
|
||||
|
||||
// accessor URL of the joint names
|
||||
std::string mJointNameSource;
|
||||
// accessor URL of the joint names
|
||||
std::string mJointNameSource;
|
||||
|
||||
///< The bind shape matrix, as array of floats. I'm not sure what this matrix actually describes, but it can't be ignored in all cases
|
||||
float mBindShapeMatrix[16];
|
||||
|
||||
// accessor URL of the joint inverse bind matrices
|
||||
std::string mJointOffsetMatrixSource;
|
||||
// accessor URL of the joint inverse bind matrices
|
||||
std::string mJointOffsetMatrixSource;
|
||||
|
||||
// input channel: joint names.
|
||||
InputChannel mWeightInputJoints;
|
||||
// input channel: joint weights
|
||||
InputChannel mWeightInputWeights;
|
||||
// input channel: joint names.
|
||||
InputChannel mWeightInputJoints;
|
||||
// input channel: joint weights
|
||||
InputChannel mWeightInputWeights;
|
||||
|
||||
// Number of weights per vertex.
|
||||
std::vector<size_t> mWeightCounts;
|
||||
// Number of weights per vertex.
|
||||
std::vector<size_t> mWeightCounts;
|
||||
|
||||
// JointIndex-WeightIndex pairs for all vertices
|
||||
std::vector< std::pair<size_t, size_t> > mWeights;
|
||||
// JointIndex-WeightIndex pairs for all vertices
|
||||
std::vector< std::pair<size_t, size_t> > mWeights;
|
||||
};
|
||||
|
||||
/** A collada material. Pretty much the only member is a reference to an effect. */
|
||||
struct Material
|
||||
{
|
||||
std::string mName;
|
||||
std::string mEffect;
|
||||
std::string mName;
|
||||
std::string mEffect;
|
||||
};
|
||||
|
||||
/** Type of the effect param */
|
||||
enum ParamType
|
||||
{
|
||||
Param_Sampler,
|
||||
Param_Surface
|
||||
Param_Sampler,
|
||||
Param_Surface
|
||||
};
|
||||
|
||||
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
|
||||
struct EffectParam
|
||||
{
|
||||
ParamType mType;
|
||||
std::string mReference; // to which other thing the param is referring to.
|
||||
ParamType mType;
|
||||
std::string mReference; // to which other thing the param is referring to.
|
||||
};
|
||||
|
||||
/** Shading type supported by the standard effect spec of Collada */
|
||||
enum ShadeType
|
||||
{
|
||||
Shade_Invalid,
|
||||
Shade_Constant,
|
||||
Shade_Lambert,
|
||||
Shade_Phong,
|
||||
Shade_Blinn
|
||||
Shade_Invalid,
|
||||
Shade_Constant,
|
||||
Shade_Lambert,
|
||||
Shade_Phong,
|
||||
Shade_Blinn
|
||||
};
|
||||
|
||||
/** Represents a texture sampler in collada */
|
||||
struct Sampler
|
||||
{
|
||||
Sampler()
|
||||
: mWrapU (true)
|
||||
, mWrapV (true)
|
||||
, mMirrorU ()
|
||||
, mMirrorV ()
|
||||
, mOp (aiTextureOp_Multiply)
|
||||
, mUVId (UINT_MAX)
|
||||
, mWeighting (1.f)
|
||||
, mMixWithPrevious (1.f)
|
||||
{}
|
||||
Sampler()
|
||||
: mWrapU (true)
|
||||
, mWrapV (true)
|
||||
, mMirrorU ()
|
||||
, mMirrorV ()
|
||||
, mOp (aiTextureOp_Multiply)
|
||||
, mUVId (UINT_MAX)
|
||||
, mWeighting (1.f)
|
||||
, mMixWithPrevious (1.f)
|
||||
{}
|
||||
|
||||
/** Name of image reference
|
||||
*/
|
||||
std::string mName;
|
||||
/** Name of image reference
|
||||
*/
|
||||
std::string mName;
|
||||
|
||||
/** Wrap U?
|
||||
*/
|
||||
bool mWrapU;
|
||||
/** Wrap U?
|
||||
*/
|
||||
bool mWrapU;
|
||||
|
||||
/** Wrap V?
|
||||
*/
|
||||
bool mWrapV;
|
||||
/** Wrap V?
|
||||
*/
|
||||
bool mWrapV;
|
||||
|
||||
/** Mirror U?
|
||||
*/
|
||||
bool mMirrorU;
|
||||
/** Mirror U?
|
||||
*/
|
||||
bool mMirrorU;
|
||||
|
||||
/** Mirror V?
|
||||
*/
|
||||
bool mMirrorV;
|
||||
/** Mirror V?
|
||||
*/
|
||||
bool mMirrorV;
|
||||
|
||||
/** Blend mode
|
||||
*/
|
||||
aiTextureOp mOp;
|
||||
/** Blend mode
|
||||
*/
|
||||
aiTextureOp mOp;
|
||||
|
||||
/** UV transformation
|
||||
*/
|
||||
aiUVTransform mTransform;
|
||||
/** UV transformation
|
||||
*/
|
||||
aiUVTransform mTransform;
|
||||
|
||||
/** Name of source UV channel
|
||||
*/
|
||||
std::string mUVChannel;
|
||||
/** Name of source UV channel
|
||||
*/
|
||||
std::string mUVChannel;
|
||||
|
||||
/** Resolved UV channel index or UINT_MAX if not known
|
||||
*/
|
||||
unsigned int mUVId;
|
||||
/** Resolved UV channel index or UINT_MAX if not known
|
||||
*/
|
||||
unsigned int mUVId;
|
||||
|
||||
// OKINO/MAX3D extensions from here
|
||||
// -------------------------------------------------------
|
||||
// OKINO/MAX3D extensions from here
|
||||
// -------------------------------------------------------
|
||||
|
||||
/** Weighting factor
|
||||
*/
|
||||
float mWeighting;
|
||||
/** Weighting factor
|
||||
*/
|
||||
float mWeighting;
|
||||
|
||||
/** Mixing factor from OKINO
|
||||
*/
|
||||
float mMixWithPrevious;
|
||||
/** Mixing factor from OKINO
|
||||
*/
|
||||
float mMixWithPrevious;
|
||||
};
|
||||
|
||||
/** A collada effect. Can contain about anything according to the Collada spec,
|
||||
but we limit our version to a reasonable subset. */
|
||||
struct Effect
|
||||
{
|
||||
// Shading mode
|
||||
ShadeType mShadeType;
|
||||
// Shading mode
|
||||
ShadeType mShadeType;
|
||||
|
||||
// Colors
|
||||
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
|
||||
mTransparent, mReflective;
|
||||
// Colors
|
||||
aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
|
||||
mTransparent, mReflective;
|
||||
|
||||
// Textures
|
||||
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
|
||||
mTexTransparent, mTexBump, mTexReflective;
|
||||
// Textures
|
||||
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
|
||||
mTexTransparent, mTexBump, mTexReflective;
|
||||
|
||||
// Scalar factory
|
||||
float mShininess, mRefractIndex, mReflectivity;
|
||||
float mTransparency;
|
||||
bool mHasTransparency;
|
||||
bool mRGBTransparency;
|
||||
// Scalar factory
|
||||
float mShininess, mRefractIndex, mReflectivity;
|
||||
float mTransparency;
|
||||
bool mHasTransparency;
|
||||
bool mRGBTransparency;
|
||||
|
||||
// local params referring to each other by their SID
|
||||
typedef std::map<std::string, Collada::EffectParam> ParamLibrary;
|
||||
ParamLibrary mParams;
|
||||
// local params referring to each other by their SID
|
||||
typedef std::map<std::string, Collada::EffectParam> ParamLibrary;
|
||||
ParamLibrary mParams;
|
||||
|
||||
// MAX3D extensions
|
||||
// ---------------------------------------------------------
|
||||
// Double-sided?
|
||||
bool mDoubleSided, mWireframe, mFaceted;
|
||||
// MAX3D extensions
|
||||
// ---------------------------------------------------------
|
||||
// Double-sided?
|
||||
bool mDoubleSided, mWireframe, mFaceted;
|
||||
|
||||
Effect()
|
||||
: mShadeType (Shade_Phong)
|
||||
, mEmissive ( 0, 0, 0, 1)
|
||||
, mAmbient ( 0.1f, 0.1f, 0.1f, 1)
|
||||
, mDiffuse ( 0.6f, 0.6f, 0.6f, 1)
|
||||
, mSpecular ( 0.4f, 0.4f, 0.4f, 1)
|
||||
, mTransparent ( 0, 0, 0, 1)
|
||||
, mShininess (10.0f)
|
||||
, mRefractIndex (1.f)
|
||||
, mReflectivity (1.f)
|
||||
, mTransparency (1.f)
|
||||
, mHasTransparency (false)
|
||||
, mRGBTransparency(false)
|
||||
, mDoubleSided (false)
|
||||
, mWireframe (false)
|
||||
, mFaceted (false)
|
||||
{
|
||||
}
|
||||
Effect()
|
||||
: mShadeType (Shade_Phong)
|
||||
, mEmissive ( 0, 0, 0, 1)
|
||||
, mAmbient ( 0.1f, 0.1f, 0.1f, 1)
|
||||
, mDiffuse ( 0.6f, 0.6f, 0.6f, 1)
|
||||
, mSpecular ( 0.4f, 0.4f, 0.4f, 1)
|
||||
, mTransparent ( 0, 0, 0, 1)
|
||||
, mShininess (10.0f)
|
||||
, mRefractIndex (1.f)
|
||||
, mReflectivity (1.f)
|
||||
, mTransparency (1.f)
|
||||
, mHasTransparency (false)
|
||||
, mRGBTransparency(false)
|
||||
, mDoubleSided (false)
|
||||
, mWireframe (false)
|
||||
, mFaceted (false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** An image, meaning texture */
|
||||
struct Image
|
||||
{
|
||||
std::string mFileName;
|
||||
std::string mFileName;
|
||||
|
||||
/** If image file name is zero, embedded image data
|
||||
*/
|
||||
std::vector<uint8_t> mImageData;
|
||||
/** If image file name is zero, embedded image data
|
||||
*/
|
||||
std::vector<uint8_t> mImageData;
|
||||
|
||||
/** If image file name is zero, file format of
|
||||
* embedded image data.
|
||||
*/
|
||||
std::string mEmbeddedFormat;
|
||||
/** If image file name is zero, file format of
|
||||
* embedded image data.
|
||||
*/
|
||||
std::string mEmbeddedFormat;
|
||||
|
||||
};
|
||||
|
||||
/** An animation channel. */
|
||||
struct AnimationChannel
|
||||
{
|
||||
/** URL of the data to animate. Could be about anything, but we support only the
|
||||
* "NodeID/TransformID.SubElement" notation
|
||||
*/
|
||||
std::string mTarget;
|
||||
/** URL of the data to animate. Could be about anything, but we support only the
|
||||
* "NodeID/TransformID.SubElement" notation
|
||||
*/
|
||||
std::string mTarget;
|
||||
|
||||
/** Source URL of the time values. Collada calls them "input". Meh. */
|
||||
std::string mSourceTimes;
|
||||
/** Source URL of the value values. Collada calls them "output". */
|
||||
std::string mSourceValues;
|
||||
/** Source URL of the time values. Collada calls them "input". Meh. */
|
||||
std::string mSourceTimes;
|
||||
/** Source URL of the value values. Collada calls them "output". */
|
||||
std::string mSourceValues;
|
||||
};
|
||||
|
||||
/** An animation. Container for 0-x animation channels or 0-x animations */
|
||||
struct Animation
|
||||
{
|
||||
/** Anim name */
|
||||
std::string mName;
|
||||
/** Anim name */
|
||||
std::string mName;
|
||||
|
||||
/** the animation channels, if any */
|
||||
std::vector<AnimationChannel> mChannels;
|
||||
/** the animation channels, if any */
|
||||
std::vector<AnimationChannel> mChannels;
|
||||
|
||||
/** the sub-animations, if any */
|
||||
std::vector<Animation*> mSubAnims;
|
||||
/** the sub-animations, if any */
|
||||
std::vector<Animation*> mSubAnims;
|
||||
|
||||
/** Destructor */
|
||||
~Animation()
|
||||
{
|
||||
for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
/** Destructor */
|
||||
~Animation()
|
||||
{
|
||||
for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
};
|
||||
|
||||
/** Description of a collada animation channel which has been determined to affect the current node */
|
||||
struct ChannelEntry
|
||||
{
|
||||
const Collada::AnimationChannel* mChannel; ///> the source channel
|
||||
std::string mTransformId; // the ID of the transformation step of the node which is influenced
|
||||
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
|
||||
size_t mSubElement; // starting index inside the transform data
|
||||
const Collada::AnimationChannel* mChannel; ///> the source channel
|
||||
std::string mTransformId; // the ID of the transformation step of the node which is influenced
|
||||
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
|
||||
size_t mSubElement; // starting index inside the transform data
|
||||
|
||||
// resolved data references
|
||||
const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
|
||||
const Collada::Data* mTimeData; ///> Source data array for the time values
|
||||
const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
|
||||
const Collada::Data* mValueData; ///> Source datat array for the key value values
|
||||
// resolved data references
|
||||
const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
|
||||
const Collada::Data* mTimeData; ///> Source data array for the time values
|
||||
const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
|
||||
const Collada::Data* mValueData; ///> Source datat array for the key value values
|
||||
|
||||
ChannelEntry()
|
||||
ChannelEntry()
|
||||
: mChannel()
|
||||
, mTransformIndex()
|
||||
, mSubElement()
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -57,26 +57,26 @@ namespace Assimp
|
|||
|
||||
struct ColladaMeshIndex
|
||||
{
|
||||
std::string mMeshID;
|
||||
size_t mSubMesh;
|
||||
std::string mMaterial;
|
||||
ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial)
|
||||
: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
|
||||
{ }
|
||||
std::string mMeshID;
|
||||
size_t mSubMesh;
|
||||
std::string mMaterial;
|
||||
ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial)
|
||||
: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
|
||||
{ }
|
||||
|
||||
bool operator < (const ColladaMeshIndex& p) const
|
||||
{
|
||||
if( mMeshID == p.mMeshID)
|
||||
{
|
||||
if( mSubMesh == p.mSubMesh)
|
||||
return mMaterial < p.mMaterial;
|
||||
else
|
||||
return mSubMesh < p.mSubMesh;
|
||||
} else
|
||||
{
|
||||
return mMeshID < p.mMeshID;
|
||||
}
|
||||
}
|
||||
bool operator < (const ColladaMeshIndex& p) const
|
||||
{
|
||||
if( mMeshID == p.mMeshID)
|
||||
{
|
||||
if( mSubMesh == p.mSubMesh)
|
||||
return mMaterial < p.mMaterial;
|
||||
else
|
||||
return mSubMesh < p.mSubMesh;
|
||||
} else
|
||||
{
|
||||
return mMeshID < p.mMeshID;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
|
||||
|
@ -85,166 +85,166 @@ struct ColladaMeshIndex
|
|||
class ColladaLoader : public BaseImporter
|
||||
{
|
||||
public:
|
||||
ColladaLoader();
|
||||
~ColladaLoader();
|
||||
ColladaLoader();
|
||||
~ColladaLoader();
|
||||
|
||||
|
||||
public:
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
|
||||
|
||||
protected:
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
|
||||
/** Recursively constructs a scene node for the given parser node and returns it. */
|
||||
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
|
||||
/** Recursively constructs a scene node for the given parser node and returns it. */
|
||||
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
|
||||
|
||||
/** Resolve node instances */
|
||||
void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
std::vector<const Collada::Node*>& resolved);
|
||||
/** Resolve node instances */
|
||||
void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
std::vector<const Collada::Node*>& resolved);
|
||||
|
||||
/** Builds meshes for the given node and references them */
|
||||
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
aiNode* pTarget);
|
||||
/** Builds meshes for the given node and references them */
|
||||
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
aiNode* pTarget);
|
||||
|
||||
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
|
||||
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
||||
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
|
||||
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
|
||||
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
||||
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
|
||||
|
||||
/** Builds cameras for the given node and references them */
|
||||
void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
aiNode* pTarget);
|
||||
/** Builds cameras for the given node and references them */
|
||||
void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
aiNode* pTarget);
|
||||
|
||||
/** Builds lights for the given node and references them */
|
||||
void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
aiNode* pTarget);
|
||||
/** Builds lights for the given node and references them */
|
||||
void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
aiNode* pTarget);
|
||||
|
||||
/** Stores all meshes in the given scene */
|
||||
void StoreSceneMeshes( aiScene* pScene);
|
||||
/** Stores all meshes in the given scene */
|
||||
void StoreSceneMeshes( aiScene* pScene);
|
||||
|
||||
/** Stores all materials in the given scene */
|
||||
void StoreSceneMaterials( aiScene* pScene);
|
||||
/** Stores all materials in the given scene */
|
||||
void StoreSceneMaterials( aiScene* pScene);
|
||||
|
||||
/** Stores all lights in the given scene */
|
||||
void StoreSceneLights( aiScene* pScene);
|
||||
/** Stores all lights in the given scene */
|
||||
void StoreSceneLights( aiScene* pScene);
|
||||
|
||||
/** Stores all cameras in the given scene */
|
||||
void StoreSceneCameras( aiScene* pScene);
|
||||
/** Stores all cameras in the given scene */
|
||||
void StoreSceneCameras( aiScene* pScene);
|
||||
|
||||
/** Stores all textures in the given scene */
|
||||
void StoreSceneTextures( aiScene* pScene);
|
||||
/** Stores all textures in the given scene */
|
||||
void StoreSceneTextures( aiScene* pScene);
|
||||
|
||||
/** Stores all animations
|
||||
* @param pScene target scene to store the anims
|
||||
*/
|
||||
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser);
|
||||
/** Stores all animations
|
||||
* @param pScene target scene to store the anims
|
||||
*/
|
||||
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser);
|
||||
|
||||
/** Stores all animations for the given source anim and its nested child animations
|
||||
* @param pScene target scene to store the anims
|
||||
* @param pSrcAnim the source animation to process
|
||||
* @param pPrefix Prefix to the name in case of nested animations
|
||||
*/
|
||||
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pPrefix);
|
||||
/** Stores all animations for the given source anim and its nested child animations
|
||||
* @param pScene target scene to store the anims
|
||||
* @param pSrcAnim the source animation to process
|
||||
* @param pPrefix Prefix to the name in case of nested animations
|
||||
*/
|
||||
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pPrefix);
|
||||
|
||||
/** Constructs the animation for the given source anim */
|
||||
void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName);
|
||||
/** Constructs the animation for the given source anim */
|
||||
void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName);
|
||||
|
||||
/** Constructs materials from the collada material definitions */
|
||||
void BuildMaterials( ColladaParser& pParser, aiScene* pScene);
|
||||
/** Constructs materials from the collada material definitions */
|
||||
void BuildMaterials( ColladaParser& pParser, aiScene* pScene);
|
||||
|
||||
/** Fill materials from the collada material definitions */
|
||||
void FillMaterials( const ColladaParser& pParser, aiScene* pScene);
|
||||
/** Fill materials from the collada material definitions */
|
||||
void FillMaterials( const ColladaParser& pParser, aiScene* pScene);
|
||||
|
||||
/** Resolve UV channel mappings*/
|
||||
void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
|
||||
const Collada::SemanticMappingTable& table);
|
||||
/** Resolve UV channel mappings*/
|
||||
void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
|
||||
const Collada::SemanticMappingTable& table);
|
||||
|
||||
/** Add a texture and all of its sampling properties to a material*/
|
||||
void AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
|
||||
const Collada::Effect& effect,
|
||||
const Collada::Sampler& sampler,
|
||||
aiTextureType type, unsigned int idx = 0);
|
||||
/** Add a texture and all of its sampling properties to a material*/
|
||||
void AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
|
||||
const Collada::Effect& effect,
|
||||
const Collada::Sampler& sampler,
|
||||
aiTextureType type, unsigned int idx = 0);
|
||||
|
||||
/** Resolves the texture name for the given effect texture entry */
|
||||
aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
|
||||
const Collada::Effect& pEffect, const std::string& pName);
|
||||
/** Resolves the texture name for the given effect texture entry */
|
||||
aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
|
||||
const Collada::Effect& pEffect, const std::string& pName);
|
||||
|
||||
/** Converts a path read from a collada file to the usual representation */
|
||||
void ConvertPath( aiString& ss);
|
||||
/** Converts a path read from a collada file to the usual representation */
|
||||
void ConvertPath( aiString& ss);
|
||||
|
||||
/** Reads a float value from an accessor and its data array.
|
||||
* @param pAccessor The accessor to use for reading
|
||||
* @param pData The data array to read from
|
||||
* @param pIndex The index of the element to retrieve
|
||||
* @param pOffset Offset into the element, for multipart elements such as vectors or matrices
|
||||
* @return the specified value
|
||||
*/
|
||||
float ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const;
|
||||
/** Reads a float value from an accessor and its data array.
|
||||
* @param pAccessor The accessor to use for reading
|
||||
* @param pData The data array to read from
|
||||
* @param pIndex The index of the element to retrieve
|
||||
* @param pOffset Offset into the element, for multipart elements such as vectors or matrices
|
||||
* @return the specified value
|
||||
*/
|
||||
float ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const;
|
||||
|
||||
/** Reads a string value from an accessor and its data array.
|
||||
* @param pAccessor The accessor to use for reading
|
||||
* @param pData The data array to read from
|
||||
* @param pIndex The index of the element to retrieve
|
||||
* @return the specified value
|
||||
*/
|
||||
const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const;
|
||||
/** Reads a string value from an accessor and its data array.
|
||||
* @param pAccessor The accessor to use for reading
|
||||
* @param pData The data array to read from
|
||||
* @param pIndex The index of the element to retrieve
|
||||
* @return the specified value
|
||||
*/
|
||||
const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const;
|
||||
|
||||
/** Recursively collects all nodes into the given array */
|
||||
void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const;
|
||||
/** Recursively collects all nodes into the given array */
|
||||
void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const;
|
||||
|
||||
/** Finds a node in the collada scene by the given name */
|
||||
const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const;
|
||||
/** Finds a node in the collada scene by the given SID */
|
||||
const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
|
||||
/** Finds a node in the collada scene by the given name */
|
||||
const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const;
|
||||
/** Finds a node in the collada scene by the given SID */
|
||||
const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
|
||||
|
||||
/** Finds a proper name for a node derived from the collada-node's properties */
|
||||
std::string FindNameForNode( const Collada::Node* pNode);
|
||||
/** Finds a proper name for a node derived from the collada-node's properties */
|
||||
std::string FindNameForNode( const Collada::Node* pNode);
|
||||
|
||||
protected:
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
|
||||
/** Which mesh-material compound was stored under which mesh ID */
|
||||
std::map<ColladaMeshIndex, size_t> mMeshIndexByID;
|
||||
/** Which mesh-material compound was stored under which mesh ID */
|
||||
std::map<ColladaMeshIndex, size_t> mMeshIndexByID;
|
||||
|
||||
/** Which material was stored under which index in the scene */
|
||||
std::map<std::string, size_t> mMaterialIndexByName;
|
||||
/** Which material was stored under which index in the scene */
|
||||
std::map<std::string, size_t> mMaterialIndexByName;
|
||||
|
||||
/** Accumulated meshes for the target scene */
|
||||
std::vector<aiMesh*> mMeshes;
|
||||
/** Accumulated meshes for the target scene */
|
||||
std::vector<aiMesh*> mMeshes;
|
||||
|
||||
/** Temporary material list */
|
||||
std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
|
||||
/** Temporary material list */
|
||||
std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
|
||||
|
||||
/** Temporary camera list */
|
||||
std::vector<aiCamera*> mCameras;
|
||||
/** Temporary camera list */
|
||||
std::vector<aiCamera*> mCameras;
|
||||
|
||||
/** Temporary light list */
|
||||
std::vector<aiLight*> mLights;
|
||||
/** Temporary light list */
|
||||
std::vector<aiLight*> mLights;
|
||||
|
||||
/** Temporary texture list */
|
||||
std::vector<aiTexture*> mTextures;
|
||||
/** Temporary texture list */
|
||||
std::vector<aiTexture*> mTextures;
|
||||
|
||||
/** Accumulated animations for the target scene */
|
||||
std::vector<aiAnimation*> mAnims;
|
||||
/** Accumulated animations for the target scene */
|
||||
std::vector<aiAnimation*> mAnims;
|
||||
|
||||
bool noSkeletonMesh;
|
||||
bool ignoreUpDirection;
|
||||
bool invertTransparency;
|
||||
bool noSkeletonMesh;
|
||||
bool ignoreUpDirection;
|
||||
bool invertTransparency;
|
||||
|
||||
/** Used by FindNameForNode() to generate unique node names */
|
||||
unsigned int mNodeNameCounter;
|
||||
/** Used by FindNameForNode() to generate unique node names */
|
||||
unsigned int mNodeNameCounter;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -61,279 +61,279 @@ namespace Assimp
|
|||
*/
|
||||
class ColladaParser
|
||||
{
|
||||
friend class ColladaLoader;
|
||||
friend class ColladaLoader;
|
||||
|
||||
protected:
|
||||
/** Constructor from XML file */
|
||||
ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
|
||||
/** Constructor from XML file */
|
||||
ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
|
||||
|
||||
/** Destructor */
|
||||
~ColladaParser();
|
||||
/** Destructor */
|
||||
~ColladaParser();
|
||||
|
||||
/** Reads the contents of the file */
|
||||
void ReadContents();
|
||||
/** Reads the contents of the file */
|
||||
void ReadContents();
|
||||
|
||||
/** Reads the structure of the file */
|
||||
void ReadStructure();
|
||||
/** Reads the structure of the file */
|
||||
void ReadStructure();
|
||||
|
||||
/** Reads asset informations such as coordinate system informations and legal blah */
|
||||
void ReadAssetInfo();
|
||||
/** Reads asset informations such as coordinate system informations and legal blah */
|
||||
void ReadAssetInfo();
|
||||
|
||||
/** Reads the animation library */
|
||||
void ReadAnimationLibrary();
|
||||
/** Reads the animation library */
|
||||
void ReadAnimationLibrary();
|
||||
|
||||
/** Reads an animation into the given parent structure */
|
||||
void ReadAnimation( Collada::Animation* pParent);
|
||||
/** Reads an animation into the given parent structure */
|
||||
void ReadAnimation( Collada::Animation* pParent);
|
||||
|
||||
/** Reads an animation sampler into the given anim channel */
|
||||
void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
|
||||
/** Reads an animation sampler into the given anim channel */
|
||||
void ReadAnimationSampler( Collada::AnimationChannel& pChannel);
|
||||
|
||||
/** Reads the skeleton controller library */
|
||||
void ReadControllerLibrary();
|
||||
/** Reads the skeleton controller library */
|
||||
void ReadControllerLibrary();
|
||||
|
||||
/** Reads a controller into the given mesh structure */
|
||||
void ReadController( Collada::Controller& pController);
|
||||
/** Reads a controller into the given mesh structure */
|
||||
void ReadController( Collada::Controller& pController);
|
||||
|
||||
/** Reads the joint definitions for the given controller */
|
||||
void ReadControllerJoints( Collada::Controller& pController);
|
||||
/** Reads the joint definitions for the given controller */
|
||||
void ReadControllerJoints( Collada::Controller& pController);
|
||||
|
||||
/** Reads the joint weights for the given controller */
|
||||
void ReadControllerWeights( Collada::Controller& pController);
|
||||
/** Reads the joint weights for the given controller */
|
||||
void ReadControllerWeights( Collada::Controller& pController);
|
||||
|
||||
/** Reads the image library contents */
|
||||
void ReadImageLibrary();
|
||||
/** Reads the image library contents */
|
||||
void ReadImageLibrary();
|
||||
|
||||
/** Reads an image entry into the given image */
|
||||
void ReadImage( Collada::Image& pImage);
|
||||
/** Reads an image entry into the given image */
|
||||
void ReadImage( Collada::Image& pImage);
|
||||
|
||||
/** Reads the material library */
|
||||
void ReadMaterialLibrary();
|
||||
/** Reads the material library */
|
||||
void ReadMaterialLibrary();
|
||||
|
||||
/** Reads a material entry into the given material */
|
||||
void ReadMaterial( Collada::Material& pMaterial);
|
||||
/** Reads a material entry into the given material */
|
||||
void ReadMaterial( Collada::Material& pMaterial);
|
||||
|
||||
/** Reads the camera library */
|
||||
void ReadCameraLibrary();
|
||||
/** Reads the camera library */
|
||||
void ReadCameraLibrary();
|
||||
|
||||
/** Reads a camera entry into the given camera */
|
||||
void ReadCamera( Collada::Camera& pCamera);
|
||||
/** Reads a camera entry into the given camera */
|
||||
void ReadCamera( Collada::Camera& pCamera);
|
||||
|
||||
/** Reads the light library */
|
||||
void ReadLightLibrary();
|
||||
/** Reads the light library */
|
||||
void ReadLightLibrary();
|
||||
|
||||
/** Reads a light entry into the given light */
|
||||
void ReadLight( Collada::Light& pLight);
|
||||
/** Reads a light entry into the given light */
|
||||
void ReadLight( Collada::Light& pLight);
|
||||
|
||||
/** Reads the effect library */
|
||||
void ReadEffectLibrary();
|
||||
/** Reads the effect library */
|
||||
void ReadEffectLibrary();
|
||||
|
||||
/** Reads an effect entry into the given effect*/
|
||||
void ReadEffect( Collada::Effect& pEffect);
|
||||
/** Reads an effect entry into the given effect*/
|
||||
void ReadEffect( Collada::Effect& pEffect);
|
||||
|
||||
/** Reads an COMMON effect profile */
|
||||
void ReadEffectProfileCommon( Collada::Effect& pEffect);
|
||||
/** Reads an COMMON effect profile */
|
||||
void ReadEffectProfileCommon( Collada::Effect& pEffect);
|
||||
|
||||
/** Read sampler properties */
|
||||
void ReadSamplerProperties( Collada::Sampler& pSampler);
|
||||
/** Read sampler properties */
|
||||
void ReadSamplerProperties( Collada::Sampler& pSampler);
|
||||
|
||||
/** Reads an effect entry containing a color or a texture defining that color */
|
||||
void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
|
||||
/** Reads an effect entry containing a color or a texture defining that color */
|
||||
void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler);
|
||||
|
||||
/** Reads an effect entry containing a float */
|
||||
void ReadEffectFloat( float& pFloat);
|
||||
/** Reads an effect entry containing a float */
|
||||
void ReadEffectFloat( float& pFloat);
|
||||
|
||||
/** Reads an effect parameter specification of any kind */
|
||||
void ReadEffectParam( Collada::EffectParam& pParam);
|
||||
/** Reads an effect parameter specification of any kind */
|
||||
void ReadEffectParam( Collada::EffectParam& pParam);
|
||||
|
||||
/** Reads the geometry library contents */
|
||||
void ReadGeometryLibrary();
|
||||
/** Reads the geometry library contents */
|
||||
void ReadGeometryLibrary();
|
||||
|
||||
/** Reads a geometry from the geometry library. */
|
||||
void ReadGeometry( Collada::Mesh* pMesh);
|
||||
/** Reads a geometry from the geometry library. */
|
||||
void ReadGeometry( Collada::Mesh* pMesh);
|
||||
|
||||
/** Reads a mesh from the geometry library */
|
||||
void ReadMesh( Collada::Mesh* pMesh);
|
||||
/** Reads a mesh from the geometry library */
|
||||
void ReadMesh( Collada::Mesh* pMesh);
|
||||
|
||||
/** Reads a source element - a combination of raw data and an accessor defining
|
||||
* things that should not be redefinable. Yes, that's another rant.
|
||||
*/
|
||||
void ReadSource();
|
||||
/** Reads a source element - a combination of raw data and an accessor defining
|
||||
* things that should not be redefinable. Yes, that's another rant.
|
||||
*/
|
||||
void ReadSource();
|
||||
|
||||
/** Reads a data array holding a number of elements, and stores it in the global library.
|
||||
* Currently supported are array of floats and arrays of strings.
|
||||
*/
|
||||
void ReadDataArray();
|
||||
/** Reads a data array holding a number of elements, and stores it in the global library.
|
||||
* Currently supported are array of floats and arrays of strings.
|
||||
*/
|
||||
void ReadDataArray();
|
||||
|
||||
/** Reads an accessor and stores it in the global library under the given ID -
|
||||
* accessors use the ID of the parent <source> element
|
||||
*/
|
||||
void ReadAccessor( const std::string& pID);
|
||||
/** Reads an accessor and stores it in the global library under the given ID -
|
||||
* accessors use the ID of the parent <source> element
|
||||
*/
|
||||
void ReadAccessor( const std::string& pID);
|
||||
|
||||
/** Reads input declarations of per-vertex mesh data into the given mesh */
|
||||
void ReadVertexData( Collada::Mesh* pMesh);
|
||||
/** Reads input declarations of per-vertex mesh data into the given mesh */
|
||||
void ReadVertexData( Collada::Mesh* pMesh);
|
||||
|
||||
/** Reads input declarations of per-index mesh data into the given mesh */
|
||||
void ReadIndexData( Collada::Mesh* pMesh);
|
||||
/** Reads input declarations of per-index mesh data into the given mesh */
|
||||
void ReadIndexData( Collada::Mesh* pMesh);
|
||||
|
||||
/** Reads a single input channel element and stores it in the given array, if valid */
|
||||
void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
|
||||
/** Reads a single input channel element and stores it in the given array, if valid */
|
||||
void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
|
||||
|
||||
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
|
||||
size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
|
||||
size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
|
||||
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
|
||||
size_t ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
|
||||
size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
|
||||
|
||||
/** Copies the data for a single primitive into the mesh, based on the InputChannels */
|
||||
void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
|
||||
Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
|
||||
size_t currentPrimitive, const std::vector<size_t>& indices);
|
||||
/** Copies the data for a single primitive into the mesh, based on the InputChannels */
|
||||
void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
|
||||
Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
|
||||
size_t currentPrimitive, const std::vector<size_t>& indices);
|
||||
|
||||
/** Reads one triangle of a tristrip into the mesh */
|
||||
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh,
|
||||
std::vector<Collada::InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices);
|
||||
/** Reads one triangle of a tristrip into the mesh */
|
||||
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh,
|
||||
std::vector<Collada::InputChannel>& pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t>& indices);
|
||||
|
||||
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
|
||||
void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
|
||||
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
|
||||
void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
|
||||
|
||||
/** Reads the library of node hierarchies and scene parts */
|
||||
void ReadSceneLibrary();
|
||||
/** Reads the library of node hierarchies and scene parts */
|
||||
void ReadSceneLibrary();
|
||||
|
||||
/** Reads a scene node's contents including children and stores it in the given node */
|
||||
void ReadSceneNode( Collada::Node* pNode);
|
||||
/** Reads a scene node's contents including children and stores it in the given node */
|
||||
void ReadSceneNode( Collada::Node* pNode);
|
||||
|
||||
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
|
||||
void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
|
||||
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
|
||||
void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
|
||||
|
||||
/** Reads a mesh reference in a node and adds it to the node's mesh list */
|
||||
void ReadNodeGeometry( Collada::Node* pNode);
|
||||
/** Reads a mesh reference in a node and adds it to the node's mesh list */
|
||||
void ReadNodeGeometry( Collada::Node* pNode);
|
||||
|
||||
/** Reads the collada scene */
|
||||
void ReadScene();
|
||||
/** Reads the collada scene */
|
||||
void ReadScene();
|
||||
|
||||
// Processes bind_vertex_input and bind elements
|
||||
void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
|
||||
// Processes bind_vertex_input and bind elements
|
||||
void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
|
||||
|
||||
protected:
|
||||
/** Aborts the file reading with an exception */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
|
||||
/** Aborts the file reading with an exception */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
|
||||
|
||||
/** Skips all data until the end node of the current element */
|
||||
void SkipElement();
|
||||
/** Skips all data until the end node of the current element */
|
||||
void SkipElement();
|
||||
|
||||
/** Skips all data until the end node of the given element */
|
||||
void SkipElement( const char* pElement);
|
||||
/** Skips all data until the end node of the given element */
|
||||
void SkipElement( const char* pElement);
|
||||
|
||||
/** Compares the current xml element name to the given string and returns true if equal */
|
||||
bool IsElement( const char* pName) const;
|
||||
/** Compares the current xml element name to the given string and returns true if equal */
|
||||
bool IsElement( const char* pName) const;
|
||||
|
||||
/** Tests for the opening tag of the given element, throws an exception if not found */
|
||||
void TestOpening( const char* pName);
|
||||
/** Tests for the opening tag of the given element, throws an exception if not found */
|
||||
void TestOpening( const char* pName);
|
||||
|
||||
/** Tests for the closing tag of the given element, throws an exception if not found */
|
||||
void TestClosing( const char* pName);
|
||||
/** Tests for the closing tag of the given element, throws an exception if not found */
|
||||
void TestClosing( const char* pName);
|
||||
|
||||
/** Checks the present element for the presence of the attribute, returns its index
|
||||
or throws an exception if not found */
|
||||
int GetAttribute( const char* pAttr) const;
|
||||
/** Checks the present element for the presence of the attribute, returns its index
|
||||
or throws an exception if not found */
|
||||
int GetAttribute( const char* pAttr) const;
|
||||
|
||||
/** Returns the index of the named attribute or -1 if not found. Does not throw,
|
||||
therefore useful for optional attributes */
|
||||
int TestAttribute( const char* pAttr) const;
|
||||
/** Returns the index of the named attribute or -1 if not found. Does not throw,
|
||||
therefore useful for optional attributes */
|
||||
int TestAttribute( const char* pAttr) const;
|
||||
|
||||
/** Reads the text contents of an element, throws an exception if not given.
|
||||
Skips leading whitespace. */
|
||||
const char* GetTextContent();
|
||||
/** Reads the text contents of an element, throws an exception if not given.
|
||||
Skips leading whitespace. */
|
||||
const char* GetTextContent();
|
||||
|
||||
/** Reads the text contents of an element, returns NULL if not given.
|
||||
Skips leading whitespace. */
|
||||
const char* TestTextContent();
|
||||
/** Reads the text contents of an element, returns NULL if not given.
|
||||
Skips leading whitespace. */
|
||||
const char* TestTextContent();
|
||||
|
||||
/** Reads a single bool from current text content */
|
||||
bool ReadBoolFromTextContent();
|
||||
/** Reads a single bool from current text content */
|
||||
bool ReadBoolFromTextContent();
|
||||
|
||||
/** Reads a single float from current text content */
|
||||
float ReadFloatFromTextContent();
|
||||
/** Reads a single float from current text content */
|
||||
float ReadFloatFromTextContent();
|
||||
|
||||
/** Calculates the resulting transformation from all the given transform steps */
|
||||
aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
|
||||
/** Calculates the resulting transformation from all the given transform steps */
|
||||
aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
|
||||
|
||||
/** Determines the input data type for the given semantic string */
|
||||
Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
|
||||
/** Determines the input data type for the given semantic string */
|
||||
Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
|
||||
|
||||
/** Finds the item in the given library by its reference, throws if not found */
|
||||
template <typename Type> const Type& ResolveLibraryReference(
|
||||
const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
|
||||
/** Finds the item in the given library by its reference, throws if not found */
|
||||
template <typename Type> const Type& ResolveLibraryReference(
|
||||
const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
|
||||
|
||||
protected:
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
|
||||
/** XML reader, member for everyday use */
|
||||
irr::io::IrrXMLReader* mReader;
|
||||
/** XML reader, member for everyday use */
|
||||
irr::io::IrrXMLReader* mReader;
|
||||
|
||||
/** All data arrays found in the file by ID. Might be referred to by actually
|
||||
everyone. Collada, you are a steaming pile of indirection. */
|
||||
typedef std::map<std::string, Collada::Data> DataLibrary;
|
||||
DataLibrary mDataLibrary;
|
||||
/** All data arrays found in the file by ID. Might be referred to by actually
|
||||
everyone. Collada, you are a steaming pile of indirection. */
|
||||
typedef std::map<std::string, Collada::Data> DataLibrary;
|
||||
DataLibrary mDataLibrary;
|
||||
|
||||
/** Same for accessors which define how the data in a data array is accessed. */
|
||||
typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
|
||||
AccessorLibrary mAccessorLibrary;
|
||||
/** Same for accessors which define how the data in a data array is accessed. */
|
||||
typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
|
||||
AccessorLibrary mAccessorLibrary;
|
||||
|
||||
/** Mesh library: mesh by ID */
|
||||
typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
|
||||
MeshLibrary mMeshLibrary;
|
||||
/** Mesh library: mesh by ID */
|
||||
typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
|
||||
MeshLibrary mMeshLibrary;
|
||||
|
||||
/** node library: root node of the hierarchy part by ID */
|
||||
typedef std::map<std::string, Collada::Node*> NodeLibrary;
|
||||
NodeLibrary mNodeLibrary;
|
||||
/** node library: root node of the hierarchy part by ID */
|
||||
typedef std::map<std::string, Collada::Node*> NodeLibrary;
|
||||
NodeLibrary mNodeLibrary;
|
||||
|
||||
/** Image library: stores texture properties by ID */
|
||||
typedef std::map<std::string, Collada::Image> ImageLibrary;
|
||||
ImageLibrary mImageLibrary;
|
||||
/** Image library: stores texture properties by ID */
|
||||
typedef std::map<std::string, Collada::Image> ImageLibrary;
|
||||
ImageLibrary mImageLibrary;
|
||||
|
||||
/** Effect library: surface attributes by ID */
|
||||
typedef std::map<std::string, Collada::Effect> EffectLibrary;
|
||||
EffectLibrary mEffectLibrary;
|
||||
/** Effect library: surface attributes by ID */
|
||||
typedef std::map<std::string, Collada::Effect> EffectLibrary;
|
||||
EffectLibrary mEffectLibrary;
|
||||
|
||||
/** Material library: surface material by ID */
|
||||
typedef std::map<std::string, Collada::Material> MaterialLibrary;
|
||||
MaterialLibrary mMaterialLibrary;
|
||||
/** Material library: surface material by ID */
|
||||
typedef std::map<std::string, Collada::Material> MaterialLibrary;
|
||||
MaterialLibrary mMaterialLibrary;
|
||||
|
||||
/** Light library: surface light by ID */
|
||||
typedef std::map<std::string, Collada::Light> LightLibrary;
|
||||
LightLibrary mLightLibrary;
|
||||
/** Light library: surface light by ID */
|
||||
typedef std::map<std::string, Collada::Light> LightLibrary;
|
||||
LightLibrary mLightLibrary;
|
||||
|
||||
/** Camera library: surface material by ID */
|
||||
typedef std::map<std::string, Collada::Camera> CameraLibrary;
|
||||
CameraLibrary mCameraLibrary;
|
||||
/** Camera library: surface material by ID */
|
||||
typedef std::map<std::string, Collada::Camera> CameraLibrary;
|
||||
CameraLibrary mCameraLibrary;
|
||||
|
||||
/** Controller library: joint controllers by ID */
|
||||
typedef std::map<std::string, Collada::Controller> ControllerLibrary;
|
||||
ControllerLibrary mControllerLibrary;
|
||||
/** Controller library: joint controllers by ID */
|
||||
typedef std::map<std::string, Collada::Controller> ControllerLibrary;
|
||||
ControllerLibrary mControllerLibrary;
|
||||
|
||||
/** Pointer to the root node. Don't delete, it just points to one of
|
||||
the nodes in the node library. */
|
||||
Collada::Node* mRootNode;
|
||||
/** Pointer to the root node. Don't delete, it just points to one of
|
||||
the nodes in the node library. */
|
||||
Collada::Node* mRootNode;
|
||||
|
||||
/** Root animation container */
|
||||
Collada::Animation mAnims;
|
||||
/** Root animation container */
|
||||
Collada::Animation mAnims;
|
||||
|
||||
/** Size unit: how large compared to a meter */
|
||||
float mUnitSize;
|
||||
/** Size unit: how large compared to a meter */
|
||||
float mUnitSize;
|
||||
|
||||
/** Which is the up vector */
|
||||
enum { UP_X, UP_Y, UP_Z } mUpDirection;
|
||||
/** Which is the up vector */
|
||||
enum { UP_X, UP_Y, UP_Z } mUpDirection;
|
||||
|
||||
/** Collada file format version */
|
||||
Collada::FormatVersion mFormat;
|
||||
/** Collada file format version */
|
||||
Collada::FormatVersion mFormat;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check for element match
|
||||
inline bool ColladaParser::IsElement( const char* pName) const
|
||||
{
|
||||
ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
|
||||
return ::strcmp( mReader->getNodeName(), pName) == 0;
|
||||
ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT);
|
||||
return ::strcmp( mReader->getNodeName(), pName) == 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -341,10 +341,10 @@ inline bool ColladaParser::IsElement( const char* pName) const
|
|||
template <typename Type>
|
||||
const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const
|
||||
{
|
||||
typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
|
||||
if( it == pLibrary.end())
|
||||
ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
|
||||
return it->second;
|
||||
typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL);
|
||||
if( it == pLibrary.end())
|
||||
ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -49,42 +49,42 @@ using namespace Assimp;
|
|||
|
||||
namespace {
|
||||
|
||||
const static aiVector3D base_axis_y(0.f,1.f,0.f);
|
||||
const static aiVector3D base_axis_x(1.f,0.f,0.f);
|
||||
const static aiVector3D base_axis_z(0.f,0.f,1.f);
|
||||
const static float angle_epsilon = 0.95f;
|
||||
const static aiVector3D base_axis_y(0.f,1.f,0.f);
|
||||
const static aiVector3D base_axis_x(1.f,0.f,0.f);
|
||||
const static aiVector3D base_axis_z(0.f,0.f,1.f);
|
||||
const static float angle_epsilon = 0.95f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ComputeUVMappingProcess::ComputeUVMappingProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
ComputeUVMappingProcess::~ComputeUVMappingProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_GenUVCoords) != 0;
|
||||
return (pFlags & aiProcess_GenUVCoords) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a ray intersects a plane and find the intersection point
|
||||
inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
|
||||
const aiVector3D& planeNormal, aiVector3D& pos)
|
||||
const aiVector3D& planeNormal, aiVector3D& pos)
|
||||
{
|
||||
const float b = planeNormal * (planePos - ray.pos);
|
||||
float h = ray.dir * planeNormal;
|
||||
const float b = planeNormal * (planePos - ray.pos);
|
||||
float h = ray.dir * planeNormal;
|
||||
if ((h < 10e-5f && h > -10e-5f) || (h = b/h) < 0)
|
||||
return false;
|
||||
return false;
|
||||
|
||||
pos = ray.pos + (ray.dir * h);
|
||||
return true;
|
||||
|
@ -94,411 +94,411 @@ inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
|
|||
// Find the first empty UV channel in a mesh
|
||||
inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
|
||||
{
|
||||
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
|
||||
if (!mesh->mTextureCoords[m])return m;
|
||||
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
|
||||
if (!mesh->mTextureCoords[m])return m;
|
||||
|
||||
DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found");
|
||||
return UINT_MAX;
|
||||
DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found");
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Try to remove UV seams
|
||||
void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
||||
{
|
||||
// TODO: just a very rough algorithm. I think it could be done
|
||||
// much easier, but I don't know how and am currently too tired to
|
||||
// to think about a better solution.
|
||||
// TODO: just a very rough algorithm. I think it could be done
|
||||
// much easier, but I don't know how and am currently too tired to
|
||||
// to think about a better solution.
|
||||
|
||||
const static float LOWER_LIMIT = 0.1f;
|
||||
const static float UPPER_LIMIT = 0.9f;
|
||||
const static float LOWER_LIMIT = 0.1f;
|
||||
const static float UPPER_LIMIT = 0.9f;
|
||||
|
||||
const static float LOWER_EPSILON = 10e-3f;
|
||||
const static float UPPER_EPSILON = 1.f-10e-3f;
|
||||
const static float LOWER_EPSILON = 10e-3f;
|
||||
const static float UPPER_EPSILON = 1.f-10e-3f;
|
||||
|
||||
for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[fidx];
|
||||
if (face.mNumIndices < 3) continue; // triangles and polygons only, please
|
||||
for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[fidx];
|
||||
if (face.mNumIndices < 3) continue; // triangles and polygons only, please
|
||||
|
||||
unsigned int small = face.mNumIndices, large = small;
|
||||
bool zero = false, one = false, round_to_zero = false;
|
||||
unsigned int small = face.mNumIndices, large = small;
|
||||
bool zero = false, one = false, round_to_zero = false;
|
||||
|
||||
// Check whether this face lies on a UV seam. We can just guess,
|
||||
// but the assumption that a face with at least one very small
|
||||
// on the one side and one very large U coord on the other side
|
||||
// lies on a UV seam should work for most cases.
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
if (out[face.mIndices[n]].x < LOWER_LIMIT)
|
||||
{
|
||||
small = n;
|
||||
// Check whether this face lies on a UV seam. We can just guess,
|
||||
// but the assumption that a face with at least one very small
|
||||
// on the one side and one very large U coord on the other side
|
||||
// lies on a UV seam should work for most cases.
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
if (out[face.mIndices[n]].x < LOWER_LIMIT)
|
||||
{
|
||||
small = n;
|
||||
|
||||
// If we have a U value very close to 0 we can't
|
||||
// round the others to 0, too.
|
||||
if (out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
zero = true;
|
||||
else round_to_zero = true;
|
||||
}
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT)
|
||||
{
|
||||
large = n;
|
||||
// If we have a U value very close to 0 we can't
|
||||
// round the others to 0, too.
|
||||
if (out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
zero = true;
|
||||
else round_to_zero = true;
|
||||
}
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT)
|
||||
{
|
||||
large = n;
|
||||
|
||||
// If we have a U value very close to 1 we can't
|
||||
// round the others to 1, too.
|
||||
if (out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
one = true;
|
||||
}
|
||||
}
|
||||
if (small != face.mNumIndices && large != face.mNumIndices)
|
||||
{
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
// If the u value is over the upper limit and no other u
|
||||
// value of that face is 0, round it to 0
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
|
||||
out[face.mIndices[n]].x = 0.f;
|
||||
// If we have a U value very close to 1 we can't
|
||||
// round the others to 1, too.
|
||||
if (out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
one = true;
|
||||
}
|
||||
}
|
||||
if (small != face.mNumIndices && large != face.mNumIndices)
|
||||
{
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
// If the u value is over the upper limit and no other u
|
||||
// value of that face is 0, round it to 0
|
||||
if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
|
||||
out[face.mIndices[n]].x = 0.f;
|
||||
|
||||
// If the u value is below the lower limit and no other u
|
||||
// value of that face is 1, round it to 1
|
||||
else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one)
|
||||
out[face.mIndices[n]].x = 1.f;
|
||||
// If the u value is below the lower limit and no other u
|
||||
// value of that face is 1, round it to 1
|
||||
else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one)
|
||||
out[face.mIndices[n]].x = 1.f;
|
||||
|
||||
// The face contains both 0 and 1 as UV coords. This can occur
|
||||
// for faces which have an edge that lies directly on the seam.
|
||||
// Due to numerical inaccuracies one U coord becomes 0, the
|
||||
// other 1. But we do still have a third UV coord to determine
|
||||
// to which side we must round to.
|
||||
else if (one && zero)
|
||||
{
|
||||
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
out[face.mIndices[n]].x = 0.f;
|
||||
else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
out[face.mIndices[n]].x = 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The face contains both 0 and 1 as UV coords. This can occur
|
||||
// for faces which have an edge that lies directly on the seam.
|
||||
// Due to numerical inaccuracies one U coord becomes 0, the
|
||||
// other 1. But we do still have a third UV coord to determine
|
||||
// to which side we must round to.
|
||||
else if (one && zero)
|
||||
{
|
||||
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
|
||||
out[face.mIndices[n]].x = 0.f;
|
||||
else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
|
||||
out[face.mIndices[n]].x = 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
aiVector3D center, min, max;
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
aiVector3D center, min, max;
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
|
||||
// For each point get a normalized projection vector in the sphere,
|
||||
// get its longitude and latitude and map them to their respective
|
||||
// UV axes. Problems occur around the poles ... unsolvable.
|
||||
//
|
||||
// The spherical coordinate system looks like this:
|
||||
// x = cos(lon)*cos(lat)
|
||||
// y = sin(lon)*cos(lat)
|
||||
// z = sin(lat)
|
||||
//
|
||||
// Thus we can derive:
|
||||
// lat = arcsin (z)
|
||||
// lon = arctan (y/x)
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
// For each point get a normalized projection vector in the sphere,
|
||||
// get its longitude and latitude and map them to their respective
|
||||
// UV axes. Problems occur around the poles ... unsolvable.
|
||||
//
|
||||
// The spherical coordinate system looks like this:
|
||||
// x = cos(lon)*cos(lat)
|
||||
// y = sin(lon)*cos(lat)
|
||||
// z = sin(lat)
|
||||
//
|
||||
// Thus we can derive:
|
||||
// lat = arcsin (z)
|
||||
// lon = arctan (y/x)
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
// ... just the same again
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
|
||||
out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
||||
(asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
aiVector3D center, min, max;
|
||||
aiVector3D center, min, max;
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const float diff = max.x - min.x;
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const float diff = max.x - min.x;
|
||||
|
||||
// If the main axis is 'z', the z coordinate of a point 'p' is mapped
|
||||
// directly to the texture V axis. The other axis is derived from
|
||||
// the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
|
||||
// 'c' is the center point of the mesh.
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
// If the main axis is 'z', the z coordinate of a point 'p' is mapped
|
||||
// directly to the texture V axis. The other axis is derived from
|
||||
// the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
|
||||
// 'c' is the center point of the mesh.
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.x - min.x) / diff;
|
||||
uv.x = (atan2 ( pos.z - center.z, pos.y - center.y) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const float diff = max.y - min.y;
|
||||
uv.y = (pos.x - min.x) / diff;
|
||||
uv.x = (atan2 ( pos.z - center.z, pos.y - center.y) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const float diff = max.y - min.y;
|
||||
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const float diff = max.z - min.z;
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
const float diff = max.z - min.z;
|
||||
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
// just the same ...
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.z - min.z) / diff;
|
||||
uv.x = (atan2 ( pos.y - center.y, pos.x - center.x) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
const float diff = max.y - min.y;
|
||||
uv.y = (pos.z - min.z) / diff;
|
||||
uv.x = (atan2 ( pos.y - center.y, pos.x - center.x) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else {
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
const float diff = max.y - min.y;
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
|
||||
const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
|
||||
const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
|
||||
aiVector3D& uv = out[pnt];
|
||||
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
uv.y = (pos.y - min.y) / diff;
|
||||
uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
||||
}
|
||||
}
|
||||
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
// Now find and remove UV seams. A seam occurs if a face has a tcoord
|
||||
// close to zero on the one side, and a tcoord close to one on the
|
||||
// other side.
|
||||
RemoveUVSeams(mesh,out);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
||||
{
|
||||
float diffu,diffv;
|
||||
aiVector3D center, min, max;
|
||||
float diffu,diffv;
|
||||
aiVector3D center, min, max;
|
||||
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.z - min.z;
|
||||
diffv = max.y - min.y;
|
||||
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
||||
// currently the mapping axis will always be one of x,y,z, except if the
|
||||
// PretransformVertices step is used (it transforms the meshes into worldspace,
|
||||
// thus changing the mapping axis)
|
||||
if (axis * base_axis_x >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.z - min.z;
|
||||
diffv = max.y - min.y;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_y >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.y - min.y;
|
||||
diffv = max.z - min.z;
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.y - min.y;
|
||||
diffv = max.z - min.z;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else
|
||||
{
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
else
|
||||
{
|
||||
aiMatrix4x4 mTrafo;
|
||||
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
||||
FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.z - min.z;
|
||||
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
// again the same, except we're applying a transformation now
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
|
||||
}
|
||||
}
|
||||
|
||||
// shouldn't be necessary to remove UV seams ...
|
||||
// shouldn't be necessary to remove UV seams ...
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
|
||||
{
|
||||
DefaultLogger::get()->error("Mapping type currently not implemented");
|
||||
DefaultLogger::get()->error("Mapping type currently not implemented");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
DefaultLogger::get()->debug("GenUVCoordsProcess begin");
|
||||
char buffer[1024];
|
||||
DefaultLogger::get()->debug("GenUVCoordsProcess begin");
|
||||
char buffer[1024];
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
|
||||
throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
|
||||
throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
|
||||
|
||||
std::list<MappingInfo> mappingStack;
|
||||
std::list<MappingInfo> mappingStack;
|
||||
|
||||
/* Iterate through all materials and search for non-UV mapped textures
|
||||
*/
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
{
|
||||
mappingStack.clear();
|
||||
aiMaterial* mat = pScene->mMaterials[i];
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a)
|
||||
{
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapping"))
|
||||
{
|
||||
aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
|
||||
if (aiTextureMapping_UV != mapping)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
sprintf(buffer, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
|
||||
TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
|
||||
MappingTypeToString(mapping));
|
||||
/* Iterate through all materials and search for non-UV mapped textures
|
||||
*/
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
{
|
||||
mappingStack.clear();
|
||||
aiMaterial* mat = pScene->mMaterials[i];
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a)
|
||||
{
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapping"))
|
||||
{
|
||||
aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
|
||||
if (aiTextureMapping_UV != mapping)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
sprintf(buffer, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
|
||||
TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
|
||||
MappingTypeToString(mapping));
|
||||
|
||||
DefaultLogger::get()->info(buffer);
|
||||
}
|
||||
DefaultLogger::get()->info(buffer);
|
||||
}
|
||||
|
||||
if (aiTextureMapping_OTHER == mapping)
|
||||
continue;
|
||||
if (aiTextureMapping_OTHER == mapping)
|
||||
continue;
|
||||
|
||||
MappingInfo info (mapping);
|
||||
MappingInfo info (mapping);
|
||||
|
||||
// Get further properties - currently only the major axis
|
||||
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
|
||||
{
|
||||
aiMaterialProperty* prop2 = mat->mProperties[a2];
|
||||
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
|
||||
continue;
|
||||
// Get further properties - currently only the major axis
|
||||
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
|
||||
{
|
||||
aiMaterialProperty* prop2 = mat->mProperties[a2];
|
||||
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
|
||||
continue;
|
||||
|
||||
if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) {
|
||||
info.axis = *((aiVector3D*)prop2->mData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) {
|
||||
info.axis = *((aiVector3D*)prop2->mData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int idx;
|
||||
unsigned int idx;
|
||||
|
||||
// Check whether we have this mapping mode already
|
||||
std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
|
||||
if (mappingStack.end() != it)
|
||||
{
|
||||
idx = (*it).uv;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have found a non-UV mapped texture. Now
|
||||
* we need to find all meshes using this material
|
||||
* that we can compute UV channels for them.
|
||||
*/
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[m];
|
||||
unsigned int outIdx = 0;
|
||||
if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
|
||||
!mesh->mNumVertices)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Check whether we have this mapping mode already
|
||||
std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
|
||||
if (mappingStack.end() != it)
|
||||
{
|
||||
idx = (*it).uv;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have found a non-UV mapped texture. Now
|
||||
* we need to find all meshes using this material
|
||||
* that we can compute UV channels for them.
|
||||
*/
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
|
||||
{
|
||||
aiMesh* mesh = pScene->mMeshes[m];
|
||||
unsigned int outIdx = 0;
|
||||
if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
|
||||
!mesh->mNumVertices)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allocate output storage
|
||||
aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
|
||||
// Allocate output storage
|
||||
aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
|
||||
|
||||
switch (mapping)
|
||||
{
|
||||
case aiTextureMapping_SPHERE:
|
||||
ComputeSphereMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_CYLINDER:
|
||||
ComputeCylinderMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_PLANE:
|
||||
ComputePlaneMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_BOX:
|
||||
ComputeBoxMapping(mesh,p);
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
}
|
||||
if (m && idx != outIdx)
|
||||
{
|
||||
DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to "
|
||||
"this material have equal numbers of UV channels. The UV index stored in "
|
||||
"the material structure does therefore not apply for all meshes. ");
|
||||
}
|
||||
idx = outIdx;
|
||||
}
|
||||
info.uv = idx;
|
||||
mappingStack.push_back(info);
|
||||
}
|
||||
switch (mapping)
|
||||
{
|
||||
case aiTextureMapping_SPHERE:
|
||||
ComputeSphereMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_CYLINDER:
|
||||
ComputeCylinderMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_PLANE:
|
||||
ComputePlaneMapping(mesh,info.axis,p);
|
||||
break;
|
||||
case aiTextureMapping_BOX:
|
||||
ComputeBoxMapping(mesh,p);
|
||||
break;
|
||||
default:
|
||||
ai_assert(false);
|
||||
}
|
||||
if (m && idx != outIdx)
|
||||
{
|
||||
DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to "
|
||||
"this material have equal numbers of UV channels. The UV index stored in "
|
||||
"the material structure does therefore not apply for all meshes. ");
|
||||
}
|
||||
idx = outIdx;
|
||||
}
|
||||
info.uv = idx;
|
||||
mappingStack.push_back(info);
|
||||
}
|
||||
|
||||
// Update the material property list
|
||||
mapping = aiTextureMapping_UV;
|
||||
((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DefaultLogger::get()->debug("GenUVCoordsProcess finished");
|
||||
// Update the material property list
|
||||
mapping = aiTextureMapping_UV;
|
||||
((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DefaultLogger::get()->debug("GenUVCoordsProcess finished");
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
class ComputeUVMappingTest;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** ComputeUVMappingProcess - converts special mappings, such as spherical,
|
||||
|
@ -60,86 +60,86 @@ namespace Assimp
|
|||
class ComputeUVMappingProcess : public BaseProcess
|
||||
{
|
||||
public:
|
||||
ComputeUVMappingProcess();
|
||||
~ComputeUVMappingProcess();
|
||||
ComputeUVMappingProcess();
|
||||
~ComputeUVMappingProcess();
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
* @param pFlags The processing flags the importer was called with. A bitwise
|
||||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag field.
|
||||
* @param pFlags The processing flags the importer was called with. A bitwise
|
||||
* combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields, false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes spherical UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes spherical UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cylindrical UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cylindrical UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes planar UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes planar UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param axis Main axis
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis,
|
||||
aiVector3D* out);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cubic UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out);
|
||||
// -------------------------------------------------------------------
|
||||
/** Computes cubic UV coordinates for a mesh
|
||||
*
|
||||
* @param mesh Mesh to be processed
|
||||
* @param out Receives output UV coordinates
|
||||
*/
|
||||
void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out);
|
||||
|
||||
private:
|
||||
|
||||
// temporary structure to describe a mapping
|
||||
struct MappingInfo
|
||||
{
|
||||
MappingInfo(aiTextureMapping _type)
|
||||
: type (_type)
|
||||
, axis (0.f,1.f,0.f)
|
||||
, uv (0u)
|
||||
{}
|
||||
// temporary structure to describe a mapping
|
||||
struct MappingInfo
|
||||
{
|
||||
MappingInfo(aiTextureMapping _type)
|
||||
: type (_type)
|
||||
, axis (0.f,1.f,0.f)
|
||||
, uv (0u)
|
||||
{}
|
||||
|
||||
aiTextureMapping type;
|
||||
aiVector3D axis;
|
||||
unsigned int uv;
|
||||
aiTextureMapping type;
|
||||
aiVector3D axis;
|
||||
unsigned int uv;
|
||||
|
||||
bool operator== (const MappingInfo& other)
|
||||
{
|
||||
return type == other.type && axis == other.axis;
|
||||
}
|
||||
};
|
||||
bool operator== (const MappingInfo& other)
|
||||
{
|
||||
return type == other.type && axis == other.axis;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -74,59 +74,59 @@ MakeLeftHandedProcess::~MakeLeftHandedProcess() {
|
|||
// Returns whether the processing step is present in the given flag field.
|
||||
bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return 0 != (pFlags & aiProcess_MakeLeftHanded);
|
||||
return 0 != (pFlags & aiProcess_MakeLeftHanded);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void MakeLeftHandedProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
// Check for an existent root node to proceed
|
||||
ai_assert(pScene->mRootNode != NULL);
|
||||
DefaultLogger::get()->debug("MakeLeftHandedProcess begin");
|
||||
// Check for an existent root node to proceed
|
||||
ai_assert(pScene->mRootNode != NULL);
|
||||
DefaultLogger::get()->debug("MakeLeftHandedProcess begin");
|
||||
|
||||
// recursively convert all the nodes
|
||||
ProcessNode( pScene->mRootNode, aiMatrix4x4());
|
||||
// recursively convert all the nodes
|
||||
ProcessNode( pScene->mRootNode, aiMatrix4x4());
|
||||
|
||||
// process the meshes accordingly
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
|
||||
ProcessMesh( pScene->mMeshes[a]);
|
||||
// process the meshes accordingly
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
|
||||
ProcessMesh( pScene->mMeshes[a]);
|
||||
|
||||
// process the materials accordingly
|
||||
for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
|
||||
ProcessMaterial( pScene->mMaterials[a]);
|
||||
// process the materials accordingly
|
||||
for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
|
||||
ProcessMaterial( pScene->mMaterials[a]);
|
||||
|
||||
// transform all animation channels as well
|
||||
for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
|
||||
{
|
||||
aiAnimation* anim = pScene->mAnimations[a];
|
||||
for( unsigned int b = 0; b < anim->mNumChannels; b++)
|
||||
{
|
||||
aiNodeAnim* nodeAnim = anim->mChannels[b];
|
||||
ProcessAnimation( nodeAnim);
|
||||
}
|
||||
}
|
||||
DefaultLogger::get()->debug("MakeLeftHandedProcess finished");
|
||||
// transform all animation channels as well
|
||||
for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
|
||||
{
|
||||
aiAnimation* anim = pScene->mAnimations[a];
|
||||
for( unsigned int b = 0; b < anim->mNumChannels; b++)
|
||||
{
|
||||
aiNodeAnim* nodeAnim = anim->mChannels[b];
|
||||
ProcessAnimation( nodeAnim);
|
||||
}
|
||||
}
|
||||
DefaultLogger::get()->debug("MakeLeftHandedProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively converts a node, all of its children and all of its meshes
|
||||
void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation)
|
||||
{
|
||||
// mirror all base vectors at the local Z axis
|
||||
pNode->mTransformation.c1 = -pNode->mTransformation.c1;
|
||||
pNode->mTransformation.c2 = -pNode->mTransformation.c2;
|
||||
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
|
||||
pNode->mTransformation.c4 = -pNode->mTransformation.c4;
|
||||
// mirror all base vectors at the local Z axis
|
||||
pNode->mTransformation.c1 = -pNode->mTransformation.c1;
|
||||
pNode->mTransformation.c2 = -pNode->mTransformation.c2;
|
||||
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
|
||||
pNode->mTransformation.c4 = -pNode->mTransformation.c4;
|
||||
|
||||
// now invert the Z axis again to keep the matrix determinant positive.
|
||||
// The local meshes will be inverted accordingly so that the result should look just fine again.
|
||||
pNode->mTransformation.a3 = -pNode->mTransformation.a3;
|
||||
pNode->mTransformation.b3 = -pNode->mTransformation.b3;
|
||||
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
|
||||
pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
|
||||
// now invert the Z axis again to keep the matrix determinant positive.
|
||||
// The local meshes will be inverted accordingly so that the result should look just fine again.
|
||||
pNode->mTransformation.a3 = -pNode->mTransformation.a3;
|
||||
pNode->mTransformation.b3 = -pNode->mTransformation.b3;
|
||||
pNode->mTransformation.c3 = -pNode->mTransformation.c3;
|
||||
pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
|
||||
|
||||
// continue for all children
|
||||
// continue for all children
|
||||
for( size_t a = 0; a < pNode->mNumChildren; ++a ) {
|
||||
ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation );
|
||||
}
|
||||
|
@ -136,78 +136,78 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
|
|||
// Converts a single mesh to left handed coordinates.
|
||||
void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
// mirror positions, normals and stuff along the Z axis
|
||||
for( size_t a = 0; a < pMesh->mNumVertices; ++a)
|
||||
{
|
||||
pMesh->mVertices[a].z *= -1.0f;
|
||||
if( pMesh->HasNormals())
|
||||
pMesh->mNormals[a].z *= -1.0f;
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
pMesh->mTangents[a].z *= -1.0f;
|
||||
pMesh->mBitangents[a].z *= -1.0f;
|
||||
}
|
||||
}
|
||||
// mirror positions, normals and stuff along the Z axis
|
||||
for( size_t a = 0; a < pMesh->mNumVertices; ++a)
|
||||
{
|
||||
pMesh->mVertices[a].z *= -1.0f;
|
||||
if( pMesh->HasNormals())
|
||||
pMesh->mNormals[a].z *= -1.0f;
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
pMesh->mTangents[a].z *= -1.0f;
|
||||
pMesh->mBitangents[a].z *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// mirror offset matrices of all bones
|
||||
for( size_t a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
aiBone* bone = pMesh->mBones[a];
|
||||
bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
|
||||
bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
|
||||
bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
|
||||
bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
|
||||
bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
|
||||
bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
|
||||
}
|
||||
// mirror offset matrices of all bones
|
||||
for( size_t a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
aiBone* bone = pMesh->mBones[a];
|
||||
bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
|
||||
bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
|
||||
bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
|
||||
bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1;
|
||||
bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2;
|
||||
bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4;
|
||||
}
|
||||
|
||||
// mirror bitangents as well as they're derived from the texture coords
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mBitangents[a] *= -1.0f;
|
||||
}
|
||||
// mirror bitangents as well as they're derived from the texture coords
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mBitangents[a] *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single material to left handed coordinates.
|
||||
void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
|
||||
{
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
|
||||
// Mapping axis for UV mappings?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
|
||||
aiVector3D* pff = (aiVector3D*)prop->mData;
|
||||
// Mapping axis for UV mappings?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
|
||||
aiVector3D* pff = (aiVector3D*)prop->mData;
|
||||
|
||||
pff->z *= -1.f;
|
||||
}
|
||||
}
|
||||
pff->z *= -1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts the given animation to LH coordinates.
|
||||
void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim)
|
||||
{
|
||||
// position keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
|
||||
pAnim->mPositionKeys[a].mValue.z *= -1.0f;
|
||||
// position keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
|
||||
pAnim->mPositionKeys[a].mValue.z *= -1.0f;
|
||||
|
||||
// rotation keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
|
||||
{
|
||||
/* That's the safe version, but the float errors add up. So we try the short version instead
|
||||
aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
|
||||
rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
|
||||
rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
|
||||
aiQuaternion rotquat( rotmat);
|
||||
pAnim->mRotationKeys[a].mValue = rotquat;
|
||||
*/
|
||||
pAnim->mRotationKeys[a].mValue.x *= -1.0f;
|
||||
pAnim->mRotationKeys[a].mValue.y *= -1.0f;
|
||||
}
|
||||
// rotation keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
|
||||
{
|
||||
/* That's the safe version, but the float errors add up. So we try the short version instead
|
||||
aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
|
||||
rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
|
||||
rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2;
|
||||
aiQuaternion rotquat( rotmat);
|
||||
pAnim->mRotationKeys[a].mValue = rotquat;
|
||||
*/
|
||||
pAnim->mRotationKeys[a].mValue.x *= -1.0f;
|
||||
pAnim->mRotationKeys[a].mValue.y *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
|
||||
|
@ -228,52 +228,52 @@ FlipUVsProcess::~FlipUVsProcess()
|
|||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FlipUVsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return 0 != (pFlags & aiProcess_FlipUVs);
|
||||
return 0 != (pFlags & aiProcess_FlipUVs);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FlipUVsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
DefaultLogger::get()->debug("FlipUVsProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
DefaultLogger::get()->debug("FlipUVsProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
ProcessMaterial(pScene->mMaterials[i]);
|
||||
DefaultLogger::get()->debug("FlipUVsProcess finished");
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
ProcessMaterial(pScene->mMaterials[i]);
|
||||
DefaultLogger::get()->debug("FlipUVsProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single material
|
||||
void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
|
||||
{
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if( !prop ) {
|
||||
DefaultLogger::get()->debug( "Property is null" );
|
||||
continue;
|
||||
}
|
||||
|
||||
// UV transformation key?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */
|
||||
aiUVTransform* uv = (aiUVTransform*)prop->mData;
|
||||
// UV transformation key?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */
|
||||
aiUVTransform* uv = (aiUVTransform*)prop->mData;
|
||||
|
||||
// just flip it, that's everything
|
||||
uv->mTranslation.y *= -1.f;
|
||||
uv->mRotation *= -1.f;
|
||||
}
|
||||
}
|
||||
// just flip it, that's everything
|
||||
uv->mTranslation.y *= -1.f;
|
||||
uv->mRotation *= -1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh
|
||||
void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
// mirror texture y coordinate
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
|
||||
// mirror texture y coordinate
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) {
|
||||
if( !pMesh->HasTextureCoords( a ) ) {
|
||||
break;
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
|
|||
for( unsigned int b = 0; b < pMesh->mNumVertices; b++ ) {
|
||||
pMesh->mTextureCoords[ a ][ b ].y = 1.0f - pMesh->mTextureCoords[ a ][ b ].y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS
|
||||
|
@ -302,30 +302,30 @@ FlipWindingOrderProcess::~FlipWindingOrderProcess()
|
|||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return 0 != (pFlags & aiProcess_FlipWindingOrder);
|
||||
return 0 != (pFlags & aiProcess_FlipWindingOrder);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FlipWindingOrderProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
DefaultLogger::get()->debug("FlipWindingOrderProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
DefaultLogger::get()->debug("FlipWindingOrderProcess finished");
|
||||
DefaultLogger::get()->debug("FlipWindingOrderProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
DefaultLogger::get()->debug("FlipWindingOrderProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh
|
||||
void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
// invert the order of all faces in this mesh
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
aiFace& face = pMesh->mFaces[a];
|
||||
for( unsigned int b = 0; b < face.mNumIndices / 2; b++)
|
||||
std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]);
|
||||
}
|
||||
// invert the order of all faces in this mesh
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
aiFace& face = pMesh->mFaces[a];
|
||||
for( unsigned int b = 0; b < face.mNumIndices / 2; b++)
|
||||
std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
|
||||
|
|
|
@ -57,7 +57,7 @@ struct aiNodeAnim;
|
|||
struct aiNode;
|
||||
struct aiMaterial;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
/** @brief The MakeLeftHandedProcess converts all imported data to a left-handed
|
||||
|
@ -74,43 +74,43 @@ class MakeLeftHandedProcess : public BaseProcess
|
|||
|
||||
|
||||
public:
|
||||
MakeLeftHandedProcess();
|
||||
~MakeLeftHandedProcess();
|
||||
MakeLeftHandedProcess();
|
||||
~MakeLeftHandedProcess();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Recursively converts a node and all of its children
|
||||
*/
|
||||
void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation);
|
||||
// -------------------------------------------------------------------
|
||||
/** Recursively converts a node and all of its children
|
||||
*/
|
||||
void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a single mesh to left handed coordinates.
|
||||
* This means that positions, normals and tangents are mirrored at
|
||||
* the local Z axis and the order of all faces are inverted.
|
||||
* @param pMesh The mesh to convert.
|
||||
*/
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a single mesh to left handed coordinates.
|
||||
* This means that positions, normals and tangents are mirrored at
|
||||
* the local Z axis and the order of all faces are inverted.
|
||||
* @param pMesh The mesh to convert.
|
||||
*/
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a single material to left-handed coordinates
|
||||
* @param pMat Material to convert
|
||||
*/
|
||||
void ProcessMaterial( aiMaterial* pMat);
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts a single material to left-handed coordinates
|
||||
* @param pMat Material to convert
|
||||
*/
|
||||
void ProcessMaterial( aiMaterial* pMat);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts the given animation to LH coordinates.
|
||||
* The rotation and translation keys are transformed, the scale keys
|
||||
* work in local space and can therefore be left untouched.
|
||||
* @param pAnim The bone animation to transform
|
||||
*/
|
||||
void ProcessAnimation( aiNodeAnim* pAnim);
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts the given animation to LH coordinates.
|
||||
* The rotation and translation keys are transformed, the scale keys
|
||||
* work in local space and can therefore be left untouched.
|
||||
* @param pAnim The bone animation to transform
|
||||
*/
|
||||
void ProcessAnimation( aiNodeAnim* pAnim);
|
||||
};
|
||||
|
||||
|
||||
|
@ -119,23 +119,23 @@ protected:
|
|||
*/
|
||||
class FlipWindingOrderProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
/** Constructor to be privately used by Importer */
|
||||
FlipWindingOrderProcess();
|
||||
/** Constructor to be privately used by Importer */
|
||||
FlipWindingOrderProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~FlipWindingOrderProcess();
|
||||
/** Destructor, private as well */
|
||||
~FlipWindingOrderProcess();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -143,24 +143,24 @@ protected:
|
|||
*/
|
||||
class FlipUVsProcess : public BaseProcess
|
||||
{
|
||||
friend class Importer;
|
||||
friend class Importer;
|
||||
|
||||
public:
|
||||
/** Constructor to be privately used by Importer */
|
||||
FlipUVsProcess();
|
||||
/** Constructor to be privately used by Importer */
|
||||
FlipUVsProcess();
|
||||
|
||||
/** Destructor, private as well */
|
||||
~FlipUVsProcess();
|
||||
/** Destructor, private as well */
|
||||
~FlipUVsProcess();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
// -------------------------------------------------------------------
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
void ProcessMaterial( aiMaterial* mat);
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
void ProcessMaterial( aiMaterial* mat);
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
210
code/DXFHelper.h
210
code/DXFHelper.h
|
@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/assimp/DefaultLogger.hpp"
|
||||
|
||||
namespace Assimp {
|
||||
namespace DXF {
|
||||
namespace DXF {
|
||||
|
||||
|
||||
// read pairs of lines, parse group code and value and provide utilities
|
||||
|
@ -63,113 +63,113 @@ class LineReader
|
|||
|
||||
public:
|
||||
|
||||
LineReader(StreamReaderLE& reader)
|
||||
// do NOT skip empty lines. In DXF files, they count as valid data.
|
||||
: splitter(reader,false,true)
|
||||
, end()
|
||||
{
|
||||
}
|
||||
LineReader(StreamReaderLE& reader)
|
||||
// do NOT skip empty lines. In DXF files, they count as valid data.
|
||||
: splitter(reader,false,true)
|
||||
, end()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
|
||||
// -----------------------------------------
|
||||
bool Is(int gc, const char* what) const {
|
||||
return groupcode == gc && !strcmp(what,value.c_str());
|
||||
}
|
||||
// -----------------------------------------
|
||||
bool Is(int gc, const char* what) const {
|
||||
return groupcode == gc && !strcmp(what,value.c_str());
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
bool Is(int gc) const {
|
||||
return groupcode == gc;
|
||||
}
|
||||
// -----------------------------------------
|
||||
bool Is(int gc) const {
|
||||
return groupcode == gc;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
int GroupCode() const {
|
||||
return groupcode;
|
||||
}
|
||||
// -----------------------------------------
|
||||
int GroupCode() const {
|
||||
return groupcode;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
const std::string& Value() const {
|
||||
return value;
|
||||
}
|
||||
// -----------------------------------------
|
||||
const std::string& Value() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
bool End() const {
|
||||
return !((bool)*this);
|
||||
}
|
||||
// -----------------------------------------
|
||||
bool End() const {
|
||||
return !((bool)*this);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// -----------------------------------------
|
||||
unsigned int ValueAsUnsignedInt() const {
|
||||
return strtoul10(value.c_str());
|
||||
}
|
||||
// -----------------------------------------
|
||||
unsigned int ValueAsUnsignedInt() const {
|
||||
return strtoul10(value.c_str());
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
int ValueAsSignedInt() const {
|
||||
return strtol10(value.c_str());
|
||||
}
|
||||
// -----------------------------------------
|
||||
int ValueAsSignedInt() const {
|
||||
return strtol10(value.c_str());
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
float ValueAsFloat() const {
|
||||
return fast_atof(value.c_str());
|
||||
}
|
||||
// -----------------------------------------
|
||||
float ValueAsFloat() const {
|
||||
return fast_atof(value.c_str());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// -----------------------------------------
|
||||
/** pseudo-iterator increment to advance to the next (groupcode/value) pair */
|
||||
LineReader& operator++() {
|
||||
if (end) {
|
||||
if (end == 1) {
|
||||
++end;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
// -----------------------------------------
|
||||
/** pseudo-iterator increment to advance to the next (groupcode/value) pair */
|
||||
LineReader& operator++() {
|
||||
if (end) {
|
||||
if (end == 1) {
|
||||
++end;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
try {
|
||||
groupcode = strtol10(splitter->c_str());
|
||||
splitter++;
|
||||
try {
|
||||
groupcode = strtol10(splitter->c_str());
|
||||
splitter++;
|
||||
|
||||
value = *splitter;
|
||||
splitter++;
|
||||
value = *splitter;
|
||||
splitter++;
|
||||
|
||||
// automatically skip over {} meta blocks (these are for application use
|
||||
// and currently not relevant for Assimp).
|
||||
if (value.length() && value[0] == '{') {
|
||||
// automatically skip over {} meta blocks (these are for application use
|
||||
// and currently not relevant for Assimp).
|
||||
if (value.length() && value[0] == '{') {
|
||||
|
||||
size_t cnt = 0;
|
||||
for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
|
||||
size_t cnt = 0;
|
||||
for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
|
||||
|
||||
splitter++;
|
||||
DefaultLogger::get()->debug((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
|
||||
}
|
||||
} catch(std::logic_error&) {
|
||||
ai_assert(!splitter);
|
||||
}
|
||||
if (!splitter) {
|
||||
end = 1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
splitter++;
|
||||
DefaultLogger::get()->debug((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
|
||||
}
|
||||
} catch(std::logic_error&) {
|
||||
ai_assert(!splitter);
|
||||
}
|
||||
if (!splitter) {
|
||||
end = 1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
LineReader& operator++(int) {
|
||||
return ++(*this);
|
||||
}
|
||||
// -----------------------------------------
|
||||
LineReader& operator++(int) {
|
||||
return ++(*this);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------
|
||||
operator bool() const {
|
||||
return end <= 1;
|
||||
}
|
||||
// -----------------------------------------
|
||||
operator bool() const {
|
||||
return end <= 1;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
LineSplitter splitter;
|
||||
int groupcode;
|
||||
std::string value;
|
||||
int end;
|
||||
LineSplitter splitter;
|
||||
int groupcode;
|
||||
std::string value;
|
||||
int end;
|
||||
};
|
||||
|
||||
|
||||
|
@ -177,52 +177,52 @@ private:
|
|||
// represents a POLYLINE or a LWPOLYLINE. or even a 3DFACE The data is converted as needed.
|
||||
struct PolyLine
|
||||
{
|
||||
PolyLine()
|
||||
: flags()
|
||||
{}
|
||||
PolyLine()
|
||||
: flags()
|
||||
{}
|
||||
|
||||
std::vector<aiVector3D> positions;
|
||||
std::vector<aiColor4D> colors;
|
||||
std::vector<unsigned int> indices;
|
||||
std::vector<unsigned int> counts;
|
||||
unsigned int flags;
|
||||
std::vector<aiVector3D> positions;
|
||||
std::vector<aiColor4D> colors;
|
||||
std::vector<unsigned int> indices;
|
||||
std::vector<unsigned int> counts;
|
||||
unsigned int flags;
|
||||
|
||||
std::string layer;
|
||||
std::string desc;
|
||||
std::string layer;
|
||||
std::string desc;
|
||||
};
|
||||
|
||||
|
||||
// reference to a BLOCK. Specifies its own coordinate system.
|
||||
struct InsertBlock
|
||||
{
|
||||
InsertBlock()
|
||||
: scale(1.f,1.f,1.f)
|
||||
, angle()
|
||||
{}
|
||||
InsertBlock()
|
||||
: scale(1.f,1.f,1.f)
|
||||
, angle()
|
||||
{}
|
||||
|
||||
aiVector3D pos;
|
||||
aiVector3D scale;
|
||||
float angle;
|
||||
aiVector3D pos;
|
||||
aiVector3D scale;
|
||||
float angle;
|
||||
|
||||
std::string name;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
|
||||
// keeps track of all geometry in a single BLOCK.
|
||||
struct Block
|
||||
{
|
||||
std::vector< boost::shared_ptr<PolyLine> > lines;
|
||||
std::vector<InsertBlock> insertions;
|
||||
std::vector< boost::shared_ptr<PolyLine> > lines;
|
||||
std::vector<InsertBlock> insertions;
|
||||
|
||||
std::string name;
|
||||
aiVector3D base;
|
||||
std::string name;
|
||||
aiVector3D base;
|
||||
};
|
||||
|
||||
|
||||
struct FileData
|
||||
{
|
||||
// note: the LAST block always contains the stuff from ENTITIES.
|
||||
std::vector<Block> blocks;
|
||||
// note: the LAST block always contains the stuff from ENTITIES.
|
||||
std::vector<Block> blocks;
|
||||
};
|
||||
|
||||
|
||||
|
|
1218
code/DXFLoader.cpp
1218
code/DXFLoader.cpp
File diff suppressed because it is too large
Load Diff
128
code/DXFLoader.h
128
code/DXFLoader.h
|
@ -46,17 +46,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "BaseImporter.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace DXF {
|
||||
namespace Assimp {
|
||||
namespace DXF {
|
||||
|
||||
class LineReader;
|
||||
struct FileData;
|
||||
struct PolyLine;
|
||||
struct Block;
|
||||
struct InsertBlock;
|
||||
class LineReader;
|
||||
struct FileData;
|
||||
struct PolyLine;
|
||||
struct Block;
|
||||
struct InsertBlock;
|
||||
|
||||
typedef std::map<std::string, const DXF::Block*> BlockMap;
|
||||
}
|
||||
typedef std::map<std::string, const DXF::Block*> BlockMap;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -66,85 +66,85 @@ namespace Assimp {
|
|||
class DXFImporter : public BaseImporter
|
||||
{
|
||||
public:
|
||||
DXFImporter();
|
||||
~DXFImporter();
|
||||
DXFImporter();
|
||||
~DXFImporter();
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details */
|
||||
void InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details */
|
||||
void InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
private:
|
||||
|
||||
// -----------------------------------------------------
|
||||
void SkipSection(DXF::LineReader& reader);
|
||||
// -----------------------------------------------------
|
||||
void SkipSection(DXF::LineReader& reader);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ParseHeader(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void ParseHeader(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ParseEntities(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void ParseEntities(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ParseBlocks(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void ParseBlocks(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ParseBlock(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void ParseBlock(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ParseInsertion(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void ParseInsertion(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ParsePolyLine(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void ParsePolyLine(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ParsePolyLineVertex(DXF::LineReader& reader,
|
||||
DXF::PolyLine& line);
|
||||
// -----------------------------------------------------
|
||||
void ParsePolyLineVertex(DXF::LineReader& reader,
|
||||
DXF::PolyLine& line);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void Parse3DFace(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void Parse3DFace(DXF::LineReader& reader,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ConvertMeshes(aiScene* pScene,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void ConvertMeshes(aiScene* pScene,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void GenerateHierarchy(aiScene* pScene,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void GenerateHierarchy(aiScene* pScene,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void GenerateMaterials(aiScene* pScene,
|
||||
DXF::FileData& output);
|
||||
// -----------------------------------------------------
|
||||
void GenerateMaterials(aiScene* pScene,
|
||||
DXF::FileData& output);
|
||||
|
||||
// -----------------------------------------------------
|
||||
void ExpandBlockReferences(DXF::Block& bl,
|
||||
const DXF::BlockMap& blocks_by_name);
|
||||
// -----------------------------------------------------
|
||||
void ExpandBlockReferences(DXF::Block& bl,
|
||||
const DXF::BlockMap& blocks_by_name);
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -55,411 +55,411 @@ using namespace Assimp;
|
|||
// Constructor to be privately used by Importer
|
||||
DeboneProcess::DeboneProcess()
|
||||
{
|
||||
mNumBones = 0;
|
||||
mNumBonesCanDoWithout = 0;
|
||||
mNumBones = 0;
|
||||
mNumBonesCanDoWithout = 0;
|
||||
|
||||
mThreshold = AI_DEBONE_THRESHOLD;
|
||||
mAllOrNone = false;
|
||||
mThreshold = AI_DEBONE_THRESHOLD;
|
||||
mAllOrNone = false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
DeboneProcess::~DeboneProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool DeboneProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_Debone) != 0;
|
||||
return (pFlags & aiProcess_Debone) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void DeboneProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
// get the current value of the property
|
||||
mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
|
||||
mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
|
||||
// get the current value of the property
|
||||
mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
|
||||
mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void DeboneProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
DefaultLogger::get()->debug("DeboneProcess begin");
|
||||
DefaultLogger::get()->debug("DeboneProcess begin");
|
||||
|
||||
if(!pScene->mNumMeshes) {
|
||||
return;
|
||||
}
|
||||
if(!pScene->mNumMeshes) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<bool> splitList(pScene->mNumMeshes);
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
splitList[a] = ConsiderMesh( pScene->mMeshes[a] );
|
||||
}
|
||||
std::vector<bool> splitList(pScene->mNumMeshes);
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
splitList[a] = ConsiderMesh( pScene->mMeshes[a] );
|
||||
}
|
||||
|
||||
int numSplits = 0;
|
||||
int numSplits = 0;
|
||||
|
||||
if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) {
|
||||
for(unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if(splitList[a]) {
|
||||
numSplits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) {
|
||||
for(unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if(splitList[a]) {
|
||||
numSplits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(numSplits) {
|
||||
// we need to do something. Let's go.
|
||||
//mSubMeshIndices.clear(); // really needed?
|
||||
mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway
|
||||
if(numSplits) {
|
||||
// we need to do something. Let's go.
|
||||
//mSubMeshIndices.clear(); // really needed?
|
||||
mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway
|
||||
|
||||
// build a new array of meshes for the scene
|
||||
std::vector<aiMesh*> meshes;
|
||||
// build a new array of meshes for the scene
|
||||
std::vector<aiMesh*> meshes;
|
||||
|
||||
for(unsigned int a=0;a<pScene->mNumMeshes;a++)
|
||||
{
|
||||
aiMesh* srcMesh = pScene->mMeshes[a];
|
||||
for(unsigned int a=0;a<pScene->mNumMeshes;a++)
|
||||
{
|
||||
aiMesh* srcMesh = pScene->mMeshes[a];
|
||||
|
||||
std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
|
||||
std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
|
||||
|
||||
if(splitList[a]) {
|
||||
SplitMesh(srcMesh,newMeshes);
|
||||
}
|
||||
if(splitList[a]) {
|
||||
SplitMesh(srcMesh,newMeshes);
|
||||
}
|
||||
|
||||
// mesh was split
|
||||
if(!newMeshes.empty()) {
|
||||
unsigned int out = 0, in = srcMesh->mNumBones;
|
||||
// mesh was split
|
||||
if(!newMeshes.empty()) {
|
||||
unsigned int out = 0, in = srcMesh->mNumBones;
|
||||
|
||||
// store new meshes and indices of the new meshes
|
||||
for(unsigned int b=0;b<newMeshes.size();b++) {
|
||||
const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0;
|
||||
// store new meshes and indices of the new meshes
|
||||
for(unsigned int b=0;b<newMeshes.size();b++) {
|
||||
const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0;
|
||||
|
||||
aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0;
|
||||
std::pair<unsigned int,aiNode*> push_pair(meshes.size(),theNode);
|
||||
aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0;
|
||||
std::pair<unsigned int,aiNode*> push_pair(meshes.size(),theNode);
|
||||
|
||||
mSubMeshIndices[a].push_back(push_pair);
|
||||
meshes.push_back(newMeshes[b].first);
|
||||
mSubMeshIndices[a].push_back(push_pair);
|
||||
meshes.push_back(newMeshes[b].first);
|
||||
|
||||
out+=newMeshes[b].first->mNumBones;
|
||||
}
|
||||
out+=newMeshes[b].first->mNumBones;
|
||||
}
|
||||
|
||||
if(!DefaultLogger::isNullLogger()) {
|
||||
char buffer[1024];
|
||||
::sprintf(buffer,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out);
|
||||
DefaultLogger::get()->info(buffer);
|
||||
}
|
||||
if(!DefaultLogger::isNullLogger()) {
|
||||
char buffer[1024];
|
||||
::sprintf(buffer,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out);
|
||||
DefaultLogger::get()->info(buffer);
|
||||
}
|
||||
|
||||
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||
delete srcMesh;
|
||||
}
|
||||
else {
|
||||
// Mesh is kept unchanged - store it's new place in the mesh array
|
||||
mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(meshes.size(),(aiNode*)0));
|
||||
meshes.push_back(srcMesh);
|
||||
}
|
||||
}
|
||||
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||
delete srcMesh;
|
||||
}
|
||||
else {
|
||||
// Mesh is kept unchanged - store it's new place in the mesh array
|
||||
mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(meshes.size(),(aiNode*)0));
|
||||
meshes.push_back(srcMesh);
|
||||
}
|
||||
}
|
||||
|
||||
// rebuild the scene's mesh array
|
||||
pScene->mNumMeshes = meshes.size();
|
||||
delete [] pScene->mMeshes;
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
|
||||
// rebuild the scene's mesh array
|
||||
pScene->mNumMeshes = meshes.size();
|
||||
delete [] pScene->mMeshes;
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
|
||||
|
||||
// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
|
||||
UpdateNode( pScene->mRootNode);
|
||||
}
|
||||
// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
|
||||
UpdateNode( pScene->mRootNode);
|
||||
}
|
||||
|
||||
DefaultLogger::get()->debug("DeboneProcess end");
|
||||
DefaultLogger::get()->debug("DeboneProcess end");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Counts bones total/removable in a given mesh.
|
||||
bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
|
||||
{
|
||||
if(!pMesh->HasBones()) {
|
||||
return false;
|
||||
}
|
||||
if(!pMesh->HasBones()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool split = false;
|
||||
bool split = false;
|
||||
|
||||
//interstitial faces not permitted
|
||||
bool isInterstitialRequired = false;
|
||||
//interstitial faces not permitted
|
||||
bool isInterstitialRequired = false;
|
||||
|
||||
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
|
||||
std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
|
||||
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
|
||||
std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
|
||||
|
||||
const unsigned int cUnowned = UINT_MAX;
|
||||
const unsigned int cCoowned = UINT_MAX-1;
|
||||
const unsigned int cUnowned = UINT_MAX;
|
||||
const unsigned int cCoowned = UINT_MAX-1;
|
||||
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
|
||||
float w = pMesh->mBones[i]->mWeights[j].mWeight;
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
|
||||
float w = pMesh->mBones[i]->mWeights[j].mWeight;
|
||||
|
||||
if(w==0.0f) {
|
||||
continue;
|
||||
}
|
||||
if(w==0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
|
||||
if(w>=mThreshold) {
|
||||
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
|
||||
if(w>=mThreshold) {
|
||||
|
||||
if(vertexBones[vid]!=cUnowned) {
|
||||
if(vertexBones[vid]==i) //double entry
|
||||
{
|
||||
DefaultLogger::get()->warn("Encountered double entry in bone weights");
|
||||
}
|
||||
else //TODO: track attraction in order to break tie
|
||||
{
|
||||
vertexBones[vid] = cCoowned;
|
||||
}
|
||||
}
|
||||
else vertexBones[vid] = i;
|
||||
}
|
||||
if(vertexBones[vid]!=cUnowned) {
|
||||
if(vertexBones[vid]==i) //double entry
|
||||
{
|
||||
DefaultLogger::get()->warn("Encountered double entry in bone weights");
|
||||
}
|
||||
else //TODO: track attraction in order to break tie
|
||||
{
|
||||
vertexBones[vid] = cCoowned;
|
||||
}
|
||||
}
|
||||
else vertexBones[vid] = i;
|
||||
}
|
||||
|
||||
if(!isBoneNecessary[i]) {
|
||||
isBoneNecessary[i] = w<mThreshold;
|
||||
}
|
||||
}
|
||||
if(!isBoneNecessary[i]) {
|
||||
isBoneNecessary[i] = w<mThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isBoneNecessary[i]) {
|
||||
isInterstitialRequired = true;
|
||||
}
|
||||
}
|
||||
if(!isBoneNecessary[i]) {
|
||||
isInterstitialRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(isInterstitialRequired) {
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
|
||||
if(isInterstitialRequired) {
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
|
||||
|
||||
for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
|
||||
unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
|
||||
for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
|
||||
unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
|
||||
|
||||
if(v!=w) {
|
||||
if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
|
||||
if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(v!=w) {
|
||||
if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
|
||||
if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
if(!isBoneNecessary[i]) {
|
||||
mNumBonesCanDoWithout++;
|
||||
split = true;
|
||||
}
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
if(!isBoneNecessary[i]) {
|
||||
mNumBonesCanDoWithout++;
|
||||
split = true;
|
||||
}
|
||||
|
||||
mNumBones++;
|
||||
}
|
||||
return split;
|
||||
mNumBones++;
|
||||
}
|
||||
return split;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Splits the given mesh by bone count.
|
||||
void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const
|
||||
{
|
||||
// same deal here as ConsiderMesh basically
|
||||
// same deal here as ConsiderMesh basically
|
||||
|
||||
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
|
||||
std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
|
||||
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
|
||||
std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
|
||||
|
||||
const unsigned int cUnowned = UINT_MAX;
|
||||
const unsigned int cCoowned = UINT_MAX-1;
|
||||
const unsigned int cUnowned = UINT_MAX;
|
||||
const unsigned int cCoowned = UINT_MAX-1;
|
||||
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
|
||||
float w = pMesh->mBones[i]->mWeights[j].mWeight;
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
|
||||
float w = pMesh->mBones[i]->mWeights[j].mWeight;
|
||||
|
||||
if(w==0.0f) {
|
||||
continue;
|
||||
}
|
||||
if(w==0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
|
||||
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
|
||||
|
||||
if(w>=mThreshold) {
|
||||
if(vertexBones[vid]!=cUnowned) {
|
||||
if(vertexBones[vid]==i) //double entry
|
||||
{
|
||||
//DefaultLogger::get()->warn("Encountered double entry in bone weights");
|
||||
}
|
||||
else //TODO: track attraction in order to break tie
|
||||
{
|
||||
vertexBones[vid] = cCoowned;
|
||||
}
|
||||
}
|
||||
else vertexBones[vid] = i;
|
||||
}
|
||||
if(w>=mThreshold) {
|
||||
if(vertexBones[vid]!=cUnowned) {
|
||||
if(vertexBones[vid]==i) //double entry
|
||||
{
|
||||
//DefaultLogger::get()->warn("Encountered double entry in bone weights");
|
||||
}
|
||||
else //TODO: track attraction in order to break tie
|
||||
{
|
||||
vertexBones[vid] = cCoowned;
|
||||
}
|
||||
}
|
||||
else vertexBones[vid] = i;
|
||||
}
|
||||
|
||||
if(!isBoneNecessary[i]) {
|
||||
isBoneNecessary[i] = w<mThreshold;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!isBoneNecessary[i]) {
|
||||
isBoneNecessary[i] = w<mThreshold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int nFacesUnowned = 0;
|
||||
unsigned int nFacesUnowned = 0;
|
||||
|
||||
std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX);
|
||||
std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0);
|
||||
std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX);
|
||||
std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0);
|
||||
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
unsigned int nInterstitial = 1;
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
unsigned int nInterstitial = 1;
|
||||
|
||||
unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
|
||||
unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
|
||||
|
||||
for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
|
||||
unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
|
||||
for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
|
||||
unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
|
||||
|
||||
if(v!=w) {
|
||||
if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
|
||||
if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
|
||||
}
|
||||
else nInterstitial++;
|
||||
}
|
||||
if(v!=w) {
|
||||
if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
|
||||
if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
|
||||
}
|
||||
else nInterstitial++;
|
||||
}
|
||||
|
||||
if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices) {
|
||||
faceBones[i] = v; //primitive belongs to bone #v
|
||||
facesPerBone[v]++;
|
||||
}
|
||||
else nFacesUnowned++;
|
||||
}
|
||||
if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices) {
|
||||
faceBones[i] = v; //primitive belongs to bone #v
|
||||
facesPerBone[v]++;
|
||||
}
|
||||
else nFacesUnowned++;
|
||||
}
|
||||
|
||||
// invalidate any "cojoined" faces
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]])
|
||||
{
|
||||
ai_assert(facesPerBone[faceBones[i]]>0);
|
||||
facesPerBone[faceBones[i]]--;
|
||||
// invalidate any "cojoined" faces
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]])
|
||||
{
|
||||
ai_assert(facesPerBone[faceBones[i]]>0);
|
||||
facesPerBone[faceBones[i]]--;
|
||||
|
||||
nFacesUnowned++;
|
||||
faceBones[i] = cUnowned;
|
||||
}
|
||||
}
|
||||
nFacesUnowned++;
|
||||
faceBones[i] = cUnowned;
|
||||
}
|
||||
}
|
||||
|
||||
if(nFacesUnowned) {
|
||||
std::vector<unsigned int> subFaces;
|
||||
if(nFacesUnowned) {
|
||||
std::vector<unsigned int> subFaces;
|
||||
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
if(faceBones[i]==cUnowned) {
|
||||
subFaces.push_back(i);
|
||||
}
|
||||
}
|
||||
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||
if(faceBones[i]==cUnowned) {
|
||||
subFaces.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0);
|
||||
std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0);
|
||||
aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0);
|
||||
std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0);
|
||||
|
||||
poNewMeshes.push_back(push_pair);
|
||||
}
|
||||
poNewMeshes.push_back(push_pair);
|
||||
}
|
||||
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||
|
||||
if(!isBoneNecessary[i]&&facesPerBone[i]>0) {
|
||||
std::vector<unsigned int> subFaces;
|
||||
if(!isBoneNecessary[i]&&facesPerBone[i]>0) {
|
||||
std::vector<unsigned int> subFaces;
|
||||
|
||||
for(unsigned int j=0;j<pMesh->mNumFaces;j++) {
|
||||
if(faceBones[j]==i) {
|
||||
subFaces.push_back(j);
|
||||
}
|
||||
}
|
||||
for(unsigned int j=0;j<pMesh->mNumFaces;j++) {
|
||||
if(faceBones[j]==i) {
|
||||
subFaces.push_back(j);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES;
|
||||
aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f);
|
||||
unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES;
|
||||
aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f);
|
||||
|
||||
//Lifted from PretransformVertices.cpp
|
||||
ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix);
|
||||
std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]);
|
||||
//Lifted from PretransformVertices.cpp
|
||||
ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix);
|
||||
std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]);
|
||||
|
||||
poNewMeshes.push_back(push_pair);
|
||||
}
|
||||
}
|
||||
poNewMeshes.push_back(push_pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void DeboneProcess::UpdateNode(aiNode* pNode) const
|
||||
{
|
||||
// rebuild the node's mesh index list
|
||||
// rebuild the node's mesh index list
|
||||
|
||||
std::vector<unsigned int> newMeshList;
|
||||
std::vector<unsigned int> newMeshList;
|
||||
|
||||
// this will require two passes
|
||||
// this will require two passes
|
||||
|
||||
unsigned int m = pNode->mNumMeshes, n = mSubMeshIndices.size();
|
||||
unsigned int m = pNode->mNumMeshes, n = mSubMeshIndices.size();
|
||||
|
||||
// first pass, look for meshes which have not moved
|
||||
// first pass, look for meshes which have not moved
|
||||
|
||||
for(unsigned int a=0;a<m;a++) {
|
||||
for(unsigned int a=0;a<m;a++) {
|
||||
|
||||
unsigned int srcIndex = pNode->mMeshes[a];
|
||||
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
|
||||
unsigned int nSubmeshes = subMeshes.size();
|
||||
unsigned int srcIndex = pNode->mMeshes[a];
|
||||
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
|
||||
unsigned int nSubmeshes = subMeshes.size();
|
||||
|
||||
for(unsigned int b=0;b<nSubmeshes;b++) {
|
||||
if(!subMeshes[b].second) {
|
||||
newMeshList.push_back(subMeshes[b].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(unsigned int b=0;b<nSubmeshes;b++) {
|
||||
if(!subMeshes[b].second) {
|
||||
newMeshList.push_back(subMeshes[b].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// second pass, collect deboned meshes
|
||||
// second pass, collect deboned meshes
|
||||
|
||||
for(unsigned int a=0;a<n;a++)
|
||||
{
|
||||
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
|
||||
unsigned int nSubmeshes = subMeshes.size();
|
||||
for(unsigned int a=0;a<n;a++)
|
||||
{
|
||||
const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
|
||||
unsigned int nSubmeshes = subMeshes.size();
|
||||
|
||||
for(unsigned int b=0;b<nSubmeshes;b++) {
|
||||
if(subMeshes[b].second == pNode) {
|
||||
newMeshList.push_back(subMeshes[b].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(unsigned int b=0;b<nSubmeshes;b++) {
|
||||
if(subMeshes[b].second == pNode) {
|
||||
newMeshList.push_back(subMeshes[b].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pNode->mNumMeshes > 0 ) {
|
||||
delete [] pNode->mMeshes; pNode->mMeshes = NULL;
|
||||
}
|
||||
if( pNode->mNumMeshes > 0 ) {
|
||||
delete [] pNode->mMeshes; pNode->mMeshes = NULL;
|
||||
}
|
||||
|
||||
pNode->mNumMeshes = newMeshList.size();
|
||||
pNode->mNumMeshes = newMeshList.size();
|
||||
|
||||
if(pNode->mNumMeshes) {
|
||||
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||
std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
|
||||
}
|
||||
if(pNode->mNumMeshes) {
|
||||
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||
std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
|
||||
}
|
||||
|
||||
// do that also recursively for all children
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) {
|
||||
UpdateNode( pNode->mChildren[a]);
|
||||
}
|
||||
// do that also recursively for all children
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) {
|
||||
UpdateNode( pNode->mChildren[a]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Apply the node transformation to a mesh
|
||||
void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const
|
||||
{
|
||||
// Check whether we need to transform the coordinates at all
|
||||
if (!mat.IsIdentity()) {
|
||||
// Check whether we need to transform the coordinates at all
|
||||
if (!mat.IsIdentity()) {
|
||||
|
||||
if (mesh->HasPositions()) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
mesh->mVertices[i] = mat * mesh->mVertices[i];
|
||||
}
|
||||
}
|
||||
if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
|
||||
aiMatrix4x4 mWorldIT = mat;
|
||||
mWorldIT.Inverse().Transpose();
|
||||
if (mesh->HasPositions()) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
mesh->mVertices[i] = mat * mesh->mVertices[i];
|
||||
}
|
||||
}
|
||||
if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
|
||||
aiMatrix4x4 mWorldIT = mat;
|
||||
mWorldIT.Inverse().Transpose();
|
||||
|
||||
// TODO: implement Inverse() for aiMatrix3x3
|
||||
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
|
||||
// TODO: implement Inverse() for aiMatrix3x3
|
||||
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
|
||||
|
||||
if (mesh->HasNormals()) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
|
||||
}
|
||||
}
|
||||
if (mesh->HasTangentsAndBitangents()) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
|
||||
mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mesh->HasNormals()) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
|
||||
}
|
||||
}
|
||||
if (mesh->HasTangentsAndBitangents()) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
|
||||
mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace Assimp
|
|||
{
|
||||
|
||||
#if (!defined AI_DEBONE_THRESHOLD)
|
||||
# define AI_DEBONE_THRESHOLD 1.0f
|
||||
# define AI_DEBONE_THRESHOLD 1.0f
|
||||
#endif // !! AI_DEBONE_THRESHOLD
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -68,63 +68,63 @@ class DeboneProcess : public BaseProcess
|
|||
{
|
||||
public:
|
||||
|
||||
DeboneProcess();
|
||||
~DeboneProcess();
|
||||
DeboneProcess();
|
||||
~DeboneProcess();
|
||||
|
||||
public:
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with.
|
||||
* A bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with.
|
||||
* A bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Counts bones total/removable in a given mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
*/
|
||||
bool ConsiderMesh( const aiMesh* pMesh);
|
||||
// -------------------------------------------------------------------
|
||||
/** Counts bones total/removable in a given mesh.
|
||||
* @param pMesh The mesh to process.
|
||||
*/
|
||||
bool ConsiderMesh( const aiMesh* pMesh);
|
||||
|
||||
/// Splits the given mesh by bone count.
|
||||
/// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
|
||||
/// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
|
||||
void SplitMesh(const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const;
|
||||
/// Splits the given mesh by bone count.
|
||||
/// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
|
||||
/// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
|
||||
void SplitMesh(const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const;
|
||||
|
||||
/// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void UpdateNode(aiNode* pNode) const;
|
||||
/// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void UpdateNode(aiNode* pNode) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Apply transformation to a mesh
|
||||
void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const;
|
||||
// -------------------------------------------------------------------
|
||||
// Apply transformation to a mesh
|
||||
void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const;
|
||||
|
||||
public:
|
||||
/** Number of bones present in the scene. */
|
||||
unsigned int mNumBones;
|
||||
unsigned int mNumBonesCanDoWithout;
|
||||
/** Number of bones present in the scene. */
|
||||
unsigned int mNumBones;
|
||||
unsigned int mNumBonesCanDoWithout;
|
||||
|
||||
float mThreshold;
|
||||
bool mAllOrNone;
|
||||
float mThreshold;
|
||||
bool mAllOrNone;
|
||||
|
||||
/// Per mesh index: Array of indices of the new submeshes.
|
||||
std::vector< std::vector< std::pair< unsigned int,aiNode* > > > mSubMeshIndices;
|
||||
/// Per mesh index: Array of indices of the new submeshes.
|
||||
std::vector< std::vector< std::pair< unsigned int,aiNode* > > > mSubMeshIndices;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -54,62 +54,62 @@ using namespace Assimp;
|
|||
// ----------------------------------------------------------------------------------
|
||||
DefaultIOStream::~DefaultIOStream()
|
||||
{
|
||||
if (mFile) {
|
||||
::fclose(mFile);
|
||||
}
|
||||
if (mFile) {
|
||||
::fclose(mFile);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Read(void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
|
||||
return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0);
|
||||
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
|
||||
return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Write(const void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
size_t pSize,
|
||||
size_t pCount)
|
||||
{
|
||||
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
|
||||
return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0);
|
||||
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
|
||||
return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
aiReturn DefaultIOStream::Seek(size_t pOffset,
|
||||
aiOrigin pOrigin)
|
||||
aiOrigin pOrigin)
|
||||
{
|
||||
if (!mFile) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
if (!mFile) {
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// Just to check whether our enum maps one to one with the CRT constants
|
||||
BOOST_STATIC_ASSERT(aiOrigin_CUR == SEEK_CUR &&
|
||||
aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET);
|
||||
// Just to check whether our enum maps one to one with the CRT constants
|
||||
BOOST_STATIC_ASSERT(aiOrigin_CUR == SEEK_CUR &&
|
||||
aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET);
|
||||
|
||||
// do the seek
|
||||
return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE);
|
||||
// do the seek
|
||||
return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::Tell() const
|
||||
{
|
||||
if (!mFile) {
|
||||
return 0;
|
||||
}
|
||||
return ::ftell(mFile);
|
||||
if (!mFile) {
|
||||
return 0;
|
||||
}
|
||||
return ::ftell(mFile);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
size_t DefaultIOStream::FileSize() const
|
||||
{
|
||||
if (! mFile || mFilename.empty()) {
|
||||
return 0;
|
||||
}
|
||||
if (! mFile || mFilename.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SIZE_MAX == cachedSize) {
|
||||
if (SIZE_MAX == cachedSize) {
|
||||
|
||||
// Although fseek/ftell would allow us to reuse the exising file handle here,
|
||||
// it is generally unsafe because:
|
||||
|
@ -120,28 +120,28 @@ size_t DefaultIOStream::FileSize() const
|
|||
// See here for details:
|
||||
// https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
|
||||
#if defined _WIN32 && !defined __GNUC__
|
||||
struct __stat64 fileStat;
|
||||
int err = _stat64( mFilename.c_str(), &fileStat );
|
||||
if (0 != err)
|
||||
return 0;
|
||||
cachedSize = (size_t) (fileStat.st_size);
|
||||
struct __stat64 fileStat;
|
||||
int err = _stat64( mFilename.c_str(), &fileStat );
|
||||
if (0 != err)
|
||||
return 0;
|
||||
cachedSize = (size_t) (fileStat.st_size);
|
||||
#else
|
||||
struct stat fileStat;
|
||||
int err = stat(mFilename.c_str(), &fileStat );
|
||||
if (0 != err)
|
||||
return 0;
|
||||
cachedSize = (size_t) (fileStat.st_size);
|
||||
struct stat fileStat;
|
||||
int err = stat(mFilename.c_str(), &fileStat );
|
||||
if (0 != err)
|
||||
return 0;
|
||||
cachedSize = (size_t) (fileStat.st_size);
|
||||
#endif
|
||||
}
|
||||
return cachedSize;
|
||||
}
|
||||
return cachedSize;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void DefaultIOStream::Flush()
|
||||
{
|
||||
if (mFile) {
|
||||
::fflush(mFile);
|
||||
}
|
||||
if (mFile) {
|
||||
::fflush(mFile);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
|
|
@ -47,17 +47,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/assimp/importerdesc.h"
|
||||
#include "Defines.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
//! @class DefaultIOStream
|
||||
//! @brief Default IO implementation, use standard IO operations
|
||||
//! @class DefaultIOStream
|
||||
//! @brief Default IO implementation, use standard IO operations
|
||||
//! @note An instance of this class can exist without a valid file handle
|
||||
//! attached to it. All calls fail, but the instance can nevertheless be
|
||||
//! used with no restrictions.
|
||||
class DefaultIOStream : public IOStream
|
||||
{
|
||||
friend class DefaultIOSystem;
|
||||
friend class DefaultIOSystem;
|
||||
#if __ANDROID__
|
||||
#if __ANDROID_API__ > 9
|
||||
#if defined(AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT)
|
||||
|
@ -67,72 +67,72 @@ class DefaultIOStream : public IOStream
|
|||
#endif // __ANDROID__
|
||||
|
||||
protected:
|
||||
DefaultIOStream();
|
||||
DefaultIOStream(FILE* pFile, const std::string &strFilename);
|
||||
DefaultIOStream();
|
||||
DefaultIOStream(FILE* pFile, const std::string &strFilename);
|
||||
|
||||
public:
|
||||
/** Destructor public to allow simple deletion to close the file. */
|
||||
~DefaultIOStream ();
|
||||
/** Destructor public to allow simple deletion to close the file. */
|
||||
~DefaultIOStream ();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Read from stream
|
||||
// -------------------------------------------------------------------
|
||||
/// Read from stream
|
||||
size_t Read(void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount);
|
||||
size_t pSize,
|
||||
size_t pCount);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Write to stream
|
||||
// -------------------------------------------------------------------
|
||||
/// Write to stream
|
||||
size_t Write(const void* pvBuffer,
|
||||
size_t pSize,
|
||||
size_t pCount);
|
||||
size_t pSize,
|
||||
size_t pCount);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Seek specific position
|
||||
aiReturn Seek(size_t pOffset,
|
||||
aiOrigin pOrigin);
|
||||
// -------------------------------------------------------------------
|
||||
/// Seek specific position
|
||||
aiReturn Seek(size_t pOffset,
|
||||
aiOrigin pOrigin);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Get current seek position
|
||||
// -------------------------------------------------------------------
|
||||
/// Get current seek position
|
||||
size_t Tell() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Get size of file
|
||||
size_t FileSize() const;
|
||||
// -------------------------------------------------------------------
|
||||
/// Get size of file
|
||||
size_t FileSize() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/// Flush file contents
|
||||
void Flush();
|
||||
// -------------------------------------------------------------------
|
||||
/// Flush file contents
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
// File datastructure, using clib
|
||||
FILE* mFile;
|
||||
// Filename
|
||||
std::string mFilename;
|
||||
// File datastructure, using clib
|
||||
FILE* mFile;
|
||||
// Filename
|
||||
std::string mFilename;
|
||||
|
||||
// Cached file size
|
||||
mutable size_t cachedSize;
|
||||
// Cached file size
|
||||
mutable size_t cachedSize;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
inline DefaultIOStream::DefaultIOStream () :
|
||||
mFile (NULL),
|
||||
mFilename (""),
|
||||
cachedSize (SIZE_MAX)
|
||||
mFile (NULL),
|
||||
mFilename (""),
|
||||
cachedSize (SIZE_MAX)
|
||||
{
|
||||
// empty
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
inline DefaultIOStream::DefaultIOStream (FILE* pFile,
|
||||
const std::string &strFilename) :
|
||||
mFile(pFile),
|
||||
mFilename(strFilename),
|
||||
cachedSize (SIZE_MAX)
|
||||
const std::string &strFilename) :
|
||||
mFile(pFile),
|
||||
mFilename(strFilename),
|
||||
cachedSize (SIZE_MAX)
|
||||
{
|
||||
// empty
|
||||
// empty
|
||||
}
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -60,47 +60,47 @@ using namespace Assimp;
|
|||
// Constructor.
|
||||
DefaultIOSystem::DefaultIOSystem()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor.
|
||||
DefaultIOSystem::~DefaultIOSystem()
|
||||
{
|
||||
// nothing to do here
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Tests for the existence of a file at the given path.
|
||||
bool DefaultIOSystem::Exists( const char* pFile) const
|
||||
{
|
||||
FILE* file = ::fopen( pFile, "rb");
|
||||
if( !file)
|
||||
return false;
|
||||
FILE* file = ::fopen( pFile, "rb");
|
||||
if( !file)
|
||||
return false;
|
||||
|
||||
::fclose( file);
|
||||
return true;
|
||||
::fclose( file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Open a new file with a given path.
|
||||
IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
|
||||
{
|
||||
ai_assert(NULL != strFile);
|
||||
ai_assert(NULL != strMode);
|
||||
ai_assert(NULL != strFile);
|
||||
ai_assert(NULL != strMode);
|
||||
|
||||
FILE* file = ::fopen( strFile, strMode);
|
||||
if( NULL == file)
|
||||
return NULL;
|
||||
FILE* file = ::fopen( strFile, strMode);
|
||||
if( NULL == file)
|
||||
return NULL;
|
||||
|
||||
return new DefaultIOStream(file, (std::string) strFile);
|
||||
return new DefaultIOStream(file, (std::string) strFile);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Closes the given file and releases all resources associated with it.
|
||||
void DefaultIOSystem::Close( IOStream* pFile)
|
||||
{
|
||||
delete pFile;
|
||||
delete pFile;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -108,9 +108,9 @@ void DefaultIOSystem::Close( IOStream* pFile)
|
|||
char DefaultIOSystem::getOsSeparator() const
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return '/';
|
||||
return '/';
|
||||
#else
|
||||
return '\\';
|
||||
return '\\';
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -118,80 +118,80 @@ char DefaultIOSystem::getOsSeparator() const
|
|||
// IOSystem default implementation (ComparePaths isn't a pure virtual function)
|
||||
bool IOSystem::ComparePaths (const char* one, const char* second) const
|
||||
{
|
||||
return !ASSIMP_stricmp(one,second);
|
||||
return !ASSIMP_stricmp(one,second);
|
||||
}
|
||||
|
||||
// maximum path length
|
||||
// XXX http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
|
||||
#ifdef PATH_MAX
|
||||
# define PATHLIMIT PATH_MAX
|
||||
# define PATHLIMIT PATH_MAX
|
||||
#else
|
||||
# define PATHLIMIT 4096
|
||||
# define PATHLIMIT 4096
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a relative path into an absolute path
|
||||
inline void MakeAbsolutePath (const char* in, char* _out)
|
||||
{
|
||||
ai_assert(in && _out);
|
||||
char* ret;
|
||||
ai_assert(in && _out);
|
||||
char* ret;
|
||||
#ifdef _WIN32
|
||||
ret = ::_fullpath(_out, in,PATHLIMIT);
|
||||
ret = ::_fullpath(_out, in,PATHLIMIT);
|
||||
#else
|
||||
// use realpath
|
||||
ret = realpath(in, _out);
|
||||
// use realpath
|
||||
ret = realpath(in, _out);
|
||||
#endif
|
||||
if(!ret) {
|
||||
// preserve the input path, maybe someone else is able to fix
|
||||
// the path before it is accessed (e.g. our file system filter)
|
||||
DefaultLogger::get()->warn("Invalid path: "+std::string(in));
|
||||
strcpy(_out,in);
|
||||
}
|
||||
if(!ret) {
|
||||
// preserve the input path, maybe someone else is able to fix
|
||||
// the path before it is accessed (e.g. our file system filter)
|
||||
DefaultLogger::get()->warn("Invalid path: "+std::string(in));
|
||||
strcpy(_out,in);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// DefaultIOSystem's more specialized implementation
|
||||
bool DefaultIOSystem::ComparePaths (const char* one, const char* second) const
|
||||
{
|
||||
// chances are quite good both paths are formatted identically,
|
||||
// so we can hopefully return here already
|
||||
if( !ASSIMP_stricmp(one,second) )
|
||||
return true;
|
||||
// chances are quite good both paths are formatted identically,
|
||||
// so we can hopefully return here already
|
||||
if( !ASSIMP_stricmp(one,second) )
|
||||
return true;
|
||||
|
||||
char temp1[PATHLIMIT];
|
||||
char temp2[PATHLIMIT];
|
||||
char temp1[PATHLIMIT];
|
||||
char temp2[PATHLIMIT];
|
||||
|
||||
MakeAbsolutePath (one, temp1);
|
||||
MakeAbsolutePath (second, temp2);
|
||||
MakeAbsolutePath (one, temp1);
|
||||
MakeAbsolutePath (second, temp2);
|
||||
|
||||
return !ASSIMP_stricmp(temp1,temp2);
|
||||
return !ASSIMP_stricmp(temp1,temp2);
|
||||
}
|
||||
|
||||
|
||||
std::string DefaultIOSystem::fileName(std::string path)
|
||||
{
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
if (last != std::string::npos) ret = ret.substr(last + 1);
|
||||
return ret;
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
if (last != std::string::npos) ret = ret.substr(last + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::string DefaultIOSystem::completeBaseName(std::string path)
|
||||
{
|
||||
std::string ret = fileName(path);
|
||||
std::size_t pos = ret.find_last_of('.');
|
||||
if(pos != ret.npos) ret = ret.substr(0, pos);
|
||||
return ret;
|
||||
std::string ret = fileName(path);
|
||||
std::size_t pos = ret.find_last_of('.');
|
||||
if(pos != ret.npos) ret = ret.substr(0, pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::string DefaultIOSystem::absolutePath(std::string path)
|
||||
{
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
if (last != std::string::npos) ret = ret.substr(0, last);
|
||||
return ret;
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
if (last != std::string::npos) ret = ret.substr(0, last);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef PATHLIMIT
|
||||
|
|
|
@ -44,53 +44,53 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "../include/assimp/IOSystem.hpp"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Default implementation of IOSystem using the standard C file functions */
|
||||
class DefaultIOSystem : public IOSystem
|
||||
{
|
||||
public:
|
||||
/** Constructor. */
|
||||
/** Constructor. */
|
||||
DefaultIOSystem();
|
||||
|
||||
/** Destructor. */
|
||||
~DefaultIOSystem();
|
||||
/** Destructor. */
|
||||
~DefaultIOSystem();
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Tests for the existence of a file at the given path. */
|
||||
bool Exists( const char* pFile) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Tests for the existence of a file at the given path. */
|
||||
bool Exists( const char* pFile) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the directory separator. */
|
||||
char getOsSeparator() const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns the directory separator. */
|
||||
char getOsSeparator() const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Open a new file with a given path. */
|
||||
IOStream* Open( const char* pFile, const char* pMode = "rb");
|
||||
// -------------------------------------------------------------------
|
||||
/** Open a new file with a given path. */
|
||||
IOStream* Open( const char* pFile, const char* pMode = "rb");
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Closes the given file and releases all resources associated with it. */
|
||||
void Close( IOStream* pFile);
|
||||
// -------------------------------------------------------------------
|
||||
/** Closes the given file and releases all resources associated with it. */
|
||||
void Close( IOStream* pFile);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Compare two paths */
|
||||
bool ComparePaths (const char* one, const char* second) const;
|
||||
// -------------------------------------------------------------------
|
||||
/** Compare two paths */
|
||||
bool ComparePaths (const char* one, const char* second) const;
|
||||
|
||||
/** @brief get the file name of a full filepath
|
||||
* example: /tmp/archive.tar.gz -> archive.tar.gz
|
||||
*/
|
||||
static std::string fileName(std::string path);
|
||||
/** @brief get the file name of a full filepath
|
||||
* example: /tmp/archive.tar.gz -> archive.tar.gz
|
||||
*/
|
||||
static std::string fileName(std::string path);
|
||||
|
||||
/** @brief get the complete base name of a full filepath
|
||||
* example: /tmp/archive.tar.gz -> archive.tar
|
||||
*/
|
||||
static std::string completeBaseName(std::string path);
|
||||
/** @brief get the complete base name of a full filepath
|
||||
* example: /tmp/archive.tar.gz -> archive.tar
|
||||
*/
|
||||
static std::string completeBaseName(std::string path);
|
||||
|
||||
/** @brief get the path of a full filepath
|
||||
* example: /tmp/archive.tar.gz -> /tmp/
|
||||
*/
|
||||
static std::string absolutePath(std::string path);
|
||||
/** @brief get the path of a full filepath
|
||||
* example: /tmp/archive.tar.gz -> /tmp/
|
||||
*/
|
||||
static std::string absolutePath(std::string path);
|
||||
};
|
||||
|
||||
} //!ns Assimp
|
||||
|
|
|
@ -56,13 +56,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <stdio.h>
|
||||
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
# include <boost/thread/thread.hpp>
|
||||
# include <boost/thread/mutex.hpp>
|
||||
# include <boost/thread/thread.hpp>
|
||||
# include <boost/thread/mutex.hpp>
|
||||
|
||||
boost::mutex loggerMutex;
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
NullLogger DefaultLogger::s_pNullLogger;
|
||||
|
@ -74,347 +74,347 @@ static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::War
|
|||
// Represents a log-stream + its error severity
|
||||
struct LogStreamInfo
|
||||
{
|
||||
unsigned int m_uiErrorSeverity;
|
||||
LogStream *m_pStream;
|
||||
unsigned int m_uiErrorSeverity;
|
||||
LogStream *m_pStream;
|
||||
|
||||
// Constructor
|
||||
LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
|
||||
m_uiErrorSeverity( uiErrorSev ),
|
||||
m_pStream( pStream )
|
||||
{
|
||||
// empty
|
||||
}
|
||||
// Constructor
|
||||
LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
|
||||
m_uiErrorSeverity( uiErrorSev ),
|
||||
m_pStream( pStream )
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~LogStreamInfo()
|
||||
{
|
||||
delete m_pStream;
|
||||
}
|
||||
// Destructor
|
||||
~LogStreamInfo()
|
||||
{
|
||||
delete m_pStream;
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Construct a default log stream
|
||||
LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
||||
const char* name /*= "AssimpLog.txt"*/,
|
||||
IOSystem* io /*= NULL*/)
|
||||
LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
||||
const char* name /*= "AssimpLog.txt"*/,
|
||||
IOSystem* io /*= NULL*/)
|
||||
{
|
||||
switch (streams)
|
||||
{
|
||||
// This is a platform-specific feature
|
||||
case aiDefaultLogStream_DEBUGGER:
|
||||
switch (streams)
|
||||
{
|
||||
// This is a platform-specific feature
|
||||
case aiDefaultLogStream_DEBUGGER:
|
||||
#ifdef WIN32
|
||||
return new Win32DebugLogStream();
|
||||
return new Win32DebugLogStream();
|
||||
#else
|
||||
return NULL;
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
// Platform-independent default streams
|
||||
case aiDefaultLogStream_STDERR:
|
||||
return new StdOStreamLogStream(std::cerr);
|
||||
case aiDefaultLogStream_STDOUT:
|
||||
return new StdOStreamLogStream(std::cout);
|
||||
case aiDefaultLogStream_FILE:
|
||||
return (name && *name ? new FileLogStream(name,io) : NULL);
|
||||
default:
|
||||
// We don't know this default log stream, so raise an assertion
|
||||
ai_assert(false);
|
||||
// Platform-independent default streams
|
||||
case aiDefaultLogStream_STDERR:
|
||||
return new StdOStreamLogStream(std::cerr);
|
||||
case aiDefaultLogStream_STDOUT:
|
||||
return new StdOStreamLogStream(std::cout);
|
||||
case aiDefaultLogStream_FILE:
|
||||
return (name && *name ? new FileLogStream(name,io) : NULL);
|
||||
default:
|
||||
// We don't know this default log stream, so raise an assertion
|
||||
ai_assert(false);
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
// For compilers without dead code path detection
|
||||
return NULL;
|
||||
// For compilers without dead code path detection
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Creates the only singleton instance
|
||||
// Creates the only singleton instance
|
||||
Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
|
||||
LogSeverity severity /*= NORMAL*/,
|
||||
unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
|
||||
IOSystem* io /*= NULL*/)
|
||||
LogSeverity severity /*= NORMAL*/,
|
||||
unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
|
||||
IOSystem* io /*= NULL*/)
|
||||
{
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
boost::mutex::scoped_lock lock(loggerMutex);
|
||||
boost::mutex::scoped_lock lock(loggerMutex);
|
||||
#endif
|
||||
|
||||
if (m_pLogger && !isNullLogger() )
|
||||
delete m_pLogger;
|
||||
if (m_pLogger && !isNullLogger() )
|
||||
delete m_pLogger;
|
||||
|
||||
m_pLogger = new DefaultLogger( severity );
|
||||
m_pLogger = new DefaultLogger( severity );
|
||||
|
||||
// Attach default log streams
|
||||
// Stream the log to the MSVC debugger?
|
||||
if (defStreams & aiDefaultLogStream_DEBUGGER)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_DEBUGGER));
|
||||
// Attach default log streams
|
||||
// Stream the log to the MSVC debugger?
|
||||
if (defStreams & aiDefaultLogStream_DEBUGGER)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_DEBUGGER));
|
||||
|
||||
// Stream the log to COUT?
|
||||
if (defStreams & aiDefaultLogStream_STDOUT)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDOUT));
|
||||
// Stream the log to COUT?
|
||||
if (defStreams & aiDefaultLogStream_STDOUT)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDOUT));
|
||||
|
||||
// Stream the log to CERR?
|
||||
if (defStreams & aiDefaultLogStream_STDERR)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDERR));
|
||||
// Stream the log to CERR?
|
||||
if (defStreams & aiDefaultLogStream_STDERR)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDERR));
|
||||
|
||||
// Stream the log to a file
|
||||
if (defStreams & aiDefaultLogStream_FILE && name && *name)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_FILE,name,io));
|
||||
// Stream the log to a file
|
||||
if (defStreams & aiDefaultLogStream_FILE && name && *name)
|
||||
m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_FILE,name,io));
|
||||
|
||||
return m_pLogger;
|
||||
return m_pLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::debug(const char* message) {
|
||||
void Logger::debug(const char* message) {
|
||||
|
||||
// SECURITY FIX: otherwise it's easy to produce overruns since
|
||||
// sometimes importers will include data from the input file
|
||||
// (i.e. node names) in their messages.
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnDebug(message);
|
||||
// SECURITY FIX: otherwise it's easy to produce overruns since
|
||||
// sometimes importers will include data from the input file
|
||||
// (i.e. node names) in their messages.
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnDebug(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::info(const char* message) {
|
||||
void Logger::info(const char* message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnInfo(message);
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnInfo(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::warn(const char* message) {
|
||||
void Logger::warn(const char* message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnWarn(message);
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnWarn(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void Logger::error(const char* message) {
|
||||
void Logger::error(const char* message) {
|
||||
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnError(message);
|
||||
// SECURITY FIX: see above
|
||||
if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
|
||||
return;
|
||||
}
|
||||
return OnError(message);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
void DefaultLogger::set( Logger *logger )
|
||||
{
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
boost::mutex::scoped_lock lock(loggerMutex);
|
||||
boost::mutex::scoped_lock lock(loggerMutex);
|
||||
#endif
|
||||
|
||||
if (!logger)logger = &s_pNullLogger;
|
||||
if (m_pLogger && !isNullLogger() )
|
||||
delete m_pLogger;
|
||||
if (!logger)logger = &s_pNullLogger;
|
||||
if (m_pLogger && !isNullLogger() )
|
||||
delete m_pLogger;
|
||||
|
||||
DefaultLogger::m_pLogger = logger;
|
||||
DefaultLogger::m_pLogger = logger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
bool DefaultLogger::isNullLogger()
|
||||
{
|
||||
return m_pLogger == &s_pNullLogger;
|
||||
return m_pLogger == &s_pNullLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Singleton getter
|
||||
// Singleton getter
|
||||
Logger *DefaultLogger::get()
|
||||
{
|
||||
return m_pLogger;
|
||||
return m_pLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Kills the only instance
|
||||
// Kills the only instance
|
||||
void DefaultLogger::kill()
|
||||
{
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
// enter the mutex here to avoid concurrency problems
|
||||
#ifndef ASSIMP_BUILD_SINGLETHREADED
|
||||
boost::mutex::scoped_lock lock(loggerMutex);
|
||||
boost::mutex::scoped_lock lock(loggerMutex);
|
||||
#endif
|
||||
|
||||
if (m_pLogger == &s_pNullLogger)return;
|
||||
delete m_pLogger;
|
||||
m_pLogger = &s_pNullLogger;
|
||||
if (m_pLogger == &s_pNullLogger)return;
|
||||
delete m_pLogger;
|
||||
m_pLogger = &s_pNullLogger;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Debug message
|
||||
// Debug message
|
||||
void DefaultLogger::OnDebug( const char* message )
|
||||
{
|
||||
if ( m_Severity == Logger::NORMAL )
|
||||
return;
|
||||
if ( m_Severity == Logger::NORMAL )
|
||||
return;
|
||||
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Debug, T%u: %s", GetThreadID(), message );
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Debug, T%u: %s", GetThreadID(), message );
|
||||
|
||||
WriteToStreams( msg, Logger::Debugging );
|
||||
WriteToStreams( msg, Logger::Debugging );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Logs an info
|
||||
// Logs an info
|
||||
void DefaultLogger::OnInfo( const char* message )
|
||||
{
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Info, T%u: %s", GetThreadID(), message );
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Info, T%u: %s", GetThreadID(), message );
|
||||
|
||||
WriteToStreams( msg , Logger::Info );
|
||||
WriteToStreams( msg , Logger::Info );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Logs a warning
|
||||
// Logs a warning
|
||||
void DefaultLogger::OnWarn( const char* message )
|
||||
{
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Warn, T%u: %s", GetThreadID(), message );
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Warn, T%u: %s", GetThreadID(), message );
|
||||
|
||||
WriteToStreams( msg, Logger::Warn );
|
||||
WriteToStreams( msg, Logger::Warn );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Logs an error
|
||||
// Logs an error
|
||||
void DefaultLogger::OnError( const char* message )
|
||||
{
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Error, T%u: %s", GetThreadID(), message );
|
||||
char msg[MAX_LOG_MESSAGE_LENGTH + 16];
|
||||
::sprintf(msg,"Error, T%u: %s", GetThreadID(), message );
|
||||
|
||||
WriteToStreams( msg, Logger::Err );
|
||||
WriteToStreams( msg, Logger::Err );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Will attach a new stream
|
||||
// Will attach a new stream
|
||||
bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
|
||||
{
|
||||
if (!pStream)
|
||||
return false;
|
||||
if (!pStream)
|
||||
return false;
|
||||
|
||||
if (0 == severity) {
|
||||
severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
|
||||
}
|
||||
if (0 == severity) {
|
||||
severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
|
||||
}
|
||||
|
||||
for ( StreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it )
|
||||
{
|
||||
if ( (*it)->m_pStream == pStream )
|
||||
{
|
||||
(*it)->m_uiErrorSeverity |= severity;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for ( StreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it )
|
||||
{
|
||||
if ( (*it)->m_pStream == pStream )
|
||||
{
|
||||
(*it)->m_uiErrorSeverity |= severity;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream );
|
||||
m_StreamArray.push_back( pInfo );
|
||||
return true;
|
||||
LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream );
|
||||
m_StreamArray.push_back( pInfo );
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Detatch a stream
|
||||
// Detatch a stream
|
||||
bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
|
||||
{
|
||||
if (!pStream)
|
||||
return false;
|
||||
if (!pStream)
|
||||
return false;
|
||||
|
||||
if (0 == severity) {
|
||||
severity = SeverityAll;
|
||||
}
|
||||
if (0 == severity) {
|
||||
severity = SeverityAll;
|
||||
}
|
||||
|
||||
for ( StreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it )
|
||||
{
|
||||
if ( (*it)->m_pStream == pStream )
|
||||
{
|
||||
(*it)->m_uiErrorSeverity &= ~severity;
|
||||
if ( (*it)->m_uiErrorSeverity == 0 )
|
||||
{
|
||||
// don't delete the underlying stream 'cause the caller gains ownership again
|
||||
(**it).m_pStream = NULL;
|
||||
delete *it;
|
||||
m_StreamArray.erase( it );
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
for ( StreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it )
|
||||
{
|
||||
if ( (*it)->m_pStream == pStream )
|
||||
{
|
||||
(*it)->m_uiErrorSeverity &= ~severity;
|
||||
if ( (*it)->m_uiErrorSeverity == 0 )
|
||||
{
|
||||
// don't delete the underlying stream 'cause the caller gains ownership again
|
||||
(**it).m_pStream = NULL;
|
||||
delete *it;
|
||||
m_StreamArray.erase( it );
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// Constructor
|
||||
DefaultLogger::DefaultLogger(LogSeverity severity)
|
||||
|
||||
: Logger ( severity )
|
||||
, noRepeatMsg (false)
|
||||
, lastLen( 0 )
|
||||
: Logger ( severity )
|
||||
, noRepeatMsg (false)
|
||||
, lastLen( 0 )
|
||||
{
|
||||
lastMsg[0] = '\0';
|
||||
lastMsg[0] = '\0';
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
// Destructor
|
||||
DefaultLogger::~DefaultLogger()
|
||||
{
|
||||
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
|
||||
// also frees the underlying stream, we are its owner.
|
||||
delete *it;
|
||||
}
|
||||
for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
|
||||
// also frees the underlying stream, we are its owner.
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Writes message to stream
|
||||
// Writes message to stream
|
||||
void DefaultLogger::WriteToStreams(const char *message,
|
||||
ErrorSeverity ErrorSev )
|
||||
ErrorSeverity ErrorSev )
|
||||
{
|
||||
ai_assert(NULL != message);
|
||||
ai_assert(NULL != message);
|
||||
|
||||
// Check whether this is a repeated message
|
||||
if (! ::strncmp( message,lastMsg, lastLen-1))
|
||||
{
|
||||
if (!noRepeatMsg)
|
||||
{
|
||||
noRepeatMsg = true;
|
||||
message = "Skipping one or more lines with the same contents\n";
|
||||
}
|
||||
else return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// append a new-line character to the message to be printed
|
||||
lastLen = ::strlen(message);
|
||||
::memcpy(lastMsg,message,lastLen+1);
|
||||
::strcat(lastMsg+lastLen,"\n");
|
||||
// Check whether this is a repeated message
|
||||
if (! ::strncmp( message,lastMsg, lastLen-1))
|
||||
{
|
||||
if (!noRepeatMsg)
|
||||
{
|
||||
noRepeatMsg = true;
|
||||
message = "Skipping one or more lines with the same contents\n";
|
||||
}
|
||||
else return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// append a new-line character to the message to be printed
|
||||
lastLen = ::strlen(message);
|
||||
::memcpy(lastMsg,message,lastLen+1);
|
||||
::strcat(lastMsg+lastLen,"\n");
|
||||
|
||||
message = lastMsg;
|
||||
noRepeatMsg = false;
|
||||
++lastLen;
|
||||
}
|
||||
for ( ConstStreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it)
|
||||
{
|
||||
if ( ErrorSev & (*it)->m_uiErrorSeverity )
|
||||
(*it)->m_pStream->write( message);
|
||||
}
|
||||
message = lastMsg;
|
||||
noRepeatMsg = false;
|
||||
++lastLen;
|
||||
}
|
||||
for ( ConstStreamIt it = m_StreamArray.begin();
|
||||
it != m_StreamArray.end();
|
||||
++it)
|
||||
{
|
||||
if ( ErrorSev & (*it)->m_uiErrorSeverity )
|
||||
(*it)->m_pStream->write( message);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Returns thread id, if not supported only a zero will be returned.
|
||||
// Returns thread id, if not supported only a zero will be returned.
|
||||
unsigned int DefaultLogger::GetThreadID()
|
||||
{
|
||||
// fixme: we can get this value via boost::threads
|
||||
// fixme: we can get this value via boost::threads
|
||||
#ifdef WIN32
|
||||
return (unsigned int)::GetCurrentThreadId();
|
||||
return (unsigned int)::GetCurrentThreadId();
|
||||
#else
|
||||
return 0; // not supported
|
||||
return 0; // not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -45,17 +45,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define INCLUDED_AI_DEFAULTPROGRESSHANDLER_H
|
||||
|
||||
#include "../include/assimp/ProgressHandler.hpp"
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** @brief Internal default implementation of the #ProgressHandler interface. */
|
||||
class DefaultProgressHandler
|
||||
: public ProgressHandler {
|
||||
: public ProgressHandler {
|
||||
|
||||
|
||||
virtual bool Update(float /*percentage*/) {
|
||||
return false;
|
||||
}
|
||||
virtual bool Update(float /*percentage*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}; // !class DefaultProgressHandler
|
||||
|
|
|
@ -40,10 +40,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// We need those constants, workaround for any platforms where nobody defined them yet
|
||||
#if (!defined SIZE_MAX)
|
||||
# define SIZE_MAX (~((size_t)0))
|
||||
# define SIZE_MAX (~((size_t)0))
|
||||
#endif
|
||||
|
||||
#if (!defined UINT_MAX)
|
||||
# define UINT_MAX (~((unsigned int)0))
|
||||
# define UINT_MAX (~((unsigned int)0))
|
||||
#endif
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using std::runtime_error;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable : 4275)
|
||||
# pragma warning(disable : 4275)
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -54,14 +54,14 @@ using std::runtime_error;
|
|||
* unrecoverable error occurs while importing. Loading APIs return
|
||||
* NULL instead of a valid aiScene then. */
|
||||
class DeadlyImportError
|
||||
: public runtime_error
|
||||
: public runtime_error
|
||||
{
|
||||
public:
|
||||
/** Constructor with arguments */
|
||||
explicit DeadlyImportError( const std::string& pErrorText)
|
||||
: runtime_error(pErrorText)
|
||||
{
|
||||
}
|
||||
/** Constructor with arguments */
|
||||
explicit DeadlyImportError( const std::string& pErrorText)
|
||||
: runtime_error(pErrorText)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
@ -69,57 +69,57 @@ private:
|
|||
typedef DeadlyImportError DeadlyExportError;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(default : 4275)
|
||||
# pragma warning(default : 4275)
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct ExceptionSwallower {
|
||||
T operator ()() const {
|
||||
return T();
|
||||
}
|
||||
struct ExceptionSwallower {
|
||||
T operator ()() const {
|
||||
return T();
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct ExceptionSwallower<T*> {
|
||||
T* operator ()() const {
|
||||
return NULL;
|
||||
}
|
||||
struct ExceptionSwallower<T*> {
|
||||
T* operator ()() const {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
template <>
|
||||
struct ExceptionSwallower<aiReturn> {
|
||||
aiReturn operator ()() const {
|
||||
try {
|
||||
throw;
|
||||
}
|
||||
catch (std::bad_alloc&) {
|
||||
return aiReturn_OUTOFMEMORY;
|
||||
}
|
||||
catch (...) {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
}
|
||||
struct ExceptionSwallower<aiReturn> {
|
||||
aiReturn operator ()() const {
|
||||
try {
|
||||
throw;
|
||||
}
|
||||
catch (std::bad_alloc&) {
|
||||
return aiReturn_OUTOFMEMORY;
|
||||
}
|
||||
catch (...) {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
template <>
|
||||
struct ExceptionSwallower<void> {
|
||||
void operator ()() const {
|
||||
return;
|
||||
}
|
||||
struct ExceptionSwallower<void> {
|
||||
void operator ()() const {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
#define ASSIMP_BEGIN_EXCEPTION_REGION()\
|
||||
{\
|
||||
try {
|
||||
try {
|
||||
|
||||
#define ASSIMP_END_EXCEPTION_REGION(type)\
|
||||
} catch(...) {\
|
||||
return ExceptionSwallower<type>()();\
|
||||
}\
|
||||
} catch(...) {\
|
||||
return ExceptionSwallower<type>()();\
|
||||
}\
|
||||
}
|
||||
|
||||
#endif // INCLUDED_EXCEPTIONAL_H
|
||||
|
|
|
@ -95,52 +95,52 @@ void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportPrope
|
|||
Exporter::ExportFormatEntry gExporters[] =
|
||||
{
|
||||
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
|
||||
Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
|
||||
Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_XFILE_EXPORTER
|
||||
Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
|
||||
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
|
||||
Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
|
||||
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
|
||||
Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0),
|
||||
Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */),
|
||||
Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
|
||||
Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
|
||||
Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
|
||||
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
|
||||
Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
|
||||
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||
Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
|
||||
Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
|
||||
Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0),
|
||||
Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -150,42 +150,42 @@ Exporter::ExportFormatEntry gExporters[] =
|
|||
class ExporterPimpl {
|
||||
public:
|
||||
|
||||
ExporterPimpl()
|
||||
: blob()
|
||||
, mIOSystem(new Assimp::DefaultIOSystem())
|
||||
, mIsDefaultIOHandler(true)
|
||||
{
|
||||
GetPostProcessingStepInstanceList(mPostProcessingSteps);
|
||||
ExporterPimpl()
|
||||
: blob()
|
||||
, mIOSystem(new Assimp::DefaultIOSystem())
|
||||
, mIsDefaultIOHandler(true)
|
||||
{
|
||||
GetPostProcessingStepInstanceList(mPostProcessingSteps);
|
||||
|
||||
// grab all builtin exporters
|
||||
mExporters.resize(ASSIMP_NUM_EXPORTERS);
|
||||
std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin());
|
||||
}
|
||||
// grab all builtin exporters
|
||||
mExporters.resize(ASSIMP_NUM_EXPORTERS);
|
||||
std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin());
|
||||
}
|
||||
|
||||
~ExporterPimpl()
|
||||
{
|
||||
delete blob;
|
||||
~ExporterPimpl()
|
||||
{
|
||||
delete blob;
|
||||
|
||||
// Delete all post-processing plug-ins
|
||||
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
|
||||
delete mPostProcessingSteps[a];
|
||||
}
|
||||
}
|
||||
// Delete all post-processing plug-ins
|
||||
for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
|
||||
delete mPostProcessingSteps[a];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
aiExportDataBlob* blob;
|
||||
boost::shared_ptr< Assimp::IOSystem > mIOSystem;
|
||||
bool mIsDefaultIOHandler;
|
||||
aiExportDataBlob* blob;
|
||||
boost::shared_ptr< Assimp::IOSystem > mIOSystem;
|
||||
bool mIsDefaultIOHandler;
|
||||
|
||||
/** Post processing steps we can apply at the imported data. */
|
||||
std::vector< BaseProcess* > mPostProcessingSteps;
|
||||
/** Post processing steps we can apply at the imported data. */
|
||||
std::vector< BaseProcess* > mPostProcessingSteps;
|
||||
|
||||
/** Last fatal export error */
|
||||
std::string mError;
|
||||
/** Last fatal export error */
|
||||
std::string mError;
|
||||
|
||||
/** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
|
||||
std::vector<Exporter::ExportFormatEntry> mExporters;
|
||||
/** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
|
||||
std::vector<Exporter::ExportFormatEntry> mExporters;
|
||||
};
|
||||
|
||||
|
||||
|
@ -208,306 +208,306 @@ Exporter :: Exporter()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
Exporter :: ~Exporter()
|
||||
{
|
||||
FreeBlob();
|
||||
FreeBlob();
|
||||
|
||||
delete pimpl;
|
||||
delete pimpl;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter :: SetIOHandler( IOSystem* pIOHandler)
|
||||
{
|
||||
pimpl->mIsDefaultIOHandler = !pIOHandler;
|
||||
pimpl->mIOSystem.reset(pIOHandler);
|
||||
pimpl->mIsDefaultIOHandler = !pIOHandler;
|
||||
pimpl->mIOSystem.reset(pIOHandler);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IOSystem* Exporter :: GetIOHandler() const
|
||||
{
|
||||
return pimpl->mIOSystem.get();
|
||||
return pimpl->mIOSystem.get();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Exporter :: IsDefaultIOHandler() const
|
||||
{
|
||||
return pimpl->mIsDefaultIOHandler;
|
||||
return pimpl->mIsDefaultIOHandler;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter :: ExportToBlob( const aiScene* pScene, const char* pFormatId, unsigned int, const ExportProperties* pProperties)
|
||||
{
|
||||
if (pimpl->blob) {
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = NULL;
|
||||
}
|
||||
if (pimpl->blob) {
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = NULL;
|
||||
}
|
||||
|
||||
|
||||
boost::shared_ptr<IOSystem> old = pimpl->mIOSystem;
|
||||
boost::shared_ptr<IOSystem> old = pimpl->mIOSystem;
|
||||
|
||||
BlobIOSystem* blobio = new BlobIOSystem();
|
||||
pimpl->mIOSystem = boost::shared_ptr<IOSystem>( blobio );
|
||||
BlobIOSystem* blobio = new BlobIOSystem();
|
||||
pimpl->mIOSystem = boost::shared_ptr<IOSystem>( blobio );
|
||||
|
||||
if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
|
||||
pimpl->mIOSystem = old;
|
||||
return NULL;
|
||||
}
|
||||
if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
|
||||
pimpl->mIOSystem = old;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pimpl->blob = blobio->GetBlobChain();
|
||||
pimpl->mIOSystem = old;
|
||||
pimpl->blob = blobio->GetBlobChain();
|
||||
pimpl->mIOSystem = old;
|
||||
|
||||
return pimpl->blob;
|
||||
return pimpl->blob;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IsVerboseFormat(const aiMesh* mesh)
|
||||
{
|
||||
// avoid slow vector<bool> specialization
|
||||
std::vector<unsigned int> seen(mesh->mNumVertices,0);
|
||||
for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||
const aiFace& f = mesh->mFaces[i];
|
||||
for(unsigned int j = 0; j < f.mNumIndices; ++j) {
|
||||
if(++seen[f.mIndices[j]] == 2) {
|
||||
// found a duplicate index
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
// avoid slow vector<bool> specialization
|
||||
std::vector<unsigned int> seen(mesh->mNumVertices,0);
|
||||
for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||
const aiFace& f = mesh->mFaces[i];
|
||||
for(unsigned int j = 0; j < f.mNumIndices; ++j) {
|
||||
if(++seen[f.mIndices[j]] == 2) {
|
||||
// found a duplicate index
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IsVerboseFormat(const aiScene* pScene)
|
||||
{
|
||||
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
if(!IsVerboseFormat(pScene->mMeshes[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
if(!IsVerboseFormat(pScene->mMeshes[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties)
|
||||
{
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// when they create scenes from scratch, users will likely create them not in verbose
|
||||
// format. They will likely not be aware that there is a flag in the scene to indicate
|
||||
// this, however. To avoid surprises and bug reports, we check for duplicates in
|
||||
// meshes upfront.
|
||||
const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);
|
||||
// when they create scenes from scratch, users will likely create them not in verbose
|
||||
// format. They will likely not be aware that there is a flag in the scene to indicate
|
||||
// this, however. To avoid surprises and bug reports, we check for duplicates in
|
||||
// meshes upfront.
|
||||
const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);
|
||||
|
||||
pimpl->mError = "";
|
||||
for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
|
||||
const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
|
||||
if (!strcmp(exp.mDescription.id,pFormatId)) {
|
||||
pimpl->mError = "";
|
||||
for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
|
||||
const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
|
||||
if (!strcmp(exp.mDescription.id,pFormatId)) {
|
||||
|
||||
try {
|
||||
try {
|
||||
|
||||
// Always create a full copy of the scene. We might optimize this one day,
|
||||
// but for now it is the most pragmatic way.
|
||||
aiScene* scenecopy_tmp;
|
||||
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
|
||||
// Always create a full copy of the scene. We might optimize this one day,
|
||||
// but for now it is the most pragmatic way.
|
||||
aiScene* scenecopy_tmp;
|
||||
SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
|
||||
|
||||
std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
|
||||
const ScenePrivateData* const priv = ScenePriv(pScene);
|
||||
std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
|
||||
const ScenePrivateData* const priv = ScenePriv(pScene);
|
||||
|
||||
// steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
|
||||
// original state before the step was applied first. When checking which steps we don't need
|
||||
// to run, those are excluded.
|
||||
const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
|
||||
// steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
|
||||
// original state before the step was applied first. When checking which steps we don't need
|
||||
// to run, those are excluded.
|
||||
const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
|
||||
|
||||
// Erase all pp steps that were already applied to this scene
|
||||
const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
|
||||
? (priv->mPPStepsApplied & ~nonIdempotentSteps)
|
||||
: 0u);
|
||||
// Erase all pp steps that were already applied to this scene
|
||||
const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
|
||||
? (priv->mPPStepsApplied & ~nonIdempotentSteps)
|
||||
: 0u);
|
||||
|
||||
// If no extra postprocessing was specified, and we obtained this scene from an
|
||||
// Assimp importer, apply the reverse steps automatically.
|
||||
// TODO: either drop this, or document it. Otherwise it is just a bad surprise.
|
||||
//if (!pPreprocessing && priv) {
|
||||
// pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
|
||||
//}
|
||||
// If no extra postprocessing was specified, and we obtained this scene from an
|
||||
// Assimp importer, apply the reverse steps automatically.
|
||||
// TODO: either drop this, or document it. Otherwise it is just a bad surprise.
|
||||
//if (!pPreprocessing && priv) {
|
||||
// pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
|
||||
//}
|
||||
|
||||
// If the input scene is not in verbose format, but there is at least postprocessing step that relies on it,
|
||||
// we need to run the MakeVerboseFormat step first.
|
||||
bool must_join_again = false;
|
||||
if (!is_verbose_format) {
|
||||
// If the input scene is not in verbose format, but there is at least postprocessing step that relies on it,
|
||||
// we need to run the MakeVerboseFormat step first.
|
||||
bool must_join_again = false;
|
||||
if (!is_verbose_format) {
|
||||
|
||||
bool verbosify = false;
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||
BaseProcess* const p = pimpl->mPostProcessingSteps[a];
|
||||
bool verbosify = false;
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||
BaseProcess* const p = pimpl->mPostProcessingSteps[a];
|
||||
|
||||
if (p->IsActive(pp) && p->RequireVerboseFormat()) {
|
||||
verbosify = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p->IsActive(pp) && p->RequireVerboseFormat()) {
|
||||
verbosify = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
|
||||
DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
|
||||
if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
|
||||
DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
|
||||
|
||||
MakeVerboseFormatProcess proc;
|
||||
proc.Execute(scenecopy.get());
|
||||
MakeVerboseFormatProcess proc;
|
||||
proc.Execute(scenecopy.get());
|
||||
|
||||
if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
|
||||
must_join_again = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
|
||||
must_join_again = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pp) {
|
||||
// the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
|
||||
{
|
||||
FlipWindingOrderProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
if (pp) {
|
||||
// the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
|
||||
{
|
||||
FlipWindingOrderProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
FlipUVsProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
{
|
||||
FlipUVsProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MakeLeftHandedProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
{
|
||||
MakeLeftHandedProcess step;
|
||||
if (step.IsActive(pp)) {
|
||||
step.Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch other processes
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||
BaseProcess* const p = pimpl->mPostProcessingSteps[a];
|
||||
// dispatch other processes
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||
BaseProcess* const p = pimpl->mPostProcessingSteps[a];
|
||||
|
||||
if (p->IsActive(pp)
|
||||
&& !dynamic_cast<FlipUVsProcess*>(p)
|
||||
&& !dynamic_cast<FlipWindingOrderProcess*>(p)
|
||||
&& !dynamic_cast<MakeLeftHandedProcess*>(p)) {
|
||||
if (p->IsActive(pp)
|
||||
&& !dynamic_cast<FlipUVsProcess*>(p)
|
||||
&& !dynamic_cast<FlipWindingOrderProcess*>(p)
|
||||
&& !dynamic_cast<MakeLeftHandedProcess*>(p)) {
|
||||
|
||||
p->Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
|
||||
ai_assert(privOut);
|
||||
p->Execute(scenecopy.get());
|
||||
}
|
||||
}
|
||||
ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
|
||||
ai_assert(privOut);
|
||||
|
||||
privOut->mPPStepsApplied |= pp;
|
||||
}
|
||||
privOut->mPPStepsApplied |= pp;
|
||||
}
|
||||
|
||||
if(must_join_again) {
|
||||
JoinVerticesProcess proc;
|
||||
proc.Execute(scenecopy.get());
|
||||
}
|
||||
if(must_join_again) {
|
||||
JoinVerticesProcess proc;
|
||||
proc.Execute(scenecopy.get());
|
||||
}
|
||||
|
||||
ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry.
|
||||
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties);
|
||||
}
|
||||
catch (DeadlyExportError& err) {
|
||||
pimpl->mError = err.what();
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
}
|
||||
ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry.
|
||||
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties);
|
||||
}
|
||||
catch (DeadlyExportError& err) {
|
||||
pimpl->mError = err.what();
|
||||
return AI_FAILURE;
|
||||
}
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
return AI_FAILURE;
|
||||
pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char* Exporter :: GetErrorString() const
|
||||
{
|
||||
return pimpl->mError.c_str();
|
||||
return pimpl->mError.c_str();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter :: FreeBlob( )
|
||||
{
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = NULL;
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = NULL;
|
||||
|
||||
pimpl->mError = "";
|
||||
pimpl->mError = "";
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter :: GetBlob() const
|
||||
{
|
||||
return pimpl->blob;
|
||||
return pimpl->blob;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter :: GetOrphanedBlob() const
|
||||
{
|
||||
const aiExportDataBlob* tmp = pimpl->blob;
|
||||
pimpl->blob = NULL;
|
||||
return tmp;
|
||||
const aiExportDataBlob* tmp = pimpl->blob;
|
||||
pimpl->blob = NULL;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Exporter :: GetExportFormatCount() const
|
||||
{
|
||||
return pimpl->mExporters.size();
|
||||
return pimpl->mExporters.size();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportFormatDesc* Exporter :: GetExportFormatDescription( size_t pIndex ) const
|
||||
{
|
||||
if (pIndex >= GetExportFormatCount()) {
|
||||
return NULL;
|
||||
}
|
||||
if (pIndex >= GetExportFormatCount()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return from static storage if the requested index is built-in.
|
||||
if (pIndex < sizeof(gExporters) / sizeof(gExporters[0])) {
|
||||
return &gExporters[pIndex].mDescription;
|
||||
}
|
||||
// Return from static storage if the requested index is built-in.
|
||||
if (pIndex < sizeof(gExporters) / sizeof(gExporters[0])) {
|
||||
return &gExporters[pIndex].mDescription;
|
||||
}
|
||||
|
||||
return &pimpl->mExporters[pIndex].mDescription;
|
||||
return &pimpl->mExporters[pIndex].mDescription;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn Exporter :: RegisterExporter(const ExportFormatEntry& desc)
|
||||
{
|
||||
BOOST_FOREACH(const ExportFormatEntry& e, pimpl->mExporters) {
|
||||
if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const ExportFormatEntry& e, pimpl->mExporters) {
|
||||
if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
pimpl->mExporters.push_back(desc);
|
||||
return aiReturn_SUCCESS;
|
||||
pimpl->mExporters.push_back(desc);
|
||||
return aiReturn_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter :: UnregisterExporter(const char* id)
|
||||
{
|
||||
for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) {
|
||||
if (!strcmp((*it).mDescription.id,id)) {
|
||||
pimpl->mExporters.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) {
|
||||
if (!strcmp((*it).mDescription.id,id)) {
|
||||
pimpl->mExporters.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExportProperties :: ExportProperties() {}
|
||||
|
||||
ExportProperties::ExportProperties(const ExportProperties &other)
|
||||
: mIntProperties(other.mIntProperties),
|
||||
: mIntProperties(other.mIntProperties),
|
||||
mFloatProperties(other.mFloatProperties),
|
||||
mStringProperties(other.mStringProperties),
|
||||
mMatrixProperties(other.mMatrixProperties)
|
||||
|
@ -520,95 +520,95 @@ ExportProperties::ExportProperties(const ExportProperties &other)
|
|||
// Set a configuration property
|
||||
bool ExportProperties :: SetPropertyInteger(const char* szName, int iValue)
|
||||
{
|
||||
return SetGenericProperty<int>(mIntProperties, szName,iValue);
|
||||
return SetGenericProperty<int>(mIntProperties, szName,iValue);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool ExportProperties :: SetPropertyFloat(const char* szName, float iValue)
|
||||
{
|
||||
return SetGenericProperty<float>(mFloatProperties, szName,iValue);
|
||||
return SetGenericProperty<float>(mFloatProperties, szName,iValue);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool ExportProperties :: SetPropertyString(const char* szName, const std::string& value)
|
||||
{
|
||||
return SetGenericProperty<std::string>(mStringProperties, szName,value);
|
||||
return SetGenericProperty<std::string>(mStringProperties, szName,value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool ExportProperties :: SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
|
||||
{
|
||||
return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
|
||||
return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
int ExportProperties :: GetPropertyInteger(const char* szName,
|
||||
int iErrorReturn /*= 0xffffffff*/) const
|
||||
int iErrorReturn /*= 0xffffffff*/) const
|
||||
{
|
||||
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
|
||||
return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
float ExportProperties :: GetPropertyFloat(const char* szName,
|
||||
float iErrorReturn /*= 10e10*/) const
|
||||
float iErrorReturn /*= 10e10*/) const
|
||||
{
|
||||
return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
|
||||
return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
const std::string ExportProperties :: GetPropertyString(const char* szName,
|
||||
const std::string& iErrorReturn /*= ""*/) const
|
||||
const std::string& iErrorReturn /*= ""*/) const
|
||||
{
|
||||
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
|
||||
return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
const aiMatrix4x4 ExportProperties :: GetPropertyMatrix(const char* szName,
|
||||
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
|
||||
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
|
||||
{
|
||||
return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
|
||||
return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties :: HasPropertyInteger(const char* szName) const
|
||||
{
|
||||
return HasGenericProperty<int>(mIntProperties, szName);
|
||||
return HasGenericProperty<int>(mIntProperties, szName);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties :: HasPropertyBool(const char* szName) const
|
||||
{
|
||||
return HasGenericProperty<int>(mIntProperties, szName);
|
||||
return HasGenericProperty<int>(mIntProperties, szName);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties :: HasPropertyFloat(const char* szName) const
|
||||
{
|
||||
return HasGenericProperty<float>(mFloatProperties, szName);
|
||||
return HasGenericProperty<float>(mFloatProperties, szName);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties :: HasPropertyString(const char* szName) const
|
||||
{
|
||||
return HasGenericProperty<std::string>(mStringProperties, szName);
|
||||
return HasGenericProperty<std::string>(mStringProperties, szName);
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Has a configuration property
|
||||
bool ExportProperties :: HasPropertyMatrix(const char* szName) const
|
||||
{
|
||||
return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
|
||||
return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -56,37 +56,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
|
||||
: Object(id, element, name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
|
||||
const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
|
||||
const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
|
||||
|
||||
ParseVectorDataArray(keys, KeyTime);
|
||||
ParseVectorDataArray(values, KeyValueFloat);
|
||||
ParseVectorDataArray(keys, KeyTime);
|
||||
ParseVectorDataArray(values, KeyValueFloat);
|
||||
|
||||
if(keys.size() != values.size()) {
|
||||
DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
|
||||
}
|
||||
if(keys.size() != values.size()) {
|
||||
DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
|
||||
}
|
||||
|
||||
// check if the key times are well-ordered
|
||||
if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
|
||||
DOMError("the keyframes are not in ascending order",&KeyTime);
|
||||
}
|
||||
// check if the key times are well-ordered
|
||||
if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
|
||||
DOMError("the keyframes are not in ascending order",&KeyTime);
|
||||
}
|
||||
|
||||
const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
|
||||
if(KeyAttrDataFloat) {
|
||||
ParseVectorDataArray(attributes, *KeyAttrDataFloat);
|
||||
}
|
||||
const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
|
||||
if(KeyAttrDataFloat) {
|
||||
ParseVectorDataArray(attributes, *KeyAttrDataFloat);
|
||||
}
|
||||
|
||||
const Element* KeyAttrFlags = sc["KeyAttrFlags"];
|
||||
if(KeyAttrFlags) {
|
||||
ParseVectorDataArray(flags, *KeyAttrFlags);
|
||||
}
|
||||
const Element* KeyAttrFlags = sc["KeyAttrFlags"];
|
||||
if(KeyAttrFlags) {
|
||||
ParseVectorDataArray(flags, *KeyAttrFlags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,61 +99,61 @@ AnimationCurve::~AnimationCurve()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
|
||||
const char* const * target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/)
|
||||
const char* const * target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/)
|
||||
: Object(id, element, name)
|
||||
, target()
|
||||
, doc(doc)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
// find target node
|
||||
const char* whitelist[] = {"Model","NodeAttribute"};
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,2);
|
||||
// find target node
|
||||
const char* whitelist[] = {"Model","NodeAttribute"};
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,2);
|
||||
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(target_prop_whitelist) {
|
||||
const char* const s = con->PropertyName().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(target_prop_whitelist) {
|
||||
const char* const s = con->PropertyName().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
throw std::range_error("AnimationCurveNode target property is not in whitelist");
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
throw std::range_error("AnimationCurveNode target property is not in whitelist");
|
||||
}
|
||||
}
|
||||
|
||||
const Object* const ob = con->DestinationObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const Object* const ob = con->DestinationObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
// XXX support constraints as DOM class
|
||||
//ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
|
||||
target = ob;
|
||||
if(!target) {
|
||||
continue;
|
||||
}
|
||||
// XXX support constraints as DOM class
|
||||
//ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
|
||||
target = ob;
|
||||
if(!target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
prop = con->PropertyName();
|
||||
break;
|
||||
}
|
||||
prop = con->PropertyName();
|
||||
break;
|
||||
}
|
||||
|
||||
if(!target) {
|
||||
DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
|
||||
}
|
||||
if(!target) {
|
||||
DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
|
||||
props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -167,34 +167,34 @@ AnimationCurveNode::~AnimationCurveNode()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
const AnimationCurveMap& AnimationCurveNode::Curves() const
|
||||
{
|
||||
if(curves.empty()) {
|
||||
// resolve attached animation curves
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
|
||||
if(curves.empty()) {
|
||||
// resolve attached animation curves
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
|
||||
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
// link should go for a property
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
|
||||
continue;
|
||||
}
|
||||
const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
curves[con->PropertyName()] = anim;
|
||||
}
|
||||
}
|
||||
curves[con->PropertyName()] = anim;
|
||||
}
|
||||
}
|
||||
|
||||
return curves;
|
||||
return curves;
|
||||
}
|
||||
|
||||
|
||||
|
@ -203,10 +203,10 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::s
|
|||
: Object(id, element, name)
|
||||
, doc(doc)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
// note: the props table here bears little importance and is usually absent
|
||||
props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
|
||||
// note: the props table here bears little importance and is usually absent
|
||||
props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -219,85 +219,85 @@ AnimationLayer::~AnimationLayer()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/,
|
||||
size_t whitelist_size /*= 0*/) const
|
||||
size_t whitelist_size /*= 0*/) const
|
||||
{
|
||||
AnimationCurveNodeList nodes;
|
||||
AnimationCurveNodeList nodes;
|
||||
|
||||
// resolve attached animation nodes
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
|
||||
nodes.reserve(conns.size());
|
||||
// resolve attached animation nodes
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
|
||||
nodes.reserve(conns.size());
|
||||
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
|
||||
continue;
|
||||
}
|
||||
const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(target_prop_whitelist) {
|
||||
const char* s = anim->TargetProperty().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ok) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodes.push_back(anim);
|
||||
}
|
||||
if(target_prop_whitelist) {
|
||||
const char* s = anim->TargetProperty().c_str();
|
||||
bool ok = false;
|
||||
for (size_t i = 0; i < whitelist_size; ++i) {
|
||||
if (!strcmp(s, target_prop_whitelist[i])) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ok) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nodes.push_back(anim);
|
||||
}
|
||||
|
||||
return nodes; // pray for NRVO
|
||||
return nodes; // pray for NRVO
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Object(id, element, name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
// note: we don't currently use any of these properties so we shouldn't bother if it is missing
|
||||
props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
|
||||
// note: we don't currently use any of these properties so we shouldn't bother if it is missing
|
||||
props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
|
||||
|
||||
// resolve attached animation layers
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
|
||||
layers.reserve(conns.size());
|
||||
// resolve attached animation layers
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
|
||||
layers.reserve(conns.size());
|
||||
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
// link should not go to a property
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
|
||||
continue;
|
||||
}
|
||||
layers.push_back(anim);
|
||||
}
|
||||
const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
|
||||
continue;
|
||||
}
|
||||
layers.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,22 +58,22 @@ namespace FBX {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset)
|
||||
:
|
||||
#ifdef DEBUG
|
||||
contents(sbegin, static_cast<size_t>(send-sbegin)),
|
||||
#endif
|
||||
sbegin(sbegin)
|
||||
, send(send)
|
||||
, type(type)
|
||||
, line(offset)
|
||||
, column(BINARY_MARKER)
|
||||
:
|
||||
#ifdef DEBUG
|
||||
contents(sbegin, static_cast<size_t>(send-sbegin)),
|
||||
#endif
|
||||
sbegin(sbegin)
|
||||
, send(send)
|
||||
, type(type)
|
||||
, line(offset)
|
||||
, column(BINARY_MARKER)
|
||||
{
|
||||
ai_assert(sbegin);
|
||||
ai_assert(send);
|
||||
ai_assert(sbegin);
|
||||
ai_assert(send);
|
||||
|
||||
// binary tokens may have zero length because they are sometimes dummies
|
||||
// inserted by TokenizeBinary()
|
||||
ai_assert(send >= sbegin);
|
||||
// binary tokens may have zero length because they are sometimes dummies
|
||||
// inserted by TokenizeBinary()
|
||||
ai_assert(send >= sbegin);
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,85 +84,85 @@ namespace {
|
|||
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset) AI_WONT_RETURN_SUFFIX;
|
||||
AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset)
|
||||
{
|
||||
throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
|
||||
throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t Offset(const char* begin, const char* cursor)
|
||||
{
|
||||
ai_assert(begin <= cursor);
|
||||
return static_cast<unsigned int>(cursor - begin);
|
||||
ai_assert(begin <= cursor);
|
||||
return static_cast<unsigned int>(cursor - begin);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeError(const std::string& message, const char* begin, const char* cursor)
|
||||
{
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
TokenizeError(message, Offset(begin, cursor));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint32_t ReadWord(const char* input, const char*& cursor, const char* end)
|
||||
{
|
||||
if(Offset(cursor, end) < 4) {
|
||||
TokenizeError("cannot ReadWord, out of bounds",input, cursor);
|
||||
}
|
||||
if(Offset(cursor, end) < 4) {
|
||||
TokenizeError("cannot ReadWord, out of bounds",input, cursor);
|
||||
}
|
||||
|
||||
uint32_t word = *reinterpret_cast<const uint32_t*>(cursor);
|
||||
AI_SWAP4(word);
|
||||
uint32_t word = *reinterpret_cast<const uint32_t*>(cursor);
|
||||
AI_SWAP4(word);
|
||||
|
||||
cursor += 4;
|
||||
cursor += 4;
|
||||
|
||||
return word;
|
||||
return word;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
uint8_t ReadByte(const char* input, const char*& cursor, const char* end)
|
||||
{
|
||||
if(Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadByte, out of bounds",input, cursor);
|
||||
}
|
||||
if(Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadByte, out of bounds",input, cursor);
|
||||
}
|
||||
|
||||
uint8_t word = *reinterpret_cast<const uint8_t*>(cursor);
|
||||
++cursor;
|
||||
uint8_t word = *reinterpret_cast<const uint8_t*>(cursor);
|
||||
++cursor;
|
||||
|
||||
return word;
|
||||
return word;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end,
|
||||
bool long_length = false,
|
||||
bool allow_null = false)
|
||||
bool long_length = false,
|
||||
bool allow_null = false)
|
||||
{
|
||||
const uint32_t len_len = long_length ? 4 : 1;
|
||||
if(Offset(cursor, end) < len_len) {
|
||||
TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
|
||||
}
|
||||
const uint32_t len_len = long_length ? 4 : 1;
|
||||
if(Offset(cursor, end) < len_len) {
|
||||
TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
|
||||
}
|
||||
|
||||
const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
|
||||
const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
|
||||
|
||||
if (Offset(cursor, end) < length) {
|
||||
TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
|
||||
}
|
||||
if (Offset(cursor, end) < length) {
|
||||
TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
|
||||
}
|
||||
|
||||
sbegin_out = cursor;
|
||||
cursor += length;
|
||||
sbegin_out = cursor;
|
||||
cursor += length;
|
||||
|
||||
send_out = cursor;
|
||||
send_out = cursor;
|
||||
|
||||
if(!allow_null) {
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
if(sbegin_out[i] == '\0') {
|
||||
TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!allow_null) {
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
if(sbegin_out[i] == '\0') {
|
||||
TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
|
@ -170,203 +170,203 @@ unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const ch
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end)
|
||||
{
|
||||
if(Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
|
||||
}
|
||||
if(Offset(cursor, end) < 1) {
|
||||
TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
|
||||
}
|
||||
|
||||
const char type = *cursor;
|
||||
sbegin_out = cursor++;
|
||||
const char type = *cursor;
|
||||
sbegin_out = cursor++;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
// 16 bit int
|
||||
case 'Y':
|
||||
cursor += 2;
|
||||
break;
|
||||
switch(type)
|
||||
{
|
||||
// 16 bit int
|
||||
case 'Y':
|
||||
cursor += 2;
|
||||
break;
|
||||
|
||||
// 1 bit bool flag (yes/no)
|
||||
case 'C':
|
||||
cursor += 1;
|
||||
break;
|
||||
// 1 bit bool flag (yes/no)
|
||||
case 'C':
|
||||
cursor += 1;
|
||||
break;
|
||||
|
||||
// 32 bit int
|
||||
case 'I':
|
||||
// <- fall thru
|
||||
// 32 bit int
|
||||
case 'I':
|
||||
// <- fall thru
|
||||
|
||||
// float
|
||||
case 'F':
|
||||
cursor += 4;
|
||||
break;
|
||||
// float
|
||||
case 'F':
|
||||
cursor += 4;
|
||||
break;
|
||||
|
||||
// double
|
||||
case 'D':
|
||||
cursor += 8;
|
||||
break;
|
||||
// double
|
||||
case 'D':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// 64 bit int
|
||||
case 'L':
|
||||
cursor += 8;
|
||||
break;
|
||||
// 64 bit int
|
||||
case 'L':
|
||||
cursor += 8;
|
||||
break;
|
||||
|
||||
// note: do not write cursor += ReadWord(...cursor) as this would be UB
|
||||
// note: do not write cursor += ReadWord(...cursor) as this would be UB
|
||||
|
||||
// raw binary data
|
||||
case 'R':
|
||||
{
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
cursor += length;
|
||||
break;
|
||||
}
|
||||
// raw binary data
|
||||
case 'R':
|
||||
{
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
cursor += length;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b':
|
||||
// TODO: what is the 'b' type code? Right now we just skip over it /
|
||||
// take the full range we could get
|
||||
cursor = end;
|
||||
break;
|
||||
case 'b':
|
||||
// TODO: what is the 'b' type code? Right now we just skip over it /
|
||||
// take the full range we could get
|
||||
cursor = end;
|
||||
break;
|
||||
|
||||
// array of *
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'l':
|
||||
case 'i': {
|
||||
// array of *
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'l':
|
||||
case 'i': {
|
||||
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
const uint32_t encoding = ReadWord(input, cursor, end);
|
||||
const uint32_t length = ReadWord(input, cursor, end);
|
||||
const uint32_t encoding = ReadWord(input, cursor, end);
|
||||
|
||||
const uint32_t comp_len = ReadWord(input, cursor, end);
|
||||
const uint32_t comp_len = ReadWord(input, cursor, end);
|
||||
|
||||
// compute length based on type and check against the stored value
|
||||
if(encoding == 0) {
|
||||
uint32_t stride = 0;
|
||||
switch(type)
|
||||
{
|
||||
case 'f':
|
||||
case 'i':
|
||||
stride = 4;
|
||||
break;
|
||||
// compute length based on type and check against the stored value
|
||||
if(encoding == 0) {
|
||||
uint32_t stride = 0;
|
||||
switch(type)
|
||||
{
|
||||
case 'f':
|
||||
case 'i':
|
||||
stride = 4;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'l':
|
||||
stride = 8;
|
||||
break;
|
||||
case 'd':
|
||||
case 'l':
|
||||
stride = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
ai_assert(false);
|
||||
};
|
||||
default:
|
||||
ai_assert(false);
|
||||
};
|
||||
ai_assert(stride > 0);
|
||||
if(length * stride != comp_len) {
|
||||
TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
|
||||
}
|
||||
}
|
||||
// zip/deflate algorithm (encoding==1)? take given length. anything else? die
|
||||
else if (encoding != 1) {
|
||||
TokenizeError("cannot ReadData, unknown encoding",input, cursor);
|
||||
}
|
||||
cursor += comp_len;
|
||||
break;
|
||||
}
|
||||
if(length * stride != comp_len) {
|
||||
TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
|
||||
}
|
||||
}
|
||||
// zip/deflate algorithm (encoding==1)? take given length. anything else? die
|
||||
else if (encoding != 1) {
|
||||
TokenizeError("cannot ReadData, unknown encoding",input, cursor);
|
||||
}
|
||||
cursor += comp_len;
|
||||
break;
|
||||
}
|
||||
|
||||
// string
|
||||
case 'S': {
|
||||
const char* sb, *se;
|
||||
// 0 characters can legally happen in such strings
|
||||
ReadString(sb, se, input, cursor, end, true, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
|
||||
}
|
||||
// string
|
||||
case 'S': {
|
||||
const char* sb, *se;
|
||||
// 0 characters can legally happen in such strings
|
||||
ReadString(sb, se, input, cursor, end, true, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
|
||||
}
|
||||
|
||||
if(cursor > end) {
|
||||
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor);
|
||||
}
|
||||
if(cursor > end) {
|
||||
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor);
|
||||
}
|
||||
|
||||
// the type code is contained in the returned range
|
||||
send_out = cursor;
|
||||
// the type code is contained in the returned range
|
||||
send_out = cursor;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end)
|
||||
{
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint32_t end_offset = ReadWord(input, cursor, end);
|
||||
// the first word contains the offset at which this block ends
|
||||
const uint32_t end_offset = ReadWord(input, cursor, end);
|
||||
|
||||
// we may get 0 if reading reached the end of the file -
|
||||
// fbx files have a mysterious extra footer which I don't know
|
||||
// how to extract any information from, but at least it always
|
||||
// starts with a 0.
|
||||
if(!end_offset) {
|
||||
return false;
|
||||
}
|
||||
// we may get 0 if reading reached the end of the file -
|
||||
// fbx files have a mysterious extra footer which I don't know
|
||||
// how to extract any information from, but at least it always
|
||||
// starts with a 0.
|
||||
if(!end_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(end_offset > Offset(input, end)) {
|
||||
TokenizeError("block offset is out of range",input, cursor);
|
||||
}
|
||||
else if(end_offset < Offset(input, cursor)) {
|
||||
TokenizeError("block offset is negative out of range",input, cursor);
|
||||
}
|
||||
if(end_offset > Offset(input, end)) {
|
||||
TokenizeError("block offset is out of range",input, cursor);
|
||||
}
|
||||
else if(end_offset < Offset(input, cursor)) {
|
||||
TokenizeError("block offset is negative out of range",input, cursor);
|
||||
}
|
||||
|
||||
// the second data word contains the number of properties in the scope
|
||||
const uint32_t prop_count = ReadWord(input, cursor, end);
|
||||
// the second data word contains the number of properties in the scope
|
||||
const uint32_t prop_count = ReadWord(input, cursor, end);
|
||||
|
||||
// the third data word contains the length of the property list
|
||||
const uint32_t prop_length = ReadWord(input, cursor, end);
|
||||
// the third data word contains the length of the property list
|
||||
const uint32_t prop_length = ReadWord(input, cursor, end);
|
||||
|
||||
// now comes the name of the scope/key
|
||||
const char* sbeg, *send;
|
||||
ReadString(sbeg, send, input, cursor, end);
|
||||
// now comes the name of the scope/key
|
||||
const char* sbeg, *send;
|
||||
ReadString(sbeg, send, input, cursor, end);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
|
||||
|
||||
// now come the individual properties
|
||||
const char* begin_cursor = cursor;
|
||||
for (unsigned int i = 0; i < prop_count; ++i) {
|
||||
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
|
||||
// now come the individual properties
|
||||
const char* begin_cursor = cursor;
|
||||
for (unsigned int i = 0; i < prop_count; ++i) {
|
||||
ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
|
||||
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
|
||||
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
|
||||
|
||||
if(i != prop_count-1) {
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
|
||||
}
|
||||
}
|
||||
if(i != prop_count-1) {
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
|
||||
}
|
||||
}
|
||||
|
||||
if (Offset(begin_cursor, cursor) != prop_length) {
|
||||
TokenizeError("property length not reached, something is wrong",input, cursor);
|
||||
}
|
||||
if (Offset(begin_cursor, cursor) != prop_length) {
|
||||
TokenizeError("property length not reached, something is wrong",input, cursor);
|
||||
}
|
||||
|
||||
// at the end of each nested block, there is a NUL record to indicate
|
||||
// that the sub-scope exists (i.e. to distinguish between P: and P : {})
|
||||
// this NUL record is 13 bytes long.
|
||||
// at the end of each nested block, there is a NUL record to indicate
|
||||
// that the sub-scope exists (i.e. to distinguish between P: and P : {})
|
||||
// this NUL record is 13 bytes long.
|
||||
#define BLOCK_SENTINEL_LENGTH 13
|
||||
|
||||
if (Offset(input, cursor) < end_offset) {
|
||||
if (Offset(input, cursor) < end_offset) {
|
||||
|
||||
if (end_offset - Offset(input, cursor) < BLOCK_SENTINEL_LENGTH) {
|
||||
TokenizeError("insufficient padding bytes at block end",input, cursor);
|
||||
}
|
||||
if (end_offset - Offset(input, cursor) < BLOCK_SENTINEL_LENGTH) {
|
||||
TokenizeError("insufficient padding bytes at block end",input, cursor);
|
||||
}
|
||||
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
|
||||
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while(Offset(input, cursor) < end_offset - BLOCK_SENTINEL_LENGTH) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - BLOCK_SENTINEL_LENGTH);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
|
||||
// XXX this is vulnerable to stack overflowing ..
|
||||
while(Offset(input, cursor) < end_offset - BLOCK_SENTINEL_LENGTH) {
|
||||
ReadScope(output_tokens, input, cursor, input + end_offset - BLOCK_SENTINEL_LENGTH);
|
||||
}
|
||||
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
|
||||
|
||||
for (unsigned int i = 0; i < BLOCK_SENTINEL_LENGTH; ++i) {
|
||||
if(cursor[i] != '\0') {
|
||||
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
|
||||
}
|
||||
}
|
||||
cursor += BLOCK_SENTINEL_LENGTH;
|
||||
}
|
||||
for (unsigned int i = 0; i < BLOCK_SENTINEL_LENGTH; ++i) {
|
||||
if(cursor[i] != '\0') {
|
||||
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
|
||||
}
|
||||
}
|
||||
cursor += BLOCK_SENTINEL_LENGTH;
|
||||
}
|
||||
|
||||
if (Offset(input, cursor) != end_offset) {
|
||||
TokenizeError("scope length not reached, something is wrong",input, cursor);
|
||||
}
|
||||
if (Offset(input, cursor) != end_offset) {
|
||||
TokenizeError("scope length not reached, something is wrong",input, cursor);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -375,26 +375,26 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length)
|
||||
{
|
||||
ai_assert(input);
|
||||
ai_assert(input);
|
||||
|
||||
if(length < 0x1b) {
|
||||
TokenizeError("file is too short",0);
|
||||
}
|
||||
if(length < 0x1b) {
|
||||
TokenizeError("file is too short",0);
|
||||
}
|
||||
|
||||
if (strncmp(input,"Kaydara FBX Binary",18)) {
|
||||
TokenizeError("magic bytes not found",0);
|
||||
}
|
||||
if (strncmp(input,"Kaydara FBX Binary",18)) {
|
||||
TokenizeError("magic bytes not found",0);
|
||||
}
|
||||
|
||||
|
||||
//uint32_t offset = 0x1b;
|
||||
//uint32_t offset = 0x1b;
|
||||
|
||||
const char* cursor = input + 0x1b;
|
||||
const char* cursor = input + 0x1b;
|
||||
|
||||
while (cursor < input + length) {
|
||||
if(!ReadScope(output_tokens, input, cursor, input + length)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (cursor < input + length) {
|
||||
if(!ReadScope(output_tokens, input, cursor, input + length)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // !FBX
|
||||
|
|
|
@ -46,21 +46,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
//
|
||||
#if _MSC_VER > 1500 || (defined __GNUC___)
|
||||
# define ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# else
|
||||
# define fbx_unordered_map map
|
||||
# define fbx_unordered_multimap multimap
|
||||
# define ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# else
|
||||
# define fbx_unordered_map map
|
||||
# define fbx_unordered_multimap multimap
|
||||
#endif
|
||||
|
||||
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# include <unordered_map>
|
||||
# if _MSC_VER > 1600
|
||||
# define fbx_unordered_map unordered_map
|
||||
# define fbx_unordered_multimap unordered_multimap
|
||||
# else
|
||||
# define fbx_unordered_map tr1::unordered_map
|
||||
# define fbx_unordered_multimap tr1::unordered_multimap
|
||||
# endif
|
||||
# include <unordered_map>
|
||||
# if _MSC_VER > 1600
|
||||
# define fbx_unordered_map unordered_map
|
||||
# define fbx_unordered_multimap unordered_multimap
|
||||
# else
|
||||
# define fbx_unordered_map tr1::unordered_map
|
||||
# define fbx_unordered_multimap tr1::unordered_multimap
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,7 +49,7 @@ struct aiScene;
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
class Document;
|
||||
class Document;
|
||||
|
||||
|
||||
/** Convert a FBX #Document to #aiScene
|
||||
|
|
|
@ -55,16 +55,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
: Object(id,element,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
||||
props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
|
||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
||||
props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,44 +80,44 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const
|
|||
: Deformer(id,element,doc,name)
|
||||
, node()
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Indexes = sc["Indexes"];
|
||||
const Element* const Weights = sc["Weights"];
|
||||
const Element* const Indexes = sc["Indexes"];
|
||||
const Element* const Weights = sc["Weights"];
|
||||
|
||||
const Element& Transform = GetRequiredElement(sc,"Transform",&element);
|
||||
const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element);
|
||||
const Element& Transform = GetRequiredElement(sc,"Transform",&element);
|
||||
const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element);
|
||||
|
||||
transform = ReadMatrix(Transform);
|
||||
transformLink = ReadMatrix(TransformLink);
|
||||
transform = ReadMatrix(Transform);
|
||||
transformLink = ReadMatrix(TransformLink);
|
||||
|
||||
// it is actually possible that there be Deformer's with no weights
|
||||
if (!!Indexes != !!Weights) {
|
||||
DOMError("either Indexes or Weights are missing from Cluster",&element);
|
||||
}
|
||||
// it is actually possible that there be Deformer's with no weights
|
||||
if (!!Indexes != !!Weights) {
|
||||
DOMError("either Indexes or Weights are missing from Cluster",&element);
|
||||
}
|
||||
|
||||
if(Indexes) {
|
||||
ParseVectorDataArray(indices,*Indexes);
|
||||
ParseVectorDataArray(weights,*Weights);
|
||||
}
|
||||
if(Indexes) {
|
||||
ParseVectorDataArray(indices,*Indexes);
|
||||
ParseVectorDataArray(weights,*Weights);
|
||||
}
|
||||
|
||||
if(indices.size() != weights.size()) {
|
||||
DOMError("sizes of index and weight array don't match up",&element);
|
||||
}
|
||||
if(indices.size() != weights.size()) {
|
||||
DOMError("sizes of index and weight array don't match up",&element);
|
||||
}
|
||||
|
||||
// read assigned node
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
|
||||
if(mod) {
|
||||
node = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// read assigned node
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
|
||||
if(mod) {
|
||||
node = mod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
DOMError("failed to read target Node for Cluster",&element);
|
||||
}
|
||||
if (!node) {
|
||||
DOMError("failed to read target Node for Cluster",&element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -132,25 +132,25 @@ Cluster::~Cluster()
|
|||
Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Deformer(id,element,doc,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"];
|
||||
if(Link_DeformAcuracy) {
|
||||
accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0));
|
||||
}
|
||||
const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"];
|
||||
if(Link_DeformAcuracy) {
|
||||
accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0));
|
||||
}
|
||||
|
||||
// resolve assigned clusters
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||
// resolve assigned clusters
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||
|
||||
clusters.reserve(conns.size());
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
clusters.reserve(conns.size());
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
|
||||
const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
|
||||
if(cluster) {
|
||||
clusters.push_back(cluster);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
|
||||
if(cluster) {
|
||||
clusters.push_back(cluster);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -80,141 +80,141 @@ LazyObject::~LazyObject()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* LazyObject::Get(bool dieOnError)
|
||||
{
|
||||
if(IsBeingConstructed() || FailedToConstruct()) {
|
||||
return NULL;
|
||||
}
|
||||
if(IsBeingConstructed() || FailedToConstruct()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (object.get()) {
|
||||
return object.get();
|
||||
}
|
||||
if (object.get()) {
|
||||
return object.get();
|
||||
}
|
||||
|
||||
// if this is the root object, we return a dummy since there
|
||||
// is no root object int he fbx file - it is just referenced
|
||||
// with id 0.
|
||||
if(id == 0L) {
|
||||
object.reset(new Object(id, element, "Model::RootNode"));
|
||||
return object.get();
|
||||
}
|
||||
// if this is the root object, we return a dummy since there
|
||||
// is no root object int he fbx file - it is just referenced
|
||||
// with id 0.
|
||||
if(id == 0L) {
|
||||
object.reset(new Object(id, element, "Model::RootNode"));
|
||||
return object.get();
|
||||
}
|
||||
|
||||
const Token& key = element.KeyToken();
|
||||
const TokenList& tokens = element.Tokens();
|
||||
const Token& key = element.KeyToken();
|
||||
const TokenList& tokens = element.Tokens();
|
||||
|
||||
if(tokens.size() < 3) {
|
||||
DOMError("expected at least 3 tokens: id, name and class tag",&element);
|
||||
}
|
||||
if(tokens.size() < 3) {
|
||||
DOMError("expected at least 3 tokens: id, name and class tag",&element);
|
||||
}
|
||||
|
||||
const char* err;
|
||||
std::string name = ParseTokenAsString(*tokens[1],err);
|
||||
if (err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
const char* err;
|
||||
std::string name = ParseTokenAsString(*tokens[1],err);
|
||||
if (err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
|
||||
// small fix for binary reading: binary fbx files don't use
|
||||
// prefixes such as Model:: in front of their names. The
|
||||
// loading code expects this at many places, though!
|
||||
// so convert the binary representation (a 0x0001) to the
|
||||
// double colon notation.
|
||||
if(tokens[1]->IsBinary()) {
|
||||
for (size_t i = 0; i < name.length(); ++i) {
|
||||
if (name[i] == 0x0 && name[i+1] == 0x1) {
|
||||
name = name.substr(i+2) + "::" + name.substr(0,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
// small fix for binary reading: binary fbx files don't use
|
||||
// prefixes such as Model:: in front of their names. The
|
||||
// loading code expects this at many places, though!
|
||||
// so convert the binary representation (a 0x0001) to the
|
||||
// double colon notation.
|
||||
if(tokens[1]->IsBinary()) {
|
||||
for (size_t i = 0; i < name.length(); ++i) {
|
||||
if (name[i] == 0x0 && name[i+1] == 0x1) {
|
||||
name = name.substr(i+2) + "::" + name.substr(0,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string classtag = ParseTokenAsString(*tokens[2],err);
|
||||
if (err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
const std::string classtag = ParseTokenAsString(*tokens[2],err);
|
||||
if (err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
|
||||
// prevent recursive calls
|
||||
flags |= BEING_CONSTRUCTED;
|
||||
// prevent recursive calls
|
||||
flags |= BEING_CONSTRUCTED;
|
||||
|
||||
try {
|
||||
// this needs to be relatively fast since it happens a lot,
|
||||
// so avoid constructing strings all the time.
|
||||
const char* obtype = key.begin();
|
||||
const size_t length = static_cast<size_t>(key.end()-key.begin());
|
||||
if (!strncmp(obtype,"Geometry",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Mesh")) {
|
||||
object.reset(new MeshGeometry(id,element,name,doc));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"NodeAttribute",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Camera")) {
|
||||
object.reset(new Camera(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"CameraSwitcher")) {
|
||||
object.reset(new CameraSwitcher(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Light")) {
|
||||
object.reset(new Light(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Null")) {
|
||||
object.reset(new Null(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"LimbNode")) {
|
||||
object.reset(new LimbNode(id,element,doc,name));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Deformer",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Cluster")) {
|
||||
object.reset(new Cluster(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Skin")) {
|
||||
object.reset(new Skin(id,element,doc,name));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Model",length)) {
|
||||
// FK and IK effectors are not supported
|
||||
if (strcmp(classtag.c_str(),"IKEffector") && strcmp(classtag.c_str(),"FKEffector")) {
|
||||
object.reset(new Model(id,element,doc,name));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Material",length)) {
|
||||
object.reset(new Material(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"Texture",length)) {
|
||||
object.reset(new Texture(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"LayeredTexture",length)) {
|
||||
object.reset(new LayeredTexture(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationStack",length)) {
|
||||
object.reset(new AnimationStack(id,element,name,doc));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationLayer",length)) {
|
||||
object.reset(new AnimationLayer(id,element,name,doc));
|
||||
}
|
||||
// note: order matters for these two
|
||||
else if (!strncmp(obtype,"AnimationCurve",length)) {
|
||||
object.reset(new AnimationCurve(id,element,name,doc));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationCurveNode",length)) {
|
||||
object.reset(new AnimationCurveNode(id,element,name,doc));
|
||||
}
|
||||
}
|
||||
catch(std::exception& ex) {
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
flags |= FAILED_TO_CONSTRUCT;
|
||||
try {
|
||||
// this needs to be relatively fast since it happens a lot,
|
||||
// so avoid constructing strings all the time.
|
||||
const char* obtype = key.begin();
|
||||
const size_t length = static_cast<size_t>(key.end()-key.begin());
|
||||
if (!strncmp(obtype,"Geometry",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Mesh")) {
|
||||
object.reset(new MeshGeometry(id,element,name,doc));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"NodeAttribute",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Camera")) {
|
||||
object.reset(new Camera(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"CameraSwitcher")) {
|
||||
object.reset(new CameraSwitcher(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Light")) {
|
||||
object.reset(new Light(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Null")) {
|
||||
object.reset(new Null(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"LimbNode")) {
|
||||
object.reset(new LimbNode(id,element,doc,name));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Deformer",length)) {
|
||||
if (!strcmp(classtag.c_str(),"Cluster")) {
|
||||
object.reset(new Cluster(id,element,doc,name));
|
||||
}
|
||||
else if (!strcmp(classtag.c_str(),"Skin")) {
|
||||
object.reset(new Skin(id,element,doc,name));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Model",length)) {
|
||||
// FK and IK effectors are not supported
|
||||
if (strcmp(classtag.c_str(),"IKEffector") && strcmp(classtag.c_str(),"FKEffector")) {
|
||||
object.reset(new Model(id,element,doc,name));
|
||||
}
|
||||
}
|
||||
else if (!strncmp(obtype,"Material",length)) {
|
||||
object.reset(new Material(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"Texture",length)) {
|
||||
object.reset(new Texture(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"LayeredTexture",length)) {
|
||||
object.reset(new LayeredTexture(id,element,doc,name));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationStack",length)) {
|
||||
object.reset(new AnimationStack(id,element,name,doc));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationLayer",length)) {
|
||||
object.reset(new AnimationLayer(id,element,name,doc));
|
||||
}
|
||||
// note: order matters for these two
|
||||
else if (!strncmp(obtype,"AnimationCurve",length)) {
|
||||
object.reset(new AnimationCurve(id,element,name,doc));
|
||||
}
|
||||
else if (!strncmp(obtype,"AnimationCurveNode",length)) {
|
||||
object.reset(new AnimationCurveNode(id,element,name,doc));
|
||||
}
|
||||
}
|
||||
catch(std::exception& ex) {
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
flags |= FAILED_TO_CONSTRUCT;
|
||||
|
||||
if(dieOnError || doc.Settings().strictMode) {
|
||||
throw;
|
||||
}
|
||||
if(dieOnError || doc.Settings().strictMode) {
|
||||
throw;
|
||||
}
|
||||
|
||||
// note: the error message is already formatted, so raw logging is ok
|
||||
if(!DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::get()->error(ex.what());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// note: the error message is already formatted, so raw logging is ok
|
||||
if(!DefaultLogger::isNullLogger()) {
|
||||
DefaultLogger::get()->error(ex.what());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!object.get()) {
|
||||
//DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
|
||||
}
|
||||
if (!object.get()) {
|
||||
//DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
|
||||
}
|
||||
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
return object.get();
|
||||
flags &= ~BEING_CONSTRUCTED;
|
||||
return object.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -254,214 +254,214 @@ Document::Document(const Parser& parser, const ImportSettings& settings)
|
|||
: settings(settings)
|
||||
, parser(parser)
|
||||
{
|
||||
// Cannot use array default initialization syntax because vc8 fails on it
|
||||
for (unsigned int i = 0; i < sizeof(creationTimeStamp) / sizeof(creationTimeStamp[0]); ++i) {
|
||||
creationTimeStamp[i] = 0;
|
||||
}
|
||||
// Cannot use array default initialization syntax because vc8 fails on it
|
||||
for (unsigned int i = 0; i < sizeof(creationTimeStamp) / sizeof(creationTimeStamp[0]); ++i) {
|
||||
creationTimeStamp[i] = 0;
|
||||
}
|
||||
|
||||
ReadHeader();
|
||||
ReadPropertyTemplates();
|
||||
ReadHeader();
|
||||
ReadPropertyTemplates();
|
||||
|
||||
ReadGlobalSettings();
|
||||
ReadGlobalSettings();
|
||||
|
||||
// This order is important, connections need parsed objects to check
|
||||
// whether connections are ok or not. Objects may not be evaluated yet,
|
||||
// though, since this may require valid connections.
|
||||
ReadObjects();
|
||||
ReadConnections();
|
||||
// This order is important, connections need parsed objects to check
|
||||
// whether connections are ok or not. Objects may not be evaluated yet,
|
||||
// though, since this may require valid connections.
|
||||
ReadObjects();
|
||||
ReadConnections();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Document::~Document()
|
||||
{
|
||||
BOOST_FOREACH(ObjectMap::value_type& v, objects) {
|
||||
delete v.second;
|
||||
}
|
||||
BOOST_FOREACH(ObjectMap::value_type& v, objects) {
|
||||
delete v.second;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(ConnectionMap::value_type& v, src_connections) {
|
||||
delete v.second;
|
||||
}
|
||||
// |dest_connections| contain the same Connection objects as the |src_connections|
|
||||
BOOST_FOREACH(ConnectionMap::value_type& v, src_connections) {
|
||||
delete v.second;
|
||||
}
|
||||
// |dest_connections| contain the same Connection objects as the |src_connections|
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadHeader()
|
||||
{
|
||||
// Read ID objects from "Objects" section
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const ehead = sc["FBXHeaderExtension"];
|
||||
if(!ehead || !ehead->Compound()) {
|
||||
DOMError("no FBXHeaderExtension dictionary found");
|
||||
}
|
||||
// Read ID objects from "Objects" section
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const ehead = sc["FBXHeaderExtension"];
|
||||
if(!ehead || !ehead->Compound()) {
|
||||
DOMError("no FBXHeaderExtension dictionary found");
|
||||
}
|
||||
|
||||
const Scope& shead = *ehead->Compound();
|
||||
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
|
||||
const Scope& shead = *ehead->Compound();
|
||||
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
|
||||
|
||||
// While we maye have some success with newer files, we don't support
|
||||
// the older 6.n fbx format
|
||||
if(fbxVersion < 7100) {
|
||||
DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
|
||||
}
|
||||
if(fbxVersion > 7300) {
|
||||
if(Settings().strictMode) {
|
||||
DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013"
|
||||
" (turn off strict mode to try anyhow) ");
|
||||
}
|
||||
else {
|
||||
DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013,"
|
||||
" trying to read it nevertheless");
|
||||
}
|
||||
}
|
||||
// While we maye have some success with newer files, we don't support
|
||||
// the older 6.n fbx format
|
||||
if(fbxVersion < 7100) {
|
||||
DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
|
||||
}
|
||||
if(fbxVersion > 7300) {
|
||||
if(Settings().strictMode) {
|
||||
DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013"
|
||||
" (turn off strict mode to try anyhow) ");
|
||||
}
|
||||
else {
|
||||
DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013,"
|
||||
" trying to read it nevertheless");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const Element* const ecreator = shead["Creator"];
|
||||
if(ecreator) {
|
||||
creator = ParseTokenAsString(GetRequiredToken(*ecreator,0));
|
||||
}
|
||||
const Element* const ecreator = shead["Creator"];
|
||||
if(ecreator) {
|
||||
creator = ParseTokenAsString(GetRequiredToken(*ecreator,0));
|
||||
}
|
||||
|
||||
const Element* const etimestamp = shead["CreationTimeStamp"];
|
||||
if(etimestamp && etimestamp->Compound()) {
|
||||
const Scope& stimestamp = *etimestamp->Compound();
|
||||
creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0));
|
||||
creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0));
|
||||
creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0));
|
||||
creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0));
|
||||
creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0));
|
||||
creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0));
|
||||
creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0));
|
||||
}
|
||||
const Element* const etimestamp = shead["CreationTimeStamp"];
|
||||
if(etimestamp && etimestamp->Compound()) {
|
||||
const Scope& stimestamp = *etimestamp->Compound();
|
||||
creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0));
|
||||
creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0));
|
||||
creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0));
|
||||
creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0));
|
||||
creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0));
|
||||
creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0));
|
||||
creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadGlobalSettings()
|
||||
{
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const ehead = sc["GlobalSettings"];
|
||||
if(!ehead || !ehead->Compound()) {
|
||||
DOMWarning("no GlobalSettings dictionary found");
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const ehead = sc["GlobalSettings"];
|
||||
if(!ehead || !ehead->Compound()) {
|
||||
DOMWarning("no GlobalSettings dictionary found");
|
||||
|
||||
globals.reset(new FileGlobalSettings(*this, boost::make_shared<const PropertyTable>()));
|
||||
return;
|
||||
}
|
||||
globals.reset(new FileGlobalSettings(*this, boost::make_shared<const PropertyTable>()));
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<const PropertyTable> props = GetPropertyTable(*this, "", *ehead, *ehead->Compound(), true);
|
||||
boost::shared_ptr<const PropertyTable> props = GetPropertyTable(*this, "", *ehead, *ehead->Compound(), true);
|
||||
|
||||
if(!props) {
|
||||
DOMError("GlobalSettings dictionary contains no property table");
|
||||
}
|
||||
if(!props) {
|
||||
DOMError("GlobalSettings dictionary contains no property table");
|
||||
}
|
||||
|
||||
globals.reset(new FileGlobalSettings(*this, props));
|
||||
globals.reset(new FileGlobalSettings(*this, props));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadObjects()
|
||||
{
|
||||
// read ID objects from "Objects" section
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const eobjects = sc["Objects"];
|
||||
if(!eobjects || !eobjects->Compound()) {
|
||||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
// read ID objects from "Objects" section
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
const Element* const eobjects = sc["Objects"];
|
||||
if(!eobjects || !eobjects->Compound()) {
|
||||
DOMError("no Objects dictionary found");
|
||||
}
|
||||
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, *eobjects, *this);
|
||||
// add a dummy entry to represent the Model::RootNode object (id 0),
|
||||
// which is only indirectly defined in the input file
|
||||
objects[0] = new LazyObject(0L, *eobjects, *this);
|
||||
|
||||
const Scope& sobjects = *eobjects->Compound();
|
||||
BOOST_FOREACH(const ElementMap::value_type& el, sobjects.Elements()) {
|
||||
const Scope& sobjects = *eobjects->Compound();
|
||||
BOOST_FOREACH(const ElementMap::value_type& el, sobjects.Elements()) {
|
||||
|
||||
// extract ID
|
||||
const TokenList& tok = el.second->Tokens();
|
||||
// extract ID
|
||||
const TokenList& tok = el.second->Tokens();
|
||||
|
||||
if (tok.empty()) {
|
||||
DOMError("expected ID after object key",el.second);
|
||||
}
|
||||
if (tok.empty()) {
|
||||
DOMError("expected ID after object key",el.second);
|
||||
}
|
||||
|
||||
const char* err;
|
||||
const char* err;
|
||||
|
||||
const uint64_t id = ParseTokenAsID(*tok[0], err);
|
||||
if(err) {
|
||||
DOMError(err,el.second);
|
||||
}
|
||||
const uint64_t id = ParseTokenAsID(*tok[0], err);
|
||||
if(err) {
|
||||
DOMError(err,el.second);
|
||||
}
|
||||
|
||||
// id=0 is normally implicit
|
||||
if(id == 0L) {
|
||||
DOMError("encountered object with implicitly defined id 0",el.second);
|
||||
}
|
||||
// id=0 is normally implicit
|
||||
if(id == 0L) {
|
||||
DOMError("encountered object with implicitly defined id 0",el.second);
|
||||
}
|
||||
|
||||
if(objects.find(id) != objects.end()) {
|
||||
DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
|
||||
}
|
||||
if(objects.find(id) != objects.end()) {
|
||||
DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
|
||||
}
|
||||
|
||||
objects[id] = new LazyObject(id, *el.second, *this);
|
||||
objects[id] = new LazyObject(id, *el.second, *this);
|
||||
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if(!strcmp(el.first.c_str(),"AnimationStack")) {
|
||||
animationStacks.push_back(id);
|
||||
}
|
||||
}
|
||||
// grab all animation stacks upfront since there is no listing of them
|
||||
if(!strcmp(el.first.c_str(),"AnimationStack")) {
|
||||
animationStacks.push_back(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadPropertyTemplates()
|
||||
{
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const edefs = sc["Definitions"];
|
||||
if(!edefs || !edefs->Compound()) {
|
||||
DOMWarning("no Definitions dictionary found");
|
||||
return;
|
||||
}
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const edefs = sc["Definitions"];
|
||||
if(!edefs || !edefs->Compound()) {
|
||||
DOMWarning("no Definitions dictionary found");
|
||||
return;
|
||||
}
|
||||
|
||||
const Scope& sdefs = *edefs->Compound();
|
||||
const ElementCollection otypes = sdefs.GetCollection("ObjectType");
|
||||
for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const Scope* sc = el.Compound();
|
||||
if(!sc) {
|
||||
DOMWarning("expected nested scope in ObjectType, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
const Scope& sdefs = *edefs->Compound();
|
||||
const ElementCollection otypes = sdefs.GetCollection("ObjectType");
|
||||
for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const Scope* sc = el.Compound();
|
||||
if(!sc) {
|
||||
DOMWarning("expected nested scope in ObjectType, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList& tok = el.Tokens();
|
||||
if(tok.empty()) {
|
||||
DOMWarning("expected name for ObjectType element, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
const TokenList& tok = el.Tokens();
|
||||
if(tok.empty()) {
|
||||
DOMWarning("expected name for ObjectType element, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& oname = ParseTokenAsString(*tok[0]);
|
||||
const std::string& oname = ParseTokenAsString(*tok[0]);
|
||||
|
||||
const ElementCollection templs = sc->GetCollection("PropertyTemplate");
|
||||
for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const Scope* sc = el.Compound();
|
||||
if(!sc) {
|
||||
DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
const ElementCollection templs = sc->GetCollection("PropertyTemplate");
|
||||
for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const Scope* sc = el.Compound();
|
||||
if(!sc) {
|
||||
DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const TokenList& tok = el.Tokens();
|
||||
if(tok.empty()) {
|
||||
DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
const TokenList& tok = el.Tokens();
|
||||
if(tok.empty()) {
|
||||
DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& pname = ParseTokenAsString(*tok[0]);
|
||||
const std::string& pname = ParseTokenAsString(*tok[0]);
|
||||
|
||||
const Element* Properties70 = (*sc)["Properties70"];
|
||||
if(Properties70) {
|
||||
boost::shared_ptr<const PropertyTable> props = boost::make_shared<const PropertyTable>(
|
||||
*Properties70,boost::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
|
||||
);
|
||||
const Element* Properties70 = (*sc)["Properties70"];
|
||||
if(Properties70) {
|
||||
boost::shared_ptr<const PropertyTable> props = boost::make_shared<const PropertyTable>(
|
||||
*Properties70,boost::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
|
||||
);
|
||||
|
||||
templates[oname+"."+pname] = props;
|
||||
}
|
||||
}
|
||||
}
|
||||
templates[oname+"."+pname] = props;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -469,202 +469,202 @@ void Document::ReadPropertyTemplates()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void Document::ReadConnections()
|
||||
{
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const econns = sc["Connections"];
|
||||
if(!econns || !econns->Compound()) {
|
||||
DOMError("no Connections dictionary found");
|
||||
}
|
||||
const Scope& sc = parser.GetRootScope();
|
||||
// read property templates from "Definitions" section
|
||||
const Element* const econns = sc["Connections"];
|
||||
if(!econns || !econns->Compound()) {
|
||||
DOMError("no Connections dictionary found");
|
||||
}
|
||||
|
||||
uint64_t insertionOrder = 0l;
|
||||
uint64_t insertionOrder = 0l;
|
||||
|
||||
const Scope& sconns = *econns->Compound();
|
||||
const ElementCollection conns = sconns.GetCollection("C");
|
||||
for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
|
||||
const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
|
||||
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
|
||||
const Scope& sconns = *econns->Compound();
|
||||
const ElementCollection conns = sconns.GetCollection("C");
|
||||
for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
||||
const Element& el = *(*it).second;
|
||||
const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
|
||||
const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
|
||||
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
|
||||
|
||||
// OO = object-object connection
|
||||
// OP = object-property connection, in which case the destination property follows the object ID
|
||||
const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : "");
|
||||
// OO = object-object connection
|
||||
// OP = object-property connection, in which case the destination property follows the object ID
|
||||
const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : "");
|
||||
|
||||
if(objects.find(src) == objects.end()) {
|
||||
DOMWarning("source object for connection does not exist",&el);
|
||||
continue;
|
||||
}
|
||||
if(objects.find(src) == objects.end()) {
|
||||
DOMWarning("source object for connection does not exist",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// dest may be 0 (root node) but we added a dummy object before
|
||||
if(objects.find(dest) == objects.end()) {
|
||||
DOMWarning("destination object for connection does not exist",&el);
|
||||
continue;
|
||||
}
|
||||
// dest may be 0 (root node) but we added a dummy object before
|
||||
if(objects.find(dest) == objects.end()) {
|
||||
DOMWarning("destination object for connection does not exist",&el);
|
||||
continue;
|
||||
}
|
||||
|
||||
// add new connection
|
||||
const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
|
||||
src_connections.insert(ConnectionMap::value_type(src,c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest,c));
|
||||
}
|
||||
// add new connection
|
||||
const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this);
|
||||
src_connections.insert(ConnectionMap::value_type(src,c));
|
||||
dest_connections.insert(ConnectionMap::value_type(dest,c));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const std::vector<const AnimationStack*>& Document::AnimationStacks() const
|
||||
{
|
||||
if (!animationStacksResolved.empty() || !animationStacks.size()) {
|
||||
return animationStacksResolved;
|
||||
}
|
||||
if (!animationStacksResolved.empty() || !animationStacks.size()) {
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
animationStacksResolved.reserve(animationStacks.size());
|
||||
BOOST_FOREACH(uint64_t id, animationStacks) {
|
||||
LazyObject* const lazy = GetObject(id);
|
||||
const AnimationStack* stack;
|
||||
if(!lazy || !(stack = lazy->Get<AnimationStack>())) {
|
||||
DOMWarning("failed to read AnimationStack object");
|
||||
continue;
|
||||
}
|
||||
animationStacksResolved.push_back(stack);
|
||||
}
|
||||
animationStacksResolved.reserve(animationStacks.size());
|
||||
BOOST_FOREACH(uint64_t id, animationStacks) {
|
||||
LazyObject* const lazy = GetObject(id);
|
||||
const AnimationStack* stack;
|
||||
if(!lazy || !(stack = lazy->Get<AnimationStack>())) {
|
||||
DOMWarning("failed to read AnimationStack object");
|
||||
continue;
|
||||
}
|
||||
animationStacksResolved.push_back(stack);
|
||||
}
|
||||
|
||||
return animationStacksResolved;
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject* Document::GetObject(uint64_t id) const
|
||||
{
|
||||
ObjectMap::const_iterator it = objects.find(id);
|
||||
return it == objects.end() ? NULL : (*it).second;
|
||||
ObjectMap::const_iterator it = objects.find(id);
|
||||
return it == objects.end() ? NULL : (*it).second;
|
||||
}
|
||||
|
||||
#define MAX_CLASSNAMES 6
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id,
|
||||
const ConnectionMap& conns) const
|
||||
const ConnectionMap& conns) const
|
||||
{
|
||||
std::vector<const Connection*> temp;
|
||||
std::vector<const Connection*> temp;
|
||||
|
||||
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first,range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
temp.reserve(std::distance(range.first,range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
|
||||
|
||||
return temp; // NRVO should handle this
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src,
|
||||
const ConnectionMap& conns,
|
||||
const char* const* classnames,
|
||||
size_t count) const
|
||||
const ConnectionMap& conns,
|
||||
const char* const* classnames,
|
||||
size_t count) const
|
||||
|
||||
{
|
||||
ai_assert(classnames);
|
||||
ai_assert(count != 0 && count <= MAX_CLASSNAMES);
|
||||
ai_assert(classnames);
|
||||
ai_assert(count != 0 && count <= MAX_CLASSNAMES);
|
||||
|
||||
size_t lenghts[MAX_CLASSNAMES];
|
||||
size_t lenghts[MAX_CLASSNAMES];
|
||||
|
||||
const size_t c = count;
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
lenghts[i] = strlen(classnames[i]);
|
||||
}
|
||||
const size_t c = count;
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
lenghts[i] = strlen(classnames[i]);
|
||||
}
|
||||
|
||||
std::vector<const Connection*> temp;
|
||||
std::vector<const Connection*> temp;
|
||||
|
||||
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
|
||||
conns.equal_range(id);
|
||||
|
||||
temp.reserve(std::distance(range.first,range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
const Token& key = (is_src
|
||||
? (*it).second->LazyDestinationObject()
|
||||
: (*it).second->LazySourceObject()
|
||||
).GetElement().KeyToken();
|
||||
temp.reserve(std::distance(range.first,range.second));
|
||||
for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
|
||||
const Token& key = (is_src
|
||||
? (*it).second->LazyDestinationObject()
|
||||
: (*it).second->LazySourceObject()
|
||||
).GetElement().KeyToken();
|
||||
|
||||
const char* obtype = key.begin();
|
||||
const char* obtype = key.begin();
|
||||
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
ai_assert(classnames[i]);
|
||||
if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lenghts[i] && !strncmp(classnames[i],obtype,lenghts[i])) {
|
||||
obtype = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
ai_assert(classnames[i]);
|
||||
if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lenghts[i] && !strncmp(classnames[i],obtype,lenghts[i])) {
|
||||
obtype = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(obtype) {
|
||||
continue;
|
||||
}
|
||||
if(obtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
temp.push_back((*it).second);
|
||||
}
|
||||
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
|
||||
return temp; // NRVO should handle this
|
||||
std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare));
|
||||
return temp; // NRVO should handle this
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const
|
||||
{
|
||||
return GetConnectionsSequenced(source, ConnectionsBySource());
|
||||
return GetConnectionsSequenced(source, ConnectionsBySource());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t dest,
|
||||
const char* classname) const
|
||||
const char* classname) const
|
||||
{
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsBySourceSequenced(dest, arr,1);
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsBySourceSequenced(dest, arr,1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source,
|
||||
const char* const* classnames, size_t count) const
|
||||
const char* const* classnames, size_t count) const
|
||||
{
|
||||
return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
|
||||
return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char* classname) const
|
||||
const char* classname) const
|
||||
{
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsByDestinationSequenced(dest, arr,1);
|
||||
const char* arr[] = {classname};
|
||||
return GetConnectionsByDestinationSequenced(dest, arr,1);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const
|
||||
{
|
||||
return GetConnectionsSequenced(dest, ConnectionsByDestination());
|
||||
return GetConnectionsSequenced(dest, ConnectionsByDestination());
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
|
||||
const char* const* classnames, size_t count) const
|
||||
const char* const* classnames, size_t count) const
|
||||
|
||||
{
|
||||
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
|
||||
return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop,
|
||||
const Document& doc)
|
||||
const Document& doc)
|
||||
|
||||
: insertionOrder(insertionOrder)
|
||||
, prop(prop)
|
||||
|
@ -672,9 +672,9 @@ Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, co
|
|||
, dest(dest)
|
||||
, doc(doc)
|
||||
{
|
||||
ai_assert(doc.Objects().find(src) != doc.Objects().end());
|
||||
// dest may be 0 (root node)
|
||||
ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
|
||||
ai_assert(doc.Objects().find(src) != doc.Objects().end());
|
||||
// dest may be 0 (root node)
|
||||
ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
|
||||
}
|
||||
|
||||
|
||||
|
@ -688,36 +688,36 @@ Connection::~Connection()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject& Connection::LazySourceObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject& Connection::LazyDestinationObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return *lazy;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* Connection::SourceObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
LazyObject* const lazy = doc.GetObject(src);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Object* Connection::DestinationObject() const
|
||||
{
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
LazyObject* const lazy = doc.GetObject(dest);
|
||||
ai_assert(lazy);
|
||||
return lazy->Get();
|
||||
}
|
||||
|
||||
} // !FBX
|
||||
|
|
1574
code/FBXDocument.h
1574
code/FBXDocument.h
File diff suppressed because it is too large
Load Diff
|
@ -59,16 +59,16 @@ namespace Util {
|
|||
// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
|
||||
void DOMError(const std::string& message, const Token& token)
|
||||
{
|
||||
throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
|
||||
throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DOMError(const std::string& message, const Element* element /*= NULL*/)
|
||||
{
|
||||
if(element) {
|
||||
DOMError(message,element->KeyToken());
|
||||
}
|
||||
throw DeadlyImportError("FBX-DOM " + message);
|
||||
if(element) {
|
||||
DOMError(message,element->KeyToken());
|
||||
}
|
||||
throw DeadlyImportError("FBX-DOM " + message);
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,55 +76,55 @@ void DOMError(const std::string& message, const Element* element /*= NULL*/)
|
|||
// print warning, do return
|
||||
void DOMWarning(const std::string& message, const Token& token)
|
||||
{
|
||||
if(DefaultLogger::get()) {
|
||||
DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
|
||||
}
|
||||
if(DefaultLogger::get()) {
|
||||
DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
|
||||
{
|
||||
if(element) {
|
||||
DOMWarning(message,element->KeyToken());
|
||||
return;
|
||||
}
|
||||
if(DefaultLogger::get()) {
|
||||
DefaultLogger::get()->warn("FBX-DOM: " + message);
|
||||
}
|
||||
if(element) {
|
||||
DOMWarning(message,element->KeyToken());
|
||||
return;
|
||||
}
|
||||
if(DefaultLogger::get()) {
|
||||
DefaultLogger::get()->warn("FBX-DOM: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// fetch a property table and the corresponding property template
|
||||
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||
const std::string& templateName,
|
||||
const Element &element,
|
||||
const Scope& sc,
|
||||
bool no_warn /*= false*/)
|
||||
const std::string& templateName,
|
||||
const Element &element,
|
||||
const Scope& sc,
|
||||
bool no_warn /*= false*/)
|
||||
{
|
||||
const Element* const Properties70 = sc["Properties70"];
|
||||
boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
|
||||
static_cast<const PropertyTable*>(NULL));
|
||||
const Element* const Properties70 = sc["Properties70"];
|
||||
boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
|
||||
static_cast<const PropertyTable*>(NULL));
|
||||
|
||||
if(templateName.length()) {
|
||||
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
|
||||
if(it != doc.Templates().end()) {
|
||||
templateProps = (*it).second;
|
||||
}
|
||||
}
|
||||
if(templateName.length()) {
|
||||
PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
|
||||
if(it != doc.Templates().end()) {
|
||||
templateProps = (*it).second;
|
||||
}
|
||||
}
|
||||
|
||||
if(!Properties70) {
|
||||
if(!no_warn) {
|
||||
DOMWarning("property table (Properties70) not found",&element);
|
||||
}
|
||||
if(templateProps) {
|
||||
return templateProps;
|
||||
}
|
||||
else {
|
||||
return boost::make_shared<const PropertyTable>();
|
||||
}
|
||||
}
|
||||
return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
|
||||
if(!Properties70) {
|
||||
if(!no_warn) {
|
||||
DOMWarning("property table (Properties70) not found",&element);
|
||||
}
|
||||
if(templateProps) {
|
||||
return templateProps;
|
||||
}
|
||||
else {
|
||||
return boost::make_shared<const PropertyTable>();
|
||||
}
|
||||
}
|
||||
return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
|
||||
}
|
||||
} // !Util
|
||||
} // !FBX
|
||||
|
|
|
@ -68,50 +68,50 @@ void DOMWarning(const std::string& message, const Element* element = NULL);
|
|||
|
||||
// fetch a property table and the corresponding property template
|
||||
boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
|
||||
const std::string& templateName,
|
||||
const Element &element,
|
||||
const Scope& sc,
|
||||
bool no_warn = false);
|
||||
const std::string& templateName,
|
||||
const Element &element,
|
||||
const Scope& sc,
|
||||
bool no_warn = false);
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline const T* ProcessSimpleConnection(const Connection& con,
|
||||
bool is_object_property_conn,
|
||||
const char* name,
|
||||
const Element& element,
|
||||
const char** propNameOut = NULL)
|
||||
bool is_object_property_conn,
|
||||
const char* name,
|
||||
const Element& element,
|
||||
const char** propNameOut = NULL)
|
||||
{
|
||||
if (is_object_property_conn && !con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-object connection, ignoring",
|
||||
&element
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
else if (!is_object_property_conn && con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-property connection, ignoring",
|
||||
&element
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
if (is_object_property_conn && !con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-object connection, ignoring",
|
||||
&element
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
else if (!is_object_property_conn && con.PropertyName().length()) {
|
||||
DOMWarning("expected incoming " + std::string(name) +
|
||||
" link to be an object-property connection, ignoring",
|
||||
&element
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(is_object_property_conn && propNameOut) {
|
||||
// note: this is ok, the return value of PropertyValue() is guaranteed to
|
||||
// remain valid and unchanged as long as the document exists.
|
||||
*propNameOut = con.PropertyName().c_str();
|
||||
}
|
||||
if(is_object_property_conn && propNameOut) {
|
||||
// note: this is ok, the return value of PropertyValue() is guaranteed to
|
||||
// remain valid and unchanged as long as the document exists.
|
||||
*propNameOut = con.PropertyName().c_str();
|
||||
}
|
||||
|
||||
const Object* const ob = con.SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for incoming" + std::string(name) +
|
||||
" link, ignoring",
|
||||
&element);
|
||||
return NULL;
|
||||
}
|
||||
const Object* const ob = con.SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for incoming" + std::string(name) +
|
||||
" link, ignoring",
|
||||
&element);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dynamic_cast<const T*>(ob);
|
||||
return dynamic_cast<const T*>(ob);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,88 +50,88 @@ namespace FBX {
|
|||
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
|
||||
struct ImportSettings
|
||||
{
|
||||
ImportSettings()
|
||||
: strictMode(true)
|
||||
, readAllLayers(true)
|
||||
, readAllMaterials(false)
|
||||
, readMaterials(true)
|
||||
, readCameras(true)
|
||||
, readLights(true)
|
||||
, readAnimations(true)
|
||||
, readWeights(true)
|
||||
, preservePivots(true)
|
||||
, optimizeEmptyAnimationCurves(true)
|
||||
{}
|
||||
ImportSettings()
|
||||
: strictMode(true)
|
||||
, readAllLayers(true)
|
||||
, readAllMaterials(false)
|
||||
, readMaterials(true)
|
||||
, readCameras(true)
|
||||
, readLights(true)
|
||||
, readAnimations(true)
|
||||
, readWeights(true)
|
||||
, preservePivots(true)
|
||||
, optimizeEmptyAnimationCurves(true)
|
||||
{}
|
||||
|
||||
|
||||
/** enable strict mode:
|
||||
* - only accept fbx 2012, 2013 files
|
||||
* - on the slightest error, give up.
|
||||
*
|
||||
* Basically, strict mode means that the fbx file will actually
|
||||
* be validated. Strict mode is off by default. */
|
||||
bool strictMode;
|
||||
/** enable strict mode:
|
||||
* - only accept fbx 2012, 2013 files
|
||||
* - on the slightest error, give up.
|
||||
*
|
||||
* Basically, strict mode means that the fbx file will actually
|
||||
* be validated. Strict mode is off by default. */
|
||||
bool strictMode;
|
||||
|
||||
/** specifies whether all geometry layers are read and scanned for
|
||||
* usable data channels. The FBX spec indicates that many readers
|
||||
* will only read the first channel and that this is in some way
|
||||
* the recommended way- in reality, however, it happens a lot that
|
||||
* vertex data is spread among multiple layers. The default
|
||||
* value for this option is true.*/
|
||||
bool readAllLayers;
|
||||
/** specifies whether all geometry layers are read and scanned for
|
||||
* usable data channels. The FBX spec indicates that many readers
|
||||
* will only read the first channel and that this is in some way
|
||||
* the recommended way- in reality, however, it happens a lot that
|
||||
* vertex data is spread among multiple layers. The default
|
||||
* value for this option is true.*/
|
||||
bool readAllLayers;
|
||||
|
||||
/** specifies whether all materials are read, or only those that
|
||||
* are referenced by at least one mesh. Reading all materials
|
||||
* may make FBX reading a lot slower since all objects
|
||||
* need to be processed .
|
||||
* This bit is ignored unless readMaterials=true*/
|
||||
bool readAllMaterials;
|
||||
/** specifies whether all materials are read, or only those that
|
||||
* are referenced by at least one mesh. Reading all materials
|
||||
* may make FBX reading a lot slower since all objects
|
||||
* need to be processed .
|
||||
* This bit is ignored unless readMaterials=true*/
|
||||
bool readAllMaterials;
|
||||
|
||||
|
||||
/** import materials (true) or skip them and assign a default
|
||||
* material. The default value is true.*/
|
||||
bool readMaterials;
|
||||
/** import materials (true) or skip them and assign a default
|
||||
* material. The default value is true.*/
|
||||
bool readMaterials;
|
||||
|
||||
/** import cameras? Default value is true.*/
|
||||
bool readCameras;
|
||||
/** import cameras? Default value is true.*/
|
||||
bool readCameras;
|
||||
|
||||
/** import light sources? Default value is true.*/
|
||||
bool readLights;
|
||||
/** import light sources? Default value is true.*/
|
||||
bool readLights;
|
||||
|
||||
/** import animations (i.e. animation curves, the node
|
||||
* skeleton is always imported). Default value is true. */
|
||||
bool readAnimations;
|
||||
/** import animations (i.e. animation curves, the node
|
||||
* skeleton is always imported). Default value is true. */
|
||||
bool readAnimations;
|
||||
|
||||
/** read bones (vertex weights and deform info).
|
||||
* Default value is true. */
|
||||
bool readWeights;
|
||||
/** read bones (vertex weights and deform info).
|
||||
* Default value is true. */
|
||||
bool readWeights;
|
||||
|
||||
/** preserve transformation pivots and offsets. Since these can
|
||||
* not directly be represented in assimp, additional dummy
|
||||
* nodes will be generated. Note that settings this to false
|
||||
* can make animation import a lot slower. The default value
|
||||
* is true.
|
||||
*
|
||||
* The naming scheme for the generated nodes is:
|
||||
* <OriginalName>_$AssimpFbx$_<TransformName>
|
||||
*
|
||||
* where <TransformName> is one of
|
||||
* RotationPivot
|
||||
* RotationOffset
|
||||
* PreRotation
|
||||
* PostRotation
|
||||
* ScalingPivot
|
||||
* ScalingOffset
|
||||
* Translation
|
||||
* Scaling
|
||||
* Rotation
|
||||
**/
|
||||
bool preservePivots;
|
||||
/** preserve transformation pivots and offsets. Since these can
|
||||
* not directly be represented in assimp, additional dummy
|
||||
* nodes will be generated. Note that settings this to false
|
||||
* can make animation import a lot slower. The default value
|
||||
* is true.
|
||||
*
|
||||
* The naming scheme for the generated nodes is:
|
||||
* <OriginalName>_$AssimpFbx$_<TransformName>
|
||||
*
|
||||
* where <TransformName> is one of
|
||||
* RotationPivot
|
||||
* RotationOffset
|
||||
* PreRotation
|
||||
* PostRotation
|
||||
* ScalingPivot
|
||||
* ScalingOffset
|
||||
* Translation
|
||||
* Scaling
|
||||
* Rotation
|
||||
**/
|
||||
bool preservePivots;
|
||||
|
||||
/** do not import animation curves that specify a constant
|
||||
* values matching the corresponding node transformation.
|
||||
* The default value is true. */
|
||||
bool optimizeEmptyAnimationCurves;
|
||||
/** do not import animation curves that specify a constant
|
||||
* values matching the corresponding node transformation.
|
||||
* The default value is true. */
|
||||
bool optimizeEmptyAnimationCurves;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/assimp/Importer.hpp"
|
||||
|
||||
namespace Assimp {
|
||||
template<> const std::string LogFunctions<FBXImporter>::log_prefix = "FBX: ";
|
||||
template<> const std::string LogFunctions<FBXImporter>::log_prefix = "FBX: ";
|
||||
}
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -70,16 +70,16 @@ using namespace Assimp::FBX;
|
|||
|
||||
namespace {
|
||||
static const aiImporterDesc desc = {
|
||||
"Autodesk FBX Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"fbx"
|
||||
"Autodesk FBX Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"fbx"
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -98,24 +98,24 @@ FBXImporter::~FBXImporter()
|
|||
// Returns whether the class can handle the format of the given file.
|
||||
bool FBXImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
const std::string& extension = GetExtension(pFile);
|
||||
if (extension == "fbx") {
|
||||
return true;
|
||||
}
|
||||
const std::string& extension = GetExtension(pFile);
|
||||
if (extension == "fbx") {
|
||||
return true;
|
||||
}
|
||||
|
||||
else if ((!extension.length() || checkSig) && pIOHandler) {
|
||||
// at least ascii FBX files usually have a 'FBX' somewhere in their head
|
||||
const char* tokens[] = {"fbx"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
else if ((!extension.length() || checkSig) && pIOHandler) {
|
||||
// at least ascii FBX files usually have a 'FBX' somewhere in their head
|
||||
const char* tokens[] = {"fbx"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// List all extensions handled by this loader
|
||||
const aiImporterDesc* FBXImporter::GetInfo () const
|
||||
{
|
||||
return &desc;
|
||||
return &desc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,69 +123,69 @@ const aiImporterDesc* FBXImporter::GetInfo () const
|
|||
// Setup configuration properties for the loader
|
||||
void FBXImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void FBXImporter::InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
boost::scoped_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
|
||||
if (!stream) {
|
||||
ThrowException("Could not open file for reading");
|
||||
}
|
||||
boost::scoped_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
|
||||
if (!stream) {
|
||||
ThrowException("Could not open file for reading");
|
||||
}
|
||||
|
||||
// read entire file into memory - no streaming for this, fbx
|
||||
// files can grow large, but the assimp output data structure
|
||||
// then becomes very large, too. Assimp doesn't support
|
||||
// streaming for its output data structures so the net win with
|
||||
// streaming input data would be very low.
|
||||
std::vector<char> contents;
|
||||
contents.resize(stream->FileSize()+1);
|
||||
// read entire file into memory - no streaming for this, fbx
|
||||
// files can grow large, but the assimp output data structure
|
||||
// then becomes very large, too. Assimp doesn't support
|
||||
// streaming for its output data structures so the net win with
|
||||
// streaming input data would be very low.
|
||||
std::vector<char> contents;
|
||||
contents.resize(stream->FileSize()+1);
|
||||
stream->Read( &*contents.begin(), 1, contents.size()-1 );
|
||||
contents[ contents.size() - 1 ] = 0;
|
||||
const char* const begin = &*contents.begin();
|
||||
const char* const begin = &*contents.begin();
|
||||
|
||||
// broadphase tokenizing pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
// broadphase tokenizing pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin,"Kaydara FBX Binary",18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens,begin,contents.size());
|
||||
}
|
||||
else {
|
||||
Tokenize(tokens,begin);
|
||||
}
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin,"Kaydara FBX Binary",18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens,begin,contents.size());
|
||||
}
|
||||
else {
|
||||
Tokenize(tokens,begin);
|
||||
}
|
||||
|
||||
// use this information to construct a very rudimentary
|
||||
// parse-tree representing the FBX scope structure
|
||||
Parser parser(tokens, is_binary);
|
||||
// use this information to construct a very rudimentary
|
||||
// parse-tree representing the FBX scope structure
|
||||
Parser parser(tokens, is_binary);
|
||||
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser,settings);
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser,settings);
|
||||
|
||||
// convert the FBX DOM to aiScene
|
||||
ConvertToAssimpScene(pScene,doc);
|
||||
// convert the FBX DOM to aiScene
|
||||
ConvertToAssimpScene(pScene,doc);
|
||||
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
}
|
||||
catch(std::exception&) {
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
}
|
||||
catch(std::exception&) {
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||
|
|
|
@ -49,13 +49,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "FBXImportSettings.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
// TinyFormatter.h
|
||||
namespace Formatter {
|
||||
template <typename T,typename TR, typename A> class basic_formatter;
|
||||
typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
@ -67,38 +67,38 @@ namespace Assimp {
|
|||
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter>
|
||||
{
|
||||
public:
|
||||
FBXImporter();
|
||||
~FBXImporter();
|
||||
FBXImporter();
|
||||
~FBXImporter();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile,
|
||||
IOSystem* pIOHandler,
|
||||
bool checkSig
|
||||
) const;
|
||||
// --------------------
|
||||
bool CanRead( const std::string& pFile,
|
||||
IOSystem* pIOHandler,
|
||||
bool checkSig
|
||||
) const;
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
// --------------------
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
// --------------------
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler
|
||||
);
|
||||
// --------------------
|
||||
void InternReadFile( const std::string& pFile,
|
||||
aiScene* pScene,
|
||||
IOSystem* pIOHandler
|
||||
);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
private:
|
||||
|
||||
FBX::ImportSettings settings;
|
||||
FBX::ImportSettings settings;
|
||||
|
||||
}; // !class FBXImporter
|
||||
|
||||
|
|
|
@ -55,85 +55,85 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Material::Material(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const ShadingModel = sc["ShadingModel"];
|
||||
const Element* const MultiLayer = sc["MultiLayer"];
|
||||
const Element* const ShadingModel = sc["ShadingModel"];
|
||||
const Element* const MultiLayer = sc["MultiLayer"];
|
||||
|
||||
if(MultiLayer) {
|
||||
multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
|
||||
}
|
||||
if(MultiLayer) {
|
||||
multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
|
||||
}
|
||||
|
||||
if(ShadingModel) {
|
||||
shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
|
||||
}
|
||||
else {
|
||||
DOMWarning("shading mode not specified, assuming phong",&element);
|
||||
shading = "phong";
|
||||
}
|
||||
if(ShadingModel) {
|
||||
shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
|
||||
}
|
||||
else {
|
||||
DOMWarning("shading mode not specified, assuming phong",&element);
|
||||
shading = "phong";
|
||||
}
|
||||
|
||||
std::string templateName;
|
||||
std::string templateName;
|
||||
|
||||
const char* const sh = shading.c_str();
|
||||
if(!strcmp(sh,"phong")) {
|
||||
templateName = "Material.FbxSurfacePhong";
|
||||
}
|
||||
else if(!strcmp(sh,"lambert")) {
|
||||
templateName = "Material.FbxSurfaceLambert";
|
||||
}
|
||||
else {
|
||||
DOMWarning("shading mode not recognized: " + shading,&element);
|
||||
}
|
||||
const char* const sh = shading.c_str();
|
||||
if(!strcmp(sh,"phong")) {
|
||||
templateName = "Material.FbxSurfacePhong";
|
||||
}
|
||||
else if(!strcmp(sh,"lambert")) {
|
||||
templateName = "Material.FbxSurfaceLambert";
|
||||
}
|
||||
else {
|
||||
DOMWarning("shading mode not recognized: " + shading,&element);
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,templateName,element,sc);
|
||||
props = GetPropertyTable(doc,templateName,element,sc);
|
||||
|
||||
// resolve texture links
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
// resolve texture links
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
|
||||
// texture link to properties, not objects
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
// texture link to properties, not objects
|
||||
if (!con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture* const tex = dynamic_cast<const Texture*>(ob);
|
||||
if(!tex) {
|
||||
const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
|
||||
if(!layeredTexture) {
|
||||
DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const std::string& prop = con->PropertyName();
|
||||
if (layeredTextures.find(prop) != layeredTextures.end()) {
|
||||
DOMWarning("duplicate layered texture link: " + prop,&element);
|
||||
}
|
||||
const Texture* const tex = dynamic_cast<const Texture*>(ob);
|
||||
if(!tex) {
|
||||
const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
|
||||
if(!layeredTexture) {
|
||||
DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const std::string& prop = con->PropertyName();
|
||||
if (layeredTextures.find(prop) != layeredTextures.end()) {
|
||||
DOMWarning("duplicate layered texture link: " + prop,&element);
|
||||
}
|
||||
|
||||
layeredTextures[prop] = layeredTexture;
|
||||
((LayeredTexture*)layeredTexture)->fillTexture(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string& prop = con->PropertyName();
|
||||
if (textures.find(prop) != textures.end()) {
|
||||
DOMWarning("duplicate texture link: " + prop,&element);
|
||||
}
|
||||
layeredTextures[prop] = layeredTexture;
|
||||
((LayeredTexture*)layeredTexture)->fillTexture(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string& prop = con->PropertyName();
|
||||
if (textures.find(prop) != textures.end()) {
|
||||
DOMWarning("duplicate texture link: " + prop,&element);
|
||||
}
|
||||
|
||||
textures[prop] = tex;
|
||||
}
|
||||
textures[prop] = tex;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -148,57 +148,57 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const
|
|||
: Object(id,element,name)
|
||||
, uvScaling(1.0f,1.0f)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const Type = sc["Type"];
|
||||
const Element* const FileName = sc["FileName"];
|
||||
const Element* const RelativeFilename = sc["RelativeFilename"];
|
||||
const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
|
||||
const Element* const ModelUVScaling = sc["ModelUVScaling"];
|
||||
const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
|
||||
const Element* const Cropping = sc["Cropping"];
|
||||
const Element* const Type = sc["Type"];
|
||||
const Element* const FileName = sc["FileName"];
|
||||
const Element* const RelativeFilename = sc["RelativeFilename"];
|
||||
const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
|
||||
const Element* const ModelUVScaling = sc["ModelUVScaling"];
|
||||
const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
|
||||
const Element* const Cropping = sc["Cropping"];
|
||||
|
||||
if(Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(*Type,0));
|
||||
}
|
||||
if(Type) {
|
||||
type = ParseTokenAsString(GetRequiredToken(*Type,0));
|
||||
}
|
||||
|
||||
if(FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
|
||||
}
|
||||
if(FileName) {
|
||||
fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
|
||||
}
|
||||
|
||||
if(RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
|
||||
}
|
||||
if(RelativeFilename) {
|
||||
relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
|
||||
}
|
||||
|
||||
if(ModelUVTranslation) {
|
||||
uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
|
||||
);
|
||||
}
|
||||
if(ModelUVTranslation) {
|
||||
uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
|
||||
);
|
||||
}
|
||||
|
||||
if(ModelUVScaling) {
|
||||
uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
|
||||
);
|
||||
}
|
||||
if(ModelUVScaling) {
|
||||
uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
|
||||
ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
|
||||
);
|
||||
}
|
||||
|
||||
if(Cropping) {
|
||||
crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
|
||||
crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
|
||||
crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
|
||||
crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
|
||||
}
|
||||
else {
|
||||
// vc8 doesn't support the crop() syntax in initialization lists
|
||||
// (and vc9 WARNS about the new (i.e. compliant) behaviour).
|
||||
crop[0] = crop[1] = crop[2] = crop[3] = 0;
|
||||
}
|
||||
if(Cropping) {
|
||||
crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
|
||||
crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
|
||||
crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
|
||||
crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
|
||||
}
|
||||
else {
|
||||
// vc8 doesn't support the crop() syntax in initialization lists
|
||||
// (and vc9 WARNS about the new (i.e. compliant) behaviour).
|
||||
crop[0] = crop[1] = crop[2] = crop[3] = 0;
|
||||
}
|
||||
|
||||
if(Texture_Alpha_Source) {
|
||||
alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
|
||||
}
|
||||
if(Texture_Alpha_Source) {
|
||||
alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
|
||||
props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
|
||||
}
|
||||
|
||||
|
||||
|
@ -213,20 +213,20 @@ LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Docume
|
|||
,blendMode(BlendMode_Modulate)
|
||||
,alpha(1)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const Element* const BlendModes = sc["BlendModes"];
|
||||
const Element* const Alphas = sc["Alphas"];
|
||||
const Element* const BlendModes = sc["BlendModes"];
|
||||
const Element* const Alphas = sc["Alphas"];
|
||||
|
||||
|
||||
if(BlendModes!=0)
|
||||
{
|
||||
blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
|
||||
}
|
||||
if(Alphas!=0)
|
||||
{
|
||||
alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
|
||||
}
|
||||
if(BlendModes!=0)
|
||||
{
|
||||
blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
|
||||
}
|
||||
if(Alphas!=0)
|
||||
{
|
||||
alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
|
||||
}
|
||||
}
|
||||
|
||||
LayeredTexture::~LayeredTexture()
|
||||
|
@ -236,21 +236,21 @@ LayeredTexture::~LayeredTexture()
|
|||
|
||||
void LayeredTexture::fillTexture(const Document& doc)
|
||||
{
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for(size_t i = 0; i < conns.size();++i)
|
||||
{
|
||||
const Connection* con = conns.at(i);
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||
for(size_t i = 0; i < conns.size();++i)
|
||||
{
|
||||
const Connection* con = conns.at(i);
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Texture* const tex = dynamic_cast<const Texture*>(ob);
|
||||
const Texture* const tex = dynamic_cast<const Texture*>(ob);
|
||||
|
||||
texture = tex;
|
||||
}
|
||||
texture = tex;
|
||||
}
|
||||
}
|
||||
|
||||
} //!FBX
|
||||
|
|
|
@ -57,22 +57,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
using namespace Util;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Object(id, element,name)
|
||||
, skin()
|
||||
: Object(id, element,name)
|
||||
, skin()
|
||||
{
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if(sk) {
|
||||
skin = sk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
|
||||
if(sk) {
|
||||
skin = sk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -88,98 +88,98 @@ Geometry::~Geometry()
|
|||
MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Geometry(id, element,name, doc)
|
||||
{
|
||||
const Scope* sc = element.Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Mesh), no data scope found");
|
||||
}
|
||||
const Scope* sc = element.Compound();
|
||||
if (!sc) {
|
||||
DOMError("failed to read Geometry object (class: Mesh), no data scope found");
|
||||
}
|
||||
|
||||
// must have Mesh elements:
|
||||
const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
|
||||
const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
|
||||
// must have Mesh elements:
|
||||
const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
|
||||
const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
|
||||
|
||||
// optional Mesh elements:
|
||||
const ElementCollection& Layer = sc->GetCollection("Layer");
|
||||
// optional Mesh elements:
|
||||
const ElementCollection& Layer = sc->GetCollection("Layer");
|
||||
|
||||
std::vector<aiVector3D> tempVerts;
|
||||
ParseVectorDataArray(tempVerts,Vertices);
|
||||
std::vector<aiVector3D> tempVerts;
|
||||
ParseVectorDataArray(tempVerts,Vertices);
|
||||
|
||||
if(tempVerts.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no vertices");
|
||||
return;
|
||||
}
|
||||
if(tempVerts.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no vertices");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<int> tempFaces;
|
||||
ParseVectorDataArray(tempFaces,PolygonVertexIndex);
|
||||
std::vector<int> tempFaces;
|
||||
ParseVectorDataArray(tempFaces,PolygonVertexIndex);
|
||||
|
||||
if(tempFaces.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no faces");
|
||||
return;
|
||||
}
|
||||
if(tempFaces.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no faces");
|
||||
return;
|
||||
}
|
||||
|
||||
vertices.reserve(tempFaces.size());
|
||||
faces.reserve(tempFaces.size() / 3);
|
||||
vertices.reserve(tempFaces.size());
|
||||
faces.reserve(tempFaces.size() / 3);
|
||||
|
||||
mapping_offsets.resize(tempVerts.size());
|
||||
mapping_counts.resize(tempVerts.size(),0);
|
||||
mappings.resize(tempFaces.size());
|
||||
mapping_offsets.resize(tempVerts.size());
|
||||
mapping_counts.resize(tempVerts.size(),0);
|
||||
mappings.resize(tempFaces.size());
|
||||
|
||||
const size_t vertex_count = tempVerts.size();
|
||||
const size_t vertex_count = tempVerts.size();
|
||||
|
||||
// generate output vertices, computing an adjacency table to
|
||||
// preserve the mapping from fbx indices to *this* indexing.
|
||||
unsigned int count = 0;
|
||||
BOOST_FOREACH(int index, tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
if(static_cast<size_t>(absi) >= vertex_count) {
|
||||
DOMError("polygon vertex index out of range",&PolygonVertexIndex);
|
||||
}
|
||||
// generate output vertices, computing an adjacency table to
|
||||
// preserve the mapping from fbx indices to *this* indexing.
|
||||
unsigned int count = 0;
|
||||
BOOST_FOREACH(int index, tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
if(static_cast<size_t>(absi) >= vertex_count) {
|
||||
DOMError("polygon vertex index out of range",&PolygonVertexIndex);
|
||||
}
|
||||
|
||||
vertices.push_back(tempVerts[absi]);
|
||||
++count;
|
||||
vertices.push_back(tempVerts[absi]);
|
||||
++count;
|
||||
|
||||
++mapping_counts[absi];
|
||||
++mapping_counts[absi];
|
||||
|
||||
if (index < 0) {
|
||||
faces.push_back(count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
if (index < 0) {
|
||||
faces.push_back(count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int cursor = 0;
|
||||
for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
|
||||
mapping_offsets[i] = cursor;
|
||||
cursor += mapping_counts[i];
|
||||
unsigned int cursor = 0;
|
||||
for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
|
||||
mapping_offsets[i] = cursor;
|
||||
cursor += mapping_counts[i];
|
||||
|
||||
mapping_counts[i] = 0;
|
||||
}
|
||||
mapping_counts[i] = 0;
|
||||
}
|
||||
|
||||
cursor = 0;
|
||||
BOOST_FOREACH(int index, tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
mappings[mapping_offsets[absi] + mapping_counts[absi]++] = cursor++;
|
||||
}
|
||||
cursor = 0;
|
||||
BOOST_FOREACH(int index, tempFaces) {
|
||||
const int absi = index < 0 ? (-index - 1) : index;
|
||||
mappings[mapping_offsets[absi] + mapping_counts[absi]++] = cursor++;
|
||||
}
|
||||
|
||||
// if settings.readAllLayers is true:
|
||||
// * read all layers, try to load as many vertex channels as possible
|
||||
// if settings.readAllLayers is false:
|
||||
// * read only the layer with index 0, but warn about any further layers
|
||||
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
|
||||
const TokenList& tokens = (*it).second->Tokens();
|
||||
// if settings.readAllLayers is true:
|
||||
// * read all layers, try to load as many vertex channels as possible
|
||||
// if settings.readAllLayers is false:
|
||||
// * read only the layer with index 0, but warn about any further layers
|
||||
for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
|
||||
const TokenList& tokens = (*it).second->Tokens();
|
||||
|
||||
const char* err;
|
||||
const int index = ParseTokenAsInt(*tokens[0], err);
|
||||
if(err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
const char* err;
|
||||
const int index = ParseTokenAsInt(*tokens[0], err);
|
||||
if(err) {
|
||||
DOMError(err,&element);
|
||||
}
|
||||
|
||||
if(doc.Settings().readAllLayers || index == 0) {
|
||||
const Scope& layer = GetRequiredScope(*(*it).second);
|
||||
ReadLayer(layer);
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogWarn("ignoring additional geometry layers");
|
||||
}
|
||||
}
|
||||
if(doc.Settings().readAllLayers || index == 0) {
|
||||
const Scope& layer = GetRequiredScope(*(*it).second);
|
||||
ReadLayer(layer);
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogWarn("ignoring additional geometry layers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,141 +194,141 @@ MeshGeometry::~MeshGeometry()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadLayer(const Scope& layer)
|
||||
{
|
||||
const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
|
||||
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
||||
const Scope& elayer = GetRequiredScope(*(*eit).second);
|
||||
const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
|
||||
for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
|
||||
const Scope& elayer = GetRequiredScope(*(*eit).second);
|
||||
|
||||
ReadLayerElement(elayer);
|
||||
}
|
||||
ReadLayerElement(elayer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadLayerElement(const Scope& layerElement)
|
||||
{
|
||||
const Element& Type = GetRequiredElement(layerElement,"Type");
|
||||
const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
|
||||
const Element& Type = GetRequiredElement(layerElement,"Type");
|
||||
const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
|
||||
|
||||
const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
|
||||
const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
|
||||
const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
|
||||
|
||||
const Scope& top = GetRequiredScope(element);
|
||||
const ElementCollection candidates = top.GetCollection(type);
|
||||
const Scope& top = GetRequiredScope(element);
|
||||
const ElementCollection candidates = top.GetCollection(type);
|
||||
|
||||
for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
|
||||
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
|
||||
if(index == typedIndex) {
|
||||
ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
|
||||
const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
|
||||
if(index == typedIndex) {
|
||||
ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
|
||||
<< type << ", index: " << typedIndex);
|
||||
FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
|
||||
<< type << ", index: " << typedIndex);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
|
||||
{
|
||||
const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"MappingInformationType"),0)
|
||||
);
|
||||
const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"MappingInformationType"),0)
|
||||
);
|
||||
|
||||
const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"ReferenceInformationType"),0)
|
||||
);
|
||||
const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
|
||||
GetRequiredElement(source,"ReferenceInformationType"),0)
|
||||
);
|
||||
|
||||
if (type == "LayerElementUV") {
|
||||
if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||
FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
|
||||
return;
|
||||
}
|
||||
if (type == "LayerElementUV") {
|
||||
if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||
FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
|
||||
return;
|
||||
}
|
||||
|
||||
const Element* Name = source["Name"];
|
||||
uvNames[index] = "";
|
||||
if(Name) {
|
||||
uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
|
||||
}
|
||||
const Element* Name = source["Name"];
|
||||
uvNames[index] = "";
|
||||
if(Name) {
|
||||
uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
|
||||
}
|
||||
|
||||
ReadVertexDataUV(uvs[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementMaterial") {
|
||||
if (materials.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional material layer");
|
||||
return;
|
||||
}
|
||||
ReadVertexDataUV(uvs[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementMaterial") {
|
||||
if (materials.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional material layer");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<int> temp_materials;
|
||||
std::vector<int> temp_materials;
|
||||
|
||||
ReadVertexDataMaterials(temp_materials,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
ReadVertexDataMaterials(temp_materials,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
|
||||
// sometimes, there will be only negative entries. Drop the material
|
||||
// layer in such a case (I guess it means a default material should
|
||||
// be used). This is what the converter would do anyway, and it
|
||||
// avoids loosing the material if there are more material layers
|
||||
// coming of which at least one contains actual data (did observe
|
||||
// that with one test file).
|
||||
const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less<int>(),0));
|
||||
if(count_neg == temp_materials.size()) {
|
||||
FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
|
||||
return;
|
||||
}
|
||||
// sometimes, there will be only negative entries. Drop the material
|
||||
// layer in such a case (I guess it means a default material should
|
||||
// be used). This is what the converter would do anyway, and it
|
||||
// avoids loosing the material if there are more material layers
|
||||
// coming of which at least one contains actual data (did observe
|
||||
// that with one test file).
|
||||
const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less<int>(),0));
|
||||
if(count_neg == temp_materials.size()) {
|
||||
FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
|
||||
return;
|
||||
}
|
||||
|
||||
std::swap(temp_materials, materials);
|
||||
}
|
||||
else if (type == "LayerElementNormal") {
|
||||
if (normals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional normal layer");
|
||||
return;
|
||||
}
|
||||
std::swap(temp_materials, materials);
|
||||
}
|
||||
else if (type == "LayerElementNormal") {
|
||||
if (normals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional normal layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataNormals(normals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementTangent") {
|
||||
if (tangents.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional tangent layer");
|
||||
return;
|
||||
}
|
||||
ReadVertexDataNormals(normals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementTangent") {
|
||||
if (tangents.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional tangent layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataTangents(tangents,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementBinormal") {
|
||||
if (binormals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional binormal layer");
|
||||
return;
|
||||
}
|
||||
ReadVertexDataTangents(tangents,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementBinormal") {
|
||||
if (binormals.size() > 0) {
|
||||
FBXImporter::LogError("ignoring additional binormal layer");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataBinormals(binormals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementColor") {
|
||||
if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
||||
FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
|
||||
return;
|
||||
}
|
||||
ReadVertexDataBinormals(binormals,source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
else if (type == "LayerElementColor") {
|
||||
if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
|
||||
FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
|
||||
<< index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
|
||||
return;
|
||||
}
|
||||
|
||||
ReadVertexDataColors(colors[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
ReadVertexDataColors(colors[index],source,
|
||||
MappingInformationType,
|
||||
ReferenceInformationType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -338,201 +338,201 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
|
|||
// tangents ..
|
||||
template <typename T>
|
||||
void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType,
|
||||
const char* dataElementName,
|
||||
const char* indexDataElementName,
|
||||
size_t vertex_count,
|
||||
const std::vector<unsigned int>& mapping_counts,
|
||||
const std::vector<unsigned int>& mapping_offsets,
|
||||
const std::vector<unsigned int>& mappings)
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType,
|
||||
const char* dataElementName,
|
||||
const char* indexDataElementName,
|
||||
size_t vertex_count,
|
||||
const std::vector<unsigned int>& mapping_counts,
|
||||
const std::vector<unsigned int>& mapping_offsets,
|
||||
const std::vector<unsigned int>& mappings)
|
||||
{
|
||||
std::vector<T> tempUV;
|
||||
ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
|
||||
std::vector<T> tempUV;
|
||||
ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
|
||||
|
||||
// handle permutations of Mapping and Reference type - it would be nice to
|
||||
// deal with this more elegantly and with less redundancy, but right
|
||||
// now it seems unavoidable.
|
||||
if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
|
||||
data_out.resize(vertex_count);
|
||||
for (size_t i = 0, e = tempUV.size(); i < e; ++i) {
|
||||
// handle permutations of Mapping and Reference type - it would be nice to
|
||||
// deal with this more elegantly and with less redundancy, but right
|
||||
// now it seems unavoidable.
|
||||
if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
|
||||
data_out.resize(vertex_count);
|
||||
for (size_t i = 0, e = tempUV.size(); i < e; ++i) {
|
||||
|
||||
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
|
||||
for (unsigned int j = istart; j < iend; ++j) {
|
||||
data_out[mappings[j]] = tempUV[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
|
||||
data_out.resize(vertex_count);
|
||||
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
|
||||
for (unsigned int j = istart; j < iend; ++j) {
|
||||
data_out[mappings[j]] = tempUV[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
|
||||
data_out.resize(vertex_count);
|
||||
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
|
||||
for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
|
||||
for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
|
||||
|
||||
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
|
||||
for (unsigned int j = istart; j < iend; ++j) {
|
||||
if(static_cast<size_t>(uvIndices[i]) >= tempUV.size()) {
|
||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||
}
|
||||
data_out[mappings[j]] = tempUV[uvIndices[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
|
||||
if (tempUV.size() != vertex_count) {
|
||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||
<< tempUV.size() << ", expected " << vertex_count
|
||||
);
|
||||
return;
|
||||
}
|
||||
const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
|
||||
for (unsigned int j = istart; j < iend; ++j) {
|
||||
if(static_cast<size_t>(uvIndices[i]) >= tempUV.size()) {
|
||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||
}
|
||||
data_out[mappings[j]] = tempUV[uvIndices[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
|
||||
if (tempUV.size() != vertex_count) {
|
||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||
<< tempUV.size() << ", expected " << vertex_count
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
data_out.swap(tempUV);
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
|
||||
data_out.resize(vertex_count);
|
||||
data_out.swap(tempUV);
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
|
||||
data_out.resize(vertex_count);
|
||||
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
std::vector<int> uvIndices;
|
||||
ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
|
||||
|
||||
if (uvIndices.size() != vertex_count) {
|
||||
FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
|
||||
return;
|
||||
}
|
||||
if (uvIndices.size() != vertex_count) {
|
||||
FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int next = 0;
|
||||
BOOST_FOREACH(int i, uvIndices) {
|
||||
if(static_cast<size_t>(i) >= tempUV.size()) {
|
||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||
}
|
||||
unsigned int next = 0;
|
||||
BOOST_FOREACH(int i, uvIndices) {
|
||||
if(static_cast<size_t>(i) >= tempUV.size()) {
|
||||
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
|
||||
}
|
||||
|
||||
data_out[next++] = tempUV[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
data_out[next++] = tempUV[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Normals",
|
||||
"NormalsIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Normals",
|
||||
"NormalsIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"UV",
|
||||
"UVIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"UV",
|
||||
"UVIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Colors",
|
||||
"ColorIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
|
||||
"Colors",
|
||||
"ColorIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
|
||||
ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
"TangentIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
|
||||
ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
"TangentIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
|
||||
ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
"BinormalIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
|
||||
ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
|
||||
str,
|
||||
"BinormalIndex",
|
||||
vertices.size(),
|
||||
mapping_counts,
|
||||
mapping_offsets,
|
||||
mappings);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source,
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
const std::string& MappingInformationType,
|
||||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const size_t face_count = faces.size();
|
||||
ai_assert(face_count);
|
||||
const size_t face_count = faces.size();
|
||||
ai_assert(face_count);
|
||||
|
||||
// materials are handled separately. First of all, they are assigned per-face
|
||||
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
||||
// has a slightly different meaning for materials.
|
||||
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
|
||||
// materials are handled separately. First of all, they are assigned per-face
|
||||
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
||||
// has a slightly different meaning for materials.
|
||||
ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
|
||||
|
||||
if (MappingInformationType == "AllSame") {
|
||||
// easy - same material for all faces
|
||||
if (materials_out.empty()) {
|
||||
FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
|
||||
return;
|
||||
}
|
||||
else if (materials_out.size() > 1) {
|
||||
FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
|
||||
materials_out.clear();
|
||||
}
|
||||
if (MappingInformationType == "AllSame") {
|
||||
// easy - same material for all faces
|
||||
if (materials_out.empty()) {
|
||||
FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
|
||||
return;
|
||||
}
|
||||
else if (materials_out.size() > 1) {
|
||||
FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
|
||||
materials_out.clear();
|
||||
}
|
||||
|
||||
materials.assign(vertices.size(),materials_out[0]);
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
|
||||
materials.resize(face_count);
|
||||
materials.assign(vertices.size(),materials_out[0]);
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
|
||||
materials.resize(face_count);
|
||||
|
||||
if(materials_out.size() != face_count) {
|
||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||
<< materials_out.size() << ", expected " << face_count
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
if(materials_out.size() != face_count) {
|
||||
FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
|
||||
<< materials_out.size() << ", expected " << face_count
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
}
|
||||
|
||||
} // !FBX
|
||||
|
|
|
@ -55,27 +55,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Model::Model(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
, shading("Y")
|
||||
: Object(id,element,name)
|
||||
, shading("Y")
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element* const Shading = sc["Shading"];
|
||||
const Element* const Culling = sc["Culling"];
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element* const Shading = sc["Shading"];
|
||||
const Element* const Culling = sc["Culling"];
|
||||
|
||||
if(Shading) {
|
||||
shading = GetRequiredToken(*Shading,0).StringContents();
|
||||
}
|
||||
if(Shading) {
|
||||
shading = GetRequiredToken(*Shading,0).StringContents();
|
||||
}
|
||||
|
||||
if (Culling) {
|
||||
culling = ParseTokenAsString(GetRequiredToken(*Culling,0));
|
||||
}
|
||||
if (Culling) {
|
||||
culling = ParseTokenAsString(GetRequiredToken(*Culling,0));
|
||||
}
|
||||
|
||||
props = GetPropertyTable(doc,"Model.FbxNode",element,sc);
|
||||
ResolveLinks(element,doc);
|
||||
props = GetPropertyTable(doc,"Model.FbxNode",element,sc);
|
||||
ResolveLinks(element,doc);
|
||||
}
|
||||
|
||||
|
||||
|
@ -89,64 +89,64 @@ Model::~Model()
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void Model::ResolveLinks(const Element& element, const Document& doc)
|
||||
{
|
||||
const char* const arr[] = {"Geometry","Material","NodeAttribute"};
|
||||
const char* const arr[] = {"Geometry","Material","NodeAttribute"};
|
||||
|
||||
// resolve material
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3);
|
||||
// resolve material
|
||||
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3);
|
||||
|
||||
materials.reserve(conns.size());
|
||||
geometry.reserve(conns.size());
|
||||
attributes.reserve(conns.size());
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
materials.reserve(conns.size());
|
||||
geometry.reserve(conns.size());
|
||||
attributes.reserve(conns.size());
|
||||
BOOST_FOREACH(const Connection* con, conns) {
|
||||
|
||||
// material and geometry links should be Object-Object connections
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
// material and geometry links should be Object-Object connections
|
||||
if (con->PropertyName().length()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
const Object* const ob = con->SourceObject();
|
||||
if(!ob) {
|
||||
DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Material* const mat = dynamic_cast<const Material*>(ob);
|
||||
if(mat) {
|
||||
materials.push_back(mat);
|
||||
continue;
|
||||
}
|
||||
const Material* const mat = dynamic_cast<const Material*>(ob);
|
||||
if(mat) {
|
||||
materials.push_back(mat);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Geometry* const geo = dynamic_cast<const Geometry*>(ob);
|
||||
if(geo) {
|
||||
geometry.push_back(geo);
|
||||
continue;
|
||||
}
|
||||
const Geometry* const geo = dynamic_cast<const Geometry*>(ob);
|
||||
if(geo) {
|
||||
geometry.push_back(geo);
|
||||
continue;
|
||||
}
|
||||
|
||||
const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob);
|
||||
if(att) {
|
||||
attributes.push_back(att);
|
||||
continue;
|
||||
}
|
||||
const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob);
|
||||
if(att) {
|
||||
attributes.push_back(att);
|
||||
continue;
|
||||
}
|
||||
|
||||
DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Model::IsNull() const
|
||||
{
|
||||
const std::vector<const NodeAttribute*>& attrs = GetAttributes();
|
||||
BOOST_FOREACH(const NodeAttribute* att, attrs) {
|
||||
const std::vector<const NodeAttribute*>& attrs = GetAttributes();
|
||||
BOOST_FOREACH(const NodeAttribute* att, attrs) {
|
||||
|
||||
const Null* null_tag = dynamic_cast<const Null*>(att);
|
||||
if(null_tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const Null* null_tag = dynamic_cast<const Null*>(att);
|
||||
if(null_tag) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,21 +54,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: Object(id,element,name)
|
||||
: Object(id,element,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
|
||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
||||
const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
|
||||
|
||||
// hack on the deriving type but Null/LimbNode attributes are the only case in which
|
||||
// the property table is by design absent and no warning should be generated
|
||||
// for it.
|
||||
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
|
||||
props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
|
||||
// hack on the deriving type but Null/LimbNode attributes are the only case in which
|
||||
// the property table is by design absent and no warning should be generated
|
||||
// for it.
|
||||
const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
|
||||
props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,24 +81,24 @@ NodeAttribute::~NodeAttribute()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||
: NodeAttribute(id,element,doc,name)
|
||||
: NodeAttribute(id,element,doc,name)
|
||||
{
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element* const CameraId = sc["CameraId"];
|
||||
const Element* const CameraName = sc["CameraName"];
|
||||
const Element* const CameraIndexName = sc["CameraIndexName"];
|
||||
const Scope& sc = GetRequiredScope(element);
|
||||
const Element* const CameraId = sc["CameraId"];
|
||||
const Element* const CameraName = sc["CameraName"];
|
||||
const Element* const CameraIndexName = sc["CameraIndexName"];
|
||||
|
||||
if(CameraId) {
|
||||
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
|
||||
}
|
||||
if(CameraId) {
|
||||
cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
|
||||
}
|
||||
|
||||
if(CameraName) {
|
||||
cameraName = GetRequiredToken(*CameraName,0).StringContents();
|
||||
}
|
||||
if(CameraName) {
|
||||
cameraName = GetRequiredToken(*CameraName,0).StringContents();
|
||||
}
|
||||
|
||||
if(CameraIndexName && CameraIndexName->Tokens().size()) {
|
||||
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
|
||||
}
|
||||
if(CameraIndexName && CameraIndexName->Tokens().size()) {
|
||||
cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
1586
code/FBXParser.cpp
1586
code/FBXParser.cpp
File diff suppressed because it is too large
Load Diff
112
code/FBXParser.h
112
code/FBXParser.h
|
@ -60,18 +60,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
class Scope;
|
||||
class Parser;
|
||||
class Element;
|
||||
class Scope;
|
||||
class Parser;
|
||||
class Element;
|
||||
|
||||
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
|
||||
typedef std::vector< Scope* > ScopeList;
|
||||
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
|
||||
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
|
||||
typedef std::vector< Scope* > ScopeList;
|
||||
typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
|
||||
|
||||
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
|
||||
typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
|
||||
|
||||
# define new_Scope new Scope
|
||||
# define new_Element new Element
|
||||
# define new_Scope new Scope
|
||||
# define new_Element new Element
|
||||
|
||||
|
||||
/** FBX data entity that consists of a key:value tuple.
|
||||
|
@ -89,28 +89,28 @@ class Element
|
|||
{
|
||||
public:
|
||||
|
||||
Element(const Token& key_token, Parser& parser);
|
||||
~Element();
|
||||
Element(const Token& key_token, Parser& parser);
|
||||
~Element();
|
||||
|
||||
public:
|
||||
|
||||
const Scope* Compound() const {
|
||||
return compound.get();
|
||||
}
|
||||
const Scope* Compound() const {
|
||||
return compound.get();
|
||||
}
|
||||
|
||||
const Token& KeyToken() const {
|
||||
return key_token;
|
||||
}
|
||||
const Token& KeyToken() const {
|
||||
return key_token;
|
||||
}
|
||||
|
||||
const TokenList& Tokens() const {
|
||||
return tokens;
|
||||
}
|
||||
const TokenList& Tokens() const {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const Token& key_token;
|
||||
TokenList tokens;
|
||||
boost::scoped_ptr<Scope> compound;
|
||||
const Token& key_token;
|
||||
TokenList tokens;
|
||||
boost::scoped_ptr<Scope> compound;
|
||||
};
|
||||
|
||||
|
||||
|
@ -131,27 +131,27 @@ class Scope
|
|||
|
||||
public:
|
||||
|
||||
Scope(Parser& parser, bool topLevel = false);
|
||||
~Scope();
|
||||
Scope(Parser& parser, bool topLevel = false);
|
||||
~Scope();
|
||||
|
||||
public:
|
||||
|
||||
const Element* operator[] (const std::string& index) const {
|
||||
ElementMap::const_iterator it = elements.find(index);
|
||||
return it == elements.end() ? NULL : (*it).second;
|
||||
}
|
||||
const Element* operator[] (const std::string& index) const {
|
||||
ElementMap::const_iterator it = elements.find(index);
|
||||
return it == elements.end() ? NULL : (*it).second;
|
||||
}
|
||||
|
||||
ElementCollection GetCollection(const std::string& index) const {
|
||||
return elements.equal_range(index);
|
||||
}
|
||||
ElementCollection GetCollection(const std::string& index) const {
|
||||
return elements.equal_range(index);
|
||||
}
|
||||
|
||||
const ElementMap& Elements() const {
|
||||
return elements;
|
||||
}
|
||||
const ElementMap& Elements() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ElementMap elements;
|
||||
ElementMap elements;
|
||||
};
|
||||
|
||||
|
||||
|
@ -161,43 +161,43 @@ class Parser
|
|||
{
|
||||
public:
|
||||
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser (const TokenList& tokens,bool is_binary);
|
||||
~Parser();
|
||||
/** Parse given a token list. Does not take ownership of the tokens -
|
||||
* the objects must persist during the entire parser lifetime */
|
||||
Parser (const TokenList& tokens,bool is_binary);
|
||||
~Parser();
|
||||
|
||||
public:
|
||||
|
||||
const Scope& GetRootScope() const {
|
||||
return *root.get();
|
||||
}
|
||||
const Scope& GetRootScope() const {
|
||||
return *root.get();
|
||||
}
|
||||
|
||||
|
||||
bool IsBinary() const {
|
||||
return is_binary;
|
||||
}
|
||||
bool IsBinary() const {
|
||||
return is_binary;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
friend class Scope;
|
||||
friend class Element;
|
||||
|
||||
TokenPtr AdvanceToNextToken();
|
||||
TokenPtr AdvanceToNextToken();
|
||||
|
||||
TokenPtr LastToken() const;
|
||||
TokenPtr CurrentToken() const;
|
||||
TokenPtr LastToken() const;
|
||||
TokenPtr CurrentToken() const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
const TokenList& tokens;
|
||||
const TokenList& tokens;
|
||||
|
||||
TokenPtr last, current;
|
||||
TokenList::const_iterator cursor;
|
||||
boost::scoped_ptr<Scope> root;
|
||||
TokenPtr last, current;
|
||||
TokenList::const_iterator cursor;
|
||||
boost::scoped_ptr<Scope> root;
|
||||
|
||||
const bool is_binary;
|
||||
const bool is_binary;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
using namespace Util;
|
||||
using namespace Util;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Property::Property()
|
||||
|
@ -72,46 +72,46 @@ namespace {
|
|||
// read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
|
||||
Property* ReadTypedProperty(const Element& element)
|
||||
{
|
||||
ai_assert(element.KeyToken().StringContents() == "P");
|
||||
ai_assert(element.KeyToken().StringContents() == "P");
|
||||
|
||||
const TokenList& tok = element.Tokens();
|
||||
ai_assert(tok.size() >= 5);
|
||||
const TokenList& tok = element.Tokens();
|
||||
ai_assert(tok.size() >= 5);
|
||||
|
||||
const std::string& s = ParseTokenAsString(*tok[1]);
|
||||
const char* const cs = s.c_str();
|
||||
if (!strcmp(cs,"KString")) {
|
||||
return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
|
||||
return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
|
||||
}
|
||||
else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
|
||||
return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs, "ULongLong")) {
|
||||
return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs, "KTime")) {
|
||||
return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs,"Vector3D") ||
|
||||
!strcmp(cs,"ColorRGB") ||
|
||||
!strcmp(cs,"Vector") ||
|
||||
!strcmp(cs,"Color") ||
|
||||
!strcmp(cs,"Lcl Translation") ||
|
||||
!strcmp(cs,"Lcl Rotation") ||
|
||||
!strcmp(cs,"Lcl Scaling")
|
||||
) {
|
||||
return new TypedProperty<aiVector3D>(aiVector3D(
|
||||
ParseTokenAsFloat(*tok[4]),
|
||||
ParseTokenAsFloat(*tok[5]),
|
||||
ParseTokenAsFloat(*tok[6]))
|
||||
);
|
||||
}
|
||||
else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) {
|
||||
return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
|
||||
}
|
||||
return NULL;
|
||||
const std::string& s = ParseTokenAsString(*tok[1]);
|
||||
const char* const cs = s.c_str();
|
||||
if (!strcmp(cs,"KString")) {
|
||||
return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
|
||||
return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
|
||||
}
|
||||
else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
|
||||
return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs, "ULongLong")) {
|
||||
return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs, "KTime")) {
|
||||
return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
|
||||
}
|
||||
else if (!strcmp(cs,"Vector3D") ||
|
||||
!strcmp(cs,"ColorRGB") ||
|
||||
!strcmp(cs,"Vector") ||
|
||||
!strcmp(cs,"Color") ||
|
||||
!strcmp(cs,"Lcl Translation") ||
|
||||
!strcmp(cs,"Lcl Rotation") ||
|
||||
!strcmp(cs,"Lcl Scaling")
|
||||
) {
|
||||
return new TypedProperty<aiVector3D>(aiVector3D(
|
||||
ParseTokenAsFloat(*tok[4]),
|
||||
ParseTokenAsFloat(*tok[5]),
|
||||
ParseTokenAsFloat(*tok[6]))
|
||||
);
|
||||
}
|
||||
else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView")) {
|
||||
return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,13 +119,13 @@ Property* ReadTypedProperty(const Element& element)
|
|||
// peek into an element and check if it contains a FBX property, if so return its name.
|
||||
std::string PeekPropertyName(const Element& element)
|
||||
{
|
||||
ai_assert(element.KeyToken().StringContents() == "P");
|
||||
const TokenList& tok = element.Tokens();
|
||||
if(tok.size() < 4) {
|
||||
return "";
|
||||
}
|
||||
ai_assert(element.KeyToken().StringContents() == "P");
|
||||
const TokenList& tok = element.Tokens();
|
||||
if(tok.size() < 4) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return ParseTokenAsString(*tok[0]);
|
||||
return ParseTokenAsString(*tok[0]);
|
||||
}
|
||||
|
||||
} //! anon
|
||||
|
@ -144,89 +144,89 @@ PropertyTable::PropertyTable(const Element& element, boost::shared_ptr<const Pro
|
|||
: templateProps(templateProps)
|
||||
, element(&element)
|
||||
{
|
||||
const Scope& scope = GetRequiredScope(element);
|
||||
BOOST_FOREACH(const ElementMap::value_type& v, scope.Elements()) {
|
||||
if(v.first != "P") {
|
||||
DOMWarning("expected only P elements in property table",v.second);
|
||||
continue;
|
||||
}
|
||||
const Scope& scope = GetRequiredScope(element);
|
||||
BOOST_FOREACH(const ElementMap::value_type& v, scope.Elements()) {
|
||||
if(v.first != "P") {
|
||||
DOMWarning("expected only P elements in property table",v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string& name = PeekPropertyName(*v.second);
|
||||
if(!name.length()) {
|
||||
DOMWarning("could not read property name",v.second);
|
||||
continue;
|
||||
}
|
||||
const std::string& name = PeekPropertyName(*v.second);
|
||||
if(!name.length()) {
|
||||
DOMWarning("could not read property name",v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
LazyPropertyMap::const_iterator it = lazyProps.find(name);
|
||||
if (it != lazyProps.end()) {
|
||||
DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
|
||||
continue;
|
||||
}
|
||||
LazyPropertyMap::const_iterator it = lazyProps.find(name);
|
||||
if (it != lazyProps.end()) {
|
||||
DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
lazyProps[name] = v.second;
|
||||
}
|
||||
lazyProps[name] = v.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
PropertyTable::~PropertyTable()
|
||||
{
|
||||
BOOST_FOREACH(PropertyMap::value_type& v, props) {
|
||||
delete v.second;
|
||||
}
|
||||
BOOST_FOREACH(PropertyMap::value_type& v, props) {
|
||||
delete v.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const Property* PropertyTable::Get(const std::string& name) const
|
||||
{
|
||||
PropertyMap::const_iterator it = props.find(name);
|
||||
if (it == props.end()) {
|
||||
// hasn't been parsed yet?
|
||||
LazyPropertyMap::const_iterator lit = lazyProps.find(name);
|
||||
if(lit != lazyProps.end()) {
|
||||
props[name] = ReadTypedProperty(*(*lit).second);
|
||||
it = props.find(name);
|
||||
PropertyMap::const_iterator it = props.find(name);
|
||||
if (it == props.end()) {
|
||||
// hasn't been parsed yet?
|
||||
LazyPropertyMap::const_iterator lit = lazyProps.find(name);
|
||||
if(lit != lazyProps.end()) {
|
||||
props[name] = ReadTypedProperty(*(*lit).second);
|
||||
it = props.find(name);
|
||||
|
||||
ai_assert(it != props.end());
|
||||
}
|
||||
ai_assert(it != props.end());
|
||||
}
|
||||
|
||||
if (it == props.end()) {
|
||||
// check property template
|
||||
if(templateProps) {
|
||||
return templateProps->Get(name);
|
||||
}
|
||||
if (it == props.end()) {
|
||||
// check property template
|
||||
if(templateProps) {
|
||||
return templateProps->Get(name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
DirectPropertyMap PropertyTable::GetUnparsedProperties() const
|
||||
{
|
||||
DirectPropertyMap result;
|
||||
DirectPropertyMap result;
|
||||
|
||||
// Loop through all the lazy properties (which is all the properties)
|
||||
BOOST_FOREACH(const LazyPropertyMap::value_type& element, lazyProps) {
|
||||
// Loop through all the lazy properties (which is all the properties)
|
||||
BOOST_FOREACH(const LazyPropertyMap::value_type& element, lazyProps) {
|
||||
|
||||
// Skip parsed properties
|
||||
if (props.end() != props.find(element.first)) continue;
|
||||
// Skip parsed properties
|
||||
if (props.end() != props.find(element.first)) continue;
|
||||
|
||||
// Read the element's value.
|
||||
// Wrap the naked pointer (since the call site is required to acquire ownership)
|
||||
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
|
||||
boost::shared_ptr<Property> prop = boost::shared_ptr<Property>(ReadTypedProperty(*element.second));
|
||||
// Read the element's value.
|
||||
// Wrap the naked pointer (since the call site is required to acquire ownership)
|
||||
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
|
||||
boost::shared_ptr<Property> prop = boost::shared_ptr<Property>(ReadTypedProperty(*element.second));
|
||||
|
||||
// Element could not be read. Skip it.
|
||||
if (!prop) continue;
|
||||
// Element could not be read. Skip it.
|
||||
if (!prop) continue;
|
||||
|
||||
// Add to result
|
||||
result[element.first] = prop;
|
||||
}
|
||||
// Add to result
|
||||
result[element.first] = prop;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
||||
class Element;
|
||||
class Element;
|
||||
|
||||
|
||||
/** Represents a dynamic property. Type info added by deriving classes,
|
||||
|
@ -67,18 +67,18 @@ class Property
|
|||
{
|
||||
protected:
|
||||
|
||||
Property();
|
||||
Property();
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Property();
|
||||
virtual ~Property();
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
const T* As() const {
|
||||
return dynamic_cast<const T*>(this);
|
||||
}
|
||||
template <typename T>
|
||||
const T* As() const {
|
||||
return dynamic_cast<const T*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -87,19 +87,19 @@ class TypedProperty : public Property
|
|||
{
|
||||
public:
|
||||
|
||||
TypedProperty(const T& value)
|
||||
: value(value)
|
||||
{
|
||||
}
|
||||
TypedProperty(const T& value)
|
||||
: value(value)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
const T& Value() const {
|
||||
return value;
|
||||
}
|
||||
const T& Value() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
T value;
|
||||
T value;
|
||||
};
|
||||
|
||||
|
||||
|
@ -112,76 +112,76 @@ class PropertyTable
|
|||
{
|
||||
public:
|
||||
|
||||
// in-memory property table with no source element
|
||||
PropertyTable();
|
||||
// in-memory property table with no source element
|
||||
PropertyTable();
|
||||
|
||||
PropertyTable(const Element& element, boost::shared_ptr<const PropertyTable> templateProps);
|
||||
~PropertyTable();
|
||||
PropertyTable(const Element& element, boost::shared_ptr<const PropertyTable> templateProps);
|
||||
~PropertyTable();
|
||||
|
||||
public:
|
||||
|
||||
const Property* Get(const std::string& name) const;
|
||||
const Property* Get(const std::string& name) const;
|
||||
|
||||
// PropertyTable's need not be coupled with FBX elements so this can be NULL
|
||||
const Element* GetElement() const {
|
||||
return element;
|
||||
}
|
||||
// PropertyTable's need not be coupled with FBX elements so this can be NULL
|
||||
const Element* GetElement() const {
|
||||
return element;
|
||||
}
|
||||
|
||||
const PropertyTable* TemplateProps() const {
|
||||
return templateProps.get();
|
||||
}
|
||||
const PropertyTable* TemplateProps() const {
|
||||
return templateProps.get();
|
||||
}
|
||||
|
||||
DirectPropertyMap GetUnparsedProperties() const;
|
||||
DirectPropertyMap GetUnparsedProperties() const;
|
||||
|
||||
private:
|
||||
|
||||
LazyPropertyMap lazyProps;
|
||||
mutable PropertyMap props;
|
||||
const boost::shared_ptr<const PropertyTable> templateProps;
|
||||
const Element* const element;
|
||||
LazyPropertyMap lazyProps;
|
||||
mutable PropertyMap props;
|
||||
const boost::shared_ptr<const PropertyTable> templateProps;
|
||||
const Element* const element;
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable& in, const std::string& name,
|
||||
const T& defaultValue)
|
||||
const T& defaultValue)
|
||||
{
|
||||
const Property* const prop = in.Get(name);
|
||||
if(!prop) {
|
||||
return defaultValue;
|
||||
}
|
||||
const Property* const prop = in.Get(name);
|
||||
if(!prop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
|
||||
if(!tprop) {
|
||||
return defaultValue;
|
||||
}
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
|
||||
if(!tprop) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return tprop->Value();
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline T PropertyGet(const PropertyTable& in, const std::string& name,
|
||||
bool& result)
|
||||
bool& result)
|
||||
{
|
||||
const Property* const prop = in.Get(name);
|
||||
if(!prop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
const Property* const prop = in.Get(name);
|
||||
if(!prop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
|
||||
if(!tprop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
// strong typing, no need to be lenient
|
||||
const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
|
||||
if(!tprop) {
|
||||
result = false;
|
||||
return T();
|
||||
}
|
||||
|
||||
result = true;
|
||||
return tprop->Value();
|
||||
result = true;
|
||||
return tprop->Value();
|
||||
}
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue