Refactor: Expand tabs to 4 spaces

pull/566/head
Richard 2015-05-18 21:57:13 -06:00
parent a96a595a7a
commit 83de707587
324 changed files with 78951 additions and 78956 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;
};

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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();
}
// ------------------------------------------------------------------------------------------------

View File

@ -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

View File

@ -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;
};
}

View File

@ -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

View File

@ -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

View File

@ -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 %%%");
}
}

View 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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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);
}
}
}

View File

@ -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);
};

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
) ;
};

View File

@ -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);
}
//--------------------------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
};
}

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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() {}
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
};

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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();
}
}
}
}
}

View File

@ -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

View File

@ -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);
}
}
// ----------------------------------------------------------------------------------

View File

@ -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
}
// ----------------------------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
};

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -49,7 +49,7 @@ struct aiScene;
namespace Assimp {
namespace FBX {
class Document;
class Document;
/** Convert a FBX #Document to #aiScene

View File

@ -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;
}
}
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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