// // Copyright 2013 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #include #include "../common/shape_utils.h" // // Regression testing matching Hbr to a pre-generated data-set // // Precision is currently held at bit-wise identical static bool g_allowWeakRegression=true, g_strictRegressionFailure=false, g_verbose=false; #define STRICT_PRECISION 0 #define WEAK_PRECISION 1e-6 //------------------------------------------------------------------------------ // Vertex class implementation struct xyzVV { xyzVV() { } xyzVV( int /*i*/ ) { } xyzVV( float x, float y, float z ) { _pos[0]=x; _pos[1]=y; _pos[2]=z; } xyzVV( const xyzVV & src ) { _pos[0]=src._pos[0]; _pos[1]=src._pos[1]; _pos[2]=src._pos[2]; } ~xyzVV( ) { } void AddWithWeight(const xyzVV& src, float weight, void * =0 ) { _pos[0]+=weight*src._pos[0]; _pos[1]+=weight*src._pos[1]; _pos[2]+=weight*src._pos[2]; } void AddVaryingWithWeight(const xyzVV& , float, void * =0 ) { } void Clear( void * =0 ) { _pos[0]=_pos[1]=_pos[2]=0.0f; } void SetPosition(float x, float y, float z) { _pos[0]=x; _pos[1]=y; _pos[2]=z; } void ApplyVertexEdit(const OpenSubdiv::HbrVertexEdit & edit) { const float *src = edit.GetEdit(); switch(edit.GetOperation()) { case OpenSubdiv::HbrHierarchicalEdit::Set: _pos[0] = src[0]; _pos[1] = src[1]; _pos[2] = src[2]; break; case OpenSubdiv::HbrHierarchicalEdit::Add: _pos[0] += src[0]; _pos[1] += src[1]; _pos[2] += src[2]; break; case OpenSubdiv::HbrHierarchicalEdit::Subtract: _pos[0] -= src[0]; _pos[1] -= src[1]; _pos[2] -= src[2]; break; } } void ApplyMovingVertexEdit(const OpenSubdiv::HbrMovingVertexEdit &) { } const float * GetPos() const { return _pos; } private: float _pos[3]; }; //------------------------------------------------------------------------------ class xyzFV; typedef OpenSubdiv::HbrMesh xyzmesh; typedef OpenSubdiv::HbrFace xyzface; typedef OpenSubdiv::HbrVertex xyzvertex; typedef OpenSubdiv::HbrHalfedge xyzhalfedge; typedef OpenSubdiv::HbrFaceOperator xyzFaceOperator; typedef OpenSubdiv::HbrVertexOperator xyzVertexOperator; //------------------------------------------------------------------------------ #include "./init_shapes.h" static shape * readShape( char const * fname ) { FILE * handle = fopen( fname, "rt" ); if (not handle) { printf("Could not open \"%s\" - aborting.\n", fname); exit(0); } fseek( handle, 0, SEEK_END ); size_t size = ftell(handle); fseek( handle, 0, SEEK_SET ); char * shapeStr = new char[size+1]; if ( fread( shapeStr, size, 1, handle)!=1 ) { printf("Error reading \"%s\" - aborting.\n", fname); exit(0); } fclose(handle); shapeStr[size]='\0'; return shape::parseShape( shapeStr, 1 ); } #define STR(x) x #ifdef HBR_BASELINE_DIR std::string g_baseline_path = STR(HBR_BASELINE_DIR); #else std::string g_baseline_path; #endif //------------------------------------------------------------------------------ static void writeObj( const char * fname, xyzmesh const * mesh, int firstface, int lastface, int firstvert, int lastvert ) { FILE * handle = fopen( fname, "w" ); if (not handle) { printf("Could not open \"%s\" - aborting.\n", fname); exit(0); } fprintf(handle, "# This file uses centimeters as units for non-parametric coordinates.\n"); for (int i=firstvert; iGetVertex(i)->GetData().GetPos(); fprintf(handle, "v %.*g %.*g %.*g\n", 9, pos[0], 9, pos[1], 9, pos[2]); } fprintf(handle, "s off\n"); for (int i=firstface; iGetFace(i); fprintf(handle, "f "); for (int j=0; jGetNumVertices();) { int vert = f->GetVertex(j)->GetID()-firstvert+1; fprintf(handle, "%d", vert); if (++jGetNumVertices()) fprintf(handle, " "); } fprintf(handle, "\n"); } fclose(handle); } //------------------------------------------------------------------------------ static int checkMesh( shaperec const & r, int levels ) { int count=0; float deltaAvg[3] = {0.0f, 0.0f, 0.0f}, deltaCnt[3] = {0.0f, 0.0f, 0.0f}; xyzmesh * mesh = simpleHbr(r.data.c_str(), r.scheme, 0); int firstface=0, lastface=mesh->GetNumFaces(), firstvert=0, lastvert=mesh->GetNumVertices(), nverts; static char const * schemes[] = { "Bilinear", "Catmark", "Loop" }; printf("- %-25s ( %-8s ): ", r.name.c_str(), schemes[r.scheme]); for (int l=0; lGetFace(i); f->Refine(); } firstface = lastface; lastface = mesh->GetNumFaces(); //nfaces = lastface - firstface; firstvert = lastvert; lastvert = mesh->GetNumVertices(); nverts = lastvert - firstvert; for (int i=firstvert; iGetVertex(i)->GetData().GetPos(), * bpos = &sh->verts[(i-firstvert)*3]; if ( apos[0] != bpos[0] ) deltaCnt[0]++; if ( apos[1] != bpos[1] ) deltaCnt[1]++; if ( apos[2] != bpos[2] ) deltaCnt[2]++; float delta[3] = { apos[0] - bpos[0], apos[1] - bpos[1], apos[2] - bpos[2] }; deltaAvg[0]+=delta[0]; deltaAvg[1]+=delta[1]; deltaAvg[2]+=delta[2]; float dist = sqrtf( delta[0]*delta[0]+delta[1]*delta[1]+delta[2]*delta[2]); if ( dist > STRICT_PRECISION ) { if(dist < WEAK_PRECISION and g_allowWeakRegression) { g_strictRegressionFailure=true; } else { if (g_verbose) { printf("\n// HbrVertex %d fails : dist=%.10f " "(%.10f %.10f %.10f) (%.10f %.10f %.10f)", i, dist, apos[0], apos[1], apos[2], bpos[0], bpos[1], bpos[2] ); } ++errcount; } } } if (errcount) { std::stringstream errfile; errfile << r.name << "_level" << l << "_error.obj"; writeObj(errfile.str().c_str(), mesh, firstface, lastface, firstvert, lastvert); printf("\n wrote: %s\n", errfile.str().c_str()); } delete sh; count += errcount; } if (deltaCnt[0]) deltaAvg[0]/=deltaCnt[0]; if (deltaCnt[1]) deltaAvg[1]/=deltaCnt[1]; if (deltaCnt[2]) deltaAvg[2]/=deltaCnt[2]; if (g_verbose) { printf("\n delta ratio : (%d/%d %d/%d %d/%d)", (int)deltaCnt[0], nverts, (int)deltaCnt[1], nverts, (int)deltaCnt[2], nverts ); printf("\n average delta : (%.10f %.10f %.10f)", deltaAvg[0], deltaAvg[1], deltaAvg[2] ); } if (count==0) { printf(" success !\n"); } else printf(" failed !\n"); delete mesh; return count; } //------------------------------------------------------------------------------ static void usage(char const * appname) { printf("Usage : %s [options]\n", appname); printf(" -s | -strict : strict bitwise comparisons\n"); printf(" -v | -verbose : verbose output\n"); } //------------------------------------------------------------------------------ int main(int argc, char ** argv) { int levels=5, total=0; for (int i=1; i