#include "ProxyHeaders.hpp" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FindErrorsProcess::FindErrorsProcess(): enableDuplicateCheck(true), enableDegenerateCheck(true), enableCoplanarCheck(true), enableColinearCheck(true), enableConvexCheck(true) { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // FindErrorsProcess::FindErrorsProcess( Stuff::NotationFile *data_file, bool bSuppress, void* fcn ): Process(data_file,bSuppress,fcn), enableDuplicateCheck(true), enableDegenerateCheck(true), enableCoplanarCheck(true), enableColinearCheck(true), enableConvexCheck(true) { Check_Object(data_file); Page *page = data_file->FindPage("FindErrors"); if (page) { page->GetEntry("DuplicateCheck", &enableDuplicateCheck); page->GetEntry("DegenerateCheck", &enableDegenerateCheck); page->GetEntry("CoplanarCheck", &enableCoplanarCheck); page->GetEntry("ColinearCheck", &enableColinearCheck); page->GetEntry("ConvexCheck", &enableConvexCheck); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int PolygonProxy::FindErrors(FindErrorsProcess *process) { Check_Object(this); Check_Object(process); // //--------------------------------------------------------------------- // Get the area of the polygon. This will be used to scale some of the // error process so they fit with larger polygons //--------------------------------------------------------------------- // Scalar area = GetArea(); Scalar area_edge = Sqrt(area); Scalar plane_tolerance = process->planeThicknessTolerance * area_edge; Scalar duplicate_tolerance = process->duplicateVertexTolerance; Scalar colinear_tolerance = process->colinearTolerance; int total = 0; // //-------------------------------------------- // Delete all the error groups on this polygon //-------------------------------------------- // MStringChain group_list(NULL); GetCollections(&group_list); MStringChainIterator group_itr(&group_list); PlugOf *group; while ((group = group_itr.ReadAndNext()) != NULL) { Check_Object(group); const char* name = group->GetItem(); Check_Pointer(name); if (!_strnicmp(name, "_ERROR_", 7)) RemoveFromCollection(name); Unregister_Object(group); delete group; } // //------------------------------------------------------------------------ // The first task we have is to find the two longest consecutive edges. // We will use these edges to compute the desired polygon normal and plane // equation //------------------------------------------------------------------------ // Point3D position_a, position_b = Point3D::Identity, position_c = Point3D::Identity; VertexProxy *vertex_a = NULL, *vertex_b = NULL, *vertex_c = NULL; Vector3D edge_1, edge_2 = Vector3D::Identity; Plane plane; // //----------------------------------------------------------------- // Put in checks to make sure that the colors, normals, and uvs are // compatible for all the vertices in this polygon //----------------------------------------------------------------- // bool uv_there = false, color_there = false, normal_there = false; // //----------------------------------- // Spin through, testing the vertices //----------------------------------- // DynamicArrayOf indices; unsigned index_count = UseIndexArray(&indices); Verify(index_count == indices.GetLength()); Verify(index_count >= 3); unsigned end=2; for (unsigned i=0; iGetVertexProxy(); Check_Object(vertex_a); Check_Object(indices[1]); vertex_b = indices[1]->GetVertexProxy(); Check_Object(vertex_b); Check_Object(indices[2]); vertex_c = indices[2]->GetVertexProxy(); Check_Object(vertex_c); vertex_a->GetPosition(&position_a); vertex_b->GetPosition(&position_b); vertex_c->GetPosition(&position_c); edge_1.Subtract(position_b, position_a); edge_2.Subtract(position_c, position_b); Normal3D normal; if (vertex_c->GetNormal(&normal)) { if (!Close_Enough(normal.Vector3D::GetLengthSquared(), 1.0f, 2e-5f)) { AddToCollection("_ERROR_Bad_Normal"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Bad_Normal ); break; } } // //--------------------------------- // Set up the additional attributes //--------------------------------- // RGBAColor color; color_there = vertex_c->GetColor(&color); DynamicArrayOf > uv; uv_there = vertex_c->GetUVs(&uv); normal_there = vertex_c->GetNormal(&normal); } // //-------------------------------------------------------------- // Get the index info. If this is not the first pass, copy the // information from last pass //-------------------------------------------------------------- // else { Check_Object(vertex_b); vertex_a = vertex_b; Check_Object(vertex_c); vertex_b = vertex_c; if (++end >= index_count) end -= index_count; Check_Object(indices[end]); vertex_c = indices[end]->GetVertexProxy(); Check_Object(vertex_c); position_a = position_b; position_b = position_c; vertex_c->GetPosition(&position_c); edge_1 = edge_2; edge_2.Subtract(position_c, position_b); // //-------------------------------- // Check the additional attributes //-------------------------------- // RGBAColor color; if (color_there != vertex_c->GetColor(&color)) { AddToCollection("_ERROR_Mismatched_Vertex_Colors"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Mismatched_Vertex_Colors ); break; } DynamicArrayOf > uv; if (uv_there != vertex_c->GetUVs(&uv)) { AddToCollection("_ERROR_Mismatched_UVs"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Mismatched_UVs ); break; } Normal3D normal; if (normal_there != vertex_c->GetNormal(&normal)) { AddToCollection("_ERROR_Mismatched_Normals"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Mismatched_Normals ); break; } } // //----------------------------------------------------------------- // Check the forward leg length to see if the polygon has duplicate // points //----------------------------------------------------------------- // Scalar length = edge_2.GetLengthSquared(); if ( Small_Enough(length, duplicate_tolerance) && process->enableDuplicateCheck ) { AddToCollection("_ERROR_Duplicate_Vertex"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Duplicate_Vertex ); break; } // //--------------------------------------------------------------------- // Compute the cross-product of the two legs and check for colinearness. // This is not necessarily bad, as long as we are coplanar //--------------------------------------------------------------------- // Vector3D v; v.Cross(edge_1, edge_2); Scalar cross_len = v.GetLength(); if (Small_Enough(cross_len, colinear_tolerance)) { if (!i && process->enableDegenerateCheck) { AddToCollection("_ERROR_Degenerate_Polygon"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Degenerate_Polygon ); break; } else if ( !Small_Enough(plane.GetDistanceTo(position_b), plane_tolerance) && process->enableCoplanarCheck ) { AddToCollection("_ERROR_Noncoplanar_Polygon"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Noncoplanar_Polygon ); break; } continue; } // //------------------------------------------------------------------- // Normalize the cross. If this is the first pass, compute the plane // equation for the polygon //------------------------------------------------------------------- // cross_len = 1.0f / cross_len; Normal3D edge_normal(v.x*cross_len, v.y*cross_len, v.z*cross_len); if (!i) { plane.normal = edge_normal; plane.offset = plane.normal * position_b; } else { // //-------------------------- // Check for non-coplanarity //-------------------------- // if ( !Small_Enough(plane.GetDistanceTo(position_b), plane_tolerance) && process->enableCoplanarCheck ) { AddToCollection("_ERROR_Noncoplanar_Polygon"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Noncoplanar_Polygon ); break; } // //---------------------- // Check for concaveness //---------------------- // Scalar cosine = plane.normal*edge_normal; if (cosine < colinear_tolerance && process->enableConvexCheck) { AddToCollection("_ERROR_Nonconvex_Polygon"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Noncoplanar_Polygon ); break; } } } #if 0 // //-------------------------------- // Check for polygons w/o textures //-------------------------------- // if(stateArray.GetLength() < 1) { AddToCollection("_ERROR_Nontextured_Polygon"); ++total; process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Nontextured_Polygon ); } #endif // //----------------------------- // Delete the remaining proxies //----------------------------- // DetachArrayReferences(&indices); return total; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int TextureProxy::FindErrors(FindErrorsProcess *process) { Check_Object(this); Check_Object(process); // //------------------------------------------------------------ // Make sure that the process says its OK to check the texture //------------------------------------------------------------ // process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck); if (!process->continueProcess) return 1; // //--------------------------------------------------------- // Make sure that the texture is between 32 and 256 in size //--------------------------------------------------------- // Vector2DOf size; GetImageSize(&size); if (size.x<32 || size.x>512 || size.y<32 || size.y>512) { process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Bad_Texture_Size ); return 1; } // //-------------------------------------------------------- // Make sure that we are dealing with a power of 2 texture //-------------------------------------------------------- // size.x ^= size.x&(-size.x); size.y ^= size.y&(-size.y); if (size.x || size.y) { process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Bad_Texture_Size ); return 1; } return 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int TextureLibrary::FindErrors(FindErrorsProcess *process) { Check_Object(this); Check_Object(process); // //--------------------------- // Handle the texture library //--------------------------- // int total = 0; TextureProxy *texture = UseFirstTextureProxy(); while (texture) { Check_Object(texture); total += texture->FindErrors(process); TextureProxy *next = texture->UseNextTextureProxyInLibrary(); texture->DetachReference(); if (!process->continueProcess) { if (next) next->DetachReference(); return total; } texture = next; } return total; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int ChildProxy::FindErrors(FindErrorsProcess *process) { Check_Object(this); Check_Object(process); process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck); return (!process->continueProcess) ? 1 : 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int GroupProxy::FindErrors(FindErrorsProcess *process) { Check_Object(this); Check_Object(process); // //--------------------------------------------------- // Make sure that the process says its OK to continue //--------------------------------------------------- // process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck); if (!process->continueProcess) return 1; // //----------------------------------------------------- // Go through each child and count the number of errors //----------------------------------------------------- // int total = 0; ChildProxy *child = UseFirstChildProxy(); while (child) { Check_Object(child); total += child->FindErrors(process); ChildProxy *next = child->UseNextSiblingProxy(); child->DetachReference(); if (!process->continueProcess) { if (next) next->DetachReference(); return total; } child = next; } return total; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int PolygonMeshProxy::FindErrors(FindErrorsProcess *process) { Check_Object(this); Check_Object(process); // //--------------------------------------------------- // Make sure that the process says its OK to continue //--------------------------------------------------- // process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck); if (!process->continueProcess) return 1; // //----------------------------------- // Count the number of polygon errors //----------------------------------- // int total = 0; DynamicArrayOf polygons; unsigned polygon_count = UsePolygonArray(&polygons); Verify(polygon_count == polygons.GetLength()); if (polygon_count) { for (unsigned i=0; iFindErrors(process); } } else { process->FindErrorsCallback( this, FindErrorsProcess::ERROR_Empty_Mesh ); total = 1; } DetachArrayReferences(&polygons); return total; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int SceneProxy::FindErrors(FindErrorsProcess *process) { Check_Object(this); Check_Object(process); // //--------------------------------------------------- // Make sure that the process says its OK to continue //--------------------------------------------------- // process->FindErrorsCallback(this, FindErrorsProcess::StatusCheck); if (!process->continueProcess) return 1; // //------------------- // Check the textures //------------------- // int total=0; StateLibrary *states = GetStateLibrary(); Check_Object(states); TextureLibrary *textures = states->GetTextureLibrary(); Check_Object(textures); total += textures->FindErrors(process); if (!process->continueProcess) return total; // //----------------- // Check each child //----------------- // ChildProxy *child = UseFirstChildProxy(); while (child) { Check_Object(child); total += child->FindErrors(process); ChildProxy *next = child->UseNextSiblingProxy(); child->DetachReference(); if (!process->continueProcess) { if (next) next->DetachReference(); break; } child = next; } return total; }