Collada: Ensure <geometry> has unique id

Use the "id" for mesh names by default.
Set option AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES to use the mesh "name" instead
This commit is contained in:
RichardTea
2020-04-29 17:17:46 +01:00
parent 2c6ac23a4e
commit ff9f3b8608
10 changed files with 274 additions and 94 deletions
+1
View File
@@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/color4.h
${HEADER_PATH}/color4.inl
${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
${HEADER_PATH}/ColladaMetaData.h
${HEADER_PATH}/commonMetaData.h
${HEADER_PATH}/defs.h
${HEADER_PATH}/Defines.h
+79 -25
View File
@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaExporter.h"
#include <assimp/Bitmap.h>
#include <assimp/ColladaMetaData.h>
#include <assimp/DefaultIOSystem.h>
#include <assimp/MathFunctions.h>
#include <assimp/SceneCombiner.h>
@@ -115,7 +116,7 @@ static const std::string XMLIDEncode(const std::string &name) {
if (strchr(XML_ID_CHARS, *it) != nullptr) {
idEncoded << *it;
} 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];
}
}
@@ -854,8 +855,8 @@ void ColladaExporter::WriteControllerLibrary() {
// Writes a skin controller of the given mesh
void ColladaExporter::WriteController(size_t pIndex) {
const aiMesh *mesh = mScene->mMeshes[pIndex];
const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str();
const std::string idstrEscaped = XMLIDEncode(idstr);
const std::string idstr = GetMeshUniqueId(pIndex);
const std::string namestr = GetMeshName(pIndex);
if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
return;
@@ -863,11 +864,11 @@ void ColladaExporter::WriteController(size_t pIndex) {
if (mesh->mNumBones == 0)
return;
mOutput << startstr << "<controller id=\"" << idstrEscaped << "-skin\" ";
mOutput << startstr << "<controller id=\"" << idstr << "-skin\" ";
mOutput << "name=\"skinCluster" << pIndex << "\">" << endstr;
PushTag();
mOutput << startstr << "<skin source=\"#" << idstrEscaped << "\">" << endstr;
mOutput << startstr << "<skin source=\"#" << idstr << "\">" << endstr;
PushTag();
// bind pose matrix
@@ -884,10 +885,10 @@ void ColladaExporter::WriteController(size_t pIndex) {
PopTag();
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();
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)
mOutput << XMLIDEncode(mesh->mBones[i]->mName.C_Str()) << " ";
@@ -897,7 +898,7 @@ void ColladaExporter::WriteController(size_t pIndex) {
mOutput << startstr << "<technique_common>" << endstr;
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();
mOutput << startstr << "<param name=\"JOINT\" type=\"Name\"></param>" << endstr;
@@ -934,8 +935,8 @@ void ColladaExporter::WriteController(size_t pIndex) {
mOutput << startstr << "<joints>" << endstr;
PushTag();
mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstrEscaped << "-skin-joints\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"INV_BIND_MATRIX\" source=\"#" << idstrEscaped << "-skin-bind_poses\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstr << "-skin-joints\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"INV_BIND_MATRIX\" source=\"#" << idstr << "-skin-bind_poses\"></input>" << endstr;
PopTag();
mOutput << startstr << "</joints>" << endstr;
@@ -943,8 +944,8 @@ void ColladaExporter::WriteController(size_t pIndex) {
mOutput << startstr << "<vertex_weights count=\"" << mesh->mNumVertices << "\">" << endstr;
PushTag();
mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstrEscaped << "-skin-joints\" offset=\"0\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"WEIGHT\" source=\"#" << idstrEscaped << "-skin-weights\" offset=\"1\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstr << "-skin-joints\" offset=\"0\"></input>" << endstr;
mOutput << startstr << "<input semantic=\"WEIGHT\" source=\"#" << idstr << "-skin-weights\" offset=\"1\"></input>" << endstr;
mOutput << startstr << "<vcount>";
@@ -1019,9 +1020,8 @@ void ColladaExporter::WriteGeometryLibrary() {
// Writes the given mesh
void ColladaExporter::WriteGeometry(size_t pIndex) {
const aiMesh *mesh = mScene->mMeshes[pIndex];
const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str();
const std::string geometryName = XMLEscape(idstr);
const std::string geometryId = XMLIDEncode(idstr);
const std::string geometryName = GetMeshName(pIndex);
const std::string geometryId = GetMeshUniqueId(pIndex);
if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
return;
@@ -1034,15 +1034,15 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
PushTag();
// 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
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
for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++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);
}
}
@@ -1050,7 +1050,7 @@ void ColladaExporter::WriteGeometry(size_t pIndex) {
// vertex colors
for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++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
@@ -1530,13 +1530,13 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) {
const std::string node_name = XMLEscape(pNode->mName.data);
mOutput << startstr << "<node ";
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.
mFoundSkeletonRootNodeID = node_id;
} else {
mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id + "\"" : "");
mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id + "\" " : "");
}
mOutput << " name=\"" << node_name
mOutput << "name=\"" << node_name
<< "\" type=\"" << node_type
<< "\">" << endstr;
PushTag();
@@ -1595,14 +1595,14 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) {
if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
continue;
const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str();
const std::string meshId = GetMeshUniqueId(pNode->mMeshes[a]);
if (mesh->mNumBones == 0) {
mOutput << startstr << "<instance_geometry url=\"#" << XMLIDEncode(meshName) << "\">" << endstr;
mOutput << startstr << "<instance_geometry url=\"#" << meshId << "\">" << endstr;
PushTag();
} else {
mOutput << startstr
<< "<instance_controller url=\"#" << XMLIDEncode(meshName) << "-skin\">"
<< "<instance_controller url=\"#" << meshId << "-skin\">"
<< endstr;
PushTag();
@@ -1649,5 +1649,59 @@ void ColladaExporter::WriteNode(const aiScene *pScene, aiNode *pNode) {
mOutput << startstr << "</node>" << endstr;
}
/// Get or Create a unique mesh ID string for the given mesh index
std::string Assimp::ColladaExporter::GetMeshUniqueId(size_t pIndex) {
auto meshId = mMeshIdMap.find(pIndex);
if (meshId != mMeshIdMap.cend())
return meshId->second;
// Not seen this mesh before, create and add
return AddMeshIndexToMaps(pIndex, true);
}
std::string Assimp::ColladaExporter::GetMeshName(size_t pIndex) {
auto meshName = mMeshNameMap.find(pIndex);
if (meshName != mMeshNameMap.cend())
return meshName->second;
// Not seen this mesh before, create and add
return AddMeshIndexToMaps(pIndex, false);
}
inline bool ValueIsUnique(const std::map<size_t, std::string> &map, const std::string &value) {
for (const auto &map_val : map) {
if (value == map_val.second)
return false;
}
return true;
}
// Add the mesh index to both Id and Name maps and return either Id or Name
std::string Assimp::ColladaExporter::AddMeshIndexToMaps(size_t pIndex, bool meshId) {
const aiMesh *mesh = mScene->mMeshes[pIndex];
std::string idStr = mesh->mName.length == 0 ? std::string("meshId_") + to_string(pIndex) : XMLIDEncode(mesh->mName.C_Str());
// Ensure is unique. Relatively slow but will only happen once per mesh
if (!ValueIsUnique(mMeshIdMap, idStr)) {
// Select a number to append
size_t postfix = 1;
idStr.append("_");
while (!ValueIsUnique(mMeshIdMap, idStr + to_string(postfix))) {
++postfix;
}
idStr = idStr + to_string(postfix);
}
// Add to map
mMeshIdMap.insert(std::make_pair(pIndex, idStr));
// Add name to map
const std::string nameStr = mesh->mName.length == 0 ? idStr : XMLEscape(mesh->mName.C_Str());
mMeshNameMap.insert(std::make_pair(pIndex, nameStr));
if (meshId)
return idStr;
else
return nameStr;
}
#endif
#endif
+8 -4
View File
@@ -145,10 +145,14 @@ protected:
startstr.erase(startstr.length() - 2);
}
/// Creates a mesh ID for the given mesh
std::string GetMeshId(size_t pIndex) const {
return std::string("meshId") + to_string(pIndex);
}
/// Get or Create a unique mesh ID string for the given mesh index
std::string GetMeshUniqueId(size_t pIndex);
std::string GetMeshName(size_t pIndex);
private:
std::string AddMeshIndexToMaps(size_t pIndex, bool meshId);
mutable std::map<size_t, std::string> mMeshIdMap; // Cache of encoded unique IDs
mutable std::map<size_t, std::string> mMeshNameMap; // Cache of encoded mesh names
public:
/// Stringstream to write all output into
+3 -1
View File
@@ -339,11 +339,13 @@ struct SubMesh {
/** Contains data for a single mesh */
struct Mesh {
Mesh() {
Mesh(const std::string &id) :
mId(id) {
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
mNumUVComponents[i] = 2;
}
const std::string mId;
std::string mName;
// just to check if there's some sophisticated addressing involved...
+15 -3
View File
@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaLoader.h"
#include "ColladaParser.h"
#include <assimp/ColladaMetaData.h>
#include <assimp/Defines.h>
#include <assimp/anim.h>
#include <assimp/importerdesc.h>
@@ -265,6 +266,13 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad
// find a name for the new node. It's more complicated than you might think
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())
node->mMetaData->Add(AI_METADATA_COLLADA_ID, aiString(pNode->mID));
if (!pNode->mSID.empty())
node->mMetaData->Add(AI_METADATA_COLLADA_SID, aiString(pNode->mSID));
}
// calculate the transformation matrix for it
node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms);
@@ -603,7 +611,11 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
std::unique_ptr<aiMesh> dstMesh(new aiMesh);
dstMesh->mName = pSrcMesh->mName;
if (useColladaName) {
dstMesh->mName = pSrcMesh->mName;
} else {
dstMesh->mName = pSrcMesh->mId;
}
// count the vertices addressed by its faces
const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace,
@@ -700,10 +712,10 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
for (unsigned int i = 0; i < targetData.mStrings.size(); ++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 (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);
mTargetMeshes.push_back(aimesh);
+54 -47
View File
@@ -1716,18 +1716,25 @@ void ColladaParser::ReadGeometryLibrary() {
// TODO: (thom) support SIDs
// ai_assert( TestAttribute( "sid") == -1);
// create a mesh and store it in the library under its ID
Mesh *mesh = new Mesh;
mMeshLibrary[id] = mesh;
// create a mesh and store it in the library under its (resolved) ID
// Skip and warn if ID is not unique
if (mMeshLibrary.find(id) == mMeshLibrary.cend()) {
std::unique_ptr<Mesh> mesh(new Mesh(id));
// read the mesh name if it exists
const int nameIndex = TestAttribute("name");
if (nameIndex != -1) {
mesh->mName = mReader->getAttributeValue(nameIndex);
// read the mesh name if it exists
const int nameIndex = TestAttribute("name");
if (nameIndex != -1) {
mesh->mName = mReader->getAttributeValue(nameIndex);
}
// read on from there
ReadGeometry(*mesh);
// Read successfully, add to library
mMeshLibrary.insert({ id, mesh.release() });
} else {
ASSIMP_LOG_ERROR_F("Collada: Skipped duplicate geometry id: \"", id, "\"");
SkipElement();
}
// read on from there
ReadGeometry(mesh);
} else {
// ignore the rest
SkipElement();
@@ -1743,7 +1750,7 @@ void ColladaParser::ReadGeometryLibrary() {
// ------------------------------------------------------------------------------------------------
// Reads a geometry from the geometry library.
void ColladaParser::ReadGeometry(Collada::Mesh *pMesh) {
void ColladaParser::ReadGeometry(Collada::Mesh &pMesh) {
if (mReader->isEmptyElement())
return;
@@ -1767,7 +1774,7 @@ void ColladaParser::ReadGeometry(Collada::Mesh *pMesh) {
// ------------------------------------------------------------------------------------------------
// Reads a mesh from the geometry library
void ColladaParser::ReadMesh(Mesh *pMesh) {
void ColladaParser::ReadMesh(Mesh &pMesh) {
if (mReader->isEmptyElement())
return;
@@ -1997,16 +2004,16 @@ void ColladaParser::ReadAccessor(const std::string &pID) {
// ------------------------------------------------------------------------------------------------
// Reads input declarations of per-vertex mesh data into the given mesh
void ColladaParser::ReadVertexData(Mesh *pMesh) {
void ColladaParser::ReadVertexData(Mesh &pMesh) {
// extract the ID of the <vertices> element. Not that we care, but to catch strange referencing schemes we should warn about
int attrID = GetAttribute("id");
pMesh->mVertexID = mReader->getAttributeValue(attrID);
pMesh.mVertexID = mReader->getAttributeValue(attrID);
// a number of <input> elements
while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
if (IsElement("input")) {
ReadInputChannel(pMesh->mPerVertexData);
ReadInputChannel(pMesh.mPerVertexData);
} else {
ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <vertices>");
}
@@ -2021,7 +2028,7 @@ void ColladaParser::ReadVertexData(Mesh *pMesh) {
// ------------------------------------------------------------------------------------------------
// Reads input declarations of per-index mesh data into the given mesh
void ColladaParser::ReadIndexData(Mesh *pMesh) {
void ColladaParser::ReadIndexData(Mesh &pMesh) {
std::vector<size_t> vcount;
std::vector<InputChannel> perIndexData;
@@ -2111,7 +2118,7 @@ void ColladaParser::ReadIndexData(Mesh *pMesh) {
// only when we're done reading all <p> tags (and thus know the final vertex count) can we commit the submesh
subgroup.mNumFaces = actualPrimitives;
pMesh->mSubMeshes.push_back(subgroup);
pMesh.mSubMeshes.push_back(subgroup);
}
// ------------------------------------------------------------------------------------------------
@@ -2158,7 +2165,7 @@ void ColladaParser::ReadInputChannel(std::vector<InputChannel> &poChannels) {
// ------------------------------------------------------------------------------------------------
// Reads a <p> primitive index list and assembles the mesh data into the given mesh
size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector<InputChannel> &pPerIndexChannels,
size_t ColladaParser::ReadPrimitives(Mesh &pMesh, std::vector<InputChannel> &pPerIndexChannels,
size_t pNumPrimitives, const std::vector<size_t> &pVCount, PrimitiveType pPrimType) {
// determine number of indices coming per vertex
// find the offset index for all per-vertex channels
@@ -2220,7 +2227,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector<InputChannel> &pPe
ThrowException("Expected different index count in <p> element.");
// find the data for all sources
for (std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) {
for (std::vector<InputChannel>::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
InputChannel &input = *it;
if (input.mResolved)
continue;
@@ -2241,7 +2248,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector<InputChannel> &pPe
// ignore vertex pointer, it doesn't refer to an accessor
if (input.mType == IT_Vertex) {
// warn if the vertex channel does not refer to the <vertices> element in the same mesh
if (input.mAccessor != pMesh->mVertexID)
if (input.mAccessor != pMesh.mVertexID)
ThrowException("Unsupported vertex referencing scheme.");
continue;
}
@@ -2268,8 +2275,8 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector<InputChannel> &pPe
numPrimitives = numberOfVertices - 1;
}
pMesh->mFaceSize.reserve(numPrimitives);
pMesh->mFacePosIndices.reserve(indices.size() / numOffsets);
pMesh.mFaceSize.reserve(numPrimitives);
pMesh.mFacePosIndices.reserve(indices.size() / numOffsets);
size_t polylistStartVertex = 0;
for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++) {
@@ -2314,7 +2321,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector<InputChannel> &pPe
}
// store the face size to later reconstruct the face from
pMesh->mFaceSize.push_back(numPoints);
pMesh.mFaceSize.push_back(numPoints);
}
// if I ever get my hands on that guy who invented this steaming pile of indirection...
@@ -2325,7 +2332,7 @@ size_t ColladaParser::ReadPrimitives(Mesh *pMesh, std::vector<InputChannel> &pPe
///@note This function willn't work correctly if both PerIndex and PerVertex channels have same channels.
///For example if TEXCOORD present in both <vertices> and <polylist> tags this function will create wrong uv coordinates.
///It's not clear from COLLADA documentation is this allowed or not. For now only exporter fixed to avoid such behavior
void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh *pMesh, std::vector<InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices) {
void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh &pMesh, std::vector<InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices) {
// calculate the base offset of the vertex whose attributes we ant to copy
size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets;
@@ -2333,17 +2340,17 @@ void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t n
ai_assert((baseOffset + numOffsets - 1) < indices.size());
// extract per-vertex channels using the global per-vertex offset
for (std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
for (std::vector<InputChannel>::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it)
ExtractDataObjectFromChannel(*it, indices[baseOffset + perVertexOffset], pMesh);
// and extract per-index channels using there specified offset
for (std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it)
ExtractDataObjectFromChannel(*it, indices[baseOffset + it->mOffset], pMesh);
// store the vertex-data index for later assignment of bone vertex weights
pMesh->mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]);
pMesh.mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]);
}
void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh *pMesh, std::vector<InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices) {
void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh &pMesh, std::vector<InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices) {
if (currentPrimitive % 2 != 0) {
//odd tristrip triangles need their indices mangled, to preserve winding direction
CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
@@ -2358,7 +2365,7 @@ void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset,
// ------------------------------------------------------------------------------------------------
// Extracts a single object from an input channel and stores it in the appropriate mesh data array
void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, size_t pLocalIndex, Mesh *pMesh) {
void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, size_t pLocalIndex, Mesh &pMesh) {
// ignore vertex referrer - we handle them that separate
if (pInput.mType == IT_Vertex)
return;
@@ -2380,40 +2387,40 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz
switch (pInput.mType) {
case IT_Position: // ignore all position streams except 0 - there can be only one position
if (pInput.mIndex == 0)
pMesh->mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2]));
pMesh.mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2]));
else
ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported");
break;
case IT_Normal:
// pad to current vertex count if necessary
if (pMesh->mNormals.size() < pMesh->mPositions.size() - 1)
pMesh->mNormals.insert(pMesh->mNormals.end(), pMesh->mPositions.size() - pMesh->mNormals.size() - 1, aiVector3D(0, 1, 0));
if (pMesh.mNormals.size() < pMesh.mPositions.size() - 1)
pMesh.mNormals.insert(pMesh.mNormals.end(), pMesh.mPositions.size() - pMesh.mNormals.size() - 1, aiVector3D(0, 1, 0));
// ignore all normal streams except 0 - there can be only one normal
if (pInput.mIndex == 0)
pMesh->mNormals.push_back(aiVector3D(obj[0], obj[1], obj[2]));
pMesh.mNormals.push_back(aiVector3D(obj[0], obj[1], obj[2]));
else
ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported");
break;
case IT_Tangent:
// pad to current vertex count if necessary
if (pMesh->mTangents.size() < pMesh->mPositions.size() - 1)
pMesh->mTangents.insert(pMesh->mTangents.end(), pMesh->mPositions.size() - pMesh->mTangents.size() - 1, aiVector3D(1, 0, 0));
if (pMesh.mTangents.size() < pMesh.mPositions.size() - 1)
pMesh.mTangents.insert(pMesh.mTangents.end(), pMesh.mPositions.size() - pMesh.mTangents.size() - 1, aiVector3D(1, 0, 0));
// ignore all tangent streams except 0 - there can be only one tangent
if (pInput.mIndex == 0)
pMesh->mTangents.push_back(aiVector3D(obj[0], obj[1], obj[2]));
pMesh.mTangents.push_back(aiVector3D(obj[0], obj[1], obj[2]));
else
ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported");
break;
case IT_Bitangent:
// pad to current vertex count if necessary
if (pMesh->mBitangents.size() < pMesh->mPositions.size() - 1)
pMesh->mBitangents.insert(pMesh->mBitangents.end(), pMesh->mPositions.size() - pMesh->mBitangents.size() - 1, aiVector3D(0, 0, 1));
if (pMesh.mBitangents.size() < pMesh.mPositions.size() - 1)
pMesh.mBitangents.insert(pMesh.mBitangents.end(), pMesh.mPositions.size() - pMesh.mBitangents.size() - 1, aiVector3D(0, 0, 1));
// ignore all bitangent streams except 0 - there can be only one bitangent
if (pInput.mIndex == 0)
pMesh->mBitangents.push_back(aiVector3D(obj[0], obj[1], obj[2]));
pMesh.mBitangents.push_back(aiVector3D(obj[0], obj[1], obj[2]));
else
ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported");
break;
@@ -2421,13 +2428,13 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz
// up to 4 texture coord sets are fine, ignore the others
if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) {
// pad to current vertex count if necessary
if (pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size() - 1)
pMesh->mTexCoords[pInput.mIndex].insert(pMesh->mTexCoords[pInput.mIndex].end(),
pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0));
if (pMesh.mTexCoords[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
pMesh.mTexCoords[pInput.mIndex].insert(pMesh.mTexCoords[pInput.mIndex].end(),
pMesh.mPositions.size() - pMesh.mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0));
pMesh->mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2]));
pMesh.mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2]));
if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */
pMesh->mNumUVComponents[pInput.mIndex] = 3;
pMesh.mNumUVComponents[pInput.mIndex] = 3;
} else {
ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
}
@@ -2436,15 +2443,15 @@ void ColladaParser::ExtractDataObjectFromChannel(const InputChannel &pInput, siz
// up to 4 color sets are fine, ignore the others
if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) {
// pad to current vertex count if necessary
if (pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size() - 1)
pMesh->mColors[pInput.mIndex].insert(pMesh->mColors[pInput.mIndex].end(),
pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1));
if (pMesh.mColors[pInput.mIndex].size() < pMesh.mPositions.size() - 1)
pMesh.mColors[pInput.mIndex].insert(pMesh.mColors[pInput.mIndex].end(),
pMesh.mPositions.size() - pMesh.mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1));
aiColor4D result(0, 0, 0, 1);
for (size_t i = 0; i < pInput.mResolved->mSize; ++i) {
result[static_cast<unsigned int>(i)] = obj[pInput.mResolved->mSubOffset[i]];
}
pMesh->mColors[pInput.mIndex].push_back(result);
pMesh.mColors[pInput.mIndex].push_back(result);
} else {
ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
}
+8 -8
View File
@@ -174,10 +174,10 @@ protected:
void ReadGeometryLibrary();
/** Reads a geometry from the geometry library. */
void ReadGeometry(Collada::Mesh *pMesh);
void ReadGeometry(Collada::Mesh &pMesh);
/** 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
* things that should not be redefinable. Yes, that's another rant.
@@ -195,29 +195,29 @@ protected:
void ReadAccessor(const std::string &pID);
/** 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 */
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 */
void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels);
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
size_t ReadPrimitives(Collada::Mesh *pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t ReadPrimitives(Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
/** Copies the data for a single primitive into the mesh, based on the InputChannels */
void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
Collada::Mesh *pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
size_t currentPrimitive, const std::vector<size_t> &indices);
/** Reads one triangle of a tristrip into the mesh */
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh *pMesh,
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh &pMesh,
std::vector<Collada::InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices);
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh *pMesh);
void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
/** Reads the library of node hierarchies and scene parts */
void ReadSceneLibrary();