Merge branch 'master' into master

pull/3195/head
Kim Kulling 2020-05-16 20:41:05 +02:00 committed by GitHub
commit d7e8fefed7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
152 changed files with 5096 additions and 22141 deletions

View File

@ -1,4 +1,4 @@
/* /*
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/* /*
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/* /*
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/* /*
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -44,8 +44,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
#include "ColladaExporter.h" #include "ColladaExporter.h"
#include <assimp/Bitmap.h> #include <assimp/Bitmap.h>
#include <assimp/ColladaMetaData.h>
#include <assimp/DefaultIOSystem.h> #include <assimp/DefaultIOSystem.h>
#include <assimp/Exceptional.h>
#include <assimp/MathFunctions.h> #include <assimp/MathFunctions.h>
#include <assimp/SceneCombiner.h> #include <assimp/SceneCombiner.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
@ -56,15 +59,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/Exporter.hpp> #include <assimp/Exporter.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/Exceptional.h>
#include <ctime> #include <ctime>
#include <iostream>
#include <memory> #include <memory>
#include <set>
#include <vector>
using namespace Assimp;
namespace Assimp { namespace Assimp {
@ -91,8 +87,6 @@ void ExportSceneCollada(const char *pFile, IOSystem *pIOSystem, const aiScene *p
outfile->Write(iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()), 1); outfile->Write(iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()), 1);
} }
} // end of namespace Assimp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Encodes a string into a valid XML ID using the xsd:ID schema qualifications. // Encodes a string into a valid XML ID using the xsd:ID schema qualifications.
static const std::string XMLIDEncode(const std::string &name) { static const std::string XMLIDEncode(const std::string &name) {
@ -115,7 +109,7 @@ static const std::string XMLIDEncode(const std::string &name) {
if (strchr(XML_ID_CHARS, *it) != nullptr) { if (strchr(XML_ID_CHARS, *it) != nullptr) {
idEncoded << *it; idEncoded << *it;
} else { } else {
// Select placeholder character based on invalid character to prevent name collisions // Select placeholder character based on invalid character to reduce ID collisions
idEncoded << XML_ID_CHARS[(*it) % XML_ID_CHARS_COUNT]; idEncoded << XML_ID_CHARS[(*it) % XML_ID_CHARS_COUNT];
} }
} }
@ -126,7 +120,9 @@ static const std::string XMLIDEncode(const std::string &name) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor for a specific scene to export // Constructor for a specific scene to export
ColladaExporter::ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file) : ColladaExporter::ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file) :
mIOSystem(pIOSystem), mPath(path), mFile(file) { mIOSystem(pIOSystem),
mPath(path),
mFile(file) {
// make sure that all formatting happens using the standard, C locale and not the user's current locale // make sure that all formatting happens using the standard, C locale and not the user's current locale
mOutput.imbue(std::locale("C")); mOutput.imbue(std::locale("C"));
mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
@ -161,6 +157,9 @@ void ColladaExporter::WriteFile() {
WriteTextures(); WriteTextures();
WriteHeader(); WriteHeader();
// Add node names to the unique id database first so they are most likely to use their names as unique ids
CreateNodeIds(mScene->mRootNode);
WriteCamerasLibrary(); WriteCamerasLibrary();
WriteLightsLibrary(); WriteLightsLibrary();
WriteMaterials(); WriteMaterials();
@ -175,7 +174,7 @@ void ColladaExporter::WriteFile() {
// useless Collada fu at the end, just in case we haven't had enough indirections, yet. // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
mOutput << startstr << "<scene>" << endstr; mOutput << startstr << "<scene>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<instance_visual_scene url=\"#" + XMLIDEncode(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr; mOutput << startstr << "<instance_visual_scene url=\"#" + GetNodeUniqueId(mScene->mRootNode) + "\" />" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</scene>" << endstr; mOutput << startstr << "</scene>" << endstr;
PopTag(); PopTag();
@ -201,7 +200,7 @@ void ColladaExporter::WriteHeader() {
static const unsigned int date_nb_chars = 20; static const unsigned int date_nb_chars = 20;
char date_str[date_nb_chars]; char date_str[date_nb_chars];
std::time_t date = std::time(NULL); std::time_t date = std::time(nullptr);
std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date)); std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date));
aiVector3D scaling; aiVector3D scaling;
@ -352,7 +351,7 @@ void ColladaExporter::WriteTextures() {
std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char *)texture->achFormatHint); std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char *)texture->achFormatHint);
std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb")); std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb"));
if (outfile == NULL) { if (outfile == nullptr) {
throw DeadlyExportError("could not open output texture file: " + mPath + name); throw DeadlyExportError("could not open output texture file: " + mPath + name);
} }
@ -388,10 +387,10 @@ void ColladaExporter::WriteCamerasLibrary() {
void ColladaExporter::WriteCamera(size_t pIndex) { void ColladaExporter::WriteCamera(size_t pIndex) {
const aiCamera *cam = mScene->mCameras[pIndex]; const aiCamera *cam = mScene->mCameras[pIndex];
const std::string cameraName = XMLEscape(cam->mName.C_Str()); const std::string cameraId = GetObjectUniqueId(AiObjectType::Camera, pIndex);
const std::string cameraId = XMLIDEncode(cam->mName.C_Str()); const std::string cameraName = GetObjectName(AiObjectType::Camera, pIndex);
mOutput << startstr << "<camera id=\"" << cameraId << "-camera\" name=\"" << cameraName << "\" >" << endstr; mOutput << startstr << "<camera id=\"" << cameraId << "\" name=\"" << cameraName << "\" >" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<optics>" << endstr; mOutput << startstr << "<optics>" << endstr;
PushTag(); PushTag();
@ -441,10 +440,10 @@ void ColladaExporter::WriteLightsLibrary() {
void ColladaExporter::WriteLight(size_t pIndex) { void ColladaExporter::WriteLight(size_t pIndex) {
const aiLight *light = mScene->mLights[pIndex]; const aiLight *light = mScene->mLights[pIndex];
const std::string lightName = XMLEscape(light->mName.C_Str()); const std::string lightId = GetObjectUniqueId(AiObjectType::Light, pIndex);
const std::string lightId = XMLIDEncode(light->mName.C_Str()); const std::string lightName = GetObjectName(AiObjectType::Light, pIndex);
mOutput << startstr << "<light id=\"" << lightId << "-light\" name=\"" mOutput << startstr << "<light id=\"" << lightId << "\" name=\""
<< lightName << "\" >" << endstr; << lightName << "\" >" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<technique_common>" << endstr; mOutput << startstr << "<technique_common>" << endstr;
@ -561,12 +560,11 @@ void ColladaExporter::WriteAmbienttLight(const aiLight *const light) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads a single surface entry from the given material keys // Reads a single surface entry from the given material keys
void ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial *pSrcMat, bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex) {
aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex) { if (pSrcMat.GetTextureCount(pTexture) > 0) {
if (pSrcMat->GetTextureCount(pTexture) > 0) {
aiString texfile; aiString texfile;
unsigned int uvChannel = 0; unsigned int uvChannel = 0;
pSrcMat->GetTexture(pTexture, 0, &texfile, NULL, &uvChannel); pSrcMat.GetTexture(pTexture, 0, &texfile, nullptr, &uvChannel);
std::string index_str(texfile.C_Str()); std::string index_str(texfile.C_Str());
@ -596,8 +594,9 @@ void ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial *
poSurface.exist = true; poSurface.exist = true;
} else { } else {
if (pKey) if (pKey)
poSurface.exist = pSrcMat->Get(pKey, static_cast<unsigned int>(pType), static_cast<unsigned int>(pIndex), poSurface.color) == aiReturn_SUCCESS; poSurface.exist = pSrcMat.Get(pKey, static_cast<unsigned int>(pType), static_cast<unsigned int>(pIndex), poSurface.color) == aiReturn_SUCCESS;
} }
return poSurface.exist;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -608,9 +607,9 @@ static bool isalnum_C(char c) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Writes an image entry for the given surface // Writes an image entry for the given surface
void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &pNameAdd) { void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &imageId) {
if (!pSurface.texture.empty()) { if (!pSurface.texture.empty()) {
mOutput << startstr << "<image id=\"" << XMLIDEncode(pNameAdd) << "\">" << endstr; mOutput << startstr << "<image id=\"" << imageId << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<init_from>"; mOutput << startstr << "<init_from>";
@ -631,14 +630,14 @@ void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Writes a color-or-texture entry into an effect definition // Writes a color-or-texture entry into an effect definition
void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pImageName) { void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId) {
if (pSurface.exist) { if (pSurface.exist) {
mOutput << startstr << "<" << pTypeName << ">" << endstr; mOutput << startstr << "<" << pTypeName << ">" << endstr;
PushTag(); PushTag();
if (pSurface.texture.empty()) { if (pSurface.texture.empty()) {
mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "</color>" << endstr; mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "</color>" << endstr;
} else { } else {
mOutput << startstr << "<texture texture=\"" << XMLIDEncode(pImageName) << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr; mOutput << startstr << "<texture texture=\"" << imageId << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
} }
PopTag(); PopTag();
mOutput << startstr << "</" << pTypeName << ">" << endstr; mOutput << startstr << "</" << pTypeName << ">" << endstr;
@ -647,24 +646,24 @@ void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Writes the two parameters necessary for referencing a texture in an effect entry // Writes the two parameters necessary for referencing a texture in an effect entry
void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &pMatName) { void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId) {
// if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
if (!pSurface.texture.empty()) { if (!pSurface.texture.empty()) {
mOutput << startstr << "<newparam sid=\"" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface\">" << endstr; mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-surface\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<surface type=\"2D\">" << endstr; mOutput << startstr << "<surface type=\"2D\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<init_from>" << XMLIDEncode(pMatName) << "-" << pTypeName << "-image</init_from>" << endstr; mOutput << startstr << "<init_from>" << materialId << "-" << pTypeName << "-image</init_from>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</surface>" << endstr; mOutput << startstr << "</surface>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</newparam>" << endstr; mOutput << startstr << "</newparam>" << endstr;
mOutput << startstr << "<newparam sid=\"" << XMLIDEncode(pMatName) << "-" << pTypeName << "-sampler\">" << endstr; mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-sampler\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<sampler2D>" << endstr; mOutput << startstr << "<sampler2D>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<source>" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface</source>" << endstr; mOutput << startstr << "<source>" << materialId << "-" << pTypeName << "-surface</source>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</sampler2D>" << endstr; mOutput << startstr << "</sampler2D>" << endstr;
PopTag(); PopTag();
@ -687,80 +686,63 @@ void ColladaExporter::WriteFloatEntry(const Property &pProperty, const std::stri
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Writes the material setup // Writes the material setup
void ColladaExporter::WriteMaterials() { void ColladaExporter::WriteMaterials() {
std::vector<Material> materials;
materials.resize(mScene->mNumMaterials); materials.resize(mScene->mNumMaterials);
/// collect all materials from the scene /// collect all materials from the scene
size_t numTextures = 0; size_t numTextures = 0;
for (size_t a = 0; a < mScene->mNumMaterials; ++a) { for (size_t a = 0; a < mScene->mNumMaterials; ++a) {
const aiMaterial *mat = mScene->mMaterials[a]; Material &material = materials[a];
material.id = GetObjectUniqueId(AiObjectType::Material, a);
aiString name; material.name = GetObjectName(AiObjectType::Material, a);
if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) {
name = "mat";
materials[a].name = std::string("m") + to_string(a) + name.C_Str();
} else {
// try to use the material's name if no other material has already taken it, else append #
std::string testName = name.C_Str();
size_t materialCountWithThisName = 0;
for (size_t i = 0; i < a; i++) {
if (materials[i].name == testName) {
materialCountWithThisName++;
}
}
if (materialCountWithThisName == 0) {
materials[a].name = name.C_Str();
} else {
materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName);
}
}
const aiMaterial &mat = *(mScene->mMaterials[a]);
aiShadingMode shading = aiShadingMode_Flat; aiShadingMode shading = aiShadingMode_Flat;
materials[a].shading_model = "phong"; material.shading_model = "phong";
if (mat->Get(AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) { if (mat.Get(AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) {
if (shading == aiShadingMode_Phong) { if (shading == aiShadingMode_Phong) {
materials[a].shading_model = "phong"; material.shading_model = "phong";
} else if (shading == aiShadingMode_Blinn) { } else if (shading == aiShadingMode_Blinn) {
materials[a].shading_model = "blinn"; material.shading_model = "blinn";
} else if (shading == aiShadingMode_NoShading) { } else if (shading == aiShadingMode_NoShading) {
materials[a].shading_model = "constant"; material.shading_model = "constant";
} else if (shading == aiShadingMode_Gouraud) { } else if (shading == aiShadingMode_Gouraud) {
materials[a].shading_model = "lambert"; material.shading_model = "lambert";
} }
} }
ReadMaterialSurface(materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); if (ReadMaterialSurface(material.ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT))
if (!materials[a].ambient.texture.empty()) numTextures++; ++numTextures;
ReadMaterialSurface(materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); if (ReadMaterialSurface(material.diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE))
if (!materials[a].diffuse.texture.empty()) numTextures++; ++numTextures;
ReadMaterialSurface(materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); if (ReadMaterialSurface(material.specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR))
if (!materials[a].specular.texture.empty()) numTextures++; ++numTextures;
ReadMaterialSurface(materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE); if (ReadMaterialSurface(material.emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE))
if (!materials[a].emissive.texture.empty()) numTextures++; ++numTextures;
ReadMaterialSurface(materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE); if (ReadMaterialSurface(material.reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE))
if (!materials[a].reflective.texture.empty()) numTextures++; ++numTextures;
ReadMaterialSurface(materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT); if (ReadMaterialSurface(material.transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT))
if (!materials[a].transparent.texture.empty()) numTextures++; ++numTextures;
ReadMaterialSurface(materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0); if (ReadMaterialSurface(material.normal, mat, aiTextureType_NORMALS, nullptr, 0, 0))
if (!materials[a].normal.texture.empty()) numTextures++; ++numTextures;
materials[a].shininess.exist = mat->Get(AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS; material.shininess.exist = mat.Get(AI_MATKEY_SHININESS, material.shininess.value) == aiReturn_SUCCESS;
materials[a].transparency.exist = mat->Get(AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS; material.transparency.exist = mat.Get(AI_MATKEY_OPACITY, material.transparency.value) == aiReturn_SUCCESS;
materials[a].index_refraction.exist = mat->Get(AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS; material.index_refraction.exist = mat.Get(AI_MATKEY_REFRACTI, material.index_refraction.value) == aiReturn_SUCCESS;
} }
// output textures if present // output textures if present
if (numTextures > 0) { if (numTextures > 0) {
mOutput << startstr << "<library_images>" << endstr; mOutput << startstr << "<library_images>" << endstr;
PushTag(); PushTag();
for (std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) { for (const Material &mat : materials) {
const Material &mat = *it; WriteImageEntry(mat.ambient, mat.id + "-ambient-image");
WriteImageEntry(mat.ambient, mat.name + "-ambient-image"); WriteImageEntry(mat.diffuse, mat.id + "-diffuse-image");
WriteImageEntry(mat.diffuse, mat.name + "-diffuse-image"); WriteImageEntry(mat.specular, mat.id + "-specular-image");
WriteImageEntry(mat.specular, mat.name + "-specular-image"); WriteImageEntry(mat.emissive, mat.id + "-emission-image");
WriteImageEntry(mat.emissive, mat.name + "-emission-image"); WriteImageEntry(mat.reflective, mat.id + "-reflective-image");
WriteImageEntry(mat.reflective, mat.name + "-reflective-image"); WriteImageEntry(mat.transparent, mat.id + "-transparent-image");
WriteImageEntry(mat.transparent, mat.name + "-transparent-image"); WriteImageEntry(mat.normal, mat.id + "-normal-image");
WriteImageEntry(mat.normal, mat.name + "-normal-image");
} }
PopTag(); PopTag();
mOutput << startstr << "</library_images>" << endstr; mOutput << startstr << "</library_images>" << endstr;
@ -770,40 +752,39 @@ void ColladaExporter::WriteMaterials() {
if (!materials.empty()) { if (!materials.empty()) {
mOutput << startstr << "<library_effects>" << endstr; mOutput << startstr << "<library_effects>" << endstr;
PushTag(); PushTag();
for (std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) { for (const Material &mat : materials) {
const Material &mat = *it;
// this is so ridiculous it must be right // this is so ridiculous it must be right
mOutput << startstr << "<effect id=\"" << XMLIDEncode(mat.name) << "-fx\" name=\"" << XMLEscape(mat.name) << "\">" << endstr; mOutput << startstr << "<effect id=\"" << mat.id << "-fx\" name=\"" << mat.name << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<profile_COMMON>" << endstr; mOutput << startstr << "<profile_COMMON>" << endstr;
PushTag(); PushTag();
// write sampler- and surface params for the texture entries // write sampler- and surface params for the texture entries
WriteTextureParamEntry(mat.emissive, "emission", mat.name); WriteTextureParamEntry(mat.emissive, "emission", mat.id);
WriteTextureParamEntry(mat.ambient, "ambient", mat.name); WriteTextureParamEntry(mat.ambient, "ambient", mat.id);
WriteTextureParamEntry(mat.diffuse, "diffuse", mat.name); WriteTextureParamEntry(mat.diffuse, "diffuse", mat.id);
WriteTextureParamEntry(mat.specular, "specular", mat.name); WriteTextureParamEntry(mat.specular, "specular", mat.id);
WriteTextureParamEntry(mat.reflective, "reflective", mat.name); WriteTextureParamEntry(mat.reflective, "reflective", mat.id);
WriteTextureParamEntry(mat.transparent, "transparent", mat.name); WriteTextureParamEntry(mat.transparent, "transparent", mat.id);
WriteTextureParamEntry(mat.normal, "normal", mat.name); WriteTextureParamEntry(mat.normal, "normal", mat.id);
mOutput << startstr << "<technique sid=\"standard\">" << endstr; mOutput << startstr << "<technique sid=\"standard\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<" << mat.shading_model << ">" << endstr; mOutput << startstr << "<" << mat.shading_model << ">" << endstr;
PushTag(); PushTag();
WriteTextureColorEntry(mat.emissive, "emission", mat.name + "-emission-sampler"); WriteTextureColorEntry(mat.emissive, "emission", mat.id + "-emission-sampler");
WriteTextureColorEntry(mat.ambient, "ambient", mat.name + "-ambient-sampler"); WriteTextureColorEntry(mat.ambient, "ambient", mat.id + "-ambient-sampler");
WriteTextureColorEntry(mat.diffuse, "diffuse", mat.name + "-diffuse-sampler"); WriteTextureColorEntry(mat.diffuse, "diffuse", mat.id + "-diffuse-sampler");
WriteTextureColorEntry(mat.specular, "specular", mat.name + "-specular-sampler"); WriteTextureColorEntry(mat.specular, "specular", mat.id + "-specular-sampler");
WriteFloatEntry(mat.shininess, "shininess"); WriteFloatEntry(mat.shininess, "shininess");
WriteTextureColorEntry(mat.reflective, "reflective", mat.name + "-reflective-sampler"); WriteTextureColorEntry(mat.reflective, "reflective", mat.id + "-reflective-sampler");
WriteTextureColorEntry(mat.transparent, "transparent", mat.name + "-transparent-sampler"); WriteTextureColorEntry(mat.transparent, "transparent", mat.id + "-transparent-sampler");
WriteFloatEntry(mat.transparency, "transparency"); WriteFloatEntry(mat.transparency, "transparency");
WriteFloatEntry(mat.index_refraction, "index_of_refraction"); WriteFloatEntry(mat.index_refraction, "index_of_refraction");
if (!mat.normal.texture.empty()) { if (!mat.normal.texture.empty()) {
WriteTextureColorEntry(mat.normal, "bump", mat.name + "-normal-sampler"); WriteTextureColorEntry(mat.normal, "bump", mat.id + "-normal-sampler");
} }
PopTag(); PopTag();
@ -823,9 +804,9 @@ void ColladaExporter::WriteMaterials() {
PushTag(); PushTag();
for (std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) { for (std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
const Material &mat = *it; const Material &mat = *it;
mOutput << startstr << "<material id=\"" << XMLIDEncode(mat.name) << "\" name=\"" << XMLEscape(mat.name) << "\">" << endstr; mOutput << startstr << "<material id=\"" << mat.id << "\" name=\"" << mat.name << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<instance_effect url=\"#" << XMLIDEncode(mat.name) << "-fx\"/>" << endstr; mOutput << startstr << "<instance_effect url=\"#" << mat.id << "-fx\"/>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</material>" << endstr; mOutput << startstr << "</material>" << endstr;
} }
@ -852,20 +833,18 @@ void ColladaExporter::WriteControllerLibrary() {
// Writes a skin controller of the given mesh // Writes a skin controller of the given mesh
void ColladaExporter::WriteController(size_t pIndex) { void ColladaExporter::WriteController(size_t pIndex) {
const aiMesh *mesh = mScene->mMeshes[pIndex]; const aiMesh *mesh = mScene->mMeshes[pIndex];
const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); // Is there a skin controller?
const std::string idstrEscaped = XMLIDEncode(idstr); if (mesh->mNumBones == 0 || mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
return; return;
if (mesh->mNumBones == 0) const std::string idstr = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
return; const std::string namestr = GetObjectName(AiObjectType::Mesh, pIndex);
mOutput << startstr << "<controller id=\"" << idstrEscaped << "-skin\" "; mOutput << startstr << "<controller id=\"" << idstr << "-skin\" ";
mOutput << "name=\"skinCluster" << pIndex << "\">" << endstr; mOutput << "name=\"skinCluster" << pIndex << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<skin source=\"#" << idstrEscaped << "\">" << endstr; mOutput << startstr << "<skin source=\"#" << idstr << "\">" << endstr;
PushTag(); PushTag();
// bind pose matrix // bind pose matrix
@ -882,20 +861,20 @@ void ColladaExporter::WriteController(size_t pIndex) {
PopTag(); PopTag();
mOutput << startstr << "</bind_shape_matrix>" << endstr; mOutput << startstr << "</bind_shape_matrix>" << endstr;
mOutput << startstr << "<source id=\"" << idstrEscaped << "-skin-joints\" name=\"" << idstrEscaped << "-skin-joints\">" << endstr; mOutput << startstr << "<source id=\"" << idstr << "-skin-joints\" name=\"" << namestr << "-skin-joints\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<Name_array id=\"" << idstrEscaped << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">"; mOutput << startstr << "<Name_array id=\"" << idstr << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">";
for (size_t i = 0; i < mesh->mNumBones; ++i) for (size_t i = 0; i < mesh->mNumBones; ++i)
mOutput << XMLIDEncode(mesh->mBones[i]->mName.C_Str()) << " "; mOutput << GetBoneUniqueId(mesh->mBones[i]) << ' ';
mOutput << "</Name_array>" << endstr; mOutput << "</Name_array>" << endstr;
mOutput << startstr << "<technique_common>" << endstr; mOutput << startstr << "<technique_common>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<accessor source=\"#" << idstrEscaped << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\" stride=\"" << 1 << "\">" << endstr; mOutput << startstr << "<accessor source=\"#" << idstr << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\" stride=\"" << 1 << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<param name=\"JOINT\" type=\"Name\"></param>" << endstr; mOutput << startstr << "<param name=\"JOINT\" type=\"Name\"></param>" << endstr;
@ -932,8 +911,8 @@ void ColladaExporter::WriteController(size_t pIndex) {
mOutput << startstr << "<joints>" << endstr; mOutput << startstr << "<joints>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstrEscaped << "-skin-joints\"></input>" << endstr; mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstr << "-skin-joints\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"INV_BIND_MATRIX\" source=\"#" << idstrEscaped << "-skin-bind_poses\"></input>" << endstr; mOutput << startstr << "<input semantic=\"INV_BIND_MATRIX\" source=\"#" << idstr << "-skin-bind_poses\"></input>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</joints>" << endstr; mOutput << startstr << "</joints>" << endstr;
@ -941,8 +920,8 @@ void ColladaExporter::WriteController(size_t pIndex) {
mOutput << startstr << "<vertex_weights count=\"" << mesh->mNumVertices << "\">" << endstr; mOutput << startstr << "<vertex_weights count=\"" << mesh->mNumVertices << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstrEscaped << "-skin-joints\" offset=\"0\"></input>" << endstr; mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstr << "-skin-joints\" offset=\"0\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"WEIGHT\" source=\"#" << idstrEscaped << "-skin-weights\" offset=\"1\"></input>" << endstr; mOutput << startstr << "<input semantic=\"WEIGHT\" source=\"#" << idstr << "-skin-weights\" offset=\"1\"></input>" << endstr;
mOutput << startstr << "<vcount>"; mOutput << startstr << "<vcount>";
@ -1017,9 +996,8 @@ void ColladaExporter::WriteGeometryLibrary() {
// Writes the given mesh // Writes the given mesh
void ColladaExporter::WriteGeometry(size_t pIndex) { void ColladaExporter::WriteGeometry(size_t pIndex) {
const aiMesh *mesh = mScene->mMeshes[pIndex]; const aiMesh *mesh = mScene->mMeshes[pIndex];
const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); const std::string geometryId = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
const std::string geometryName = XMLEscape(idstr); const std::string geometryName = GetObjectName(AiObjectType::Mesh, pIndex);
const std::string geometryId = XMLIDEncode(idstr);
if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
return; return;
@ -1032,15 +1010,15 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
PushTag(); PushTag();
// Positions // Positions
WriteFloatArray(idstr + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices); WriteFloatArray(geometryId + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices);
// Normals, if any // Normals, if any
if (mesh->HasNormals()) if (mesh->HasNormals())
WriteFloatArray(idstr + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices); WriteFloatArray(geometryId + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices);
// texture coords // texture coords
for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
if (mesh->HasTextureCoords(static_cast<unsigned int>(a))) { if (mesh->HasTextureCoords(static_cast<unsigned int>(a))) {
WriteFloatArray(idstr + "-tex" + to_string(a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2, WriteFloatArray(geometryId + "-tex" + to_string(a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2,
(ai_real *)mesh->mTextureCoords[a], mesh->mNumVertices); (ai_real *)mesh->mTextureCoords[a], mesh->mNumVertices);
} }
} }
@ -1048,7 +1026,7 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
// vertex colors // vertex colors
for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
if (mesh->HasVertexColors(static_cast<unsigned int>(a))) if (mesh->HasVertexColors(static_cast<unsigned int>(a)))
WriteFloatArray(idstr + "-color" + to_string(a), FloatType_Color, (ai_real *)mesh->mColors[a], mesh->mNumVertices); WriteFloatArray(geometryId + "-color" + to_string(a), FloatType_Color, (ai_real *)mesh->mColors[a], mesh->mNumVertices);
} }
// assemble vertex structure // assemble vertex structure
@ -1248,8 +1226,8 @@ void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataTyp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Writes the scene library // Writes the scene library
void ColladaExporter::WriteSceneLibrary() { void ColladaExporter::WriteSceneLibrary() {
const std::string sceneName = XMLEscape(mScene->mRootNode->mName.C_Str()); const std::string sceneId = GetNodeUniqueId(mScene->mRootNode);
const std::string sceneId = XMLIDEncode(mScene->mRootNode->mName.C_Str()); const std::string sceneName = GetNodeName(mScene->mRootNode);
mOutput << startstr << "<library_visual_scenes>" << endstr; mOutput << startstr << "<library_visual_scenes>" << endstr;
PushTag(); PushTag();
@ -1258,7 +1236,7 @@ void ColladaExporter::WriteSceneLibrary() {
// start recursive write at the root node // start recursive write at the root node
for (size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a) for (size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a)
WriteNode(mScene, mScene->mRootNode->mChildren[a]); WriteNode(mScene->mRootNode->mChildren[a]);
PopTag(); PopTag();
mOutput << startstr << "</visual_scene>" << endstr; mOutput << startstr << "</visual_scene>" << endstr;
@ -1272,20 +1250,10 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) {
if (anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels == 0) if (anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels == 0)
return; return;
const std::string animation_name_escaped = XMLEscape(anim->mName.C_Str()); const std::string animationNameEscaped = GetObjectName(AiObjectType::Animation, pIndex);
std::string idstr = anim->mName.C_Str(); const std::string idstrEscaped = GetObjectUniqueId(AiObjectType::Animation, pIndex);
std::string ending = std::string("AnimId") + to_string(pIndex);
if (idstr.length() >= ending.length()) {
if (0 != idstr.compare(idstr.length() - ending.length(), ending.length(), ending)) {
idstr = idstr + ending;
}
} else {
idstr = idstr + ending;
}
const std::string idstrEscaped = XMLIDEncode(idstr); mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animationNameEscaped + "\">" << endstr;
mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
PushTag(); PushTag();
std::string cur_node_idstr; std::string cur_node_idstr;
@ -1435,20 +1403,21 @@ void ColladaExporter::WriteAnimationsLibrary() {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Helper to find a bone by name in the scene // Helper to find a bone by name in the scene
aiBone *findBone(const aiScene *scene, const char *name) { aiBone *findBone(const aiScene *scene, const aiString &name) {
for (size_t m = 0; m < scene->mNumMeshes; m++) { for (size_t m = 0; m < scene->mNumMeshes; m++) {
aiMesh *mesh = scene->mMeshes[m]; aiMesh *mesh = scene->mMeshes[m];
for (size_t b = 0; b < mesh->mNumBones; b++) { for (size_t b = 0; b < mesh->mNumBones; b++) {
aiBone *bone = mesh->mBones[b]; aiBone *bone = mesh->mBones[b];
if (0 == strcmp(name, bone->mName.C_Str())) { if (name == bone->mName) {
return bone; return bone;
} }
} }
} }
return NULL; return nullptr;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Helper to find the node associated with a bone in the scene
const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) { const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) {
if (aNode && bone && aNode->mName == bone->mName) { if (aNode && bone && aNode->mName == bone->mName) {
return aNode; return aNode;
@ -1457,15 +1426,17 @@ const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) {
if (aNode && bone) { if (aNode && bone) {
for (unsigned int i = 0; i < aNode->mNumChildren; ++i) { for (unsigned int i = 0; i < aNode->mNumChildren; ++i) {
aiNode *aChild = aNode->mChildren[i]; aiNode *aChild = aNode->mChildren[i];
const aiNode *foundFromChild = 0; const aiNode *foundFromChild = nullptr;
if (aChild) { if (aChild) {
foundFromChild = findBoneNode(aChild, bone); foundFromChild = findBoneNode(aChild, bone);
if (foundFromChild) return foundFromChild; if (foundFromChild) {
return foundFromChild;
}
} }
} }
} }
return NULL; return nullptr;
} }
const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) { const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) {
@ -1476,7 +1447,7 @@ const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) {
const aiNode *node = findBoneNode(scene->mRootNode, bone); const aiNode *node = findBoneNode(scene->mRootNode, bone);
if (node) { if (node) {
while (node->mParent && findBone(scene, node->mParent->mName.C_Str()) != 0) { while (node->mParent && findBone(scene, node->mParent->mName) != nullptr) {
node = node->mParent; node = node->mParent;
} }
topParentBoneNodes.insert(node); topParentBoneNodes.insert(node);
@ -1496,36 +1467,30 @@ const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) {
} }
} }
return NULL; return nullptr;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Recursively writes the given node // Recursively writes the given node
void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) { void ColladaExporter::WriteNode(const aiNode *pNode) {
// the node must have a name
if (pNode->mName.length == 0) {
std::stringstream ss;
ss << "Node_" << pNode;
pNode->mName.Set(ss.str());
}
// If the node is associated with a bone, it is a joint node (JOINT) // If the node is associated with a bone, it is a joint node (JOINT)
// otherwise it is a normal node (NODE) // otherwise it is a normal node (NODE)
// Assimp-specific: nodes with no name cannot be associated with bones
const char *node_type; const char *node_type;
bool is_joint, is_skeleton_root = false; bool is_joint, is_skeleton_root = false;
if (nullptr == findBone(pScene, pNode->mName.C_Str())) { if (pNode->mName.length == 0 || nullptr == findBone(mScene, pNode->mName)) {
node_type = "NODE"; node_type = "NODE";
is_joint = false; is_joint = false;
} else { } else {
node_type = "JOINT"; node_type = "JOINT";
is_joint = true; is_joint = true;
if (!pNode->mParent || nullptr == findBone(pScene, pNode->mParent->mName.C_Str())) { if (!pNode->mParent || nullptr == findBone(mScene, pNode->mParent->mName)) {
is_skeleton_root = true; is_skeleton_root = true;
} }
} }
const std::string node_id = XMLIDEncode(pNode->mName.data); const std::string node_id = GetNodeUniqueId(pNode);
const std::string node_name = XMLEscape(pNode->mName.data); const std::string node_name = GetNodeName(pNode);
mOutput << startstr << "<node "; mOutput << startstr << "<node ";
if (is_skeleton_root) { if (is_skeleton_root) {
mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id + "\" " : ""); // For now, only support one skeleton in a scene. mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id + "\" " : ""); // For now, only support one skeleton in a scene.
@ -1573,14 +1538,14 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) {
//check if it is a camera node //check if it is a camera node
for (size_t i = 0; i < mScene->mNumCameras; i++) { for (size_t i = 0; i < mScene->mNumCameras; i++) {
if (mScene->mCameras[i]->mName == pNode->mName) { if (mScene->mCameras[i]->mName == pNode->mName) {
mOutput << startstr << "<instance_camera url=\"#" << node_id << "-camera\"/>" << endstr; mOutput << startstr << "<instance_camera url=\"#" << GetObjectUniqueId(AiObjectType::Camera, i) << "\"/>" << endstr;
break; break;
} }
} }
//check if it is a light node //check if it is a light node
for (size_t i = 0; i < mScene->mNumLights; i++) { for (size_t i = 0; i < mScene->mNumLights; i++) {
if (mScene->mLights[i]->mName == pNode->mName) { if (mScene->mLights[i]->mName == pNode->mName) {
mOutput << startstr << "<instance_light url=\"#" << node_id << "-light\"/>" << endstr; mOutput << startstr << "<instance_light url=\"#" << GetObjectUniqueId(AiObjectType::Light, i) << "\"/>" << endstr;
break; break;
} }
} }
@ -1593,22 +1558,22 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) {
if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0) if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
continue; continue;
const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str(); const std::string meshId = GetObjectUniqueId(AiObjectType::Mesh, pNode->mMeshes[a]);
if (mesh->mNumBones == 0) { if (mesh->mNumBones == 0) {
mOutput << startstr << "<instance_geometry url=\"#" << XMLIDEncode(meshName) << "\">" << endstr; mOutput << startstr << "<instance_geometry url=\"#" << meshId << "\">" << endstr;
PushTag(); PushTag();
} else { } else {
mOutput << startstr mOutput << startstr
<< "<instance_controller url=\"#" << XMLIDEncode(meshName) << "-skin\">" << "<instance_controller url=\"#" << meshId << "-skin\">"
<< endstr; << endstr;
PushTag(); PushTag();
// note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node. // note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node.
// use the first bone to find skeleton root // use the first bone to find skeleton root
const aiNode *skeletonRootBoneNode = findSkeletonRootNode(pScene, mesh); const aiNode *skeletonRootBoneNode = findSkeletonRootNode(mScene, mesh);
if (skeletonRootBoneNode) { if (skeletonRootBoneNode) {
mFoundSkeletonRootNodeID = XMLIDEncode(skeletonRootBoneNode->mName.C_Str()); mFoundSkeletonRootNodeID = GetNodeUniqueId(skeletonRootBoneNode);
} }
mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr; mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr;
} }
@ -1616,7 +1581,7 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) {
PushTag(); PushTag();
mOutput << startstr << "<technique_common>" << endstr; mOutput << startstr << "<technique_common>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << XMLIDEncode(materials[mesh->mMaterialIndex].name) << "\">" << endstr; mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << GetObjectUniqueId(AiObjectType::Material, mesh->mMaterialIndex) << "\">" << endstr;
PushTag(); PushTag();
for (size_t aa = 0; aa < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++aa) { for (size_t aa = 0; aa < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++aa) {
if (mesh->HasTextureCoords(static_cast<unsigned int>(aa))) if (mesh->HasTextureCoords(static_cast<unsigned int>(aa)))
@ -1641,11 +1606,152 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) {
// recurse into subnodes // recurse into subnodes
for (size_t a = 0; a < pNode->mNumChildren; ++a) for (size_t a = 0; a < pNode->mNumChildren; ++a)
WriteNode(pScene, pNode->mChildren[a]); WriteNode(pNode->mChildren[a]);
PopTag(); PopTag();
mOutput << startstr << "</node>" << endstr; mOutput << startstr << "</node>" << endstr;
} }
inline bool IsUniqueId(const std::unordered_set<std::string> &idSet, const std::string &idStr) {
return (idSet.find(idStr) == idSet.end());
}
inline std::string MakeUniqueId(const std::unordered_set<std::string> &idSet, const std::string &idPrefix, const std::string &postfix) {
std::string result(idPrefix + postfix);
if (!IsUniqueId(idSet, result)) {
// Select a number to append
size_t idnum = 1;
do {
result = idPrefix + '_' + to_string(idnum) + postfix;
++idnum;
} while (!IsUniqueId(idSet, result));
}
return result;
}
void ColladaExporter::CreateNodeIds(const aiNode *node) {
GetNodeUniqueId(node);
for (size_t a = 0; a < node->mNumChildren; ++a)
CreateNodeIds(node->mChildren[a]);
}
std::string ColladaExporter::GetNodeUniqueId(const aiNode *node) {
// Use the pointer as the key. This is safe because the scene is immutable.
auto idIt = mNodeIdMap.find(node);
if (idIt != mNodeIdMap.cend())
return idIt->second;
// Prefer the requested Collada Id if extant
std::string idStr;
aiString origId;
if (node->mMetaData && node->mMetaData->Get(AI_METADATA_COLLADA_ID, origId)) {
idStr = origId.C_Str();
} else {
idStr = node->mName.C_Str();
}
// Make sure the requested id is valid
if (idStr.empty())
idStr = "node";
else
idStr = XMLIDEncode(idStr);
// Ensure it's unique
idStr = MakeUniqueId(mUniqueIds, idStr, std::string());
mUniqueIds.insert(idStr);
mNodeIdMap.insert(std::make_pair(node, idStr));
return idStr;
}
std::string ColladaExporter::GetNodeName(const aiNode *node) {
return XMLEscape(node->mName.C_Str());
}
std::string ColladaExporter::GetBoneUniqueId(const aiBone *bone) {
// Find the Node that is this Bone
const aiNode *boneNode = findBoneNode(mScene->mRootNode, bone);
if (boneNode == nullptr)
return std::string();
return GetNodeUniqueId(boneNode);
}
std::string ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) {
auto idIt = GetObjectIdMap(type).find(pIndex);
if (idIt != GetObjectIdMap(type).cend())
return idIt->second;
// Not seen this object before, create and add
NameIdPair result = AddObjectIndexToMaps(type, pIndex);
return result.second;
}
std::string ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) {
auto objectName = GetObjectNameMap(type).find(pIndex);
if (objectName != GetObjectNameMap(type).cend())
return objectName->second;
// Not seen this object before, create and add
NameIdPair result = AddObjectIndexToMaps(type, pIndex);
return result.first;
}
// Determine unique id and add the name and id to the maps
// @param type object type
// @param index object index
// @param name in/out. Caller to set the original name if known.
// @param idStr in/out. Caller to set the preferred id if known.
ColladaExporter::NameIdPair ColladaExporter::AddObjectIndexToMaps(AiObjectType type, size_t index) {
std::string name;
std::string idStr;
std::string idPostfix;
// Get the name and id postfix
switch (type) {
case AiObjectType::Mesh: name = mScene->mMeshes[index]->mName.C_Str(); break;
case AiObjectType::Material: name = mScene->mMaterials[index]->GetName().C_Str(); break;
case AiObjectType::Animation: name = mScene->mAnimations[index]->mName.C_Str(); break;
case AiObjectType::Light:
name = mScene->mLights[index]->mName.C_Str();
idPostfix = "-light";
break;
case AiObjectType::Camera:
name = mScene->mCameras[index]->mName.C_Str();
idPostfix = "-camera";
break;
case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type");
}
if (name.empty()) {
// Default ids if empty name
switch (type) {
case AiObjectType::Mesh: idStr = std::string("mesh_"); break;
case AiObjectType::Material: idStr = std::string("material_"); break; // This one should never happen
case AiObjectType::Animation: idStr = std::string("animation_"); break;
case AiObjectType::Light: idStr = std::string("light_"); break;
case AiObjectType::Camera: idStr = std::string("camera_"); break;
case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type");
}
idStr.append(to_string(index));
} else {
idStr = XMLIDEncode(name);
}
if (!name.empty())
name = XMLEscape(name);
idStr = MakeUniqueId(mUniqueIds, idStr, idPostfix);
// Add to maps
mUniqueIds.insert(idStr);
GetObjectIdMap(type).insert(std::make_pair(index, idStr));
GetObjectNameMap(type).insert(std::make_pair(index, name));
return std::make_pair(name, idStr);
}
} // end of namespace Assimp
#endif #endif
#endif #endif

View File

@ -48,25 +48,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/mesh.h>
#include <assimp/light.h>
#include <assimp/Exporter.hpp>
#include <sstream>
#include <vector>
#include <map>
#include <assimp/StringUtils.h> #include <array>
#include <map>
#include <sstream>
#include <unordered_set>
#include <vector>
struct aiScene; struct aiScene;
struct aiNode; struct aiNode;
struct aiLight;
struct aiBone;
namespace Assimp namespace Assimp {
{
class IOSystem;
/// Helper class to export a given scene to a Collada file. Just for my personal /// Helper class to export a given scene to a Collada file. Just for my personal
/// comfort when implementing it. /// comfort when implementing it.
class ColladaExporter class ColladaExporter {
{
public: public:
/// Constructor for a specific scene to export /// Constructor for a specific scene to export
ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file); ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file);
@ -117,7 +117,13 @@ protected:
//enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight }; //enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
// customized to add animation related type // customized to add animation related type
enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight, FloatType_Time }; enum FloatDataType { FloatType_Vector,
FloatType_TexCoord2,
FloatType_TexCoord3,
FloatType_Color,
FloatType_Mat4x4,
FloatType_Weight,
FloatType_Time };
/// Writes a float array of the given type /// Writes a float array of the given type
void WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount); void WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount);
@ -131,7 +137,7 @@ protected:
std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call. std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call.
/// Recursively writes the given node /// Recursively writes the given node
void WriteNode( const aiScene* scene, aiNode* pNode); void WriteNode(const aiNode *pNode);
/// Enters a new xml element, which increases the indentation /// Enters a new xml element, which increases the indentation
void PushTag() { startstr.append(" "); } void PushTag() { startstr.append(" "); }
@ -141,10 +147,40 @@ protected:
startstr.erase(startstr.length() - 2); startstr.erase(startstr.length() - 2);
} }
/// Creates a mesh ID for the given mesh void CreateNodeIds(const aiNode *node);
std::string GetMeshId( size_t pIndex) const {
return std::string( "meshId" ) + to_string(pIndex); /// Get or Create a unique Node ID string for the given Node
} std::string GetNodeUniqueId(const aiNode *node);
std::string GetNodeName(const aiNode *node);
std::string GetBoneUniqueId(const aiBone *bone);
enum class AiObjectType {
Mesh,
Material,
Animation,
Light,
Camera,
Count,
};
/// Get or Create a unique ID string for the given scene object index
std::string GetObjectUniqueId(AiObjectType type, size_t pIndex);
/// Get or Create a name string for the given scene object index
std::string GetObjectName(AiObjectType type, size_t pIndex);
typedef std::map<size_t, std::string> IndexIdMap;
typedef std::pair<std::string, std::string> NameIdPair;
NameIdPair AddObjectIndexToMaps(AiObjectType type, size_t pIndex);
// Helpers
inline IndexIdMap &GetObjectIdMap(AiObjectType type) { return mObjectIdMap[static_cast<size_t>(type)]; }
inline IndexIdMap &GetObjectNameMap(AiObjectType type) { return mObjectNameMap[static_cast<size_t>(type)]; }
private:
std::unordered_set<std::string> mUniqueIds; // Cache of used unique ids
std::map<const void *, std::string> mNodeIdMap; // Cache of encoded node and bone ids
std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectIdMap; // Cache of encoded unique IDs
std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectNameMap; // Cache of encoded names
public: public:
/// Stringstream to write all output into /// Stringstream to write all output into
@ -169,28 +205,28 @@ public:
std::string endstr; std::string endstr;
// pair of color and texture - texture precedences color // pair of color and texture - texture precedences color
struct Surface struct Surface {
{
bool exist; bool exist;
aiColor4D color; aiColor4D color;
std::string texture; std::string texture;
size_t channel; size_t channel;
Surface() { exist = false; channel = 0; } Surface() {
exist = false;
channel = 0;
}
}; };
struct Property struct Property {
{
bool exist; bool exist;
ai_real value; ai_real value;
Property() Property() :
: exist(false) exist(false),
, value(0.0) value(0.0) {}
{}
}; };
// summarize a material in an convenient way. // summarize a material in an convenient way.
struct Material struct Material {
{ std::string id;
std::string name; std::string name;
std::string shading_model; std::string shading_model;
Surface ambient, diffuse, specular, emissive, reflective, transparent, normal; Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
@ -199,24 +235,22 @@ public:
Material() {} Material() {}
}; };
std::vector<Material> materials;
std::map<unsigned int, std::string> textures; std::map<unsigned int, std::string> textures;
public: public:
/// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
/// Reads a single surface entry from the given material keys /// Reads a single surface entry from the given material keys
void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex); bool ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex);
/// Writes an image entry for the given surface /// Writes an image entry for the given surface
void WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd); void WriteImageEntry(const Surface &pSurface, const std::string &imageId);
/// Writes the two parameters necessary for referencing a texture in an effect entry /// Writes the two parameters necessary for referencing a texture in an effect entry
void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName); void WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId);
/// Writes a color-or-texture entry into an effect definition /// Writes a color-or-texture entry into an effect definition
void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName); void WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId);
/// Writes a scalar property /// Writes a scalar property
void WriteFloatEntry(const Property &pProperty, const std::string &pTypeName); void WriteFloatEntry(const Property &pProperty, const std::string &pTypeName);
}; };
} } // namespace Assimp
#endif // !! AI_COLLADAEXPORTER_H_INC #endif // !! AI_COLLADAEXPORTER_H_INC

View File

@ -43,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaHelper.h" #include "ColladaHelper.h"
#include <assimp/commonMetaData.h>
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/commonMetaData.h>
namespace Assimp { namespace Assimp {
namespace Collada { namespace Collada {
@ -63,39 +63,32 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() { const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
MetaKeyPairVector result = MakeColladaAssimpMetaKeys(); MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
for (auto &val : result) for (auto &val : result) {
{
ToCamelCase(val.first); ToCamelCase(val.first);
} }
return result; return result;
}; };
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
{
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase(); static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
return result; return result;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool" // Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
void ToCamelCase(std::string &text) void ToCamelCase(std::string &text) {
{
if (text.empty()) if (text.empty())
return; return;
// Capitalise first character // Capitalise first character
auto it = text.begin(); auto it = text.begin();
(*it) = ToUpper(*it); (*it) = ToUpper(*it);
++it; ++it;
for (/*started above*/ ; it != text.end(); /*iterated below*/) for (/*started above*/; it != text.end(); /*iterated below*/) {
{ if ((*it) == '_') {
if ((*it) == '_')
{
it = text.erase(it); it = text.erase(it);
if (it != text.end()) if (it != text.end())
(*it) = ToUpper(*it); (*it) = ToUpper(*it);
} } else {
else
{
// Make lower case // Make lower case
(*it) = ToLower(*it); (*it) = ToLower(*it);
++it; ++it;

View File

@ -45,13 +45,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_COLLADAHELPER_H_INC #ifndef AI_COLLADAHELPER_H_INC
#define AI_COLLADAHELPER_H_INC #define AI_COLLADAHELPER_H_INC
#include <map>
#include <vector>
#include <set>
#include <stdint.h>
#include <assimp/light.h> #include <assimp/light.h>
#include <assimp/mesh.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/mesh.h>
#include <stdint.h>
#include <map>
#include <set>
#include <vector>
struct aiMaterial; struct aiMaterial;
@ -59,17 +59,14 @@ namespace Assimp {
namespace Collada { namespace Collada {
/** Collada file versions which evolved during the years ... */ /** Collada file versions which evolved during the years ... */
enum FormatVersion enum FormatVersion {
{
FV_1_5_n, FV_1_5_n,
FV_1_4_n, FV_1_4_n,
FV_1_3_n FV_1_3_n
}; };
/** Transformation types that can be applied to a node */ /** Transformation types that can be applied to a node */
enum TransformType enum TransformType {
{
TF_LOOKAT, TF_LOOKAT,
TF_ROTATE, TF_ROTATE,
TF_TRANSLATE, TF_TRANSLATE,
@ -79,8 +76,7 @@ enum TransformType
}; };
/** Different types of input data to a vertex or face */ /** Different types of input data to a vertex or face */
enum InputType enum InputType {
{
IT_Invalid, IT_Invalid,
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data. IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
IT_Position, IT_Position,
@ -92,15 +88,13 @@ enum InputType
}; };
/** Supported controller types */ /** Supported controller types */
enum ControllerType enum ControllerType {
{
Skin, Skin,
Morph Morph
}; };
/** Supported morph methods */ /** Supported morph methods */
enum MorphMethod enum MorphMethod {
{
Normalized, Normalized,
Relative Relative
}; };
@ -118,24 +112,21 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
void ToCamelCase(std::string &text); void ToCamelCase(std::string &text);
/** Contains all data for one of the different transformation types */ /** Contains all data for one of the different transformation types */
struct Transform struct Transform {
{
std::string mID; ///< SID of the transform step, by which anim channels address their target node std::string mID; ///< SID of the transform step, by which anim channels address their target node
TransformType mType; TransformType mType;
ai_real f[16]; ///< Interpretation of data depends on the type of the transformation ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
}; };
/** A collada camera. */ /** A collada camera. */
struct Camera struct Camera {
{ Camera() :
Camera() mOrtho(false),
: mOrtho (false) mHorFov(10e10f),
, mHorFov (10e10f) mVerFov(10e10f),
, mVerFov (10e10f) mAspect(10e10f),
, mAspect (10e10f) mZNear(0.1f),
, mZNear (0.1f) mZFar(1000.f) {}
, mZFar (1000.f)
{}
// Name of camera // Name of camera
std::string mName; std::string mName;
@ -159,19 +150,17 @@ struct Camera
#define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
/** A collada light source. */ /** A collada light source. */
struct Light struct Light {
{ Light() :
Light() mType(aiLightSource_UNDEFINED),
: mType (aiLightSource_UNDEFINED) mAttConstant(1.f),
, mAttConstant (1.f) mAttLinear(0.f),
, mAttLinear (0.f) mAttQuadratic(0.f),
, mAttQuadratic (0.f) mFalloffAngle(180.f),
, mFalloffAngle (180.f) mFalloffExponent(0.f),
, mFalloffExponent (0.f) mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
, mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
, mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) mIntensity(1.f) {}
, mIntensity (1.f)
{}
//! Type of the light source aiLightSourceType + ambient //! Type of the light source aiLightSourceType + ambient
unsigned int mType; unsigned int mType;
@ -198,12 +187,10 @@ struct Light
}; };
/** Short vertex index description */ /** Short vertex index description */
struct InputSemanticMapEntry struct InputSemanticMapEntry {
{ InputSemanticMapEntry() :
InputSemanticMapEntry() mSet(0),
: mSet(0) mType(IT_Invalid) {}
, mType(IT_Invalid)
{}
//! Index of set, optional //! Index of set, optional
unsigned int mSet; unsigned int mSet;
@ -213,8 +200,7 @@ struct InputSemanticMapEntry
}; };
/** Table to map from effect to vertex input semantics */ /** Table to map from effect to vertex input semantics */
struct SemanticMappingTable struct SemanticMappingTable {
{
//! Name of material //! Name of material
std::string mMatName; std::string mMatName;
@ -230,8 +216,7 @@ struct SemanticMappingTable
/** A reference to a mesh inside a node, including materials assigned to the various subgroups. /** A reference to a mesh inside a node, including materials assigned to the various subgroups.
* The ID refers to either a mesh or a controller which specifies the mesh * The ID refers to either a mesh or a controller which specifies the mesh
*/ */
struct MeshInstance struct MeshInstance {
{
///< ID of the mesh or controller to be instanced ///< ID of the mesh or controller to be instanced
std::string mMeshOrController; std::string mMeshOrController;
@ -240,29 +225,25 @@ struct MeshInstance
}; };
/** A reference to a camera inside a node*/ /** A reference to a camera inside a node*/
struct CameraInstance struct CameraInstance {
{
///< ID of the camera ///< ID of the camera
std::string mCamera; std::string mCamera;
}; };
/** A reference to a light inside a node*/ /** A reference to a light inside a node*/
struct LightInstance struct LightInstance {
{
///< ID of the camera ///< ID of the camera
std::string mLight; std::string mLight;
}; };
/** A reference to a node inside a node*/ /** A reference to a node inside a node*/
struct NodeInstance struct NodeInstance {
{
///< ID of the node ///< ID of the node
std::string mNode; std::string mNode;
}; };
/** A node in a scene hierarchy */ /** A node in a scene hierarchy */
struct Node struct Node {
{
std::string mName; std::string mName;
std::string mID; std::string mID;
std::string mSID; std::string mSID;
@ -288,8 +269,8 @@ struct Node
std::string mPrimaryCamera; std::string mPrimaryCamera;
//! Constructor. Begin with a zero parent //! Constructor. Begin with a zero parent
Node() Node() :
: mParent( nullptr ){ mParent(nullptr) {
// empty // empty
} }
@ -301,16 +282,14 @@ struct Node
}; };
/** Data source array: either floats or strings */ /** Data source array: either floats or strings */
struct Data struct Data {
{
bool mIsStringArray; bool mIsStringArray;
std::vector<ai_real> mValues; std::vector<ai_real> mValues;
std::vector<std::string> mStrings; std::vector<std::string> mStrings;
}; };
/** Accessor to a data array */ /** Accessor to a data array */
struct Accessor struct Accessor {
{
size_t mCount; // in number of objects size_t mCount; // in number of objects
size_t mSize; // size of an object, in elements (floats or strings, mostly 1) size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
size_t mOffset; // in number of values size_t mOffset; // in number of values
@ -321,47 +300,52 @@ struct Accessor
std::string mSource; // URL of the source array std::string mSource; // URL of the source array
mutable const Data *mData; // Pointer to the source array, if resolved. NULL else mutable const Data *mData; // Pointer to the source array, if resolved. NULL else
Accessor() Accessor() {
{ mCount = 0;
mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL; mSize = 0;
mOffset = 0;
mStride = 0;
mData = NULL;
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0; mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
} }
}; };
/** A single face in a mesh */ /** A single face in a mesh */
struct Face struct Face {
{
std::vector<size_t> mIndices; std::vector<size_t> mIndices;
}; };
/** An input channel for mesh data, referring to a single accessor */ /** An input channel for mesh data, referring to a single accessor */
struct InputChannel struct InputChannel {
{
InputType mType; // Type of the data InputType mType; // Type of the data
size_t mIndex; // Optional index, if multiple sets of the same data type are given 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. 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. 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 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 */ /** Subset of a mesh with a certain material */
struct SubMesh struct SubMesh {
{
std::string mMaterial; ///< subgroup identifier std::string mMaterial; ///< subgroup identifier
size_t mNumFaces; ///< number of faces in this submesh size_t mNumFaces; ///< number of faces in this submesh
}; };
/** Contains data for a single mesh */ /** Contains data for a single mesh */
struct Mesh struct Mesh {
{ Mesh(const std::string &id) :
Mesh() mId(id) {
{
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
mNumUVComponents[i] = 2; mNumUVComponents[i] = 2;
} }
const std::string mId;
std::string mName; std::string mName;
// just to check if there's some sophisticated addressing involved... // just to check if there's some sophisticated addressing involved...
@ -394,8 +378,7 @@ struct Mesh
}; };
/** Which type of primitives the ReadPrimitives() function is going to read */ /** Which type of primitives the ReadPrimitives() function is going to read */
enum PrimitiveType enum PrimitiveType {
{
Prim_Invalid, Prim_Invalid,
Prim_Lines, Prim_Lines,
Prim_LineStrip, Prim_LineStrip,
@ -407,8 +390,7 @@ enum PrimitiveType
}; };
/** A skeleton controller to deform a mesh with the use of joints */ /** A skeleton controller to deform a mesh with the use of joints */
struct Controller struct Controller {
{
// controller type // controller type
ControllerType mType; ControllerType mType;
@ -443,29 +425,25 @@ struct Controller
}; };
/** A collada material. Pretty much the only member is a reference to an effect. */ /** A collada material. Pretty much the only member is a reference to an effect. */
struct Material struct Material {
{
std::string mName; std::string mName;
std::string mEffect; std::string mEffect;
}; };
/** Type of the effect param */ /** Type of the effect param */
enum ParamType enum ParamType {
{
Param_Sampler, Param_Sampler,
Param_Surface Param_Surface
}; };
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */ /** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
struct EffectParam struct EffectParam {
{
ParamType mType; ParamType mType;
std::string mReference; // to which other thing the param is referring to. std::string mReference; // to which other thing the param is referring to.
}; };
/** Shading type supported by the standard effect spec of Collada */ /** Shading type supported by the standard effect spec of Collada */
enum ShadeType enum ShadeType {
{
Shade_Invalid, Shade_Invalid,
Shade_Constant, Shade_Constant,
Shade_Lambert, Shade_Lambert,
@ -474,18 +452,16 @@ enum ShadeType
}; };
/** Represents a texture sampler in collada */ /** Represents a texture sampler in collada */
struct Sampler struct Sampler {
{ Sampler() :
Sampler() mWrapU(true),
: mWrapU (true) mWrapV(true),
, mWrapV (true) mMirrorU(),
, mMirrorU () mMirrorV(),
, mMirrorV () mOp(aiTextureOp_Multiply),
, mOp (aiTextureOp_Multiply) mUVId(UINT_MAX),
, mUVId (UINT_MAX) mWeighting(1.f),
, mWeighting (1.f) mMixWithPrevious(1.f) {}
, mMixWithPrevious (1.f)
{}
/** Name of image reference /** Name of image reference
*/ */
@ -537,8 +513,7 @@ struct Sampler
/** A collada effect. Can contain about anything according to the Collada spec, /** A collada effect. Can contain about anything according to the Collada spec,
but we limit our version to a reasonable subset. */ but we limit our version to a reasonable subset. */
struct Effect struct Effect {
{
// Shading mode // Shading mode
ShadeType mShadeType; ShadeType mShadeType;
@ -566,30 +541,28 @@ struct Effect
// Double-sided? // Double-sided?
bool mDoubleSided, mWireframe, mFaceted; bool mDoubleSided, mWireframe, mFaceted;
Effect() Effect() :
: mShadeType (Shade_Phong) mShadeType(Shade_Phong),
, mEmissive ( 0, 0, 0, 1) mEmissive(0, 0, 0, 1),
, mAmbient ( 0.1f, 0.1f, 0.1f, 1) mAmbient(0.1f, 0.1f, 0.1f, 1),
, mDiffuse ( 0.6f, 0.6f, 0.6f, 1) mDiffuse(0.6f, 0.6f, 0.6f, 1),
, mSpecular ( 0.4f, 0.4f, 0.4f, 1) mSpecular(0.4f, 0.4f, 0.4f, 1),
, mTransparent ( 0, 0, 0, 1) mTransparent(0, 0, 0, 1),
, mShininess (10.0f) mShininess(10.0f),
, mRefractIndex (1.f) mRefractIndex(1.f),
, mReflectivity (0.f) mReflectivity(0.f),
, mTransparency (1.f) mTransparency(1.f),
, mHasTransparency (false) mHasTransparency(false),
, mRGBTransparency(false) mRGBTransparency(false),
, mInvertTransparency(false) mInvertTransparency(false),
, mDoubleSided (false) mDoubleSided(false),
, mWireframe (false) mWireframe(false),
, mFaceted (false) mFaceted(false) {
{
} }
}; };
/** An image, meaning texture */ /** An image, meaning texture */
struct Image struct Image {
{
std::string mFileName; std::string mFileName;
/** Embedded image data */ /** Embedded image data */
@ -600,8 +573,7 @@ struct Image
}; };
/** An animation channel. */ /** An animation channel. */
struct AnimationChannel struct AnimationChannel {
{
/** URL of the data to animate. Could be about anything, but we support only the /** URL of the data to animate. Could be about anything, but we support only the
* "NodeID/TransformID.SubElement" notation * "NodeID/TransformID.SubElement" notation
*/ */
@ -620,8 +592,7 @@ struct AnimationChannel
}; };
/** An animation. Container for 0-x animation channels or 0-x animations */ /** An animation. Container for 0-x animation channels or 0-x animations */
struct Animation struct Animation {
{
/** Anim name */ /** Anim name */
std::string mName; std::string mName;
@ -632,19 +603,16 @@ struct Animation
std::vector<Animation *> mSubAnims; std::vector<Animation *> mSubAnims;
/** Destructor */ /** Destructor */
~Animation() ~Animation() {
{
for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
delete *it; delete *it;
} }
/** Collect all channels in the animation hierarchy into a single channel list. */ /** Collect all channels in the animation hierarchy into a single channel list. */
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
{
channels.insert(channels.end(), mChannels.begin(), mChannels.end()); channels.insert(channels.end(), mChannels.begin(), mChannels.end());
for (std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
{
Animation *pAnim = (*it); Animation *pAnim = (*it);
pAnim->CollectChannelsRecursively(channels); pAnim->CollectChannelsRecursively(channels);
@ -652,18 +620,15 @@ struct Animation
} }
/** Combine all single-channel animations' channel into the same (parent) animation channel list. */ /** Combine all single-channel animations' channel into the same (parent) animation channel list. */
void CombineSingleChannelAnimations() void CombineSingleChannelAnimations() {
{
CombineSingleChannelAnimationsRecursively(this); CombineSingleChannelAnimationsRecursively(this);
} }
void CombineSingleChannelAnimationsRecursively(Animation *pParent) void CombineSingleChannelAnimationsRecursively(Animation *pParent) {
{
std::set<std::string> childrenTargets; std::set<std::string> childrenTargets;
bool childrenAnimationsHaveDifferentChannels = true; bool childrenAnimationsHaveDifferentChannels = true;
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
{
Animation *anim = *it; Animation *anim = *it;
CombineSingleChannelAnimationsRecursively(anim); CombineSingleChannelAnimationsRecursively(anim);
@ -678,10 +643,8 @@ struct Animation
} }
// We only want to combine animations if they have different channels // We only want to combine animations if they have different channels
if (childrenAnimationsHaveDifferentChannels) if (childrenAnimationsHaveDifferentChannels) {
{ for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
{
Animation *anim = *it; Animation *anim = *it;
pParent->mChannels.push_back(anim->mChannels[0]); pParent->mChannels.push_back(anim->mChannels[0]);
@ -696,8 +659,7 @@ struct Animation
}; };
/** Description of a collada animation channel which has been determined to affect the current node */ /** Description of a collada animation channel which has been determined to affect the current node */
struct ChannelEntry struct ChannelEntry {
{
const Collada::AnimationChannel *mChannel; ///> the source channel const Collada::AnimationChannel *mChannel; ///> the source channel
std::string mTargetId; std::string mTargetId;
std::string mTransformId; // the ID of the transformation step of the node which is influenced std::string mTransformId; // the ID of the transformation step of the node which is influenced
@ -710,15 +672,14 @@ struct ChannelEntry
const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values
const Collada::Data *mValueData; ///> Source datat array for the key value values const Collada::Data *mValueData; ///> Source datat array for the key value values
ChannelEntry() ChannelEntry() :
: mChannel() mChannel(),
, mTransformIndex() mTransformIndex(),
, mSubElement() mSubElement(),
, mTimeAccessor() mTimeAccessor(),
, mTimeData() mTimeData(),
, mValueAccessor() mValueAccessor(),
, mValueData() mValueData() {}
{}
}; };
} // end of namespace Collada } // end of namespace Collada

View File

@ -46,24 +46,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaLoader.h" #include "ColladaLoader.h"
#include "ColladaParser.h" #include "ColladaParser.h"
#include <assimp/ColladaMetaData.h>
#include <assimp/Defines.h>
#include <assimp/anim.h> #include <assimp/anim.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/importerdesc.h>
#include <assimp/Defines.h>
#include <assimp/fast_atof.h> #include <assimp/CreateAnimMesh.h>
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/SkeletonMeshBuilder.h> #include <assimp/SkeletonMeshBuilder.h>
#include <assimp/CreateAnimMesh.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/fast_atof.h>
#include "time.h"
#include "math.h" #include "math.h"
#include "time.h"
#include <algorithm> #include <algorithm>
#include <numeric>
#include <memory> #include <memory>
#include <numeric>
namespace Assimp { namespace Assimp {
@ -82,22 +83,34 @@ static const aiImporterDesc desc = {
"dae zae" "dae zae"
}; };
static const float kMillisecondsFromSeconds = 1000.f;
// Add an item of metadata to a node
// Assumes the key is not already in the list
template <typename T>
inline void AddNodeMetaData(aiNode *node, const std::string &key, const T &value) {
if (nullptr == node->mMetaData) {
node->mMetaData = new aiMetadata();
}
node->mMetaData->Add(key, value);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
ColladaLoader::ColladaLoader() ColladaLoader::ColladaLoader() :
: mFileName() mFileName(),
, mMeshIndexByID() mMeshIndexByID(),
, mMaterialIndexByName() mMaterialIndexByName(),
, mMeshes() mMeshes(),
, newMats() newMats(),
, mCameras() mCameras(),
, mLights() mLights(),
, mTextures() mTextures(),
, mAnims() mAnims(),
, noSkeletonMesh(false) noSkeletonMesh(false),
, ignoreUpDirection(false) ignoreUpDirection(false),
, useColladaName(false) useColladaName(false),
, mNodeNameCounter(0) { mNodeNameCounter(0) {
// empty // empty
} }
@ -176,7 +189,6 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO
// parse the input file // parse the input file
ColladaParser parser(pIOHandler, pFile); ColladaParser parser(pIOHandler, pFile);
if (!parser.mRootNode) { if (!parser.mRootNode) {
throw DeadlyImportError("Collada: File came out empty. Something is wrong here."); throw DeadlyImportError("Collada: File came out empty. Something is wrong here.");
} }
@ -230,27 +242,15 @@ void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IO
} }
} }
// store all meshes
StoreSceneMeshes(pScene); StoreSceneMeshes(pScene);
// store all materials
StoreSceneMaterials(pScene); StoreSceneMaterials(pScene);
// store all textures
StoreSceneTextures(pScene); StoreSceneTextures(pScene);
// store all lights
StoreSceneLights(pScene); StoreSceneLights(pScene);
// store all cameras
StoreSceneCameras(pScene); StoreSceneCameras(pScene);
// store all animations
StoreAnimations(pScene, parser); StoreAnimations(pScene, parser);
// If no meshes have been loaded, it's probably just an animated skeleton. // If no meshes have been loaded, it's probably just an animated skeleton.
if (0u == pScene->mNumMeshes) { if (0u == pScene->mNumMeshes) {
if (!noSkeletonMesh) { if (!noSkeletonMesh) {
SkeletonMeshBuilder hero(pScene); SkeletonMeshBuilder hero(pScene);
} }
@ -266,6 +266,15 @@ aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collad
// find a name for the new node. It's more complicated than you might think // find a name for the new node. It's more complicated than you might think
node->mName.Set(FindNameForNode(pNode)); node->mName.Set(FindNameForNode(pNode));
// if we're not using the unique IDs, hold onto them for reference and export
if (useColladaName) {
if (!pNode->mID.empty()) {
AddNodeMetaData(node, AI_METADATA_COLLADA_ID, aiString(pNode->mID));
}
if (!pNode->mSID.empty()) {
AddNodeMetaData(node, AI_METADATA_COLLADA_SID, aiString(pNode->mSID));
}
}
// calculate the transformation matrix for it // calculate the transformation matrix for it
node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms); node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms);
@ -289,13 +298,8 @@ aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collad
node->mChildren[pNode->mChildren.size() + a]->mParent = node; node->mChildren[pNode->mChildren.size() + a]->mParent = node;
} }
// construct meshes
BuildMeshesForNode(pParser, pNode, node); BuildMeshesForNode(pParser, pNode, node);
// construct cameras
BuildCamerasForNode(pParser, pNode, node); BuildCamerasForNode(pParser, pNode, node);
// construct lights
BuildLightsForNode(pParser, pNode, node); BuildLightsForNode(pParser, pNode, node);
return node; return node;
@ -331,9 +335,7 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser& pParser, const Col
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Resolve UV channels // Resolve UV channels
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler, void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
const Collada::SemanticMappingTable& table) {
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel); std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it != table.mMap.end()) { if (it != table.mMap.end()) {
if (it->second.mType != Collada::IT_Texcoord) { if (it->second.mType != Collada::IT_Texcoord) {
@ -372,8 +374,7 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Colla
if (out->mType == aiLightSource_AMBIENT) { if (out->mType == aiLightSource_AMBIENT) {
out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0); out->mColorDiffuse = out->mColorSpecular = aiColor3D(0, 0, 0);
out->mColorAmbient = srcLight->mColor * srcLight->mIntensity; out->mColorAmbient = srcLight->mColor * srcLight->mIntensity;
} } else {
else {
// collada doesn't differentiate between these color types // collada doesn't differentiate between these color types
out->mColorDiffuse = out->mColorSpecular = srcLight->mColor * srcLight->mIntensity; out->mColorDiffuse = out->mColorSpecular = srcLight->mColor * srcLight->mIntensity;
out->mColorAmbient = aiColor3D(0, 0, 0); out->mColorAmbient = aiColor3D(0, 0, 0);
@ -391,14 +392,12 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Colla
// epsilon chosen to be 0.1 // epsilon chosen to be 0.1
out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) + out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) +
out->mAngleInnerCone; out->mAngleInnerCone;
} } else {
else {
out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle); out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
if (out->mAngleOuterCone < out->mAngleInnerCone) if (out->mAngleOuterCone < out->mAngleInnerCone)
std::swap(out->mAngleInnerCone, out->mAngleOuterCone); std::swap(out->mAngleInnerCone, out->mAngleOuterCone);
} }
} } else {
else {
out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle); out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle);
} }
} }
@ -488,13 +487,11 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
} }
} }
if (nullptr == srcMesh) { if (nullptr == srcMesh) {
ASSIMP_LOG_WARN_F("Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping."); ASSIMP_LOG_WARN_F("Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping.");
continue; continue;
} }
} } else {
else {
// ID found in the mesh library -> direct reference to an unskinned mesh // ID found in the mesh library -> direct reference to an unskinned mesh
srcMesh = srcMeshIt->second; srcMesh = srcMeshIt->second;
} }
@ -515,8 +512,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
if (meshMatIt != mid.mMaterials.end()) { if (meshMatIt != mid.mMaterials.end()) {
table = &meshMatIt->second; table = &meshMatIt->second;
meshMaterial = table->mMatName; meshMaterial = table->mMatName;
} } else {
else {
ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <", ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
mid.mMeshOrController, ">."); mid.mMeshOrController, ">.");
if (!mid.mMaterials.empty()) { if (!mid.mMaterials.empty()) {
@ -552,8 +548,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find(index); std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find(index);
if (dstMeshIt != mMeshIndexByID.end()) { if (dstMeshIt != mMeshIndexByID.end()) {
newMeshRefs.push_back(dstMeshIt->second); newMeshRefs.push_back(dstMeshIt->second);
} } else {
else {
// else we have to add the mesh to the collection and store its newly assigned index at the node // else we have to add the mesh to the collection and store its newly assigned index at the node
aiMesh *dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart); aiMesh *dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart);
@ -561,7 +556,8 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
newMeshRefs.push_back(mMeshes.size()); newMeshRefs.push_back(mMeshes.size());
mMeshIndexByID[index] = mMeshes.size(); mMeshIndexByID[index] = mMeshes.size();
mMeshes.push_back(dstMesh); mMeshes.push_back(dstMesh);
vertexStart += dstMesh->mNumVertices; faceStart += submesh.mNumFaces; vertexStart += dstMesh->mNumVertices;
faceStart += submesh.mNumFaces;
// assign the material index // assign the material index
dstMesh->mMaterialIndex = matIdx; dstMesh->mMaterialIndex = matIdx;
@ -589,6 +585,10 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Colla
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Find mesh from either meshes or morph target meshes // Find mesh from either meshes or morph target meshes
aiMesh *ColladaLoader::findMesh(const std::string &meshid) { aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
if ( meshid.empty()) {
return nullptr;
}
for (unsigned int i = 0; i < mMeshes.size(); ++i) { for (unsigned int i = 0; i < mMeshes.size(); ++i) {
if (std::string(mMeshes[i]->mName.data) == meshid) { if (std::string(mMeshes[i]->mName.data) == meshid) {
return mMeshes[i]; return mMeshes[i];
@ -610,7 +610,11 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) { const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
std::unique_ptr<aiMesh> dstMesh(new aiMesh); std::unique_ptr<aiMesh> dstMesh(new aiMesh);
if (useColladaName) {
dstMesh->mName = pSrcMesh->mName; dstMesh->mName = pSrcMesh->mName;
} else {
dstMesh->mName = pSrcMesh->mId;
}
// count the vertices addressed by its faces // count the vertices addressed by its faces
const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace, const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace,
@ -619,30 +623,26 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
// copy positions // copy positions
dstMesh->mNumVertices = static_cast<unsigned int>(numVertices); dstMesh->mNumVertices = static_cast<unsigned int>(numVertices);
dstMesh->mVertices = new aiVector3D[numVertices]; dstMesh->mVertices = new aiVector3D[numVertices];
std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + pStartVertex + numVertices, dstMesh->mVertices);
pStartVertex + numVertices, dstMesh->mVertices);
// normals, if given. HACK: (thom) Due to the glorious Collada spec we never // normals, if given. HACK: (thom) Due to the glorious Collada spec we never
// know if we have the same number of normals as there are positions. So we // know if we have the same number of normals as there are positions. So we
// also ignore any vertex attribute if it has a different count // also ignore any vertex attribute if it has a different count
if (pSrcMesh->mNormals.size() >= pStartVertex + numVertices) { if (pSrcMesh->mNormals.size() >= pStartVertex + numVertices) {
dstMesh->mNormals = new aiVector3D[numVertices]; dstMesh->mNormals = new aiVector3D[numVertices];
std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + pStartVertex + numVertices, dstMesh->mNormals);
pStartVertex + numVertices, dstMesh->mNormals);
} }
// tangents, if given. // tangents, if given.
if (pSrcMesh->mTangents.size() >= pStartVertex + numVertices) { if (pSrcMesh->mTangents.size() >= pStartVertex + numVertices) {
dstMesh->mTangents = new aiVector3D[numVertices]; dstMesh->mTangents = new aiVector3D[numVertices];
std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + pStartVertex + numVertices, dstMesh->mTangents);
pStartVertex + numVertices, dstMesh->mTangents);
} }
// bitangents, if given. // bitangents, if given.
if (pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) { if (pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) {
dstMesh->mBitangents = new aiVector3D[numVertices]; dstMesh->mBitangents = new aiVector3D[numVertices];
std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents);
pStartVertex + numVertices, dstMesh->mBitangents);
} }
// same for texturecoords, as many as we have // same for texturecoords, as many as we have
@ -711,10 +711,10 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) { for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) {
const Collada::Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i)); const Collada::Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i));
aiMesh *aimesh = findMesh(targetMesh->mName); aiMesh *aimesh = findMesh(useColladaName ? targetMesh->mName : targetMesh->mId);
if (!aimesh) { if (!aimesh) {
if (targetMesh->mSubMeshes.size() > 1) { if (targetMesh->mSubMeshes.size() > 1) {
throw DeadlyImportError("Morhing target mesh must be a single"); throw DeadlyImportError("Morphing target mesh must be a single");
} }
aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0); aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0);
mTargetMeshes.push_back(aimesh); mTargetMeshes.push_back(aimesh);
@ -736,9 +736,7 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
animMesh->mName = targetMesh->mName; animMesh->mName = targetMesh->mName;
animMeshes.push_back(animMesh); animMeshes.push_back(animMesh);
} }
dstMesh->mMethod = (method == Collada::Relative) dstMesh->mMethod = (method == Collada::Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED;
? aiMorphingMethod_MORPH_RELATIVE
: aiMorphingMethod_MORPH_NORMALIZED;
dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()]; dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()];
dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size()); dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
for (unsigned int i = 0; i < animMeshes.size(); ++i) { for (unsigned int i = 0; i < animMeshes.size(); ++i) {
@ -792,7 +790,6 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex]; IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex];
size_t pairCount = pSrcController->mWeightCounts[orgIndex]; size_t pairCount = pSrcController->mWeightCounts[orgIndex];
for (size_t b = 0; b < pairCount; ++b, ++iit) { for (size_t b = 0; b < pairCount; ++b, ++iit) {
const size_t jointIndex = iit->first; const size_t jointIndex = iit->first;
const size_t vertexIndex = iit->second; const size_t vertexIndex = iit->second;
@ -802,8 +799,7 @@ aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::M
} }
// one day I gonna kill that XSI Collada exporter // one day I gonna kill that XSI Collada exporter
if (weight > 0.0f) if (weight > 0.0f) {
{
aiVertexWeight w; aiVertexWeight w;
w.mVertexId = static_cast<unsigned int>(a - pStartVertex); w.mVertexId = static_cast<unsigned int>(a - pStartVertex);
w.mWeight = weight; w.mWeight = weight;
@ -980,8 +976,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
std::set<std::string> animTargets; std::set<std::string> animTargets;
animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str()); animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str());
bool collectedAnimationsHaveDifferentChannels = true; bool collectedAnimationsHaveDifferentChannels = true;
for (size_t b = 0; b < collectedAnimIndices.size(); ++b) for (size_t b = 0; b < collectedAnimIndices.size(); ++b) {
{
aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]]; aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]];
std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str()); std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str());
if (animTargets.find(channelName) == animTargets.end()) { if (animTargets.find(channelName) == animTargets.end()) {
@ -996,8 +991,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
continue; continue;
// if there are other animations which fit the template anim, combine all channels into a single anim // if there are other animations which fit the template anim, combine all channels into a single anim
if (!collectedAnimIndices.empty()) if (!collectedAnimIndices.empty()) {
{
aiAnimation *combinedAnim = new aiAnimation(); aiAnimation *combinedAnim = new aiAnimation();
combinedAnim->mName = aiString(std::string("combinedAnim_") + char('0' + a)); combinedAnim->mName = aiString(std::string("combinedAnim_") + char('0' + a));
combinedAnim->mDuration = templateAnim->mDuration; combinedAnim->mDuration = templateAnim->mDuration;
@ -1012,8 +1006,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
mAnims[a] = combinedAnim; mAnims[a] = combinedAnim;
// move the memory of all other anims to the combined anim and erase them from the source anims // move the memory of all other anims to the combined anim and erase them from the source anims
for (size_t b = 0; b < collectedAnimIndices.size(); ++b) for (size_t b = 0; b < collectedAnimIndices.size(); ++b) {
{
aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]]; aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]];
combinedAnim->mChannels[1 + b] = srcAnimation->mChannels[0]; combinedAnim->mChannels[1 + b] = srcAnimation->mChannels[0];
srcAnimation->mChannels[0] = NULL; srcAnimation->mChannels[0] = NULL;
@ -1022,8 +1015,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
// in a second go, delete all the single-channel-anims that we've stripped from their channels // in a second go, delete all the single-channel-anims that we've stripped from their channels
// back to front to preserve indices - you know, removing an element from a vector moves all elements behind the removed one // back to front to preserve indices - you know, removing an element from a vector moves all elements behind the removed one
while (!collectedAnimIndices.empty()) while (!collectedAnimIndices.empty()) {
{
mAnims.erase(mAnims.begin() + collectedAnimIndices.back()); mAnims.erase(mAnims.begin() + collectedAnimIndices.back());
collectedAnimIndices.pop_back(); collectedAnimIndices.pop_back();
} }
@ -1032,8 +1024,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
} }
// now store all anims in the scene // now store all anims in the scene
if (!mAnims.empty()) if (!mAnims.empty()) {
{
pScene->mNumAnimations = static_cast<unsigned int>(mAnims.size()); pScene->mNumAnimations = static_cast<unsigned int>(mAnims.size());
pScene->mAnimations = new aiAnimation *[mAnims.size()]; pScene->mAnimations = new aiAnimation *[mAnims.size()];
std::copy(mAnims.begin(), mAnims.end(), pScene->mAnimations); std::copy(mAnims.begin(), mAnims.end(), pScene->mAnimations);
@ -1044,8 +1035,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructs the animations for the given source anim // Constructs the animations for the given source anim
void ColladaLoader::StoreAnimations(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string &pPrefix) void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pPrefix) {
{
std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName; std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName;
// create nested animations, if given // create nested animations, if given
@ -1057,47 +1047,38 @@ void ColladaLoader::StoreAnimations(aiScene* pScene, const ColladaParser& pParse
CreateAnimation(pScene, pParser, pSrcAnim, animName); CreateAnimation(pScene, pParser, pSrcAnim, animName);
} }
struct MorphTimeValues struct MorphTimeValues {
{
float mTime; float mTime;
struct key struct key {
{
float mWeight; float mWeight;
unsigned int mValue; unsigned int mValue;
}; };
std::vector<key> mKeys; std::vector<key> mKeys;
}; };
void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, float weight, unsigned int value) void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, float weight, unsigned int value) {
{
MorphTimeValues::key k; MorphTimeValues::key k;
k.mValue = value; k.mValue = value;
k.mWeight = weight; k.mWeight = weight;
if (values.size() == 0 || time < values[0].mTime) if (values.size() == 0 || time < values[0].mTime) {
{
MorphTimeValues val; MorphTimeValues val;
val.mTime = time; val.mTime = time;
val.mKeys.push_back(k); val.mKeys.push_back(k);
values.insert(values.begin(), val); values.insert(values.begin(), val);
return; return;
} }
if (time > values.back().mTime) if (time > values.back().mTime) {
{
MorphTimeValues val; MorphTimeValues val;
val.mTime = time; val.mTime = time;
val.mKeys.push_back(k); val.mKeys.push_back(k);
values.insert(values.end(), val); values.insert(values.end(), val);
return; return;
} }
for (unsigned int i = 0; i < values.size(); i++) for (unsigned int i = 0; i < values.size(); i++) {
{ if (std::abs(time - values[i].mTime) < 1e-6f) {
if (std::abs(time - values[i].mTime) < 1e-6f)
{
values[i].mKeys.push_back(k); values[i].mKeys.push_back(k);
return; return;
} } else if (time > values[i].mTime && time < values[i + 1].mTime) {
else if (time > values[i].mTime && time < values[i + 1].mTime)
{
MorphTimeValues val; MorphTimeValues val;
val.mTime = time; val.mTime = time;
val.mKeys.push_back(k); val.mKeys.push_back(k);
@ -1108,10 +1089,8 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
// should not get here // should not get here
} }
float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value) float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value) {
{ for (unsigned int i = 0; i < values[key].mKeys.size(); i++) {
for (unsigned int i = 0; i < values[key].mKeys.size(); i++)
{
if (values[key].mKeys[i].mValue == value) if (values[key].mKeys[i].mValue == value)
return values[key].mKeys[i].mWeight; return values[key].mKeys[i].mWeight;
} }
@ -1122,8 +1101,7 @@ float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsign
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructs the animation for the given source anim // Constructs the animation for the given source anim
void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName) void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pName) {
{
// collect a list of animatable nodes // collect a list of animatable nodes
std::vector<const aiNode *> nodes; std::vector<const aiNode *> nodes;
CollectNodes(pScene->mRootNode, nodes); CollectNodes(pScene->mRootNode, nodes);
@ -1131,8 +1109,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
std::vector<aiNodeAnim *> anims; std::vector<aiNodeAnim *> anims;
std::vector<aiMeshMorphAnim *> morphAnims; std::vector<aiMeshMorphAnim *> morphAnims;
for (std::vector<const aiNode*>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) for (std::vector<const aiNode *>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) {
{
// find all the collada anim channels which refer to the current node // find all the collada anim channels which refer to the current node
std::vector<Collada::ChannelEntry> entries; std::vector<Collada::ChannelEntry> entries;
std::string nodeName = (*nit)->mName.data; std::string nodeName = (*nit)->mName.data;
@ -1146,16 +1123,14 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
// now check all channels if they affect the current node // now check all channels if they affect the current node
std::string targetID, subElement; std::string targetID, subElement;
for (std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin(); for (std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
cit != pSrcAnim->mChannels.end(); ++cit) cit != pSrcAnim->mChannels.end(); ++cit) {
{
const Collada::AnimationChannel &srcChannel = *cit; const Collada::AnimationChannel &srcChannel = *cit;
Collada::ChannelEntry entry; Collada::ChannelEntry entry;
// we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others // we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others
// find the slash that separates the node name - there should be only one // find the slash that separates the node name - there should be only one
std::string::size_type slashPos = srcChannel.mTarget.find('/'); std::string::size_type slashPos = srcChannel.mTarget.find('/');
if (slashPos == std::string::npos) if (slashPos == std::string::npos) {
{
std::string::size_type targetPos = srcChannel.mTarget.find(srcNode->mID); std::string::size_type targetPos = srcChannel.mTarget.find(srcNode->mID);
if (targetPos == std::string::npos) if (targetPos == std::string::npos)
continue; continue;
@ -1179,8 +1154,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
// find the dot that separates the transformID - there should be only one or zero // find the dot that separates the transformID - there should be only one or zero
std::string::size_type dotPos = srcChannel.mTarget.find('.'); std::string::size_type dotPos = srcChannel.mTarget.find('.');
if (dotPos != std::string::npos) if (dotPos != std::string::npos) {
{
if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos) if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos)
continue; continue;
@ -1198,15 +1172,13 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
entry.mSubElement = 2; entry.mSubElement = 2;
else else
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring"); ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
} } else {
else {
// no subelement following, transformId is remaining string // no subelement following, transformId is remaining string
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1); entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
} }
std::string::size_type bracketPos = srcChannel.mTarget.find('('); std::string::size_type bracketPos = srcChannel.mTarget.find('(');
if (bracketPos != std::string::npos) if (bracketPos != std::string::npos) {
{
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1); entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
subElement.clear(); subElement.clear();
subElement = srcChannel.mTarget.substr(bracketPos); subElement = srcChannel.mTarget.substr(bracketPos);
@ -1251,14 +1223,11 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
if (srcNode->mTransforms[a].mID == entry.mTransformId) if (srcNode->mTransforms[a].mID == entry.mTransformId)
entry.mTransformIndex = a; entry.mTransformIndex = a;
if (entry.mTransformIndex == SIZE_MAX) if (entry.mTransformIndex == SIZE_MAX) {
{ if (entry.mTransformId.find("morph-weights") != std::string::npos) {
if (entry.mTransformId.find("morph-weights") != std::string::npos)
{
entry.mTargetId = entry.mTransformId; entry.mTargetId = entry.mTransformId;
entry.mTransformId = ""; entry.mTransformId = "";
} } else
else
continue; continue;
} }
@ -1272,8 +1241,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
// resolve the data pointers for all anim channels. Find the minimum time while we're at it // resolve the data pointers for all anim channels. Find the minimum time while we're at it
ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20); ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20);
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
{
Collada::ChannelEntry &e = *it; Collada::ChannelEntry &e = *it;
e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes); e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes);
e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource); e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource);
@ -1284,8 +1252,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\"."); throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\".");
if (e.mTimeAccessor->mCount > 0) if (e.mTimeAccessor->mCount > 0) {
{
// find bounding times // find bounding times
startTime = std::min(startTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, 0, 0)); startTime = std::min(startTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, 0, 0));
endTime = std::max(endTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount - 1, 0)); endTime = std::max(endTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount - 1, 0));
@ -1293,25 +1260,21 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
} }
std::vector<aiMatrix4x4> resultTrafos; std::vector<aiMatrix4x4> resultTrafos;
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
{
// create a local transformation chain of the node's transforms // create a local transformation chain of the node's transforms
std::vector<Collada::Transform> transforms = srcNode->mTransforms; std::vector<Collada::Transform> transforms = srcNode->mTransforms;
// now for every unique point in time, find or interpolate the key values for that time // now for every unique point in time, find or interpolate the key values for that time
// and apply them to the transform chain. Then the node's present transformation can be calculated. // and apply them to the transform chain. Then the node's present transformation can be calculated.
ai_real time = startTime; ai_real time = startTime;
while (1) while (1) {
{ for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
{
Collada::ChannelEntry &e = *it; Collada::ChannelEntry &e = *it;
// find the keyframe behind the current point in time // find the keyframe behind the current point in time
size_t pos = 0; size_t pos = 0;
ai_real postTime = 0.0; ai_real postTime = 0.0;
while (1) while (1) {
{
if (pos >= e.mTimeAccessor->mCount) if (pos >= e.mTimeAccessor->mCount)
break; break;
postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0); postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0);
@ -1328,13 +1291,11 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c); temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c);
// if not exactly at the key time, interpolate with previous value set // if not exactly at the key time, interpolate with previous value set
if (postTime > time && pos > 0) if (postTime > time && pos > 0) {
{
ai_real preTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos - 1, 0); ai_real preTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos - 1, 0);
ai_real factor = (time - postTime) / (preTime - postTime); ai_real factor = (time - postTime) / (preTime - postTime);
for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) {
{
ai_real v = ReadFloat(*e.mValueAccessor, *e.mValueData, pos - 1, c); ai_real v = ReadFloat(*e.mValueAccessor, *e.mValueData, pos - 1, c);
temp[c] += (v - temp[c]) * factor; temp[c] += (v - temp[c]) * factor;
} }
@ -1353,17 +1314,14 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
// find next point in time to evaluate. That's the closest frame larger than the current in any channel // find next point in time to evaluate. That's the closest frame larger than the current in any channel
ai_real nextTime = ai_real(1e20); ai_real nextTime = ai_real(1e20);
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
{
Collada::ChannelEntry &channelElement = *it; Collada::ChannelEntry &channelElement = *it;
// find the next time value larger than the current // find the next time value larger than the current
size_t pos = 0; size_t pos = 0;
while (pos < channelElement.mTimeAccessor->mCount) while (pos < channelElement.mTimeAccessor->mCount) {
{
const ai_real t = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0); const ai_real t = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0);
if (t > time) if (t > time) {
{
nextTime = std::min(nextTime, t); nextTime = std::min(nextTime, t);
break; break;
} }
@ -1403,8 +1361,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
// ai_assert( resultTrafos.size() > 0); // ai_assert( resultTrafos.size() > 0);
// build an animation channel for the given node out of these trafo keys // build an animation channel for the given node out of these trafo keys
if (!resultTrafos.empty()) if (!resultTrafos.empty()) {
{
aiNodeAnim *dstAnim = new aiNodeAnim; aiNodeAnim *dstAnim = new aiNodeAnim;
dstAnim->mNodeName = nodeName; dstAnim->mNodeName = nodeName;
dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size()); dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size());
@ -1414,30 +1371,25 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()]; dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()]; dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
for (size_t a = 0; a < resultTrafos.size(); ++a) for (size_t a = 0; a < resultTrafos.size(); ++a) {
{
aiMatrix4x4 mat = resultTrafos[a]; aiMatrix4x4 mat = resultTrafos[a];
double time = double(mat.d4); // remember? time is stored in mat.d4 double time = double(mat.d4); // remember? time is stored in mat.d4
mat.d4 = 1.0f; mat.d4 = 1.0f;
dstAnim->mPositionKeys[a].mTime = time; dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds ;
dstAnim->mRotationKeys[a].mTime = time; dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds ;
dstAnim->mScalingKeys[a].mTime = time; dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds ;
mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue); mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
} }
anims.push_back(dstAnim); anims.push_back(dstAnim);
} } else {
else
{
ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter."); ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter.");
} }
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
{
std::vector<Collada::ChannelEntry> morphChannels; std::vector<Collada::ChannelEntry> morphChannels;
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
{
Collada::ChannelEntry &e = *it; Collada::ChannelEntry &e = *it;
// skip non-transform types // skip non-transform types
@ -1447,8 +1399,7 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
if (e.mTargetId.find("morph-weights") != std::string::npos) if (e.mTargetId.find("morph-weights") != std::string::npos)
morphChannels.push_back(e); morphChannels.push_back(e);
} }
if (morphChannels.size() > 0) if (!morphChannels.empty() ) {
{
// either 1) morph weight animation count should contain morph target count channels // either 1) morph weight animation count should contain morph target count channels
// or 2) one channel with morph target count arrays // or 2) one channel with morph target count arrays
// assume first // assume first
@ -1457,10 +1408,8 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
morphAnim->mName.Set(nodeName); morphAnim->mName.Set(nodeName);
std::vector<MorphTimeValues> morphTimeValues; std::vector<MorphTimeValues> morphTimeValues;
int morphAnimChannelIndex = 0; int morphAnimChannelIndex = 0;
for (std::vector<Collada::ChannelEntry>::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) for (std::vector<Collada::ChannelEntry>::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) {
{
Collada::ChannelEntry &e = *it; Collada::ChannelEntry &e = *it;
std::string::size_type apos = e.mTargetId.find('('); std::string::size_type apos = e.mTargetId.find('(');
std::string::size_type bpos = e.mTargetId.find(')'); std::string::size_type bpos = e.mTargetId.find(')');
@ -1470,23 +1419,22 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
// weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way // weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way
// we ignore the name and just assume the channels are in the right order // we ignore the name and just assume the channels are in the right order
for (unsigned int i = 0; i < e.mTimeData->mValues.size(); i++) for (unsigned int i = 0; i < e.mTimeData->mValues.size(); i++) {
insertMorphTimeValue(morphTimeValues, e.mTimeData->mValues.at(i), e.mValueData->mValues.at(i), morphAnimChannelIndex); insertMorphTimeValue(morphTimeValues, e.mTimeData->mValues[i], e.mValueData->mValues[i], morphAnimChannelIndex);
}
++morphAnimChannelIndex; ++morphAnimChannelIndex;
} }
morphAnim->mNumKeys = static_cast<unsigned int>(morphTimeValues.size()); morphAnim->mNumKeys = static_cast<unsigned int>(morphTimeValues.size());
morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys]; morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys];
for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) {
{
morphAnim->mKeys[key].mNumValuesAndWeights = static_cast<unsigned int>(morphChannels.size()); morphAnim->mKeys[key].mNumValuesAndWeights = static_cast<unsigned int>(morphChannels.size());
morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()]; morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()];
morphAnim->mKeys[key].mWeights = new double[morphChannels.size()]; morphAnim->mKeys[key].mWeights = new double[morphChannels.size()];
morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime; morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds ;
for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); valueIndex++) for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex ) {
{
morphAnim->mKeys[key].mValues[valueIndex] = valueIndex; morphAnim->mKeys[key].mValues[valueIndex] = valueIndex;
morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex); morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex);
} }
@ -1497,31 +1445,26 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
} }
} }
if (!anims.empty() || !morphAnims.empty()) if (!anims.empty() || !morphAnims.empty()) {
{
aiAnimation *anim = new aiAnimation; aiAnimation *anim = new aiAnimation;
anim->mName.Set(pName); anim->mName.Set(pName);
anim->mNumChannels = static_cast<unsigned int>(anims.size()); anim->mNumChannels = static_cast<unsigned int>(anims.size());
if (anim->mNumChannels > 0) if (anim->mNumChannels > 0) {
{
anim->mChannels = new aiNodeAnim *[anims.size()]; anim->mChannels = new aiNodeAnim *[anims.size()];
std::copy(anims.begin(), anims.end(), anim->mChannels); std::copy(anims.begin(), anims.end(), anim->mChannels);
} }
anim->mNumMorphMeshChannels = static_cast<unsigned int>(morphAnims.size()); anim->mNumMorphMeshChannels = static_cast<unsigned int>(morphAnims.size());
if (anim->mNumMorphMeshChannels > 0) if (anim->mNumMorphMeshChannels > 0) {
{
anim->mMorphMeshChannels = new aiMeshMorphAnim *[anim->mNumMorphMeshChannels]; anim->mMorphMeshChannels = new aiMeshMorphAnim *[anim->mNumMorphMeshChannels];
std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels); std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels);
} }
anim->mDuration = 0.0f; anim->mDuration = 0.0f;
for (size_t a = 0; a < anims.size(); ++a) for (size_t a = 0; a < anims.size(); ++a) {
{
anim->mDuration = std::max(anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys - 1].mTime);
anim->mDuration = std::max(anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys - 1].mTime);
anim->mDuration = std::max(anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys - 1].mTime);
} }
for (size_t a = 0; a < morphAnims.size(); ++a) for (size_t a = 0; a < morphAnims.size(); ++a) {
{
anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime); anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
} }
anim->mTicksPerSecond = 1; anim->mTicksPerSecond = 1;
@ -1534,26 +1477,29 @@ void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParse
void ColladaLoader::AddTexture(aiMaterial &mat, const ColladaParser &pParser, void ColladaLoader::AddTexture(aiMaterial &mat, const ColladaParser &pParser,
const Collada::Effect &effect, const Collada::Effect &effect,
const Collada::Sampler &sampler, const Collada::Sampler &sampler,
aiTextureType type, unsigned int idx) aiTextureType type, unsigned int idx) {
{
// first of all, basic file name // first of all, basic file name
const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName); const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName);
mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx); mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx);
// mapping mode // mapping mode
int map = aiTextureMapMode_Clamp; int map = aiTextureMapMode_Clamp;
if (sampler.mWrapU) if (sampler.mWrapU) {
map = aiTextureMapMode_Wrap; map = aiTextureMapMode_Wrap;
if (sampler.mWrapU && sampler.mMirrorU) }
if (sampler.mWrapU && sampler.mMirrorU) {
map = aiTextureMapMode_Mirror; map = aiTextureMapMode_Mirror;
}
mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_U_BASE, type, idx); mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_U_BASE, type, idx);
map = aiTextureMapMode_Clamp; map = aiTextureMapMode_Clamp;
if (sampler.mWrapV) if (sampler.mWrapV) {
map = aiTextureMapMode_Wrap; map = aiTextureMapMode_Wrap;
if (sampler.mWrapV && sampler.mMirrorV) }
if (sampler.mWrapV && sampler.mMirrorV) {
map = aiTextureMapMode_Mirror; map = aiTextureMapMode_Mirror;
}
mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_V_BASE, type, idx); mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_V_BASE, type, idx);
@ -1574,9 +1520,9 @@ void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser,
// number in the channel name. We assume it is the zero-based index into the // number in the channel name. We assume it is the zero-based index into the
// UV channel array of all corresponding meshes. It could also be one-based // UV channel array of all corresponding meshes. It could also be one-based
// for some exporters, but we won't care of it unless someone complains about. // for some exporters, but we won't care of it unless someone complains about.
if (sampler.mUVId != UINT_MAX) if (sampler.mUVId != UINT_MAX) {
map = sampler.mUVId; map = sampler.mUVId;
else { } else {
map = -1; map = -1;
for (std::string::const_iterator it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) { for (std::string::const_iterator it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) {
if (IsNumeric(*it)) { if (IsNumeric(*it)) {
@ -1594,20 +1540,17 @@ void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Fills materials from the collada material definitions // Fills materials from the collada material definitions
void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScene*/) void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pScene*/) {
{ for (auto &elem : newMats) {
for (auto &elem : newMats)
{
aiMaterial &mat = (aiMaterial &)*elem.second; aiMaterial &mat = (aiMaterial &)*elem.second;
Collada::Effect &effect = *elem.first; Collada::Effect &effect = *elem.first;
// resolve shading mode // resolve shading mode
int shadeMode; int shadeMode;
if (effect.mFaceted) /* fixme */ if (effect.mFaceted) {
shadeMode = aiShadingMode_Flat; shadeMode = aiShadingMode_Flat;
else { } else {
switch (effect.mShadeType) switch (effect.mShadeType) {
{
case Collada::Shade_Constant: case Collada::Shade_Constant:
shadeMode = aiShadingMode_NoShading; shadeMode = aiShadingMode_NoShading;
break; break;
@ -1657,17 +1600,14 @@ void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScen
// handle RGB transparency completely, cf Collada specs 1.5.0 pages 249 and 304 // handle RGB transparency completely, cf Collada specs 1.5.0 pages 249 and 304
if (effect.mRGBTransparency) { if (effect.mRGBTransparency) {
// use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4) // use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4)
effect.mTransparency *= ( effect.mTransparency *= (0.212671f * effect.mTransparent.r +
0.212671f * effect.mTransparent.r +
0.715160f * effect.mTransparent.g + 0.715160f * effect.mTransparent.g +
0.072169f * effect.mTransparent.b 0.072169f * effect.mTransparent.b);
);
effect.mTransparent.a = 1.f; effect.mTransparent.a = 1.f;
mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT); mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
} } else {
else {
effect.mTransparency *= effect.mTransparent.a; effect.mTransparency *= effect.mTransparent.a;
} }
@ -1709,8 +1649,7 @@ void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScen
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructs materials from the collada material definitions // Constructs materials from the collada material definitions
void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/) void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/) {
{
newMats.reserve(pParser.mMaterialLibrary.size()); newMats.reserve(pParser.mMaterialLibrary.size());
for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin();
@ -1734,37 +1673,18 @@ void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/)
// ScenePreprocessor generates a default material automatically if none is there. // ScenePreprocessor generates a default material automatically if none is there.
// All further code here in this loader works well without a valid material so // All further code here in this loader works well without a valid material so
// we can safely let it to ScenePreprocessor. // we can safely let it to ScenePreprocessor.
#if 0
if (newMats.size() == 0)
{
aiMaterial* mat = new aiMaterial;
aiString name(AI_DEFAULT_MATERIAL_NAME);
mat->AddProperty(&name, AI_MATKEY_NAME);
const int shadeMode = aiShadingMode_Phong;
mat->AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
aiColor4D colAmbient(0.2, 0.2, 0.2, 1.0), colDiffuse(0.8, 0.8, 0.8, 1.0), colSpecular(0.5, 0.5, 0.5, 0.5);
mat->AddProperty(&colAmbient, 1, AI_MATKEY_COLOR_AMBIENT);
mat->AddProperty(&colDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
mat->AddProperty(&colSpecular, 1, AI_MATKEY_COLOR_SPECULAR);
const ai_real specExp = 5.0;
mat->AddProperty(&specExp, 1, AI_MATKEY_SHININESS);
}
#endif
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Resolves the texture name for the given effect texture entry // Resolves the texture name for the given effect texture entry
// and loads the texture data // and loads the texture data
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParser, aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParser,
const Collada::Effect& pEffect, const std::string& pName) const Collada::Effect &pEffect, const std::string &pName) {
{
aiString result; aiString result;
// recurse through the param references until we end up at an image // recurse through the param references until we end up at an image
std::string name = pName; std::string name = pName;
while (1) while (1) {
{
// the given string is a param entry. Find it // the given string is a param entry. Find it
Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name); Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name);
// if not found, we're at the end of the recursion. The resulting string should be the image ID // if not found, we're at the end of the recursion. The resulting string should be the image ID
@ -1777,8 +1697,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
// find the image referred by this name in the image library of the scene // find the image referred by this name in the image library of the scene
ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find(name); ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find(name);
if (imIt == pParser.mImageLibrary.end()) if (imIt == pParser.mImageLibrary.end()) {
{
ASSIMP_LOG_WARN_F("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\"."); ASSIMP_LOG_WARN_F("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\".");
//set default texture file name //set default texture file name
@ -1788,8 +1707,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
} }
// if this is an embedded texture image setup an aiTexture for it // if this is an embedded texture image setup an aiTexture for it
if (!imIt->second.mImageData.empty()) if (!imIt->second.mImageData.empty()) {
{
aiTexture *tex = new aiTexture(); aiTexture *tex = new aiTexture();
// Store embedded texture name reference // Store embedded texture name reference
@ -1800,7 +1718,6 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
// result.data[0] = '*'; // result.data[0] = '*';
// result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size())); // result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
// setup format hint // setup format hint
if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) { if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters"); ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
@ -1815,23 +1732,21 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
// and add this texture to the list // and add this texture to the list
mTextures.push_back(tex); mTextures.push_back(tex);
return result;
} }
else
{
if (imIt->second.mFileName.empty()) { if (imIt->second.mFileName.empty()) {
throw DeadlyImportError("Collada: Invalid texture, no data or file reference given"); throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");
} }
result.Set(imIt->second.mFileName); result.Set(imIt->second.mFileName);
}
return result; return result;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads a float value from an accessor and its data array. // Reads a float value from an accessor and its data array.
ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const ai_real ColladaLoader::ReadFloat(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex, size_t pOffset) const {
{
// FIXME: (thom) Test for data type here in every access? For the moment, I leave this to the caller
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset; size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset;
ai_assert(pos < pData.mValues.size()); ai_assert(pos < pData.mValues.size());
return pData.mValues[pos]; return pData.mValues[pos];
@ -1839,8 +1754,7 @@ ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Colla
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads a string value from an accessor and its data array. // Reads a string value from an accessor and its data array.
const std::string& ColladaLoader::ReadString(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const const std::string &ColladaLoader::ReadString(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex) const {
{
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset; size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset;
ai_assert(pos < pData.mStrings.size()); ai_assert(pos < pData.mStrings.size());
return pData.mStrings[pos]; return pData.mStrings[pos];
@ -1848,8 +1762,7 @@ const std::string& ColladaLoader::ReadString(const Collada::Accessor& pAccessor,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Collects all nodes into the given array // Collects all nodes into the given array
void ColladaLoader::CollectNodes(const aiNode* pNode, std::vector<const aiNode*>& poNodes) const void ColladaLoader::CollectNodes(const aiNode *pNode, std::vector<const aiNode *> &poNodes) const {
{
poNodes.push_back(pNode); poNodes.push_back(pNode);
for (size_t a = 0; a < pNode->mNumChildren; ++a) { for (size_t a = 0; a < pNode->mNumChildren; ++a) {
CollectNodes(pNode->mChildren[a], poNodes); CollectNodes(pNode->mChildren[a], poNodes);
@ -1858,13 +1771,11 @@ void ColladaLoader::CollectNodes(const aiNode* pNode, std::vector<const aiNode*>
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Finds a node in the collada scene by the given name // Finds a node in the collada scene by the given name
const Collada::Node* ColladaLoader::FindNode(const Collada::Node* pNode, const std::string& pName) const const Collada::Node *ColladaLoader::FindNode(const Collada::Node *pNode, const std::string &pName) const {
{
if (pNode->mName == pName || pNode->mID == pName) if (pNode->mName == pName || pNode->mID == pName)
return pNode; return pNode;
for (size_t a = 0; a < pNode->mChildren.size(); ++a) for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
{
const Collada::Node *node = FindNode(pNode->mChildren[a], pName); const Collada::Node *node = FindNode(pNode->mChildren[a], pName);
if (node) if (node)
return node; return node;
@ -1897,28 +1808,22 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Finds a proper unique name for a node derived from the collada-node's properties. // Finds a proper unique name for a node derived from the collada-node's properties.
// The name must be unique for proper node-bone association. // The name must be unique for proper node-bone association.
std::string ColladaLoader::FindNameForNode(const Collada::Node* pNode) std::string ColladaLoader::FindNameForNode(const Collada::Node *pNode) {
{
// If explicitly requested, just use the collada name. // If explicitly requested, just use the collada name.
if (useColladaName) if (useColladaName) {
{
if (!pNode->mName.empty()) { if (!pNode->mName.empty()) {
return pNode->mName; return pNode->mName;
} } else {
else {
return format() << "$ColladaAutoName$_" << mNodeNameCounter++; return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
} }
} } else {
else
{
// Now setup the name of the assimp node. The collada name might not be // Now setup the name of the assimp node. The collada name might not be
// unique, so we use the collada ID. // unique, so we use the collada ID.
if (!pNode->mID.empty()) if (!pNode->mID.empty())
return pNode->mID; return pNode->mID;
else if (!pNode->mSID.empty()) else if (!pNode->mSID.empty())
return pNode->mSID; return pNode->mSID;
else else {
{
// No need to worry. Unnamed nodes are no problem at all, except // No need to worry. Unnamed nodes are no problem at all, except
// if cameras or lights need to be assigned to them. // if cameras or lights need to be assigned to them.
return format() << "$ColladaAutoName$_" << mNodeNameCounter++; return format() << "$ColladaAutoName$_" << mNodeNameCounter++;

File diff suppressed because it is too large Load Diff

View File

@ -47,13 +47,12 @@
#ifndef AI_COLLADAPARSER_H_INC #ifndef AI_COLLADAPARSER_H_INC
#define AI_COLLADAPARSER_H_INC #define AI_COLLADAPARSER_H_INC
#include <assimp/irrXMLWrapper.h>
#include "ColladaHelper.h" #include "ColladaHelper.h"
#include <assimp/ai_assert.h>
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/ai_assert.h>
#include <assimp/irrXMLWrapper.h>
namespace Assimp namespace Assimp {
{
class ZipArchiveIOSystem; class ZipArchiveIOSystem;
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
@ -62,8 +61,7 @@ namespace Assimp
* Does all the XML reading and builds internal data structures from it, * Does all the XML reading and builds internal data structures from it,
* but leaves the resolving of all the references to the loader. * but leaves the resolving of all the references to the loader.
*/ */
class ColladaParser class ColladaParser {
{
friend class ColladaLoader; friend class ColladaLoader;
/** Converts a path read from a collada file to the usual representation */ /** Converts a path read from a collada file to the usual representation */
@ -176,10 +174,10 @@ namespace Assimp
void ReadGeometryLibrary(); void ReadGeometryLibrary();
/** Reads a geometry from the geometry library. */ /** Reads a geometry from the geometry library. */
void ReadGeometry( Collada::Mesh* pMesh); void ReadGeometry(Collada::Mesh &pMesh);
/** Reads a mesh from the geometry library */ /** Reads a mesh from the geometry library */
void ReadMesh( Collada::Mesh* pMesh); void ReadMesh(Collada::Mesh &pMesh);
/** Reads a source element - a combination of raw data and an accessor defining /** Reads a source element - a combination of raw data and an accessor defining
* things that should not be redefinable. Yes, that's another rant. * things that should not be redefinable. Yes, that's another rant.
@ -197,29 +195,29 @@ namespace Assimp
void ReadAccessor(const std::string &pID); void ReadAccessor(const std::string &pID);
/** Reads input declarations of per-vertex mesh data into the given mesh */ /** Reads input declarations of per-vertex mesh data into the given mesh */
void ReadVertexData( Collada::Mesh* pMesh); void ReadVertexData(Collada::Mesh &pMesh);
/** Reads input declarations of per-index mesh data into the given mesh */ /** Reads input declarations of per-index mesh data into the given mesh */
void ReadIndexData( Collada::Mesh* pMesh); void ReadIndexData(Collada::Mesh &pMesh);
/** Reads a single input channel element and stores it in the given array, if valid */ /** Reads a single input channel element and stores it in the given array, if valid */
void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels); void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels);
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */ /** 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 ReadPrimitives(Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType); 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 */ /** 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, void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels, Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t currentPrimitive, const std::vector<size_t> &indices); size_t currentPrimitive, const std::vector<size_t> &indices);
/** Reads one triangle of a tristrip into the mesh */ /** Reads one triangle of a tristrip into the mesh */
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh* pMesh, 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); 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 */ /** 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); void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
/** Reads the library of node hierarchies and scene parts */ /** Reads the library of node hierarchies and scene parts */
void ReadSceneLibrary(); void ReadSceneLibrary();
@ -291,7 +289,8 @@ namespace Assimp
Collada::InputType GetTypeForSemantic(const std::string &pSemantic); Collada::InputType GetTypeForSemantic(const std::string &pSemantic);
/** Finds the item in the given library by its reference, throws if not found */ /** 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; template <typename Type>
const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
protected: protected:
/** Filename, for a verbose error message */ /** Filename, for a verbose error message */
@ -360,7 +359,9 @@ namespace Assimp
ai_real mUnitSize; ai_real mUnitSize;
/** Which is the up vector */ /** Which is the up vector */
enum { UP_X, UP_Y, UP_Z } mUpDirection; enum { UP_X,
UP_Y,
UP_Z } mUpDirection;
/** Asset metadata (global for scene) */ /** Asset metadata (global for scene) */
StringMetaData mAssetMetaData; StringMetaData mAssetMetaData;
@ -371,8 +372,7 @@ namespace Assimp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Check for element match // Check for element match
inline bool ColladaParser::IsElement( const char* pName) const inline bool ColladaParser::IsElement(const char *pName) const {
{
ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT); ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT);
return ::strcmp(mReader->getNodeName(), pName) == 0; return ::strcmp(mReader->getNodeName(), pName) == 0;
} }
@ -380,8 +380,7 @@ namespace Assimp
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Finds the item in the given library by its reference, throws if not found // Finds the item in the given library by its reference, throws if not found
template <typename Type> template <typename Type>
const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const 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); typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
if (it == pLibrary.end()) if (it == pLibrary.end())
ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\"."); ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\".");

View File

@ -3315,6 +3315,7 @@ void FBXConverter::InterpolateKeys(aiQuatKey *valOut, const KeyTimeList &keys, c
// http://www.3dkingdoms.com/weekly/weekly.php?a=36 // http://www.3dkingdoms.com/weekly/weekly.php?a=36
if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) { if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) {
quat.Conjugate(); quat.Conjugate();
quat.w = -quat.w;
} }
lastq = quat; lastq = quat;

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

@ -1,114 +0,0 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
#include "StepFileImporter.h"
#include "../../Importer/STEPParser/STEPFileReader.h"
#include <assimp/importerdesc.h>
#include <assimp/DefaultIOSystem.h>
namespace Assimp {
namespace StepFile {
using namespace STEP;
static const aiImporterDesc desc = { "StepFile Importer",
"",
"",
"",
0,
0,
0,
0,
0,
"stp" };
StepFileImporter::StepFileImporter()
: BaseImporter() {
}
StepFileImporter::~StepFileImporter() {
}
bool StepFileImporter::CanRead(const std::string& file, IOSystem* pIOHandler, bool checkSig) const {
const std::string &extension = GetExtension(file);
if ( extension == "stp" || extension == "step" ) {
return true;
} else if ((!extension.length() || checkSig) && pIOHandler) {
const char* tokens[] = { "ISO-10303-21" };
const bool found(SearchFileHeaderForToken(pIOHandler, file, tokens, 1));
return found;
}
return false;
}
const aiImporterDesc *StepFileImporter::GetInfo() const {
return &desc;
}
static const std::string mode = "rb";
static const std::string StepFileSchema = "CONFIG_CONTROL_DESIGN";
void StepFileImporter::InternReadFile(const std::string &file, aiScene*, IOSystem* pIOHandler) {
// Read file into memory
std::shared_ptr<IOStream> fileStream(pIOHandler->Open(file, mode));
if (!fileStream.get()) {
throw DeadlyImportError("Failed to open file " + file + ".");
}
std::unique_ptr<STEP::DB> db(STEP::ReadFileHeader(fileStream));
const STEP::HeaderInfo& head = static_cast<const STEP::DB&>(*db).GetHeader();
if (!head.fileSchema.size() || head.fileSchema != StepFileSchema) {
DeadlyImportError("Unrecognized file schema: " + head.fileSchema);
}
}
} // Namespace StepFile
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_STEP_IMPORTER

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------

View File

@ -363,20 +363,44 @@ struct Object {
// Classes for each glTF top-level object type // Classes for each glTF top-level object type
// //
//! Base class for types that access binary data from a BufferView, such as accessors
//! or sparse accessors' indices.
//! N.B. not a virtual class. All owned pointers to BufferViewClient instances should
//! be to their most derived types (which may of course be just BufferViewClient).
struct BufferViewClient : public Object {
Ref<BufferView> bufferView; //!< The ID of the bufferView. (required)
size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required)
inline uint8_t *GetPointer();
void Read(Value &obj, Asset &r);
};
//! BufferViewClient with component type information.
//! N.B. not a virtual class. All owned pointers to ComponentTypedBufferViewClient
//! instances should be to their most derived types (which may of course be just
//! ComponentTypedBufferViewClient).
struct ComponentTypedBufferViewClient : public BufferViewClient {
ComponentType componentType; //!< The datatype of components in the attribute. (required)
unsigned int GetBytesPerComponent();
void Read(Value &obj, Asset &r);
};
//! A typed view into a BufferView. A BufferView contains raw binary data. //! A typed view into a BufferView. A BufferView contains raw binary data.
//! An accessor provides a typed view into a BufferView or a subset of a BufferView //! An accessor provides a typed view into a BufferView or a subset of a BufferView
//! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer. //! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer.
struct Accessor : public Object { struct Accessor : public ComponentTypedBufferViewClient {
Ref<BufferView> bufferView; //!< The ID of the bufferView. (required) struct Sparse;
size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required)
ComponentType componentType; //!< The datatype of components in the attribute. (required)
size_t count; //!< The number of attributes referenced by this accessor. (required) size_t count; //!< The number of attributes referenced by this accessor. (required)
AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
std::vector<double> max; //!< Maximum value of each component in this attribute. std::vector<double> max; //!< Maximum value of each component in this attribute.
std::vector<double> min; //!< Minimum value of each component in this attribute. std::vector<double> min; //!< Minimum value of each component in this attribute.
std::unique_ptr<Sparse> sparse; //!< Sparse accessor information
unsigned int GetNumComponents(); unsigned int GetNumComponents();
unsigned int GetBytesPerComponent();
unsigned int GetElementSize(); unsigned int GetElementSize();
inline uint8_t *GetPointer(); inline uint8_t *GetPointer();
@ -417,11 +441,61 @@ struct Accessor : public Object {
} }
}; };
//! Sparse accessor information
struct Sparse {
size_t count;
ComponentTypedBufferViewClient indices;
BufferViewClient values;
std::vector<uint8_t> data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it.
inline void PopulateData(size_t numBytes, uint8_t *bytes) {
if (bytes) {
data.assign(bytes, bytes + numBytes);
} else {
data.resize(numBytes, 0x00);
}
}
inline void PatchData(unsigned int elementSize)
{
uint8_t *pIndices = indices.GetPointer();
const unsigned int indexSize = indices.GetBytesPerComponent();
uint8_t *indicesEnd = pIndices + count * indexSize;
uint8_t *pValues = values.GetPointer();
while (pIndices != indicesEnd) {
size_t offset;
switch (indices.componentType) {
case ComponentType_UNSIGNED_BYTE:
offset = *pIndices;
break;
case ComponentType_UNSIGNED_SHORT:
offset = *reinterpret_cast<uint16_t *>(pIndices);
break;
case ComponentType_UNSIGNED_INT:
offset = *reinterpret_cast<uint32_t *>(pIndices);
break;
default:
// have fun with float and negative values from signed types as indices.
throw DeadlyImportError("Unsupported component type in index.");
}
offset *= elementSize;
std::memcpy(data.data() + offset, pValues, elementSize);
pValues += elementSize;
pIndices += indexSize;
}
}
};
inline Indexer GetIndexer() { inline Indexer GetIndexer() {
return Indexer(*this); return Indexer(*this);
} }
Accessor() {} Accessor() {}
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };

View File

@ -551,36 +551,10 @@ inline void BufferView::Read(Value &obj, Asset &r) {
} }
// //
// struct Accessor // struct BufferViewClient
// //
inline void Accessor::Read(Value &obj, Asset &r) { inline uint8_t *BufferViewClient::GetPointer() {
if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
}
byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
count = MemberOrDefault(obj, "count", size_t(0));
const char *typestr;
type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
}
inline unsigned int Accessor::GetNumComponents() {
return AttribType::GetNumComponents(type);
}
inline unsigned int Accessor::GetBytesPerComponent() {
return int(ComponentTypeSize(componentType));
}
inline unsigned int Accessor::GetElementSize() {
return GetNumComponents() * GetBytesPerComponent();
}
inline uint8_t *Accessor::GetPointer() {
if (!bufferView || !bufferView->buffer) return 0; if (!bufferView || !bufferView->buffer) return 0;
uint8_t *basePtr = bufferView->buffer->GetPointer(); uint8_t *basePtr = bufferView->buffer->GetPointer();
if (!basePtr) return 0; if (!basePtr) return 0;
@ -599,6 +573,76 @@ inline uint8_t *Accessor::GetPointer() {
return basePtr + offset; return basePtr + offset;
} }
inline void BufferViewClient::Read(Value &obj, Asset &r) {
if (Value *bufferViewVal = FindUInt(obj, "bufferView")) {
bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
}
byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0));
}
//
// struct ComponentTypedBufferViewClient
//
inline unsigned int ComponentTypedBufferViewClient::GetBytesPerComponent() {
return int(ComponentTypeSize(componentType));
}
inline void ComponentTypedBufferViewClient::Read(Value &obj, Asset &r) {
BufferViewClient::Read(obj, r);
componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
}
//
// struct Accessor
//
inline uint8_t *Accessor::GetPointer() {
if (!sparse) return BufferViewClient::GetPointer();
return sparse->data.data();
}
inline void Accessor::Read(Value &obj, Asset &r) {
ComponentTypedBufferViewClient::Read(obj, r);
count = MemberOrDefault(obj, "count", size_t(0));
const char *typestr;
type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
if (Value *sparseValue = FindObject(obj, "sparse")) {
sparse.reset(new Sparse);
ReadMember(*sparseValue, "count", sparse->count);
if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
sparse->indices.Read(*indicesValue, r);
}
if (Value *valuesValue = FindObject(*sparseValue, "values")) {
sparse->values.Read(*valuesValue, r);
}
const unsigned int elementSize = GetElementSize();
const size_t dataSize = count * elementSize;
sparse->PopulateData(dataSize, BufferViewClient::GetPointer());
sparse->PatchData(elementSize);
}
}
inline unsigned int Accessor::GetNumComponents() {
return AttribType::GetNumComponents(type);
}
inline unsigned int Accessor::GetElementSize() {
return GetNumComponents() * GetBytesPerComponent();
}
namespace { namespace {
inline void CopyData(size_t count, inline void CopyData(size_t count,
const uint8_t *src, size_t src_stride, const uint8_t *src, size_t src_stride,
@ -635,7 +679,7 @@ void Accessor::ExtractData(T *&outData)
const size_t targetElemSize = sizeof(T); const size_t targetElemSize = sizeof(T);
ai_assert(elemSize <= targetElemSize); ai_assert(elemSize <= targetElemSize);
ai_assert(count * stride <= bufferView->byteLength); ai_assert(count * stride <= (bufferView ? bufferView->byteLength : sparse->data.size()));
outData = new T[count]; outData = new T[count];
if (stride == elemSize && targetElemSize == elemSize) { if (stride == elemSize && targetElemSize == elemSize) {
@ -1002,7 +1046,7 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
// Valid attribute semantics include POSITION, NORMAL, TANGENT // Valid attribute semantics include POSITION, NORMAL, TANGENT
int undPos = 0; int undPos = 0;
Mesh::AccessorList *vec = 0; Mesh::AccessorList *vec = 0;
if (GetAttribTargetVector(prim, i, attr, vec, undPos)) { if (GetAttribTargetVector(prim, j, attr, vec, undPos)) {
size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0; size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
if ((*vec).size() <= idx) { if ((*vec).size() <= idx) {
(*vec).resize(idx + 1); (*vec).resize(idx + 1);
@ -1067,10 +1111,10 @@ inline void Camera::Read(Value &obj, Asset & /*r*/) {
cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f); cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f); cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
} else { } else {
cameraProperties.ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f); cameraProperties.ortographic.xmag = MemberOrDefault(*it, "xmag", 1.f);
cameraProperties.ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f); cameraProperties.ortographic.ymag = MemberOrDefault(*it, "ymag", 1.f);
cameraProperties.ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f); cameraProperties.ortographic.zfar = MemberOrDefault(*it, "zfar", 100.f);
cameraProperties.ortographic.znear = MemberOrDefault(obj, "znear", 0.01f); cameraProperties.ortographic.znear = MemberOrDefault(*it, "znear", 0.01f);
} }
} }

View File

@ -1,4 +1,4 @@
/* /*
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
---------------------------------------------------------------------- ----------------------------------------------------------------------

View File

@ -47,8 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
CIOStreamWrapper::~CIOStreamWrapper(void) CIOStreamWrapper::~CIOStreamWrapper(void) {
{
/* Various places depend on this destructor to close the file */ /* Various places depend on this destructor to close the file */
if (mFile) { if (mFile) {
mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile); mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile);
@ -59,8 +58,7 @@ CIOStreamWrapper::~CIOStreamWrapper(void)
// ................................................................... // ...................................................................
size_t CIOStreamWrapper::Read(void *pvBuffer, size_t CIOStreamWrapper::Read(void *pvBuffer,
size_t pSize, size_t pSize,
size_t pCount size_t pCount) {
){
// need to typecast here as C has no void* // need to typecast here as C has no void*
return mFile->ReadProc(mFile, (char *)pvBuffer, pSize, pCount); return mFile->ReadProc(mFile, (char *)pvBuffer, pSize, pCount);
} }
@ -68,16 +66,14 @@ size_t CIOStreamWrapper::Read(void* pvBuffer,
// ................................................................... // ...................................................................
size_t CIOStreamWrapper::Write(const void *pvBuffer, size_t CIOStreamWrapper::Write(const void *pvBuffer,
size_t pSize, size_t pSize,
size_t pCount size_t pCount) {
){
// need to typecast here as C has no void* // need to typecast here as C has no void*
return mFile->WriteProc(mFile, (const char *)pvBuffer, pSize, pCount); return mFile->WriteProc(mFile, (const char *)pvBuffer, pSize, pCount);
} }
// ................................................................... // ...................................................................
aiReturn CIOStreamWrapper::Seek(size_t pOffset, aiReturn CIOStreamWrapper::Seek(size_t pOffset,
aiOrigin pOrigin aiOrigin pOrigin) {
){
return mFile->SeekProc(mFile, pOffset, pOrigin); return mFile->SeekProc(mFile, pOffset, pOrigin);
} }
@ -133,4 +129,4 @@ void CIOSystemWrapper::Close( IOStream* pFile) {
delete pFile; delete pFile;
} }
} } // namespace Assimp

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -56,13 +54,11 @@ class CIOSystemWrapper;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Custom IOStream implementation for the C-API // Custom IOStream implementation for the C-API
class CIOStreamWrapper : public IOStream class CIOStreamWrapper : public IOStream {
{
public: public:
explicit CIOStreamWrapper(aiFile* pFile, CIOSystemWrapper* io) explicit CIOStreamWrapper(aiFile *pFile, CIOSystemWrapper *io) :
: mFile(pFile), mFile(pFile),
mIO(io) mIO(io) {}
{}
~CIOStreamWrapper(void); ~CIOStreamWrapper(void);
size_t Read(void *pvBuffer, size_t pSize, size_t pCount); size_t Read(void *pvBuffer, size_t pSize, size_t pCount);
@ -77,23 +73,22 @@ private:
CIOSystemWrapper *mIO; CIOSystemWrapper *mIO;
}; };
class CIOSystemWrapper : public IOSystem class CIOSystemWrapper : public IOSystem {
{
friend class CIOStreamWrapper; friend class CIOStreamWrapper;
public: public:
explicit CIOSystemWrapper(aiFileIO* pFile) explicit CIOSystemWrapper(aiFileIO *pFile) :
: mFileSystem(pFile) mFileSystem(pFile) {}
{}
bool Exists(const char *pFile) const; bool Exists(const char *pFile) const;
char getOsSeparator() const; char getOsSeparator() const;
IOStream *Open(const char *pFile, const char *pMode = "rb"); IOStream *Open(const char *pFile, const char *pMode = "rb");
void Close(IOStream *pFile); void Close(IOStream *pFile);
private: private:
aiFileIO *mFileSystem; aiFileIO *mFileSystem;
}; };
} } // namespace Assimp
#endif #endif

View File

@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/color4.h ${HEADER_PATH}/color4.h
${HEADER_PATH}/color4.inl ${HEADER_PATH}/color4.inl
${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
${HEADER_PATH}/ColladaMetaData.h
${HEADER_PATH}/commonMetaData.h ${HEADER_PATH}/commonMetaData.h
${HEADER_PATH}/defs.h ${HEADER_PATH}/defs.h
${HEADER_PATH}/Defines.h ${HEADER_PATH}/Defines.h
@ -1232,7 +1233,7 @@ if (APPLE)
# add ./Compiler/*.h to assimp.framework via copy command # add ./Compiler/*.h to assimp.framework via copy command
ADD_CUSTOM_COMMAND(TARGET assimp POST_BUILD ADD_CUSTOM_COMMAND(TARGET assimp POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory COMMAND "${CMAKE_COMMAND}" -E copy_directory
"../${HEADER_PATH}/Compiler" "${HEADER_PATH}/Compiler"
assimp.framework/Headers/Compiler assimp.framework/Headers/Compiler
COMMENT "Copying public ./Compiler/ header files to framework bundle's Headers/Compiler/") COMMENT "Copying public ./Compiler/ header files to framework bundle's Headers/Compiler/")
ENDIF() ENDIF()

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* /*
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <limits> #include <limits>
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <set>
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
@ -172,7 +173,15 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
const aiBone* bone = pMesh->mBones[a]; const aiBone* bone = pMesh->mBones[a];
for( unsigned int b = 0; b < bone->mNumWeights; ++b) for( unsigned int b = 0; b < bone->mNumWeights; ++b)
{ {
vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight)); if (bone->mWeights[b].mWeight > 0.0f)
{
int vertexId = bone->mWeights[b].mVertexId;
vertexBones[vertexId].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
if (vertexBones[vertexId].size() > mMaxBoneCount)
{
throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
}
}
} }
} }
@ -188,9 +197,6 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
subMeshFaces.reserve( pMesh->mNumFaces); subMeshFaces.reserve( pMesh->mNumFaces);
// accumulated vertex count of all the faces in this submesh // accumulated vertex count of all the faces in this submesh
unsigned int numSubMeshVertices = 0; unsigned int numSubMeshVertices = 0;
// a small local array of new bones for the current face. State of all used bones for that face
// can only be updated AFTER the face is completely analysed. Thanks to imre for the fix.
std::vector<unsigned int> newBonesAtCurrentFace;
// add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit // add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit
for( unsigned int a = 0; a < pMesh->mNumFaces; ++a) for( unsigned int a = 0; a < pMesh->mNumFaces; ++a)
@ -200,6 +206,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
{ {
continue; continue;
} }
// a small local set of new bones for the current face. State of all used bones for that face
// can only be updated AFTER the face is completely analysed. Thanks to imre for the fix.
std::set<unsigned int> newBonesAtCurrentFace;
const aiFace& face = pMesh->mFaces[a]; const aiFace& face = pMesh->mFaces[a];
// check every vertex if its bones would still fit into the current submesh // check every vertex if its bones would still fit into the current submesh
@ -209,24 +218,13 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
for( unsigned int c = 0; c < vb.size(); ++c) for( unsigned int c = 0; c < vb.size(); ++c)
{ {
unsigned int boneIndex = vb[c].first; unsigned int boneIndex = vb[c].first;
// if the bone is already used in this submesh, it's ok if( !isBoneUsed[boneIndex] )
if( isBoneUsed[boneIndex] )
{ {
continue; newBonesAtCurrentFace.insert(boneIndex);
}
// if it's not used, yet, we would need to add it. Store its bone index
if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() )
{
newBonesAtCurrentFace.push_back( boneIndex);
} }
} }
} }
if (newBonesAtCurrentFace.size() > mMaxBoneCount)
{
throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
}
// leave out the face if the new bones required for this face don't fit the bone count limit anymore // leave out the face if the new bones required for this face don't fit the bone count limit anymore
if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount ) if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount )
{ {
@ -234,18 +232,14 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
} }
// mark all new bones as necessary // mark all new bones as necessary
while( !newBonesAtCurrentFace.empty() ) for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it)
{ {
unsigned int newIndex = newBonesAtCurrentFace.back(); if (!isBoneUsed[*it])
newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear()
if( isBoneUsed[newIndex] )
{ {
continue; isBoneUsed[*it] = true;
}
isBoneUsed[newIndex] = true;
numBones++; numBones++;
} }
}
// store the face index and the vertex count // store the face index and the vertex count
subMeshFaces.push_back( a); subMeshFaces.push_back( a);

View File

@ -1,4 +1,4 @@
/* /*
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
/* /*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@ -1,4 +1,4 @@
================== ==================
INSTALLATION GUIDE INSTALLATION GUIDE
================== ==================

View File

@ -196,10 +196,7 @@ if(MINGW)
set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
endif(MINGW) endif(MINGW)
add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
set_target_properties(zlib PROPERTIES SOVERSION 1)
INSTALL( TARGETS zlibstatic INSTALL( TARGETS zlibstatic
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,30 +38,19 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
#include <assimp/cimport.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#pragma once extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
aiLogStream stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
aiAttachLogStream(&stream);
#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER Importer importer;
const aiScene *sc = importer.ReadFileFromMemory(data, dataSize,
aiProcessPreset_TargetRealtime_Quality, nullptr );
#include <assimp/BaseImporter.h> aiDetachLogStream(&stream);
namespace Assimp { return 0;
namespace StepFile { }
class StepFileImporter : public BaseImporter {
public:
StepFileImporter();
~StepFileImporter();
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
const aiImporterDesc* GetInfo() const override;
protected:
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) override;
private:
};
} // Namespace StepFile
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_STEP_IMPORTER

View File

@ -0,0 +1,53 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file ColladaMetaData.h
* Declares common metadata constants used by Collada files
*/
#pragma once
#ifndef AI_COLLADAMETADATA_H_INC
#define AI_COLLADAMETADATA_H_INC
#define AI_METADATA_COLLADA_ID "Collada_id"
#define AI_METADATA_COLLADA_SID "Collada_sid"
#endif

View File

@ -1030,10 +1030,10 @@ enum aiComponent
#define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION" #define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Specifies whether the Collada loader should use Collada names as node names. /** @brief Specifies whether the Collada loader should use Collada names.
* *
* If this property is set to true, the Collada names will be used as the * If this property is set to true, the Collada names will be used as the node and
* node name. The default is to use the id tag (resp. sid tag, if no id tag is present) * mesh names. The default is to use the id tag (resp. sid tag, if no id tag is present)
* instead. * instead.
* Property type: Bool. Default value: false. * Property type: Bool. Default value: false.
*/ */

View File

@ -1,4 +1,4 @@
/* /*
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -4,5 +4,3 @@ http://assimp.sourceforge.net
Sourceforge.net project page: Sourceforge.net project page:
http://www.sourceforge.net/projects/assimp http://www.sourceforge.net/projects/assimp

View File

@ -1,4 +1,4 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Simple Assimp Directx11 Sample // Simple Assimp Directx11 Sample
// This is a very basic sample and only reads diffuse texture // This is a very basic sample and only reads diffuse texture
// but this can load both embedded textures in fbx and non-embedded textures // but this can load both embedded textures in fbx and non-embedded textures

View File

@ -124,8 +124,7 @@ SET( IMPORTERS
unit/utBlendImportMaterials.cpp unit/utBlendImportMaterials.cpp
unit/utBlenderWork.cpp unit/utBlenderWork.cpp
unit/utBVHImportExport.cpp unit/utBVHImportExport.cpp
unit/utColladaExportCamera.cpp unit/utColladaExport.cpp
unit/utColladaExportLight.cpp
unit/utColladaImportExport.cpp unit/utColladaImportExport.cpp
unit/utCSMImportExport.cpp unit/utCSMImportExport.cpp
unit/utB3DImportExport.cpp unit/utB3DImportExport.cpp

View File

@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_EXPORT
class ColladaExportLight : public ::testing::Test { class utColladaExport : public ::testing::Test {
public: public:
void SetUp() override { void SetUp() override {
ex = new Assimp::Exporter(); ex = new Assimp::Exporter();
@ -58,7 +58,9 @@ public:
void TearDown() override { void TearDown() override {
delete ex; delete ex;
ex = nullptr;
delete im; delete im;
im = nullptr;
} }
protected: protected:
@ -66,8 +68,53 @@ protected:
Assimp::Importer *im; Assimp::Importer *im;
}; };
TEST_F(utColladaExport, testExportCamera) {
const char *file = "cameraExp.dae";
const aiScene *pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/cameras.dae", aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, pTest);
ASSERT_TRUE(pTest->HasCameras());
EXPECT_EQ(AI_SUCCESS, ex->Export(pTest, "collada", file));
const unsigned int origNumCams(pTest->mNumCameras);
std::unique_ptr<float[]> origFOV(new float[origNumCams]);
std::unique_ptr<float[]> orifClipPlaneNear(new float[origNumCams]);
std::unique_ptr<float[]> orifClipPlaneFar(new float[origNumCams]);
std::unique_ptr<aiString[]> names(new aiString[origNumCams]);
std::unique_ptr<aiVector3D[]> pos(new aiVector3D[origNumCams]);
for (size_t i = 0; i < origNumCams; i++) {
const aiCamera *orig = pTest->mCameras[i];
ASSERT_NE(nullptr, orig);
origFOV[i] = orig->mHorizontalFOV;
orifClipPlaneNear[i] = orig->mClipPlaneNear;
orifClipPlaneFar[i] = orig->mClipPlaneFar;
names[i] = orig->mName;
pos[i] = orig->mPosition;
}
const aiScene *imported = im->ReadFile(file, aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, imported);
EXPECT_TRUE(imported->HasCameras());
EXPECT_EQ(origNumCams, imported->mNumCameras);
for (size_t i = 0; i < imported->mNumCameras; i++) {
const aiCamera *read = imported->mCameras[i];
EXPECT_TRUE(names[i] == read->mName);
EXPECT_NEAR(origFOV[i], read->mHorizontalFOV, 0.0001f);
EXPECT_FLOAT_EQ(orifClipPlaneNear[i], read->mClipPlaneNear);
EXPECT_FLOAT_EQ(orifClipPlaneFar[i], read->mClipPlaneFar);
EXPECT_FLOAT_EQ(pos[i].x, read->mPosition.x);
EXPECT_FLOAT_EQ(pos[i].y, read->mPosition.y);
EXPECT_FLOAT_EQ(pos[i].z, read->mPosition.z);
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
TEST_F(ColladaExportLight, testExportLight) { TEST_F(utColladaExport, testExportLight) {
const char *file = "lightsExp.dae"; const char *file = "lightsExp.dae";
const aiScene *pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/lights.dae", aiProcess_ValidateDataStructure); const aiScene *pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/lights.dae", aiProcess_ValidateDataStructure);

View File

@ -1,115 +0,0 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
#include "UnitTestPCH.h"
#include <assimp/cexport.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/Exporter.hpp>
#include <assimp/Importer.hpp>
#ifndef ASSIMP_BUILD_NO_EXPORT
class ColladaExportCamera : public ::testing::Test {
public:
void SetUp() override {
ex = new Assimp::Exporter();
im = new Assimp::Importer();
}
void TearDown() override {
delete ex;
ex = nullptr;
delete im;
im = nullptr;
}
protected:
Assimp::Exporter *ex;
Assimp::Importer *im;
};
TEST_F(ColladaExportCamera, testExportCamera) {
const char *file = "cameraExp.dae";
const aiScene *pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/cameras.dae", aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, pTest);
ASSERT_TRUE(pTest->HasCameras());
EXPECT_EQ(AI_SUCCESS, ex->Export(pTest, "collada", file));
const unsigned int origNumCams(pTest->mNumCameras);
std::unique_ptr<float[]> origFOV(new float[origNumCams]);
std::unique_ptr<float[]> orifClipPlaneNear(new float[origNumCams]);
std::unique_ptr<float[]> orifClipPlaneFar(new float[origNumCams]);
std::unique_ptr<aiString[]> names(new aiString[origNumCams]);
std::unique_ptr<aiVector3D[]> pos(new aiVector3D[origNumCams]);
for (size_t i = 0; i < origNumCams; i++) {
const aiCamera *orig = pTest->mCameras[i];
ASSERT_NE(nullptr, orig);
origFOV[i] = orig->mHorizontalFOV;
orifClipPlaneNear[i] = orig->mClipPlaneNear;
orifClipPlaneFar[i] = orig->mClipPlaneFar;
names[i] = orig->mName;
pos[i] = orig->mPosition;
}
const aiScene *imported = im->ReadFile(file, aiProcess_ValidateDataStructure);
ASSERT_NE(nullptr, imported);
EXPECT_TRUE(imported->HasCameras());
EXPECT_EQ(origNumCams, imported->mNumCameras);
for (size_t i = 0; i < imported->mNumCameras; i++) {
const aiCamera *read = imported->mCameras[i];
EXPECT_TRUE(names[i] == read->mName);
EXPECT_NEAR(origFOV[i], read->mHorizontalFOV, 0.0001f);
EXPECT_FLOAT_EQ(orifClipPlaneNear[i], read->mClipPlaneNear);
EXPECT_FLOAT_EQ(orifClipPlaneFar[i], read->mClipPlaneFar);
EXPECT_FLOAT_EQ(pos[i].x, read->mPosition.x);
EXPECT_FLOAT_EQ(pos[i].y, read->mPosition.y);
EXPECT_FLOAT_EQ(pos[i].z, read->mPosition.z);
}
}
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -41,16 +41,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AbstractImportExportBase.h" #include "AbstractImportExportBase.h"
#include "UnitTestPCH.h" #include "UnitTestPCH.h"
#include <assimp/ColladaMetaData.h>
#include <assimp/commonMetaData.h> #include <assimp/commonMetaData.h>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/Exporter.hpp>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
using namespace Assimp; using namespace Assimp;
class utColladaImportExport : public AbstractImportExportBase { class utColladaImportExport : public AbstractImportExportBase {
public: public:
virtual bool importerTest() { virtual bool importerTest() final {
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure); const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure);
if (scene == nullptr) if (scene == nullptr)
@ -80,15 +82,201 @@ public:
return true; return true;
} }
typedef std::pair<std::string, std::string> IdNameString;
typedef std::map<std::string, std::string> IdNameMap;
template <typename T>
static inline IdNameString GetColladaIdName(const T *item, size_t index) {
std::ostringstream stream;
stream << typeid(T).name() << "@" << index;
if (item->mMetaData) {
aiString aiStr;
if (item->mMetaData->Get(AI_METADATA_COLLADA_ID, aiStr))
return std::make_pair(std::string(aiStr.C_Str()), stream.str());
}
return std::make_pair(std::string(), stream.str());
}
template <typename T>
static inline IdNameString GetItemIdName(const T *item, size_t index) {
std::ostringstream stream;
stream << typeid(T).name() << "@" << index;
return std::make_pair(std::string(item->mName.C_Str()), stream.str());
}
// Specialisations
static inline IdNameString GetItemIdName(aiMaterial *item, size_t index) {
std::ostringstream stream;
stream << typeid(aiMaterial).name() << "@" << index;
return std::make_pair(std::string(item->GetName().C_Str()), stream.str());
}
static inline IdNameString GetItemIdName(aiTexture *item, size_t index) {
std::ostringstream stream;
stream << typeid(aiTexture).name() << "@" << index;
return std::make_pair(std::string(item->mFilename.C_Str()), stream.str());
}
static inline void ReportDuplicate(IdNameMap &itemIdMap, const IdNameString &namePair, const char *typeNameStr) {
const auto result = itemIdMap.insert(namePair);
EXPECT_TRUE(result.second) << "Duplicate '" << typeNameStr << "' name: '" << namePair.first << "'. " << namePair.second << " == " << result.first->second;
}
template <typename T>
static inline void CheckUniqueIds(IdNameMap &itemIdMap, unsigned int itemCount, T **itemArray) {
for (size_t idx = 0; idx < itemCount; ++idx) {
IdNameString namePair = GetItemIdName(itemArray[idx], idx);
ReportDuplicate(itemIdMap, namePair, typeid(T).name());
}
}
static inline void CheckUniqueIds(IdNameMap &itemIdMap, const aiNode *parent, size_t index) {
IdNameString namePair = GetItemIdName(parent, index);
ReportDuplicate(itemIdMap, namePair, typeid(aiNode).name());
for (size_t idx = 0; idx < parent->mNumChildren; ++idx) {
CheckUniqueIds(itemIdMap, parent->mChildren[idx], idx);
}
}
static inline void CheckNodeIdNames(IdNameMap &nodeIdMap, IdNameMap &nodeNameMap, const aiNode *parent, size_t index) {
IdNameString namePair = GetItemIdName(parent, index);
const auto result = nodeNameMap.insert(namePair);
IdNameString idPair = GetColladaIdName(parent, index);
ReportDuplicate(nodeIdMap, idPair, typeid(aiNode).name());
for (size_t idx = 0; idx < parent->mNumChildren; ++idx) {
CheckNodeIdNames(nodeIdMap, nodeNameMap, parent->mChildren[idx], idx);
}
}
static inline void SetAllNodeNames(const aiString &newName, aiNode *node) {
node->mName = newName;
for (size_t idx = 0; idx < node->mNumChildren; ++idx) {
SetAllNodeNames(newName, node->mChildren[idx]);
}
}
void ImportAndCheckIds(const char *file, const aiScene *origScene) {
// Import the Collada using the 'default' where aiNode and aiMesh names are the Collada ids
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure);
ASSERT_TRUE(scene != nullptr) << "Fatal: could not re-import " << file;
EXPECT_EQ(origScene->mNumMeshes, scene->mNumMeshes) << "in " << file;
// Check the ids are unique
IdNameMap itemIdMap;
// Recurse the Nodes
CheckUniqueIds(itemIdMap, scene->mRootNode, 0);
// Check the lists
CheckUniqueIds(itemIdMap, scene->mNumMeshes, scene->mMeshes);
// The remaining will come in using the name, which may not be unique
// Check we have the right number
EXPECT_EQ(origScene->mNumAnimations, scene->mNumAnimations);
EXPECT_EQ(origScene->mNumMaterials, scene->mNumMaterials);
EXPECT_EQ(origScene->mNumTextures, scene->mNumTextures);
EXPECT_EQ(origScene->mNumLights, scene->mNumLights);
EXPECT_EQ(origScene->mNumCameras, scene->mNumCameras);
}
void ImportAsNames(const char *file, const aiScene *origScene) {
// Import the Collada but using the user-visible names for aiNode and aiMesh
// Note that this mode may not support bones or animations
Assimp::Importer importer;
importer.SetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 1);
const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure);
ASSERT_TRUE(scene != nullptr) << "Fatal: could not re-import " << file;
EXPECT_EQ(origScene->mNumMeshes, scene->mNumMeshes) << "in " << file;
// Check the node ids are unique but the node names are not
IdNameMap nodeIdMap;
IdNameMap nodeNameMap;
// Recurse the Nodes
CheckNodeIdNames(nodeIdMap, nodeNameMap, scene->mRootNode, 0);
// nodeNameMap should have fewer than nodeIdMap
EXPECT_LT(nodeNameMap.size(), nodeIdMap.size()) << "Some nodes should have the same names";
// Check the counts haven't changed
EXPECT_EQ(origScene->mNumAnimations, scene->mNumAnimations);
EXPECT_EQ(origScene->mNumMaterials, scene->mNumMaterials);
EXPECT_EQ(origScene->mNumTextures, scene->mNumTextures);
EXPECT_EQ(origScene->mNumLights, scene->mNumLights);
EXPECT_EQ(origScene->mNumCameras, scene->mNumCameras);
}
}; };
TEST_F(utColladaImportExport, importBlenFromFileTest) { TEST_F(utColladaImportExport, importDaeFromFileTest) {
EXPECT_TRUE(importerTest()); EXPECT_TRUE(importerTest());
} }
TEST_F(utColladaImportExport, exporterUniqueIdsTest) {
Assimp::Importer importer;
Assimp::Exporter exporter;
const char *outFileEmpty = "exportMeshIdTest_empty_out.dae";
const char *outFileNamed = "exportMeshIdTest_named_out.dae";
// Load a sample file containing multiple meshes
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/teapots.DAE", aiProcess_ValidateDataStructure);
ASSERT_TRUE(scene != nullptr) << "Fatal: could not import teapots.DAE!";
ASSERT_EQ(3u, scene->mNumMeshes) << "Fatal: teapots.DAE initial load failed";
// Clear all the names
for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) {
scene->mMeshes[idx]->mName.Clear();
}
for (size_t idx = 0; idx < scene->mNumMaterials; ++idx) {
scene->mMaterials[idx]->RemoveProperty(AI_MATKEY_NAME);
}
for (size_t idx = 0; idx < scene->mNumAnimations; ++idx) {
scene->mAnimations[idx]->mName.Clear();
}
// Can't clear texture names
for (size_t idx = 0; idx < scene->mNumLights; ++idx) {
scene->mLights[idx]->mName.Clear();
}
for (size_t idx = 0; idx < scene->mNumCameras; ++idx) {
scene->mCameras[idx]->mName.Clear();
}
SetAllNodeNames(aiString(), scene->mRootNode);
ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileEmpty)) << "Fatal: Could not export un-named meshes file";
ImportAndCheckIds(outFileEmpty, scene);
// Force everything to have the same non-empty name
aiString testName("test_name");
for (size_t idx = 0; idx < scene->mNumMeshes; ++idx) {
scene->mMeshes[idx]->mName = testName;
}
for (size_t idx = 0; idx < scene->mNumMaterials; ++idx) {
scene->mMaterials[idx]->AddProperty(&testName, AI_MATKEY_NAME);
}
for (size_t idx = 0; idx < scene->mNumAnimations; ++idx) {
scene->mAnimations[idx]->mName = testName;
}
// Can't clear texture names
for (size_t idx = 0; idx < scene->mNumLights; ++idx) {
scene->mLights[idx]->mName = testName;
}
for (size_t idx = 0; idx < scene->mNumCameras; ++idx) {
scene->mCameras[idx]->mName = testName;
}
SetAllNodeNames(testName, scene->mRootNode);
ASSERT_EQ(AI_SUCCESS, exporter.Export(scene, "collada", outFileNamed)) << "Fatal: Could not export named meshes file";
ImportAndCheckIds(outFileNamed, scene);
ImportAsNames(outFileNamed, scene);
}
class utColladaZaeImportExport : public AbstractImportExportBase { class utColladaZaeImportExport : public AbstractImportExportBase {
public: public:
virtual bool importerTest() { virtual bool importerTest() final {
{ {
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure); const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure);

View File

@ -65,8 +65,7 @@ void TriangulateProcessTest::SetUp() {
pcMesh->mFaces = new aiFace[1000]; pcMesh->mFaces = new aiFace[1000];
pcMesh->mVertices = new aiVector3D[10000]; pcMesh->mVertices = new aiVector3D[10000];
pcMesh->mPrimitiveTypes = aiPrimitiveType_POINT | aiPrimitiveType_LINE | pcMesh->mPrimitiveTypes = aiPrimitiveType_POINT | aiPrimitiveType_LINE | aiPrimitiveType_POLYGON;
aiPrimitiveType_LINE | aiPrimitiveType_POLYGON;
for (unsigned int m = 0, t = 0, q = 4; m < 1000; ++m) { for (unsigned int m = 0, t = 0, q = 4; m < 1000; ++m) {
++t; ++t;

View File

@ -47,9 +47,10 @@ using namespace AssimpView;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor on a given animation. // Constructor on a given animation.
AnimEvaluator::AnimEvaluator( const aiAnimation *pAnim ) AnimEvaluator::AnimEvaluator(const aiAnimation *pAnim) :
: mAnim(pAnim) mAnim(pAnim),
, mLastTime(0.0) { mLastTime(0.0) {
ai_assert(nullptr != pAnim);
mLastPositions.resize(pAnim->mNumChannels, std::make_tuple(0, 0, 0)); mLastPositions.resize(pAnim->mNumChannels, std::make_tuple(0, 0, 0));
} }
@ -160,10 +161,18 @@ void AnimEvaluator::Evaluate( double pTime ) {
// build a transformation matrix from it // build a transformation matrix from it
aiMatrix4x4 &mat = mTransforms[a]; aiMatrix4x4 &mat = mTransforms[a];
mat = aiMatrix4x4(presentRotation.GetMatrix()); mat = aiMatrix4x4(presentRotation.GetMatrix());
mat.a1 *= presentScaling.x; mat.b1 *= presentScaling.x; mat.c1 *= presentScaling.x; mat.a1 *= presentScaling.x;
mat.a2 *= presentScaling.y; mat.b2 *= presentScaling.y; mat.c2 *= presentScaling.y; mat.b1 *= presentScaling.x;
mat.a3 *= presentScaling.z; mat.b3 *= presentScaling.z; mat.c3 *= presentScaling.z; mat.c1 *= presentScaling.x;
mat.a4 = presentPosition.x; mat.b4 = presentPosition.y; mat.c4 = presentPosition.z; mat.a2 *= presentScaling.y;
mat.b2 *= presentScaling.y;
mat.c2 *= presentScaling.y;
mat.a3 *= presentScaling.z;
mat.b3 *= presentScaling.z;
mat.c3 *= presentScaling.z;
mat.a4 = presentPosition.x;
mat.b4 = presentPosition.y;
mat.c4 = presentPosition.z;
} }
mLastTime = time; mLastTime = time;

View File

@ -39,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
#if (!defined AV_ASSET_HELPER_H_INCLUDED) #if (!defined AV_ASSET_HELPER_H_INCLUDED)
#define AV_ASSET_HELPER_H_INCLUDED #define AV_ASSET_HELPER_H_INCLUDED
@ -57,11 +56,9 @@ namespace AssimpView {
/** \brief Class to wrap ASSIMP's asset output structures /** \brief Class to wrap ASSIMP's asset output structures
*/ */
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
class AssetHelper class AssetHelper {
{
public: public:
enum enum {
{
// the original normal set will be used // the original normal set will be used
ORIGINAL = 0x0u, ORIGINAL = 0x0u,
@ -73,9 +70,8 @@ namespace AssimpView {
}; };
// default constructor // default constructor
AssetHelper() AssetHelper() :
: iNormalSet( ORIGINAL ) iNormalSet(ORIGINAL) {
{
mAnimator = NULL; mAnimator = NULL;
apcMeshes = NULL; apcMeshes = NULL;
pcScene = NULL; pcScene = NULL;
@ -86,8 +82,7 @@ namespace AssimpView {
// (even if tangents, bitangents or normals aren't // (even if tangents, bitangents or normals aren't
// required by the shader they will be committed to the GPU) // required by the shader they will be committed to the GPU)
//--------------------------------------------------------------- //---------------------------------------------------------------
struct Vertex struct Vertex {
{
aiVector3D vPosition; aiVector3D vPosition;
aiVector3D vNormal; aiVector3D vNormal;
@ -100,10 +95,8 @@ namespace AssimpView {
unsigned char mBoneWeights[4]; // last Weight not used, calculated inside the vertex shader unsigned char mBoneWeights[4]; // last Weight not used, calculated inside the vertex shader
/** Returns the vertex declaration elements to create a declaration from. */ /** Returns the vertex declaration elements to create a declaration from. */
static D3DVERTEXELEMENT9* GetDeclarationElements() static D3DVERTEXELEMENT9 *GetDeclarationElements() {
{ static D3DVERTEXELEMENT9 decl[] = {
static D3DVERTEXELEMENT9 decl[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, { 0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
@ -123,14 +116,12 @@ namespace AssimpView {
//--------------------------------------------------------------- //---------------------------------------------------------------
// FVF vertex structure used for normals // FVF vertex structure used for normals
//--------------------------------------------------------------- //---------------------------------------------------------------
struct LineVertex struct LineVertex {
{
aiVector3D vPosition; aiVector3D vPosition;
DWORD dColorDiffuse; DWORD dColorDiffuse;
// retrieves the FVF code of the vertex type // retrieves the FVF code of the vertex type
static DWORD GetFVF() static DWORD GetFVF() {
{
return D3DFVF_DIFFUSE | D3DFVF_XYZ; return D3DFVF_DIFFUSE | D3DFVF_XYZ;
} }
}; };
@ -139,12 +130,9 @@ namespace AssimpView {
// Helper class to store GPU related resources created for // Helper class to store GPU related resources created for
// a given aiMesh // a given aiMesh
//--------------------------------------------------------------- //---------------------------------------------------------------
class MeshHelper class MeshHelper {
{
public: public:
MeshHelper() :
MeshHelper()
:
eShadingMode(), eShadingMode(),
piVB(NULL), piVB(NULL),
piIB(NULL), piIB(NULL),
@ -163,11 +151,9 @@ namespace AssimpView {
fShininess(), fShininess(),
fSpecularStrength(), fSpecularStrength(),
twosided(false), twosided(false),
pvOriginalNormals( NULL ) pvOriginalNormals(NULL) {}
{}
~MeshHelper() ~MeshHelper() {
{
// NOTE: This is done in DeleteAssetData() // NOTE: This is done in DeleteAssetData()
// TODO: Make this a proper d'tor // TODO: Make this a proper d'tor
} }
@ -245,6 +231,6 @@ namespace AssimpView {
void FlipNormals(); void FlipNormals();
void FlipNormalsInt(); void FlipNormalsInt();
}; };
} } // namespace AssimpView
#endif // !! IG #endif // !! IG

View File

@ -118,8 +118,9 @@ CBackgroundPainter CBackgroundPainter::s_cInstance;
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
void CBackgroundPainter::SetColor(D3DCOLOR p_clrNew) { void CBackgroundPainter::SetColor(D3DCOLOR p_clrNew) {
if (TEXTURE_CUBE == eMode) if (TEXTURE_CUBE == eMode) {
RemoveSBDeps(); RemoveSBDeps();
}
clrColor = p_clrNew; clrColor = p_clrNew;
eMode = SIMPLE_COLOR; eMode = SIMPLE_COLOR;

View File

@ -45,22 +45,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssetHelper.h" #include "AssetHelper.h"
namespace AssimpView namespace AssimpView {
{
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
/* Helper class to create, access and destroy materials /* Helper class to create, access and destroy materials
*/ */
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
class CMaterialManager class CMaterialManager {
{
private: private:
friend class CDisplay; friend class CDisplay;
// default constructor // default constructor
CMaterialManager() CMaterialManager() :
: m_iShaderCount( 0 ), sDefaultTexture() {} m_iShaderCount(0), sDefaultTexture() {}
~CMaterialManager() { ~CMaterialManager() {
if (sDefaultTexture) { if (sDefaultTexture) {
@ -70,12 +67,10 @@ namespace AssimpView
} }
public: public:
//------------------------------------------------------------------ //------------------------------------------------------------------
// Singleton accessors // Singleton accessors
static CMaterialManager s_cInstance; static CMaterialManager s_cInstance;
inline static CMaterialManager& Instance() inline static CMaterialManager &Instance() {
{
return s_cInstance; return s_cInstance;
} }
@ -137,20 +132,17 @@ namespace AssimpView
// The function tries to find a valid path for a texture // The function tries to find a valid path for a texture
int LoadTexture(IDirect3DTexture9 **p_ppiOut, aiString *szPath); int LoadTexture(IDirect3DTexture9 **p_ppiOut, aiString *szPath);
//------------------------------------------------------------------ //------------------------------------------------------------------
// Getter for m_iShaderCount // Getter for m_iShaderCount
// //
inline unsigned int GetShaderCount() inline unsigned int GetShaderCount() {
{
return this->m_iShaderCount; return this->m_iShaderCount;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
// Reset the state of the class // Reset the state of the class
// Called whenever a new asset is loaded // Called whenever a new asset is loaded
inline void Reset() inline void Reset() {
{
this->m_iShaderCount = 0; this->m_iShaderCount = 0;
for (TextureCache::iterator it = sCachedTextures.begin(); it != sCachedTextures.end(); ++it) { for (TextureCache::iterator it = sCachedTextures.begin(); it != sCachedTextures.end(); ++it) {
(*it).second->Release(); (*it).second->Release();
@ -159,7 +151,6 @@ namespace AssimpView
} }
private: private:
//------------------------------------------------------------------ //------------------------------------------------------------------
// find a valid path to a texture file // find a valid path to a texture file
// //
@ -192,7 +183,6 @@ namespace AssimpView
bool HasAlphaPixels(IDirect3DTexture9 *piTexture); bool HasAlphaPixels(IDirect3DTexture9 *piTexture);
private: private:
// //
// Specifies the number of different shaders generated for // Specifies the number of different shaders generated for
// the current asset. This number is incremented by CreateMaterial() // the current asset. This number is incremented by CreateMaterial()
@ -205,4 +195,4 @@ namespace AssimpView
TextureCache sCachedTextures; TextureCache sCachedTextures;
}; };
} } // namespace AssimpView

View File

@ -71,24 +71,14 @@ struct SceneAnimNode {
int mChannelIndex; int mChannelIndex;
//! Default construction //! Default construction
SceneAnimNode() SceneAnimNode() :
: mName() mName(), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
, mParent(nullptr)
, mChildren()
, mLocalTransform()
, mGlobalTransform()
, mChannelIndex(-1) {
// empty // empty
} }
//! Construction from a given name //! Construction from a given name
SceneAnimNode( const std::string& pName) SceneAnimNode(const std::string &pName) :
: mName( pName) mName(pName), mParent(nullptr), mChildren(), mLocalTransform(), mGlobalTransform(), mChannelIndex(-1) {
, mParent(nullptr)
, mChildren()
, mLocalTransform()
, mGlobalTransform()
, mChannelIndex(-1) {
// empty // empty
} }
@ -112,7 +102,6 @@ struct SceneAnimNode {
*/ */
class SceneAnimator { class SceneAnimator {
public: public:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Constructor for a given scene. /** Constructor for a given scene.
* *
@ -205,7 +194,6 @@ public:
} }
protected: protected:
/** Recursively creates an internal node structure matching the /** Recursively creates an internal node structure matching the
* current scene and animation. * current scene and animation.
*/ */

View File

@ -1394,4 +1394,4 @@ std::string g_szCheckerBackgroundShader = std::string(
"VertexShader = compile vs_3_0 DefaultVShader();\n" "VertexShader = compile vs_3_0 DefaultVShader();\n"
"}\n" "}\n"
"};\n"); "};\n");
}; // namespace AssimpView } // namespace AssimpView

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -41,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
#include "assimp_view.h" #include "assimp_view.h"
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <map> #include <map>
@ -113,11 +110,9 @@ aiMatrix4x4 g_mWorldRotate;
aiVector3D g_vRotateSpeed = aiVector3D(0.5f, 0.5f, 0.5f); aiVector3D g_vRotateSpeed = aiVector3D(0.5f, 0.5f, 0.5f);
// NOTE: The second light direction is now computed from the first // NOTE: The second light direction is now computed from the first
aiVector3D g_avLightDirs[1] = aiVector3D g_avLightDirs[1] = { aiVector3D(-0.5f, 0.6f, 0.2f) };
{ aiVector3D(-0.5f,0.6f,0.2f) };
D3DCOLOR g_avLightColors[3] = D3DCOLOR g_avLightColors[3] = {
{
D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF), D3DCOLOR_ARGB(0xFF, 0xFF, 0xFF, 0xFF),
D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0x00), D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0x00),
D3DCOLOR_ARGB(0xFF, 0x05, 0x05, 0x05), D3DCOLOR_ARGB(0xFF, 0x05, 0x05, 0x05),
@ -145,14 +140,12 @@ unsigned char* g_szImageMask = nullptr;
float g_fLoadTime = 0.0f; float g_fLoadTime = 0.0f;
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Entry point for the loader thread // Entry point for the loader thread
// The loader thread loads the asset while the progress dialog displays the // The loader thread loads the asset while the progress dialog displays the
// smart progress bar // smart progress bar
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
DWORD WINAPI LoadThreadProc(LPVOID lpParameter) DWORD WINAPI LoadThreadProc(LPVOID lpParameter) {
{
UNREFERENCED_PARAMETER(lpParameter); UNREFERENCED_PARAMETER(lpParameter);
// get current time // get current time
@ -186,8 +179,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
g_bLoadingFinished = true; g_bLoadingFinished = true;
// check whether the loading process has failed ... // check whether the loading process has failed ...
if (nullptr == g_pcAsset->pcScene) if (nullptr == g_pcAsset->pcScene) {
{
CLogDisplay::Instance().AddEntry("[ERROR] Unable to load this asset:", CLogDisplay::Instance().AddEntry("[ERROR] Unable to load this asset:",
D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0)); D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
@ -204,8 +196,7 @@ DWORD WINAPI LoadThreadProc(LPVOID lpParameter)
// load the current asset // load the current asset
// THe path to the asset is specified in the global path variable // THe path to the asset is specified in the global path variable
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int LoadAsset() int LoadAsset() {
{
// set the world and world rotation matrices to the identity // set the world and world rotation matrices to the identity
g_mWorldRotate = aiMatrix4x4(); g_mWorldRotate = aiMatrix4x4();
g_mWorld = aiMatrix4x4(); g_mWorld = aiMatrix4x4();
@ -225,8 +216,7 @@ int LoadAsset()
g_pcAsset = new AssetHelper(); g_pcAsset = new AssetHelper();
g_hThreadHandle = CreateThread(nullptr, 0, &LoadThreadProc, nullptr, 0, &dwID); g_hThreadHandle = CreateThread(nullptr, 0, &LoadThreadProc, nullptr, 0, &dwID);
if (!g_hThreadHandle) if (!g_hThreadHandle) {
{
CLogDisplay::Instance().AddEntry( CLogDisplay::Instance().AddEntry(
"[ERROR] Unable to create helper thread for loading", "[ERROR] Unable to create helper thread for loading",
D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0)); D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
@ -243,10 +233,8 @@ int LoadAsset()
// now we should have loaded the asset. Check this ... // now we should have loaded the asset. Check this ...
g_bLoadingFinished = false; g_bLoadingFinished = false;
if (!g_pcAsset || !g_pcAsset->pcScene) if (!g_pcAsset || !g_pcAsset->pcScene) {
{ if (g_pcAsset) {
if (g_pcAsset)
{
delete g_pcAsset; delete g_pcAsset;
g_pcAsset = nullptr; g_pcAsset = nullptr;
} }
@ -259,7 +247,6 @@ int LoadAsset()
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i)
g_pcAsset->apcMeshes[i] = new AssetHelper::MeshHelper(); g_pcAsset->apcMeshes[i] = new AssetHelper::MeshHelper();
// create animator // create animator
g_pcAsset->mAnimator = new SceneAnimator(g_pcAsset->pcScene); g_pcAsset->mAnimator = new SceneAnimator(g_pcAsset->pcScene);
@ -285,8 +272,7 @@ int LoadAsset()
if (!g_pcAsset->pcScene->HasAnimations()) { if (!g_pcAsset->pcScene->HasAnimations()) {
EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), FALSE); EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), FALSE);
EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), FALSE); EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), FALSE);
} } else {
else {
EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), TRUE); EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), TRUE);
EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), TRUE); EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), TRUE);
} }
@ -305,7 +291,6 @@ int LoadAsset()
return 1; return 1;
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Delete the loaded asset // Delete the loaded asset
// The function does nothing is no asset is loaded // The function does nothing is no asset is loaded
@ -320,8 +305,7 @@ int DeleteAsset(void) {
// delete everything // delete everything
DeleteAssetData(); DeleteAssetData();
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
{
delete g_pcAsset->apcMeshes[i]; delete g_pcAsset->apcMeshes[i];
} }
aiReleaseImport(g_pcAsset->pcScene); aiReleaseImport(g_pcAsset->pcScene);
@ -342,7 +326,6 @@ int DeleteAsset(void) {
return 1; return 1;
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Calculate the boundaries of a given node and all of its children // Calculate the boundaries of a given node and all of its children
// The boundaries are in Worldspace (AABB) // The boundaries are in Worldspace (AABB)
@ -358,11 +341,8 @@ int CalculateBounds(aiNode* piNode, aiVector3D* p_avOut, const aiMatrix4x4& piMa
mTemp.Transpose(); mTemp.Transpose();
aiMatrix4x4 aiMe = mTemp * piMatrix; aiMatrix4x4 aiMe = mTemp * piMatrix;
for (unsigned int i = 0; i < piNode->mNumMeshes;++i) for (unsigned int i = 0; i < piNode->mNumMeshes; ++i) {
{ for (unsigned int a = 0; a < g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]]->mNumVertices; ++a) {
for( unsigned int a = 0; a < g_pcAsset->pcScene->mMeshes[
piNode->mMeshes[i]]->mNumVertices;++a)
{
aiVector3D pc = g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]]->mVertices[a]; aiVector3D pc = g_pcAsset->pcScene->mMeshes[piNode->mMeshes[i]]->mVertices[a];
aiVector3D pc1; aiVector3D pc1;
@ -377,8 +357,7 @@ int CalculateBounds(aiNode* piNode, aiVector3D* p_avOut, const aiMatrix4x4& piMa
p_avOut[1].z = max(p_avOut[1].z, pc1.z); p_avOut[1].z = max(p_avOut[1].z, pc1.z);
} }
} }
for (unsigned int i = 0; i < piNode->mNumChildren;++i) for (unsigned int i = 0; i < piNode->mNumChildren; ++i) {
{
CalculateBounds(piNode->mChildren[i], p_avOut, aiMe); CalculateBounds(piNode->mChildren[i], p_avOut, aiMe);
} }
return 1; return 1;
@ -388,13 +367,11 @@ int CalculateBounds(aiNode* piNode, aiVector3D* p_avOut, const aiMatrix4x4& piMa
// The function calculates the boundaries of the mesh and modifies the // The function calculates the boundaries of the mesh and modifies the
// global world transformation matrix according to the aset AABB // global world transformation matrix according to the aset AABB
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int ScaleAsset(void) int ScaleAsset(void) {
{
aiVector3D aiVecs[2] = { aiVector3D(1e10f, 1e10f, 1e10f), aiVector3D aiVecs[2] = { aiVector3D(1e10f, 1e10f, 1e10f),
aiVector3D(-1e10f, -1e10f, -1e10f) }; aiVector3D(-1e10f, -1e10f, -1e10f) };
if (g_pcAsset->pcScene->mRootNode) if (g_pcAsset->pcScene->mRootNode) {
{
aiMatrix4x4 m; aiMatrix4x4 m;
CalculateBounds(g_pcAsset->pcScene->mRootNode, aiVecs, m); CalculateBounds(g_pcAsset->pcScene->mRootNode, aiVecs, m);
} }
@ -422,8 +399,7 @@ int ScaleAsset(void)
// pcMesh Input mesh // pcMesh Input mesh
// pcSource Source mesh from ASSIMP // pcSource Source mesh from ASSIMP
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int GenerateNormalsAsLineList(AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSource) int GenerateNormalsAsLineList(AssetHelper::MeshHelper *pcMesh, const aiMesh *pcSource) {
{
ai_assert(nullptr != pcMesh); ai_assert(nullptr != pcMesh);
ai_assert(nullptr != pcSource); ai_assert(nullptr != pcSource);
@ -434,8 +410,7 @@ int GenerateNormalsAsLineList(AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSo
pcSource->mNumVertices * 2, pcSource->mNumVertices * 2,
D3DUSAGE_WRITEONLY, D3DUSAGE_WRITEONLY,
AssetHelper::LineVertex::GetFVF(), AssetHelper::LineVertex::GetFVF(),
D3DPOOL_DEFAULT, &pcMesh->piVBNormals,nullptr))) D3DPOOL_DEFAULT, &pcMesh->piVBNormals, nullptr))) {
{
CLogDisplay::Instance().AddEntry("Failed to create vertex buffer for the normal list", CLogDisplay::Instance().AddEntry("Failed to create vertex buffer for the normal list",
D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0)); D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
return 2; return 2;
@ -444,8 +419,7 @@ int GenerateNormalsAsLineList(AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSo
// now fill the vertex buffer with data // now fill the vertex buffer with data
AssetHelper::LineVertex *pbData2; AssetHelper::LineVertex *pbData2;
pcMesh->piVBNormals->Lock(0, 0, (void **)&pbData2, 0); pcMesh->piVBNormals->Lock(0, 0, (void **)&pbData2, 0);
for (unsigned int x = 0; x < pcSource->mNumVertices;++x) for (unsigned int x = 0; x < pcSource->mNumVertices; ++x) {
{
pbData2->vPosition = pcSource->mVertices[x]; pbData2->vPosition = pcSource->mVertices[x];
++pbData2; ++pbData2;
@ -472,16 +446,14 @@ int GenerateNormalsAsLineList(AssetHelper::MeshHelper* pcMesh,const aiMesh* pcSo
// Create the native D3D representation of the asset: vertex buffers, // Create the native D3D representation of the asset: vertex buffers,
// index buffers, materials ... // index buffers, materials ...
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int CreateAssetData() int CreateAssetData() {
{
if (!g_pcAsset) return 0; if (!g_pcAsset) return 0;
// reset all subsystems // reset all subsystems
CMaterialManager::Instance().Reset(); CMaterialManager::Instance().Reset();
CDisplay::Instance().Reset(); CDisplay::Instance().Reset();
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
{
const aiMesh *mesh = g_pcAsset->pcScene->mMeshes[i]; const aiMesh *mesh = g_pcAsset->pcScene->mMeshes[i];
// create the material for the mesh // create the material for the mesh
@ -534,8 +506,7 @@ int CreateAssetData()
D3DFMT_INDEX32, D3DFMT_INDEX32,
D3DPOOL_DEFAULT, D3DPOOL_DEFAULT,
&g_pcAsset->apcMeshes[i]->piIB, &g_pcAsset->apcMeshes[i]->piIB,
nullptr))) nullptr))) {
{
MessageBox(g_hDlg, "Failed to create 32 Bit index buffer", MessageBox(g_hDlg, "Failed to create 32 Bit index buffer",
"ASSIMP Viewer Utility", MB_OK); "ASSIMP Viewer Utility", MB_OK);
return 2; return 2;
@ -544,15 +515,12 @@ int CreateAssetData()
// now fill the index buffer // now fill the index buffer
unsigned int *pbData; unsigned int *pbData;
g_pcAsset->apcMeshes[i]->piIB->Lock(0, 0, (void **)&pbData, 0); g_pcAsset->apcMeshes[i]->piIB->Lock(0, 0, (void **)&pbData, 0);
for (unsigned int x = 0; x < mesh->mNumFaces;++x) for (unsigned int x = 0; x < mesh->mNumFaces; ++x) {
{ for (unsigned int a = 0; a < nidx; ++a) {
for (unsigned int a = 0; a < nidx;++a)
{
*pbData++ = mesh->mFaces[x].mIndices[a]; *pbData++ = mesh->mFaces[x].mIndices[a];
} }
} }
} } else {
else {
// create 16 bit index buffer // create 16 bit index buffer
if (FAILED(g_piDevice->CreateIndexBuffer(2 * if (FAILED(g_piDevice->CreateIndexBuffer(2 *
numIndices, numIndices,
@ -560,8 +528,7 @@ int CreateAssetData()
D3DFMT_INDEX16, D3DFMT_INDEX16,
D3DPOOL_DEFAULT, D3DPOOL_DEFAULT,
&g_pcAsset->apcMeshes[i]->piIB, &g_pcAsset->apcMeshes[i]->piIB,
nullptr))) nullptr))) {
{
MessageBox(g_hDlg, "Failed to create 16 Bit index buffer", MessageBox(g_hDlg, "Failed to create 16 Bit index buffer",
"ASSIMP Viewer Utility", MB_OK); "ASSIMP Viewer Utility", MB_OK);
return 2; return 2;
@ -570,10 +537,8 @@ int CreateAssetData()
// now fill the index buffer // now fill the index buffer
uint16_t *pbData; uint16_t *pbData;
g_pcAsset->apcMeshes[i]->piIB->Lock(0, 0, (void **)&pbData, 0); g_pcAsset->apcMeshes[i]->piIB->Lock(0, 0, (void **)&pbData, 0);
for (unsigned int x = 0; x < mesh->mNumFaces;++x) for (unsigned int x = 0; x < mesh->mNumFaces; ++x) {
{ for (unsigned int a = 0; a < nidx; ++a) {
for (unsigned int a = 0; a < nidx;++a)
{
*pbData++ = (uint16_t)mesh->mFaces[x].mIndices[a]; *pbData++ = (uint16_t)mesh->mFaces[x].mIndices[a];
} }
} }
@ -591,19 +556,18 @@ int CreateAssetData()
// now fill the vertex buffer // now fill the vertex buffer
AssetHelper::Vertex *pbData2; AssetHelper::Vertex *pbData2;
g_pcAsset->apcMeshes[i]->piVB->Lock(0, 0, (void **)&pbData2, 0); g_pcAsset->apcMeshes[i]->piVB->Lock(0, 0, (void **)&pbData2, 0);
for (unsigned int x = 0; x < mesh->mNumVertices;++x) for (unsigned int x = 0; x < mesh->mNumVertices; ++x) {
{
pbData2->vPosition = mesh->mVertices[x]; pbData2->vPosition = mesh->mVertices[x];
if (nullptr == mesh->mNormals) if (nullptr == mesh->mNormals)
pbData2->vNormal = aiVector3D(0.0f, 0.0f, 0.0f); pbData2->vNormal = aiVector3D(0.0f, 0.0f, 0.0f);
else pbData2->vNormal = mesh->mNormals[x]; else
pbData2->vNormal = mesh->mNormals[x];
if (nullptr == mesh->mTangents) { if (nullptr == mesh->mTangents) {
pbData2->vTangent = aiVector3D(0.0f, 0.0f, 0.0f); pbData2->vTangent = aiVector3D(0.0f, 0.0f, 0.0f);
pbData2->vBitangent = aiVector3D(0.0f, 0.0f, 0.0f); pbData2->vBitangent = aiVector3D(0.0f, 0.0f, 0.0f);
} } else {
else {
pbData2->vTangent = mesh->mTangents[x]; pbData2->vTangent = mesh->mTangents[x];
pbData2->vBitangent = mesh->mBitangents[x]; pbData2->vBitangent = mesh->mBitangents[x];
} }
@ -614,39 +578,37 @@ int CreateAssetData()
((unsigned char)max(min(mesh->mColors[0][x].r * 255.0f, 255.0f), 0.0f)), ((unsigned char)max(min(mesh->mColors[0][x].r * 255.0f, 255.0f), 0.0f)),
((unsigned char)max(min(mesh->mColors[0][x].g * 255.0f, 255.0f), 0.0f)), ((unsigned char)max(min(mesh->mColors[0][x].g * 255.0f, 255.0f), 0.0f)),
((unsigned char)max(min(mesh->mColors[0][x].b * 255.0f, 255.0f), 0.0f))); ((unsigned char)max(min(mesh->mColors[0][x].b * 255.0f, 255.0f), 0.0f)));
} } else
else pbData2->dColorDiffuse = D3DCOLOR_ARGB(0xFF,0xff,0xff,0xff); pbData2->dColorDiffuse = D3DCOLOR_ARGB(0xFF, 0xff, 0xff, 0xff);
// ignore a third texture coordinate component // ignore a third texture coordinate component
if (mesh->HasTextureCoords(0)) { if (mesh->HasTextureCoords(0)) {
pbData2->vTextureUV = aiVector2D( pbData2->vTextureUV = aiVector2D(
mesh->mTextureCoords[0][x].x, mesh->mTextureCoords[0][x].x,
mesh->mTextureCoords[0][x].y); mesh->mTextureCoords[0][x].y);
} } else
else pbData2->vTextureUV = aiVector2D(0.5f,0.5f); pbData2->vTextureUV = aiVector2D(0.5f, 0.5f);
if (mesh->HasTextureCoords(1)) { if (mesh->HasTextureCoords(1)) {
pbData2->vTextureUV2 = aiVector2D( pbData2->vTextureUV2 = aiVector2D(
mesh->mTextureCoords[1][x].x, mesh->mTextureCoords[1][x].x,
mesh->mTextureCoords[1][x].y); mesh->mTextureCoords[1][x].y);
} } else
else pbData2->vTextureUV2 = aiVector2D(0.5f,0.5f); pbData2->vTextureUV2 = aiVector2D(0.5f, 0.5f);
// Bone indices and weights // Bone indices and weights
if (mesh->HasBones()) { if (mesh->HasBones()) {
unsigned char boneIndices[4] = { 0, 0, 0, 0 }; unsigned char boneIndices[4] = { 0, 0, 0, 0 };
unsigned char boneWeights[4] = { 0, 0, 0, 0 }; unsigned char boneWeights[4] = { 0, 0, 0, 0 };
ai_assert(weightsPerVertex[x].size() <= 4); ai_assert(weightsPerVertex[x].size() <= 4);
for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++) for (unsigned int a = 0; a < weightsPerVertex[x].size(); a++) {
{
boneIndices[a] = static_cast<unsigned char>(weightsPerVertex[x][a].mVertexId); boneIndices[a] = static_cast<unsigned char>(weightsPerVertex[x][a].mVertexId);
boneWeights[a] = (unsigned char)(weightsPerVertex[x][a].mWeight * 255.0f); boneWeights[a] = (unsigned char)(weightsPerVertex[x][a].mWeight * 255.0f);
} }
memcpy(pbData2->mBoneIndices, boneIndices, sizeof(boneIndices)); memcpy(pbData2->mBoneIndices, boneIndices, sizeof(boneIndices));
memcpy(pbData2->mBoneWeights, boneWeights, sizeof(boneWeights)); memcpy(pbData2->mBoneWeights, boneWeights, sizeof(boneWeights));
} else } else {
{
memset(pbData2->mBoneIndices, 0, sizeof(pbData2->mBoneIndices)); memset(pbData2->mBoneIndices, 0, sizeof(pbData2->mBoneIndices));
memset(pbData2->mBoneWeights, 0, sizeof(pbData2->mBoneWeights)); memset(pbData2->mBoneWeights, 0, sizeof(pbData2->mBoneWeights));
} }
@ -667,25 +629,20 @@ int CreateAssetData()
// Delete all effects, textures, vertex buffers ... associated with // Delete all effects, textures, vertex buffers ... associated with
// an asset // an asset
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int DeleteAssetData(bool bNoMaterials) int DeleteAssetData(bool bNoMaterials) {
{
if (!g_pcAsset) return 0; if (!g_pcAsset) return 0;
// TODO: Move this to a proper destructor // TODO: Move this to a proper destructor
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes; ++i) {
{ if (g_pcAsset->apcMeshes[i]->piVB) {
if(g_pcAsset->apcMeshes[i]->piVB)
{
g_pcAsset->apcMeshes[i]->piVB->Release(); g_pcAsset->apcMeshes[i]->piVB->Release();
g_pcAsset->apcMeshes[i]->piVB = nullptr; g_pcAsset->apcMeshes[i]->piVB = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piVBNormals) if (g_pcAsset->apcMeshes[i]->piVBNormals) {
{
g_pcAsset->apcMeshes[i]->piVBNormals->Release(); g_pcAsset->apcMeshes[i]->piVBNormals->Release();
g_pcAsset->apcMeshes[i]->piVBNormals = nullptr; g_pcAsset->apcMeshes[i]->piVBNormals = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piIB) if (g_pcAsset->apcMeshes[i]->piIB) {
{
g_pcAsset->apcMeshes[i]->piIB->Release(); g_pcAsset->apcMeshes[i]->piIB->Release();
g_pcAsset->apcMeshes[i]->piIB = nullptr; g_pcAsset->apcMeshes[i]->piIB = nullptr;
} }
@ -698,45 +655,36 @@ int DeleteAssetData(bool bNoMaterials)
// delete[] g_pcAsset->apcMeshes[i]->pvOriginalNormals; // delete[] g_pcAsset->apcMeshes[i]->pvOriginalNormals;
//} //}
if (!bNoMaterials) if (!bNoMaterials) {
{ if (g_pcAsset->apcMeshes[i]->piEffect) {
if(g_pcAsset->apcMeshes[i]->piEffect)
{
g_pcAsset->apcMeshes[i]->piEffect->Release(); g_pcAsset->apcMeshes[i]->piEffect->Release();
g_pcAsset->apcMeshes[i]->piEffect = nullptr; g_pcAsset->apcMeshes[i]->piEffect = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piDiffuseTexture) if (g_pcAsset->apcMeshes[i]->piDiffuseTexture) {
{
g_pcAsset->apcMeshes[i]->piDiffuseTexture->Release(); g_pcAsset->apcMeshes[i]->piDiffuseTexture->Release();
g_pcAsset->apcMeshes[i]->piDiffuseTexture = nullptr; g_pcAsset->apcMeshes[i]->piDiffuseTexture = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piNormalTexture) if (g_pcAsset->apcMeshes[i]->piNormalTexture) {
{
g_pcAsset->apcMeshes[i]->piNormalTexture->Release(); g_pcAsset->apcMeshes[i]->piNormalTexture->Release();
g_pcAsset->apcMeshes[i]->piNormalTexture = nullptr; g_pcAsset->apcMeshes[i]->piNormalTexture = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piSpecularTexture) if (g_pcAsset->apcMeshes[i]->piSpecularTexture) {
{
g_pcAsset->apcMeshes[i]->piSpecularTexture->Release(); g_pcAsset->apcMeshes[i]->piSpecularTexture->Release();
g_pcAsset->apcMeshes[i]->piSpecularTexture = nullptr; g_pcAsset->apcMeshes[i]->piSpecularTexture = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piAmbientTexture) if (g_pcAsset->apcMeshes[i]->piAmbientTexture) {
{
g_pcAsset->apcMeshes[i]->piAmbientTexture->Release(); g_pcAsset->apcMeshes[i]->piAmbientTexture->Release();
g_pcAsset->apcMeshes[i]->piAmbientTexture = nullptr; g_pcAsset->apcMeshes[i]->piAmbientTexture = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piEmissiveTexture) if (g_pcAsset->apcMeshes[i]->piEmissiveTexture) {
{
g_pcAsset->apcMeshes[i]->piEmissiveTexture->Release(); g_pcAsset->apcMeshes[i]->piEmissiveTexture->Release();
g_pcAsset->apcMeshes[i]->piEmissiveTexture = nullptr; g_pcAsset->apcMeshes[i]->piEmissiveTexture = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piOpacityTexture) if (g_pcAsset->apcMeshes[i]->piOpacityTexture) {
{
g_pcAsset->apcMeshes[i]->piOpacityTexture->Release(); g_pcAsset->apcMeshes[i]->piOpacityTexture->Release();
g_pcAsset->apcMeshes[i]->piOpacityTexture = nullptr; g_pcAsset->apcMeshes[i]->piOpacityTexture = nullptr;
} }
if(g_pcAsset->apcMeshes[i]->piShininessTexture) if (g_pcAsset->apcMeshes[i]->piShininessTexture) {
{
g_pcAsset->apcMeshes[i]->piShininessTexture->Release(); g_pcAsset->apcMeshes[i]->piShininessTexture->Release();
g_pcAsset->apcMeshes[i]->piShininessTexture = nullptr; g_pcAsset->apcMeshes[i]->piShininessTexture = nullptr;
} }
@ -745,22 +693,17 @@ int DeleteAssetData(bool bNoMaterials)
return 1; return 1;
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Switch between zoom/rotate view and the standard FPS view // Switch between zoom/rotate view and the standard FPS view
// g_bFPSView specifies the view mode to setup // g_bFPSView specifies the view mode to setup
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int SetupFPSView() int SetupFPSView() {
{ if (!g_bFPSView) {
if (!g_bFPSView)
{
g_sCamera.vPos = aiVector3D(0.0f, 0.0f, g_fWheelPos); g_sCamera.vPos = aiVector3D(0.0f, 0.0f, g_fWheelPos);
g_sCamera.vLookAt = aiVector3D(0.0f, 0.0f, 1.0f); g_sCamera.vLookAt = aiVector3D(0.0f, 0.0f, 1.0f);
g_sCamera.vUp = aiVector3D(0.0f, 1.0f, 0.0f); g_sCamera.vUp = aiVector3D(0.0f, 1.0f, 0.0f);
g_sCamera.vRight = aiVector3D(0.0f, 1.0f, 0.0f); g_sCamera.vRight = aiVector3D(0.0f, 1.0f, 0.0f);
} } else {
else
{
g_fWheelPos = g_sCamera.vPos.z; g_fWheelPos = g_sCamera.vPos.z;
g_sCamera.vPos = aiVector3D(0.0f, 0.0f, -10.0f); g_sCamera.vPos = aiVector3D(0.0f, 0.0f, -10.0f);
g_sCamera.vLookAt = aiVector3D(0.0f, 0.0f, 1.0f); g_sCamera.vLookAt = aiVector3D(0.0f, 0.0f, 1.0f);
@ -774,26 +717,21 @@ int SetupFPSView()
// Initialize the IDIrect3D interface // Initialize the IDIrect3D interface
// Called by the WinMain // Called by the WinMain
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int InitD3D(void) int InitD3D(void) {
{ if (nullptr == g_piD3D) {
if (nullptr == g_piD3D)
{
g_piD3D = Direct3DCreate9(D3D_SDK_VERSION); g_piD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (nullptr == g_piD3D) return 0; if (nullptr == g_piD3D) return 0;
} }
return 1; return 1;
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Release the IDirect3D interface. // Release the IDirect3D interface.
// NOTE: Assumes that the device has already been deleted // NOTE: Assumes that the device has already been deleted
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int ShutdownD3D(void) int ShutdownD3D(void) {
{
ShutdownDevice(); ShutdownDevice();
if (nullptr != g_piD3D) if (nullptr != g_piD3D) {
{
g_piD3D->Release(); g_piD3D->Release();
g_piD3D = nullptr; g_piD3D = nullptr;
} }
@ -801,8 +739,7 @@ int ShutdownD3D(void)
} }
template <class TComPtr> template <class TComPtr>
inline inline void SafeRelease(TComPtr *&ptr) {
void SafeRelease(TComPtr *&ptr) {
if (nullptr != ptr) { if (nullptr != ptr) {
ptr->Release(); ptr->Release();
ptr = nullptr; ptr = nullptr;
@ -813,8 +750,7 @@ void SafeRelease(TComPtr *&ptr) {
// Shutdown the D3D device object and all resources associated with it // Shutdown the D3D device object and all resources associated with it
// NOTE: Assumes that the asset has already been deleted // NOTE: Assumes that the asset has already been deleted
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int ShutdownDevice(void) int ShutdownDevice(void) {
{
// release other subsystems // release other subsystems
CBackgroundPainter::Instance().ReleaseNativeResource(); CBackgroundPainter::Instance().ReleaseNativeResource();
CLogDisplay::Instance().ReleaseNativeResource(); CLogDisplay::Instance().ReleaseNativeResource();
@ -837,11 +773,9 @@ int ShutdownDevice(void)
return 1; return 1;
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int CreateHUDTexture() int CreateHUDTexture() {
{
// lock the memory resource ourselves // lock the memory resource ourselves
HRSRC res = FindResource(nullptr, MAKEINTRESOURCE(IDR_HUD), RT_RCDATA); HRSRC res = FindResource(nullptr, MAKEINTRESOURCE(IDR_HUD), RT_RCDATA);
HGLOBAL hg = LoadResource(nullptr, res); HGLOBAL hg = LoadResource(nullptr, res);
@ -860,8 +794,7 @@ int CreateHUDTexture()
0, 0,
nullptr, nullptr,
nullptr, nullptr,
&g_pcTexture))) &g_pcTexture))) {
{
CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD texture", CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD texture",
D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0)); D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
@ -877,7 +810,6 @@ int CreateHUDTexture()
D3DSURFACE_DESC sDesc; D3DSURFACE_DESC sDesc;
g_pcTexture->GetLevelDesc(0, &sDesc); g_pcTexture->GetLevelDesc(0, &sDesc);
// lock the memory resource ourselves // lock the memory resource ourselves
res = FindResource(nullptr, MAKEINTRESOURCE(IDR_HUDMASK), RT_RCDATA); res = FindResource(nullptr, MAKEINTRESOURCE(IDR_HUDMASK), RT_RCDATA);
hg = LoadResource(nullptr, res); hg = LoadResource(nullptr, res);
@ -897,8 +829,7 @@ int CreateHUDTexture()
0, 0,
nullptr, nullptr,
nullptr, nullptr,
&pcTex))) &pcTex))) {
{
CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD mask texture", CLogDisplay::Instance().AddEntry("[ERROR] Unable to load HUD mask texture",
D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0)); D3DCOLOR_ARGB(0xFF, 0xFF, 0, 0));
g_szImageMask = nullptr; g_szImageMask = nullptr;
@ -917,8 +848,7 @@ int CreateHUDTexture()
unsigned char *_szOut = szOut; unsigned char *_szOut = szOut;
unsigned char *szCur = (unsigned char *)sRect.pBits; unsigned char *szCur = (unsigned char *)sRect.pBits;
for (unsigned int y = 0; y < sDesc.Height;++y) for (unsigned int y = 0; y < sDesc.Height; ++y) {
{
memcpy(_szOut, szCur, sDesc.Width); memcpy(_szOut, szCur, sDesc.Width);
szCur += sRect.Pitch; szCur += sRect.Pitch;
@ -933,8 +863,7 @@ int CreateHUDTexture()
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) int CreateDevice(bool p_bMultiSample, bool p_bSuperSample, bool bHW /*= true*/) {
{
D3DDEVTYPE eType = bHW ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF; D3DDEVTYPE eType = bHW ? D3DDEVTYPE_HAL : D3DDEVTYPE_REF;
// get the client rectangle of the window. // get the client rectangle of the window.
@ -962,30 +891,25 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
// check whether we can use a D32 depth buffer format // check whether we can use a D32 depth buffer format
if (SUCCEEDED(g_piD3D->CheckDepthStencilMatch(0, eType, if (SUCCEEDED(g_piD3D->CheckDepthStencilMatch(0, eType,
D3DFMT_X8R8G8B8,D3DFMT_X8R8G8B8,D3DFMT_D32))) D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_D32))) {
{
sParams.AutoDepthStencilFormat = D3DFMT_D32; sParams.AutoDepthStencilFormat = D3DFMT_D32;
} } else
else sParams.AutoDepthStencilFormat = D3DFMT_D24X8; sParams.AutoDepthStencilFormat = D3DFMT_D24X8;
// find the highest multisample type available on this device // find the highest multisample type available on this device
D3DMULTISAMPLE_TYPE sMS = D3DMULTISAMPLE_2_SAMPLES; D3DMULTISAMPLE_TYPE sMS = D3DMULTISAMPLE_2_SAMPLES;
D3DMULTISAMPLE_TYPE sMSOut = D3DMULTISAMPLE_NONE; D3DMULTISAMPLE_TYPE sMSOut = D3DMULTISAMPLE_NONE;
DWORD dwQuality = 0; DWORD dwQuality = 0;
if (p_bMultiSample) if (p_bMultiSample) {
{
while ((D3DMULTISAMPLE_TYPE)(D3DMULTISAMPLE_16_SAMPLES + 1) != while ((D3DMULTISAMPLE_TYPE)(D3DMULTISAMPLE_16_SAMPLES + 1) !=
(sMS = (D3DMULTISAMPLE_TYPE)(sMS + 1))) (sMS = (D3DMULTISAMPLE_TYPE)(sMS + 1))) {
{
if (SUCCEEDED(g_piD3D->CheckDeviceMultiSampleType(0, eType, if (SUCCEEDED(g_piD3D->CheckDeviceMultiSampleType(0, eType,
sMode.Format,TRUE,sMS,&dwQuality))) sMode.Format, TRUE, sMS, &dwQuality))) {
{
sMSOut = sMS; sMSOut = sMS;
} }
} }
if (0 != dwQuality) dwQuality -= 1; if (0 != dwQuality) dwQuality -= 1;
sParams.MultiSampleQuality = dwQuality; sParams.MultiSampleQuality = dwQuality;
sParams.MultiSampleType = sMSOut; sParams.MultiSampleType = sMSOut;
} }
@ -999,8 +923,7 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; creationFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
// create the D3D9 device object. with software-vertexprocessing if VS2.0 isn`t supported in hardware // create the D3D9 device object. with software-vertexprocessing if VS2.0 isn`t supported in hardware
if(FAILED(g_piD3D->CreateDevice(0,eType, g_hDlg, creationFlags ,&sParams,&g_piDevice))) if (FAILED(g_piD3D->CreateDevice(0, eType, g_hDlg, creationFlags, &sParams, &g_piDevice))) {
{
// if hardware fails use software rendering instead // if hardware fails use software rendering instead
if (bHW) return CreateDevice(p_bMultiSample, p_bSuperSample, false); if (bHW) return CreateDevice(p_bMultiSample, p_bSuperSample, false);
return 0; return 0;
@ -1008,8 +931,7 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
// create a vertex declaration to match the vertex // create a vertex declaration to match the vertex
D3DVERTEXELEMENT9 *vdecl = AssetHelper::Vertex::GetDeclarationElements(); D3DVERTEXELEMENT9 *vdecl = AssetHelper::Vertex::GetDeclarationElements();
if( FAILED( g_piDevice->CreateVertexDeclaration( vdecl, &gDefaultVertexDecl))) if (FAILED(g_piDevice->CreateVertexDeclaration(vdecl, &gDefaultVertexDecl))) {
{
MessageBox(g_hDlg, "Failed to create vertex declaration", "Init", MB_OK); MessageBox(g_hDlg, "Failed to create vertex declaration", "Init", MB_OK);
return 0; return 0;
} }
@ -1017,8 +939,7 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
// get the capabilities of the device object // get the capabilities of the device object
g_piDevice->GetDeviceCaps(&g_sCaps); g_piDevice->GetDeviceCaps(&g_sCaps);
if(g_sCaps.PixelShaderVersion < D3DPS_VERSION(3,0)) if (g_sCaps.PixelShaderVersion < D3DPS_VERSION(3, 0)) {
{
EnableWindow(GetDlgItem(g_hDlg, IDC_LOWQUALITY), FALSE); EnableWindow(GetDlgItem(g_hDlg, IDC_LOWQUALITY), FALSE);
} }
@ -1031,17 +952,14 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
nullptr, nullptr,
AI_SHADER_COMPILE_FLAGS, AI_SHADER_COMPILE_FLAGS,
nullptr, nullptr,
&g_piDefaultEffect,&piBuffer))) &g_piDefaultEffect, &piBuffer))) {
{ if (piBuffer) {
if( piBuffer)
{
MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK); MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
piBuffer->Release(); piBuffer->Release();
} }
return 0; return 0;
} }
if( piBuffer) if (piBuffer) {
{
piBuffer->Release(); piBuffer->Release();
piBuffer = nullptr; piBuffer = nullptr;
} }
@ -1053,17 +971,14 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
// create the shader used to draw the HUD // create the shader used to draw the HUD
if (FAILED(D3DXCreateEffect(g_piDevice, if (FAILED(D3DXCreateEffect(g_piDevice,
g_szPassThroughShader.c_str(), (UINT)g_szPassThroughShader.length(), g_szPassThroughShader.c_str(), (UINT)g_szPassThroughShader.length(),
nullptr,nullptr,AI_SHADER_COMPILE_FLAGS,nullptr,&g_piPassThroughEffect,&piBuffer))) nullptr, nullptr, AI_SHADER_COMPILE_FLAGS, nullptr, &g_piPassThroughEffect, &piBuffer))) {
{ if (piBuffer) {
if( piBuffer)
{
MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK); MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
piBuffer->Release(); piBuffer->Release();
} }
return 0; return 0;
} }
if( piBuffer) if (piBuffer) {
{
piBuffer->Release(); piBuffer->Release();
piBuffer = nullptr; piBuffer = nullptr;
} }
@ -1075,17 +990,14 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
// create the shader used to visualize normal vectors // create the shader used to visualize normal vectors
if (FAILED(D3DXCreateEffect(g_piDevice, if (FAILED(D3DXCreateEffect(g_piDevice,
g_szNormalsShader.c_str(), (UINT)g_szNormalsShader.length(), g_szNormalsShader.c_str(), (UINT)g_szNormalsShader.length(),
nullptr,nullptr,AI_SHADER_COMPILE_FLAGS,nullptr,&g_piNormalsEffect, &piBuffer))) nullptr, nullptr, AI_SHADER_COMPILE_FLAGS, nullptr, &g_piNormalsEffect, &piBuffer))) {
{ if (piBuffer) {
if( piBuffer)
{
MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK); MessageBox(g_hDlg, (LPCSTR)piBuffer->GetBufferPointer(), "HLSL", MB_OK);
piBuffer->Release(); piBuffer->Release();
} }
return 0; return 0;
} }
if( piBuffer) if (piBuffer) {
{
piBuffer->Release(); piBuffer->Release();
piBuffer = nullptr; piBuffer = nullptr;
} }
@ -1108,15 +1020,13 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int CreateDevice() int CreateDevice() {
{
return CreateDevice(g_sOptions.bMultiSample, return CreateDevice(g_sOptions.bMultiSample,
g_sOptions.bSuperSample); g_sOptions.bSuperSample);
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int GetProjectionMatrix (aiMatrix4x4& p_mOut) int GetProjectionMatrix(aiMatrix4x4 &p_mOut) {
{
const float fFarPlane = 100.0f; const float fFarPlane = 100.0f;
const float fNearPlane = 0.1f; const float fNearPlane = 0.1f;
const float fFOV = (float)(45.0 * 0.0174532925); const float fFOV = (float)(45.0 * 0.0174532925);
@ -1139,8 +1049,7 @@ int GetProjectionMatrix (aiMatrix4x4& p_mOut)
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
aiVector3D GetCameraMatrix (aiMatrix4x4& p_mOut) aiVector3D GetCameraMatrix(aiMatrix4x4 &p_mOut) {
{
D3DXMATRIX view; D3DXMATRIX view;
D3DXMatrixIdentity(&view); D3DXMatrixIdentity(&view);
@ -1175,4 +1084,4 @@ aiVector3D GetCameraMatrix (aiMatrix4x4& p_mOut)
return g_sCamera.vPos; return g_sCamera.vPos;
} }
} } // namespace AssimpView

View File

@ -51,24 +51,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "resource.h" #include "resource.h"
#include <assert.h> #include <assert.h>
#include <stdlib.h>
#include <malloc.h> #include <malloc.h>
#include <memory.h> #include <memory.h>
#include <tchar.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <time.h> #include <time.h>
// Include ASSIMP headers (XXX: do we really need all of them?) // Include ASSIMP headers (XXX: do we really need all of them?)
#include <assimp/cimport.h>
#include <assimp/Importer.hpp>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/cfileio.h> #include <assimp/cfileio.h>
#include <assimp/cimport.h>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/IOSystem.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/LogStream.hpp>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <assimp/Importer.hpp>
#include <assimp/LogStream.hpp>
#include "Material/MaterialSystem.h" // aiMaterial class #include "Material/MaterialSystem.h" // aiMaterial class
#include <assimp/StringComparison.h> // ASSIMP_stricmp and ASSIMP_strincmp #include <assimp/StringComparison.h> // ASSIMP_stricmp and ASSIMP_strincmp
@ -79,23 +79,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define MOVE_SPEED 3.f #define MOVE_SPEED 3.f
#include "AssetHelper.h" #include "AssetHelper.h"
#include "Camera.h"
#include "RenderOptions.h"
#include "Shaders.h"
#include "Background.h" #include "Background.h"
#include "Camera.h"
#include "Display.h"
#include "LogDisplay.h" #include "LogDisplay.h"
#include "LogWindow.h" #include "LogWindow.h"
#include "Display.h"
#include "MeshRenderer.h"
#include "MaterialManager.h" #include "MaterialManager.h"
#include "MeshRenderer.h"
#include "RenderOptions.h"
#include "Shaders.h"
// outside of namespace, to help Intellisense and solve boost::metatype_stuff_miracle // outside of namespace, to help Intellisense and solve boost::metatype_stuff_miracle
#include "AnimEvaluator.h" #include "AnimEvaluator.h"
#include "SceneAnimator.h" #include "SceneAnimator.h"
namespace AssimpView namespace AssimpView {
{
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Function prototypes // Function prototypes
@ -125,7 +123,6 @@ void HandleMouseInputSkyBox( void );
void HandleKeyboardInputTextureView(void); void HandleKeyboardInputTextureView(void);
void HandleMouseInputTextureView(void); void HandleMouseInputTextureView(void);
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// //
// Dialog procedure for the progress bar window // Dialog procedure for the progress bar window
@ -161,7 +158,6 @@ INT_PTR CALLBACK AboutMessageProc(HWND hwndDlg,UINT uMsg,
INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg, UINT uMsg, INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam); WPARAM wParam, LPARAM lParam);
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Handle command line parameters // Handle command line parameters
// //
@ -170,22 +166,18 @@ INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg,UINT uMsg,
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
void HandleCommandLine(char *p_szCommand); void HandleCommandLine(char *p_szCommand);
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
template <class type, class intype> template <class type, class intype>
type clamp(intype in) type clamp(intype in) {
{
// for unsigned types only ... // for unsigned types only ...
intype mask = (0x1u << (sizeof(type) * 8)) - 1; intype mask = (0x1u << (sizeof(type) * 8)) - 1;
return (type)std::max((intype)0, std::min(in, mask)); return (type)std::max((intype)0, std::min(in, mask));
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// Position of the cursor relative to the 3ds max' like control circle // Position of the cursor relative to the 3ds max' like control circle
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
enum EClickPos enum EClickPos {
{
// The click was inside the inner circle (x,y axis) // The click was inside the inner circle (x,y axis)
EClickPos_Circle, EClickPos_Circle,
// The click was inside one of the vertical snap-ins // The click was inside one of the vertical snap-ins
@ -232,8 +224,8 @@ enum EClickPos
extern aiVector3D g_avLightDirs[1] /* = extern aiVector3D g_avLightDirs[1] /* =
{ aiVector3D(-0.5f,0.6f,0.2f) , { aiVector3D(-0.5f,0.6f,0.2f) ,
aiVector3D(-0.5f,0.5f,0.5f)} */; aiVector3D(-0.5f,0.5f,0.5f)} */
;
extern POINT g_mousePos /*= {0,0};*/; extern POINT g_mousePos /*= {0,0};*/;
extern POINT g_LastmousePos /*= {0,0}*/; extern POINT g_LastmousePos /*= {0,0}*/;
@ -254,7 +246,6 @@ enum EClickPos
extern Camera g_sCamera; extern Camera g_sCamera;
extern AssetHelper *g_pcAsset /*= NULL*/; extern AssetHelper *g_pcAsset /*= NULL*/;
// //
// Contains the mask image for the HUD // Contains the mask image for the HUD
// (used to determine the position of a click) // (used to determine the position of a click)
@ -264,7 +255,6 @@ enum EClickPos
// //
extern unsigned char *g_szImageMask /*= NULL*/; extern unsigned char *g_szImageMask /*= NULL*/;
extern float g_fACMR /*= 3.0f*/; extern float g_fACMR /*= 3.0f*/;
extern IDirect3DQuery9 *g_piQuery; extern IDirect3DQuery9 *g_piQuery;
@ -275,6 +265,6 @@ enum EClickPos
extern unsigned int ppsteps, ppstepsdefault; extern unsigned int ppsteps, ppstepsdefault;
extern bool nopointslines; extern bool nopointslines;
} } // namespace AssimpView
#endif // !! AV_MAIN_H_INCLUDED #endif // !! AV_MAIN_H_INCLUDED