Refactor: Expand tabs to 4 spaces

This commit is contained in:
Richard
2015-05-18 21:57:13 -06:00
parent a96a595a7a
commit 83de707587
324 changed files with 78951 additions and 78956 deletions

View File

@@ -57,514 +57,514 @@ using namespace Assimp;
TextureTransformStep::TextureTransformStep() :
configFlags()
{
// nothing to do here
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
TextureTransformStep::~TextureTransformStep()
{
// nothing to do here
// nothing to do here
}
// ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field.
bool TextureTransformStep::IsActive( unsigned int pFlags) const
{
return (pFlags & aiProcess_TransformUVCoords) != 0;
return (pFlags & aiProcess_TransformUVCoords) != 0;
}
// ------------------------------------------------------------------------------------------------
// Setup properties
void TextureTransformStep::SetupProperties(const Importer* pImp)
{
configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL);
configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL);
}
// ------------------------------------------------------------------------------------------------
void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
{
/* This function tries to simplify the input UV transformation.
* That's very important as it allows us to reduce the number
* of output UV channels. The oder in which the transformations
* are applied is - as always - scaling, rotation, translation.
*/
/* This function tries to simplify the input UV transformation.
* That's very important as it allows us to reduce the number
* of output UV channels. The oder in which the transformations
* are applied is - as always - scaling, rotation, translation.
*/
char szTemp[512];
int rounded = 0;
char szTemp[512];
int rounded = 0;
/* Optimize the rotation angle. That's slightly difficult as
* we have an inprecise floating-point number (when comparing
* UV transformations we'll take that into account by using
* an epsilon of 5 degrees). If there is a rotation value, we can't
* perform any further optimizations.
*/
if (info.mRotation)
{
float out = info.mRotation;
if ((rounded = (int)(info.mRotation / (float)AI_MATH_TWO_PI)))
{
out -= rounded*(float)AI_MATH_PI;
/* Optimize the rotation angle. That's slightly difficult as
* we have an inprecise floating-point number (when comparing
* UV transformations we'll take that into account by using
* an epsilon of 5 degrees). If there is a rotation value, we can't
* perform any further optimizations.
*/
if (info.mRotation)
{
float out = info.mRotation;
if ((rounded = (int)(info.mRotation / (float)AI_MATH_TWO_PI)))
{
out -= rounded*(float)AI_MATH_PI;
sprintf(szTemp,"Texture coordinate rotation %f can be simplified to %f",info.mRotation,out);
DefaultLogger::get()->info(szTemp);
}
sprintf(szTemp,"Texture coordinate rotation %f can be simplified to %f",info.mRotation,out);
DefaultLogger::get()->info(szTemp);
}
// Next step - convert negative rotation angles to positives
if (out < 0.f)
out = (float)AI_MATH_TWO_PI * 2 + out;
// Next step - convert negative rotation angles to positives
if (out < 0.f)
out = (float)AI_MATH_TWO_PI * 2 + out;
info.mRotation = out;
return;
}
info.mRotation = out;
return;
}
/* Optimize UV translation in the U direction. To determine whether
* or not we can optimize we need to look at the requested mapping
* type (e.g. if mirroring is active there IS a difference between
* offset 2 and 3)
*/
if ((rounded = (int)info.mTranslation.x)) {
float out = 0.0f;
szTemp[0] = 0;
if (aiTextureMapMode_Wrap == info.mapU) {
// Wrap - simple take the fraction of the field
out = info.mTranslation.x-(float)rounded;
sprintf(szTemp,"[w] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
}
else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded) {
// Mirror
if (rounded % 2)
rounded--;
out = info.mTranslation.x-(float)rounded;
/* Optimize UV translation in the U direction. To determine whether
* or not we can optimize we need to look at the requested mapping
* type (e.g. if mirroring is active there IS a difference between
* offset 2 and 3)
*/
if ((rounded = (int)info.mTranslation.x)) {
float out = 0.0f;
szTemp[0] = 0;
if (aiTextureMapMode_Wrap == info.mapU) {
// Wrap - simple take the fraction of the field
out = info.mTranslation.x-(float)rounded;
sprintf(szTemp,"[w] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
}
else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded) {
// Mirror
if (rounded % 2)
rounded--;
out = info.mTranslation.x-(float)rounded;
sprintf(szTemp,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
}
else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU) {
// Clamp - translations beyond 1,1 are senseless
sprintf(szTemp,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x);
sprintf(szTemp,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out);
}
else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU) {
// Clamp - translations beyond 1,1 are senseless
sprintf(szTemp,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x);
out = 1.f;
}
if (szTemp[0]) {
DefaultLogger::get()->info(szTemp);
info.mTranslation.x = out;
}
}
out = 1.f;
}
if (szTemp[0]) {
DefaultLogger::get()->info(szTemp);
info.mTranslation.x = out;
}
}
/* Optimize UV translation in the V direction. To determine whether
* or not we can optimize we need to look at the requested mapping
* type (e.g. if mirroring is active there IS a difference between
* offset 2 and 3)
*/
if ((rounded = (int)info.mTranslation.y)) {
float out = 0.0f;
szTemp[0] = 0;
if (aiTextureMapMode_Wrap == info.mapV) {
// Wrap - simple take the fraction of the field
out = info.mTranslation.y-(float)rounded;
sprintf(szTemp,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
}
else if (aiTextureMapMode_Mirror == info.mapV && 1 != rounded) {
// Mirror
if (rounded % 2)
rounded--;
out = info.mTranslation.x-(float)rounded;
/* Optimize UV translation in the V direction. To determine whether
* or not we can optimize we need to look at the requested mapping
* type (e.g. if mirroring is active there IS a difference between
* offset 2 and 3)
*/
if ((rounded = (int)info.mTranslation.y)) {
float out = 0.0f;
szTemp[0] = 0;
if (aiTextureMapMode_Wrap == info.mapV) {
// Wrap - simple take the fraction of the field
out = info.mTranslation.y-(float)rounded;
sprintf(szTemp,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
}
else if (aiTextureMapMode_Mirror == info.mapV && 1 != rounded) {
// Mirror
if (rounded % 2)
rounded--;
out = info.mTranslation.x-(float)rounded;
sprintf(szTemp,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
}
else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) {
// Clamp - translations beyond 1,1 are senseless
sprintf(szTemp,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y);
sprintf(szTemp,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out);
}
else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) {
// Clamp - translations beyond 1,1 are senseless
sprintf(szTemp,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y);
out = 1.f;
}
if (szTemp[0]) {
DefaultLogger::get()->info(szTemp);
info.mTranslation.y = out;
}
}
return;
out = 1.f;
}
if (szTemp[0]) {
DefaultLogger::get()->info(szTemp);
info.mTranslation.y = out;
}
}
return;
}
// ------------------------------------------------------------------------------------------------
void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n)
{
// Don't set if == 0 && wasn't set before
for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) {
const TTUpdateInfo& info = *it;
// Don't set if == 0 && wasn't set before
for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) {
const TTUpdateInfo& info = *it;
if (info.directShortcut)
*info.directShortcut = n;
else if (!n)
{
info.mat->AddProperty<int>((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index));
}
}
if (info.directShortcut)
*info.directShortcut = n;
else if (!n)
{
info.mat->AddProperty<int>((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index));
}
}
}
// ------------------------------------------------------------------------------------------------
inline const char* MappingModeToChar(aiTextureMapMode map)
{
if (aiTextureMapMode_Wrap == map)
return "-w";
if (aiTextureMapMode_Wrap == map)
return "-w";
if (aiTextureMapMode_Mirror == map)
return "-m";
if (aiTextureMapMode_Mirror == map)
return "-m";
return "-c";
return "-c";
}
// ------------------------------------------------------------------------------------------------
void TextureTransformStep::Execute( aiScene* pScene)
{
DefaultLogger::get()->debug("TransformUVCoordsProcess begin");
/* We build a per-mesh list of texture transformations we'll need
* to apply. To achieve this, we iterate through all materials,
* find all textures and get their transformations and UV indices.
* Then we search for all meshes using this material.
*/
typedef std::list<STransformVecInfo> MeshTrafoList;
std::vector<MeshTrafoList> meshLists(pScene->mNumMeshes);
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
aiMaterial* mat = pScene->mMaterials[i];
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
aiMaterialProperty* prop = mat->mProperties[a];
if (!::strcmp( prop->mKey.data, "$tex.file")) {
STransformVecInfo info;
// Setup a shortcut structure to allow for a fast updating
// of the UV index later
TTUpdateInfo update;
update.mat = (aiMaterial*) mat;
update.semantic = prop->mSemantic;
update.index = prop->mIndex;
// Get textured properties and transform
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) {
aiMaterialProperty* prop2 = mat->mProperties[a2];
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) {
continue;
}
if ( !::strcmp( prop2->mKey.data, "$tex.uvwsrc")) {
info.uvIndex = *((int*)prop2->mData);
// Store a direct pointer for later use
update.directShortcut = (unsigned int*) prop2->mData;
}
else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu")) {
info.mapU = *((aiTextureMapMode*)prop2->mData);
}
else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev")) {
info.mapV = *((aiTextureMapMode*)prop2->mData);
}
else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo")) {
// ValidateDS should check this
ai_assert(prop2->mDataLength >= 20);
::memcpy(&info.mTranslation.x,prop2->mData,sizeof(float)*5);
// Directly remove this property from the list
mat->mNumProperties--;
for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3) {
mat->mProperties[a3] = mat->mProperties[a3+1];
}
delete prop2;
// Warn: could be an underflow, but this does not invoke undefined behaviour
--a2;
}
}
// Find out which transformations are to be evaluated
if (!(configFlags & AI_UVTRAFO_ROTATION)) {
info.mRotation = 0.f;
}
if (!(configFlags & AI_UVTRAFO_SCALING)) {
info.mScaling = aiVector2D(1.f,1.f);
}
if (!(configFlags & AI_UVTRAFO_TRANSLATION)) {
info.mTranslation = aiVector2D(0.f,0.f);
}
// Do some preprocessing
PreProcessUVTransform(info);
info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u);
// Find out whether this material is used by more than
// one mesh. This will make our task much, much more difficult!
unsigned int cnt = 0;
for (unsigned int n = 0; n < pScene->mNumMeshes;++n) {
if (pScene->mMeshes[n]->mMaterialIndex == i)
++cnt;
}
if (!cnt)
continue;
else if (1 != cnt) {
// This material is referenced by more than one mesh!
// So we need to make sure the UV index for the texture
// is identical for each of it ...
info.lockedPos = AI_TT_UV_IDX_LOCK_TBD;
}
// Get all coresponding meshes
for (unsigned int n = 0; n < pScene->mNumMeshes;++n) {
aiMesh* mesh = pScene->mMeshes[n];
if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0])
continue;
unsigned int uv = info.uvIndex;
if (!mesh->mTextureCoords[uv]) {
// If the requested UV index is not available, take the first one instead.
uv = 0;
}
if (mesh->mNumUVComponents[info.uvIndex] >= 3){
DefaultLogger::get()->warn("UV transformations on 3D mapping channels are not supported");
continue;
}
MeshTrafoList::iterator it;
// Check whether we have this transform setup already
for (it = meshLists[n].begin();it != meshLists[n].end(); ++it) {
if ((*it) == info && (*it).uvIndex == uv) {
(*it).updateList.push_back(update);
break;
}
}
if (it == meshLists[n].end()) {
meshLists[n].push_back(info);
meshLists[n].back().uvIndex = uv;
meshLists[n].back().updateList.push_back(update);
}
}
}
}
}
char buffer[1024]; // should be sufficiently large
unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0;
// Now process all meshes. Important: we don't remove unreferenced UV channels.
// This is a job for the RemoveUnreferencedData-Step.
for (unsigned int q = 0; q < pScene->mNumMeshes;++q) {
aiMesh* mesh = pScene->mMeshes[q];
MeshTrafoList& trafo = meshLists[q];
inChannels += mesh->GetNumUVChannels();
if (!mesh->mTextureCoords[0] || trafo.empty() || (trafo.size() == 1 && trafo.begin()->IsUntransformed())) {
outChannels += mesh->GetNumUVChannels();
continue;
}
// Move untransformed UV channels to the first position in the list ....
// except if we need a new locked index which should be as small as possible
bool veto = false, need = false;
unsigned int cnt = 0;
unsigned int untransformed = 0;
MeshTrafoList::iterator it,it2;
for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
if (!(*it).IsUntransformed()) {
need = true;
}
if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD) {
// Lock this index and make sure it won't be changed
(*it).lockedPos = cnt;
veto = true;
continue;
}
if (!veto && it != trafo.begin() && (*it).IsUntransformed()) {
for (it2 = trafo.begin();it2 != it; ++it2) {
if (!(*it2).IsUntransformed())
break;
}
trafo.insert(it2,*it);
trafo.erase(it);
break;
}
}
if (!need)
continue;
// Find all that are not at their 'locked' position and move them to it.
// Conflicts are possible but quite unlikely.
cnt = 0;
for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) {
it2 = trafo.begin();unsigned int t = 0;
while (t != (*it).lockedPos)
++it2;
if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) {
DefaultLogger::get()->error("Channel mismatch, can't compute all transformations properly [design bug]");
continue;
}
std::swap(*it2,*it);
if ((*it).lockedPos == untransformed)
untransformed = cnt;
}
}
// ... and add dummies for all unreferenced channels
// at the end of the list
bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS];
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
ref[n] = (!mesh->mTextureCoords[n] ? true : false);
for (it = trafo.begin();it != trafo.end(); ++it)
ref[(*it).uvIndex] = true;
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
if (ref[n])
continue;
trafo.push_back(STransformVecInfo());
trafo.back().uvIndex = n;
}
// Then check whether this list breaks the channel limit.
// The unimportant ones are at the end of the list, so
// it shouldn't be too worse if we remove them.
unsigned int size = (unsigned int)trafo.size();
if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
if (!DefaultLogger::isNullLogger()) {
::sprintf(buffer,"%u UV channels required but just %u available",
static_cast<unsigned int>(trafo.size()),AI_MAX_NUMBER_OF_TEXTURECOORDS);
DefaultLogger::get()->error(buffer);
}
size = AI_MAX_NUMBER_OF_TEXTURECOORDS;
}
aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS];
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
old[n] = mesh->mTextureCoords[n];
// Now continue and generate the output channels. Channels
// that we're not going to need later can be overridden.
it = trafo.begin();
for (unsigned int n = 0; n < trafo.size();++n,++it) {
if (n >= size) {
// Try to use an untransformed channel for all channels we threw over board
UpdateUVIndex((*it).updateList,untransformed);
continue;
}
outChannels++;
// Write to the log
if (!DefaultLogger::isNullLogger()) {
sprintf(buffer,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s",
q,n,
(*it).mTranslation.x,
(*it).mTranslation.y,
(*it).mScaling.x,
(*it).mScaling.y,
AI_RAD_TO_DEG( (*it).mRotation),
MappingModeToChar ((*it).mapU),
MappingModeToChar ((*it).mapV));
DefaultLogger::get()->info(buffer);
}
// Check whether we need a new buffer here
if (mesh->mTextureCoords[n]) {
it2 = it;++it2;
for (unsigned int m = n+1; m < size;++m, ++it2) {
if ((*it2).uvIndex == n){
it2 = trafo.begin();
break;
}
}
if (it2 == trafo.begin()){
mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
}
}
else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
aiVector3D* src = old[(*it).uvIndex];
aiVector3D* dest, *end;
dest = mesh->mTextureCoords[n];
ai_assert(NULL != src);
// Copy the data to the destination array
if (dest != src)
::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
end = dest + mesh->mNumVertices;
// Build a transformation matrix and transform all UV coords with it
if (!(*it).IsUntransformed()) {
const aiVector2D& trl = (*it).mTranslation;
const aiVector2D& scl = (*it).mScaling;
// fixme: simplify ..
++transformedChannels;
aiMatrix3x3 matrix;
aiMatrix3x3 m2,m3,m4,m5;
m4.a1 = scl.x;
m4.b2 = scl.y;
m2.a3 = m2.b3 = 0.5f;
m3.a3 = m3.b3 = -0.5f;
if ((*it).mRotation > AI_TT_ROTATION_EPSILON )
aiMatrix3x3::RotationZ((*it).mRotation,matrix);
m5.a3 += trl.x; m5.b3 += trl.y;
matrix = m2 * m4 * matrix * m3 * m5;
for (src = dest; src != end; ++src) { /* manual homogenious divide */
src->z = 1.f;
*src = matrix * *src;
src->x /= src->z;
src->y /= src->z;
src->z = 0.f;
}
}
// Update all UV indices
UpdateUVIndex((*it).updateList,n);
}
}
// Print some detailled statistics into the log
if (!DefaultLogger::isNullLogger()) {
if (transformedChannels) {
::sprintf(buffer,"TransformUVCoordsProcess end: %u output channels (in: %u, modified: %u)",
outChannels,inChannels,transformedChannels);
DefaultLogger::get()->info(buffer);
}
else DefaultLogger::get()->debug("TransformUVCoordsProcess finished");
}
DefaultLogger::get()->debug("TransformUVCoordsProcess begin");
/* We build a per-mesh list of texture transformations we'll need
* to apply. To achieve this, we iterate through all materials,
* find all textures and get their transformations and UV indices.
* Then we search for all meshes using this material.
*/
typedef std::list<STransformVecInfo> MeshTrafoList;
std::vector<MeshTrafoList> meshLists(pScene->mNumMeshes);
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
aiMaterial* mat = pScene->mMaterials[i];
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
aiMaterialProperty* prop = mat->mProperties[a];
if (!::strcmp( prop->mKey.data, "$tex.file")) {
STransformVecInfo info;
// Setup a shortcut structure to allow for a fast updating
// of the UV index later
TTUpdateInfo update;
update.mat = (aiMaterial*) mat;
update.semantic = prop->mSemantic;
update.index = prop->mIndex;
// Get textured properties and transform
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) {
aiMaterialProperty* prop2 = mat->mProperties[a2];
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) {
continue;
}
if ( !::strcmp( prop2->mKey.data, "$tex.uvwsrc")) {
info.uvIndex = *((int*)prop2->mData);
// Store a direct pointer for later use
update.directShortcut = (unsigned int*) prop2->mData;
}
else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu")) {
info.mapU = *((aiTextureMapMode*)prop2->mData);
}
else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev")) {
info.mapV = *((aiTextureMapMode*)prop2->mData);
}
else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo")) {
// ValidateDS should check this
ai_assert(prop2->mDataLength >= 20);
::memcpy(&info.mTranslation.x,prop2->mData,sizeof(float)*5);
// Directly remove this property from the list
mat->mNumProperties--;
for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3) {
mat->mProperties[a3] = mat->mProperties[a3+1];
}
delete prop2;
// Warn: could be an underflow, but this does not invoke undefined behaviour
--a2;
}
}
// Find out which transformations are to be evaluated
if (!(configFlags & AI_UVTRAFO_ROTATION)) {
info.mRotation = 0.f;
}
if (!(configFlags & AI_UVTRAFO_SCALING)) {
info.mScaling = aiVector2D(1.f,1.f);
}
if (!(configFlags & AI_UVTRAFO_TRANSLATION)) {
info.mTranslation = aiVector2D(0.f,0.f);
}
// Do some preprocessing
PreProcessUVTransform(info);
info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u);
// Find out whether this material is used by more than
// one mesh. This will make our task much, much more difficult!
unsigned int cnt = 0;
for (unsigned int n = 0; n < pScene->mNumMeshes;++n) {
if (pScene->mMeshes[n]->mMaterialIndex == i)
++cnt;
}
if (!cnt)
continue;
else if (1 != cnt) {
// This material is referenced by more than one mesh!
// So we need to make sure the UV index for the texture
// is identical for each of it ...
info.lockedPos = AI_TT_UV_IDX_LOCK_TBD;
}
// Get all coresponding meshes
for (unsigned int n = 0; n < pScene->mNumMeshes;++n) {
aiMesh* mesh = pScene->mMeshes[n];
if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0])
continue;
unsigned int uv = info.uvIndex;
if (!mesh->mTextureCoords[uv]) {
// If the requested UV index is not available, take the first one instead.
uv = 0;
}
if (mesh->mNumUVComponents[info.uvIndex] >= 3){
DefaultLogger::get()->warn("UV transformations on 3D mapping channels are not supported");
continue;
}
MeshTrafoList::iterator it;
// Check whether we have this transform setup already
for (it = meshLists[n].begin();it != meshLists[n].end(); ++it) {
if ((*it) == info && (*it).uvIndex == uv) {
(*it).updateList.push_back(update);
break;
}
}
if (it == meshLists[n].end()) {
meshLists[n].push_back(info);
meshLists[n].back().uvIndex = uv;
meshLists[n].back().updateList.push_back(update);
}
}
}
}
}
char buffer[1024]; // should be sufficiently large
unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0;
// Now process all meshes. Important: we don't remove unreferenced UV channels.
// This is a job for the RemoveUnreferencedData-Step.
for (unsigned int q = 0; q < pScene->mNumMeshes;++q) {
aiMesh* mesh = pScene->mMeshes[q];
MeshTrafoList& trafo = meshLists[q];
inChannels += mesh->GetNumUVChannels();
if (!mesh->mTextureCoords[0] || trafo.empty() || (trafo.size() == 1 && trafo.begin()->IsUntransformed())) {
outChannels += mesh->GetNumUVChannels();
continue;
}
// Move untransformed UV channels to the first position in the list ....
// except if we need a new locked index which should be as small as possible
bool veto = false, need = false;
unsigned int cnt = 0;
unsigned int untransformed = 0;
MeshTrafoList::iterator it,it2;
for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
if (!(*it).IsUntransformed()) {
need = true;
}
if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD) {
// Lock this index and make sure it won't be changed
(*it).lockedPos = cnt;
veto = true;
continue;
}
if (!veto && it != trafo.begin() && (*it).IsUntransformed()) {
for (it2 = trafo.begin();it2 != it; ++it2) {
if (!(*it2).IsUntransformed())
break;
}
trafo.insert(it2,*it);
trafo.erase(it);
break;
}
}
if (!need)
continue;
// Find all that are not at their 'locked' position and move them to it.
// Conflicts are possible but quite unlikely.
cnt = 0;
for (it = trafo.begin();it != trafo.end(); ++it,++cnt) {
if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) {
it2 = trafo.begin();unsigned int t = 0;
while (t != (*it).lockedPos)
++it2;
if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) {
DefaultLogger::get()->error("Channel mismatch, can't compute all transformations properly [design bug]");
continue;
}
std::swap(*it2,*it);
if ((*it).lockedPos == untransformed)
untransformed = cnt;
}
}
// ... and add dummies for all unreferenced channels
// at the end of the list
bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS];
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
ref[n] = (!mesh->mTextureCoords[n] ? true : false);
for (it = trafo.begin();it != trafo.end(); ++it)
ref[(*it).uvIndex] = true;
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
if (ref[n])
continue;
trafo.push_back(STransformVecInfo());
trafo.back().uvIndex = n;
}
// Then check whether this list breaks the channel limit.
// The unimportant ones are at the end of the list, so
// it shouldn't be too worse if we remove them.
unsigned int size = (unsigned int)trafo.size();
if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
if (!DefaultLogger::isNullLogger()) {
::sprintf(buffer,"%u UV channels required but just %u available",
static_cast<unsigned int>(trafo.size()),AI_MAX_NUMBER_OF_TEXTURECOORDS);
DefaultLogger::get()->error(buffer);
}
size = AI_MAX_NUMBER_OF_TEXTURECOORDS;
}
aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS];
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
old[n] = mesh->mTextureCoords[n];
// Now continue and generate the output channels. Channels
// that we're not going to need later can be overridden.
it = trafo.begin();
for (unsigned int n = 0; n < trafo.size();++n,++it) {
if (n >= size) {
// Try to use an untransformed channel for all channels we threw over board
UpdateUVIndex((*it).updateList,untransformed);
continue;
}
outChannels++;
// Write to the log
if (!DefaultLogger::isNullLogger()) {
sprintf(buffer,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s",
q,n,
(*it).mTranslation.x,
(*it).mTranslation.y,
(*it).mScaling.x,
(*it).mScaling.y,
AI_RAD_TO_DEG( (*it).mRotation),
MappingModeToChar ((*it).mapU),
MappingModeToChar ((*it).mapV));
DefaultLogger::get()->info(buffer);
}
// Check whether we need a new buffer here
if (mesh->mTextureCoords[n]) {
it2 = it;++it2;
for (unsigned int m = n+1; m < size;++m, ++it2) {
if ((*it2).uvIndex == n){
it2 = trafo.begin();
break;
}
}
if (it2 == trafo.begin()){
mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
}
}
else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
aiVector3D* src = old[(*it).uvIndex];
aiVector3D* dest, *end;
dest = mesh->mTextureCoords[n];
ai_assert(NULL != src);
// Copy the data to the destination array
if (dest != src)
::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
end = dest + mesh->mNumVertices;
// Build a transformation matrix and transform all UV coords with it
if (!(*it).IsUntransformed()) {
const aiVector2D& trl = (*it).mTranslation;
const aiVector2D& scl = (*it).mScaling;
// fixme: simplify ..
++transformedChannels;
aiMatrix3x3 matrix;
aiMatrix3x3 m2,m3,m4,m5;
m4.a1 = scl.x;
m4.b2 = scl.y;
m2.a3 = m2.b3 = 0.5f;
m3.a3 = m3.b3 = -0.5f;
if ((*it).mRotation > AI_TT_ROTATION_EPSILON )
aiMatrix3x3::RotationZ((*it).mRotation,matrix);
m5.a3 += trl.x; m5.b3 += trl.y;
matrix = m2 * m4 * matrix * m3 * m5;
for (src = dest; src != end; ++src) { /* manual homogenious divide */
src->z = 1.f;
*src = matrix * *src;
src->x /= src->z;
src->y /= src->z;
src->z = 0.f;
}
}
// Update all UV indices
UpdateUVIndex((*it).updateList,n);
}
}
// Print some detailled statistics into the log
if (!DefaultLogger::isNullLogger()) {
if (transformedChannels) {
::sprintf(buffer,"TransformUVCoordsProcess end: %u output channels (in: %u, modified: %u)",
outChannels,inChannels,transformedChannels);
DefaultLogger::get()->info(buffer);
}
else DefaultLogger::get()->debug("TransformUVCoordsProcess finished");
}
}