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

patch.C

Go to the documentation of this file.
00001 /*!
00002  *  \file patch.C
00003  *  \brief Contains the implementation of the Patch class.
00004  *
00005  *  \sa patch.H
00006  *
00007  */
00008 
00009 #include "ioblock.H"
00010 #include "gtexture.H"
00011 #include "bfilters.H"
00012 #include "patch.H"
00013 #include "std/config.H"
00014 #include "sps/sps.H"
00015 
00016 // example defined in src/jot.C:
00017 init_fade_func_t Patch::_init_fade = 0;
00018 
00019 TAGlist*  Patch::_patch_tags    = 0;
00020 int Patch::_next_stencil_id = 0;
00021 
00022 //********************** MANAGERS **********************
00023 Patch::Patch(BMESH* mesh) :
00024    _mesh(mesh),
00025    _faces(0),
00026    _creases(0),
00027    _borders(0),
00028    _textures(0),
00029    _cur_tex_i(0),
00030    _non_tex_i(0),
00031    _prev_tex(0),
00032    _pixels(0),
00033    _stamp(0),
00034    _mesh_version(0),
00035    _tri_strips_dirty(1),
00036    _tex_coord_gen(0),
00037    _data(0),
00038    _stencil_id(0),
00039    _scale(1.0),
00040    _o(PIXEL(0,0)),
00041    _u_o(PIXEL(1,0)),
00042    _v_o(PIXEL(0,1)),
00043    _dynamic_stamp(UINT_MAX),
00044    _do_dynamic_stuff(true),
00045    _do_lod(true),
00046    _lod_t(0)
00047 {
00048    _textures.set_unique();
00049 
00050    //XXX - By default, APPEARs will look white if no
00051    //      color is defined, so let's not pollute the
00052    //      .jot files with yet more gunk...
00053    //set_color(COLOR::white);
00054 
00055    if (_mesh)
00056      _mesh->changed(BMESH::RENDERING_CHANGED);
00057 
00058    set_name(str_ptr("patch-") + str_ptr(_mesh->patches().num()));
00059 }
00060 
00061 Patch::~Patch()
00062 {
00063    //XXX - Moved this up here...
00064    _textures.delete_all();
00065 
00066    // Get out of the patch list if needed:
00067    if (_mesh) _mesh->unlist(this);
00068    _mesh = 0;
00069 
00070    // The patch owns its tri_strips, crease strips, and Gtexures, 
00071    // but not its faces, edge strips, or vert strips. So it deletes
00072    // the former but not the latter.
00073    while (!_tri_strips.empty())
00074       delete _tri_strips.pop();
00075    delete _creases;
00076    delete _borders;
00077 
00078    //XXX - Moved this higher so that GTextures that do things
00079    //      like unobserving meshes on destruction, still have
00080    //      a valid _mesh pointer...
00081    //_textures.delete_all();
00082    
00083    for (int i=0; i<_faces.num(); i++) {
00084       _faces[i]->set_patch(0);
00085       _faces[i]->set_patch_index(-1);
00086    }
00087 }
00088 
00089 void 
00090 Patch::triangulation_changed() 
00091 {
00092    _tri_strips_dirty = 1;
00093 
00094    creases_changed();
00095    borders_changed();
00096 
00097    changed(); 
00098 }
00099 
00100 void 
00101 Patch::creases_changed() 
00102 {
00103    delete _creases;
00104    _creases = 0; 
00105 }
00106 
00107 void 
00108 Patch::borders_changed() 
00109 {
00110    delete _borders;
00111    _borders = 0; 
00112 }
00113 
00114 //********************** ACCESSING PATCH GEOMETRY **********************
00115 EdgeStrip&
00116 Patch::build_sils()
00117 {
00118    // May be a no-op (after the first time in the current frame):
00119    _mesh->build_sil_strips();
00120 
00121    return _sils;
00122 }
00123 
00124 ZcrossPath&
00125 Patch::build_zx_sils()
00126 {
00127    // May be a no-op (after the first time in the current frame):
00128    _mesh->build_zcross_strips();
00129 
00130    return _zx_sils;
00131 }
00132 
00133 /*!
00134  *  Utility method used in build_creases() and build_borders().
00135  *  
00136  *  Fill the given edge strip with edges of a given type that
00137  *  belong to this patch.
00138  *
00139  */
00140 EdgeStrip*
00141 Patch::build_edge_strip(EdgeStrip* strip, CSimplexFilter& filter)
00142 {
00143 
00144    if (strip) {
00145       strip->reset();
00146       strip->build_with_tips(edges(), filter + PatchEdgeFilter(this));
00147    }
00148    return strip;
00149 }
00150 
00151 EdgeStrip*
00152 Patch::build_creases()
00153 {
00154    // If _creases is non-null, it is assumed to be up-to-date.
00155    if (_creases)
00156       return _creases;
00157 
00158    // Attempt to generate an EdgeStrip of the correct type
00159    // (maybe LedgeStrip), depending on the mesh type (maybe LMESH):
00160    _creases = _mesh ? _mesh->new_edge_strip() : new EdgeStrip();
00161 
00162    // Fill it in and return it:
00163    return build_edge_strip(_creases, CreaseEdgeFilter());
00164 }
00165 
00166 EdgeStrip*
00167 Patch::build_borders()
00168 {
00169    // If _borders is non-null, it is assumed to be up-to-date.
00170    if (_borders)
00171       return _borders;
00172 
00173    // Attempt to generate an EdgeStrip of the correct type
00174    // (maybe LedgeStrip), depending on the mesh type (maybe LMESH):
00175    _borders = _mesh ? _mesh->new_edge_strip() : new EdgeStrip();
00176 
00177    // Fill it in and return it:
00178    return build_edge_strip(_borders, BorderEdgeFilter());
00179 }
00180 
00181 Bvert_list
00182 Patch::verts() const
00183 {
00184    // Return vertices of faces of this patch
00185 
00186    assert(_mesh);
00187 
00188    // Short-cut if patch is whole mesh
00189    if (_mesh->nfaces() == _faces.num() &&
00190        !(_mesh->is_polylines() || _mesh->is_points()))
00191       return _mesh->verts();
00192 
00193    return _faces.get_verts();
00194 }
00195 
00196 Bedge_list
00197 Patch::edges() const
00198 {
00199    // Return edges of faces of this patch
00200 
00201    assert(_mesh);
00202 
00203    // Short-cut if patch is whole mesh
00204    if (_mesh->nfaces() == _faces.num() && !_mesh->is_polylines())
00205       return _mesh->edges();
00206 
00207    return _faces.get_edges();
00208 }
00209 
00210 //********************** BUILDING **********************
00211 void            
00212 Patch::add(Bface* f) 
00213 {
00214    // Check for no-op:
00215    if (!f || f->patch() == this)
00216       return;
00217 
00218    // Take it out of its current patch:
00219    if (f->patch())
00220       f->patch()->remove(f);
00221 
00222    // Add it to the face list etc.:
00223    f->set_patch_index(_faces.num());
00224    _faces += f;
00225    f->set_patch(this);
00226 
00227    triangulation_changed();
00228 }
00229 
00230 void            
00231 Patch::remove(Bface* f) 
00232 {
00233    if (!(f && f->patch() == this)) {
00234       err_msg("Patch::remove: error: face is NULL or not owned by this Patch");
00235       return;
00236    }
00237 
00238    int k = f->patch_index();
00239    if (_faces.valid_index(k)) {
00240       _faces.remove(k);
00241       _faces[k]->set_patch_index(k);
00242    }
00243    f->set_patch_index(-1);
00244    f->set_patch(0);
00245    triangulation_changed();
00246 }
00247 
00248 void            
00249 Patch::add(VertStrip* vs) 
00250 {
00251    if (vs->patch())
00252       vs->patch()->remove(vs);
00253    vs->set_patch(this);
00254    vs->set_patch_index(_vert_strips.num());
00255    _vert_strips += vs;
00256    changed();
00257 }
00258 
00259 void            
00260 Patch::remove(VertStrip* vs) 
00261 {
00262    assert(vs->patch() == this);
00263    int k = vs->patch_index();
00264    if (_vert_strips.valid_index(k)) {
00265       _vert_strips.remove(k);
00266       _vert_strips[k]->set_patch_index(k);
00267       changed();
00268    }
00269    vs->set_patch_index(-1);
00270    vs->set_patch(0);
00271 }
00272 
00273 void            
00274 Patch::add(EdgeStrip* es) 
00275 {
00276    if (es->patch())
00277       es->patch()->remove(es);
00278    es->set_patch(this);
00279    es->set_patch_index(_edge_strips.num());
00280    _edge_strips += es;
00281    changed();
00282 }
00283 
00284 void            
00285 Patch::remove(EdgeStrip* es) 
00286 {
00287    assert(es->patch() == this);
00288    int k = es->patch_index();
00289    if (_edge_strips.valid_index(k)) {
00290       _edge_strips.remove(k);
00291       _edge_strips[k]->set_patch_index(k);
00292       changed();
00293    }
00294    es->set_patch_index(-1);
00295    es->set_patch(0);
00296 }
00297 
00298 void
00299 Patch::build_tri_strips()
00300 {
00301    if (_tri_strips_dirty) {
00302       _tri_strips_dirty = 0;
00303 
00304       // get rid of old strips:
00305       int k;
00306       for (k=0; k<_tri_strips.num(); k++)
00307          delete _tri_strips[k];
00308       _tri_strips.clear();
00309 
00310       // clear face flags before finding triangle strips
00311       for (k=0; k<_faces.num(); k++) {
00312          _faces[k]->clear_flag();
00313          _faces[k]->orient_strip(0);
00314       }
00315 
00316       // If secondary faces shouldn't be drawn, set their flags
00317       // so they won't be drawn:
00318       if (!BMESH::show_secondary_faces())
00319          _faces.secondary_faces().set_flags(1);
00320 
00321       for (k=0; k<_faces.num(); k++)
00322          if (!_faces[k]->flag())
00323             TriStrip::get_strips(_faces[k], _tri_strips);
00324 
00325       static bool debug = Config::get_var_bool("PRINT_TRIS_PER_STRIP",false);
00326       if (debug)
00327          err_msg("tris/strip: %1.1f", tris_per_strip());
00328    }
00329 }
00330 
00331 //********************** DRAWING **********************
00332 int
00333 Patch::draw(CVIEWptr& v)
00334 {
00335    GTexture* cur = cur_tex(v);
00336    if (!cur)
00337       return 0;
00338 
00339    // if we just switched GTextures then setup a fade from
00340    // the old one to the new one:
00341    static const double FADE_DUR = Config::get_var_dbl("FADE_DUR", 0.5,true);
00342    if (_prev_tex && _prev_tex != cur && _init_fade)
00343       (*_init_fade)(cur, _prev_tex, v->frame_time(), FADE_DUR);
00344    _prev_tex = cur;
00345    int ret = cur->draw(v);
00346    _pixels.clear();
00347    return ret;
00348 }
00349 
00350 int
00351 Patch::draw_tri_strips(StripCB* cb)
00352 {
00353    build_tri_strips();
00354 
00355    for (int k=0; k<_tri_strips.num(); k++)
00356       _tri_strips[k]->draw(cb);
00357    
00358    return _faces.num();
00359 }
00360 
00361 int
00362 Patch::draw_sil_strips(StripCB *cb)
00363 {
00364    cur_sils().draw(cb);
00365    return cur_sils().num();
00366 }
00367 
00368 int
00369 Patch::draw_crease_strips(StripCB *cb)
00370 {
00371    EdgeStrip* strip = cur_creases();
00372    if (strip)
00373       strip->draw(cb);
00374    return 0;
00375 }
00376 
00377 int
00378 Patch::draw_edge_strips(StripCB *cb)
00379 {
00380    // Obsolete
00381 
00382    int ret=0;
00383 
00384    // draw edges as line strips
00385    for (int i=0; i<_edge_strips.num(); i++) {
00386       _edge_strips[i]->draw(cb);
00387       ret += _edge_strips[i]->num();
00388    }
00389 
00390    return ret;
00391 }
00392 
00393 int
00394 Patch::draw_vert_strips(StripCB *cb)
00395 {
00396    int ret=0;
00397 
00398    // draw point strips (vertices as dots):
00399    for (int i=0; i<_vert_strips.num(); i++) {
00400       _vert_strips[i]->draw(cb);
00401       ret += _vert_strips[i]->num();
00402    }
00403 
00404    return ret;
00405 }
00406 
00407 //********************** PROCEDURAL TEXTURES **********************
00408 void
00409 Patch::set_texture(GTexture* gtex)
00410 {
00411    if (!gtex) {
00412       err_msg("Patch::set_texture: can't set nil texture");
00413       return;
00414    }
00415    _textures.add_uniquely(gtex);
00416    _cur_tex_i = _textures.get_index(gtex);
00417 //    _mesh->changed(BMESH::RENDERING_CHANGED);
00418 }
00419 
00420 void
00421 Patch::set_texture(Cstr_ptr& style)
00422 {
00423    _cur_tex_i = get_tex_index(style);
00424 //    _mesh->changed(BMESH::RENDERING_CHANGED);
00425 }
00426 
00427 void
00428 Patch::next_texture()
00429 {
00430    _cur_tex_i = (_cur_tex_i + 1) % _textures.num();
00431 //    _mesh->changed(BMESH::RENDERING_CHANGED);
00432 }
00433 
00434 /*!
00435  *  Find an existing texture of the given type,
00436  *  but don't create one if it can't be found.
00437  *
00438  */
00439 GTexture* 
00440 Patch::find_tex(Cstr_ptr& tex_name) const
00441 {
00442 
00443    //Hack so that both textures point to the same class
00444    str_ptr temp_tex_name;
00445    if(tex_name == "FFSTexture2")
00446        temp_tex_name = "FFSTexture";
00447    else
00448        temp_tex_name = tex_name;
00449        
00450    for (int i=0; i<_textures.num(); i++)
00451       if (_textures[i]->type() == temp_tex_name)
00452          return _textures[i];
00453 
00454    return 0;
00455 }
00456 
00457 /*!
00458  *  Returns a texture by class name.
00459  *  Finds one or gets one.
00460  *
00461  */
00462 GTexture*
00463 Patch::get_tex(Cstr_ptr& tex_name)
00464 {
00465 
00466    // first try to find one
00467    GTexture* tex = find_tex(tex_name);
00468    if (tex)
00469       return tex;
00470 
00471    // if not found, instantiate it.
00472    tex = (GTexture*)DATA_ITEM::lookup(tex_name);
00473    if (!tex)
00474       return 0;        // can't look it up
00475 
00476    // got one of the right type, now duplicate it
00477    if ((tex = (GTexture*)tex->dup())) {
00478       tex->set_patch(this);
00479       _textures += tex;
00480       return tex;
00481    } else {
00482       err_msg("Patch::get_tex: tex->dup() returned nil");
00483       return 0;        // can't duplicate it
00484    }
00485 }
00486 
00487 /*!
00488  *  The texture name to use comes from the mesh, unless it's
00489  *  the null string, then it comes from the view. If the
00490  *  texture name is GTexture::static_name() then return the
00491  *  Patch's "current texture." Otherwise return a texture
00492  *  matching the given texture name.
00493  *
00494  */
00495 GTexture*
00496 Patch::cur_tex(CVIEWptr& v)
00497 {
00498 
00499    // What name are we going for?
00500    str_ptr tex_name =
00501       (_mesh->render_style() == str_ptr::null_str()) ?
00502       v->rendering() :
00503       _mesh->render_style();
00504 
00505    if (tex_name == GTexture::static_name()) {
00506       GTexture* tex = cur_tex();
00507       if (tex)
00508          return tex;
00509 
00510       // If there is no current texture, go w/ flat shading as a
00511       // default:
00512       tex_name = RFLAT_SHADE;
00513    }
00514 
00515    return get_tex(tex_name);
00516 }
00517 
00518 //********************** I/O FUNCTIONS **********************
00519 int
00520 Patch::write_stream(ostream &os)
00521 {
00522    // Don't write an empty patch, because the convention
00523    // below is that a patch with ALL the faces signals it by
00524    // claiming to have "0" faces.
00525    //
00526    // XXX - must be a better way.
00527 
00528    if (_faces.empty())
00529       return 0;
00530 
00531    assert(_mesh != NULL);
00532 
00533    os << "#BEGIN PATCH" << endl;
00534 
00535    //******** FACES ********
00536 
00537    // Don't output any faces if this patch has all the faces
00538    if (_faces.num() > _mesh->nfaces()) {
00539 
00540       // Never happens
00541       assert(0);
00542 
00543    } else if (_faces.num() == _mesh->nfaces()) {
00544 
00545       // We have them all. "0" faces here is a secret code
00546       // meaning "all" faces.
00547       os << (int)0 << endl;
00548 
00549    } else {
00550 
00551       // If this is a subdivision mesh, we're writing out
00552       // the faces at the current level of subdivision:
00553       CBface_list& cfaces = cur_faces();
00554 
00555       // Number of faces in this patch
00556       os << cfaces.num() << endl;
00557 
00558       for (int f=0; f<cfaces.num(); f++) {
00559          assert(get_ctrl_patch(cfaces[f]) == this);
00560          os << cfaces[f]->index() << endl;
00561       }
00562    }
00563    
00564    //******** GTEXTURES ********
00565    os << endl<< _cur_tex_i << endl;
00566    _textures.write_stream(os);
00567 
00568    //******** NAME ********
00569    if (_name != NULL_STR) {
00570       os << "#BEGIN PATCHNAME" << endl;
00571       os << _name << endl;
00572       os << "#END PATCHNAME" << endl;
00573    }
00574    
00575    //******** COLOR ********
00576    if (_has_color) {
00577       os << "#BEGIN COLOR" << endl;
00578       os << _color << endl;
00579       os << "#END COLOR" << endl;
00580    }
00581    
00582    //******** TEXTURE MAP ********
00583    if (has_texture()) {
00584       os << "#BEGIN TEXTURE_MAP" << endl;
00585       os << _texture->file() << endl;
00586       os << "#END TEXTURE_MAP" << endl;
00587    }
00588 
00589    os << "#END PATCH" << endl;
00590 
00591    return 1;
00592 }
00593 
00594 int
00595 Patch::read_stream(istream &is, str_list &leftover)
00596 {
00597    leftover.clear();
00598    // Number of faces in this patch
00599    int num_faces;
00600    is >> num_faces;
00601 
00602    bool debug = Config::get_var_bool("DEBUG_PATCH_READ_STREAM",false);
00603    if (debug)
00604       err_msg("\n********\nPatch::read_stream: %d faces to read", num_faces);
00605 
00606    if (num_faces > 0) {
00607 
00608       if (debug)
00609          err_msg("Patch::read_stream: reading %d faces from file", num_faces);
00610 
00611       // for each face...
00612       int face;
00613       for (int f = 0; f < num_faces; f++) {
00614          is >> face;
00615          if (face < _mesh->nfaces()) {
00616             add(_mesh->bf(face));
00617          } else {
00618             cerr << "Patch::read_stream - face " << face << " > "
00619                << _mesh->nfaces()
00620                << ", at byte " << is.tellg() << endl;
00621          }
00622       }
00623    } else {
00624       if (debug)
00625          err_msg("Patch::read_stream: using all %d faces of mesh",
00626                  _mesh->nfaces());
00627 
00628       for (int f = 0; f < _mesh->nfaces(); f++)
00629          add(_mesh->bf(f));
00630    }
00631 
00632    is >> _cur_tex_i;
00633    if (debug)
00634       err_msg("Patch::read_stream: cur texture is number %d", _cur_tex_i);
00635    
00636    // Save old textures
00637    GTexture_list tmp_textures = _textures;
00638    // Clear texture list
00639    _textures.clear();
00640    
00641 
00642    // continue reading the file but now check for tokens
00643    static IOBlockList blocklist;
00644    if (blocklist.num() == 0) {
00645       blocklist += new IOBlockMeth<Patch>("GTEXTURE", &Patch::read_texture,
00646                                           this);
00647       blocklist += new IOBlockMeth<Patch>("COLOR",    &Patch::read_color,
00648                                           this);
00649       blocklist += new IOBlockMeth<Patch>("TEXTURE_MAP",
00650                                           &Patch::read_texture_map,
00651                                           this);
00652       blocklist += new IOBlockMeth<Patch>("PATCHNAME",&Patch::read_patchname,
00653                                           this);
00654    } else {
00655       for (int i = 0; i < blocklist.num(); i++) {
00656          ((IOBlockMeth<Patch> *) blocklist[i])->set_obj(this);
00657       }
00658    }
00659    int ret = IOBlock::consume(is, blocklist, leftover);
00660 
00661    changed();
00662    
00663    if (_textures.num() > 0) {
00664 
00665       if (debug) {
00666          err_msg("Patch::read_stream: read %d textures", _textures.num());
00667          err_msg(" ... deleting %d old textures", tmp_textures.num());
00668       }
00669 
00670       // Textures were loaded in, so get rid of previous textures
00671       tmp_textures.delete_all();
00672 
00673    } else {
00674 
00675       if (debug)
00676          err_msg("Patch::read_stream: read 0 textures, keeping old ones");
00677 
00678       // No textures were loaded in, go back to pre-existing texture list
00679       _textures = tmp_textures;
00680    }
00681 
00682    return ret;
00683 }
00684 
00685 int
00686 Patch::read_texture(istream &is, str_list &leftover)
00687 {
00688    leftover.clear();
00689    const int namelen = 256;
00690    char name1[namelen];
00691    char name[namelen];
00692    char *wherecr;
00693    is.getline(name1, namelen); // Finish "#BEGIN GTEXTURE" line 
00694    is.getline(name, namelen); // Get name of texture
00695    
00696    // Strip out CR
00697    // XXX - also in ViewStroke::read_stroke()
00698    while ((wherecr = strchr(name, '\015'))) {
00699       *wherecr = 0;
00700    }
00701    int texnum = get_tex_index(name);
00702    if (texnum < 0) {
00703       // Clear spaces at end
00704       // XXX - this should be in str_ptr
00705       while (strrchr(name, ' ') == name + strlen(name) - 1) {
00706          name[strlen(name) - 1] = '\0';
00707       }
00708       texnum = get_tex_index(name);
00709    }
00710    GTexture* tex = texnum >= 0 ? _textures[texnum] : 0;
00711    if (!tex) {
00712       cerr << "Patch::read_texture - could not find GTexture '"
00713            << name << "' (skipping)" << endl;
00714       return 1;
00715    }
00716 
00717    return tex->read_stream(is, leftover);
00718 }
00719 
00720 int
00721 Patch::read_color(istream &is, str_list &leftover)
00722 {
00723    leftover.clear();
00724 
00725    COLOR c;
00726    is >> c;
00727    set_color(c);
00728 
00729    return 1;
00730 }
00731 
00732 int
00733 Patch::read_texture_map(istream &is, str_list &leftover)
00734 {
00735    leftover.clear();
00736 
00737    char buf[126];
00738    is >> buf;
00739    _texture_file = str_ptr(buf);
00740 
00741    return 1;
00742 }
00743 
00744 int
00745 Patch::read_patchname(istream &is, str_list &leftover)
00746 {
00747    leftover.clear();
00748    const int namelen = 256;
00749    char name[256];
00750    is.getline(name, namelen); // Finish "#BEGIN PATCHNAME" line 
00751    is.getline(name, namelen); // Get name of patch
00752    set_name(name);
00753 
00754    return 1;
00755 }
00756 
00757 //********************** RefImageClient METHODS **********************
00758 RefImageClient::ref_img_t
00759 Patch::use_ref_image()
00760 {
00761    GTexture* tex = cur_tex(VIEW::peek());
00762    return tex ? tex->use_ref_image() : REF_IMG_NONE;
00763 }
00764 
00765 int
00766 Patch::draw_vis_ref()
00767 {
00768    GTexture* tex = cur_tex(VIEW::peek());
00769    return tex ? tex->draw_vis_ref() : 0;
00770 }
00771 
00772 int
00773 Patch::draw_ref_img(ref_img_t t)
00774 {
00775    GTexture* tex = cur_tex(VIEW::peek());
00776    return tex ? tex->draw_ref_img(t) : 0;
00777 }
00778 
00779 int
00780 Patch::draw_final(CVIEWptr &v)
00781 {
00782    GTexture* tex = cur_tex(VIEW::peek());
00783    return tex ? tex->draw_final(v) : 0;
00784 }
00785 
00786 //********************** DATA_ITEM METHODS **********************
00787 CTAGlist &
00788 Patch::tags() const
00789 {
00790    if (!_patch_tags) {
00791       _patch_tags = new TAGlist(0);
00792       *_patch_tags += new TAG_meth<Patch>   ("faces",    &Patch::put_faces,
00793                                                          &Patch::get_faces,  1);
00794 
00795       *_patch_tags += new TAG_val<Patch,int>("cur_tex",        &Patch::cur_tex_i_);
00796       *_patch_tags += new TAG_val<Patch,str_ptr>("patchname",  &Patch::name_);
00797       //XXX - Changed to only writing it when 
00798       //      has_color is true
00799       //*_patch_tags += new TAG_val<Patch,COLOR>  ("color",      &Patch::color_);
00800       *_patch_tags += new TAG_meth<Patch>   ("color",  &Patch::put_color,
00801                                                    &Patch::get_color, 0);
00802 
00803       // XXX - textures (why the XXX?!)
00804       *_patch_tags += new TAG_meth<Patch>   ("texture",  &Patch::put_textures,
00805                                                          &Patch::get_texture, 1);
00806    }
00807    return *_patch_tags;
00808 }
00809 
00810 DATA_ITEM*
00811 Patch::dup() const
00812 {
00813    // to be filled in...
00814 
00815    return 0;
00816 }
00817 
00818 
00819 //********************** APPEAR METHODS **********************
00820 CCOLOR &
00821 Patch::color() const
00822 {
00823    return APPEAR::color();
00824 }
00825 
00826 bool
00827 Patch::has_color() const
00828 {
00829    return APPEAR::has_color();
00830 }
00831 
00832 void
00833 Patch::set_color(CCOLOR  &c)
00834 {
00835    // should be in APPEAR
00836    if (has_color() && color().is_equal(c))
00837       return;
00838 
00839    APPEAR::set_color(c);
00840 }
00841 
00842 void
00843 Patch::unset_color()
00844 {
00845    APPEAR::unset_color();
00846 }
00847 
00848 double
00849 Patch::transp() const
00850 {
00851    return APPEAR::transp();
00852 }
00853 
00854 bool
00855 Patch::has_transp() const
00856 {
00857    return APPEAR::has_transp();
00858 }
00859 
00860 void
00861 Patch::set_transp(double t) 
00862 { 
00863    APPEAR::set_transp(t); 
00864 }
00865 
00866 void
00867 Patch::unset_transp()       
00868 { 
00869    APPEAR::unset_transp(); 
00870 }
00871 
00872 void
00873 Patch::set_texture(CTEXTUREptr& t)
00874 {
00875    APPEAR::set_texture(t);
00876    changed();
00877 }
00878 
00879 void
00880 Patch::unset_texture()
00881 {
00882    APPEAR::unset_texture();
00883    changed();
00884 }
00885 
00886 void
00887 Patch::get_texture(TAGformat &d)
00888 {
00889    str_ptr str, str1;
00890    *d >> str;
00891 
00892    if ((*d).ascii())
00893    {
00894       while (str1 = (*d).get_string_with_spaces())
00895       {
00896          str = str + " " + str1;
00897       }
00898    }
00899 
00900    int texnum = get_tex_index(str);
00901 
00902    if (texnum < 0) 
00903    {
00904       err_msg("Patch::get_texture() - ERROR! Could not find texture '%s'", **str);
00905       return;
00906    }
00907 
00908    GTexture* tex = _textures[texnum];   assert(tex);
00909 
00910    err_mesg(ERR_LEV_SPAM, "Patch::get_texture() - Loaded: '%s'", **str);
00911    
00912    tex->decode(*d);
00913 
00914 }
00915 
00916 void
00917 Patch::put_textures(TAGformat &d) const
00918 {
00919    for (int t = 0; t < _textures.num(); t++) 
00920    {
00921       err_mesg(ERR_LEV_SPAM, "Patch::put_textures() - Writing texture #%d '%s'", 
00922          t, **_textures[t]->class_name());
00923       d.id();
00924       _textures[t]->format(*d);
00925       d.end_id();
00926    }
00927 }
00928 
00929 void
00930 Patch::recompute()
00931 {
00932    if (_faces.empty()) {
00933       // This patch has no faces, so we take all the faces...
00934       for (int k = 0; k<_mesh->nfaces(); k++) {
00935          add(_mesh->bf(k));
00936       }
00937    }
00938 }
00939 
00940 void
00941 Patch::get_faces(TAGformat &d)
00942 {
00943    ARRAY<int> faces;
00944    *d >> faces;
00945 
00946    // for each face...
00947    for (int f = 0; f < faces.num(); f++) 
00948    {
00949       if (faces[f] < _mesh->nfaces()) 
00950       {
00951          add(_mesh->bf(faces[f]));
00952       } 
00953       else 
00954       {
00955          err_msg("Patch::get_faces() - ERROR! face #%d > %d.", faces[f], _mesh->nfaces());
00956       }
00957    }
00958 }
00959 
00960 void
00961 Patch::put_faces(TAGformat &d) const
00962 {
00963    // XXX - no faces entry means all faces
00964    if (_faces.num() == ((Patch *) this)->mesh()->nfaces()) return;
00965 
00966    ARRAY<int> faces(_faces.num());
00967 
00968    for (int f=0; f<_faces.num(); f++) 
00969    {
00970       const Bface *outf = _faces[f];
00971       if (outf->patch() != this) 
00972       {
00973          err_msg("Patch::put_faces() - ERROR! face #%d has ownership issues...", outf->index());
00974       }
00975       faces += outf->index();
00976    }
00977    d.id();
00978    *d << faces;
00979    d.end_id();
00980 }
00981 
00982 // Dynamic Samples Stuff
00983 
00984 inline VEXEL
00985 cmult(CVEXEL& a, CVEXEL& b)
00986 {
00987    // complex number multiplication:
00988    return VEXEL(a[0]*b[0] - a[1]*b[1], a[0]*b[1] + a[1]*b[0]);
00989 }
00990 inline bool
00991 is_good(CBvert* v)
00992 {
00993    return v && v->is_front_facing() && v->wloc().in_frustum();
00994 }
00995 
00996 inline double
00997 get_weight(CBvert* v)
00998 {
00999     return (!is_good(v)) ? 0 : 1.0;
01000 }
01001 
01002 inline bool
01003 is_good(CBface* f, CWpt& p)
01004 {
01005    
01006    return f && f->front_facing() && p.in_frustum();
01007 }
01008 
01009 inline double
01010 get_weight(CBface* f, CWpt& p)
01011 {
01012     return (!is_good(f, p)) ? 0 : 1.0;
01013 }
01014 
01015 inline double
01016 sum_weights(const vector<DynamicSample>& w1, const vector<DynamicSample>& w2)
01017 {
01018    // sum of w1 weights; but don't count any w1 when
01019    // the corresponding w2 value is 0
01020 
01021    double ret = 0;
01022    for (uint i=0; i< w1.size(); ++i)
01023       if ((w1[i]).get_weight() > 0 && (w2[i]).get_weight() > 0)
01024          ret += (w1[i]).get_weight();
01025    return ret;
01026 }
01027 
01028 inline PIXEL
01029 weighted_sum(const vector<DynamicSample>& w1,
01030              const vector<DynamicSample>& w2)
01031 {
01032    // weighted sum; but don't count any w1 when
01033    // the corresponding w2 value is 0
01034 
01035    assert(w1.size() == w2.size());
01036    PIXEL ret;
01037    for (uint i=0; i<w1.size(); ++i)      
01038       if (w1[i].get_weight() > 0 && w2[i].get_weight() > 0)
01039          ret += w1[i].get_pix()*w1[i].get_weight();
01040    return ret;
01041 }
01042 
01043 void 
01044 Patch::create_dynamic_samples()
01045 {
01046    _old_samples.clear();
01047 
01048    Bface_list faces;
01049    ARRAY<Wvec> bc_list;
01050 
01051    generate_samples(_mesh, faces ,bc_list ,5 ,0.35 ,20);
01052    //cerr << "Patch::create_dynamic_samples : Made samples: " << faces.num() << endl; 
01053    assert(faces.num() == bc_list.num());
01054    //Bvert_list& verts = cur_patch()->verts();
01055    for(int i=0; i < faces.num(); ++i){
01056       //Wvec bc(1.0, 0.0, 0.0);
01057       //bool weight = get_weight((CBvert*)verts[i]);
01058       //PIXEL pix = verts[i]->pix();
01059       //DynamicSample sample(verts[i], bc, pix, weight);
01060       
01061 
01062       Wpt pos;
01063       faces[i]->bc2pos(bc_list[i], pos);
01064       PIXEL pix = PIXEL(pos);
01065       double weight = get_weight((CBface*)faces[i], pos);
01066       DynamicSample sample(faces[i], bc_list[i], pix, weight); 
01067       _old_samples.push_back(sample);
01068    }
01069 }
01070 
01071 void
01072 Patch::update_dynamic_samples()
01073 {
01074    if(!_do_dynamic_stuff)
01075       return;
01076    
01077    if (_dynamic_stamp == VIEW::stamp())
01078       return;
01079    _dynamic_stamp = VIEW::stamp();
01080 
01081    // compute a 2D translation (delt) and rotation and uniform
01082    // scale (z) from the 2D motion of sample points on the patch
01083    VEXEL delt;   
01084    delt = VEXEL(0,0);
01085    _z = VEXEL(1,0);
01086    if(_old_samples.empty())
01087       create_dynamic_samples();  
01088 
01089    // create the new samples:
01090    vector<DynamicSample>  new_samples; 
01091    for (uint i=0; i< _old_samples.size(); ++i) {
01092       //Wvec bc(1.0, 0.0, 0.0);      
01093       //PIXEL pix = ((CBvert*)(_old_samples[i].get_simplex()))->pix();
01094       //bool weight = get_weight((CBvert*)_old_samples[i].get_simplex());
01095       //DynamicSample sample(_old_samples[i].get_simplex(), bc, pix, weight);
01096 
01097       PIXEL pix = PIXEL(_old_samples[i].get_pos(xform()));
01098       bool weight = get_weight((CBface*)_old_samples[i].get_simplex(),
01099                                _old_samples[i].get_pos(xform()));
01100       DynamicSample sample(_old_samples[i].get_simplex(),
01101                            _old_samples[i].get_bc(), pix, weight);
01102       new_samples.push_back(sample);
01103    }
01104 
01105    // we are assuming the number of samples stays constant each frame: 
01106    assert(new_samples.size() == _old_samples.size());
01107 
01108    // Compute the transformation from old samples to new samples.
01109    // It is a combination of translation, rotation, and uniform scale.
01110    // The latter two are represented by multiplication by complex number z.
01111 
01112    // Get old and new average locations (using weights).
01113    double ow = sum_weights(_old_samples,  new_samples); // total of old weights
01114    double nw = sum_weights( new_samples, _old_samples); // total of new weights
01115   
01116    if (ow < epsZeroMath() || nw < epsZeroMath()) {
01117       // Few or no sample points to work with (weights are all 0).
01118       // Should just start over in this case...
01119       //cerr << "Patch::calculate_xform: too few samples: " << endl;
01120       _old_samples = new_samples;  
01121 
01122    //recursive call but it's ok, it will use current new samples as old ones
01123    update_dynamic_samples();
01124 
01125       return;
01126    }
01127    _old_center = weighted_sum(_old_samples,  new_samples)/ow;
01128    _new_center = weighted_sum(new_samples, _old_samples)/nw;
01129    
01130    // compute the translation:
01131    delt = _new_center - _old_center;
01132 
01133    // compute z via least-squares method:
01134    _z = VEXEL(0,0);
01135    double so = 0;     // sum of squares of "old" vectors
01136    double sn = 0;     // sum of squares of "new" vectors
01137    for (unsigned int k=0; k< new_samples.size(); ++k) {
01138       if (new_samples[k].get_weight() > 0 && _old_samples[k].get_weight() > 0) {
01139          
01140          VEXEL  o = _old_samples[k].get_pix() - _old_center;
01141          VEXEL  n =  new_samples[k].get_pix() - _new_center;
01142 
01143          double w = new_samples[k].get_weight();  // ignore old weight?         
01144          _z  += VEXEL(o*n, det(o,n))*w;
01145          so += o.length_sqrd()*w;
01146          sn += n.length_sqrd()*w;
01147       }
01148    }
01149    if (isZero(so) || isZero(sn)) {
01150       // impossible? old/new samples are each concentrated at a point
01151       cerr << "Patch::calculate_xform: error, divide by zero "
01152          << so << " " << sn << " " << new_samples.size() <<" " << _old_samples.size() << endl;
01153       _z = VEXEL(1,0);
01154  
01155      //create_dynamic_samples(); <- bad idea 
01156      return;
01157    } 
01158 
01159    bool do_symmetric = true;
01160    if (!do_symmetric) {
01161       // old policy: scaling is not symmetric if you swap "old" and "new":
01162       _z /= so;
01163    } else {
01164       // new policy: does symmetric scaling, prevents shrinkage:
01165       _z = _z.normalized() * sqrt(sn/so);
01166    }
01167    // store the new locations/weights for next time:
01168    _old_samples.clear();
01169    _old_samples = new_samples;
01170 
01171    // LOD Stuff
01172    if(_do_lod)
01173       _scale *= _z.length();
01174 
01175    _o = _new_center + cmult(_o - _old_center, _z);
01176    _u_o = _new_center + cmult(_u_o - _old_center, _z);
01177    _v_o = _new_center + cmult(_v_o - _old_center, _z);
01178 
01179    // LOD computations:
01180    double s = _scale;
01181    assert(s > 0);
01182    // ensure s is in [1,2)
01183    while (s >= 2) s /= 2;
01184    while (s < 1)  s *= 2;
01185 
01186    // find interpolation parameter t between the 2 scales:
01187    const float st0 = 1.3; // transition start
01188    const float st1 = 1.7; // transition end
01189    _lod_t = (s < st0) ? 0.0 : (s > st1) ? 1.0: (s - st0)/(st1 - st0);
01190    _lod_u = sample_u_vec().normalized()*s;
01191    _lod_v = sample_v_vec().normalized()*s;
01192 
01193    if (Config::get_var_bool("DEBUG_DYN_SAMPLE_LOD",false))
01194       cerr << "s0: " << s/2 << ", s1: " << s << ", t: " << _lod_t << endl;
01195 }
01196 
01197 void 
01198 Patch::reset_dynamic_samples()
01199 {
01200 }
01201 
01202 // end of file patch.C

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