Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

bmesh.C

Go to the documentation of this file.
00001 /**********************************************************************
00002  * bmesh.C
00003  **********************************************************************/
00004 #include "std/fstream.H"
00005 #include "std/run_avg.H"
00006 #include "std/stop_watch.H"
00007 #include "std/config.H"
00008 
00009 #include "disp/ray.H"
00010 #include "net/io_manager.H"
00011 
00012 #include "mesh/patch.H"
00013 #include "mesh/uv_data.H"
00014 #include "mesh/base_ref_image.H"
00015 #include "mesh/ioblock.H"
00016 #include "mesh/gtexture.H"
00017 #include "mesh/bfilters.H"
00018 #include "mesh/lmesh.H"      // because of DECODER_ADD(LMESH) hack, below
00019 
00020 using namespace mlib;
00021 
00022 //******** STATICS ********
00023 str_ptr BODY::_base_name = BMESH::static_name();
00024 TAGlist BODY::_body_tags;
00025 
00026 // This makes sure that BMESH is used to create BODY's -
00027 // sub-classes can override this, but it should not be done in a
00028 // static constructor, since static constructor order is fickle
00029 static int dummy = BODY::set_factory(new BMESH);
00030 
00031 bool     BMESH::_random_sils = !Config::get_var_bool("NO_RANDOM_SILS",false);
00032 bool     BMESH::_freeze_sils  = false;
00033 TAGlist* BMESH::_bmesh_tags   = NULL;
00034 TAGlist* BMESH::_bmesh_update_tags   = NULL;
00035 BMESH*   BMESH::_center_of_interest   = 0;
00036 bool     BMESH::_show_secondary_faces = false;
00037 
00038 bool use_new_bface_io = Config::get_var_bool("JOT_USE_NEW_BFACE_IO",true);
00039 
00040 // add BMESH to decoder hash table:
00041 
00042 // XXX - Moved these definitions above
00043 // the LMESH decoder to insure the
00044 // BMESHobs statics are available
00045 // when the LMESH is constructed.
00046 // On WIN32 this wasn't happening...
00047 
00048 BMESHobs_list BMESHobs::_all_observers(32);
00049 HASH          BMESHobs::_hash(300);
00050 
00051 static class DECODERS
00052 {
00053  public:
00054    DECODERS() {
00055       DECODER_ADD(BMESH);
00056       DECODER_ADD(LMESH);
00057    }
00058 }
00059 DECODERS_static;
00060 
00061 BMESH::BMESH(int num_v, int num_e, int num_f) :
00062    _verts(num_v),
00063    _edges(num_e),
00064    _faces(num_f),
00065    _version(1),
00066    _creases(0),
00067    _borders(0),
00068    _polylines(0),
00069    _lone_verts(0),
00070    _sil_stamp(0),
00071    _zx_stamp(0),
00072    _draw_enabled(1),
00073    _pix_size(0),
00074    _pix_size_stamp(0),
00075    _type(EMPTY_MESH),
00076    _type_valid(1),
00077    _geom(0),
00078    _pm_stamp(0),
00079    _eye_local_stamp(0),
00080    _curv_data(0),
00081    _avg_edge_len(0),
00082    _avg_edge_len_valid(0),
00083    _edit_level(0)
00084 {
00085    begin_index();
00086    _drawables.set_unique();
00087 }
00088 
00089 BMESH::BMESH(CBMESH& m) :
00090    _version(1),
00091    _polylines(0),
00092    _lone_verts(0),
00093    _sil_stamp(0),
00094    _zx_stamp(0),
00095    _draw_enabled(1),
00096    _pix_size(0),
00097    _pix_size_stamp(0),
00098    _type(EMPTY_MESH),
00099    _type_valid(1),
00100    _geom(0),
00101    _pm_stamp(0),
00102    _eye_local_stamp(0),
00103    _curv_data(0),
00104    _avg_edge_len(0),
00105    _avg_edge_len_valid(0),
00106    _edit_level(0)
00107 {
00108    begin_index();
00109    _drawables.set_unique();
00110         
00111    *this = m;
00112 }
00113 
00114 BMESH::~BMESH()
00115 {
00116    static bool debug = Config::get_var_bool("DEBUG_BMESH_DESTRUCTOR",false);
00117    if (debug)
00118       err_msg("BMESH::~BMESH called...");
00119 
00120    // Notify observers that it's gonna happen
00121    BMESHobs::broadcast_delete(this);
00122    
00123    // Disable indexing (prevents crash on WIN32 and possibly other OS's):
00124    end_index();
00125 
00126    // then delete mesh elements
00127    delete_elements();
00128 
00129    if (is_center_of_interest(this))
00130       set_center_of_interest(0);
00131 }
00132 
00133 void
00134 BMESH::begin_index()
00135 {
00136    _verts.begin_index();
00137    _edges.begin_index();
00138    _faces.begin_index();
00139 }
00140 
00141 
00142 void
00143 BMESH::end_index()
00144 {
00145    _verts.end_index();
00146    _edges.end_index();
00147    _faces.end_index();
00148 }
00149 
00150 Bvert*
00151 BMESH::add_vertex(Bvert* v)
00152 {
00153    if (v) {
00154       v->set_mesh(this);
00155       _verts += v;
00156    } else
00157       err_msg("BMESH::add_vertex:: error: vertex is nil");
00158    return v;
00159 }
00160 
00161 Bvert*
00162 BMESH::add_vertex(CWpt& loc)
00163 {
00164    return add_vertex(new_vert(loc));
00165 }
00166 
00167 Bvert_list 
00168 BMESH::add_verts(CWpt_list& pts)
00169 {
00170    Bvert_list ret(pts.num());
00171    for (int i=0; i<pts.num(); i++)
00172       ret += add_vertex(pts[i]);
00173    return ret;
00174 }
00175 
00176 Bedge*
00177 BMESH::add_edge(Bedge* e)
00178 {
00179    if (e) {
00180       e->set_mesh(this);
00181       _edges += e;
00182    } else
00183       err_msg("BMESH::add_edge:: error: edge is nil");
00184    return e;
00185 }
00186 
00187 Bedge*
00188 BMESH::add_edge(Bvert* u, Bvert* v)
00189 {
00190    if (!(u && v)) {
00191       err_msg("BMESH::add_edge: Error: vertices are nil");
00192    } else if (u == v) {
00193       err_msg("BMESH::add_edge: Error: repeated vertex");
00194    } else if (!((u->mesh() == this) && (v->mesh() == this))) {
00195       err_msg("BMESH::add_edge: Error: foreign vertices not allowed");
00196    } else {
00197       Bedge* ret = u->lookup_edge(v);
00198       return ret ? ret : add_edge(new_edge(u,v));
00199    }
00200    return 0;
00201 }
00202 
00203 Bedge*
00204 BMESH::add_edge(int i, int j)
00205 {
00206    Bedge* ret = 0;
00207    if (valid_vert_indices(i,j))
00208       ret = add_edge(_verts[i],_verts[j]);
00209    else
00210       err_msg("BMESH::add_edge: invalid vertex indices (%d,%d)", i, j);
00211    return ret;
00212 }
00213 
00214 Bedge*
00215 BMESH::lookup_edge (const Point2i &p)
00216 {
00217    if (!(_verts.valid_index(p[0]) && _verts.valid_index(p[1])))
00218       return 0;
00219    return (::lookup_edge (bv(p[0]), bv(p[1])));
00220 
00221 }
00222 
00223 
00224 Bface*
00225 BMESH::add_face(Bface* f, Patch* p)
00226 {
00227    if (!f) {
00228       err_msg("BMESH::add_face: error: face is nil");
00229       return 0;
00230    }
00231 
00232    f->set_mesh(this);
00233    _faces += f;
00234 
00235    // deal with the patch.
00236    // first do error-check
00237    if (p && p->mesh() != this) {
00238       cerr << "BMESH::add_face: error: patch specified "
00239            << "belongs to a different mesh"  << endl;
00240       p = 0; // reject it
00241    }
00242 
00243    // use the patch if it is given
00244    if (p)
00245       p->add(f);
00246 
00247    return f;
00248 }
00249 
00250 Bface*
00251 BMESH::add_face(Bvert* u, Bvert* v, Bvert* w, Patch* p)
00252 {
00253    // Screen for wackos:
00254    if (!(u && v && w)) {
00255       err_msg("BMESH::add_face: Error: vertices are nil");
00256       return 0;
00257    } else if (u==v || u==w || v==w) {
00258       err_msg("BMESH::add_face: Error: repeated vertex");
00259       return 0;
00260    }
00261    if (!((u->mesh() == this) && (v->mesh() == this) && (w->mesh() == this))) {
00262       err_msg("BMESH::add_face: Error: foreign vertices not allowed");
00263       return 0;
00264    }
00265 
00266    // Is the face already defined?
00267    Bface* tmp = ::lookup_face(u,v,w);
00268    if (tmp) {
00269       // The proposed face already exists.
00270       // This is not considered a problem.
00271       // (Return the existing face).
00272       return tmp;
00273    }
00274 
00275    // Create the edges for the face:
00276    Bedge *e1=add_edge(u,v), *e2=add_edge(v,w), *e3=add_edge(w,u);
00277    if (!(e1 && e2 && e3)) {
00278       err_msg("BMESH::add_face: Error: can't create edges");
00279       return 0;
00280    }
00281    return add_face(new_face(u,v,w,e1,e2,e3), p);
00282 }
00283 
00284 Bface*
00285 BMESH::add_face(int i, int j, int k, Patch* p)
00286 {
00287    if (!valid_vert_indices(i,j,k)) {
00288       err_msg("BMESH::add_face: Error: invalid vertex indices (%d,%d,%d)",
00289               i, j, k);
00290       return 0;
00291    }
00292    return add_face(_verts[i],_verts[j],_verts[k], p);
00293 }
00294 
00295 Bface*
00296 BMESH::add_face(Bvert* u, Bvert* v, Bvert* w, CUVpt& a, CUVpt& b, CUVpt& c, Patch* p)
00297 {
00298    Bface* ret = add_face(u,v,w,p);
00299    if (ret)
00300       UVdata::set
00301          (ret, u, v, w, a, b, c);
00302    return ret;
00303 }
00304 
00305 Bface*
00306 BMESH::add_face(int i, int j, int k, CUVpt& a, CUVpt& b, CUVpt& c, Patch* p)
00307 {
00308    Bface* ret = add_face(i,j,k,p);
00309    if (ret)
00310       UVdata::set
00311          (ret, _verts[i], _verts[j], _verts[k], a, b, c);
00312    return ret;
00313 }
00314 
00315 /*!
00316  * Create the quad defined as follows:
00317  * 
00318  *      x --------  w
00319  *      |         / |
00320  *      |       /   |
00321  *      |     /     |
00322  *      |   /       |
00323  *      | /         |
00324  *      u --------  v
00325  *
00326  * u,v,w,x should form a cycle, i.e., (u,v), (v,w), (w,x) and (x,u) should the edges.
00327  * {u,v,w} and {w,x,u} are the faces created and added.
00328  */
00329 
00330 Bface*
00331 BMESH::add_quad(Bvert* u, Bvert* v, Bvert* w, Bvert* x, Patch* p)
00332 {
00333    Bface* f1 = add_face(u,v,w,p);
00334    Bface* f2 = add_face(u,w,x,p);
00335 
00336    if (f1 && f2) {
00337       Bedge* weak_edge = u->lookup_edge(w);
00338       assert(weak_edge);
00339       weak_edge->set_bit(Bedge::WEAK_BIT);
00340       assert(f1->is_quad());
00341       return f1->quad_rep();
00342    }
00343    if (f1 || f2)
00344       err_msg("BMESH::add_quad: Error: created one face, not the other");
00345    else
00346       err_msg("BMESH::add_quad: Error: couldn't create either face");
00347    return 0;
00348 }
00349 
00350 Bface*
00351 BMESH::add_quad(
00352    Bvert* u, Bvert* v, Bvert* w, Bvert* x,
00353    CUVpt& a, CUVpt& b, CUVpt& c, CUVpt& d, Patch* p)
00354 {
00355    Bface* ret = add_quad(u,v,w,x,p);
00356 
00357    if (ret && !UVdata::set
00358        (u,v,w,x,a,b,c,d))
00359       err_msg("BMESH::add_quad: Error: could not set UV coordinates");
00360 
00361    return ret;
00362 }
00363 
00364 Bface*
00365 BMESH::add_quad(int i, int j, int k, int l, Patch* p)
00366 {
00367    return (
00368       valid_vert_indices(i,j,k,l) ?
00369       add_quad(_verts[i],_verts[j],_verts[k],_verts[l],p) :
00370       0);
00371 }
00372 
00373 Bface*
00374 BMESH::add_quad(int i, int j, int k, int l,
00375                 CUVpt& a, CUVpt& b, CUVpt& c, CUVpt& d, Patch* p)
00376 {
00377    return (
00378       valid_vert_indices(i,j,k,l) ?
00379       add_quad(_verts[i],_verts[j],_verts[k],_verts[l],a,b,c,d,p) :
00380       0);
00381 }
00382 
00383 Bface*
00384 BMESH::lookup_face (const Point3i &p)
00385 {
00386    if (!(_verts.valid_index(p[0]) && _verts.valid_index(p[1])&&
00387          _verts.valid_index(p[2]))) {
00388       cerr << "BMESH::lookup_face - invalid vert index\n";
00389       return 0;
00390    }
00391    return (::lookup_face (bv(p[0]), bv(p[1]), bv(p[2])));
00392 
00393 }
00394 
00395 
00396 void
00397 BMESH::Cube(CWpt& a, CWpt& b, Patch* p)
00398 {
00399    // XXX - desired policy?
00400 //   delete_elements();
00401 
00402    // Create vectors we'll use:
00403    Wvec diag = (b - a);
00404    Wvec dx(diag[0],0,0);
00405    Wvec dy(0,diag[1],0);
00406    Wvec dz(0,0,diag[2]);
00407 
00408    // Create the 8 vertices:
00409    add_vertex(a + dz);
00410    add_vertex(a);
00411    add_vertex(a + dx + dz);
00412    add_vertex(a + dx);
00413    add_vertex(a + dx + dy + dz);
00414    add_vertex(a + dx + dy);
00415    add_vertex(a + dy + dz);
00416    add_vertex(a + dy);
00417 
00418    // setup uv coords:
00419    UVpt u00(0,0), u10(1,0), u11(1,1), u01(0,1);
00420 
00421    // Set up the Patch:
00422    if (p && p->mesh() != this) {
00423       err_msg("BMESH::Cube: foreign patch, rejecting...");
00424       p = 0;
00425    }
00426    if (!p)
00427       p = new_patch();
00428 
00429    // Create the 6 quads with uv-coords:
00430    add_quad(0,1,3,2,u00,u10,u11,u01,p);
00431    add_quad(2,3,5,4,u00,u10,u11,u01,p);
00432    add_quad(4,5,7,6,u00,u10,u11,u01,p);
00433    add_quad(6,7,1,0,u00,u10,u11,u01,p);
00434    add_quad(6,0,2,4,u00,u10,u11,u01,p);
00435    add_quad(5,3,1,7,u00,u10,u11,u01,p);
00436 
00437    changed(TOPOLOGY_CHANGED);
00438 }
00439 
00440 void
00441 BMESH::Octahedron(CWpt& bot, CWpt& m0, CWpt& m1,
00442                   CWpt& m2,  CWpt& m3, CWpt& top, Patch* p)
00443 {
00444    // XXX - desired policy?
00445 //   delete_elements();
00446 
00447    add_vertex(bot);
00448    add_vertex(m0);
00449    add_vertex(m1);
00450    add_vertex(m2);
00451    add_vertex(m3);
00452    add_vertex(top);
00453 
00454    // Set up the Patch:
00455    if (p && p->mesh() != this) {
00456       err_msg("BMESH::Octahedron: foreign patch, rejecting...");
00457       p = 0;
00458    }
00459    if (!p)
00460       p = new_patch();
00461 
00462    add_face(0,1,4,p);
00463    add_face(0,2,1,p);
00464    add_face(0,3,2,p);
00465    add_face(0,4,3,p);
00466 
00467    add_face(5,1,2,p);
00468    add_face(5,2,3,p);
00469    add_face(5,3,4,p);
00470    add_face(5,4,1,p);
00471 
00472    changed(TOPOLOGY_CHANGED);
00473 }
00474 
00475 
00476 //this should generate a radius 1.0 sphere 
00477 //with normals and texture coordinates
00478 //used by skybox
00479 void   
00480 BMESH::Sphere(Patch* p)
00481 {
00482    // XXX - desired policy?
00483 //   delete_elements();
00484 
00485    //sphere mesh resolution 
00486    //values below 4 are impractical
00487    const int RESOLUTION = 16;
00488 
00489    //needs a way to delete existing data here before it starts
00490         
00491 
00492    //stage #1
00493    //creates all of the point rings
00494    //special case at the poles creates single point instead of a ring
00495 
00496    for (int i=0; i<(RESOLUTION+1); i++) { //north to south
00497       for (int j=0; j<(RESOLUTION*2); j++) { //one ring around the sphere
00498          //spherical coordinates of the points
00499          double alpha = (double(j)/double(RESOLUTION*2))*TWO_PI;//(0-360)
00500          double beta  = (double(i)/double(RESOLUTION))*M_PI;//(0-180)
00501 
00502          //3d coordinate
00503          double x = sin(alpha) * sin(beta);
00504          double y = cos(beta);
00505          double z = cos(alpha) * sin(beta);  
00506 
00507          add_vertex(Wpt(x,y,z));
00508                 
00509          if((beta==0)||(beta==M_PI))
00510             break;  //don't put a bunch of identical points at the poles
00511       }
00512    }
00513    // Set up the Patch:
00514    if (p && p->mesh() != this) {
00515       err_msg("BMESH::Sphere: foreign patch, rejecting...");
00516       p = 0;
00517    }
00518    if (!p)
00519       p = new_patch();
00520 
00521    //stage #2
00522    //construct faces
00523 
00524    //pole caps, two triangle fans at the poles
00525    //each triangle fan has a special case triangle 
00526    //that is between the begining and endpoint of a point ring
00527    //texture is somewhat distorted because there is no way to 
00528    //smoothly connect it at the center of the fan
00529 
00530    for (int i=1; i<=(RESOLUTION*2); i++)
00531       add_face(0,i,((i)%(RESOLUTION*2)+1) /*special case */,   
00532                UVpt((double(i)/double(RESOLUTION*2)),1.0),     
00533                UVpt((double(i)/double(RESOLUTION*2)),1.0 -(1.0/double(RESOLUTION+1))),      
00534                UVpt((double(i+1)/double(RESOLUTION*2)),1.0 -(1.0/double(RESOLUTION+1))),    
00535                p);  
00536                 
00537    //south cap is a little more complicated..
00538    int start=((RESOLUTION-2)*((RESOLUTION*2))+1);
00539    int stop= ((RESOLUTION-1)*((RESOLUTION*2)));
00540 
00541    for (int i=start; i<=stop; i++)
00542       add_face((RESOLUTION-1)*((RESOLUTION*2))+1,i,(i==stop ? start : i+1)/*special case face between start and stop */,   
00543                UVpt((double(i)/double(RESOLUTION*2)),0.0),                    
00544                UVpt((double(i+1)/double(RESOLUTION*2)),1.0 -(double(RESOLUTION-1)/double(RESOLUTION+1))),            
00545                UVpt((double(i)/double(RESOLUTION*2)),1.0 -(double(RESOLUTION-1)/double(RESOLUTION+1))),          
00546                p);
00547 
00548         
00549    //quads around the regular sphere rings
00550    for (int j=0; j<(RESOLUTION-2); j++) { //iterate over rings
00551       for (int i=1; i<=(RESOLUTION*2); i++) { //build quad ring
00552          int k = ((RESOLUTION*2)*j)+(i); //index to the points
00553          if (i!= (RESOLUTION*2)) {
00554             add_quad(k,k+(RESOLUTION*2),((k+1))+(RESOLUTION*2),((k+1)),
00555                      UVpt((double(i)/double(RESOLUTION*2)),1.0-(double(j+1)/double(RESOLUTION+1))),
00556                      UVpt((double(i)/double(RESOLUTION*2)),1.0-(double(j+2)/double(RESOLUTION+1))),
00557                      UVpt((double(i+1)/double(RESOLUTION*2)),1.0-(double(j+2)/double(RESOLUTION+1))),
00558                      UVpt((double(i+1)/double(RESOLUTION*2)),1.0-(double(j+1)/double(RESOLUTION+1))),
00559                      p);                                                                                
00560          } else { //ring seem, quad between beginning and end of the ring
00561             add_quad(k,k+(RESOLUTION*2),((k+1)),((k+1))-(RESOLUTION*2),
00562                      UVpt((double(i)/double(RESOLUTION*2)),1.0-(double(j+1)/double(RESOLUTION+1))),
00563                      UVpt((double(i)/double(RESOLUTION*2)),1.0-(double(j+2)/double(RESOLUTION+1))),
00564                      UVpt((double(i+1)/double(RESOLUTION*2)),1.0-(double(j+2)/double(RESOLUTION+1))),
00565                      UVpt((double(i+1)/double(RESOLUTION*2)),1.0-(double(j+1)/double(RESOLUTION+1))),
00566                      p);
00567          }
00568       }
00569    }
00570 
00571    changed(TOPOLOGY_CHANGED);
00572 }// end of sphere function 
00573 
00574 void
00575 BMESH::Icosahedron(Patch* p)
00576 {
00577    // XXX - desired policy?
00578 //   delete_elements();
00579 
00580    add_vertex(Wpt(-.525731112119133606, 0,  .850650808352039932));
00581    add_vertex(Wpt( .525731112119133606, 0,  .850650808352039932));
00582    add_vertex(Wpt(-.525731112119133606, 0, -.850650808352039932));
00583    add_vertex(Wpt( .525731112119133606, 0, -.850650808352039932));
00584 
00585    add_vertex(Wpt(0,  .850650808352039932,  .525731112119133606));
00586    add_vertex(Wpt(0,  .850650808352039932, -.525731112119133606));
00587    add_vertex(Wpt(0, -.850650808352039932,  .525731112119133606));
00588    add_vertex(Wpt(0, -.850650808352039932, -.525731112119133606));
00589 
00590    add_vertex(Wpt( .850650808352039932,  .525731112119133606, 0));
00591    add_vertex(Wpt(-.850650808352039932,  .525731112119133606, 0));
00592    add_vertex(Wpt( .850650808352039932, -.525731112119133606, 0));
00593    add_vertex(Wpt(-.850650808352039932, -.525731112119133606, 0));
00594 
00595    // Set up the Patch:
00596    if (p && p->mesh() != this) {
00597       err_msg("BMESH::Icosahedron: foreign patch, rejecting...");
00598       p = 0;
00599    }
00600    if (!p)
00601       p = new_patch();
00602 
00603    add_face( 0,  1,  4, p);
00604    add_face( 0,  4,  9, p);
00605    add_face( 9,  4,  5, p);
00606    add_face( 4,  8,  5, p);
00607    add_face( 4,  1,  8, p);
00608    add_face( 8,  1, 10, p);
00609    add_face( 8, 10,  3, p);
00610    add_face( 5,  8,  3, p);
00611    add_face( 5,  3,  2, p);
00612    add_face( 2,  3,  7, p);
00613    add_face( 7,  3, 10, p);
00614    add_face( 7, 10,  6, p);
00615    add_face( 7,  6, 11, p);
00616    add_face(11,  6,  0, p);
00617    add_face( 0,  6,  1, p);
00618    add_face( 6, 10,  1, p);
00619    add_face( 9, 11,  0, p);
00620    add_face( 9,  2, 11, p);
00621    add_face( 9,  5,  2, p);
00622    add_face( 7, 11,  2, p);
00623 
00624    changed(TOPOLOGY_CHANGED);
00625 }
00626 
00627 double
00628 BMESH::area() const
00629 {
00630    // XXX - ?
00631    // send_update_notification();
00632 
00633    // sum up the area
00634 
00635    double ret = 0;
00636    for (int k=0; k<_faces.num(); k++)
00637       ret += _faces[k]->area();
00638 
00639    return ret;
00640 }
00641 
00642 double
00643 BMESH::volume() const
00644 {
00645    // sum up the volume
00646    // using the divergence theorem
00647 
00648    double ret = 0;
00649    for (int k=0; k<_faces.num(); k++)
00650       ret += _faces[k]->volume_el();
00651 
00652    return ret;
00653 }
00654 
00655 
00656 /*! \brief Return the approximate memory used for this mesh.
00657  *
00658  * The extra 4 bytes per vertex, edge, etc. is for the
00659  * pointer in the corresponding list (_verts, _edges, etc.).
00660  * For each Bvert we also count the expected number of Bedge*
00661  * pointers in the adjacency list.
00662  */
00663 int
00664 BMESH::size() const
00665 {
00666 
00667    return (
00668       (nverts()   * (sizeof(Bvert) + 6*sizeof(Bedge*) + 4)) +
00669       (nedges()   * (sizeof(Bedge) + 4)) +
00670       (nfaces()   * (sizeof(Bface) + 4)) +
00671       (npatches() * (sizeof(Patch) + 4)) +
00672       sizeof(BMESH)
00673       );
00674 }
00675 
00676 /*! Print info about this mesh to the error text stream */
00677 void
00678 BMESH::print() const
00679 {
00680    err_msg("%s: ", **class_name());
00681    err_msg("\tverts: %6d", _verts.num());
00682    err_msg("\tedges: %6d", _edges.num());
00683    err_msg("\tfaces: %6d", _faces.num());
00684    if (Config::get_var_bool("PRINT_MESH_SIZE",false))
00685       err_msg("\tMbytes used:  %6.1lf", size()/1e6);
00686    cerr << "\ttype: ";
00687    if (is_points())
00688       cerr << "points ";
00689    if (is_polylines())
00690       cerr << "polylines ";
00691    if (is_open_surface())
00692       cerr << "open surface ";
00693    if (is_closed_surface())
00694       cerr << "closed surface ";
00695    cerr << endl;
00696 }
00697 
00698 int
00699 BMESH::set_crease(int i, int j) const
00700 {
00701    Bedge* e = 0;
00702    if (valid_vert_indices(i,j) && (e = bv(i)->lookup_edge(bv(j))))
00703       e->set_crease();
00704    else
00705       err_msg("BMESH::set_crease: error: no such edge (%d,%d)", i, j);
00706    return e ? 1 : 0;
00707 }
00708 
00709 int
00710 BMESH::set_weak_edge(int i, int j) const
00711 {
00712    Bedge* e = 0;
00713    if (valid_vert_indices(i,j) && (e = bv(i)->lookup_edge(bv(j))))
00714       e->set_bit(Bedge::WEAK_BIT);
00715    else
00716       err_msg("BMESH::set_weak_edge: error: no such edge (%d,%d)", i, j);
00717    return e ? 1 : 0;
00718 }
00719 
00720 int
00721 BMESH::set_patch_boundary(int i, int j) const
00722 {
00723    Bedge* e = 0;
00724    if (valid_vert_indices(i,j) && (e = bv(i)->lookup_edge(bv(j))))
00725       e->set_patch_boundary();
00726    else
00727       err_msg("BMESH::set_patch_boundary: error: no such edge (%d,%d)", i, j);
00728    return e ? 1 : 0;
00729 }
00730 
00731 Bface*
00732 BMESH::pick_face(
00733    CWline&      world_ray,      // ray in world space
00734    Wpt&         world_hit       // returned: hit point in world space
00735    ) const
00736 {
00737    // Brute force intersection:
00738    //   Given ray in world space, return intersected face (if any)
00739    //   and intersection point in world space:
00740 
00741    static bool debug = Config::get_var_bool("DEBUG_PICK_FACE",false);
00742    if (debug)
00743       err_msg("BMESH::pick_face: doing brute force intersection");
00744 
00745    Wpt  p = inv_xform() * world_ray.point();
00746    Wvec n = inv_xform() * world_ray.vector();
00747 
00748    Bface* ret = 0;              // face to return
00749    double d, min_d = -1;        // distance, min distance
00750    Wpt    h;                    // (temp) hit point
00751    for (int i=0; i<nfaces(); i++) {
00752       if (bf(i)->ray_intersect(p, n, h, d) && (!ret || d < min_d)) {
00753          min_d     = d;
00754          ret       = bf(i);
00755          world_hit = xform()*h;
00756       }
00757    }
00758    return ret;
00759 }
00760 
00761 int
00762 BMESH::intersect(
00763    RAYhit   &r,         // ray-surface intersection data structure
00764    CWtransf &,          // object to world space xform 
00765    Wpt      &nearpt,    // ray-surface intersection, in world space
00766    Wvec     &n,         // surface normal, world space
00767    double   &d,         // distance to hit point, world space
00768    double   &d2d,       // unused screen-space distance
00769    XYpt     &uvc        // unused texture coordinate
00770    ) const
00771 {
00772    // find visibility reference image for picking:
00773    BaseVisRefImage *vis_ref = BaseVisRefImage::lookup(VIEW::peek());
00774 
00775    // but for special requests we'll still do brute force:
00776    static bool force_face_pick
00777       = Config::get_var_bool("FORCE_FACE_PICK",false);
00778 
00779    if (force_face_pick || !r.from_camera() || !vis_ref) {
00780 
00781       Bface* f = pick_face(r.line(), nearpt);
00782       if (!f)
00783          return 0;
00784 
00785       d = nearpt.dist(r.point());
00786 
00787       // If we know the GEOM, set the RAYhit appropriately
00788       if (_geom && r.test(d,1,0)) {
00789          uvc = XYpt(0,0);
00790          n  = (inv_xform().transpose() * f->norm()).normalized();
00791          Wpt obj_pt = inv_xform() * nearpt;
00792          r.check(d, 1, 0, _geom, n, nearpt, obj_pt, f->patch(), uvc);
00793          BMESHray::set_simplex(r, f); // set 'face' data iff BMESHray
00794       } else {
00795          return 1;
00796       }
00797    }
00798 
00799    // Do reference image picking
00800    vis_ref->vis_update();
00801    Bsimplex* sim = vis_ref->vis_simplex(r.screen_point());
00802    if (!(sim && sim->mesh() == this)) {
00803       return 0;
00804    }
00805 
00806    Wvec norm;
00807    if (sim->view_intersect(r.screen_point(),nearpt,d,d2d,norm) &&
00808        r.test(d,1,0)) {
00809       uvc  = XYpt();
00810       n = norm;         // it's already in world space
00811 
00812       // get the patch in case anyone cares:
00813       // XXX - returning the control patch:
00814       Patch* p = get_ctrl_patch(sim);
00815 
00816       r.check(d, 1, d2d, _geom, n, nearpt, inv_xform()*nearpt, p, uvc);
00817       BMESHray::set_simplex(r, sim);
00818       return 1;
00819    }
00820 
00821    return 0;
00822 }
00823 
00824 void
00825 BMESH::clear_creases()
00826 {
00827    bool changed_occurred = 0;
00828    for (int i=0; i<_edges.num(); i++) {
00829       if (be(i)->is_crease()) {
00830          be(i)->set_crease(0);
00831          changed_occurred=1;
00832       }
00833    }
00834 
00835    if (changed_occurred)
00836       changed(CREASES_CHANGED);
00837 }
00838 
00839 void
00840 BMESH::compute_creases()
00841 {
00842    double thresh = Config::get_var_dbl("JOT_CREASE_THRESH", 0.5, true);
00843 
00844    for (int k = 0; k < _edges.num(); k++)
00845       be(k)->compute_crease(thresh);
00846 
00847    changed(CREASES_CHANGED);
00848 }
00849 
00850 int
00851 BMESH::build_polyline_strips()
00852 {
00853    // if mesh has "polylines" (edges with no adjacent faces)
00854    // then calculate polyline strips so they can be rendered.
00855 
00856    // called e.g. in read_polylines() if needed.
00857 
00858    // reset or allocate polyline edge strip
00859    if (_polylines)
00860       _polylines->reset();
00861    else
00862       _polylines = new_edge_strip(); // an LMESH uses an LedgeStrip
00863 
00864    // add polyline edge strip to 1st patch by default
00865    // (make sure there is at least one patch)
00866    make_patch_if_needed();
00867    _patches[0]->add
00868       (_polylines);
00869 
00870    // find polyline ends; i.e., polyline edges that are
00871    // not adjacent to other polyline edges at both ends.
00872    // prefer to start strips from these polyline ends.
00873    ARRAY<Bedge*> polyline_edges(1024);
00874    ARRAY<Bedge*> polyline_ends (128);
00875    int k;
00876    for (k=0; k<_edges.num(); k++) {
00877       // also clear all edge flags.
00878       _edges[k]->clear_flag();
00879       if (_edges[k]->is_polyline()) {
00880          // collect regular polyline edges in one list,
00881          // and polyline ends into another
00882          if (_edges[k]->is_polyline_end())
00883             polyline_ends  += _edges[k];
00884          else
00885             polyline_edges += _edges[k];
00886       }
00887    }
00888 
00889    // put the polyline ends last
00890    polyline_edges += polyline_ends;
00891 
00892    // work backward to get polyline ends first:
00893    UnreachedSimplexFilter unreached;
00894    PolylineEdgeFilter     polyline;
00895    AndFilter       wanted = unreached + polyline;
00896    for (k=polyline_edges.num()-1; k>=0; k--) {
00897       Bedge* e = polyline_edges[k];
00898       Bvert* v = e->v2()->is_polyline_end() ? e->v2() : e->v1();
00899       _polylines->build(v, e, wanted);
00900    }
00901 
00902    err_msg("BMESH::build_polyline_strips: got %d edges",
00903            _polylines->edges().num());
00904    err_msg("Warning: BMESH does not currently draw polylines");
00905 
00906    return _polylines->num();
00907 }
00908 
00909 int
00910 BMESH::build_vert_strips()
00911 {
00912    // if mesh has isolated vertices, put them in vertext strips so
00913    // they can be rendered.
00914 
00915    // called e.g. in read_stream() if needed.
00916 
00917    // reset or allocate vertex strip
00918    if (_lone_verts)
00919       _lone_verts->reset();
00920    else
00921       _lone_verts = new_vert_strip(); // an LMESH uses an LvertStrip
00922 
00923    // add vertex strip to 1st patch by default
00924    // (make sure there is at least one patch)
00925    if (_patches.empty())
00926       new_patch();
00927    _patches[0]->add
00928       (_lone_verts);
00929 
00930    for (int k=0; k<_verts.num(); k++)
00931       if (bv(k)->degree() == 0)
00932          _lone_verts->add
00933             (bv(k));
00934 
00935    return _lone_verts->num();
00936 }
00937 
00938 int
00939 BMESH::build_zcross_strips()
00940 {
00941    // do nothing if silhouette strips are up-to-date
00942    // or there are no surfaces
00943 
00944    static bool HACK_EYE_POS = Config::get_var_bool("HACK_EYE_POS",false);
00945    static bool DEBUGADAPT = Config::get_var_bool("DEBUG_ADAPTIVE",false);
00946    if ((!(HACK_EYE_POS || DEBUGADAPT ) && ( _zx_stamp == VIEW::stamp())) ||
00947        nfaces() == 0 || _freeze_sils)
00948       return 0;
00949 
00950    static bool debug = Config::get_var_bool("DEBUG_BUILD_ZX_STRIPS",false);
00951    if (debug)
00952       err_msg("BMESH::build_zcross_strips: frame number %d",
00953               (int)VIEW::stamp());
00954 
00955    // clear sil strip lists in patches
00956    int k;
00957    for (k = 0; k<_patches.num(); k++)
00958       _patches[k]->zx_sils().reset();
00959 
00960    // extract sil strips
00961    get_zcross_strips();
00962 
00963    if (_zx_sils.empty())
00964       return 0;
00965    // distribute sils to patches
00966 
00967    Patch*  p = 0;
00968    Patch* lp = _zx_sils.seg(0).f()->patch(); // last p
00969    assert (lp != NULL);
00970 
00971 
00972    for (k = 0; k < _zx_sils.num(); k++) {
00973 
00974       Bface* f = _zx_sils.seg(k).f();
00975       if ( !f && k > 0 )
00976          assert ( _zx_sils.seg(k-1).f() ); //assert for double NULLS
00977 
00978       // null f means that point belongs to last f;
00979       // this accessor is probably less than safe...
00980       if (f) {
00981 
00982          p = f->patch();
00983          assert(p);
00984 
00985          p->zx_sils().add_seg (_zx_sils.seg(k));
00986 
00987          if  ( p != lp ) {
00988             //patch boundary fixit
00989 
00990             if (!lp->zx_sils().segs().empty() && lp->zx_sils().segs().last().f()) {
00991 
00992                lp->zx_sils().add_seg (
00993                   NULL, _zx_sils.seg(k-1).p(), _zx_sils.seg(k-1).v(),
00994                   _zx_sils.seg(k-1).g() , _zx_sils.seg(k-1).bc()
00995                   );
00996             }
00997          }
00998       } else {
00999 
01000          p = lp;
01001          p->zx_sils().add_seg (_zx_sils.seg(k));     //add the termination  marker to the last patch
01002 
01003       }
01004       lp = p;
01005    }
01006 
01007    // call this AFTER get_zcross_strips():
01008    _zx_stamp = VIEW::stamp();
01009 
01010    return _zx_sils.num();
01011 }
01012 
01013 RunningAvg<double> rand_secs(0);  // secs per randomized extraction
01014 RunningAvg<double> brute_secs(0); // secs per brute-force extraction
01015 RunningAvg<double> zx_secs(0);    // secs per zero-cross extraction (randomized)
01016 RunningAvg<double> rand_sils(0);  // avg num sils found randomized
01017 RunningAvg<double> brute_sils(0); // avg num sils found brute-force
01018 RunningAvg<double> zx_sils(0);    // avg num sils found randomized zero-crossing
01019 RunningAvg<double> all_edges(0);  // avg number of total mesh edges
01020 
01021 int
01022 BMESH::get_zcross_strips()
01023 {
01024    static bool REALLY_HACK_EYE_POS = Config::get_var_bool("REALLY_HACK_EYE_POS",false);
01025    static bool HACK_EYE_POS = Config::get_var_bool("HACK_EYE_POS",false);
01026    static bool ALLOW_CHECK_ALL = Config::get_var_bool("ALLOW_CHECK_ALL",false);
01027    static int CHECK_ALL_UNDER = Config::get_var_int ("CHECK_ALL_UNDER", 1000, true);
01028 
01029    ARRAY<ZXseg> old_segs = _zx_sils.segs();
01030 
01031    _zx_sils.reset();
01032    if (HACK_EYE_POS && (geom()->has_transp() | REALLY_HACK_EYE_POS)) {
01033       // get the silhouettes from the position of light4
01034       // (instead of actual camera )
01035       Wpt light_pos;
01036       VIEWptr v = VIEW::peek();
01037       if (v->light_get_in_cam_space(3))
01038          light_pos = v->cam()->xform().inverse() *
01039             v->light_get_coordinates_p(3);
01040 
01041       else
01042          light_pos = v->light_get_coordinates_p(3);
01043 
01044       light_pos = inv_xform() * light_pos;
01045 
01046       _zx_sils.set_eye(light_pos);
01047    } else
01048       _zx_sils.set_eye(eye_local());
01049 
01050    int n = _faces.num();
01051    bool CHECK_ALL = ALLOW_CHECK_ALL && (_faces.num() < CHECK_ALL_UNDER);
01052    static int min_rand_faces = Config::get_var_int("RANDOMIZED_MIN_FACES", 4000, true);
01053    if (n < min_rand_faces               ||      // if too few faces
01054        _zx_stamp < VIEW::stamp() - 1     ||      // or the old sils are too old
01055        old_segs.empty()                 ||      // or there are no old ones
01056        !_random_sils || CHECK_ALL) {            // or sposed to do brute force
01057 
01058       // check all edges to find new sils:
01059       for (int k = 0; k < n ; k++)
01060          _zx_sils.start_sil(_faces[k]);
01061 
01062    } else {
01063       int k,i;
01064 
01065       // We'll time it:
01066       stop_watch clock;
01067 
01068       // get crease and border lists from the mesh.
01069       // check triangles neighboring these edges.
01070       // solves the 'missing silhouettes on cylinders' problem
01071 
01072       // Get the crease and border edges of the mesh via the
01073       // cached strip. (It's lightweight after the first time,
01074       // until creases change again.)
01075       //
01076       CBedge_list& creases = get_creases();
01077       for (i=0; i<creases.num(); i++) {
01078          Bedge* e = creases[i];
01079          if (e && e->f(1))
01080             _zx_sils.start_sil(e->f(1));
01081          if (e && e->f(2))
01082             _zx_sils.start_sil(e->f(2));
01083       }
01084       CBedge_list& borders = get_borders();
01085       for (i=0; i<borders.num(); i++) {
01086          Bedge* e = borders[i];
01087          if (e && e->f(1))
01088             _zx_sils.start_sil(e->f(1));
01089          if (e && e->f(2))
01090             _zx_sils.start_sil(e->f(2));
01091       }
01092 
01093       // Now check old silhoutte triangles:
01094       for (k=0 ; k<old_segs.num(); k++) {
01095          // some old faces are NULL
01096          if (old_segs[k].f())
01097             _zx_sils.start_sil(old_segs[k].f());
01098       }
01099 
01100       // Now do the randomized part:
01101       int maxj = n - 1;
01102       for (k = (int)(2. * sqrt((double)n)); k>0; k--) {
01103          // XXX - On WIN32 drand48() sometimes returns 1.0,
01104          //       so we're careful below to ensure j < n:
01105          int j = min((int)(drand48()*n), maxj);
01106          _zx_sils.start_sil(_faces[j]);
01107       }
01108 
01109       // Record the time taken and number of silhouettes found:
01110       zx_secs.add(clock.elapsed_time());
01111       zx_sils.add(_zx_sils.num());
01112    }
01113 
01114    _zx_stamp = VIEW::stamp();
01115 
01116    return _faces.num();
01117 }
01118 
01119 int
01120 BMESH::build_sil_strips()
01121 {
01122    // do nothing if silhouette strips are up-to-date
01123    if (_sil_stamp == VIEW::stamp() || _freeze_sils)
01124       return 0;
01125 
01126    // clear sil strip lists in patches
01127    int k;
01128    for (k = 0; k<_patches.num(); k++)
01129       _patches[k]->sils().reset();
01130 
01131    // get sil strips
01132    get_sil_strips();
01133 
01134    // distribute sils to patches
01135    Patch* p;
01136    for (k = 0; k < _sils.num(); k++) {
01137       Bedge* e = _sils.edge(k);
01138       Bface* f = e->frontfacing_face();
01139       // if it's a border edge, there may be no front-facing triangle.
01140       // so just take the non-null face:
01141       if (!f)
01142          f = e->get_face();
01143       if (f && (p = f->patch()))
01144          p->sils().add(_sils.vert(k), e);
01145    }
01146 
01147    // call this AFTER get_sil_strips():
01148    _sil_stamp = VIEW::stamp();
01149 
01150    return _sils.num();
01151 }
01152 
01153 int
01154 BMESH::get_sil_strips()
01155 {
01156    // Record number of mesh edges this time:
01157    all_edges.add(nedges());
01158 
01159    // Copy the old sil edges into a temporary list:
01160    Bedge_list old_sils = _sils.edges();
01161 
01162    // clear the old sil strip (clears edge list):
01163    _sils.reset();
01164 
01165    // Make a filter that accepts NEW silhouettes
01166    NewSilEdgeFilter filter(VIEW::stamp(), !show_secondary_faces());
01167 
01168    static int min_rand_edges =
01169       Config::get_var_int("RANDOMIZED_MIN_EDGES", 4000, true);
01170 
01171    if (nedges() < min_rand_edges        ||  // if too few edges
01172        _sil_stamp < VIEW::stamp() - 1   ||  // or old sils are too old
01173        old_sils.empty()                 ||  // or there are no old sils
01174        !_random_sils) {                     // or we're not doing random sils
01175 
01176       // We'll time it:
01177       stop_watch clock;
01178 
01179       // Check all edges to find new sils:
01180       for (int k = 0; k < _edges.num(); k++)
01181          if (_edges[k]->is_sil())
01182             _sils.build(0, _edges[k], filter);  // get all connected sils
01183 
01184       // Record the time taken and number of silhouettes found:
01185       brute_secs.add(clock.elapsed_time());
01186       brute_sils.add(_sils.num());
01187 
01188    } else {
01189       // Randomized algorithm described in:
01190       //    "Real-Time Nonphotorealistic Rendering," by
01191       //    Lee Markosian, Michael A. Kowalski, Samuel J. Trychin,
01192       //    Lubomir D. Bourdev, Daniel Goldstein, John F. Hughes.
01193       //    Proceedings of SIGGRAPH 97.
01194       //
01195       // Assuming the silhouette edges themselves number O(sqrt(n))
01196       // (where n is the total number of edges), then the following
01197       // code runs in O(sqrt(n)) steps.
01198 
01199       // We'll time it:
01200       stop_watch clock;
01201 
01202       // 1. First check all the old ones.
01203       int k;
01204       for (k = 0; k < old_sils.num(); k++)
01205          if (old_sils[k]->is_sil())
01206             _sils.build(0, old_sils[k], filter);
01207 
01208       // 2. Now check a small fraction of the edges.
01209       //    (If n is the total number of edges,
01210       //     we'll check 2 * sqrt(n) edges.)
01211 
01212       int n = _edges.num();
01213       k = (int)(2*sqrt((double)n));
01214       for (int maxj = n - 1; k>0; k--) {
01215          // XXX - On WIN32 drand48() sometimes returns 1.0,
01216          //       so we're careful below to ensure j < n:
01217          int j = min((int)(drand48()*n), maxj);
01218          if (_edges[j]->is_sil())
01219             _sils.build(0, _edges[j], filter);  // get all connected sils
01220       }
01221 
01222       // Record the time taken and number of silhouettes found:
01223       rand_secs.add(clock.elapsed_time());
01224       rand_sils.add(_sils.num());
01225    }
01226 
01227    // Record the frame number for this silhouette extraction:
01228    _sil_stamp = VIEW::stamp();
01229 
01230    return _sils.num();
01231 }
01232 
01233 EdgeStrip 
01234 BMESH::sil_strip() 
01235 {
01236    // extract silhouette edge strip and return a copy of it:
01237    build_sil_strips();
01238    return _sils;
01239 }
01240 
01241 void
01242 BMESH::set_geom(GEOM *geom)
01243 {
01244    if (_geom)
01245       err_msg("BMESH::set_geom: warning: overwriting old geom");
01246    if (!geom)
01247       err_msg("BMESH::set_geom: warning: new geom is null");
01248    _geom = geom;
01249 }
01250 
01251 CWtransf&
01252 BMESH::xform() const 
01253 {
01254    ((BMESH*)this)->_obj_to_world = (_geom ? _geom->obj_to_world() : Identity);
01255    return _obj_to_world;
01256 }
01257 
01258 CWtransf&
01259 BMESH::inv_xform() const 
01260 {
01261    ((BMESH*)this)->_world_to_obj = (_geom ? _geom->world_to_obj() : Identity); 
01262    return _world_to_obj;
01263 }
01264 
01265 CWtransf& 
01266 BMESH::obj_to_ndc() const 
01267 {
01268    if (_pm_stamp != VIEW::stamp()) {
01269       ((BMESH*)this)->_pm_stamp = VIEW::stamp();
01270       ((BMESH*)this)->_pm = VIEW::peek_cam()->ndc_projection() * xform();
01271    }
01272    return _pm;
01273 }
01274 
01275 CWpt& 
01276 BMESH::eye_local() const 
01277 {
01278    // Returns camera position ("eye") in object space ("local coordinates")
01279 
01280    // XXX - Hmm, if the mesh's xform changes, this should
01281    // be recomputed, right?  This stamp should include that
01282    // property... I think...(rdk)
01283    //
01284    // That is correct; though the following probably works in
01285    // practice, since it means the eye local position is updated
01286    // once each frame, if requested.
01287 
01288    if (_eye_local_stamp != VIEW::stamp()) {
01289       ((BMESH*)this)->_eye_local_stamp = VIEW::stamp();
01290       CWpt& eye = VIEW::peek_cam()->data()->from();
01291       ((BMESH*)this)->_eye_local = inv_xform() * eye;
01292    }
01293    return _eye_local;
01294 }
01295 
01296 void
01297 BMESH::make_patch_if_needed()
01298 {
01299    Patch* p = 0;
01300 
01301    for (int k=0; k<_faces.num(); k++) {
01302       if (!bf(k)->patch()) {
01303          if (!p)
01304             p=new_patch();
01305          p->add
01306             (bf(k));
01307       }
01308    }
01309 }
01310 
01311 bool
01312 BMESH::remove_patch(int k)
01313 {
01314    if (!_patches.valid_index(k)) {
01315       err_msg("BMESH::remove_patch: it's not in the list of patches");
01316       return 0;
01317    }
01318    Patch* p = _patches[k];
01319    if (p->num_faces() != 0)
01320       err_msg("BMESH::remove_patch: removed patch, %d faces left stranded",
01321               p->num_faces());
01322    _patches.remove(k);
01323    _drawables -= p;
01324    delete p;
01325    return 1;
01326 }
01327 
01328 void
01329 BMESH::clean_patches()
01330 {
01331    // Clean out any empty patches.
01332 
01333    bool debug = Config::get_var_bool("DEBUG_CLEAN_PATCHES",false);
01334 
01335    // Work backward to remove from the list:
01336    for (int i=_patches.num()-1; i>=0; i--)
01337       if (_patches[i]->num_faces() == 0)
01338          if (remove_patch(i) && debug)
01339             err_msg("BMESH::clean_patches: got one");
01340 
01341 }
01342 
01343 
01344 void
01345 BMESH::send_update_notification()
01346 {
01347    // Send controllers a message to do their mesh modifications now:
01348    BMESHobs::broadcast_update_request(this);
01349 
01350    // LMESH over-rides this to also compute subdivision meshes.
01351 }
01352 
01353 RefImageClient::ref_img_t
01354 BMESH::use_ref_image()
01355 {
01356    return (draw_enabled() ?
01357            _drawables.use_ref_image() : RefImageClient::REF_IMG_NONE);
01358 }
01359 
01360 int
01361 BMESH::draw_vis_ref()
01362 {
01363    if (!draw_enabled())
01364       return 0;
01365 
01366    send_update_notification();
01367 
01368    return _drawables.draw_vis_ref();
01369 }
01370 
01371 int
01372 BMESH::draw_ref_img(ref_img_t t)
01373 {
01374    if (!draw_enabled())
01375       return 0;
01376 
01377    send_update_notification();
01378 
01379    return _drawables.draw_ref_img(t);
01380 }
01381 
01382 int
01383 BMESH::draw(CVIEWptr& v)
01384 {
01385    if (empty() || !draw_enabled())
01386       return 0;
01387 
01388    // Send controllers (e.g. Bsurfaces that operate on this mesh)
01389    // a message to update the mesh if needed:
01390    send_update_notification();
01391 
01392    if (empty()) {
01393       err_msg("BMESH::draw: warning: mesh is empty");
01394       return 0;
01395    }
01396 
01397    int ret = _drawables.draw(v);
01398 
01399    return ret;
01400 }
01401 
01402 void
01403 BMESH::transform(CWtransf &xform, CMOD& m)
01404 {
01405    for (int k=nverts()-1; k>=0; k--)
01406       _verts[k]->transform(xform);
01407 
01408    // XXX - Swapped order of these notifications... (rdk)
01409    //       why? (lem)
01410    BMESHobs::broadcast_xform(this, xform, m);
01411 
01412    changed(VERT_POSITIONS_CHANGED);
01413 }
01414 
01415 CWpt_list &
01416 BMESH::vertices()
01417 {
01418    if (!_vert_locs.empty() || _verts.empty())
01419       return _vert_locs;
01420 
01421    _vert_locs.realloc(nverts());
01422    for (int k=nverts()-1; k>=0; k--)
01423       _vert_locs += _verts[k]->loc();
01424    return _vert_locs;
01425 }
01426 
01427 void
01428 BMESH::triangulate(Wpt_list &verts, FACElist &faces)
01429 {
01430    verts.clear();
01431    faces.clear();
01432    if (nverts() > 0)
01433       verts.realloc(_verts.num());
01434    if (nfaces() > 0)
01435       faces.realloc(_faces.num());
01436 
01437    int i;
01438    for (i=0; i<nverts(); i++)
01439       verts += bv(i)->loc();
01440    for (i=0; i<nfaces(); i++)
01441       faces += Point3i(bf(i)->v(1)->index(),
01442                        bf(i)->v(2)->index(),
01443                        bf(i)->v(3)->index());
01444 }
01445 
01446 BMESHptr
01447 BMESH::read_jot_file(char* filename, BMESHptr ret)
01448 {
01449    // Opens the file and calls BMESH::read_jot_stream().
01450    
01451    if (!filename) {
01452       err_msg("BMESH::read_jot_file() - Filename is NULL");
01453       return 0;
01454    }
01455    fstream fin;
01456 #if (defined (WIN32) && (defined(_MSC_VER) && (_MSC_VER <=1300))) /*VS 6.0*/
01457 
01458    fin.open(filename, ios::in | ios::nocreate);
01459 #else
01460 
01461    fin.open(filename, ios::in);
01462 #endif
01463 
01464    if (!fin) {
01465       err_mesg(ERR_LEV_WARN, "BMESH::read_jot_file() - Could not open file '%s'", filename);
01466       return 0;
01467    }
01468 
01469    return read_jot_stream(fin, ret);
01470 }
01471 
01472 BMESHptr
01473 BMESH::read_jot_stream(istream& in, BMESHptr ret)
01474 {
01475    // Read a mesh from a stream and return it.  Handles new
01476    // .jot or .sm formats, as well as old .sm format. If ret
01477    // is null, a new mesh will be generated (BMESH or LMESH,
01478    // depending on what type is specified in the stream). If
01479    // ret is a BMESH and the file specifies LMESH, an LMESH is
01480    // generated, read from the stream, and then the mesh data
01481    // is copied into ret.
01482 
01483    // Run thru initial whitespace
01484    while (isspace(in.peek()))
01485       in.get();
01486 
01487    // If the first character isn't printable, reject it
01488    char firstchar = in.peek();
01489 
01490    if (!isprint(firstchar)) {
01491       err_msg("BMESH::read_jot_stream() - Unreadable: Non-printable first character.");
01492       return 0;
01493    } else if (isdigit(firstchar)) {
01494       // If it's numerical digit then try to load as old .sm
01495       // This will go away...
01496       if (!ret) {
01497          ret = new LMESH; // use LMESH by default for old .sm files
01498       }
01499       if (ret->read_stream(in)) {
01500          return ret;
01501       } else {
01502          err_msg("BMESH::read_jot_stream() - Error: Failed parsing old-style file.");
01503          return 0;
01504       }
01505    } else if (firstchar == '#') {
01506       // If it's a # then fail out...
01507       char file_header[2048];
01508       in.get();
01509       in >> file_header;
01510 
01511       err_mesg(ERR_LEV_INFO,
01512                "BMESH::read_jot_stream() - Warning: Rejecting file with '#%s' header.",
01513                file_header);
01514       return 0;
01515    } else {
01516       // Otherwise, it better be the new .sm format...
01517       STDdstream stream(&in);
01518 
01519       // Check the class name:
01520       str_ptr class_name;
01521       stream >> class_name;
01522 
01523       // If we don't yet have a mesh, or the mesh we have is the wrong
01524       // type, then get one of the right type:
01525       if (!(ret && ret->is_of_type(class_name))) {
01526          DATA_ITEM* di = DATA_ITEM::lookup(class_name);
01527          if (!di) {
01528             err_msg(
01529                "BMESH::read_jot_stream() - Error: Supposed mesh class '#%s' not found.",
01530                **class_name);
01531             return 0;
01532          }
01533 
01534          // Get the correct type (BMESH or LMESH) as specified in the file:
01535          ret = upcast(di->dup());
01536          if (!ret) {
01537             err_msg(
01538                "BMESH::read_jot_stream() - Error: Class '#%s' is not a BMESH subclass.",
01539                **class_name);
01540             return 0;
01541          }
01542       }
01543 
01544       ret->decode(stream);
01545       return ret;
01546    }
01547 }
01548 
01549 bool
01550 BMESH::read_file(char* filename)
01551 {
01552    // Read a mesh file into *this* mesh:
01553 
01554    BMESHptr mesh = read_jot_file(filename, this);
01555    if (!mesh)
01556       return false;
01557 
01558    // In case this is a BMESH, but the file specified an LMESH,
01559    // then read_jot_file() would have returned an LMESH. Now
01560    // copy its data into this mesh:
01561    if (this != &*mesh)
01562       *this = *mesh;
01563 
01564    return true;
01565 }
01566 
01567 // XXX - Deprecated (now TEXBODY's mesh_data_update_file tag
01568 //       also just uses read_file)
01569 int
01570 BMESH::read_update_file(char* filename)
01571 {
01572    if (!filename) {
01573       err_ret( "BMESH::read_update_file: filename is NULL");
01574       return 0;
01575    }
01576 
01577    ifstream fin;
01578    fin.open(filename);
01579    if (!fin) {
01580       err_ret( "BMESH::read_update_file: could not open file %s", filename);
01581       return 0;
01582    }
01583 
01584    int ret = 1;
01585 
01586    if (!read_update_stream(fin)) {
01587       err_msg("BMESH::read_update_file: error reading file %s", filename);
01588       ret = 0;
01589    }
01590 
01591    return ret;
01592 }
01593 
01594 // XXX - Deprecated
01595 int
01596 BMESH::read_update_stream(istream& is)
01597 {
01598    // read header
01599    if (!read_header(is))
01600       return 0;                 // stop if an error occurred
01601 
01602    // read vertices
01603    int ret = read_vertices(is);
01604 
01605    if (ret) {
01606       // must do this after changing mesh:
01607       changed(VERT_POSITIONS_CHANGED);
01608    }
01609 
01610 
01611    return ret;
01612 }
01613 
01614 
01615 // XXX - Deprecated
01616 int
01617 BMESH::read_stream(istream& is)
01618 {
01619    // free up current data
01620    delete_elements();
01621 
01622    // read header
01623    if (!read_header(is))
01624       return 0;                 // stop if an error occurred
01625 
01626    // read vertices
01627    int ret = read_vertices(is);
01628 
01629    // read faces
01630    ret = ret && read_faces(is);
01631 
01632    if (!ret) {
01633       // must do this after changing mesh:
01634       changed(TOPOLOGY_CHANGED);
01635       make_patch_if_needed();
01636       return 0;
01637    }
01638 
01639    // read creases
01640    // XXX - changed so errors here don't abort the process
01641    read_creases(is);
01642 
01643    // read edges without faces
01644    // XXX - changed so errors here don't abort the process
01645    read_polylines(is);
01646 
01647    // must do this after changing mesh:
01648    changed(TOPOLOGY_CHANGED);
01649 
01650    // now the topological type is determined; if there are lone
01651    // vertices store them in vertex strips.
01652    if (is_points() && Config::get_var_bool("BMESH_BUILD_VERT_STRIPS",false))
01653       build_vert_strips();
01654 
01655    // continue reading the file but now check for tokens
01656    ret = ret && read_blocks(is);
01657 
01658    // If faces were read in, but no Patches were created,
01659    // make a Patch now and put all the faces in:
01660    make_patch_if_needed();
01661 
01662    // Problem:
01663    //   read_faces() creates a default patch.  Then sometimes
01664    //   patches are read in from file, whereupon they take the
01665    //   faces away from the default patch, which is left
01666    //   empty. For reasons no one understands, this leads to seg
01667    //   faults in the optimized build (on linux).
01668    //
01669    // Solution:
01670    //   Don't do that. I.e., remove the empty patch.
01671    clean_patches();
01672 
01673    return ret;
01674 }
01675 
01676 int
01677 BMESH::read_blocks(istream &is)
01678 {
01679    if (Config::get_var_bool("JOT_SKIP_IOBLOCKS",false))
01680       return true;
01681 
01682    static IOBlockList blocklist;
01683    if (blocklist.num() == 0) {
01684       blocklist += new IOBlockMeth<BMESH>("COLORS",
01685                                           &BMESH::read_colors, this);
01686       blocklist += new IOBlockMeth<BMESH>("TEX_COORDS2",
01687                                           &BMESH::read_texcoords2, this);
01688       blocklist += new IOBlockMeth<BMESH>("WEAK_EDGES",
01689                                           &BMESH::read_weak_edges, this);
01690       blocklist += new IOBlockMeth<BMESH>("PATCH",
01691                                           &BMESH::read_patch,  this);
01692       blocklist += new IOBlockMeth<BMESH>("INCLUDE",
01693                                           &BMESH::read_include, this);
01694 
01695    } else {
01696       for (int i = 0; i < blocklist.num(); i++) {
01697          ((IOBlockMeth<BMESH> *) blocklist[i])->set_obj(this);
01698       }
01699    }
01700    str_list leftover;
01701    int ret = IOBlock::consume(is, blocklist, leftover);
01702    // Put leftover words back on stream
01703    for (int w = 0; w < leftover.num(); w++) {
01704       str_ptr str = leftover[w];
01705       is.putback(' ');
01706       for (int i = str.len()-1; i >= 0; i--) {
01707          is.putback(str[i]);
01708       }
01709    }
01710 
01711 
01712    return ret;
01713 }
01714 
01715 int
01716 BMESH::read_include(istream& is, str_list &/*leftover*/)
01717 {
01718    const int len = 1024;
01719    char buff[len];
01720    is >> buff;
01721    ifstream fin;
01722    fin.open(buff);
01723    if (!fin) {
01724       err_ret( "BMESH::read_include: could not open include file %s", buff);
01725       return 0;
01726    }
01727    return read_blocks(fin);
01728 }
01729 
01730 int
01731 BMESH::read_header(istream& is)
01732 {
01733    char file_header[256];
01734    char firstchar = is.peek();
01735 
01736    // If the first character isn't printable, bad!
01737    if (!isprint(firstchar))
01738       return 0;
01739 
01740    // Not a #<header>, then return a success...
01741    if (firstchar != '#')
01742       return 1;
01743 
01744 
01745    is.get();
01746    is >> file_header;
01747    if (is.bad() || is.eof())
01748       return 0;
01749 
01750    if (strstr(file_header, "jot")) {
01751       err_msg("BMESH::read_header() - Trying to read a file with #jot header, stopping...");
01752       return 0;
01753    } else {
01754       err_msg("BMESH::read_header() - Reading a file with %s header...",file_header);
01755       return 1;
01756    }
01757 
01758 }
01759 
01760 int
01761 BMESH::read_vertices(istream& is)
01762 {
01763    int n;
01764    is >> n;
01765    if (is.bad() || is.eof()) {
01766       return 0;
01767    }
01768 
01769    _verts.realloc(n);
01770    _edges.realloc(3*n);
01771 
01772    for (int i=0 ; i<n; i++) {
01773       double x, y, z;
01774       is >> x >> y >> z;
01775 
01776       if (i<_verts.num())
01777          _verts[i]->set_loc(Wpt(x,y,z));
01778       else
01779          add_vertex(Wpt(x,y,z));
01780    }
01781 
01782    return 1;
01783 }
01784 
01785 int
01786 BMESH::read_faces(istream& is)
01787 {
01788    int n = 0, i, j, k;
01789    is >> n;
01790    if (is.bad())
01791       return 0;
01792 
01793    if (n>0)
01794       _faces.realloc(n);
01795 
01796    int ret = 1; // really it's a bool (1 == success)
01797 
01798    for ( ; n>0 && !is.eof(); n--) {
01799 
01800       // Read 3 vertex indices:
01801       is >> i >> j >> k;
01802 
01803       // Create the face:
01804       if (!add_face(i,j,k,0))
01805          ret = 0;       // not success
01806    }
01807 
01808    return ret;
01809 }
01810 
01811 int
01812 BMESH::read_creases(istream& is)
01813 {
01814    // read vertex pairs corresponding to "crease" edges
01815    // mark vertices and edges w/ crease tag.
01816 
01817    int n;
01818    is >> n;
01819 
01820    int ret = 1;
01821    if (is.bad()) {
01822       err_ret( "BMESH::read_creases: istream is bad");
01823       return 0;
01824    }
01825    for (int k=0; k<n && !is.eof(); k++) {
01826       int i, j;
01827       is >> i >> j;
01828       if (!set_crease(i,j))
01829          ret = 0;
01830    }
01831 
01832    return ret;
01833 }
01834 
01835 int
01836 BMESH::read_weak_edges(istream& is, str_list &leftover)
01837 {
01838    leftover.clear();
01839 
01840    if (is.bad()) {
01841       err_ret( "BMESH::read_weak_edges: istream is bad");
01842       return 0;
01843    }
01844 
01845    int n, ret = 1;
01846    is >> n;
01847    for (int k=0; k<n && !is.eof(); k++) {
01848       int i, j;
01849       is >> i >> j;
01850       if (!set_weak_edge(i,j))
01851          ret = 0;
01852    }
01853 
01854    return ret;
01855 }
01856 
01857 int
01858 BMESH::read_polylines(istream& is)
01859 {
01860    // read vertex pairs corresponding to
01861    // lone edges (without faces)
01862 
01863    int n;
01864    is >> n;
01865 
01866    int ret = 1;
01867    if (is.bad()) {
01868       err_ret( "BMESH::read_creases: istream is bad");
01869       ret = 0;
01870    } else {
01871       for (int k=0; k<n && !is.eof(); k++) {
01872          int i, j;
01873          is >> i >> j;
01874          if (!add_edge(i,j))
01875             ret = 0;
01876       }
01877    }
01878 
01879    if (Config::get_var_bool("BMESH_BUILD_POLYSTRIPS",false) && n > 0)
01880       build_polyline_strips();
01881 
01882    return ret;
01883 }
01884 
01885 int
01886 BMESH::read_colors(istream& is, str_list &leftover)
01887 {
01888    leftover.clear();
01889    for (int i = 0; i< nverts(); i++) {
01890       double r,g,b;
01891       is >> r >> g >> b;
01892       bv(i)->set_color( COLOR(r,g,b));
01893    }
01894 
01895    return 1;
01896 }
01897 
01898 
01899 int
01900 BMESH::read_texcoords2(istream& is, str_list &leftover)
01901 {
01902    static double UV_RESOLUTION = Config::get_var_dbl("UV_RESOLUTION",0,true);
01903 
01904    leftover.clear();
01905    int n;
01906    is >> n;
01907    for (int i = 0; i<n; i++) {
01908       UVpt uv[3];
01909       int k;
01910       is >> k >> uv[0] >> uv[1] >> uv[2];
01911       if (_faces.valid_index(k)) {
01912          // Round UV's to nearest UV_RESOLUTION
01913          // A value of 0.00001 is nice...
01914          if (UV_RESOLUTION>0) {
01915             for (int j=0; j<3; j++) {
01916                double r;
01917                uv[j][0] -= r = fmod(uv[j][0],UV_RESOLUTION);
01918                if (2.0*fabs(r) > UV_RESOLUTION)
01919                   uv[j][0] += ((r>0)?(UV_RESOLUTION):(-UV_RESOLUTION));
01920                uv[j][1] -= r = fmod(uv[j][1],UV_RESOLUTION);
01921                if (2.0*fabs(r) > UV_RESOLUTION)
01922                   uv[j][1] += ((r>0)?(UV_RESOLUTION):(-UV_RESOLUTION));
01923             }
01924          }
01925 
01926          UVdata::set
01927             (bf(k),uv[0], uv[1], uv[2]);
01928       } else
01929          err_msg("BMESH::read_texcoords2: invalid face index %d", k);
01930    }
01931 
01932    return 1;
01933 }
01934 
01935 int
01936 BMESH::read_patch(istream& is, str_list &leftover)
01937 {
01938    return new_patch()->read_stream(is, leftover);
01939 }
01940 
01941 int
01942 BMESH::write_file(char* filename)
01943 {
01944    fstream fout;
01945    fout.open(filename, ios::out);
01946 
01947    if (!fout) {
01948       err_msg("BMESH::write_file: error: could not open file: %s", filename);
01949       return 0;
01950    }
01951 
01952    STDdstream stream(&fout);
01953    format(stream);
01954    fout.close();
01955 
01956    return 1;
01957 }
01958 
01959 int
01960 BMESH::write_stream(ostream& os)
01961 {
01962    // Write new-style .sm file:
01963 
01964    STDdstream out(&os);
01965    format(out);
01966    os << endl;
01967 
01968    return 1;
01969 }
01970 
01971 int
01972 BMESH::write_vertices(ostream& os) const
01973 {
01974    os << nverts() << endl;
01975    if (os.bad())
01976       return 0;
01977 
01978    bool xform_mesh = Config::get_var_bool("JOT_SAVE_XFORMED_MESH",false);
01979 
01980    Wpt p;
01981    for (int i = 0; i< nverts(); i++) {
01982       if (xform_mesh)
01983          p = bv(i)->wloc();
01984       else
01985          p = bv(i)->loc();
01986       os << p[0] << " " << p[1] << " " << p[2] << endl;
01987    }
01988 
01989    return 1;
01990 }
01991 
01992 int
01993 BMESH::write_colors(ostream& os) const
01994 {
01995    // if there are colors, write them
01996 
01997    if (!_verts.empty() && bv(0)->has_color()) {
01998       //if one vertex has a color, they all do
01999       if (os.bad())
02000          return 0;
02001 
02002       os << "#BEGIN COLORS" << endl;
02003       for (int i = 0; i< nverts(); i++) {
02004          const COLOR& c = bv(i)->color();
02005          os << c[0] << " "
02006             << c[1] << " "
02007             << c[2] << " " << endl;
02008       }
02009       os << "#END COLORS" << endl;
02010    }
02011 
02012    return 1;
02013 }
02014 
02015 int
02016 BMESH::write_texcoords2(ostream& os) const
02017 {
02018    // New version replacing write_texcoords(), but for now
02019    // leaving that one there in case some old files use it
02020 
02021    if (os.bad())
02022       return 0;
02023 
02024    // Find out how many faces have tex coords:
02025    int count=0, k;
02026    for (k=0; k<nfaces(); k++)
02027       if (UVdata::lookup(bf(k)))
02028          count++;
02029 
02030    // If none, bail early
02031    if (count == 0)
02032       return 1;
02033 
02034    // Need to work it
02035    os << "#BEGIN TEX_COORDS2" << endl;
02036    os << count << endl;
02037    for (k=0; k<nfaces(); k++) {
02038       UVdata* uvdata = UVdata::lookup(bf(k));
02039       if (uvdata) {
02040          os << k << " "
02041             << uvdata->uv(1) << " "
02042             << uvdata->uv(2) << " "
02043             << uvdata->uv(3) << endl;
02044       }
02045    }
02046    os << "#END TEX_COORDS2" << endl;
02047 
02048    return 1;
02049 }
02050 
02051 int
02052 BMESH::write_faces(ostream& os) const
02053 {
02054    os << nfaces() << endl;
02055    if (os.bad())
02056       return 0;
02057 
02058    for (int i = 0; i< nfaces(); i++)
02059       os << *bf(i);
02060 
02061    return 1;
02062 }
02063 
02064 int
02065 BMESH::write_creases(ostream& os) const
02066 {
02067    if (nedges()<1 || os.bad())
02068       return 0;
02069 
02070    static ARRAY<Bedge*> creases(512);
02071 
02072    creases.clear();
02073 
02074    int k;
02075    for (k=0; k<nedges(); k++)
02076       if (be(k)->is_crease())
02077          creases += be(k);
02078 
02079    os << creases.num() << endl;
02080    while (!creases.empty())
02081       os << *creases.pop() << endl;
02082 
02083    os << endl;
02084 
02085    return 1;
02086 }
02087 
02088 int
02089 BMESH::write_weak_edges(ostream& os) const
02090 {
02091    if (os.bad())
02092       return 0;
02093 
02094    ARRAY<Bedge*> weak_edges(nedges());
02095 
02096    for (int k=0; k<nedges(); k++)
02097       if (be(k)->is_weak())
02098          weak_edges += be(k);
02099 
02100    if (!weak_edges.empty()) {
02101 
02102       os << "#BEGIN WEAK_EDGES" << endl;
02103       os << weak_edges.num() << endl;
02104       while (!weak_edges.empty())
02105          os << *weak_edges.pop() << endl;
02106       os << endl;
02107 
02108       os << "#END WEAK_EDGES" << endl;
02109    }
02110 
02111    return 1;
02112 }
02113 
02114 int
02115 BMESH::write_patches(ostream& os) const
02116 {
02117    if (_patches.empty() || Config::get_var_bool("TMOD_DONT_WRITE_PATCHES",false))
02118       return 1;
02119 
02120    // Write out patch info
02121    if (_patches[0]->cur_tex()) {
02122       if (os.bad())
02123          return 0;
02124 
02125       _patches.write_stream(os);
02126    }
02127    return 1;
02128 }
02129 
02130 int
02131 BMESH::write_polylines(ostream& os) const
02132 {
02133    if (nedges()<1 || os.bad())
02134       return 0;
02135 
02136    // XXX - use _polylines
02137    static ARRAY<Bedge*> polylines(256);
02138 
02139    polylines.clear();
02140 
02141    int k;
02142    for (k=0; k<nedges(); k++)
02143       if (be(k)->is_polyline())
02144          polylines += be(k);
02145 
02146    os << polylines.num() << endl;
02147    while (!polylines.empty())
02148       os << *polylines.pop() << endl;
02149 
02150    os << endl;
02151 
02152    return 1;
02153 }
02154 
02155 void
02156 BMESH::delete_elements()
02157 {
02158    _drawables.clear();
02159 
02160    _patches.delete_all();
02161 
02162    // delete mesh elements, faces first,
02163    // since deleting a vert will also delete adjacent
02164    // edges and faces.
02165    _faces.delete_all();
02166    _edges.delete_all();
02167    _verts.delete_all();
02168 
02169    _type = EMPTY_MESH;
02170    _type_valid = 1;
02171 }
02172 
02173 BMESH&
02174 BMESH::operator =(CBMESH& m)
02175 {
02176    delete_elements();
02177 
02178    _type       = m._type;
02179    _type_valid = m._type_valid;
02180 
02181    if (m.nverts() > 0)
02182       _verts.realloc(m._verts.num());
02183    if (m.nedges() > 0)
02184       _edges.realloc(m._edges.num());
02185    if (m.nfaces() > 0)
02186       _faces.realloc(m._faces.num());
02187 
02188    // copy verts
02189    int k;
02190    for (k=0; k<m.nverts(); k++) {
02191       Bvert* v_old = m.bv(k);
02192       Bvert* v_new = add_vertex(v_old->loc());
02193       if (v_old->has_color())
02194          v_new->set_color(v_old->color());
02195    }
02196 
02197    // copy edges
02198    for (k=0; k<m.nedges(); k++) {
02199       Bedge* e_old = m.be(k);
02200       Bedge* e_new = add_edge(e_old->v1()->index(), e_old->v2()->index());
02201       if (e_old->is_crease())
02202          e_new->set_crease(e_old->crease_val());
02203       if (e_old->is_patch_boundary())
02204          e_new->set_patch_boundary();
02205       if (e_old->is_weak())
02206          e_new->set_bit(Bedge::WEAK_BIT);
02207    }
02208 
02209    // XXX - doesn't copy patches yet
02210    Patch* p = new_patch();
02211 
02212    // copy faces
02213    for (k=0; k<m.nfaces(); k++) {
02214       Bface* f_old = m.bf(k);
02215       Bface* f_new = add_face(f_old->v1()->index(),
02216                               f_old->v2()->index(),
02217                               f_old->v3()->index(), p);
02218       if (f_old->is_secondary())
02219          f_new->make_secondary();
02220    }
02221 
02222    changed(TRIANGULATION_CHANGED);
02223 
02224    return *this;
02225 }
02226 
02227 BMESH&
02228 BMESH::operator =(BODY& body)
02229 {
02230    if (body.is_of_type(static_name()))
02231       return *this = *((BMESH*)&body);
02232 
02233    delete_elements();
02234 
02235    Wpt_list pts;
02236    FACElist     tris;
02237    body.triangulate(pts, tris);
02238    if (pts.num() && tris.num()) {
02239       _verts.realloc(pts.num());
02240       _faces.realloc(tris.num());
02241       _edges.realloc(tris.num()*3/2+10);
02242       int i;
02243       for (i = 0; i < pts.num(); i++)
02244          add_vertex(pts[i]);
02245       Patch* p = new_patch();
02246       for (i = 0; i < tris.num(); i++)
02247          add_face(tris[i][0], tris[i][1], tris[i][2], p);
02248 
02249       // Set normals etc.
02250       changed(TOPOLOGY_CHANGED);
02251 
02252       // automatically mark creases by dihedral angle
02253       if (!Config::get_var_bool("SUPPRESS_CREASES",false)) {
02254          for (int k= nedges()-1; k>=0; k--)
02255             be(k)->compute_crease(0.5);
02256       }
02257    }
02258 
02259    return *this;
02260 }
02261 
02262 
02263 void
02264 BMESH::delete_patches()
02265 {
02266    _patches.delete_all();
02267 }
02268 
02269 int
02270 BMESH::check_type()
02271 {
02272    // check what type of mesh this is:
02273    //   POINTS,         (has isolated vertices)
02274    //   POLYLINES,      (has edges w/ no faces)
02275    //   OPEN_SURFACE,   (has some edges adjacent to just 1 face)
02276    //   CLOSED_SURFACE  (has faces; no edge adjacent to just 1 face)
02277    //
02278    // can also be a combination of the above types
02279    // (e.g. closed surface with additional isolated vertices)
02280    // except OPEN_SURFACE and CLOSED_SURFACE are mutually exclisive.
02281 
02282    // set _type_valid because we're checking the type now
02283    _type_valid = 1;
02284    _type = EMPTY_MESH;
02285 
02286    // get ready to count stuff
02287    int num_isolated_verts = 0,
02288       num_isolated_edges = 0,
02289       num_border_edges = 0,
02290       num_inconsistent_edges = 0;
02291 
02292    // check for isolated vertices:
02293    int k;
02294    for (k=0; k<_verts.num(); k++)
02295       if (bv(k)->degree() == 0)
02296          num_isolated_verts++;
02297 
02298    if (num_isolated_verts > 0)
02299       _type |= POINTS;
02300 
02301    // check for isolated edges, border edges,
02302    // and inconsistently oriented edges:
02303    for (k=0; k<_edges.num(); k++) {
02304       if (be(k)->nfaces() == 0)
02305          num_isolated_edges++;
02306       else if (be(k)->nfaces() == 1)
02307          num_border_edges++;
02308       else if (!be(k)->consistent_orientation())
02309          num_inconsistent_edges++;
02310    }
02311 
02312    // check for "polyline" edges
02313    if (num_isolated_edges > 0)
02314       _type |= POLYLINES;
02315 
02316    // check for closed/open surface.
02317    // (for closed surfaces can do backface culling, e.g.):
02318    if (num_border_edges > 0)
02319       _type |= OPEN_SURFACE;
02320    else if (nfaces() > 0)
02321       _type |= CLOSED_SURFACE;
02322 
02323    // XXX - may not be needed
02324    for (k=0; k<nfaces(); k++)
02325       _faces[k]->orient_strip(0);
02326 
02327    // deal with inconsistently oriented edges if needed.
02328    if (num_inconsistent_edges > 0) {
02329       err_msg("BMESH::check_type: inconsistently oriented faces found...");
02330       if (Config::get_var_bool("NO_FIX_ORIENTATION",false)) {
02331          err_msg("...leaving it as is");
02332       } else {
02333          if (fix_orientation())
02334             err_msg("fixed it");
02335          else
02336             err_msg("can't fix it");
02337       }
02338    }
02339 
02340    return _type;
02341 }
02342 
02343 bool
02344 BMESH::fix_orientation()
02345 {
02346    if (Config::get_var_bool("NO_FIX_ORIENTATION",false))
02347       return false;
02348 
02349    bool debug = Config::get_var_bool("DEBUG_FIX_ORIENTATION",false);
02350 
02351    _faces.clear_flags();
02352 
02353    ARRAY<Bface*> pos_faces;
02354    ARRAY<Bface*> neg_faces;
02355    for (int k=0; k<_faces.num(); k++) {
02356       if (!_faces[k]->flag()) {
02357          if (debug)
02358             err_msg("fix_orientation: starting on untouched face...");
02359          pos_faces.clear();
02360          neg_faces.clear();
02361          _faces[k]->set_flag(1);
02362          pos_faces += _faces[k];
02363          grow_oriented_face_lists(_faces[k], pos_faces, neg_faces);
02364          reverse_faces((pos_faces.num() < neg_faces.num()) ?
02365                        pos_faces : neg_faces);
02366       }
02367    }
02368    changed(TRIANGULATION_CHANGED);
02369 
02370    // check consistency (e.g. surface is not orientable)
02371    int num_inconsistent_edges = 0;
02372    for (int j=0; j<_edges.num(); j++)
02373       if (!_edges[j]->consistent_orientation())
02374          num_inconsistent_edges++;
02375 
02376    if (num_inconsistent_edges > 0)
02377       err_msg("BMESH::fix_orientation: still found %d inconsistent edges!",
02378               num_inconsistent_edges);
02379 
02380    return (num_inconsistent_edges == 0);
02381 }
02382 
02383 void
02384 BMESH::grow_oriented_face_lists(
02385    Bface* f,
02386    ARRAY<Bface*>& pos_faces,
02387    ARRAY<Bface*>& neg_faces)
02388 {
02389    for (int i=1; i<=3; i++) {
02390       Bface* nbr = f->nbr(i);
02391       if (nbr && !nbr->flag()) {
02392          nbr->set_flag(1);
02393          if (f->e(i)->consistent_orientation()) {
02394             pos_faces += nbr;
02395             grow_oriented_face_lists(nbr, pos_faces, neg_faces);
02396          } else {
02397             neg_faces += nbr;
02398             grow_oriented_face_lists(nbr, neg_faces, pos_faces);
02399          }
02400       }
02401    }
02402 }
02403 
02404 Bedge*
02405 BMESH::nearest_edge(CWpt &p)
02406 {
02407    if (_edges.empty())
02408       return 0;
02409 
02410    Wpt q;
02411    Bedge *ret = _edges[0];
02412    double dist = (p - _edges[0]->project_to_simplex(p, q)).length_sqrd(), d;
02413 
02414    for (int i=1; i<_edges.num(); i++) {
02415       if ((d = (p - _edges[i]->project_to_simplex(p, q)).length_sqrd()) < dist) {
02416          ret = _edges[i];
02417          dist = d;
02418       }
02419    }
02420 
02421    return ret;
02422 }
02423 
02424 Bvert*
02425 BMESH::nearest_vert(CWpt &p)
02426 {
02427    if (_verts.empty())
02428       return 0;
02429 
02430    Bvert *ret = _verts[0];
02431    double dist = (p - _verts[0]->loc()).length_sqrd(), d;
02432 
02433    for (int i=1; i<_verts.num(); i++) {
02434       if ((d = (p - _verts[i]->loc()).length_sqrd()) < dist) {
02435          ret = _verts[i];
02436          dist = d;
02437       }
02438    }
02439 
02440    return ret;
02441 }
02442 
02443 void
02444 BMESH::get_enclosed_verts(
02445    CXYpt_list& boundary,
02446    Bface* startface,
02447    ARRAY<Bvert*>& ret)
02448 {
02449    // Do a search on the mesh to find out vertices that
02450    // lie inside the boundary, with the vertices of the
02451    // given startface as starting point.
02452 
02453    // start fresh
02454    ret.clear();
02455 
02456    // error-check
02457    if (startface->mesh() != this) {
02458       err_msg("BMESH::get_enclosed_verts: startface is from wrong mesh");
02459       return;
02460    }
02461 
02462    // clear all vertex flags
02463    for (int j=0; j<nverts(); j++)
02464       bv(j)->clear_flag();
02465 
02466    ARRAY<Bvert*> frontier; // expandable frontier of vertices to check
02467 
02468    // start with on-screen vertices, since others
02469    // cannot be projected reliably to screen
02470    // coordinates:
02471    if (startface->v1()->ndc().in_frustum())
02472       frontier += startface->v1();
02473    if (startface->v2()->ndc().in_frustum())
02474       frontier += startface->v2();
02475    if (startface->v3()->ndc().in_frustum())
02476       frontier += startface->v3();
02477 
02478    while (!frontier.empty()) {
02479       Bvert* v = frontier.pop();
02480 
02481       // note: v->ndc() accessor takes into account
02482       // mesh transform if any
02483       XYpt xy = NDCpt(v->ndc());
02484 
02485       if (boundary.contains(xy)) {
02486          ret += v;
02487          for (int i=0 ;i<v->degree(); i++) {
02488             Bvert *nbr = v->nbr(i);
02489             if (!nbr->flag()) {
02490                nbr->set_flag();
02491                frontier += nbr;
02492             }
02493          }
02494       }
02495    }
02496 }
02497 
02498 int
02499 BMESH::remove_face(Bface* f)
02500 {
02501    _faces -= f;
02502    delete_face(f);
02503 
02504    return 1;
02505 }
02506 
02507 int
02508 BMESH::remove_edge(Bedge* e)
02509 {
02510    _edges -= e;
02511    delete_edge(e);
02512 
02513    return 1;
02514 }
02515 
02516 int
02517 BMESH::remove_vertex(Bvert* v)
02518 {
02519    _verts -= v;
02520    delete_vert(v);
02521 
02522    return 1;
02523 }
02524 
02525 int
02526 BMESH::remove_faces(CBface_list& faces)
02527 {
02528    if (!faces.empty() && faces.mesh() != this) {
02529       cerr <<"BMESH::remove_faces(): ERROR, faces not all from this mesh"
02530            << endl;
02531       return 0;
02532    }
02533 
02534    for (int i=0; i<faces.num(); i++) {
02535       remove_face(faces[i]);
02536    }
02537 
02538    return 1;
02539 }
02540 
02541 int
02542 BMESH::remove_edges(CBedge_list& edges)
02543 {
02544    if (!edges.empty() && edges.mesh() != this) {
02545       cerr <<"BMESH::remove_edges(): ERROR, edges not all from this mesh"
02546            << endl;
02547       return 0;
02548    }
02549 
02550    for (int i=0; i<edges.num(); i++) {
02551       remove_edge(edges[i]);
02552    }
02553 
02554    return 1;
02555 }
02556 
02557 int
02558 BMESH::remove_verts(CBvert_list& verts)
02559 {
02560    if (!verts.empty() && verts.mesh() != this) {
02561       cerr <<"BMESH::remove_verts(): ERROR, verts not all from this mesh"
02562            << endl;
02563       return 0;
02564    }
02565 
02566    for (int i=0; i<verts.num(); i++) {
02567       remove_vertex(verts[i]);
02568    }
02569 
02570    return 1;
02571 }
02572 
02573 void
02574 BMESH::merge_vertex(Bvert* v, Bvert* u, bool keep_vert)
02575 {
02576    // Identify vertex v to vertex u,
02577    // destroy v unless keep_vert == 1.
02578    // then v is left as a dangling vert.
02579 
02580    // Get faces around v and detach them
02581    Bface_list star_faces(6);
02582    v->get_all_faces(star_faces);
02583    int k;
02584    for (k=0; k<star_faces.num(); k++)
02585       star_faces[k]->detach();
02586 
02587    // redefine edges coming out of v,
02588    // removing those that can't be redefined
02589    // (because they would duplicate an existing edge).
02590    ARRAY<Bedge*> star_edges = v->get_adj();
02591    for (k=0; k<star_edges.num(); k++)
02592       if (!star_edges[k]->redefine(v,u))
02593          remove_edge(star_edges[k]);
02594 
02595    for (k=0; k<star_faces.num(); k++)
02596       if (!star_faces[k]->redefine(v,u))
02597          remove_face(star_faces[k]);
02598 
02599    // get rid of pathetic isolated vertex
02600    if (!keep_vert)
02601       remove_vertex(v);
02602 }
02603 
02604 
02605 int
02606 compare_locs_lexicographically(const void* va, const void* vb)
02607 {
02608    // used in BMESH::remove_duplicate_vertices() below
02609 
02610    CWpt& a = (*((Bvert**)va))->loc();
02611    CWpt& b = (*((Bvert**)vb))->loc();
02612 
02613    return ((a[0] > b[0]) ?  1 :
02614            (a[0] < b[0]) ? -1 :
02615            (a[1] > b[1]) ?  1 :
02616            (a[1] < b[1]) ? -1 :
02617            (a[2] > b[2]) ?  1 :
02618            (a[2] < b[2]) ? -1 :
02619            0);
02620 }
02621 
02622 void
02623 BMESH::remove_duplicate_vertices(bool keep_verts)
02624 {
02625    // zero-length edges cause problems -- remove them and their
02626    // adjacent zero-area faces.  NOTE: because of the way ARRAY
02627    // deletion works, we have to work backwards.
02628    for (int j=nedges()-1; j>=0; j--) {
02629       if (_edges[j]->length() == 0)
02630          remove_edge(_edges[j]);
02631    }
02632 
02633    // we need to process vertices in sorted order, but
02634    // removing vertices has the side effect
02635    // of re-shuffling the order of the _verts array.
02636    //
02637    // so we make a temporary copy of the _verts array,
02638    // which will not be reshuffled, and operate on that:
02639    Bvert_list verts = _verts;
02640 
02641    // sort verts by increasing (x,y,z) order:
02642    verts.sort(compare_locs_lexicographically);
02643 
02644    // remove duplicate vertices, which now lie
02645    // next to each other in the array:
02646    int count = 0;
02647    Bvert* prev = verts[0];
02648    for (int k=1; k<verts.num(); k++) {
02649       if (verts[k]->loc() == prev->loc()) {
02650          merge_vertex(verts[k], prev, keep_verts);
02651          count++;
02652       } else
02653          prev = verts[k];
02654    }
02655 
02656    if (count > 0) {
02657       // if anything happened, invalidate cached data:
02658       changed(TRIANGULATION_CHANGED);
02659 
02660       // this mesh was effed up -- better fix face normals
02661       // to consistent orientation or else the triangle
02662       // stripping code will crash:
02663 
02664       int fixed = fix_orientation()
02665          ;
02666 
02667       // tell the humans:
02668       err_msg("BMESH::remove_duplicate_vertices:");
02669       err_msg("       removed %d verts", count);
02670       err_msg("       %s orientation", fixed ? "fixed" : "warning: can't fix")
02671          ;
02672    }
02673 }
02674 
02675 
02676 Bvert*
02677 BMESH::split_edge(Bedge* edge, CWpt &p)
02678 {
02679    /*
02680    //            c
02681    //         /  | \
02682    //       /    |   \
02683    //      d  f1 v f2  b
02684    //       \    |    /
02685    //        \   |   /
02686    //          \ | /
02687    //            a
02688    */
02689 
02690    Bface* f1 = ccw_face(edge);
02691    Bface* f2 = edge->other_face(f1);
02692 
02693    Bvert* a = edge->v1();
02694    Bvert* c = edge->v2();
02695 
02696    // preserve UV coords, if any
02697    UVdata* uvd1 = UVdata::lookup(f1);
02698    UVdata* uvd2 = UVdata::lookup(f2);
02699 
02700    UVpt uv1a, uv1c, uv1d;
02701    UVpt uv2a, uv2b, uv2c;
02702 
02703    if (uvd1) {
02704       uv1a = uvd1->uv(a);
02705       uv1c = uvd1->uv(c);
02706       uv1d = uvd1->uv(f1->other_vertex(a,c));
02707    }
02708    if (uvd2) {
02709       uv2a = uvd2->uv(a);
02710       uv2b = uvd2->uv(f2->other_vertex(a,c));
02711       uv2c = uvd2->uv(c);
02712    }
02713 
02714    // detach faces
02715    if (f1)
02716       f1->detach();
02717    if (f2)
02718       f2->detach();
02719 
02720    // allocate new vertex
02721    Bvert* v = add_vertex(p);
02722 
02723    // propagate tess data
02724    // from edge to new vertex:
02725    edge->notify_split(v);
02726 
02727    // redefine edge, replacing a with v:
02728    edge->redefine(a,v);
02729 
02730    // create new edge from v to a:
02731    Bedge* av = add_edge(v,a);
02732 
02733    // propagate tess data from
02734    // old to new edge:
02735    edge->notify_split(av);
02736 
02737    if (f1) {
02738       Bvert* d = f1->other_vertex(a,c);
02739 
02740       // add edge from d to v, and propagate
02741       // tess data from f1 to new edge:
02742       f1->notify_split(add_edge(v,d));
02743 
02744       // redefine f1, replacing a with v:
02745       f1->redefine(a,v);
02746 
02747       // create new face joining v,d,a
02748       Bface* avd = add_face(v,d,a,f1->patch());
02749 
02750       // propagate tess data:
02751       f1->notify_split(avd);
02752 
02753       if (uvd1) {
02754          UVpt uv1v = (uv1a + uv1c)/2;
02755          UVdata::set
02756             (f1,  v, c, d, uv1v, uv1c, uv1d);
02757          UVdata::set
02758             (avd, v, d, a, uv1v, uv1d, uv1a);
02759       }
02760    }
02761    if (f2) {
02762       Bvert* b = f2->other_vertex(a,c);
02763       f2->notify_split(add_edge(v,b));
02764       f2->redefine(a,v);
02765       Bface* abv = add_face(v,a,b,f2->patch());
02766       f2->notify_split(abv);
02767 
02768       if (uvd2) {
02769          UVpt uv2v = (uv2a + uv2c)/2;
02770          UVdata::set
02771             (f2,  v, b, c, uv2v, uv2b, uv2c);
02772          UVdata::set
02773             (abv, v, a, b, uv2v, uv2a, uv2b);
02774       }
02775    }
02776 
02777    return v;
02778 }
02779 
02780 Bvert*
02781 BMESH::split_face(Bface *face, CWpt &pos)
02782 {
02783    /*
02784    //                    
02785    //                   c                              
02786    //                 /   \                            
02787    //               /      \                           
02788    //             /         \                          
02789    //           /      p     \                         
02790    //         /               \
02791    //       /                  \
02792    //      a ------------------ b                     
02793    //                                                  
02794    //    face is (a,b,c) is ccw order
02795    */
02796 
02797    Bvert* a = face->v1();
02798    Bvert* b = face->v2();
02799    Bvert* c = face->v3();
02800 
02801    // keep uv data if it exists
02802    UVpt uva, uvb, uvc, uvp;
02803    UVdata* uvd = UVdata::lookup(face);
02804    if (face) {
02805       uva = uvd->uv1();
02806       uvb = uvd->uv2();
02807       uvc = uvd->uv3();
02808       Wvec bc;
02809       face->project_barycentric(pos, bc);
02810       uvd->bc2uv(bc, uvp);
02811    }
02812    face->detach();
02813 
02814    Bvert *v = add_vertex(pos);
02815    Bedge *av = add_edge(a,v);
02816    Bedge *bv = add_edge(b,v);
02817    Bedge *cv = add_edge(c,v);
02818 
02819    face->redefine(c,v);
02820 
02821    Bface *bcv = add_face(b,c,v,face->patch());
02822    Bface *cav = add_face(c,a,v,face->patch());
02823 
02824    if (uvd) {
02825       UVdata::set
02826          (face, uva, uvb, uvp);
02827       UVdata::set
02828          (bcv,  uvb, uvc, uvp);
02829       UVdata::set
02830          (cav,  uvc, uva, uvp);
02831    }
02832    face->notify_split(v);
02833    face->notify_split(av);
02834    face->notify_split(bv);
02835    face->notify_split(cv);
02836    face->notify_split(bcv);
02837    face->notify_split(cav);
02838 
02839    return v;
02840 }
02841 
02842 
02843 int
02844 BMESH::split_faces(
02845    CXYpt_list &pts,
02846    ARRAY<Bvert *> &verts,
02847    Bface* start_face)
02848 {
02849    // preconditions:
02850    // the first point intersects with this mesh
02851    // there is at least a single point
02852 
02853    // if the first and last point are equal, and there is
02854    // more than two points, then treat pts as a closed curve.
02855    int closed = pts.num() > 2 && pts[0] == pts.last();
02856 
02857    cerr << (closed? " It's closed " : "Open!")<<endl;
02858    verts.clear();
02859 
02860    if (pts.empty()) {
02861       return 0;
02862    }
02863 
02864    Bface* cur=0;
02865    Wpt cur_pt;
02866    if (!start_face) {
02867       BaseVisRefImage *vis_ref = BaseVisRefImage::lookup(VIEW::peek());
02868       if (!vis_ref) {
02869          err_msg("BMESH::split_faces: error: can't get BaseVisRefImage");
02870          return 0;
02871       }
02872       vis_ref->vis_update();
02873       cur = vis_ref->vis_intersect(pts[0], cur_pt);
02874    } else {
02875       cur = start_face;
02876       cur_pt = cur->plane_intersect(inv_xform() * Wline(pts[0]));
02877    }
02878 
02879    if (!cur || cur->mesh() != this) {
02880       return 0;
02881    }
02882 
02883    verts += split_face(cur, cur_pt);
02884    NDCpt new_ndc;
02885 
02886    Bface_list star_faces(16);
02887 
02888    for (int i=1; i < pts.num(); ) {
02889       // walk from prev point to this point, splitting edges and faces along
02890       // the way, accumulating new vertices.
02891 
02892       int success = 0;
02893       verts.last()->get_faces(star_faces);
02894       NDCpt last_ndc = xform() * verts.last()->loc();
02895 
02896       if (closed && i==pts.num()-1) {
02897          cerr << "In closed search" <<endl;
02898          // see if there is an adjacent vertex at the final position
02899          // already.  if so, declare success and we're done.
02900          for (int j=0; j < verts.last()->degree(); j++) {
02901             if (verts.last()->nbr(j) == verts[0]) {
02902                i++;
02903                success = 1;
02904                Bvert* v= verts[0];
02905                verts += v;
02906                break;
02907             }
02908          }
02909          if (!success)
02910             cerr << "BMESH::split_faces: Closed SearchFailed" << endl;
02911          else {
02912             cerr << "BMESH::split_faces: Closing correctly" << endl;
02913             assert(verts[0]==verts.last());
02914          }
02915       }
02916 
02917       // As the first vertex may not be immediately adjacent to this vertex
02918       // so the closing can possibly fail but succeed in subsequent triangles
02919 
02920       if (!success) {
02921          for (int j=0; j<star_faces.num(); j++) {
02922 
02923             if (star_faces[j]->ndc_contains(pts[i]) ) {
02924 
02925                if (i==pts.num()-1)
02926                   cerr << "BMESH::split_faces: Why here" << endl;
02927                Wpt new_pt = star_faces[j]->plane_intersect(
02928                   inv_xform() * Wline(pts[i]));
02929                verts += split_face(star_faces[j], new_pt);
02930                cerr << "BMESH::split_faces: Split face insert "
02931                     << verts.num()
02932                     << endl;
02933                i++;
02934 
02935                success = 1;
02936                break;
02937             } else if (star_faces[j]->opposite_edge(verts.last())->
02938                        ndc_intersect(last_ndc, pts[i], new_ndc)) {
02939 
02940                if (i==pts.num()-1)
02941                   cerr << "Kept going" << endl;
02942                Wpt new_pt = star_faces[j]->plane_intersect(
02943                   inv_xform() * Wline(new_ndc));
02944                verts += split_edge(
02945                   star_faces[j]->opposite_edge(verts.last()),new_pt);
02946 
02947                cerr << "BMESH::split_faces: Split edge insert "
02948                     << verts.num()
02949                     << endl;
02950                success = 1;
02951                break;
02952             }
02953          }
02954       }
02955 
02956       if (!success) {
02957          cerr << "i fail " << i << endl;
02958          cerr << "pts.num() " << pts.num() <<endl;
02959          return 0;
02960       }
02961    }
02962 
02963    cerr << "BMESH::Split_faces :: Success.. returning "
02964         << verts.num()
02965         << " vertices"
02966         << endl;
02967    changed(TRIANGULATION_CHANGED);
02968    return 1;
02969 }
02970 
02971 int
02972 BMESH::try_swap_edge(Bedge* edge, bool favor)
02973 {
02974    /*
02975    //                  c
02976    //                / | \
02977    //              /   |   \
02978    //            /     |     \
02979    //          /       |       \
02980    //        d    f1  /|\   f2   b
02981    //          \       |       /
02982    //            \     |     /
02983    //              \   |   /
02984    //                \ | /
02985    //                  a
02986    //
02987    //         edge goes from a to c.
02988    //  "swapping" the edge means deleting it
02989    //   and putting in an edge from d to b.
02990    //  an edge is "swapable" if the operation
02991    //  is both legal (no change to topology)
02992    //   and preferable (e.g. it leads to a
02993    //           bigger minimum angle).
02994    */
02995 
02996    Bface *f1=0, *f2=0;
02997    Bvert *a=0, *b=0, *c=0, *d=0;
02998    if (!edge->swapable(f1,f2,a,b,c,d, favor))
02999       return 0;
03000 
03001    // do it
03002    f1->detach();
03003    f2->detach();
03004 
03005    // disconnect edge from its vertices
03006    edge->set_new_vertices(d,b);
03007 
03008    f1->redefine(a,b);
03009    f2->redefine(c,d);
03010 
03011    return 1;
03012 }
03013 
03014 int
03015 BMESH::try_collapse_edge(Bedge* e, Bvert* v)
03016 {
03017    // vertex v will be removed
03018    // vertex u will absorb its adjacent edges and faces
03019    Bvert *u = 0;
03020 
03021    if (v) {
03022       // caller wants v to be destroyed
03023       u = e->other_vertex(v);
03024       assert(u);
03025    } else {
03026       // caller doesn't care which vertex is destroyed
03027       v = e->v(1);
03028       u = e->v(2);
03029    }
03030 
03031    // see hoppe et al (SIG93): can't proceed if:
03032    //    1) fewer than 5 vertices in mesh
03033    //    2) both verts are border verts, but edge isn't border edge
03034    //    3) there exists a vertex adjacent to both endpoints of the edge,
03035    //       and this vertex is not in either face adjacent to the edge.
03036 
03037    //  case 1)
03038    if (nverts()<5)
03039       return 0;
03040 
03041    // case 2)
03042    static bool debug = Config::get_var_bool("SKIN_DEBUG",false);
03043    if (v->is_border() && u->is_border() && !e->is_border()) {
03044       if (debug)
03045          cerr << "BMESH::try_collapse_edge: Case 2 failure" <<endl;
03046       return 0;
03047    }
03048 
03049    // case 3) - only matters if there is a face
03050    if (e->f1() || e->f2()) {
03051       Bvert* op1 = e->opposite_vert1();
03052       Bvert* op2 = e->opposite_vert2();
03053       for (int k=v->degree()-1; k>=0; k--) {
03054          Bvert* vnbr = v->nbr(k);
03055          if (vnbr != u && u->is_adjacent(vnbr) && vnbr != op1 && vnbr != op2) {
03056             if (debug)
03057                cerr << "BMESH::try_collapse_edge: Case 3 failure" <<endl;
03058             return 0;
03059          }
03060       }
03061    }
03062 
03063    // do it
03064    merge_vertex(v, u);
03065 
03066    return 1;
03067 }
03068 
03069 
03070 Patch*
03071 BMESH::new_patch()
03072 {
03073    _patches   += new Patch(this);
03074    if (subdiv_level() == 0)
03075       _drawables += _patches.last();
03076 
03077    return _patches.last();
03078 }
03079 
03080 bool
03081 BMESH::unlist(Patch* p)
03082 {
03083    // Remove the Patch from the patch list; returns 1 on success
03084 
03085    if (!(p && p->mesh() && p->mesh() == this))
03086       return false;
03087    return _patches -= p;
03088 }
03089 
03090 void
03091 BMESH::changed(change_t change)
03092 {
03093    REFlock lock((REFcounter *)this)
03094       ;
03095 
03096    if (change == NO_CHANGE)
03097       return;
03098 
03099    if (change == PATCHES_CHANGED) {
03100 
03101       // XXX -- obsolete -- fix this
03102 
03103       // assume this means that some triangles have
03104       // been re-labeled (re: which patch they are in).
03105       // this means line strips are invalid,
03106       // but bounding box is okay.
03107 
03108       // mark sil strips invalid:
03109       _sil_stamp = 0;
03110       _zx_stamp = 0;
03111       // todo: re-do patch boundaries...
03112    }
03113 
03114    switch (change) {
03115       // cases arranged in order of decreasing severity.
03116       // breaks are not used on purpose
03117     case TOPOLOGY_CHANGED:
03118 
03119       _type_valid = 0;
03120 
03121     case TRIANGULATION_CHANGED:
03122 
03123       // mark sil strips invalid:
03124       _sil_stamp = 0;
03125       _sils.reset();
03126 
03127       // ditto zx sils:
03128       _zx_sils.reset();
03129       _zx_stamp = 0;
03130 
03131       // ditto borders:
03132       delete _borders;
03133       _borders = 0;
03134 
03135       // did you think we would forget creases?
03136       delete _creases;
03137       _creases = 0;
03138 
03139       _patches.triangulation_changed();
03140 
03141     case VERT_POSITIONS_CHANGED:
03142 
03143       //XXX (rdk) - I added this... cool?
03144       // XXX (lem):
03145       //  This means randomized zx sil detection
03146       //  is turned OFF for deforming meshes.
03147       _zx_stamp = 0;
03148 
03149       // invalidate BODY stuff:
03150       _vert_locs.clear();
03151       BODY::_edges.reset();
03152       _body = BODYptr(0);
03153       _bb.reset();
03154       _avg_edge_len_valid = 0;
03155       
03156       // invalidate curvature data:
03157       delete _curv_data;
03158       _curv_data = 0;
03159       
03160       break;
03161 
03162     case CREASES_CHANGED:
03163       // Invalidate crease strips in patches:
03164       _patches.creases_changed();
03165       delete _creases;
03166       _creases = 0;
03167 
03168     default:
03169       ;
03170    }
03171 
03172    BMESHobs::broadcast_change(this, change);
03173 
03174    // Invalidate display lists:
03175    _version++;
03176 }
03177 
03178 const BBOX &
03179 BMESH::get_bb()
03180 {
03181    if (_bb.valid())
03182       return _bb;
03183 
03184    for (int i = 0; i< nverts(); i++) {
03185       _bb.update(bv(i)->loc());
03186    }
03187    return _bb;
03188 }
03189 
03190 CTAGlist &
03191 BMESH::tags() const
03192 {
03193    // Tags used for MESHes loaded/saved during animations.
03194    // (e.g. only the vertex positions change)
03195    if  ( (IOManager::state() == IOManager::STATE_PARTIAL_LOAD) ||
03196          (IOManager::state() == IOManager::STATE_PARTIAL_SAVE) ) {
03197       if (!_bmesh_update_tags) {
03198          _bmesh_update_tags  = new TAGlist;
03199 
03200          *_bmesh_update_tags += BODY::tags();
03201 
03202          *_bmesh_update_tags += new TAG_meth<BMESH>(
03203             "vertices", &BMESH::put_vertices, &BMESH::get_vertices, 1
03204             );
03205       }
03206       return *_bmesh_update_tags;
03207    }
03208 
03209    // Full set of tags used in all other circumstances...
03210       if (!_bmesh_tags) {
03211         
03212          _bmesh_tags  = new TAGlist;
03213 
03214          *_bmesh_tags += BODY::tags();
03215 
03216          // XXX - vertices & faces must be written/read first w/
03217          //       current implementation
03218          *_bmesh_tags += new TAG_meth<BMESH>(
03219             "vertices", &BMESH::put_vertices, &BMESH::get_vertices, 1
03220             );
03221          *_bmesh_tags += new TAG_meth<BMESH>(
03222             "faces", &BMESH::put_faces, &BMESH::get_faces, 1
03223             );
03224          *_bmesh_tags += new TAG_meth<BMESH>(
03225             "uvfaces", &BMESH::put_uvfaces, &BMESH::get_uvfaces, 1
03226             );
03227          *_bmesh_tags += new TAG_meth<BMESH>(
03228             "creases", &BMESH::put_creases, &BMESH::get_creases, 1
03229             );
03230          *_bmesh_tags += new TAG_meth<BMESH>(
03231             "polylines", &BMESH::put_polylines, &BMESH::get_polylines, 1
03232             );
03233          *_bmesh_tags += new TAG_meth<BMESH>(
03234             "weak_edges", &BMESH::put_weak_edges, &BMESH::get_weak_edges, 1
03235             );
03236          *_bmesh_tags += new TAG_meth<BMESH>(
03237             "secondary_faces", &BMESH::put_sec_faces, &BMESH::get_sec_faces, 1
03238             );
03239          *_bmesh_tags += new TAG_meth<BMESH>(
03240             "colors", &BMESH::put_colors, &BMESH::get_colors, 1
03241             );
03242          *_bmesh_tags += new TAG_meth<BMESH>(
03243             "texcoords2", &BMESH::put_texcoords2, &BMESH::get_texcoords2, 1
03244             );
03245          *_bmesh_tags += new TAG_meth<BMESH>(
03246             "patch", &BMESH::put_patches, &BMESH::get_patches, 1
03247             );
03248          //XXX - Axing this one...
03249          *_bmesh_tags += new TAG_meth<BMESH>(
03250             "render_style", &BMESH::put_render_style, &BMESH::get_render_style, 1
03251             );
03252       }
03253       return *_bmesh_tags;
03254 }
03255 
03256 void
03257 BMESH::put_vertices(TAGformat &d) const
03258 {
03259    Wpt_list verts(nverts());
03260 
03261    if (Config::get_var_bool("JOT_SAVE_XFORMED_MESH",false))
03262       for (int i = 0; i< nverts(); i++)
03263          verts += bv(i)->wloc();
03264    else
03265       for (int i = 0; i< nverts(); i++)
03266          verts += bv(i)->loc();
03267 
03268    // XXX - copied code from net_type.H,
03269    //       want to avoid super long lines that may be
03270    //       causing bugs...
03271    d.id();
03272    if ((*d).ascii()) {
03273       (*d) << "{";
03274    } else {
03275       (*d) << verts.num();
03276    }
03277    for (int i=0; i<verts.num();i++) {
03278       (*d) << " " << verts[i];
03279       (*d).write_newline();
03280    }
03281    if ((*d).ascii()) {
03282       (*d) << "}";
03283       (*d).write_newline();
03284    }
03285    d.end_id();
03286 }
03287 
03288 void
03289 BMESH::put_faces(TAGformat &d) const
03290 {
03291    ARRAY<ARRAY<int> > faces(nfaces());
03292    
03293    for (int i=0; i<nfaces(); i++) {
03294       ARRAY<int> face;
03295       Bface *f = bf(i);
03296       if (use_new_bface_io) {
03297          // Faces with uv coords will be written out in
03298          // BMESH::put_uvfaces(), so we can skip writing them here.
03299          if (UVdata::has_uv(f))
03300             continue;
03301          if (!f->is_quad()) {
03302             // Write an ordinary triangle
03303             face  += f->v1()->index();
03304             face  += f->v2()->index();
03305             face  += f->v3()->index();
03306             faces += face;
03307          } else if (f->quad_rep() == f) {
03308             // Write a quad:
03309             Bvert *a=0, *b=0, *c=0, *d=0;
03310             f->get_quad_verts(a,b,c,d);
03311             assert(a && b && c && d);
03312             face  += a->index();
03313             face  += b->index();
03314             face  += c->index();
03315             face  += d->index();
03316             faces += face;
03317          }
03318       } else {
03319          // Old I/O: write a plain triangle
03320          face  += f->v1()->index();
03321          face  += f->v2()->index();
03322          face  += f->v3()->index();
03323          faces += face;
03324       }
03325    }
03326 
03327    // XXX - copied code from net_type.H,
03328    //       want to avoid super long lines that may be
03329    //       causing bugs...
03330    d.id();
03331    if ((*d).ascii()) {
03332       (*d) << "{";
03333    } else {
03334       (*d) << faces.num();
03335    }
03336    for (int i=0; i<faces.num();i++) {
03337       (*d) << " " << faces[i];
03338       (*d).write_newline();
03339    }
03340    if ((*d).ascii()) {
03341       (*d) << "}";
03342       (*d).write_newline();
03343    }
03344    d.end_id();
03345 }
03346 
03347 class UVforIO2
03348 {
03349  public:
03350    ARRAY<int>  _face;   // indices of vertices making up the triangle or quad
03351    ARRAY<UVpt> _uvs;    // corresponding UV coords
03352 
03353    UVforIO2() {}
03354    UVforIO2(CBface* f)
03355       {
03356          if (!(f && UVdata::has_uv(f)))
03357             return;
03358          if (f->is_quad()) {
03359             // Only write out the quad rep
03360             // (i.e. write out the quad just once, not twice)
03361             if (!f->is_quad_rep())
03362                return;
03363             Bvert *a=0, *b=0, *c=0, *d=0;
03364             UVpt ua, ub, uc, ud;
03365             if (f->get_quad_verts(a,b,c,d) && UVdata::get_quad_uvs(a,b,c,d,ua,ub,uc,ud)) {
03366                assert(a && b && c && d);
03367                _face += a->index();
03368                _face += b->index();
03369                _face += c->index();
03370                _face += d->index();
03371                _uvs += ua;
03372                _uvs += ub;
03373                _uvs += uc;
03374                _uvs += ud;
03375             } else {
03376                // could just as well assert(0)
03377                err_msg("UVforIO2::UVforIO2: error getting quad uv's; skipping...");
03378             }
03379          } else {
03380             UVpt ua, ub, uc;
03381             if (UVdata::get_uvs(f, ua, ub, uc)) {
03382                _face += f->v1()->index();
03383                _face += f->v2()->index();
03384                _face += f->v3()->index();
03385                _uvs += ua;
03386                _uvs += ub;
03387                _uvs += uc;
03388             } else {
03389                // could just as well assert(0)
03390                err_msg("UVforIO2::UVforIO2: error getting triangle uv's; skipping...");
03391             }
03392          }
03393       }
03394 
03395    int  num()     const { return _face.num(); }
03396    bool is_good() const { return (num() == 3 || num() == 4) && (num() == _uvs.num()); }
03397 
03398    // Needed by ARRAY<UVforIO2>::get_index():
03399    bool operator==(const UVforIO2 &u) const
03400       {
03401          // Use operator==(ARRAY<T>, ARRAY<T>)
03402          return (_face == u._face && _uvs == u._uvs);
03403       }
03404 };
03405 
03406 inline STDdstream&
03407 operator<<(STDdstream &ds, const UVforIO2& v)
03408 {
03409    if (v.is_good()) {
03410       if (ds.ascii())
03411          ds << "{" << v._face << v._uvs << "}";
03412       else
03413          ds << v._face << v._uvs;
03414    }
03415    return ds;
03416 }
03417 
03418 inline STDdstream&
03419 operator>>(STDdstream &ds, UVforIO2 &v)
03420 {
03421    if (ds.ascii()) {
03422       char brace;
03423       ds >> brace >> v._face >> v._uvs >> brace;
03424    } else {
03425       ds >> v._face >> v._uvs;
03426    }
03427    return ds;
03428 }
03429 
03430 
03431 void
03432 BMESH::put_uvfaces(TAGformat &d) const
03433 {
03434    // Writes out a record for each quad or triangle with uv coords.
03435    // When this is used, BMESH::put_faces() can skip writing out
03436    // faces that have assigned uv coords.
03437 
03438    // Don't write the new format unless requested
03439    if (!use_new_bface_io)
03440       return;
03441 
03442    ARRAY<UVforIO2> uvs(nfaces());
03443 
03444    for (int i=0; i<nfaces(); i++) {
03445       UVforIO2 uv(bf(i));
03446       if (uv.is_good())
03447          uvs += uv;
03448    }
03449 
03450    if (!uvs.empty()) {
03451       d.id();
03452       *d << uvs;
03453       d.end_id();
03454    }
03455 }
03456 
03457 void
03458 BMESH::get_uvfaces(TAGformat &d)
03459 {
03460    ARRAY<UVforIO2> uvs;
03461    *d >> uvs;
03462 
03463    if (uvs.empty())
03464       return;
03465 
03466    Patch* p = 0;
03467    for (int i=0; i<uvs.num(); i++) {
03468       const UVforIO2& uv = uvs[i];
03469       if (!uv.is_good()) {
03470          err_msg("BMESH::get_uvfaces: skipping bad face:");
03471 
03472          iostream i(cerr.rdbuf());
03473          STDdstream e(&i);
03474          //STDdstream e((iostream*)&cerr);
03475          e << uv << "\n";
03476       }
03477       switch(uv.num()) {
03478        case 3:
03479          // triangle
03480          add_face(uv._face[0], uv._face[1], uv._face[2],
03481                   uv._uvs[0],  uv._uvs[1],  uv._uvs[2], p);
03482          break;
03483        case 4:
03484          // quad
03485          add_quad(uv._face[0], uv._face[1], uv._face[2], uv._face[3],
03486                   uv._uvs[0],  uv._uvs[1],  uv._uvs[2],  uv._uvs[3], p);
03487          break;
03488        default:
03489          assert(0);
03490       }
03491    }
03492 
03493    changed(TOPOLOGY_CHANGED);
03494 }
03495 
03496 void
03497 BMESH::put_creases(TAGformat &d) const
03498 {
03499    ARRAY<Point2i> creases;
03500 
03501    for (int i=0; i<nedges(); i++) {
03502       Bedge *e = be(i);
03503       if (e->is_crease())
03504          creases += Point2i(e->v(1)->index(), e->v(2)->index());
03505    }
03506 
03507    // No tag if no creases!
03508    if (creases.num() == 0)
03509       return;
03510 
03511    d.id();
03512    *d << creases;
03513    d.end_id();
03514 
03515 }
03516 
03517 
03518 void
03519 BMESH::put_polylines(TAGformat &d) const
03520 {
03521    ARRAY<Point2i> polylines;
03522 
03523    for (int i=0; i<nedges(); i++) {
03524       Bedge *e = be(i);
03525       if (e->is_polyline())
03526          polylines += Point2i(e->v(1)->index(), e->v(2)->index());
03527    }
03528 
03529    //No tag if no creases!
03530    if (polylines.num() == 0)
03531       return;
03532 
03533    d.id();
03534    *d << polylines;
03535    d.end_id();
03536 
03537 }
03538 
03539 void
03540 BMESH::put_weak_edges(TAGformat &d) const
03541 {
03542    if (use_new_bface_io)
03543       return;
03544 
03545    ARRAY<Point2i> weak_edges;
03546 
03547    for (int i=0; i<nedges(); i++) {
03548       Bedge *e = be(i);
03549       if (e->is_weak())
03550          weak_edges += Point2i(e->v(1)->index(), e->v(2)->index());
03551    }
03552 
03553    if (weak_edges.empty())
03554       return;
03555 
03556    d.id();
03557    *d << weak_edges;
03558    d.end_id();
03559 }
03560 
03561 void
03562 BMESH::put_sec_faces(TAGformat &d) const
03563 {
03564    ARRAY<Point3i> sec_faces;
03565 
03566    for (int i=0; i<nfaces(); i++) {
03567       Bface *f = bf(i);
03568       if (f && f->is_secondary())
03569          sec_faces += Point3i(f->v1()->index(), f->v2()->index(), f->v3()->index());
03570    }
03571 
03572    if (sec_faces.empty())
03573       return;
03574 
03575    d.id();
03576    *d << sec_faces;
03577    d.end_id();
03578 
03579 }
03580 
03581 
03582 class UVforIO
03583 {
03584  public:
03585    int   _face;
03586    UVpt  _uv1;
03587    UVpt  _uv2;
03588    UVpt  _uv3;
03589 
03590    UVforIO() {}
03591    UVforIO(int f, CUVpt& uv1, CUVpt& uv2, CUVpt& uv3) : _face(f), _uv1(uv1), _uv2(uv2), _uv3(uv3) {}
03592 
03593    UVpt& uv(int i) {if (i==1)
03594       return _uv1; else if (i==2)
03595          return _uv2; else { assert(i==3); return _uv3;} }
03596 
03597    bool operator ==(const UVforIO &p)   const
03598       { return _face==p._face && _uv1==p._uv1 && _uv2==p._uv2 && _uv3==p._uv3; }
03599 
03600 };
03601 
03602 inline STDdstream &operator<<(STDdstream &ds, const UVforIO  &v)
03603 {
03604    if (ds.ascii())
03605       ds << "{" << v._face << v._uv1 << v._uv2 << v._uv3 << "}";
03606    else
03607       ds << v._face << v._uv1 << v._uv2 << v._uv3;
03608    return ds;
03609 }
03610 
03611 inline STDdstream &operator>>(STDdstream &ds, UVforIO &v)
03612 {
03613    if (ds.ascii()) {
03614       char brace;
03615       ds >> brace >> v._face >> v._uv1 >> v._uv2 >> v._uv3 >> brace;
03616    } else
03617       ds >> v._face >> v._uv1 >> v._uv2 >> v._uv3;
03618    return ds;
03619 }
03620 
03621 void
03622 BMESH::put_texcoords2(TAGformat &d) const
03623 {
03624    // Deprecated, if using BMESH::put_uvfaces()
03625    if (use_new_bface_io)
03626       return;
03627 
03628    ARRAY<UVforIO> texcoords2;
03629 
03630    for (int i=0; i<nfaces(); i++) {
03631       UVdata* uvdata = UVdata::lookup(bf(i));
03632       if (uvdata)
03633          texcoords2 += UVforIO(i, uvdata->uv(1), uvdata->uv(2), uvdata->uv(3));
03634    }
03635 
03636    // No tag if no texcoords!
03637    if (texcoords2.num() == 0)
03638       return;
03639 
03640    d.id();
03641    *d << texcoords2;
03642    d.end_id();
03643 
03644 }
03645 
03646 
03647 void
03648 BMESH::put_render_style(TAGformat &d) const
03649 {
03650    /* XXX - Saving this makes the texture menu ineffectual...
03651       str_ptr style;
03652     
03653       if (_render_style.num())
03654       // XXX - What does this mean?!?!?!?
03655       // this ain't right, but shifting out the str_list _render_style
03656       // doesn't get decoded on the other side right because individual
03657       // elements aren't separatable.
03658       style = _render_style.last();
03659       else
03660       style = VIEW::peek()->rendering();
03661     
03662       d.id();
03663       *d << style;
03664       d.end_id();
03665    */
03666 }
03667 
03668 void
03669 BMESH::put_colors(TAGformat &d) const
03670 {
03671 
03672    // Assume if the first has color that they all do (bad assumption, probably)
03673    if ((nverts()==0) || (!_verts[0]->has_color()))
03674       return;
03675 
03676 
03677    ARRAY<COLOR> colors(nverts());
03678 
03679    for (int i=0; i<nverts(); i++)
03680       colors += bv(i)->color();
03681 
03682    d.id();
03683    *d << colors;
03684    d.end_id();
03685 
03686 }
03687 
03688 void
03689 BMESH::put_patches(TAGformat &d) const
03690 {
03691    // Ideally should skip writing a single patch with only
03692    // standard Gtextures; for now skipping single patches
03693    // with no Gtextures.
03694    if (_patches.num() == 1 && _patches[0]->gtextures().empty())
03695       return;
03696 
03697    for (int i=0;i<_patches.num();i++) {
03698       d.id();
03699       _patches[i]->format(*d);
03700       d.end_id();
03701    }
03702 }
03703 
03704 
03705 void
03706 BMESH::get_vertices(TAGformat &d)
03707 {
03708    // XXX - Should this be in BMESH::decode()?
03709    // NO! Let the caller of decode (or load file) do this...
03710    // delete_elements();
03711 
03712    // Read vertices
03713    Wpt_list locs;
03714    *d >> locs;
03715 
03716 
03717    // If verts already exist...
03718    if (nverts()) {
03719       if (locs.num() == nverts()) {
03720          for (int i=0; i < locs.num(); i++)
03721             _verts[i]->set_loc(locs[i]);
03722          changed(VERT_POSITIONS_CHANGED);
03723       } else {
03724          err_msg(
03725             "BMESH::get_vertices() - Error! Num verts in mesh (%d) doesn't match num in update (%d)!\n",
03726             nverts(), locs.num());
03727       }
03728    } else {
03729       _verts.realloc(locs.num());
03730       _edges.realloc(3*locs.num());
03731 
03732       for (int i=0; i < locs.num(); i++) {
03733          // Bverts might be derived type,
03734          // so call this virtual method:
03735          Bvert* v = new_vert(locs[i]);
03736          add_vertex(v);
03737       }
03738 
03739       // XXX - Presumably there will be a matching
03740       // 'faces' and we'll call this there...
03741       //changed(TOPOLOGY_CHANGED);
03742    }
03743 }
03744 
03745 void
03746 BMESH::get_faces(TAGformat &d)
03747 {
03748    assert(nfaces() == 0);
03749 
03750    ARRAY<ARRAY<int> > faces;
03751    *d >> faces;
03752 
03753    _faces.realloc(faces.num());
03754 
03755    // Create default patch here and put all faces into it.
03756    // Later if Patches are specified in the file, faces will
03757    // be re-sorted into their correct patches and this default
03758    // patch will be removed:
03759    Patch* p = 0;  //new_patch();
03760    for (int i=0; i<faces.num(); i++) {
03761       CARRAY<int>& face = faces[i];
03762       switch(face.num()) {
03763 
03764        case 3:
03765          // triangle
03766          add_face(face[0], face[1], face[2], p);
03767          break;
03768        case 4:
03769          // quad
03770          add_quad(face[0], face[1], face[2], face[3], p);
03771          break;
03772 
03773        default: {
03774           err_msg("BMESH::get_faces: error: %d-gon found, skipping...", face.num());
03775 
03776           //XXX - This blows up on WIN32
03777           //STDdstream e((iostream*)&cerr);
03778           //XXX - This requires yet another steam class header
03779           //stdiostream s(stderr);  STDdstream e(&s);
03780           //Let's try this...
03781           iostream i(cerr.rdbuf());
03782           STDdstream e(&i);
03783           e << face << "\n";
03784        }
03785       }
03786    }
03787 
03788    changed(TOPOLOGY_CHANGED);
03789 }
03790 
03791 void
03792 BMESH::get_creases(TAGformat &d)
03793 {
03794    ARRAY<Point2i> creases;
03795    *d >> creases;
03796 
03797    for (int i=0; i<creases.num(); i++)
03798       set_crease(creases[i][0],creases[i][1]);
03799 
03800    changed(CREASES_CHANGED);
03801 }
03802 
03803 void
03804 BMESH::get_polylines(TAGformat &d)
03805 {
03806    ARRAY<Point2i> polylines;
03807    *d >> polylines;
03808 
03809    for (int i=0; i<polylines.num(); i++)
03810       add_edge(polylines[i][0],polylines[i][1]);
03811 
03812    if (Config::get_var_bool("BMESH_BUILD_POLYSTRIPS",false) &&
03813        polylines.num() > 0)
03814       build_polyline_strips();
03815 }
03816 
03817 void
03818 BMESH::get_weak_edges(TAGformat &d)
03819 {
03820    ARRAY<Point2i> weak_edges;
03821    *d >> weak_edges;
03822 
03823    bool debug = Config::get_var_bool("DEBUG_WEAK_EDGES",false);
03824    err_adv(debug, "BMESH::get_weak_edges: reading %d weak edges",
03825            weak_edges.num());
03826 
03827    int count=0;
03828    for (int i=0; i<weak_edges.num(); i++)
03829       if (set_weak_edge(weak_edges[i][0],weak_edges[i][1]))
03830          count++;
03831    err_adv(debug, "set %d/%d weak edges", count, weak_edges.num());
03832 }
03833 
03834 void
03835 BMESH::get_sec_faces(TAGformat &d)
03836 {
03837    int i;
03838    ARRAY<Point3i> sec_faces;
03839 
03840    *d >> sec_faces;
03841 
03842    Bface_list sec_faces_list;
03843 
03844    for (i=0; i<sec_faces.num(); i++) {
03845       Bface* face = lookup_face(sec_faces[i]);
03846 
03847       if (!face)
03848          cerr << "BMESH::get_sec_faces - error: could not find secondary face"
03849               << endl;
03850       else
03851          sec_faces_list += face;
03852    }
03853 
03854    if (sec_faces_list.empty())
03855       return;
03856 
03857    sec_faces_list.push_layer();
03858 
03859    for (i=0; i<nedges(); i++)
03860       be(i)->fix_multi();
03861 }
03862 
03863 
03864 void
03865 BMESH::get_texcoords2(TAGformat &d)
03866 {
03867    static double UV_RESOLUTION = Config::get_var_dbl("UV_RESOLUTION",0,true);
03868 
03869    ARRAY<UVforIO> texcoords2;
03870    *d >> texcoords2;
03871 
03872    for (int i=0; i<texcoords2.num(); i++) {
03873       if (_faces.valid_index(texcoords2[i]._face)) {
03874          // Round UV's to nearest UV_RESOLUTION
03875          // A value of 0.00001 is nice...
03876          if (UV_RESOLUTION>0) {
03877             for (int j=1; j<4; j++) {
03878                UVpt &uv = texcoords2[i].uv(j);
03879                double r;
03880                uv[0] -= r = fmod(uv[0],UV_RESOLUTION);
03881                if (2.0*fabs(r) > UV_RESOLUTION)
03882                   uv[0] += ((r>0)?(UV_RESOLUTION):(-UV_RESOLUTION));
03883                uv[1] -= r = fmod(uv[1],UV_RESOLUTION);
03884                if (2.0*fabs(r) > UV_RESOLUTION)
03885                   uv[1] += ((r>0)?(UV_RESOLUTION):(-UV_RESOLUTION));
03886             }
03887          }
03888 
03889          UVdata::set
03890             (bf(texcoords2[i]._face),
03891              texcoords2[i]._uv1,
03892              texcoords2[i]._uv2,
03893              texcoords2[i]._uv3);
03894       } else {
03895          err_msg("BMESH::read_texcoords2() -  ERROR! Invalid face index %d",
03896                  texcoords2[i]._face);
03897       }
03898 
03899 
03900    }
03901 
03902    // N'existe pas...
03903    // changed(UVDATA_CHANGED);
03904 }
03905 
03906 void
03907 BMESH::get_render_style(TAGformat &d)
03908 {
03909    //XXX - Ignore this tag now -- see note in put_render_style
03910 
03911    // Get render style string, but the string may have spaces in it, which
03912    // makes things non-trivial
03913    str_ptr style = (*d).get_string_with_spaces();
03914 
03915    //   _render_style.clear();
03916    //   _render_style += style;
03917 
03918    //   changed(RENDERING_CHANGED);  // XXX - ?
03919 }
03920 
03921 void
03922 BMESH::get_colors(TAGformat &d)
03923 {
03924    // Read vertices
03925    ARRAY<COLOR> colors;
03926    *d >> colors;
03927 
03928    if (colors.num() != nverts()) {
03929       err_msg("BMESH::get_colors: warning: %d colors for %d verts",
03930               colors.num(), nverts());
03931       err_msg("   rejecting vert colors");
03932    } else {
03933       for (int i=0; i < colors.num(); i++)
03934          _verts[i]->set_color(colors[i]);
03935       changed(VERT_COLORS_CHANGED);
03936    }
03937 }
03938 
03939 void
03940 BMESH::get_patches(TAGformat &d)
03941 {
03942    str_ptr patchname;
03943    *d >> patchname;
03944 
03945    //XXX - Check class name...
03946 
03947    Patch *patch = new_patch();
03948 
03949    patch->decode(*d);
03950 
03951    changed(PATCHES_CHANGED);
03952 }
03953 
03954 //We might put stuff in format/decode to cleanup
03955 //things before/after actually doing IO
03956 
03957 STDdstream  &
03958 BMESH::format(STDdstream &ds) const
03959 {
03960    STDdstream  &ret =  BODY::format(ds);
03961 
03962    return ret;
03963 }
03964 
03965 STDdstream  &
03966 BMESH::decode(STDdstream &ds)
03967 {
03968 
03969    STDdstream  &ret =  BODY::decode(ds);
03970 
03971    make_patch_if_needed();
03972 
03973    //clean_patches();
03974 
03975    // now the topological type is determined; if there are lone
03976    // vertices store them in vertex strips.
03977    if (is_points() && Config::get_var_bool("BMESH_BUILD_VERT_STRIPS",false))
03978       build_vert_strips();
03979 
03980    return ret;
03981 }
03982 
03983 void
03984 BMESH::recenter()
03985 {
03986    if (nverts() < 1) {
03987       err_msg("BMESH::recenter: mesh is empty");
03988       return;
03989    }
03990 
03991    static Wpt_list pts(8);
03992    if (!(get_bb().points(pts))) {
03993       err_msg("BMESH::recenter: can't get bounding box");
03994       return;
03995    }
03996    Wpt c = get_bb().center();
03997 
03998    double s = 0;
03999    for (int i=0; i<8; i++)
04000       s = max(s, pts[i].dist(c));
04001 
04002    if (s<1e-12) {
04003       err_msg("BMESH::recenter: mesh is too tiny");
04004       return;
04005    }
04006 
04007    double len = Config::get_var_dbl("JOT_REDENTER_LEN", 15);
04008    MOD::tick();
04009    transform(Wtransf::scaling(Wpt::Origin(), len/s) *
04010              Wtransf::translation(Wpt::Origin() - get_bb().center()), MOD());
04011 
04012    changed(VERT_POSITIONS_CHANGED);
04013 }
04014 
04015 double
04016 BMESH::avg_len() const
04017 {
04018    if (!_avg_edge_len_valid) {
04019       double ret = 0;
04020       for (int k=_edges.num()-1; k>=0; k--)
04021          ret += _edges[k]->length();
04022       if (!_edges.empty())
04023          ret /= _edges.num();
04024       ((BMESH*) this)->_avg_edge_len_valid = 1;
04025       ((BMESH*) this)->_avg_edge_len = ret;
04026    }
04027    return _avg_edge_len;
04028 }
04029 
04030 BMESHptr
04031 BMESH::merge(BMESHptr m1, BMESHptr m2)
04032 {
04033    // merge the two meshes together if it's legal to do so. the result
04034    // is that one mesh ends up an empty husk, with its elements and
04035    // patches sucked into the other mesh. the smaller mesh is the one
04036    // that gets sucked dry. if the meshes are different types the
04037    // operation fails and a null pointer is returned. (in that case
04038    // the meshes are not changed).
04039 
04040    // this is the public method that handles error checking, then the
04041    // real work is done in the virtual method merge() that handles
04042    // anything specific to the derived mesh types being used.
04043 
04044    // error checking:
04045    if (!m1 && !m2) {
04046       err_msg("BMESH::merge: warning: both meshes are null.");
04047       return BMESHptr(0);
04048    } else if (!m1) {
04049       return m2;        // don't fret it
04050    } else if (!m2) {
04051       return m1;        // or sweat it
04052    } else if (m1->class_name() != m2->class_name()) {
04053       cerr << "BMESH::merge: bad luck! the meshes are different types:\n   "
04054            << m1->class_name()
04055            << " and "
04056            << m2->class_name()
04057            << endl;
04058       return BMESHptr(0);
04059    }
04060 
04061    // try to think of everything. they might be the same mesh.
04062    if (m1 == m2)
04063       return m1; // don't fuss about it
04064 
04065    // make sure m1 is the larger mesh (more vertices).
04066    // m2 will get sucked into m1 and be left as an empty husk.
04067 //    if (m2->nverts() > m1->nverts())
04068 //       swap(m1,m2);      // swap pointers
04069 
04070    // m2 is now the smallest. check it's not taking smallness to an
04071    // extreme:
04072    if (m2->empty()) {
04073       err_msg("BMESH::merge: smaller mesh is empty");
04074       return m1;
04075    }
04076 
04077    // transform m2 into the coordinate system of m1:
04078    m2->transform(m1->inv_xform()*m2->xform(), MOD());
04079 
04080    // now do the merging via the virtual method that lets LMESHes
04081    // (e.g.) deal with any LMESH-specific merge issues:
04082    m1->_merge(m2);
04083 
04084    return m1;
04085 }
04086 
04087 void
04088 BMESH::_merge(BMESH* m)
04089 {
04090    // Merge the elements of mesh m into this one.
04091    //
04092    // For this protected method, it's okay to assume error checking
04093    // has already been done by the caller -- i.e. by the public method
04094    // BMESH::merge().
04095 
04096    assert(m);
04097 
04098    // Suck in verts, edges and faces:
04099    _verts.append(m->_verts);
04100    _edges.append(m->_edges);
04101    _faces.append(m->_faces);
04102 
04103    m->_verts.clear();
04104    m->_edges.clear();
04105    m->_faces.clear();
04106 
04107    // Suck in patches
04108    while (!m->_patches.empty()) {
04109       _patches += m->_patches.pop();
04110       _patches.last()->set_mesh(this);
04111    }
04112 
04113    // Suck in drawables
04114    _drawables.operator+=(m->_drawables);
04115    m->_drawables.clear();
04116 
04117    // determine the "type" of the resulting mesh:
04118    if (_type_valid && m->_type_valid) {
04119       _type |= m->_type;
04120       // That pretty much works... but it can't be both an open and
04121       // closed surface:
04122       if (_type & OPEN_SURFACE)
04123          _type &= ~CLOSED_SURFACE;
04124 
04125       // Invalidation
04126       _vert_locs.clear();
04127       BODY::_edges.reset();
04128       _body = 0;
04129       _bb.reset();
04130 
04131       // So display lists get rebuilt:
04132       _version++;
04133 
04134    } else {
04135       // This will ensure the proper type is figured out when needed:
04136       changed(TOPOLOGY_CHANGED);
04137    }
04138 
04139    // That poor sucker definitely changed in either case:
04140    m->changed(TOPOLOGY_CHANGED);
04141 
04142    // Tell observers this mesh absorbed that one:
04143    BMESHobs::broadcast_merge(this, &*m);
04144 }
04145 
04146 // assumes flags were cleared previously
04147 void
04148 BMESH::grow_mesh_equivalence_class(
04149    Bvert* v,
04150    ARRAY<Bface*> &faces,
04151    ARRAY<Bedge*> &edges,
04152    ARRAY<Bvert*> &verts)
04153 
04154 {
04155    if (v->flag() == 0)
04156       return;
04157 
04158    for (int i=0; i<v->degree(); i++) {
04159       Bedge* nbr_e = v->e(i);
04160       Bvert* nbr_v = v->nbr(i);
04161 
04162       for (int j=1; j<=2; j++) {
04163          Bface *f = nbr_e->f(j);
04164          if (f && !f->flag()) {
04165             f->set_flag();
04166             faces += f;
04167          }
04168       }
04169 
04170       if (!nbr_e->flag()) {
04171          nbr_e->set_flag();
04172          edges += nbr_e;
04173       }
04174 
04175       if (!nbr_v->flag()) {
04176          nbr_v->set_flag();
04177          verts += nbr_v;
04178 
04179          grow_mesh_equivalence_class(nbr_v, faces, edges, verts);
04180       }
04181    }
04182 }
04183 
04184 ARRAY<BMESH*>
04185 BMESH::split_components()
04186 {
04187    // Splits mesh into disconnected pieces.
04188    // Returns array of new meshes.
04189 
04190    ARRAY<BMESH*> new_meshes;
04191 
04192    // clear flags
04193    _verts.clear_flags();
04194    _edges.clear_flags();
04195    _faces.clear_flags();
04196 
04197    // split up
04198 
04199    // Work from a copy of the vertices since the list will
04200    // get sucked out from under us otherwise:
04201    Bvert_list tmp_verts = _verts;
04202 
04203    for (int i=0; i<tmp_verts.num(); i++) {
04204       Bvert* v = tmp_verts[i];
04205       if (!v->flag()) {
04206 
04207          // Mesh elements reachable from v:
04208          ARRAY<Bface*> faces;
04209          ARRAY<Bedge*> edges;
04210          ARRAY<Bvert*> verts;
04211 
04212          // The flag being set means the vertex (or edge or face)
04213          // is in the list:
04214          v->set_flag();
04215          verts += v;
04216 
04217          // Collect all reachable elements:
04218          grow_mesh_equivalence_class(v, faces, edges, verts);
04219 
04220          // The 1st mesh is us... leave it alone.
04221          if (i == 0)
04222             continue;
04223 
04224          // Make a new mesh after the first time.
04225          BMESH* m = (BMESH*)dup();
04226          new_meshes += m;
04227 
04228          int t;
04229          for (t=0; t<verts.num(); t++) {
04230             _verts -= verts[t];         // remove from this mesh
04231             m->add_vertex(verts[t]);    // add to the new mesh
04232          }
04233 
04234          for (t=0; t<edges.num(); t++) {
04235             _edges -= edges[t];         // remove from this mesh
04236             m->add_edge(edges[t]);      // add to the new mesh
04237          }
04238 
04239          // The new patch will take the face away from its
04240          // current patch, if any.
04241          Patch* p = m->new_patch();
04242          for (t=0; t<faces.num(); t++) {
04243             _faces -= faces[t];         // remove from this mesh
04244             m->add_face(faces[t],p);    // add to the new mesh
04245          }
04246 
04247          if (m != this)
04248             m->changed(TOPOLOGY_CHANGED);
04249       }
04250    }
04251 
04252    // Remove empty patches:
04253    clean_patches();
04254 
04255    changed(TOPOLOGY_CHANGED);
04256 
04257    BMESHobs::broadcast_split(this, new_meshes);
04258 
04259    return new_meshes;
04260 }
04261 
04262 ARRAY<Bface_list>
04263 BMESH::get_components() const
04264 {
04265    // Returns separate Bface_lists, one for
04266    // each connected component of the mesh:
04267 
04268    ARRAY<Bface_list> ret;
04269 
04270    // before calling Bface_list::grow_connected(),
04271    // must set all face flags to 1:
04272    _faces.set_flags(1);
04273 
04274    for (int i=0; i<_faces.num(); i++) {
04275       Bface* f = bf(i);
04276       if (f->flag() == 1) {
04277          Bface_list component;
04278          component.grow_connected(f);
04279          assert(!component.empty());
04280          ret += component;
04281       }
04282    }
04283    return ret;
04284 }
04285 
04286 void
04287 BMESH::split_tris(Bface* start_face, Wplane plane, ARRAY<Bvert*>& new_vs)
04288 {
04289    Bedge* curr_edge = 0;
04290    for (int ed=1; ed<4; ed++)
04291       if (start_face->e(ed)->which_side(plane) == 0) {
04292          curr_edge = start_face->e(ed);
04293          break;
04294       }
04295 
04296    if (!curr_edge) {
04297       cerr << "BMESH::split_tris: lost my edge, can't go on" << endl;
04298       return;
04299    }
04300 
04301    Bvert *new_pt;
04302    Bvert *last_pt  = 0;
04303    Bvert *start_pt = 0;
04304 
04305    do {
04306       if (last_pt) {
04307          Bface_list faces;
04308          last_pt->get_faces(faces);
04309          for (int i=0; i<faces.num(); i++) {
04310             curr_edge = faces[i]->opposite_edge(last_pt);
04311             if (curr_edge->which_side(plane) == 0) {
04312                if (new_vs.empty())
04313                   break;
04314                else {
04315                   Bvert* oldv = new_vs[new_vs.num()-2];
04316                   if (!faces[i]->contains(oldv))
04317                      break;
04318                }
04319             }
04320          }
04321       }
04322 
04323       Wpt p1 = curr_edge->v1()->loc();
04324       Wpt p2 = curr_edge->v2()->loc();
04325       double d1 = fabs(plane.dist(p2));
04326       double d2 = fabs(plane.dist(p1));
04327       Wpt pt = ((d1 * p1) + (d2 * p2)) / (d1+d2);
04328 
04329       new_pt = split_edge(curr_edge, pt);
04330       new_vs += new_pt;
04331 
04332       if (!last_pt)
04333          start_pt = new_pt;
04334 
04335       last_pt = new_pt;
04336    } while (new_vs.num() < 3 || last_pt->lookup_edge(start_pt) == 0);
04337 }
04338 
04339 
04340 void
04341 BMESH::kill_component(Bvert *start_vert)
04342 {
04343    ARRAY<Bface*> faces;
04344    ARRAY<Bedge*> edges;
04345    ARRAY<Bvert*> verts;
04346 
04347    int i;
04348    for (i=0; i<nfaces(); i++)
04349       _faces[i]->clear_flag();
04350    for (i=0; i<nedges(); i++)
04351       _edges[i]->clear_flag();
04352    for (i=0; i<nverts(); i++)
04353       _verts[i]->clear_flag();
04354 
04355    start_vert->set_flag();
04356    verts += start_vert;
04357 
04358    grow_mesh_equivalence_class(start_vert, faces, edges, verts);
04359 
04360    cerr << "removed " << faces.num() << " faces, "
04361         << edges.num() << " edges, " << verts.num() << " vertices" << endl;
04362 
04363    int t;
04364    for (t=0; t<faces.num(); t++)
04365       delete_face(faces[t]);
04366 
04367    for (t=0; t<edges.num(); t++)
04368       delete_edge(edges[t]);
04369 
04370    for (t=0; t<verts.num(); t++)
04371       delete_vert(verts[t]);
04372 
04373    changed(TOPOLOGY_CHANGED);
04374 }
04375 
04376 
04377 // Does a Patch with a current GTexture named name already exist in this
04378 // mesh?
04379 int
04380 BMESH::tex_already_exists(Cstr_ptr &name) const
04381 {
04382    int exists = 0;
04383    if (patches().num()) {
04384       for (int i = 0; !exists && i < patches().num(); i++) {
04385          exists = patches()[i]->cur_tex()->type() == name;
04386       }
04387    }
04388    return exists;
04389 }
04390 
04391 double
04392 BMESH::z_span() const
04393 {
04394    double a, b;
04395    return z_span(a, b);
04396 }
04397 
04398 double
04399 BMESH::z_span(double& zmin, double& zmax) const
04400 {
04401    // take the bounding box of this mesh,
04402    // collect its corners into a list of points,
04403    // transform these points to NDCZ,
04404    // find the min and max z values,
04405    // return the difference
04406 
04407    static Wpt_list pts(8);
04408 
04409    if (!(((BMESH*)this)->get_bb().points(pts)))
04410       return 2.0;       // z values lie between -1 and 1
04411 
04412    pts.xform(obj_to_ndc());
04413 
04414    zmin = pts[0][2];
04415    zmax = zmin;
04416    for (int i=1; i<pts.num(); i++) {
04417       double z = pts[i][2];
04418       zmin = min(zmin, z);
04419       zmax = max(zmax, z);
04420    }
04421 
04422    return (zmax - zmin);
04423 }
04424 
04425 
04426 void
04427 BMESH::compute_pix_size()
04428 {
04429    // XXX -
04430    //   probably should use world_length so this will be more
04431    //   robust when the mesh is partly offscreen or behind the
04432    //   camera.
04433 
04434    _pix_size_stamp = VIEW::stamp();
04435    BBOX bb = xform()*get_bb();
04436    double size = bb.dim().length();
04437    Wpt pos = bb.center();
04438    Wvec perp = VIEW::peek_cam()->data()->right_v();
04439    assert(!perp.is_null());
04440    _pix_size = VEXEL(pos, size * perp).length();
04441 }
04442 
04443 //******** RENDERING STYLE ********
04444 
04445 // the rendering style is only set on a mesh when you want
04446 // to override the current rendering style of the view.
04447 // i.e., almost never.
04448 //
04449 void
04450 BMESH::set_render_style(Cstr_ptr& s)
04451 {
04452    if (_render_style.empty())
04453       push_render_style(s) ;
04454    else
04455       _render_style.last() = s;
04456    changed(RENDERING_CHANGED);
04457 }
04458 
04459 void
04460 BMESH::push_render_style(Cstr_ptr& s)
04461 {
04462    _render_style += s;
04463    changed(RENDERING_CHANGED);
04464 }
04465 
04466 void
04467 BMESH::pop_render_style()
04468 {
04469    if (!_render_style.empty())
04470       _render_style.pop();
04471    changed(RENDERING_CHANGED);
04472 }
04473 
04474 Cstr_ptr&
04475 BMESH::render_style() const
04476 {
04477    return _render_style.empty() ? str_ptr::null_str() : _render_style.last();
04478 }
04479 
04480 /*****************************************************************
04481  * BMESHray
04482  *****************************************************************/
04483 void
04484 BMESHray::check(
04485    double    d,
04486    int       is_surface,
04487    double    d_2d,
04488    CGELptr  &g,
04489    CWvec    &n,
04490    CWpt     &nearpt,
04491    CWpt     &surfl,
04492    APPEAR   *app,
04493    CXYpt    &tex_coord
04494    )
04495 {
04496    if (test(d, is_surface, d_2d)) {
04497       // the RAYhit is being redefined ... clear the old simplex.
04498       set_simplex(0);
04499       RAYhit::check(d, is_surface, d_2d, g, n, nearpt, surfl, app, tex_coord);
04500    }
04501 }
04502 
04503 /*************************************************************
04504  * BMESHobs
04505  ************************************************************/
04506 void
04507 BMESHobs::broadcast_change(BMESH* m, BMESH::change_t change)
04508 {
04509    // Notify observers who watch all meshes
04510    _all_observers.notify_change(m, change);
04511 
04512    // Notify observers of the given mesh
04513    bmesh_obs_list(m).notify_change(m, change);
04514 }
04515 
04516 void
04517 BMESHobs::broadcast_xform(BMESH* mesh, CWtransf& xf, CMOD& mod)
04518 {
04519    // Notify observers who watch all meshes
04520    _all_observers.notify_xform(mesh, xf, mod);
04521 
04522    // Notify observers of the given mesh
04523    bmesh_obs_list(mesh).notify_xform(mesh, xf, mod);
04524 }
04525 
04526 void
04527 BMESHobs::broadcast_merge(BMESH* joined, BMESH* removed)
04528 {
04529    // The 'joined' mesh just sucked everything out of the
04530    // 'removed' mesh, which is now an empty husk.
04531 
04532    // Notify observers who watch all meshes
04533    _all_observers.notify_merge(joined, removed);
04534 
04535    // Notify observers of the joined mesh.
04536    //
04537    // Get observer list by copying, since some observers
04538    // might start hopping in and out of the original list
04539    // while we iterate over it.
04540    //
04541    // XXX - Actually the observers of the joined mesh will almost
04542    // certainly stay where they are, since their mesh wasn't
04543    // destroyed, it just jot bigger.
04544    BMESHobs_list joined_obs = bmesh_obs_list(joined);
04545    joined_obs.notify_merge(joined, removed);
04546 
04547    // Notify observers of the removed mesh.
04548    // Again work with a copy of the observer list.
04549    // This time they probably will jump off the sinking ship.
04550    BMESHobs_list removed_obs = bmesh_obs_list(removed);
04551    removed_obs.notify_merge(joined, removed);
04552 }
04553 
04554 void
04555 BMESHobs::broadcast_split(BMESH* m, CARRAY<BMESH*>& new_meshes)
04556 {
04557    // Notify observers who watch all meshes
04558    _all_observers.notify_split(m, new_meshes);
04559 
04560    // Notify observers of the given mesh.
04561    // Work from a copy of the list in case observers start
04562    // hopping between lists.
04563    BMESHobs_list list = bmesh_obs_list(m);
04564    list.notify_split(m, new_meshes);
04565 }
04566 
04567 void
04568 BMESHobs::broadcast_subdiv_gen(BMESH* m)
04569 {
04570    // Notify observers who watch all meshes
04571    _all_observers.notify_subdiv_gen(m);
04572 
04573    // Notify observers of the given mesh
04574    bmesh_obs_list(m).notify_subdiv_gen(m);
04575 }
04576 
04577 void
04578 BMESHobs::broadcast_delete(BMESH* m)
04579 {
04580    // Notify observers who watch all meshes
04581    _all_observers.notify_delete(m);
04582 
04583    // Notify observers of the given mesh.
04584    // Work with a copy of the observer list in case
04585    // observers start hopping around.
04586    BMESHobs_list list = bmesh_obs_list(m);
04587    list.notify_delete(m);
04588 }
04589 
04590 void
04591 BMESHobs::broadcast_sub_delete(BMESH* m)
04592 {
04593    // Notify observers who watch all meshes
04594    _all_observers.notify_sub_delete(m);
04595 
04596    // Notify observers of the given mesh.
04597    bmesh_obs_list(m).notify_sub_delete(m);
04598 }
04599 
04600 void
04601 BMESHobs::broadcast_update_request(BMESH* m)
04602 {
04603    // This is for observers who want to update the mesh
04604    // before it does something important like try to
04605    // draw itself.
04606    bmesh_obs_list(m).notify_update_request(m);
04607 
04608    // XXX - Notify observers who watch all meshes? Nah.
04609 }
04610 
04611 /*************************************************************
04612  * BMESHobs
04613  ************************************************************/
04614 void
04615 BMESHobs_list::notify_change(BMESH* mesh, BMESH::change_t change) const
04616 {
04617    for (int i=0; i<_num; i++)
04618       _array[i]->notify_change(mesh, change);
04619 }
04620 
04621 void
04622 BMESHobs_list::notify_xform(BMESH* mesh, CWtransf& xf, CMOD& m) const
04623 {
04624    for (int i=0; i<_num; i++)
04625       _array[i]->notify_xform(mesh, xf, m);
04626 }
04627 
04628 void
04629 BMESHobs_list::notify_merge(BMESH* m1, BMESH* m2) const
04630 {
04631    for (int i=0; i<_num; i++)
04632       _array[i]->notify_merge(m1, m2);
04633 }
04634 
04635 void
04636 BMESHobs_list::notify_split(BMESH* mesh, CARRAY<BMESH*>& pieces) const
04637 {
04638    for (int i=0; i<_num; i++)
04639       _array[i]->notify_split(mesh, pieces);
04640 }
04641 
04642 void
04643 BMESHobs_list::notify_subdiv_gen(BMESH* mesh) const
04644 {
04645    for (int i=0; i<_num; i++)
04646       _array[i]->notify_subdiv_gen(mesh);
04647 }
04648 
04649 void
04650 BMESHobs_list::notify_delete(BMESH* mesh) const
04651 {
04652    for (int i=0; i<_num; i++)
04653       _array[i]->notify_delete(mesh);
04654 }
04655 
04656 void
04657 BMESHobs_list::notify_sub_delete(BMESH* mesh) const
04658 {
04659    for (int i=0; i<_num; i++)
04660       _array[i]->notify_sub_delete(mesh);
04661 }
04662 
04663 void
04664 BMESHobs_list::notify_update_request(BMESH* mesh) const
04665 {
04666    for (int i=0; i<_num; i++)
04667       _array[i]->notify_update_request(mesh);
04668 }
04669 
04670 void
04671 BMESHobs_list::print_names() const
04672 {
04673    for (int i=0; i<_num; i++)
04674       cerr << _array[i]->name() << " ";
04675    cerr << endl;
04676 }
04677 
04678 /* end of file bmesh.C */

Generated on Mon Sep 18 11:39:28 2006 for jot by  doxygen 1.4.4