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

geom.C

Go to the documentation of this file.
00001 #include "disp/cam_focus.H"
00002 #include "disp/ray.H"
00003 #include "disp/view.H"
00004 #include "geom/geom.H"
00005 #include "geom/body.H"
00006 #include "geom/gl_view.H"
00007 #include "geom/gl_util.H"
00008 #include "std/config.H"
00009 
00010 #include "std/thread_mutex.H"
00011 
00012 using namespace mlib;
00013 
00014 BODY*       BODY::_factory = 0;
00015 CXYpt_list  BODY::_dummy(0);
00016 
00017 int         MOD::_TICK              = 0;
00018 int         MOD::_START             = 0;
00019 GEOM*       GEOM::null;
00020 TAGlist*    GEOM::_geom_tags;
00021 
00022 bool GEOM::_do_halo_view = Config::get_var_bool("DO_VIEW_HALOS",false);
00023 bool GEOM::_do_halo_ref  = Config::get_var_bool("DO_REF_HALOS", true);
00024 
00025 
00026 // Hash table fields
00027 // MAKE_NET_HASHVAR is used so these values are networked
00028 MAKE_NET_HASHVAR (XFORM_ON_BODY, int, 0);
00029 MAKE_NET_HASHVAR (HIGHLIGHTED  , int, 0);
00030 XformConstraint CONSTRAINT("CONSTRAINT", GEOM::TRANS_FREE, 1);
00031 
00032 // See net/data_item.H for more information
00033 static int gm=DECODER_ADD(GEOM);
00034 
00035 STDdstream &
00036 operator>>(STDdstream &ds, GEOMptr &p) 
00037 {
00038    DATA_ITEM *d = DATA_ITEM::Decode(ds);
00039    if (d && GEOM::isa(d))
00040       p = (GEOM *)d;
00041    else {
00042       cerr << "operator >> Couldn't find GEOM in stream" << endl;
00043       p = 0;
00044    }
00045      
00046    return ds;
00047 }
00048 
00049 /* ---- geometric object interface ----- */
00050 //
00051 // These functions are place holders for intersect methods in GEOM subclasses
00052 //
00053 RAYnear &
00054 GEOM::nearest(RAYnear &r, CWtransf &) const 
00055 {
00056    return r;
00057 }
00058 
00059 void 
00060 GEOM::set_body(CBODYptr& b)
00061 {
00062    if (b == _body)
00063       return;
00064    if (_body)
00065       _body->set_geom(0);    // clear GEOM* in old body
00066    _body = b;
00067    if (_body)
00068       _body->set_geom(this); // set GEOM* in new body
00069 }
00070 
00071 CWtransf&
00072 GEOM::inv_xform () const 
00073 {
00074    if (_inv_xf_dirty) {
00075       GEOM *me = (GEOM*)this;
00076       me->_inv_xf=xform().inverse();
00077       me->_inv_xf_dirty = 0;
00078    }
00079    return _inv_xf;
00080 }
00081 
00082 bool
00083 GEOM::find_cam_focus(CVIEWptr& view, mlib::CXYpt& x)
00084 {
00085    static const bool debug = Config::get_var_bool("DEBUG_CAM_FOCUS",false);
00086 
00087    RAYhit r(view->intersect(x));
00088    GEOMptr geom = GEOM::upcast(r.geom());
00089    if (geom) {
00090       return geom->do_cam_focus(view, r);
00091    }
00092    // failed
00093    if (debug) {
00094       cerr << "GEOM::find_cam_focus: nothing to focus on" << endl;
00095    }
00096    return false;
00097 }
00098 
00099 bool
00100 GEOM::do_cam_focus(CVIEWptr& view, CRAYhit& r)
00101 {
00102    if (Config::get_var_bool("DEBUG_CAM_FOCUS",false))
00103       cerr << "GEOM::do_cam_focus (" << name() << ")"
00104            << endl;
00105 
00106    assert(r.geom() == this);
00107 
00108    CAMptr     cam (view->cam());
00109    CAMdataptr data(cam->data());
00110 
00111    // detect "silhouette" by doing ray test to the right and left
00112    // (in image space), to see if we hit background space on one
00113    // side but not the other:
00114    XYvec    D(VEXEL(25,0)); // left/right displacement
00115    RAYhit   sil_r(r.screen_point() + D);
00116    RAYhit   sil_l(r.screen_point() - D);
00117    intersect(sil_r);
00118    intersect(sil_l);
00119 
00120    // If angle between surface normal and world up vector
00121    // is over 12 degrees, and cheesy silhouette detection
00122    // returns true, do silhouette focus:
00123    if (rad2deg(r.norm().angle(Wvec::Y())) > 12.0 &&
00124        XOR(sil_r.success(), sil_l.success())) {
00125       Wvec sil_comp;
00126       if (sil_r.success())
00127          sil_comp = -data->right_v() * 6.0 * r.dist();
00128       else
00129          sil_comp =  data->right_v() * 6.0 * r.dist();
00130 
00131       Wvec v(sil_comp + r.norm() * 4.0 * r.dist());
00132       Wpt  newpos(r.surf() + r.dist() * v.normalized());
00133       newpos[1] = data->from()[1];
00134       newpos = r.surf() + (newpos - r.surf()).normalized() * r.dist();
00135 
00136       new CamFocus(view, newpos, r.surf(), newpos + Wvec::Y(), r.surf(),
00137                    data->width(), data->height());
00138    } else {
00139       // do normal focus:
00140       Wpt  center(r.surf());
00141       Wvec norm  (r.norm().normalized());
00142       if (norm * Wvec::Y() > 0.98)
00143          norm = -data->at_v();
00144 
00145       Wvec  off   (cross(Wvec::Y(),norm).normalized() * 3);
00146       Wvec  atv   (data->at_v() - Wvec::Y() * (data->at_v() * Wvec::Y()));
00147       Wvec  newvec(norm*6 + 4.0*Wvec::Y()); 
00148       if ((center + newvec + off - data->from()).length() > 
00149           (center + newvec - off - data->from()).length())
00150          off = newvec - off;
00151       if (data->persp())
00152          off = (newvec + off).normalized() * 
00153             (data->from()-Wline(data->from(),data->at()).project(center)).
00154             length();
00155 
00156       new CamFocus(view, center + off, center, center + off + Wvec::Y(), 
00157                    center, data->width(), data->height());
00158    }
00159    return true;
00160 }
00161 
00162 /* ---- GEOM constructors ----- */
00163 
00164 GEOM::GEOM() :
00165    GEL(),
00166    _inv_xf_dirty(1),
00167    _bbox_id(-1) 
00168 {
00169 }
00170 
00171 GEOM::GEOM(Cstr_ptr &n, CBODYptr& b) :
00172    GEL(),
00173    _name(n),
00174    _body(b),
00175    _inv_xf_dirty(1),
00176    _bbox_id(-1)
00177 {
00178    if (_body)
00179       _body->set_geom(this);
00180 }
00181 
00182 GEOM::GEOM(
00183    CGEOMptr &o,
00184    Cstr_ptr &name
00185    ) :
00186    GEL(o),
00187    APPEAR(o),
00188    _name(name),
00189    _xform(o->_xform),
00190    _inv_xf_dirty(1),
00191    _bbox_id(-1)
00192 {
00193    if (o && o->body()) {
00194       _body = (BODY*)o->body()->dup();
00195       assert(_body != 0);
00196       _body->set_geom(this);
00197       *_body = *o->body();
00198    }
00199 }
00200 
00201 GEOM::~GEOM()
00202 {
00203 }
00204 
00205 CTAGlist &
00206 GEOM::tags() const
00207 {
00208    if (!_geom_tags) {
00209       _geom_tags = new TAGlist;
00210       *_geom_tags += GEL::tags();
00211       *_geom_tags += new TAG_meth<GEOM>("name",  &GEOM::put_name,
00212                                         &GEOM::get_name, 0);
00213       *_geom_tags += new TAG_meth<GEOM>("xform", &GEOM::put_xf,
00214                                         &GEOM::get_xf, 0);
00215       *_geom_tags += new TAG_meth<GEOM>("color", &GEOM::put_color,
00216                                         &GEOM::get_color);
00217       *_geom_tags += new TAG_meth<GEOM>("texture",&GEOM::put_texture,
00218                                         &GEOM::get_texture,1);
00219       *_geom_tags += new TAG_meth<GEOM>("transp",&GEOM::put_transp,
00220                                         &GEOM::get_transp);
00221    }
00222    return *_geom_tags;
00223 }
00224 
00225 /* ---- GEOM geometry/display ----- */
00226 
00227 int 
00228 GEOM::draw(CVIEWptr &v)
00229 {
00230    if (!_body)
00231       return 0;
00232 
00233    glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
00234 
00235    // Default policy is we say YES to polygon offset.
00236    GL_VIEW::init_polygon_offset();  // GL_ENABLE_BIT
00237 
00238    // use glEnable(GL_NORMALIZE) only when needed
00239    if (!xform().is_orthonormal())
00240       glEnable (GL_NORMALIZE); // GL_ENABLE_BIT
00241 
00242    // GL_CURRENT_BIT
00243    GL_COL(_has_color ? _color : COLOR::white, _has_transp ? _transp : 1);
00244 
00245    // set xform:
00246    glMatrixMode(GL_MODELVIEW);
00247    glPushMatrix();
00248    glMultMatrixd(xform().transpose().matrix());
00249 
00250    // draw the mesh normally:
00251    int ret = _body->draw(v);
00252 
00253    glPopMatrix();
00254 
00255    GL_VIEW::end_polygon_offset(); // GL_ENABLE_BIT
00256 
00257    glPopAttrib();
00258 
00259    return ret;
00260 }
00261 
00262 int
00263 GEOM::draw_vis_ref()
00264 {
00265    if (!_body)
00266       return 0;
00267 
00268    glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT);
00269    glMatrixMode(GL_MODELVIEW);
00270    glPushMatrix();
00271 
00272    glMultMatrixd(xform().transpose().matrix());
00273 
00274    // Default policy is we say YES to polygon offset.
00275    GL_VIEW::init_polygon_offset();  // GL_ENABLE_BIT
00276    int ret = _body->draw_vis_ref();
00277    GL_VIEW::end_polygon_offset();   // GL_ENABLE_BIT
00278 
00279    glPopMatrix();
00280    glPopAttrib();
00281 
00282    return ret;
00283 }
00284 
00285 int
00286 GEOM::draw_ref_img(ref_img_t t)
00287 {
00288    if (!_body)
00289       return 0;
00290 
00291    glMatrixMode(GL_MODELVIEW);
00292    glPushMatrix();
00293    glMultMatrixd(xform().transpose().matrix());
00294 
00295    GL_VIEW::init_polygon_offset();
00296    int ret = _body->draw_ref_img(t);
00297    GL_VIEW::end_polygon_offset();
00298 
00299    glPopMatrix();
00300 
00301    return ret;
00302 }
00303 
00304 RefImageClient::ref_img_t
00305 GEOM::use_ref_image()
00306 {
00307    return _body ? _body->use_ref_image() : REF_IMG_NONE;
00308 }
00309 
00310 int
00311 GEOM::draw_final(CVIEWptr &v)
00312 {
00313    if (!_body)
00314       return 0;
00315 
00316    glMatrixMode(GL_MODELVIEW);
00317    glPushMatrix();
00318    glMultMatrixd(xform().transpose().matrix());
00319 
00320    int ret = _body->draw_final(v);
00321 
00322    glPopMatrix();
00323 
00324    return ret;
00325 }
00326 
00327 RAYhit&
00328 GEOM::intersect(RAYhit& ray, CWtransf&, int) const
00329 {
00330    if (_body) {
00331       _body->intersect(ray, xform());
00332    }
00333    return ray;
00334 }
00335 
00336 MAKE_NET_HASHVAR(NO_CULL, int, 0);
00337 
00338 bool
00339 GEOM::cull(
00340    const VIEW *
00341    ) const
00342 {
00343    // say no if body is missing or culling is not allowed
00344    CBODYptr &bod = body();
00345    if (!bod || NO_CULL.get(((GEOM *)this)))
00346       return 0;
00347 
00348    // let the bounding box decide
00349    return bbox().is_off_screen();
00350 }
00351 
00352 // FIXME - Should be per-object, not global
00353 static ThreadMutex bbox_mutex;
00354 
00355 //
00356 // Only compute world space bounding box if the object has been transformed
00357 // or the object space bounding box is invalid
00358 //
00359 BBOX
00360 GEOM::bbox(int) const
00361 {
00362    if (!body()) {
00363       ((GEOM *) this)->_bbox.reset();
00364    } else {
00365       CriticalSection cs(&bbox_mutex);
00366       if (!body()->bb_valid()) {                     // Obj space bb valid?
00367          BBOX bb = body()->get_bb();
00368          double s = 1.0; // scale factor; was 1.1
00369          Wtransf xf = Wtransf::scaling(xform() * bb.center(), s) * xform();
00370          ((GEOM*)this)->_bbox = xf * bb;
00371       }
00372    }
00373    return _bbox;
00374 }
00375 
00376 
00377 /* ---- GEOM printing/networking ----- */
00378 
00379 // Print out a GEOM for debugging purposes
00380 ostream &
00381 GEOM::print(ostream &os)   const
00382 { 
00383    os << class_name() << "::" << name() << "\n\t";
00384    return os;
00385 }
00386 
00387 //
00388 // When a GEOM's transformation is changed, that change has to be
00389 // propagated to GEOM's that depend on that transformation
00390 //
00391 void
00392 GEOM::write_xform(
00393    CWtransf &x, 
00394    CWtransf &y, 
00395    CMOD     &m
00396    ) 
00397 {
00398    _xform = x;
00399    _inv_xf_dirty = true;
00400    REFlock lock(this);
00401    XFORMobs::notify_xform_every_obs(this);
00402 }
00403 
00404 void       
00405 GEOM::mult_by(
00406    CWtransf &x
00407    )
00408 {
00409    write_xform(x * _xform, Wtransf(), MOD());
00410 }
00411 
00412 void 
00413 GEOM::set_color(
00414    CCOLOR  &c
00415    )
00416 { 
00417    REFlock lock(this);
00418    APPEAR::set_color(c); 
00419    COLORobs::notify_color_obs(this); 
00420 }
00421 
00422 void 
00423 GEOM::unset_color()
00424 { 
00425    REFlock lock(this);
00426    APPEAR::unset_color(); 
00427    COLORobs::notify_color_obs(this); 
00428 }
00429 
00430 void
00431 GEOM::set_texture(CTEXTUREptr& t)
00432 {  
00433    REFlock lock(this);
00434    APPEAR::set_texture(t);
00435    TEXTUREobs::notify_texture_obs(this);
00436 }
00437 
00438 void
00439 GEOM::unset_texture()
00440 {
00441    REFlock lock(this);
00442    APPEAR::unset_texture();
00443    TEXTUREobs::notify_texture_obs(this);
00444 }
00445 
00446 
00447 /* ---- GEOMobs routines ----- */
00448 
00449 GEOMobs_list GEOMobs::_all_geom(32);
00450 
00451 /* ---- TRANSPobs routines ----- */
00452 
00453 TRANSPobs_list TRANSPobs::_all_transp(32);
00454 
00455 /* ---- COLORobs routines ----- */
00456 
00457 COLORobs_list   *COLORobs::_all_col = 0;
00458 
00459 /* ---- TEXTUREobs routines ----- */
00460 
00461 TEXTUREobs_list *TEXTUREobs::_all_texture = 0;
00462 
00463 /* ---- XFORMobs routines ----- */
00464 
00465 XFORMobs_list XFORMobs::_every_xf(32);
00466 XFORMobs_list XFORMobs::_all_xf(32);
00467 HASH          XFORMobs::_hash_xf(32);
00468 
00469 /* -------------------------------------------------------------
00470  *
00471  * XFORMobs
00472  *
00473  *   This class provides callbacks when an object's transformation 
00474  * changes.  The following method is a static helper method that
00475  * provides an easy way to make the XFORMobs callbacks for all XFORMobs
00476  * observing a particular GEOM
00477  *
00478  * ------------------------------------------------------------- */
00479 void
00480 XFORMobs::notify_xform_obs(
00481    CGEOMptr        &g, 
00482    XFORMobs::STATE  st
00483    )
00484 {
00485    // Notify observers who want to know about all xform
00486    int i;
00487    for (i = 0; i < _all_xf.num(); i++)
00488       _all_xf[i]->notify_xform(g, st);
00489 
00490    // Notify all xform observers
00491    XFORMobs_list &list = xform_obs_list(g);
00492    for (i = 0; i <list.num(); i++) {
00493       XFORMobs *obs = list[i];
00494       obs->notify_xform(g, st);
00495    }
00496 }
00497 
00498 void
00499 XFORMobs::notify_xform_every_obs(
00500    CGEOMptr        &g
00501    )
00502 {
00503    // Notify observers who want to know about all xform
00504    int i;
00505    for (i = 0; i < _every_xf.num(); i++)
00506       _every_xf[i]->notify_xform(g, EVERY);
00507 }

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