vrshoot

annotate libs/assimp/ValidateDataStructure.cpp @ 1:e7ca128b8713

looks nice :)
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Feb 2014 00:35:22 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file ValidateDataStructure.cpp
nuclear@0 43 * @brief Implementation of the post processing step to validate
nuclear@0 44 * the data structure returned by Assimp.
nuclear@0 45 */
nuclear@0 46
nuclear@0 47 #include "AssimpPCH.h"
nuclear@0 48
nuclear@0 49 // internal headers
nuclear@0 50 #include "ValidateDataStructure.h"
nuclear@0 51 #include "BaseImporter.h"
nuclear@0 52 #include "fast_atof.h"
nuclear@0 53 #include "ProcessHelper.h"
nuclear@0 54
nuclear@0 55 // CRT headers
nuclear@0 56 #include <stdarg.h>
nuclear@0 57
nuclear@0 58 using namespace Assimp;
nuclear@0 59
nuclear@0 60 // ------------------------------------------------------------------------------------------------
nuclear@0 61 // Constructor to be privately used by Importer
nuclear@0 62 ValidateDSProcess::ValidateDSProcess()
nuclear@0 63 {}
nuclear@0 64
nuclear@0 65 // ------------------------------------------------------------------------------------------------
nuclear@0 66 // Destructor, private as well
nuclear@0 67 ValidateDSProcess::~ValidateDSProcess()
nuclear@0 68 {}
nuclear@0 69
nuclear@0 70 // ------------------------------------------------------------------------------------------------
nuclear@0 71 // Returns whether the processing step is present in the given flag field.
nuclear@0 72 bool ValidateDSProcess::IsActive( unsigned int pFlags) const
nuclear@0 73 {
nuclear@0 74 return (pFlags & aiProcess_ValidateDataStructure) != 0;
nuclear@0 75 }
nuclear@0 76 // ------------------------------------------------------------------------------------------------
nuclear@0 77 AI_WONT_RETURN void ValidateDSProcess::ReportError(const char* msg,...)
nuclear@0 78 {
nuclear@0 79 ai_assert(NULL != msg);
nuclear@0 80
nuclear@0 81 va_list args;
nuclear@0 82 va_start(args,msg);
nuclear@0 83
nuclear@0 84 char szBuffer[3000];
nuclear@0 85 const int iLen = vsprintf(szBuffer,msg,args);
nuclear@0 86 ai_assert(iLen > 0);
nuclear@0 87
nuclear@0 88 va_end(args);
nuclear@0 89 #ifdef _DEBUG
nuclear@0 90 ai_assert( false );
nuclear@0 91 #endif
nuclear@0 92 throw DeadlyImportError("Validation failed: " + std::string(szBuffer,iLen));
nuclear@0 93 }
nuclear@0 94 // ------------------------------------------------------------------------------------------------
nuclear@0 95 void ValidateDSProcess::ReportWarning(const char* msg,...)
nuclear@0 96 {
nuclear@0 97 ai_assert(NULL != msg);
nuclear@0 98
nuclear@0 99 va_list args;
nuclear@0 100 va_start(args,msg);
nuclear@0 101
nuclear@0 102 char szBuffer[3000];
nuclear@0 103 const int iLen = vsprintf(szBuffer,msg,args);
nuclear@0 104 ai_assert(iLen > 0);
nuclear@0 105
nuclear@0 106 va_end(args);
nuclear@0 107 DefaultLogger::get()->warn("Validation warning: " + std::string(szBuffer,iLen));
nuclear@0 108 }
nuclear@0 109
nuclear@0 110 // ------------------------------------------------------------------------------------------------
nuclear@0 111 inline int HasNameMatch(const aiString& in, aiNode* node)
nuclear@0 112 {
nuclear@0 113 int result = (node->mName == in ? 1 : 0 );
nuclear@0 114 for (unsigned int i = 0; i < node->mNumChildren;++i) {
nuclear@0 115 result += HasNameMatch(in,node->mChildren[i]);
nuclear@0 116 }
nuclear@0 117 return result;
nuclear@0 118 }
nuclear@0 119
nuclear@0 120 // ------------------------------------------------------------------------------------------------
nuclear@0 121 template <typename T>
nuclear@0 122 inline void ValidateDSProcess::DoValidation(T** parray, unsigned int size,
nuclear@0 123 const char* firstName, const char* secondName)
nuclear@0 124 {
nuclear@0 125 // validate all entries
nuclear@0 126 if (size)
nuclear@0 127 {
nuclear@0 128 if (!parray)
nuclear@0 129 {
nuclear@0 130 ReportError("aiScene::%s is NULL (aiScene::%s is %i)",
nuclear@0 131 firstName, secondName, size);
nuclear@0 132 }
nuclear@0 133 for (unsigned int i = 0; i < size;++i)
nuclear@0 134 {
nuclear@0 135 if (!parray[i])
nuclear@0 136 {
nuclear@0 137 ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)",
nuclear@0 138 firstName,i,secondName,size);
nuclear@0 139 }
nuclear@0 140 Validate(parray[i]);
nuclear@0 141 }
nuclear@0 142 }
nuclear@0 143 }
nuclear@0 144
nuclear@0 145 // ------------------------------------------------------------------------------------------------
nuclear@0 146 template <typename T>
nuclear@0 147 inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size,
nuclear@0 148 const char* firstName, const char* secondName)
nuclear@0 149 {
nuclear@0 150 // validate all entries
nuclear@0 151 if (size)
nuclear@0 152 {
nuclear@0 153 if (!parray) {
nuclear@0 154 ReportError("aiScene::%s is NULL (aiScene::%s is %i)",
nuclear@0 155 firstName, secondName, size);
nuclear@0 156 }
nuclear@0 157 for (unsigned int i = 0; i < size;++i)
nuclear@0 158 {
nuclear@0 159 if (!parray[i])
nuclear@0 160 {
nuclear@0 161 ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)",
nuclear@0 162 firstName,i,secondName,size);
nuclear@0 163 }
nuclear@0 164 Validate(parray[i]);
nuclear@0 165
nuclear@0 166 // check whether there are duplicate names
nuclear@0 167 for (unsigned int a = i+1; a < size;++a)
nuclear@0 168 {
nuclear@0 169 if (parray[i]->mName == parray[a]->mName)
nuclear@0 170 {
nuclear@0 171 this->ReportError("aiScene::%s[%i] has the same name as "
nuclear@0 172 "aiScene::%s[%i]",firstName, i,secondName, a);
nuclear@0 173 }
nuclear@0 174 }
nuclear@0 175 }
nuclear@0 176 }
nuclear@0 177 }
nuclear@0 178
nuclear@0 179 // ------------------------------------------------------------------------------------------------
nuclear@0 180 template <typename T>
nuclear@0 181 inline void ValidateDSProcess::DoValidationWithNameCheck(T** array,
nuclear@0 182 unsigned int size, const char* firstName,
nuclear@0 183 const char* secondName)
nuclear@0 184 {
nuclear@0 185 // validate all entries
nuclear@0 186 DoValidationEx(array,size,firstName,secondName);
nuclear@0 187
nuclear@0 188 for (unsigned int i = 0; i < size;++i)
nuclear@0 189 {
nuclear@0 190 int res = HasNameMatch(array[i]->mName,mScene->mRootNode);
nuclear@0 191 if (!res) {
nuclear@0 192 ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)",
nuclear@0 193 firstName,i,array[i]->mName.data);
nuclear@0 194 }
nuclear@0 195 else if (1 != res) {
nuclear@0 196 ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name",
nuclear@0 197 firstName,i,array[i]->mName.data);
nuclear@0 198 }
nuclear@0 199 }
nuclear@0 200 }
nuclear@0 201
nuclear@0 202 // ------------------------------------------------------------------------------------------------
nuclear@0 203 // Executes the post processing step on the given imported data.
nuclear@0 204 void ValidateDSProcess::Execute( aiScene* pScene)
nuclear@0 205 {
nuclear@0 206 this->mScene = pScene;
nuclear@0 207 DefaultLogger::get()->debug("ValidateDataStructureProcess begin");
nuclear@0 208
nuclear@0 209 // validate the node graph of the scene
nuclear@0 210 Validate(pScene->mRootNode);
nuclear@0 211
nuclear@0 212 // validate all meshes
nuclear@0 213 if (pScene->mNumMeshes) {
nuclear@0 214 DoValidation(pScene->mMeshes,pScene->mNumMeshes,"mMeshes","mNumMeshes");
nuclear@0 215 }
nuclear@0 216 else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
nuclear@0 217 ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
nuclear@0 218 }
nuclear@0 219 else if (pScene->mMeshes) {
nuclear@0 220 ReportError("aiScene::mMeshes is non-null although there are no meshes");
nuclear@0 221 }
nuclear@0 222
nuclear@0 223 // validate all animations
nuclear@0 224 if (pScene->mNumAnimations) {
nuclear@0 225 DoValidation(pScene->mAnimations,pScene->mNumAnimations,
nuclear@0 226 "mAnimations","mNumAnimations");
nuclear@0 227 }
nuclear@0 228 else if (pScene->mAnimations) {
nuclear@0 229 ReportError("aiScene::mAnimations is non-null although there are no animations");
nuclear@0 230 }
nuclear@0 231
nuclear@0 232 // validate all cameras
nuclear@0 233 if (pScene->mNumCameras) {
nuclear@0 234 DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras,
nuclear@0 235 "mCameras","mNumCameras");
nuclear@0 236 }
nuclear@0 237 else if (pScene->mCameras) {
nuclear@0 238 ReportError("aiScene::mCameras is non-null although there are no cameras");
nuclear@0 239 }
nuclear@0 240
nuclear@0 241 // validate all lights
nuclear@0 242 if (pScene->mNumLights) {
nuclear@0 243 DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights,
nuclear@0 244 "mLights","mNumLights");
nuclear@0 245 }
nuclear@0 246 else if (pScene->mLights) {
nuclear@0 247 ReportError("aiScene::mLights is non-null although there are no lights");
nuclear@0 248 }
nuclear@0 249
nuclear@0 250 // validate all textures
nuclear@0 251 if (pScene->mNumTextures) {
nuclear@0 252 DoValidation(pScene->mTextures,pScene->mNumTextures,
nuclear@0 253 "mTextures","mNumTextures");
nuclear@0 254 }
nuclear@0 255 else if (pScene->mTextures) {
nuclear@0 256 ReportError("aiScene::mTextures is non-null although there are no textures");
nuclear@0 257 }
nuclear@0 258
nuclear@0 259 // validate all materials
nuclear@0 260 if (pScene->mNumMaterials) {
nuclear@0 261 DoValidation(pScene->mMaterials,pScene->mNumMaterials,"mMaterials","mNumMaterials");
nuclear@0 262 }
nuclear@0 263 #if 0
nuclear@0 264 // NOTE: ScenePreprocessor generates a default material if none is there
nuclear@0 265 else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
nuclear@0 266 ReportError("aiScene::mNumMaterials is 0. At least one material must be there");
nuclear@0 267 }
nuclear@0 268 #endif
nuclear@0 269 else if (pScene->mMaterials) {
nuclear@0 270 ReportError("aiScene::mMaterials is non-null although there are no materials");
nuclear@0 271 }
nuclear@0 272
nuclear@0 273 // if (!has)ReportError("The aiScene data structure is empty");
nuclear@0 274 DefaultLogger::get()->debug("ValidateDataStructureProcess end");
nuclear@0 275 }
nuclear@0 276
nuclear@0 277 // ------------------------------------------------------------------------------------------------
nuclear@0 278 void ValidateDSProcess::Validate( const aiLight* pLight)
nuclear@0 279 {
nuclear@0 280 if (pLight->mType == aiLightSource_UNDEFINED)
nuclear@0 281 ReportWarning("aiLight::mType is aiLightSource_UNDEFINED");
nuclear@0 282
nuclear@0 283 if (!pLight->mAttenuationConstant &&
nuclear@0 284 !pLight->mAttenuationLinear &&
nuclear@0 285 !pLight->mAttenuationQuadratic) {
nuclear@0 286 ReportWarning("aiLight::mAttenuationXXX - all are zero");
nuclear@0 287 }
nuclear@0 288
nuclear@0 289 if (pLight->mAngleInnerCone > pLight->mAngleOuterCone)
nuclear@0 290 ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone");
nuclear@0 291
nuclear@0 292 if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack()
nuclear@0 293 && pLight->mColorSpecular.IsBlack())
nuclear@0 294 {
nuclear@0 295 ReportWarning("aiLight::mColorXXX - all are black and won't have any influence");
nuclear@0 296 }
nuclear@0 297 }
nuclear@0 298
nuclear@0 299 // ------------------------------------------------------------------------------------------------
nuclear@0 300 void ValidateDSProcess::Validate( const aiCamera* pCamera)
nuclear@0 301 {
nuclear@0 302 if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
nuclear@0 303 ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear");
nuclear@0 304
nuclear@0 305 // FIX: there are many 3ds files with invalid FOVs. No reason to
nuclear@0 306 // reject them at all ... a warning is appropriate.
nuclear@0 307 if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
nuclear@0 308 ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV",pCamera->mHorizontalFOV);
nuclear@0 309 }
nuclear@0 310
nuclear@0 311 // ------------------------------------------------------------------------------------------------
nuclear@0 312 void ValidateDSProcess::Validate( const aiMesh* pMesh)
nuclear@0 313 {
nuclear@0 314 // validate the material index of the mesh
nuclear@0 315 if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials)
nuclear@0 316 {
nuclear@0 317 ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
nuclear@0 318 pMesh->mMaterialIndex,mScene->mNumMaterials-1);
nuclear@0 319 }
nuclear@0 320
nuclear@0 321 Validate(&pMesh->mName);
nuclear@0 322
nuclear@0 323 for (unsigned int i = 0; i < pMesh->mNumFaces; ++i)
nuclear@0 324 {
nuclear@0 325 aiFace& face = pMesh->mFaces[i];
nuclear@0 326
nuclear@0 327 if (pMesh->mPrimitiveTypes)
nuclear@0 328 {
nuclear@0 329 switch (face.mNumIndices)
nuclear@0 330 {
nuclear@0 331 case 0:
nuclear@0 332 ReportError("aiMesh::mFaces[%i].mNumIndices is 0",i);
nuclear@0 333 case 1:
nuclear@0 334 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT))
nuclear@0 335 {
nuclear@0 336 ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimtiveTypes "
nuclear@0 337 "does not report the POINT flag",i);
nuclear@0 338 }
nuclear@0 339 break;
nuclear@0 340 case 2:
nuclear@0 341 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE))
nuclear@0 342 {
nuclear@0 343 ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimtiveTypes "
nuclear@0 344 "does not report the LINE flag",i);
nuclear@0 345 }
nuclear@0 346 break;
nuclear@0 347 case 3:
nuclear@0 348 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE))
nuclear@0 349 {
nuclear@0 350 ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimtiveTypes "
nuclear@0 351 "does not report the TRIANGLE flag",i);
nuclear@0 352 }
nuclear@0 353 break;
nuclear@0 354 default:
nuclear@0 355 if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON))
nuclear@0 356 {
nuclear@0 357 this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimtiveTypes "
nuclear@0 358 "does not report the POLYGON flag",i);
nuclear@0 359 }
nuclear@0 360 break;
nuclear@0 361 };
nuclear@0 362 }
nuclear@0 363
nuclear@0 364 if (!face.mIndices)
nuclear@0 365 ReportError("aiMesh::mFaces[%i].mIndices is NULL",i);
nuclear@0 366 }
nuclear@0 367
nuclear@0 368 // positions must always be there ...
nuclear@0 369 if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
nuclear@0 370 ReportError("The mesh contains no vertices");
nuclear@0 371 }
nuclear@0 372
nuclear@0 373 if (pMesh->mNumVertices > AI_MAX_VERTICES) {
nuclear@0 374 ReportError("Mesh has too many vertices: %u, but the limit is %u",pMesh->mNumVertices,AI_MAX_VERTICES);
nuclear@0 375 }
nuclear@0 376 if (pMesh->mNumFaces > AI_MAX_FACES) {
nuclear@0 377 ReportError("Mesh has too many faces: %u, but the limit is %u",pMesh->mNumFaces,AI_MAX_FACES);
nuclear@0 378 }
nuclear@0 379
nuclear@0 380 // if tangents are there there must also be bitangent vectors ...
nuclear@0 381 if ((pMesh->mTangents != NULL) != (pMesh->mBitangents != NULL)) {
nuclear@0 382 ReportError("If there are tangents, bitangent vectors must be present as well");
nuclear@0 383 }
nuclear@0 384
nuclear@0 385 // faces, too
nuclear@0 386 if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) {
nuclear@0 387 ReportError("Mesh contains no faces");
nuclear@0 388 }
nuclear@0 389
nuclear@0 390 // now check whether the face indexing layout is correct:
nuclear@0 391 // unique vertices, pseudo-indexed.
nuclear@0 392 std::vector<bool> abRefList;
nuclear@0 393 abRefList.resize(pMesh->mNumVertices,false);
nuclear@0 394 for (unsigned int i = 0; i < pMesh->mNumFaces;++i)
nuclear@0 395 {
nuclear@0 396 aiFace& face = pMesh->mFaces[i];
nuclear@0 397 if (face.mNumIndices > AI_MAX_FACE_INDICES) {
nuclear@0 398 ReportError("Face %u has too many faces: %u, but the limit is %u",i,face.mNumIndices,AI_MAX_FACE_INDICES);
nuclear@0 399 }
nuclear@0 400
nuclear@0 401 for (unsigned int a = 0; a < face.mNumIndices;++a)
nuclear@0 402 {
nuclear@0 403 if (face.mIndices[a] >= pMesh->mNumVertices) {
nuclear@0 404 ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a);
nuclear@0 405 }
nuclear@0 406 // the MSB flag is temporarily used by the extra verbose
nuclear@0 407 // mode to tell us that the JoinVerticesProcess might have
nuclear@0 408 // been executed already.
nuclear@0 409 if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && abRefList[face.mIndices[a]])
nuclear@0 410 {
nuclear@0 411 ReportError("aiMesh::mVertices[%i] is referenced twice - second "
nuclear@0 412 "time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
nuclear@0 413 }
nuclear@0 414 abRefList[face.mIndices[a]] = true;
nuclear@0 415 }
nuclear@0 416 }
nuclear@0 417
nuclear@0 418 // check whether there are vertices that aren't referenced by a face
nuclear@0 419 bool b = false;
nuclear@0 420 for (unsigned int i = 0; i < pMesh->mNumVertices;++i) {
nuclear@0 421 if (!abRefList[i])b = true;
nuclear@0 422 }
nuclear@0 423 abRefList.clear();
nuclear@0 424 if (b)ReportWarning("There are unreferenced vertices");
nuclear@0 425
nuclear@0 426 // texture channel 2 may not be set if channel 1 is zero ...
nuclear@0 427 {
nuclear@0 428 unsigned int i = 0;
nuclear@0 429 for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
nuclear@0 430 {
nuclear@0 431 if (!pMesh->HasTextureCoords(i))break;
nuclear@0 432 }
nuclear@0 433 for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
nuclear@0 434 if (pMesh->HasTextureCoords(i))
nuclear@0 435 {
nuclear@0 436 ReportError("Texture coordinate channel %i exists "
nuclear@0 437 "although the previous channel was NULL.",i);
nuclear@0 438 }
nuclear@0 439 }
nuclear@0 440 // the same for the vertex colors
nuclear@0 441 {
nuclear@0 442 unsigned int i = 0;
nuclear@0 443 for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
nuclear@0 444 {
nuclear@0 445 if (!pMesh->HasVertexColors(i))break;
nuclear@0 446 }
nuclear@0 447 for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i)
nuclear@0 448 if (pMesh->HasVertexColors(i))
nuclear@0 449 {
nuclear@0 450 ReportError("Vertex color channel %i is exists "
nuclear@0 451 "although the previous channel was NULL.",i);
nuclear@0 452 }
nuclear@0 453 }
nuclear@0 454
nuclear@0 455
nuclear@0 456 // now validate all bones
nuclear@0 457 if (pMesh->mNumBones)
nuclear@0 458 {
nuclear@0 459 if (!pMesh->mBones)
nuclear@0 460 {
nuclear@0 461 ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)",
nuclear@0 462 pMesh->mNumBones);
nuclear@0 463 }
nuclear@0 464 boost::scoped_array<float> afSum(NULL);
nuclear@0 465 if (pMesh->mNumVertices)
nuclear@0 466 {
nuclear@0 467 afSum.reset(new float[pMesh->mNumVertices]);
nuclear@0 468 for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
nuclear@0 469 afSum[i] = 0.0f;
nuclear@0 470 }
nuclear@0 471
nuclear@0 472 // check whether there are duplicate bone names
nuclear@0 473 for (unsigned int i = 0; i < pMesh->mNumBones;++i)
nuclear@0 474 {
nuclear@0 475 const aiBone* bone = pMesh->mBones[i];
nuclear@0 476 if (bone->mNumWeights > AI_MAX_BONE_WEIGHTS) {
nuclear@0 477 ReportError("Bone %u has too many weights: %u, but the limit is %u",i,bone->mNumWeights,AI_MAX_BONE_WEIGHTS);
nuclear@0 478 }
nuclear@0 479
nuclear@0 480 if (!pMesh->mBones[i])
nuclear@0 481 {
nuclear@0 482 ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)",
nuclear@0 483 i,pMesh->mNumBones);
nuclear@0 484 }
nuclear@0 485 Validate(pMesh,pMesh->mBones[i],afSum.get());
nuclear@0 486
nuclear@0 487 for (unsigned int a = i+1; a < pMesh->mNumBones;++a)
nuclear@0 488 {
nuclear@0 489 if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName)
nuclear@0 490 {
nuclear@0 491 ReportError("aiMesh::mBones[%i] has the same name as "
nuclear@0 492 "aiMesh::mBones[%i]",i,a);
nuclear@0 493 }
nuclear@0 494 }
nuclear@0 495 }
nuclear@0 496 // check whether all bone weights for a vertex sum to 1.0 ...
nuclear@0 497 for (unsigned int i = 0; i < pMesh->mNumVertices;++i)
nuclear@0 498 {
nuclear@0 499 if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) {
nuclear@0 500 ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]);
nuclear@0 501 }
nuclear@0 502 }
nuclear@0 503 }
nuclear@0 504 else if (pMesh->mBones)
nuclear@0 505 {
nuclear@0 506 ReportError("aiMesh::mBones is non-null although there are no bones");
nuclear@0 507 }
nuclear@0 508 }
nuclear@0 509
nuclear@0 510 // ------------------------------------------------------------------------------------------------
nuclear@0 511 void ValidateDSProcess::Validate( const aiMesh* pMesh,
nuclear@0 512 const aiBone* pBone,float* afSum)
nuclear@0 513 {
nuclear@0 514 this->Validate(&pBone->mName);
nuclear@0 515
nuclear@0 516 if (!pBone->mNumWeights) {
nuclear@0 517 ReportError("aiBone::mNumWeights is zero");
nuclear@0 518 }
nuclear@0 519
nuclear@0 520 // check whether all vertices affected by this bone are valid
nuclear@0 521 for (unsigned int i = 0; i < pBone->mNumWeights;++i)
nuclear@0 522 {
nuclear@0 523 if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) {
nuclear@0 524 ReportError("aiBone::mWeights[%i].mVertexId is out of range",i);
nuclear@0 525 }
nuclear@0 526 else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) {
nuclear@0 527 ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value",i);
nuclear@0 528 }
nuclear@0 529 afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight;
nuclear@0 530 }
nuclear@0 531 }
nuclear@0 532
nuclear@0 533 // ------------------------------------------------------------------------------------------------
nuclear@0 534 void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
nuclear@0 535 {
nuclear@0 536 Validate(&pAnimation->mName);
nuclear@0 537
nuclear@0 538 // validate all materials
nuclear@0 539 if (pAnimation->mNumChannels)
nuclear@0 540 {
nuclear@0 541 if (!pAnimation->mChannels) {
nuclear@0 542 ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)",
nuclear@0 543 pAnimation->mNumChannels);
nuclear@0 544 }
nuclear@0 545 for (unsigned int i = 0; i < pAnimation->mNumChannels;++i)
nuclear@0 546 {
nuclear@0 547 if (!pAnimation->mChannels[i])
nuclear@0 548 {
nuclear@0 549 ReportError("aiAnimation::mChannels[%i] is NULL (aiAnimation::mNumChannels is %i)",
nuclear@0 550 i, pAnimation->mNumChannels);
nuclear@0 551 }
nuclear@0 552 Validate(pAnimation, pAnimation->mChannels[i]);
nuclear@0 553 }
nuclear@0 554 }
nuclear@0 555 else ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there.");
nuclear@0 556
nuclear@0 557 // Animation duration is allowed to be zero in cases where the anim contains only a single key frame.
nuclear@0 558 // if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero");
nuclear@0 559 }
nuclear@0 560
nuclear@0 561 // ------------------------------------------------------------------------------------------------
nuclear@0 562 void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
nuclear@0 563 aiTextureType type)
nuclear@0 564 {
nuclear@0 565 const char* szType = TextureTypeToString(type);
nuclear@0 566
nuclear@0 567 // ****************************************************************************
nuclear@0 568 // Search all keys of the material ...
nuclear@0 569 // textures must be specified with ascending indices
nuclear@0 570 // (e.g. diffuse #2 may not be specified if diffuse #1 is not there ...)
nuclear@0 571 // ****************************************************************************
nuclear@0 572
nuclear@0 573 int iNumIndices = 0;
nuclear@0 574 int iIndex = -1;
nuclear@0 575 for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
nuclear@0 576 {
nuclear@0 577 aiMaterialProperty* prop = pMaterial->mProperties[i];
nuclear@0 578 if (!::strcmp(prop->mKey.data,"$tex.file") && prop->mSemantic == type) {
nuclear@0 579 iIndex = std::max(iIndex, (int) prop->mIndex);
nuclear@0 580 ++iNumIndices;
nuclear@0 581
nuclear@0 582 if (aiPTI_String != prop->mType)
nuclear@0 583 ReportError("Material property %s is expected to be a string",prop->mKey.data);
nuclear@0 584 }
nuclear@0 585 }
nuclear@0 586 if (iIndex +1 != iNumIndices) {
nuclear@0 587 ReportError("%s #%i is set, but there are only %i %s textures",
nuclear@0 588 szType,iIndex,iNumIndices,szType);
nuclear@0 589 }
nuclear@0 590 if (!iNumIndices)return;
nuclear@0 591 std::vector<aiTextureMapping> mappings(iNumIndices);
nuclear@0 592
nuclear@0 593 // Now check whether all UV indices are valid ...
nuclear@0 594 bool bNoSpecified = true;
nuclear@0 595 for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
nuclear@0 596 {
nuclear@0 597 aiMaterialProperty* prop = pMaterial->mProperties[i];
nuclear@0 598 if (prop->mSemantic != type)continue;
nuclear@0 599
nuclear@0 600 if ((int)prop->mIndex >= iNumIndices)
nuclear@0 601 {
nuclear@0 602 ReportError("Found texture property with index %i, although there "
nuclear@0 603 "are only %i textures of type %s",
nuclear@0 604 prop->mIndex, iNumIndices, szType);
nuclear@0 605 }
nuclear@0 606
nuclear@0 607 if (!::strcmp(prop->mKey.data,"$tex.mapping")) {
nuclear@0 608 if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping))
nuclear@0 609 {
nuclear@0 610 ReportError("Material property %s%i is expected to be an integer (size is %i)",
nuclear@0 611 prop->mKey.data,prop->mIndex,prop->mDataLength);
nuclear@0 612 }
nuclear@0 613 mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData);
nuclear@0 614 }
nuclear@0 615 else if (!::strcmp(prop->mKey.data,"$tex.uvtrafo")) {
nuclear@0 616 if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform))
nuclear@0 617 {
nuclear@0 618 ReportError("Material property %s%i is expected to be 5 floats large (size is %i)",
nuclear@0 619 prop->mKey.data,prop->mIndex, prop->mDataLength);
nuclear@0 620 }
nuclear@0 621 mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData);
nuclear@0 622 }
nuclear@0 623 else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) {
nuclear@0 624 if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)
nuclear@0 625 {
nuclear@0 626 ReportError("Material property %s%i is expected to be an integer (size is %i)",
nuclear@0 627 prop->mKey.data,prop->mIndex,prop->mDataLength);
nuclear@0 628 }
nuclear@0 629 bNoSpecified = false;
nuclear@0 630
nuclear@0 631 // Ignore UV indices for texture channels that are not there ...
nuclear@0 632
nuclear@0 633 // Get the value
nuclear@0 634 iIndex = *((unsigned int*)prop->mData);
nuclear@0 635
nuclear@0 636 // Check whether there is a mesh using this material
nuclear@0 637 // which has not enough UV channels ...
nuclear@0 638 for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
nuclear@0 639 {
nuclear@0 640 aiMesh* mesh = this->mScene->mMeshes[a];
nuclear@0 641 if(mesh->mMaterialIndex == (unsigned int)i)
nuclear@0 642 {
nuclear@0 643 int iChannels = 0;
nuclear@0 644 while (mesh->HasTextureCoords(iChannels))++iChannels;
nuclear@0 645 if (iIndex >= iChannels)
nuclear@0 646 {
nuclear@0 647 ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
nuclear@0 648 iIndex,prop->mKey.data,a,iChannels);
nuclear@0 649 }
nuclear@0 650 }
nuclear@0 651 }
nuclear@0 652 }
nuclear@0 653 }
nuclear@0 654 if (bNoSpecified)
nuclear@0 655 {
nuclear@0 656 // Assume that all textures are using the first UV channel
nuclear@0 657 for (unsigned int a = 0; a < mScene->mNumMeshes;++a)
nuclear@0 658 {
nuclear@0 659 aiMesh* mesh = mScene->mMeshes[a];
nuclear@0 660 if(mesh->mMaterialIndex == (unsigned int)iIndex && mappings[0] == aiTextureMapping_UV)
nuclear@0 661 {
nuclear@0 662 if (!mesh->mTextureCoords[0])
nuclear@0 663 {
nuclear@0 664 // This is a special case ... it could be that the
nuclear@0 665 // original mesh format intended the use of a special
nuclear@0 666 // mapping here.
nuclear@0 667 ReportWarning("UV-mapped texture, but there are no UV coords");
nuclear@0 668 }
nuclear@0 669 }
nuclear@0 670 }
nuclear@0 671 }
nuclear@0 672 }
nuclear@0 673 // ------------------------------------------------------------------------------------------------
nuclear@0 674 void ValidateDSProcess::Validate( const aiMaterial* pMaterial)
nuclear@0 675 {
nuclear@0 676 // check whether there are material keys that are obviously not legal
nuclear@0 677 for (unsigned int i = 0; i < pMaterial->mNumProperties;++i)
nuclear@0 678 {
nuclear@0 679 const aiMaterialProperty* prop = pMaterial->mProperties[i];
nuclear@0 680 if (!prop) {
nuclear@0 681 ReportError("aiMaterial::mProperties[%i] is NULL (aiMaterial::mNumProperties is %i)",
nuclear@0 682 i,pMaterial->mNumProperties);
nuclear@0 683 }
nuclear@0 684 if (!prop->mDataLength || !prop->mData) {
nuclear@0 685 ReportError("aiMaterial::mProperties[%i].mDataLength or "
nuclear@0 686 "aiMaterial::mProperties[%i].mData is 0",i,i);
nuclear@0 687 }
nuclear@0 688 // check all predefined types
nuclear@0 689 if (aiPTI_String == prop->mType) {
nuclear@0 690 // FIX: strings are now stored in a less expensive way, but we can't use the
nuclear@0 691 // validation routine for 'normal' aiStrings
nuclear@0 692 uint32_t len;
nuclear@0 693 if (prop->mDataLength < 5 || prop->mDataLength < 4 + (len=*reinterpret_cast<uint32_t*>(prop->mData)) + 1) {
nuclear@0 694 ReportError("aiMaterial::mProperties[%i].mDataLength is "
nuclear@0 695 "too small to contain a string (%i, needed: %i)",
nuclear@0 696 i,prop->mDataLength,sizeof(aiString));
nuclear@0 697 }
nuclear@0 698 if(prop->mData[prop->mDataLength-1]) {
nuclear@0 699 ReportError("Missing null-terminator in string material property");
nuclear@0 700 }
nuclear@0 701 // Validate((const aiString*)prop->mData);
nuclear@0 702 }
nuclear@0 703 else if (aiPTI_Float == prop->mType) {
nuclear@0 704 if (prop->mDataLength < sizeof(float)) {
nuclear@0 705 ReportError("aiMaterial::mProperties[%i].mDataLength is "
nuclear@0 706 "too small to contain a float (%i, needed: %i)",
nuclear@0 707 i,prop->mDataLength,sizeof(float));
nuclear@0 708 }
nuclear@0 709 }
nuclear@0 710 else if (aiPTI_Integer == prop->mType) {
nuclear@0 711 if (prop->mDataLength < sizeof(int)) {
nuclear@0 712 ReportError("aiMaterial::mProperties[%i].mDataLength is "
nuclear@0 713 "too small to contain an integer (%i, needed: %i)",
nuclear@0 714 i,prop->mDataLength,sizeof(int));
nuclear@0 715 }
nuclear@0 716 }
nuclear@0 717 // TODO: check whether there is a key with an unknown name ...
nuclear@0 718 }
nuclear@0 719
nuclear@0 720 // make some more specific tests
nuclear@0 721 float fTemp;
nuclear@0 722 int iShading;
nuclear@0 723 if (AI_SUCCESS == aiGetMaterialInteger( pMaterial,AI_MATKEY_SHADING_MODEL,&iShading)) {
nuclear@0 724 switch ((aiShadingMode)iShading)
nuclear@0 725 {
nuclear@0 726 case aiShadingMode_Blinn:
nuclear@0 727 case aiShadingMode_CookTorrance:
nuclear@0 728 case aiShadingMode_Phong:
nuclear@0 729
nuclear@0 730 if (AI_SUCCESS != aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS,&fTemp)) {
nuclear@0 731 ReportWarning("A specular shading model is specified but there is no "
nuclear@0 732 "AI_MATKEY_SHININESS key");
nuclear@0 733 }
nuclear@0 734 if (AI_SUCCESS == aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS_STRENGTH,&fTemp) && !fTemp) {
nuclear@0 735 ReportWarning("A specular shading model is specified but the value of the "
nuclear@0 736 "AI_MATKEY_SHININESS_STRENGTH key is 0.0");
nuclear@0 737 }
nuclear@0 738 break;
nuclear@0 739 default: ;
nuclear@0 740 };
nuclear@0 741 }
nuclear@0 742
nuclear@0 743 if (AI_SUCCESS == aiGetMaterialFloat( pMaterial,AI_MATKEY_OPACITY,&fTemp) && (!fTemp || fTemp > 1.01f)) {
nuclear@0 744 ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)");
nuclear@0 745 }
nuclear@0 746
nuclear@0 747 // Check whether there are invalid texture keys
nuclear@0 748 // TODO: that's a relict of the past, where texture type and index were baked
nuclear@0 749 // into the material string ... we could do that in one single pass.
nuclear@0 750 SearchForInvalidTextures(pMaterial,aiTextureType_DIFFUSE);
nuclear@0 751 SearchForInvalidTextures(pMaterial,aiTextureType_SPECULAR);
nuclear@0 752 SearchForInvalidTextures(pMaterial,aiTextureType_AMBIENT);
nuclear@0 753 SearchForInvalidTextures(pMaterial,aiTextureType_EMISSIVE);
nuclear@0 754 SearchForInvalidTextures(pMaterial,aiTextureType_OPACITY);
nuclear@0 755 SearchForInvalidTextures(pMaterial,aiTextureType_SHININESS);
nuclear@0 756 SearchForInvalidTextures(pMaterial,aiTextureType_HEIGHT);
nuclear@0 757 SearchForInvalidTextures(pMaterial,aiTextureType_NORMALS);
nuclear@0 758 SearchForInvalidTextures(pMaterial,aiTextureType_DISPLACEMENT);
nuclear@0 759 SearchForInvalidTextures(pMaterial,aiTextureType_LIGHTMAP);
nuclear@0 760 SearchForInvalidTextures(pMaterial,aiTextureType_REFLECTION);
nuclear@0 761 }
nuclear@0 762
nuclear@0 763 // ------------------------------------------------------------------------------------------------
nuclear@0 764 void ValidateDSProcess::Validate( const aiTexture* pTexture)
nuclear@0 765 {
nuclear@0 766 // the data section may NEVER be NULL
nuclear@0 767 if (!pTexture->pcData) {
nuclear@0 768 ReportError("aiTexture::pcData is NULL");
nuclear@0 769 }
nuclear@0 770 if (pTexture->mHeight)
nuclear@0 771 {
nuclear@0 772 if (!pTexture->mWidth)ReportError("aiTexture::mWidth is zero "
nuclear@0 773 "(aiTexture::mHeight is %i, uncompressed texture)",pTexture->mHeight);
nuclear@0 774 }
nuclear@0 775 else
nuclear@0 776 {
nuclear@0 777 if (!pTexture->mWidth) {
nuclear@0 778 ReportError("aiTexture::mWidth is zero (compressed texture)");
nuclear@0 779 }
nuclear@0 780 if ('\0' != pTexture->achFormatHint[3]) {
nuclear@0 781 ReportWarning("aiTexture::achFormatHint must be zero-terminated");
nuclear@0 782 }
nuclear@0 783 else if ('.' == pTexture->achFormatHint[0]) {
nuclear@0 784 ReportWarning("aiTexture::achFormatHint should contain a file extension "
nuclear@0 785 "without a leading dot (format hint: %s).",pTexture->achFormatHint);
nuclear@0 786 }
nuclear@0 787 }
nuclear@0 788
nuclear@0 789 const char* sz = pTexture->achFormatHint;
nuclear@0 790 if ((sz[0] >= 'A' && sz[0] <= 'Z') ||
nuclear@0 791 (sz[1] >= 'A' && sz[1] <= 'Z') ||
nuclear@0 792 (sz[2] >= 'A' && sz[2] <= 'Z') ||
nuclear@0 793 (sz[3] >= 'A' && sz[3] <= 'Z')) {
nuclear@0 794 ReportError("aiTexture::achFormatHint contains non-lowercase letters");
nuclear@0 795 }
nuclear@0 796 }
nuclear@0 797
nuclear@0 798 // ------------------------------------------------------------------------------------------------
nuclear@0 799 void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
nuclear@0 800 const aiNodeAnim* pNodeAnim)
nuclear@0 801 {
nuclear@0 802 Validate(&pNodeAnim->mNodeName);
nuclear@0 803
nuclear@0 804 if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys)
nuclear@0 805 ReportError("Empty node animation channel");
nuclear@0 806
nuclear@0 807 // otherwise check whether one of the keys exceeds the total duration of the animation
nuclear@0 808 if (pNodeAnim->mNumPositionKeys)
nuclear@0 809 {
nuclear@0 810 if (!pNodeAnim->mPositionKeys)
nuclear@0 811 {
nuclear@0 812 this->ReportError("aiNodeAnim::mPositionKeys is NULL (aiNodeAnim::mNumPositionKeys is %i)",
nuclear@0 813 pNodeAnim->mNumPositionKeys);
nuclear@0 814 }
nuclear@0 815 double dLast = -10e10;
nuclear@0 816 for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys;++i)
nuclear@0 817 {
nuclear@0 818 // ScenePreprocessor will compute the duration if still the default value
nuclear@0 819 // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration,
nuclear@0 820 // seems to be due the compilers register usage/width.
nuclear@0 821 if (pAnimation->mDuration > 0. && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration+0.001)
nuclear@0 822 {
nuclear@0 823 ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger "
nuclear@0 824 "than aiAnimation::mDuration (which is %.5f)",i,
nuclear@0 825 (float)pNodeAnim->mPositionKeys[i].mTime,
nuclear@0 826 (float)pAnimation->mDuration);
nuclear@0 827 }
nuclear@0 828 if (i && pNodeAnim->mPositionKeys[i].mTime <= dLast)
nuclear@0 829 {
nuclear@0 830 ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller "
nuclear@0 831 "than aiAnimation::mPositionKeys[%i] (which is %.5f)",i,
nuclear@0 832 (float)pNodeAnim->mPositionKeys[i].mTime,
nuclear@0 833 i-1, (float)dLast);
nuclear@0 834 }
nuclear@0 835 dLast = pNodeAnim->mPositionKeys[i].mTime;
nuclear@0 836 }
nuclear@0 837 }
nuclear@0 838 // rotation keys
nuclear@0 839 if (pNodeAnim->mNumRotationKeys)
nuclear@0 840 {
nuclear@0 841 if (!pNodeAnim->mRotationKeys)
nuclear@0 842 {
nuclear@0 843 this->ReportError("aiNodeAnim::mRotationKeys is NULL (aiNodeAnim::mNumRotationKeys is %i)",
nuclear@0 844 pNodeAnim->mNumRotationKeys);
nuclear@0 845 }
nuclear@0 846 double dLast = -10e10;
nuclear@0 847 for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys;++i)
nuclear@0 848 {
nuclear@0 849 if (pAnimation->mDuration > 0. && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration+0.001)
nuclear@0 850 {
nuclear@0 851 ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger "
nuclear@0 852 "than aiAnimation::mDuration (which is %.5f)",i,
nuclear@0 853 (float)pNodeAnim->mRotationKeys[i].mTime,
nuclear@0 854 (float)pAnimation->mDuration);
nuclear@0 855 }
nuclear@0 856 if (i && pNodeAnim->mRotationKeys[i].mTime <= dLast)
nuclear@0 857 {
nuclear@0 858 ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller "
nuclear@0 859 "than aiAnimation::mRotationKeys[%i] (which is %.5f)",i,
nuclear@0 860 (float)pNodeAnim->mRotationKeys[i].mTime,
nuclear@0 861 i-1, (float)dLast);
nuclear@0 862 }
nuclear@0 863 dLast = pNodeAnim->mRotationKeys[i].mTime;
nuclear@0 864 }
nuclear@0 865 }
nuclear@0 866 // scaling keys
nuclear@0 867 if (pNodeAnim->mNumScalingKeys)
nuclear@0 868 {
nuclear@0 869 if (!pNodeAnim->mScalingKeys) {
nuclear@0 870 ReportError("aiNodeAnim::mScalingKeys is NULL (aiNodeAnim::mNumScalingKeys is %i)",
nuclear@0 871 pNodeAnim->mNumScalingKeys);
nuclear@0 872 }
nuclear@0 873 double dLast = -10e10;
nuclear@0 874 for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys;++i)
nuclear@0 875 {
nuclear@0 876 if (pAnimation->mDuration > 0. && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration+0.001)
nuclear@0 877 {
nuclear@0 878 ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger "
nuclear@0 879 "than aiAnimation::mDuration (which is %.5f)",i,
nuclear@0 880 (float)pNodeAnim->mScalingKeys[i].mTime,
nuclear@0 881 (float)pAnimation->mDuration);
nuclear@0 882 }
nuclear@0 883 if (i && pNodeAnim->mScalingKeys[i].mTime <= dLast)
nuclear@0 884 {
nuclear@0 885 ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller "
nuclear@0 886 "than aiAnimation::mScalingKeys[%i] (which is %.5f)",i,
nuclear@0 887 (float)pNodeAnim->mScalingKeys[i].mTime,
nuclear@0 888 i-1, (float)dLast);
nuclear@0 889 }
nuclear@0 890 dLast = pNodeAnim->mScalingKeys[i].mTime;
nuclear@0 891 }
nuclear@0 892 }
nuclear@0 893
nuclear@0 894 if (!pNodeAnim->mNumScalingKeys && !pNodeAnim->mNumRotationKeys &&
nuclear@0 895 !pNodeAnim->mNumPositionKeys)
nuclear@0 896 {
nuclear@0 897 ReportError("A node animation channel must have at least one subtrack");
nuclear@0 898 }
nuclear@0 899 }
nuclear@0 900
nuclear@0 901 // ------------------------------------------------------------------------------------------------
nuclear@0 902 void ValidateDSProcess::Validate( const aiNode* pNode)
nuclear@0 903 {
nuclear@0 904 if (!pNode)ReportError("A node of the scenegraph is NULL");
nuclear@0 905 if (pNode != mScene->mRootNode && !pNode->mParent)
nuclear@0 906 this->ReportError("A node has no valid parent (aiNode::mParent is NULL)");
nuclear@0 907
nuclear@0 908 this->Validate(&pNode->mName);
nuclear@0 909
nuclear@0 910 // validate all meshes
nuclear@0 911 if (pNode->mNumMeshes)
nuclear@0 912 {
nuclear@0 913 if (!pNode->mMeshes)
nuclear@0 914 {
nuclear@0 915 ReportError("aiNode::mMeshes is NULL (aiNode::mNumMeshes is %i)",
nuclear@0 916 pNode->mNumMeshes);
nuclear@0 917 }
nuclear@0 918 std::vector<bool> abHadMesh;
nuclear@0 919 abHadMesh.resize(mScene->mNumMeshes,false);
nuclear@0 920 for (unsigned int i = 0; i < pNode->mNumMeshes;++i)
nuclear@0 921 {
nuclear@0 922 if (pNode->mMeshes[i] >= mScene->mNumMeshes)
nuclear@0 923 {
nuclear@0 924 ReportError("aiNode::mMeshes[%i] is out of range (maximum is %i)",
nuclear@0 925 pNode->mMeshes[i],mScene->mNumMeshes-1);
nuclear@0 926 }
nuclear@0 927 if (abHadMesh[pNode->mMeshes[i]])
nuclear@0 928 {
nuclear@0 929 ReportError("aiNode::mMeshes[%i] is already referenced by this node (value: %i)",
nuclear@0 930 i,pNode->mMeshes[i]);
nuclear@0 931 }
nuclear@0 932 abHadMesh[pNode->mMeshes[i]] = true;
nuclear@0 933 }
nuclear@0 934 }
nuclear@0 935 if (pNode->mNumChildren)
nuclear@0 936 {
nuclear@0 937 if (!pNode->mChildren) {
nuclear@0 938 ReportError("aiNode::mChildren is NULL (aiNode::mNumChildren is %i)",
nuclear@0 939 pNode->mNumChildren);
nuclear@0 940 }
nuclear@0 941 for (unsigned int i = 0; i < pNode->mNumChildren;++i) {
nuclear@0 942 Validate(pNode->mChildren[i]);
nuclear@0 943 }
nuclear@0 944 }
nuclear@0 945 }
nuclear@0 946
nuclear@0 947 // ------------------------------------------------------------------------------------------------
nuclear@0 948 void ValidateDSProcess::Validate( const aiString* pString)
nuclear@0 949 {
nuclear@0 950 if (pString->length > MAXLEN)
nuclear@0 951 {
nuclear@0 952 this->ReportError("aiString::length is too large (%i, maximum is %i)",
nuclear@0 953 pString->length,MAXLEN);
nuclear@0 954 }
nuclear@0 955 const char* sz = pString->data;
nuclear@0 956 while (true)
nuclear@0 957 {
nuclear@0 958 if ('\0' == *sz)
nuclear@0 959 {
nuclear@0 960 if (pString->length != (unsigned int)(sz-pString->data))
nuclear@0 961 ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
nuclear@0 962 break;
nuclear@0 963 }
nuclear@0 964 else if (sz >= &pString->data[MAXLEN])
nuclear@0 965 ReportError("aiString::data is invalid. There is no terminal character");
nuclear@0 966 ++sz;
nuclear@0 967 }
nuclear@0 968 }