+ integrate Debone-Process into Assimp. This step was contributed by mick-p, see [3262561] (https://sourceforge.net/tracker/?func=detail&aid=3262561&group_id=226462&atid=1067634)
- refactor ProcessHelper.h. Some functions now reside in ProcessHelper.cpp, which is new. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@946 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
473dae7876
commit
a6e0a5075f
4
CREDITS
4
CREDITS
|
@ -115,3 +115,7 @@ Contributed AssimpDelphi (/port/AssimpDelphi).
|
||||||
|
|
||||||
- rdb
|
- rdb
|
||||||
Contributes a bundle of fixes and improvments for the bsp-importer.
|
Contributes a bundle of fixes and improvments for the bsp-importer.
|
||||||
|
|
||||||
|
- Mick P
|
||||||
|
For contributing the De-bone postprocessing step and filing various bug reports.
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,6 @@ SOURCE_GROUP( Common FILES
|
||||||
BaseProcess.cpp
|
BaseProcess.cpp
|
||||||
BaseProcess.h
|
BaseProcess.h
|
||||||
ByteSwap.h
|
ByteSwap.h
|
||||||
ProcessHelper.h
|
|
||||||
DefaultProgressHandler.h
|
DefaultProgressHandler.h
|
||||||
DefaultIOStream.cpp
|
DefaultIOStream.cpp
|
||||||
DefaultIOStream.h
|
DefaultIOStream.h
|
||||||
|
@ -362,6 +361,10 @@ SOURCE_GROUP( PostProcessing FILES
|
||||||
OptimizeGraph.h
|
OptimizeGraph.h
|
||||||
OptimizeMeshes.cpp
|
OptimizeMeshes.cpp
|
||||||
OptimizeMeshes.h
|
OptimizeMeshes.h
|
||||||
|
DeboneProcess.cpp
|
||||||
|
DeboneProcess.h
|
||||||
|
ProcessHelper.h
|
||||||
|
ProcessHelper.cp
|
||||||
)
|
)
|
||||||
|
|
||||||
SOURCE_GROUP( Q3D FILES
|
SOURCE_GROUP( Q3D FILES
|
||||||
|
@ -608,6 +611,7 @@ ADD_LIBRARY( assimp SHARED
|
||||||
PretransformVertices.cpp
|
PretransformVertices.cpp
|
||||||
PretransformVertices.h
|
PretransformVertices.h
|
||||||
ProcessHelper.h
|
ProcessHelper.h
|
||||||
|
ProcessHelper.cpp
|
||||||
Q3DLoader.cpp
|
Q3DLoader.cpp
|
||||||
Q3DLoader.h
|
Q3DLoader.h
|
||||||
Q3BSPFileData.h
|
Q3BSPFileData.h
|
||||||
|
@ -734,6 +738,8 @@ ADD_LIBRARY( assimp SHARED
|
||||||
Profiler.h
|
Profiler.h
|
||||||
NDOLoader.cpp
|
NDOLoader.cpp
|
||||||
NDOLoader.h
|
NDOLoader.h
|
||||||
|
DeboneProcess.cpp
|
||||||
|
DeboneProcess.h
|
||||||
ColladaExporter.h
|
ColladaExporter.h
|
||||||
ColladaExporter.cpp
|
ColladaExporter.cpp
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,466 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (ASSIMP)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2010, ASSIMP Development 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 Development 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 DeboneProcess.cpp
|
||||||
|
/** Implementation of the DeboneProcess post processing step */
|
||||||
|
|
||||||
|
#include "AssimpPCH.h"
|
||||||
|
|
||||||
|
// internal headers of the post-processing framework
|
||||||
|
#include "ProcessHelper.h"
|
||||||
|
#include "DeboneProcess.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Assimp;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Constructor to be privately used by Importer
|
||||||
|
DeboneProcess::DeboneProcess()
|
||||||
|
{
|
||||||
|
mNumBones = 0;
|
||||||
|
mNumBonesCanDoWithout = 0;
|
||||||
|
|
||||||
|
mThreshold = AI_DEBONE_THRESHOLD;
|
||||||
|
mAllOrNone = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Destructor, private as well
|
||||||
|
DeboneProcess::~DeboneProcess()
|
||||||
|
{
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Returns whether the processing step is present in the given flag field.
|
||||||
|
bool DeboneProcess::IsActive( unsigned int pFlags) const
|
||||||
|
{
|
||||||
|
return (pFlags & aiProcess_Debone) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Executes the post processing step on the given imported data.
|
||||||
|
void DeboneProcess::SetupProperties(const Importer* pImp)
|
||||||
|
{
|
||||||
|
// get the current value of the property
|
||||||
|
mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
|
||||||
|
mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Executes the post processing step on the given imported data.
|
||||||
|
void DeboneProcess::Execute( aiScene* pScene)
|
||||||
|
{
|
||||||
|
DefaultLogger::get()->debug("DeboneProcess begin");
|
||||||
|
|
||||||
|
if(!pScene->mNumMeshes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool> splitList(pScene->mNumMeshes);
|
||||||
|
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||||
|
splitList[a] = ConsiderMesh( pScene->mMeshes[a] );
|
||||||
|
}
|
||||||
|
|
||||||
|
int numSplits = 0;
|
||||||
|
|
||||||
|
if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) {
|
||||||
|
for(unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||||
|
if(splitList[a]) {
|
||||||
|
numSplits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(numSplits) {
|
||||||
|
// we need to do something. Let's go.
|
||||||
|
mSubMeshIndices.clear();
|
||||||
|
mSubMeshIndices.resize(pScene->mNumMeshes);
|
||||||
|
|
||||||
|
// build a new array of meshes for the scene
|
||||||
|
std::vector<aiMesh*> meshes;
|
||||||
|
|
||||||
|
for(unsigned int a=0;a<pScene->mNumMeshes;a++)
|
||||||
|
{
|
||||||
|
aiMesh* srcMesh = pScene->mMeshes[a];
|
||||||
|
|
||||||
|
std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
|
||||||
|
|
||||||
|
if(splitList[a]) {
|
||||||
|
SplitMesh(srcMesh,newMeshes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mesh was split
|
||||||
|
if(!newMeshes.empty()) {
|
||||||
|
unsigned int out = 0, in = srcMesh->mNumBones;
|
||||||
|
|
||||||
|
// store new meshes and indices of the new meshes
|
||||||
|
for(unsigned int b=0;b<newMeshes.size();b++) {
|
||||||
|
const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0;
|
||||||
|
|
||||||
|
aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0;
|
||||||
|
std::pair<unsigned int,aiNode*> push_pair(meshes.size(),theNode);
|
||||||
|
|
||||||
|
mSubMeshIndices[a].push_back(push_pair);
|
||||||
|
meshes.push_back(newMeshes[b].first);
|
||||||
|
|
||||||
|
out+=newMeshes[b].first->mNumBones;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!DefaultLogger::isNullLogger()) {
|
||||||
|
char buffer[1024];
|
||||||
|
::sprintf(buffer,"Removed %i bones. Input bones: %i. Output bones: %i",in-out,in,out);
|
||||||
|
DefaultLogger::get()->info(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||||
|
delete srcMesh;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Mesh is kept unchanged - store it's new place in the mesh array
|
||||||
|
mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(meshes.size(),0));
|
||||||
|
meshes.push_back(srcMesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rebuild the scene's mesh array
|
||||||
|
pScene->mNumMeshes = meshes.size();
|
||||||
|
delete [] pScene->mMeshes;
|
||||||
|
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||||
|
std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
|
||||||
|
|
||||||
|
// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
|
||||||
|
UpdateNode( pScene->mRootNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultLogger::get()->debug("DeboneProcess end");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Counts bones total/removable in a given mesh.
|
||||||
|
bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
|
||||||
|
{
|
||||||
|
if(!pMesh->HasBones()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool split = false;
|
||||||
|
|
||||||
|
//interstitial faces not permitted
|
||||||
|
bool isInterstitialRequired = false;
|
||||||
|
|
||||||
|
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
|
||||||
|
std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
|
||||||
|
|
||||||
|
const unsigned int cUnowned = UINT_MAX;
|
||||||
|
const unsigned int cCoowned = UINT_MAX-1;
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||||
|
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
|
||||||
|
float w = pMesh->mBones[i]->mWeights[j].mWeight;
|
||||||
|
|
||||||
|
if(w==0.0f) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
|
||||||
|
if(w>=mThreshold) {
|
||||||
|
|
||||||
|
if(vertexBones[vid]!=cUnowned) {
|
||||||
|
if(vertexBones[vid]==i) //double entry
|
||||||
|
{
|
||||||
|
DefaultLogger::get()->warn("Encountered double entry in bone weights");
|
||||||
|
}
|
||||||
|
else //TODO: track attraction in order to break tie
|
||||||
|
{
|
||||||
|
vertexBones[vid] = cCoowned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else vertexBones[vid] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isBoneNecessary[i]) {
|
||||||
|
isBoneNecessary[i] = w<mThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isBoneNecessary[i]) {
|
||||||
|
isInterstitialRequired = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isInterstitialRequired) {
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||||
|
unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
|
||||||
|
|
||||||
|
for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
|
||||||
|
unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
|
||||||
|
|
||||||
|
if(v!=w) {
|
||||||
|
if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
|
||||||
|
if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||||
|
if(!isBoneNecessary[i]) {
|
||||||
|
mNumBonesCanDoWithout++;
|
||||||
|
split = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mNumBones++;
|
||||||
|
}
|
||||||
|
return split;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Splits the given mesh by bone count.
|
||||||
|
void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector<std::pair<aiMesh*,const aiBone*>>& poNewMeshes) const
|
||||||
|
{
|
||||||
|
// same deal here as ConsiderMesh basically
|
||||||
|
|
||||||
|
std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
|
||||||
|
std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
|
||||||
|
|
||||||
|
const unsigned int cUnowned = UINT_MAX;
|
||||||
|
const unsigned int cCoowned = UINT_MAX-1;
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||||
|
for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
|
||||||
|
float w = pMesh->mBones[i]->mWeights[j].mWeight;
|
||||||
|
|
||||||
|
if(w==0.0f) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
|
||||||
|
|
||||||
|
if(w>=mThreshold) {
|
||||||
|
if(vertexBones[vid]!=cUnowned) {
|
||||||
|
if(vertexBones[vid]==i) //double entry
|
||||||
|
{
|
||||||
|
//DefaultLogger::get()->warn("Encountered double entry in bone weights");
|
||||||
|
}
|
||||||
|
else //TODO: track attraction in order to break tie
|
||||||
|
{
|
||||||
|
vertexBones[vid] = cCoowned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else vertexBones[vid] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isBoneNecessary[i]) {
|
||||||
|
isBoneNecessary[i] = w<mThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int nFacesUnowned = 0;
|
||||||
|
|
||||||
|
std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX);
|
||||||
|
std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0);
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||||
|
unsigned int nInterstitial = 1;
|
||||||
|
|
||||||
|
unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
|
||||||
|
|
||||||
|
for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
|
||||||
|
unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
|
||||||
|
|
||||||
|
if(v!=w) {
|
||||||
|
if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
|
||||||
|
if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
|
||||||
|
}
|
||||||
|
else nInterstitial++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices) {
|
||||||
|
faceBones[i] = v; //primitive belongs to bone #v
|
||||||
|
facesPerBone[v]++;
|
||||||
|
}
|
||||||
|
else nFacesUnowned++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidate any "cojoined" faces
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||||
|
if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]])
|
||||||
|
{
|
||||||
|
ai_assert(facesPerBone[faceBones[i]]>0);
|
||||||
|
facesPerBone[faceBones[i]]--;
|
||||||
|
|
||||||
|
nFacesUnowned++;
|
||||||
|
faceBones[i] = cUnowned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nFacesUnowned) {
|
||||||
|
std::vector<unsigned int> subFaces;
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
|
||||||
|
if(faceBones[i]==cUnowned) {
|
||||||
|
subFaces.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0);
|
||||||
|
std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,0);
|
||||||
|
|
||||||
|
poNewMeshes.push_back(push_pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<pMesh->mNumBones;i++) {
|
||||||
|
|
||||||
|
if(!isBoneNecessary[i]&&facesPerBone[i]>0) {
|
||||||
|
std::vector<unsigned int> subFaces;
|
||||||
|
|
||||||
|
for(unsigned int j=0;j<pMesh->mNumFaces;j++) {
|
||||||
|
if(faceBones[j]==i) {
|
||||||
|
subFaces.push_back(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES;
|
||||||
|
aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f);
|
||||||
|
|
||||||
|
//Lifted from PretransformVertices.cpp
|
||||||
|
ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix);
|
||||||
|
std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]);
|
||||||
|
|
||||||
|
poNewMeshes.push_back(push_pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Recursively updates the node's mesh list to account for the changed mesh list
|
||||||
|
void DeboneProcess::UpdateNode(aiNode* pNode) const
|
||||||
|
{
|
||||||
|
// rebuild the node's mesh index list
|
||||||
|
|
||||||
|
std::vector<unsigned int> newMeshList;
|
||||||
|
|
||||||
|
// this will require two passes
|
||||||
|
|
||||||
|
unsigned int m = pNode->mNumMeshes, n = mSubMeshIndices.size();
|
||||||
|
|
||||||
|
// first pass, look for meshes which have not moved
|
||||||
|
|
||||||
|
for(unsigned int a=0;a<m;a++) {
|
||||||
|
|
||||||
|
unsigned int srcIndex = pNode->mMeshes[a];
|
||||||
|
const std::vector<std::pair<unsigned int,aiNode*>> &subMeshes = mSubMeshIndices[srcIndex];
|
||||||
|
unsigned int nSubmeshes = subMeshes.size();
|
||||||
|
|
||||||
|
for(unsigned int b=0;b<nSubmeshes;b++) {
|
||||||
|
if(!subMeshes[b].second) {
|
||||||
|
newMeshList.push_back(subMeshes[b].first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// second pass, collect deboned meshes
|
||||||
|
|
||||||
|
for(unsigned int a=0;a<n;a++)
|
||||||
|
{
|
||||||
|
const std::vector<std::pair<unsigned int,aiNode*>> &subMeshes = mSubMeshIndices[a];
|
||||||
|
unsigned int nSubmeshes = subMeshes.size();
|
||||||
|
|
||||||
|
for(unsigned int b=0;b<nSubmeshes;b++) {
|
||||||
|
if(subMeshes[b].second == pNode) {
|
||||||
|
newMeshList.push_back(subMeshes[b].first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pNode->mNumMeshes > 0 ) {
|
||||||
|
delete [] pNode->mMeshes; pNode->mMeshes = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode->mNumMeshes = newMeshList.size();
|
||||||
|
|
||||||
|
if(pNode->mNumMeshes) {
|
||||||
|
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||||
|
std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do that also recursively for all children
|
||||||
|
for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) {
|
||||||
|
UpdateNode( pNode->mChildren[a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Apply the node transformation to a mesh
|
||||||
|
void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const
|
||||||
|
{
|
||||||
|
// Check whether we need to transform the coordinates at all
|
||||||
|
if (!mat.IsIdentity()) {
|
||||||
|
|
||||||
|
if (mesh->HasPositions()) {
|
||||||
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||||
|
mesh->mVertices[i] = mat * mesh->mVertices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
|
||||||
|
aiMatrix4x4 mWorldIT = mat;
|
||||||
|
mWorldIT.Inverse().Transpose();
|
||||||
|
|
||||||
|
// TODO: implement Inverse() for aiMatrix3x3
|
||||||
|
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
|
||||||
|
|
||||||
|
if (mesh->HasNormals()) {
|
||||||
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||||
|
mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mesh->HasTangentsAndBitangents()) {
|
||||||
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||||
|
mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
|
||||||
|
mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (ASSIMP)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2010, ASSIMP Development 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 Development 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.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Defines a post processing step to limit the number of bones affecting a single vertex. */
|
||||||
|
#ifndef AI_DEBONEPROCESS_H_INC
|
||||||
|
#define AI_DEBONEPROCESS_H_INC
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include "BaseProcess.h"
|
||||||
|
|
||||||
|
#include "../include/aiMesh.h"
|
||||||
|
#include "../include/aiScene.h"
|
||||||
|
|
||||||
|
class DeboneTest;
|
||||||
|
|
||||||
|
namespace Assimp
|
||||||
|
{
|
||||||
|
|
||||||
|
#if (!defined AI_DEBONE_THRESHOLD)
|
||||||
|
# define AI_DEBONE_THRESHOLD 1.0f
|
||||||
|
#endif // !! AI_DEBONE_THRESHOLD
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** This post processing step removes bones nearly losslessly or according to
|
||||||
|
* a configured threshold. In order to remove the bone, the primitives affected by
|
||||||
|
* the bone are split from the mesh. The split off (new) mesh is boneless. At any
|
||||||
|
* point in time, bones without affect upon a given mesh are to be removed.
|
||||||
|
*/
|
||||||
|
class ASSIMP_API DeboneProcess : public BaseProcess
|
||||||
|
{
|
||||||
|
friend class Importer;
|
||||||
|
friend class ::DeboneTest;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Constructor to be privately used by Importer */
|
||||||
|
DeboneProcess();
|
||||||
|
|
||||||
|
/** Destructor, private as well */
|
||||||
|
~DeboneProcess();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Returns whether the processing step is present in the given flag.
|
||||||
|
* @param pFlags The processing flags the importer was called with.
|
||||||
|
* A bitwise combination of #aiPostProcessSteps.
|
||||||
|
* @return true if the process is present in this flag fields,
|
||||||
|
* false if not.
|
||||||
|
*/
|
||||||
|
bool IsActive( unsigned int pFlags) const;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Called prior to ExecuteOnScene().
|
||||||
|
* The function is a request to the process to update its configuration
|
||||||
|
* basing on the Importer's configuration property list.
|
||||||
|
*/
|
||||||
|
void SetupProperties(const Importer* pImp);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Executes the post processing step on the given imported data.
|
||||||
|
* At the moment a process is not supposed to fail.
|
||||||
|
* @param pScene The imported data to work at.
|
||||||
|
*/
|
||||||
|
void Execute( aiScene* pScene);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Counts bones total/removable in a given mesh.
|
||||||
|
* @param pMesh The mesh to process.
|
||||||
|
*/
|
||||||
|
bool ConsiderMesh( const aiMesh* pMesh);
|
||||||
|
|
||||||
|
/// Splits the given mesh by bone count.
|
||||||
|
/// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
|
||||||
|
/// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
|
||||||
|
void SplitMesh(const aiMesh* pMesh, std::vector<std::pair<aiMesh*,const aiBone*>>& poNewMeshes) const;
|
||||||
|
|
||||||
|
/// Recursively updates the node's mesh list to account for the changed mesh list
|
||||||
|
void UpdateNode(aiNode* pNode) const;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
// Apply transformation to a mesh
|
||||||
|
void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Number of bones present in the scene. */
|
||||||
|
unsigned int mNumBones;
|
||||||
|
unsigned int mNumBonesCanDoWithout;
|
||||||
|
|
||||||
|
float mThreshold;
|
||||||
|
bool mAllOrNone;
|
||||||
|
|
||||||
|
/// Per mesh index: Array of indices of the new submeshes.
|
||||||
|
std::vector< std::vector< std::pair< unsigned int,aiNode* > > > mSubMeshIndices;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
#endif // AI_DEBONEPROCESS_H_INC
|
|
@ -178,9 +178,6 @@ using namespace Assimp::Formatter;
|
||||||
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||||
# include "BlenderLoader.h"
|
# include "BlenderLoader.h"
|
||||||
#endif
|
#endif
|
||||||
//#ifndef ASSIMP_BUILD_NO_SWORDOFMOONLIGHT_IMPORTER
|
|
||||||
//# include "SomLoader.h"
|
|
||||||
//#endif
|
|
||||||
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
|
||||||
# include "Q3BSPFileImporter.h"
|
# include "Q3BSPFileImporter.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -260,6 +257,9 @@ using namespace Assimp::Formatter;
|
||||||
#ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS
|
#ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS
|
||||||
# include "SplitByBoneCountProcess.h"
|
# include "SplitByBoneCountProcess.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
|
||||||
|
# include "DeboneProcess.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
using namespace Assimp::Intern;
|
using namespace Assimp::Intern;
|
||||||
|
@ -426,9 +426,6 @@ Importer::Importer()
|
||||||
#if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER)
|
#if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER)
|
||||||
pimpl->mImporter.push_back( new BlenderImporter());
|
pimpl->mImporter.push_back( new BlenderImporter());
|
||||||
#endif
|
#endif
|
||||||
//#if (!defined ASSIMP_BUILD_NO_SWORDOFMOONLIGHT_IMPORTER)
|
|
||||||
// pimpl->mImporter.push_back( new SomImporter());
|
|
||||||
//#endif
|
|
||||||
#if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER)
|
#if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER)
|
||||||
pimpl->mImporter.push_back( new Q3BSPFileImporter() );
|
pimpl->mImporter.push_back( new Q3BSPFileImporter() );
|
||||||
#endif
|
#endif
|
||||||
|
@ -522,6 +519,9 @@ Importer::Importer()
|
||||||
#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
|
#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
|
||||||
pimpl->mPostProcessingSteps.push_back( new FlipWindingOrderProcess());
|
pimpl->mPostProcessingSteps.push_back( new FlipWindingOrderProcess());
|
||||||
#endif
|
#endif
|
||||||
|
#if (!defined ASSIMP_BUILD_DEBONE_PROCESS)
|
||||||
|
pimpl->mPostProcessingSteps.push_back( new DeboneProcess());
|
||||||
|
#endif
|
||||||
#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
|
#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
|
||||||
pimpl->mPostProcessingSteps.push_back( new LimitBoneWeightsProcess());
|
pimpl->mPostProcessingSteps.push_back( new LimitBoneWeightsProcess());
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,410 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (ASSIMP)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2010, ASSIMP Development 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 Development 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 ProcessHelper.cpp
|
||||||
|
/** Implement shared utility functions for postprocessing steps */
|
||||||
|
|
||||||
|
#include "AssimpPCH.h"
|
||||||
|
#include "ProcessHelper.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
|
||||||
|
{
|
||||||
|
const char* s = in.c_str();
|
||||||
|
while (*s) {
|
||||||
|
SkipSpacesAndLineEnd(&s);
|
||||||
|
if (*s == '\'') {
|
||||||
|
const char* base = ++s;
|
||||||
|
while (*s != '\'') {
|
||||||
|
++s;
|
||||||
|
if (*s == '\0') {
|
||||||
|
DefaultLogger::get()->error("ConvertListToString: String list is ill-formatted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.push_back(std::string(base,(size_t)(s-base)));
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.push_back(GetNextToken(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max,
|
||||||
|
const aiMatrix4x4& m)
|
||||||
|
{
|
||||||
|
min = aiVector3D (10e10f, 10e10f, 10e10f);
|
||||||
|
max = aiVector3D (-10e10f,-10e10f,-10e10f);
|
||||||
|
for (unsigned int i = 0;i < mesh->mNumVertices;++i)
|
||||||
|
{
|
||||||
|
const aiVector3D v = m * mesh->mVertices[i];
|
||||||
|
min = std::min(v,min);
|
||||||
|
max = std::max(v,max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max)
|
||||||
|
{
|
||||||
|
ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max);
|
||||||
|
out = min + (max-min)*0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,
|
||||||
|
aiVector3D& max, const aiMatrix4x4& m)
|
||||||
|
{
|
||||||
|
FindAABBTransformed(mesh,min,max,m);
|
||||||
|
out = min + (max-min)*0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
void FindMeshCenter (aiMesh* mesh, aiVector3D& out)
|
||||||
|
{
|
||||||
|
aiVector3D min,max;
|
||||||
|
FindMeshCenter(mesh,out,min,max);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,
|
||||||
|
const aiMatrix4x4& m)
|
||||||
|
{
|
||||||
|
aiVector3D min,max;
|
||||||
|
FindMeshCenterTransformed(mesh,out,min,max,m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
float ComputePositionEpsilon(const aiMesh* pMesh)
|
||||||
|
{
|
||||||
|
const float epsilon = 1e-4f;
|
||||||
|
|
||||||
|
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
||||||
|
aiVector3D minVec, maxVec;
|
||||||
|
ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec);
|
||||||
|
return (maxVec - minVec).Length() * epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
float ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num)
|
||||||
|
{
|
||||||
|
const float epsilon = 1e-4f;
|
||||||
|
|
||||||
|
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
||||||
|
aiVector3D minVec, maxVec, mi, ma;
|
||||||
|
MinMaxChooser<aiVector3D>()(minVec,maxVec);
|
||||||
|
|
||||||
|
for (size_t a = 0; a < num; ++a) {
|
||||||
|
const aiMesh* pMesh = pMeshes[a];
|
||||||
|
ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma);
|
||||||
|
|
||||||
|
minVec = std::min(minVec,mi);
|
||||||
|
maxVec = std::max(maxVec,ma);
|
||||||
|
}
|
||||||
|
return (maxVec - minVec).Length() * epsilon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh)
|
||||||
|
{
|
||||||
|
ai_assert(NULL != pcMesh);
|
||||||
|
|
||||||
|
// FIX: the hash may never be 0. Otherwise a comparison against
|
||||||
|
// nullptr could be successful
|
||||||
|
unsigned int iRet = 1;
|
||||||
|
|
||||||
|
// normals
|
||||||
|
if (pcMesh->HasNormals())iRet |= 0x2;
|
||||||
|
// tangents and bitangents
|
||||||
|
if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4;
|
||||||
|
|
||||||
|
#ifdef BOOST_STATIC_ASSERT
|
||||||
|
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
|
||||||
|
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// texture coordinates
|
||||||
|
unsigned int p = 0;
|
||||||
|
while (pcMesh->HasTextureCoords(p))
|
||||||
|
{
|
||||||
|
iRet |= (0x100 << p);
|
||||||
|
if (3 == pcMesh->mNumUVComponents[p])
|
||||||
|
iRet |= (0x10000 << p);
|
||||||
|
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
// vertex colors
|
||||||
|
p = 0;
|
||||||
|
while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++);
|
||||||
|
return iRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh)
|
||||||
|
{
|
||||||
|
if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
|
||||||
|
for (unsigned int i = 0; i < pMesh->mNumBones;++i) {
|
||||||
|
|
||||||
|
aiBone* bone = pMesh->mBones[i];
|
||||||
|
for (unsigned int a = 0; a < bone->mNumWeights;++a) {
|
||||||
|
const aiVertexWeight& weight = bone->mWeights[a];
|
||||||
|
avPerVertexWeights[weight.mVertexId].push_back( std::pair<unsigned int,float>(i,weight.mWeight) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return avPerVertexWeights;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
const char* TextureTypeToString(aiTextureType in)
|
||||||
|
{
|
||||||
|
switch (in)
|
||||||
|
{
|
||||||
|
case aiTextureType_NONE:
|
||||||
|
return "n/a";
|
||||||
|
case aiTextureType_DIFFUSE:
|
||||||
|
return "Diffuse";
|
||||||
|
case aiTextureType_SPECULAR:
|
||||||
|
return "Specular";
|
||||||
|
case aiTextureType_AMBIENT:
|
||||||
|
return "Ambient";
|
||||||
|
case aiTextureType_EMISSIVE:
|
||||||
|
return "Emissive";
|
||||||
|
case aiTextureType_OPACITY:
|
||||||
|
return "Opacity";
|
||||||
|
case aiTextureType_NORMALS:
|
||||||
|
return "Normals";
|
||||||
|
case aiTextureType_HEIGHT:
|
||||||
|
return "Height";
|
||||||
|
case aiTextureType_SHININESS:
|
||||||
|
return "Shininess";
|
||||||
|
case aiTextureType_DISPLACEMENT:
|
||||||
|
return "Displacement";
|
||||||
|
case aiTextureType_LIGHTMAP:
|
||||||
|
return "Lightmap";
|
||||||
|
case aiTextureType_REFLECTION:
|
||||||
|
return "Reflection";
|
||||||
|
case aiTextureType_UNKNOWN:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
ai_assert(false);
|
||||||
|
return "BUG";
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
const char* MappingTypeToString(aiTextureMapping in)
|
||||||
|
{
|
||||||
|
switch (in)
|
||||||
|
{
|
||||||
|
case aiTextureMapping_UV:
|
||||||
|
return "UV";
|
||||||
|
case aiTextureMapping_BOX:
|
||||||
|
return "Box";
|
||||||
|
case aiTextureMapping_SPHERE:
|
||||||
|
return "Sphere";
|
||||||
|
case aiTextureMapping_CYLINDER:
|
||||||
|
return "Cylinder";
|
||||||
|
case aiTextureMapping_PLANE:
|
||||||
|
return "Plane";
|
||||||
|
case aiTextureMapping_OTHER:
|
||||||
|
return "Other";
|
||||||
|
}
|
||||||
|
|
||||||
|
ai_assert(false);
|
||||||
|
return "BUG";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags)
|
||||||
|
{
|
||||||
|
aiMesh *oMesh = new aiMesh();
|
||||||
|
std::vector<unsigned int> vMap(pMesh->mNumVertices,UINT_MAX);
|
||||||
|
|
||||||
|
size_t numSubVerts = 0;
|
||||||
|
size_t numSubFaces = subMeshFaces.size();
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<numSubFaces;i++) {
|
||||||
|
const aiFace &f = pMesh->mFaces[subMeshFaces[i]];
|
||||||
|
|
||||||
|
for(unsigned int j=0;j<f.mNumIndices;j++) {
|
||||||
|
if(vMap[f.mIndices[j]]==UINT_MAX) {
|
||||||
|
vMap[f.mIndices[j]] = numSubVerts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oMesh->mName = pMesh->mName;
|
||||||
|
|
||||||
|
oMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
||||||
|
oMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
|
||||||
|
|
||||||
|
// create all the arrays for this mesh if the old mesh contained them
|
||||||
|
|
||||||
|
oMesh->mNumFaces = subMeshFaces.size();
|
||||||
|
oMesh->mNumVertices = numSubVerts;
|
||||||
|
oMesh->mVertices = new aiVector3D[numSubVerts];
|
||||||
|
if( pMesh->HasNormals() ) {
|
||||||
|
oMesh->mNormals = new aiVector3D[numSubVerts];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pMesh->HasTangentsAndBitangents() ) {
|
||||||
|
oMesh->mTangents = new aiVector3D[numSubVerts];
|
||||||
|
oMesh->mBitangents = new aiVector3D[numSubVerts];
|
||||||
|
}
|
||||||
|
|
||||||
|
for( size_t a = 0; pMesh->HasTextureCoords( a) ; ++a ) {
|
||||||
|
oMesh->mTextureCoords[a] = new aiVector3D[numSubVerts];
|
||||||
|
oMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
for( size_t a = 0; pMesh->HasVertexColors( a); ++a ) {
|
||||||
|
oMesh->mColors[a] = new aiColor4D[numSubVerts];
|
||||||
|
}
|
||||||
|
|
||||||
|
// and copy over the data, generating faces with linear indices along the way
|
||||||
|
oMesh->mFaces = new aiFace[numSubFaces];
|
||||||
|
|
||||||
|
for(unsigned int a = 0; a < numSubFaces; ++a ) {
|
||||||
|
|
||||||
|
const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
|
||||||
|
aiFace& dstFace = oMesh->mFaces[a];
|
||||||
|
dstFace.mNumIndices = srcFace.mNumIndices;
|
||||||
|
dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
|
||||||
|
|
||||||
|
// accumulate linearly all the vertices of the source face
|
||||||
|
for( size_t b = 0; b < dstFace.mNumIndices; ++b ) {
|
||||||
|
dstFace.mIndices[b] = vMap[srcFace.mIndices[b]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex ) {
|
||||||
|
unsigned int nvi = vMap[srcIndex];
|
||||||
|
if(nvi==UINT_MAX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
oMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
|
||||||
|
if( pMesh->HasNormals() ) {
|
||||||
|
oMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pMesh->HasTangentsAndBitangents() ) {
|
||||||
|
oMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
|
||||||
|
oMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
|
||||||
|
}
|
||||||
|
for( size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c ) {
|
||||||
|
oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
|
||||||
|
}
|
||||||
|
for( size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c ) {
|
||||||
|
oMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(~subFlags&AI_SUBMESH_FLAGS_SANS_BONES) {
|
||||||
|
std::vector<unsigned int> subBones(pMesh->mNumBones,0);
|
||||||
|
|
||||||
|
for(unsigned int a=0;a<pMesh->mNumBones;++a) {
|
||||||
|
const aiBone* bone = pMesh->mBones[a];
|
||||||
|
|
||||||
|
for(unsigned int b=0;b<bone->mNumWeights;b++) {
|
||||||
|
unsigned int v = vMap[bone->mWeights[b].mVertexId];
|
||||||
|
|
||||||
|
if(v!=UINT_MAX) {
|
||||||
|
subBones[a]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int a=0;a<pMesh->mNumBones;++a) {
|
||||||
|
if(subBones[a]>0) {
|
||||||
|
oMesh->mNumBones++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oMesh->mNumBones) {
|
||||||
|
oMesh->mBones = new aiBone*[oMesh->mNumBones]();
|
||||||
|
unsigned int nbParanoia = oMesh->mNumBones;
|
||||||
|
|
||||||
|
oMesh->mNumBones = 0; //rewind
|
||||||
|
|
||||||
|
for(unsigned int a=0;a<pMesh->mNumBones;++a) {
|
||||||
|
if(subBones[a]==0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
aiBone *newBone = new aiBone;
|
||||||
|
oMesh->mBones[oMesh->mNumBones++] = newBone;
|
||||||
|
|
||||||
|
const aiBone* bone = pMesh->mBones[a];
|
||||||
|
|
||||||
|
newBone->mName = bone->mName;
|
||||||
|
newBone->mOffsetMatrix = bone->mOffsetMatrix;
|
||||||
|
newBone->mWeights = new aiVertexWeight[subBones[a]];
|
||||||
|
|
||||||
|
for(unsigned int b=0;b<bone->mNumWeights;b++) {
|
||||||
|
const unsigned int v = vMap[bone->mWeights[b].mVertexId];
|
||||||
|
|
||||||
|
if(v!=UINT_MAX) {
|
||||||
|
aiVertexWeight w(v,bone->mWeights[b].mWeight);
|
||||||
|
newBone->mWeights[newBone->mNumWeights++] = w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ai_assert(nbParanoia==oMesh->mNumBones);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assimp
|
|
@ -191,34 +191,6 @@ inline void ArrayBounds(const T* in, unsigned int size, T& min, T& max)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
/** @brief Extract single strings from a list of identifiers
|
|
||||||
* @param in Input string list.
|
|
||||||
* @param out Receives a list of clean output strings
|
|
||||||
* @sdee #AI_CONFIG_PP_OG_EXCLUDE_LIST
|
|
||||||
*/
|
|
||||||
inline void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
|
|
||||||
{
|
|
||||||
const char* s = in.c_str();
|
|
||||||
while (*s) {
|
|
||||||
SkipSpacesAndLineEnd(&s);
|
|
||||||
if (*s == '\'') {
|
|
||||||
const char* base = ++s;
|
|
||||||
while (*s != '\'') {
|
|
||||||
++s;
|
|
||||||
if (*s == '\0') {
|
|
||||||
DefaultLogger::get()->error("ConvertListToString: String list is ill-formatted");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.push_back(std::string(base,(size_t)(s-base)));
|
|
||||||
++s;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out.push_back(GetNextToken(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** @brief Compute the newell normal of a polygon regardless of its shape
|
/** @brief Compute the newell normal of a polygon regardless of its shape
|
||||||
|
@ -271,55 +243,37 @@ inline void NewellNormal (aiVector3D& out, int num, float* x, float* y, float* z
|
||||||
out = aiVector3D(sum_yz,sum_zx,sum_xy);
|
out = aiVector3D(sum_yz,sum_zx,sum_xy);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
/** @brief Compute newell normal of a polgon regardless of its shape
|
|
||||||
*
|
|
||||||
* @param out Receives the output normal
|
|
||||||
* @param data Input vertices
|
|
||||||
* @param idx Index buffer
|
|
||||||
* @param num Number of indices
|
|
||||||
*/
|
|
||||||
inline void NewellNormal (aiVector3D& out, const aiVector3D* data, unsigned int* idx, unsigned int num )
|
|
||||||
{
|
|
||||||
// TODO: intended to be used in GenNormals.
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** Little helper function to calculate the quadratic difference
|
/** Little helper function to calculate the quadratic difference
|
||||||
* of two colours.
|
* of two colours.
|
||||||
* @param pColor1 First color
|
* @param pColor1 First color
|
||||||
* @param pColor2 second color
|
* @param pColor2 second color
|
||||||
* @return Quadratic color difference
|
* @return Quadratic color difference */
|
||||||
*/
|
|
||||||
inline float GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pColor2)
|
inline float GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pColor2)
|
||||||
{
|
{
|
||||||
const aiColor4D c (pColor1.r - pColor2.r, pColor1.g - pColor2.g,
|
const aiColor4D c (pColor1.r - pColor2.r, pColor1.g - pColor2.g, pColor1.b - pColor2.b, pColor1.a - pColor2.a);
|
||||||
pColor1.b - pColor2.b, pColor1.a - pColor2.a);
|
|
||||||
|
|
||||||
return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a;
|
return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
/** @brief Extract single strings from a list of identifiers
|
||||||
|
* @param in Input string list.
|
||||||
|
* @param out Receives a list of clean output strings
|
||||||
|
* @sdee #AI_CONFIG_PP_OG_EXCLUDE_LIST */
|
||||||
|
void ConvertListToStrings(const std::string& in, std::list<std::string>& out);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** @brief Compute the AABB of a mesh after applying a given transform
|
/** @brief Compute the AABB of a mesh after applying a given transform
|
||||||
* @param mesh Input mesh
|
* @param mesh Input mesh
|
||||||
* @param[out] min Receives minimum transformed vertex
|
* @param[out] min Receives minimum transformed vertex
|
||||||
* @param[out] max Receives maximum transformed vertex
|
* @param[out] max Receives maximum transformed vertex
|
||||||
* @param m Transformation matrix to be applied
|
* @param m Transformation matrix to be applied */
|
||||||
*/
|
void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, const aiMatrix4x4& m);
|
||||||
inline void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max,
|
|
||||||
const aiMatrix4x4& m)
|
|
||||||
{
|
|
||||||
min = aiVector3D (10e10f, 10e10f, 10e10f);
|
|
||||||
max = aiVector3D (-10e10f,-10e10f,-10e10f);
|
|
||||||
for (unsigned int i = 0;i < mesh->mNumVertices;++i)
|
|
||||||
{
|
|
||||||
const aiVector3D v = m * mesh->mVertices[i];
|
|
||||||
min = std::min(v,min);
|
|
||||||
max = std::max(v,max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/** @brief Helper function to determine the 'real' center of a mesh
|
/** @brief Helper function to determine the 'real' center of a mesh
|
||||||
|
@ -328,191 +282,65 @@ inline void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D
|
||||||
* @param mesh Input mesh
|
* @param mesh Input mesh
|
||||||
* @param[out] min Minimum vertex of the mesh
|
* @param[out] min Minimum vertex of the mesh
|
||||||
* @param[out] max maximum vertex of the mesh
|
* @param[out] max maximum vertex of the mesh
|
||||||
* @param[out] out Center point
|
* @param[out] out Center point */
|
||||||
*/
|
void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max);
|
||||||
inline void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max)
|
|
||||||
{
|
|
||||||
ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max);
|
|
||||||
out = min + (max-min)*0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Helper function to determine the 'real' center of a mesh after applying a given transform
|
// Helper function to determine the 'real' center of a mesh after applying a given transform
|
||||||
inline void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,
|
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,aiVector3D& max, const aiMatrix4x4& m);
|
||||||
aiVector3D& max, const aiMatrix4x4& m)
|
|
||||||
{
|
|
||||||
FindAABBTransformed(mesh,min,max,m);
|
|
||||||
out = min + (max-min)*0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Helper function to determine the 'real' center of a mesh
|
// Helper function to determine the 'real' center of a mesh
|
||||||
inline void FindMeshCenter (aiMesh* mesh, aiVector3D& out)
|
void FindMeshCenter (aiMesh* mesh, aiVector3D& out);
|
||||||
{
|
|
||||||
aiVector3D min,max;
|
|
||||||
FindMeshCenter(mesh,out,min,max);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Helper function to determine the 'real' center of a mesh after applying a given transform
|
// Helper function to determine the 'real' center of a mesh after applying a given transform
|
||||||
inline void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,
|
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,const aiMatrix4x4& m);
|
||||||
const aiMatrix4x4& m)
|
|
||||||
{
|
|
||||||
aiVector3D min,max;
|
|
||||||
FindMeshCenterTransformed(mesh,out,min,max,m);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Compute a good epsilon value for position comparisons on a mesh
|
// Compute a good epsilon value for position comparisons on a mesh
|
||||||
inline float ComputePositionEpsilon(const aiMesh* pMesh)
|
float ComputePositionEpsilon(const aiMesh* pMesh);
|
||||||
{
|
|
||||||
const float epsilon = 1e-4f;
|
|
||||||
|
|
||||||
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
|
||||||
aiVector3D minVec, maxVec;
|
|
||||||
ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec);
|
|
||||||
return (maxVec - minVec).Length() * epsilon;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Compute a good epsilon value for position comparisons on a array of meshes
|
// Compute a good epsilon value for position comparisons on a array of meshes
|
||||||
inline float ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num)
|
float ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num);
|
||||||
{
|
|
||||||
const float epsilon = 1e-4f;
|
|
||||||
|
|
||||||
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
|
||||||
aiVector3D minVec, maxVec, mi, ma;
|
|
||||||
MinMaxChooser<aiVector3D>()(minVec,maxVec);
|
|
||||||
|
|
||||||
for (size_t a = 0; a < num; ++a) {
|
|
||||||
const aiMesh* pMesh = pMeshes[a];
|
|
||||||
ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma);
|
|
||||||
|
|
||||||
minVec = std::min(minVec,mi);
|
|
||||||
maxVec = std::max(maxVec,ma);
|
|
||||||
}
|
|
||||||
return (maxVec - minVec).Length() * epsilon;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Compute an unique value for the vertex format of a mesh
|
// Compute an unique value for the vertex format of a mesh
|
||||||
inline unsigned int GetMeshVFormatUnique(aiMesh* pcMesh)
|
unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh);
|
||||||
{
|
|
||||||
ai_assert(NULL != pcMesh);
|
|
||||||
|
|
||||||
// FIX: the hash may never be 0. Otherwise a comparison against
|
|
||||||
// nullptr could be successful
|
|
||||||
unsigned int iRet = 1;
|
|
||||||
|
|
||||||
// normals
|
|
||||||
if (pcMesh->HasNormals())iRet |= 0x2;
|
|
||||||
// tangents and bitangents
|
|
||||||
if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4;
|
|
||||||
|
|
||||||
#ifdef BOOST_STATIC_ASSERT
|
|
||||||
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
|
|
||||||
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// texture coordinates
|
|
||||||
unsigned int p = 0;
|
|
||||||
while (pcMesh->HasTextureCoords(p))
|
|
||||||
{
|
|
||||||
iRet |= (0x100 << p);
|
|
||||||
if (3 == pcMesh->mNumUVComponents[p])
|
|
||||||
iRet |= (0x10000 << p);
|
|
||||||
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
// vertex colors
|
|
||||||
p = 0;
|
|
||||||
while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++);
|
|
||||||
return iRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// defs for ComputeVertexBoneWeightTable()
|
||||||
typedef std::pair <unsigned int,float> PerVertexWeight;
|
typedef std::pair <unsigned int,float> PerVertexWeight;
|
||||||
typedef std::vector <PerVertexWeight> VertexWeightTable;
|
typedef std::vector <PerVertexWeight> VertexWeightTable;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Compute a per-vertex bone weight table
|
// Compute a per-vertex bone weight table
|
||||||
// please .... delete result with operator delete[] ...
|
VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh);
|
||||||
inline VertexWeightTable* ComputeVertexBoneWeightTable(aiMesh* pMesh)
|
|
||||||
{
|
|
||||||
if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
|
|
||||||
for (unsigned int i = 0; i < pMesh->mNumBones;++i)
|
|
||||||
{
|
|
||||||
aiBone* bone = pMesh->mBones[i];
|
|
||||||
for (unsigned int a = 0; a < bone->mNumWeights;++a) {
|
|
||||||
const aiVertexWeight& weight = bone->mWeights[a];
|
|
||||||
avPerVertexWeights[weight.mVertexId].push_back(
|
|
||||||
std::pair<unsigned int,float>(i,weight.mWeight));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return avPerVertexWeights;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Get a string for a given aiTextureType
|
// Get a string for a given aiTextureType
|
||||||
inline const char* TextureTypeToString(aiTextureType in)
|
const char* TextureTypeToString(aiTextureType in);
|
||||||
{
|
|
||||||
switch (in)
|
|
||||||
{
|
|
||||||
case aiTextureType_NONE:
|
|
||||||
return "n/a";
|
|
||||||
case aiTextureType_DIFFUSE:
|
|
||||||
return "Diffuse";
|
|
||||||
case aiTextureType_SPECULAR:
|
|
||||||
return "Specular";
|
|
||||||
case aiTextureType_AMBIENT:
|
|
||||||
return "Ambient";
|
|
||||||
case aiTextureType_EMISSIVE:
|
|
||||||
return "Emissive";
|
|
||||||
case aiTextureType_OPACITY:
|
|
||||||
return "Opacity";
|
|
||||||
case aiTextureType_NORMALS:
|
|
||||||
return "Normals";
|
|
||||||
case aiTextureType_HEIGHT:
|
|
||||||
return "Height";
|
|
||||||
case aiTextureType_SHININESS:
|
|
||||||
return "Shininess";
|
|
||||||
case aiTextureType_DISPLACEMENT:
|
|
||||||
return "Displacement";
|
|
||||||
case aiTextureType_LIGHTMAP:
|
|
||||||
return "Lightmap";
|
|
||||||
case aiTextureType_REFLECTION:
|
|
||||||
return "Reflection";
|
|
||||||
case aiTextureType_UNKNOWN:
|
|
||||||
return "Unknown";
|
|
||||||
default:
|
|
||||||
return "HUGE ERROR. Expect BSOD (linux guys: kernel panic ...).";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Get a string for a given aiTextureMapping
|
// Get a string for a given aiTextureMapping
|
||||||
inline const char* MappingTypeToString(aiTextureMapping in)
|
const char* MappingTypeToString(aiTextureMapping in);
|
||||||
{
|
|
||||||
switch (in)
|
|
||||||
{
|
// flags for MakeSubmesh()
|
||||||
case aiTextureMapping_UV:
|
#define AI_SUBMESH_FLAGS_SANS_BONES 0x1
|
||||||
return "UV";
|
|
||||||
case aiTextureMapping_BOX:
|
// -------------------------------------------------------------------------------
|
||||||
return "Box";
|
// Split a mesh given a list of faces to be contained in the sub mesh
|
||||||
case aiTextureMapping_SPHERE:
|
aiMesh* MakeSubmesh(const aiMesh *superMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags);
|
||||||
return "Sphere";
|
|
||||||
case aiTextureMapping_CYLINDER:
|
|
||||||
return "Cylinder";
|
|
||||||
case aiTextureMapping_PLANE:
|
|
||||||
return "Plane";
|
|
||||||
case aiTextureMapping_OTHER:
|
|
||||||
return "Other";
|
|
||||||
default:
|
|
||||||
return "HUGE ERROR. Expect BSOD (linux guys: kernel panic ...).";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Utility postprocess step to share the spatial sort tree between
|
// Utility postprocess step to share the spatial sort tree between
|
||||||
|
@ -560,5 +388,7 @@ class DestroySpatialSortProcess : public BaseProcess
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // ! namespace Assimp
|
} // ! namespace Assimp
|
||||||
#endif // !! AI_PROCESS_HELPER_H_INCLUDED
|
#endif // !! AI_PROCESS_HELPER_H_INCLUDED
|
||||||
|
|
|
@ -288,6 +288,29 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
# define AI_LMW_MAX_WEIGHTS 0x4
|
# define AI_LMW_MAX_WEIGHTS 0x4
|
||||||
#endif // !! AI_LMW_MAX_WEIGHTS
|
#endif // !! AI_LMW_MAX_WEIGHTS
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @brief Set the deboning threshold higher to remove more bones
|
||||||
|
*
|
||||||
|
* This is used by the #aiProcess_Debone PostProcess-Step.
|
||||||
|
* @note The default value is AI_DEBONE_THRESHOLD
|
||||||
|
* Property type: float.*/
|
||||||
|
#define AI_CONFIG_PP_DB_THRESHOLD \
|
||||||
|
"PP_DB_THRESHOLD"
|
||||||
|
|
||||||
|
// default value for AI_CONFIG_PP_LBW_MAX_WEIGHTS
|
||||||
|
#if (!defined AI_DEBONE_THRESHOLD)
|
||||||
|
# define AI_DEBONE_THRESHOLD 1.0f
|
||||||
|
#endif // !! AI_DEBONE_THRESHOLD
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @brief Require all bones qualify for deboning before removing any
|
||||||
|
*
|
||||||
|
* This is used by the #aiProcess_Debone PostProcess-Step.
|
||||||
|
* @note The default value is 0
|
||||||
|
* Property type: bool.*/
|
||||||
|
#define AI_CONFIG_PP_DB_ALL_OR_NONE \
|
||||||
|
"PP_DB_ALL_OR_NONE"
|
||||||
|
|
||||||
/** @brief Default value for the #AI_CONFIG_PP_ICL_PTCACHE_SIZE property
|
/** @brief Default value for the #AI_CONFIG_PP_ICL_PTCACHE_SIZE property
|
||||||
*/
|
*/
|
||||||
#ifndef PP_ICL_PTCACHE_SIZE
|
#ifndef PP_ICL_PTCACHE_SIZE
|
||||||
|
|
|
@ -500,7 +500,21 @@ enum aiPostProcessSteps
|
||||||
/** <hr>This step splits meshes with many bones into submeshes so that each
|
/** <hr>This step splits meshes with many bones into submeshes so that each
|
||||||
* submesh has fewer or as many bones as a given limit.
|
* submesh has fewer or as many bones as a given limit.
|
||||||
*/
|
*/
|
||||||
aiProcess_SplitByBoneCount = 0x2000000
|
aiProcess_SplitByBoneCount = 0x2000000,
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
/** <hr>This step removes bones losslessly or according to some threshold.
|
||||||
|
* In some cases (i.e. format that require it) exporters are forced to
|
||||||
|
* assign dummy bone weights to otherwise static meshes assigned to
|
||||||
|
* animated meshes. Since full, weight-based skinning is expensive but
|
||||||
|
* animating nodes is extremely cheap, this step is offered to cleanup
|
||||||
|
* the data in that regard.
|
||||||
|
*
|
||||||
|
* Use <tt>#AI_CONFIG_PP_DB_THRESHOLD</tt> to control this.
|
||||||
|
* Use <tt>#AI_CONFIG_PP_DB_ALL_OR_NONE</tt> if you want bones removed if and
|
||||||
|
* only if all bones within the scene qualify for removal.
|
||||||
|
*/
|
||||||
|
aiProcess_Debone = 0x4000000
|
||||||
|
|
||||||
// aiProcess_GenEntityMeshes = 0x100000,
|
// aiProcess_GenEntityMeshes = 0x100000,
|
||||||
// aiProcess_OptimizeAnimations = 0x200000
|
// aiProcess_OptimizeAnimations = 0x200000
|
||||||
|
@ -600,6 +614,7 @@ enum aiPostProcessSteps
|
||||||
aiProcess_FindInstances | \
|
aiProcess_FindInstances | \
|
||||||
aiProcess_ValidateDataStructure | \
|
aiProcess_ValidateDataStructure | \
|
||||||
aiProcess_OptimizeMeshes | \
|
aiProcess_OptimizeMeshes | \
|
||||||
|
aiProcess_Debone | \
|
||||||
0 )
|
0 )
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue