#include "precompiled.h" # include # include "sr_model.h" # include "sr_tree.h" # include "sr_sphere.h" # include "sr_cylinder.h" # include "sr_string_array.h" //# define SR_USE_TRACE1 // IO //# define SR_USE_TRACE2 // Validation of normals materials, etc # include "sr_trace.h" //=================================== SrModel ================================================= const char* SrModel::class_name = "Model"; SrModel::SrModel () { culling = true; } SrModel::~SrModel () { } void SrModel::init () { culling = true; M.capacity ( 0 ); V.capacity ( 0 ); N.capacity ( 0 ); T.capacity ( 0 ); F.capacity ( 0 ); Fm.capacity ( 0 ); Fn.capacity ( 0 ); Ft.capacity ( 0 ); mtlnames.capacity ( 0 ); name = ""; } void SrModel::compress () { M.compress(); V.compress(); N.compress(); T.compress(); F.compress(); Fm.compress(); Fn.compress(); Ft.compress(); mtlnames.compress(); name.compress(); } void SrModel::validate () { int i, j; SrArray iarray; SrStringArray sarray; int fsize = F.size(); // check if the model is empty if ( fsize==0 || V.size()==0 ) { init (); compress (); return; } // check size of Fn if ( Fn.size()!=fsize || N.size()==0 ) { Fn.size(0); N.size(0); } // check size of Ft if ( Ft.size()!=fsize || T.size()==0 ) { Ft.size(0); T.size(0); } // check size of Fm if ( M.size()==0 ) { Fm.size(0); } else if ( Fm.size()!=fsize ) { j = Fm.size(); Fm.size ( fsize ); for ( i=j; i iarray; int fsize = F.size(); if ( M.size()==0 ) { Fm.size(0); } else { j = Fm.size(); Fm.size ( fsize ); for ( i=j; i=0 && Fm[i]0 ) material_names[k-1]=0; // remove the last space for ( i=0; i iarray; int fsize = F.size(); if ( N.size()==0 || Fn.size()!=fsize ) { N.size(0); Fn.size(0); } else { // remove references to duplicated normals int nsize = N.size(); for ( i=0; i iarray; iarray.size ( vsize ); for ( i=0; i> s; if ( s!="SrModel" ) return false; // clear arrays and set culling to true init (); while ( !in.finished() ) { if ( !in.read_field(s) ) { if ( in.finished() ) break; // EOF reached return false; } SR_TRACE1 ( '<' << s << "> Field found...\n" ); if ( s=="culling" ) // read culling state { in >> i; culling = i? true:false; if ( !in.close_field(s) ) return false; } else if ( s=="name" ) // read name (is a SrInput::String type ) { in.get_token(); name = in.last_token(); if ( !in.close_field(s) ) return false; } else if ( s=="vertices" ) // read vertices: x y z { in >> i; V.size(i); for ( i=0; i> V[i]; if ( !in.close_field(s) ) return false; } else if ( s=="vertices_per_face" ) // read F: a b c { in >> i; F.size(i); for ( i=0; i> F[i]; F[i].validate(); } if ( !in.close_field(s) ) return false; } else if ( s=="normals_per_face" ) // read Fn: a b c { in >> i; Fn.size(i); for ( i=0; i> Fn[i]; if ( !in.close_field(s) ) return false; } else if ( s=="textcoords_per_face" ) // read Ft: a b c { in >> i; Ft.size(i); for ( i=0; i> Ft[i]; if ( !in.close_field(s) ) return false; } else if ( s=="materials_per_face" ) // read Fm: i { in >> i; Fm.size(i); for ( i=0; i> Fm[i]; if ( !in.close_field(s) ) return false; } else if ( s=="normals" ) // read N: x y z { in >> i; N.size(i); for ( i=0; i> N[i]; if ( !in.close_field(s) ) return false; } else if ( s=="textcoords" ) // read T: x y { in >> i; T.size(i); for ( i=0; i> T[i]; if ( !in.close_field(s) ) return false; } else if ( s=="materials" ) // read M: mtls { in >> i; M.size(i); for ( i=0; i> M[i]; if ( !in.close_field(s) ) return false; } else if ( s=="material_names" ) // read materials { SrString buf1, buf2; mtlnames.capacity ( 0 ); // clear all mtlnames.size ( M.size() ); // realloc while ( 1 ) { if ( in.get_token()!=SrInput::Integer ) { in.unget_token(); break; } i = atoi ( in.last_token() ); in.get_token(); mtlnames.set ( i, in.last_token() ); } if ( !in.close_field(s) ) return false; } else // unknown field, just skip it: { if ( !in.skip_field(s) ) return false; } } SR_TRACE1 ( "OK.\n" ); return true; } bool SrModel::save ( SrOutput &o ) const { int i; // save header as a comment o << "# SR - Simulation and Representation Toolkit\n" << "# Marcelo Kallmann 1996-2004\n\n"; // save signature o << "SrModel\n\n"; // save name if ( name.len()>0 ) { o << " \"" << name << "\" \n\n"; } // save culling state if ( !culling ) { o << " 0 \n\n"; } // save vertices (V) if ( V.size() ) { o << " " << V.size() << srnl; for ( i=0; i\n\n"; } // save faces (F) if ( F.size() ) { o << " " << F.size() << srnl; for ( i=0; i\n\n"; } // save normals (N) if ( N.size() ) { o << " " << N.size() << srnl; for ( i=0; i\n\n"; } // save normals per face (Fn) if ( Fn.size() ) { o << " " << Fn.size() << srnl; for ( i=0; i\n\n"; } // save texture coordinates (T) /* Not yet supported so not saved if ( T.size() ) { o << " " << N.size() << srnl; for ( i=0; i\n\n"; } */ // save texture coordinates per face (Ft) /* Not yet supported so not saved if ( Ft.size() ) { o << " " << Ft.size() << srnl; for ( i=0; i\n\n"; } */ // save materials (M) if ( M.size() ) { o << " " << M.size() << srnl; for ( i=0; i\n\n"; } // save materials per face (Fm) if ( Fm.size() ) { o << " " << Fm.size() << srnl; for ( i=0; i\n\n"; } // save material names if there is one: bool savemtl=false; for ( i=0; i " << srnl; for ( i=0; i\n\n"; } // done. return true; } struct EdgeNode : public SrTreeNode // EdgeNode is only internally used : { int a, b; EdgeNode ( int x, int y ) : a(x), b(y) {} EdgeNode () : a(0), b(0) {} EdgeNode ( const EdgeNode& e ) : a(e.a), b(e.b) {} ~EdgeNode () {} friend SrOutput& operator<< ( SrOutput& out, const EdgeNode& e ) { return out; }; friend SrInput& operator>> ( SrInput& inp, EdgeNode& e ) { return inp; } friend int sr_compare ( const EdgeNode* e1, const EdgeNode* e2 ) { return e1->a!=e2->a ? e1->a-e2->a : e1->b-e2->b; } }; void SrModel::make_edges ( SrArray &E ) { int i; SrTree t; E.size(0); if ( F.empty() ) return; for ( i=0; ia; E.push() = t.cur()->b; } } float SrModel::count_mean_vertex_degree () { int i; if ( F.empty() ) return 0.0f; SrArray vi(V.size()); for ( i=0; i t; for ( i=0; i> ( SrInput& inp, VertexNode& v ) { return inp; } friend int sr_compare ( const VertexNode* v1, const VertexNode* v2 ) { return v1->v!=v2->v ? v1->v-v2->v // vertices are different : v1->i-v2->i; // vertices are equal: use index i } }; static void insertv ( SrTree& t, SrArray& vi, int v, int f ) { // array vi is only used to generated a suitable tree key sorting the vertices. VertexNode *n = new VertexNode(v,++vi[v],f); if ( !t.insert(n) ) sr_out.fatal_error("Wrong faces in SrModel::smooth ()!\n"); } int SrModel::common_vertices_of_faces ( int i1, int i2 ) { int i, j, c=0; int *f1 = &(F[i1].a); int *f2 = &(F[i2].a); for ( i=0; i<3; i++ ) { for ( j=0; j<3; j++ ) { if ( f1[i]==f2[j] ) c++; //sr_out<& vec, SrArray& vi, SrModel *self, float crease_angle ) { int i, j, tmp; float ang; vec.size(vi.size()); //sr_out<<"original:\n"; //for ( i=0; iF[vi[i]].a<<","<F[vi[i]].b<<","<F[vi[i]].c<common_vertices_of_faces(vi[i],vi[j])==2 ) // share an edge { SR_SWAP(vi[i+1],vi[j]); break; } } } // gen normals for each face around v: for ( i=0; iface_normal ( vi[i] ); } // search for the first edge with a big angle and rearrange array, so // that the array starts with a "crease angled edge": bool angfound = false; for ( i=0; icrease_angle ) { for ( j=0; j<=i; j++ ) { vec.push()=vec[j]; vi.push()=vi[j]; } vec.remove ( 0, i+1 ); vi.remove ( 0, i+1 ); angfound = true; break; } } if ( !angfound ) return; // no crease angles in this face cluster // Finally set the normals: SrVec n; float x=1.0f; int init=0; SrArray& N = self->N; for ( i=0; icrease_angle ) { n = SrVec::null; x = 0.0f; for ( j=init; j<=i; j++ ) { n+=vec[j]; x=x+1.0f; } n /= x; // n is the mean normal of the previous set of smoothed faces around v for ( j=init; j<=i; j++ ) { SrModel::Face &fn=self->Fn[vi[j]]; /*if ( f.n<0 ) { f.n=N.size(); N.insert(N.size(),3); N[f.n]=N[f.a]; N[f.n+1]=N[f.b]; N[f.n+2]=N[f.c]; } if ( v==f.a ) N[f.n]=n; else if ( v==f.b ) N[f.n+1]=n; else N[f.n+2]=n; */ if ( v==fn.a ) fn.a = N.size(); else if ( v==fn.b ) fn.b = N.size(); else fn.c = N.size(); N.push() = n; } init = i+1; } } } void SrModel::smooth ( float crease_angle ) { int v, i; SrTree t; SrArray vi; SrArray vec; // this is just a buffer to be used in gen_normal() if ( !V.size() || !F.size() ) return; Fn.size ( F.size() ); vi.size(V.size()); for ( i=0; iv; vi.push() = t.cur()->f; t.gonext(); if ( t.cur()==SrTreeNode::null || v!=t.cur()->v ) { SrVec n = SrVec::null; for ( i=0; iv; vi.push() = t.cur()->f; t.gonext(); if ( t.cur()==SrTreeNode::null || v!=t.cur()->v ) { gen_normal ( v, vec, vi, this, crease_angle ); vi.size(0); } } remove_redundant_normals (); compress (); } SrVec SrModel::face_normal ( int f ) const { SrVec n; const Face& fac = F[f]; n.cross ( V[fac.b]-V[fac.a], V[fac.c]-V[fac.a] ); n.normalize(); return n; } void SrModel::invert_faces () { int i, tmp; for ( i=0; i0 ) { N.size ( orign+m.N.size() ); for ( i=0; i0 ) { M.size ( origm+m.M.size() ); for ( i=0; i170 ) vr = cross ( SrVec::j, va ); else vr = cross ( SrVec::i, va ); vr.len ( c.radius ); // radial vector SrMat rot; rot.rot ( va, dang ); SrPnt a1 = c.a+vr; SrPnt b1 = c.b+vr; SrPnt a2 = a1 * rot; SrPnt b2 = a2 + vaxis; int i=1; do { if ( smooth ) { N.push()=(a1-c.a)/c.radius; //normalized normal } V.push()=a1; V.push()=b1; if ( i==nfaces ) break; a1=a2; b1=b2; a2=a1*rot; b2=a2+vaxis; i++; } while ( true ); // make sides: int n1, n=0; int i1, i2, i3; int size = V.size(); for ( i=0; i faces; faces.capacity(16); for ( i=0; i=0 ) return (int)faces[closest]; return closest; } //================================ End of File =================================================