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

cam.C

Go to the documentation of this file.
00001 #include "std/support.H"
00002 #include "std/config.H"
00003 #include "disp/cam_focus.H"
00004 #include "net/stream.H"
00005 #include "net/net_types.H"
00006 
00007 
00008 using namespace mlib;
00009 
00010 CAMdata::CAMdata(CAM* c) :
00011    _cam(c),
00012    _from(0,0,5),
00013    _at(0,0,0),
00014    _up(0,1,5),
00015    _center(0,0,0),
00016    _focal(1),
00017    _width(1),
00018    _height(1),
00019    _perspective(true),
00020    _tilt_up(0),
00021    _tilt_left(0),
00022    _iod(2.25), 
00023    _feature_scale(0.5),
00024    _film_normal(0,0,1),
00025    _film_normal_flag(false),
00026    _loaded_from_file(false),
00027    _cblist(0),
00028    _cached(0),
00029    _stamp(0)
00030 {
00031    _iod = Config::get_var_dbl("IOD",2.25,true);
00032    changed();
00033 }
00034 
00035 
00036 void
00037 CAMdata::cache() const
00038 {
00039    if (!_cached) {
00040       CAMdata *me = (CAMdata *)this; // cast away const'ness
00041       me->_cached  = 1;
00042       me->_dist    = (_center-_from).length();
00043       me->_at_v    = (_at-_from).normalized();
00044       me->_up_v    = (_up-_from).normalized(); 
00045       me->_pup_v   = _up_v.orthogonalized(_at_v).normalized(); 
00046       me->_right_v = cross(_at_v, _pup_v).normalized();
00047    }
00048 }
00049 
00050 void
00051 CAMdata::changed()
00052 {
00053    _cached = 0;
00054    int i;
00055    for (i = LEFT; i < NUM_EYE_POSITIONS; i++) {
00056       _pos_mat_dirty[i] = 1;
00057       _proj_mat_dirty = 1;
00058    }
00059    if (_cam)
00060       _cam->data_changed(); // sets CAM::_ndc_proj_dirty = 1;
00061 
00062    ++_stamp;
00063 
00064    for (i=0; i<_cblist.num(); i++)
00065       _cblist[i]->notify(this);
00066 }
00067 
00068 void      
00069 CAMdata::start_manip()
00070 {
00071    for (int i=0; i<_cblist.num(); ++i)
00072       _cblist[i]->notify_manip_start(this);   
00073 }
00074    
00075 void
00076 CAMdata::end_manip()
00077 {
00078    for (int i=0; i<_cblist.num(); ++i)
00079       _cblist[i]->notify_manip_end(this);
00080    
00081 }
00082 /* -------------------------------------------------------------------------
00083  * DESCR   :    finds the (unit length) film plane normal vector.  It prints
00084  *              an error message and returns FALSE if anything goes wrong.
00085  *
00086  * RETURNS :    Success boolean.  The computed normal vetor is passed back
00087  *              in the argument @normal@.
00088  * ------------------------------------------------------------------------- */
00089 bool
00090 CAMdata::film_normal(
00091    CWvec      &at,             /* at vector                            */
00092    CWvec      &up,             /* up vector                            */
00093    Wvec       &normal          /* normal vector ( will be computed )   */
00094    ) const
00095 {
00096    double x = tan(_tilt_left);
00097    double y = tan(_tilt_up);
00098 
00099    Wvec v1 = cross(at, up).normalized();// normalized cross product of at and up
00100    Wvec v2 = cross(v1, at).normalized();// normalized cross product of v1 and at
00101 
00102    normal = (x * v1 + y * v2 + sqrt(1 - x*x - y*y) * at).normalized();
00103 
00104    return true;
00105 }
00106 
00107 
00108 /* -------------------------------------------------------------------------
00109  * DESCR   :    finds the vectors that go "up" and "to the right" in the 
00110  *              film plane, when given the up and normal vector.
00111  *
00112  * RETURNS :    Success boolean. The computed vectors are returned in @f_up@
00113  *              and @f_right@, respectively.
00114  * ------------------------------------------------------------------------- */
00115 bool
00116 CAMdata::film_vectors(
00117    CWvec& up,           // up vector
00118    CWvec& normal,       // normal vector
00119    Wvec&  f_up,         // up vector in film plane
00120    Wvec&  f_right       // right vector in film plane
00121    ) const
00122 {
00123    double dot = -(up * normal);
00124 
00125    // degenerate case is when normal is nearly parallel to up:
00126    if (fabs(dot) > 1.0-epsAbsSqrdMath()) {
00127       cerr << "CAMdata::film_vectors: bad dot product" << endl;
00128       cerr << "up:       " << up        << endl;
00129       cerr << "normal:   " << normal    << endl;
00130       cerr << "fabs_dot: " << fabs(dot) << endl;
00131 
00132       // why fail when we can persevere? use arbitrary up:
00133       f_up = normal.perpend();
00134       ((CAMdata*)this)->_up = _from + f_up;
00135    } else {
00136       f_up = up.orthogonalized(normal).normalized();
00137    }
00138    f_right = cross(normal, f_up).normalized();
00139 
00140    return  true;
00141 }
00142 
00143 
00144 /* -------------------------------------------------------------------------
00145  * DESCR   :    sets up some of the vectors needed by both public routines.
00146  *              It prints an error message and returns FALSE if anything 
00147  *              goes wrong.
00148  *
00149  * RETURNS :    Success boolean. The resulting vectors are returned in
00150  *              the corresponding arguments.
00151  * ------------------------------------------------------------------------- */
00152 bool
00153 CAMdata::setup_vectors(
00154    Wvec        &at,            /* Vector from "from" to "at"           */
00155    Wvec        &up,            /* Vector from "from" to "up"           */
00156    Wpt         &center,        /* Center point of film rectangle       */
00157    Wvec        &normal,        /* film plane normal                    */
00158    Wvec        &f_up,          /* "up" vector projected on film plane  */
00159    Wvec        &f_right        /* Vector to right in film plane        */
00160    ) const
00161 {
00162    up = (_up - _from).normalized(); /* Find "up" and "at" direction vectors */
00163    at = (_at - _from).normalized();
00164    
00165    center = _from + _focal * at;   /* Find the center of the film area */
00166 
00167    // says if someone has explicitly set the film plane normal
00168    // bypass the film_normal function 
00169    if (_film_normal_flag) {
00170       normal = _film_normal;
00171       film_vectors(up, _film_normal, f_up, f_right);
00172    }
00173    else {
00174       film_normal(at, up, normal);
00175       film_vectors(up, normal, f_up, f_right);
00176    }
00177 
00178    return  true;
00179 }
00180 
00181 /* -------------------------------------------------------------------------
00182  * This returns the matrix which transforms world to eye coordinates, 
00183  * (see gl redbook p. 96) transformed by the given screen and eye specs
00184  * if needed for stereo viewing.
00185  *
00186  * The matrix returned should be loaded into the MODELVIEW stack whenever 
00187  * drawing is about to start. This is already done by gl_view.C. 
00188  *
00189  * This matrix is cached for each eye.
00190  * -------------------------------------------------------------------------
00191  */
00192 CWtransf&
00193 CAMdata::xform(SCREENptr screen, eye e) const
00194 {
00195    if (!_pos_mat_dirty[e])
00196       return _pos_matrix[e];
00197 
00198    Wvec        upv;           /* Vector from "from" to "up"           */
00199    Wvec        atv;           /* Vector from "from" to "at"           */
00200    Wvec        normalv;       /* normal vector of film  plane         */
00201    Wvec        proj_upv;      /* "up" vector projected on film        */
00202    Wvec        rightv;        /* Vector to right in film plane        */
00203 
00204    Wpt         center;         /* Center of film area                  */
00205    Wtransf     rot;
00206 
00207    CAMdata *me     =(CAMdata *)this;
00208 
00209    // XXX - none of this is documented very well.
00210    //       what does the following code block do?
00211    //       we're commenting it out because changing
00212    //       the camera every frame is causing problems
00213    //       with all the camera observers who are getting
00214    //       fake notifications about camera changes.
00215    //       also commenting out the related code block
00216    //       below re: screen->pop_eye_offset()
00217    //
00218    // setup the camera based on the screen being used
00219 //    if (screen) {
00220 //       // saves current camera parameters & sets new eye offset
00221 //       screen->push_eye_offset(_cam, e);
00222 //    }
00223 
00224    // Find at, up, proj_up, and normal vectors in world space
00225    setup_vectors(atv, upv, center, normalv, proj_upv, rightv);
00226 
00227    // Translate center to origin
00228    // Rotate so that normal lies on negative z-axis, and proj_up is on y-axis
00229    rot(2, 0) = -normalv[0];
00230    rot(2, 1) = -normalv[1];
00231    rot(2, 2) = -normalv[2];
00232 
00233    rot(0, 0) = rightv[0];
00234    rot(0, 1) = rightv[1];
00235    rot(0, 2) = rightv[2];
00236 
00237    rot(1, 0) = proj_upv[0];
00238    rot(1, 1) = proj_upv[1];
00239    rot(1, 2) = proj_upv[2];
00240 
00241    /* Transform at vector by rotation matrix */
00242    atv = rot * atv;
00243 
00244    /* Shear so that atv lies on negative z-axis */
00245    me->_pos_matrix[e] = 
00246        Wtransf::shear(Wvec(0,0,-1), Wvec(atv[0]/atv[2], atv[1]/atv[2], 0.0)) *
00247        rot *
00248        Wtransf::translation(Wpt(0,0,0)-center);
00249 
00250    // XXX - commented out; see note above
00251    //
00252    // undo any modifications to the camera parameters
00253 //    if (screen) {
00254 //       screen->pop_eye_offset(&*_cam);
00255 //    }
00256 
00257    me->_pos_mat_dirty[e] = false;
00258 
00259    return _pos_matrix[e];
00260 }
00261 
00262 
00263 /*
00264  * -------------------------------------------------------------------------
00265  * DESCR   :    returns a matrix which transforms eye coordinates to the 
00266  *              window coordinates. (see gl redbook p. 96)
00267  *              The matrix includes the perspective transformation 
00268  *              if the camera has the perspective flag on;
00269  *              otherwise it excludes the perspective transformation and 
00270  *              returns a matrix suitable for orthogonal viewing. All 
00271  *              points that lie within the view volumedefined by the camera 
00272  *              will have x-coordinates between @min[0]@ and @min[0] + width@, 
00273  *              and will have y-coordinates between @min[1]@ and 
00274  *              @min[1] + height@ .
00275  *
00276  *              For perspective projections, the z-coordinates of points will
00277  *              be zero for points on the film plane, and will be negative for
00278  *              points within the view volume.  After homogenization, points
00279  *              within the view volume will be coerced to points whose
00280  *              z-coordinate is between 0.0 and -1.0. The user should 
00281  *              clip (before homogenization) all points whose z-coordinates are
00282  *              positive, which will remove points on the camera side of the
00283  *              film plane. 
00284  *              ****  Above is all lies!!  See "GL" comment in code below!!!
00285  *
00286  *              For orthographic projections, the z-coordinates of points will
00287  *              be zero for points on the film plane, and will be +-K for
00288  *              points whose distance from the film plane is K.  To use a
00289  *              z-buffer of finite resolution, the user must decide on a range
00290  *              of z values to map to the z-buffer range.
00291  *
00292  *              The projection matrix is cached once computed.
00293  * ------------------------------------------------------------------------- 
00294  */
00295 
00296 CWtransf&
00297 CAMdata::projection_xform(
00298    SCREENptr   &screen,
00299    CNDCpt      &min,
00300    double       width,
00301    double       height,
00302    eye          e
00303    )  const
00304 {
00305    if (!_proj_mat_dirty)
00306       return _proj_matrix;
00307 
00308    // setup the camera based on the screen being used
00309 
00310    // saves current camera parameters & sets new eye offset
00311    if (screen)
00312       screen->push_eye_offset(_cam, e);
00313 
00314    CAMdata *me =(CAMdata *)this;
00315 
00316    // Scale so that corners of film rectangle range from -1 to 1 in x and y
00317    me->_proj_matrix = Wtransf::scaling(Wvec(2./_width, 2./_height, 1.0));
00318 
00319    // Do perspective transformation taking canonical pyramid into 4-space
00320    if (_perspective) {
00321       // _film_normal_flag is true when doing off-axis projection
00322       double dp = (_film_normal_flag ?
00323                    fabs(_film_normal.normalized() * at_v()) :
00324                    1.0
00325                    );
00326 
00327       Wtransf persp;
00328       persp(0, 0) = _focal * dp;
00329       persp(1, 1) = _focal * dp;
00330       persp(3, 3) = _focal * dp;
00331       persp(3, 2) = -1;
00332       persp.set_perspective(true);
00333 
00334       /*    f  0  0  0
00335        *    0  f  0  0
00336        *    0  0  1  0
00337        *    0  0 -1  f
00338        * which sends [1 0 0 1] to [f 0 0 f], [0 1 0 1] to [0 f 0 f],
00339        * [0 0 0 1] to [0 0 0 f], and [0 0 f 1] to [0 0 f 0];
00340        * These last two have the effect (after homogenization) of leaving the
00341        * center of the film plane at the origin, and sending the eye (at
00342        * [0 0 f 1] out to infinity. Points with negative z coordinates
00343        * get sent into negative z-space. A point at one focal distance out
00344        * from the film plane gets sent to z = -1/2. A point way, way out in
00345        * negative z-space gets sent to z = -1.
00346        */
00347       me->_proj_matrix = persp * _proj_matrix;
00348    }
00349 
00350    /* translate so that the lower left hand corner of the film plane is at 0 */
00351    /* scale so that film plane goes from 0 to width in x, 0 to height in y */
00352    /* translate so that lower left hand corner of film plane is at 'min' */
00353 
00354 #ifdef posse
00355    double  scaling = -1.0 / (_perspective ? 1000.0 : 1000.0); // this change okay??
00356 #else
00357    double  scaling = -1.0 / (_perspective ? 1.0 : 1000.0);
00358 #endif
00359    me->_proj_matrix = 
00360             Wtransf::translation(Wvec(1, 1, 0.0)) *
00361             Wtransf::scaling    (Wvec(width * .5, height * .5, scaling)) *
00362             Wtransf::translation(Wvec(min[0], min[1], 0.0)) *
00363             _proj_matrix;
00364 
00365    if (_perspective) {
00366 
00367       // ARGHH!!! hack ... 
00368       // 
00369       // we've changed our minds.  Instead we want the center of the film plane,
00370       // [0 0 0 1], to map to [0 0 f f].   This is because GL clips points 
00371       // between 1 and -1 in Z instead of 0 and -1 in Z as previously expected
00372 
00373       me->_proj_matrix = Wtransf::translation(Wvec(0,0,-1)) * 
00374                Wtransf::scaling    (Wvec(1,1,2)) * _proj_matrix;
00375    }
00376 
00377    // undo any modifications to the camera parameters
00378    if (screen)
00379       screen->pop_eye_offset(&*_cam);
00380 
00381    me->_proj_mat_dirty = false;
00382 
00383    return _proj_matrix;
00384 }
00385 
00386 
00387 bool
00388 CAMdata::operator == (const CAMdata &cam) const
00389 {
00390    return _from         == cam._from            && 
00391           _at           == cam._at              &&
00392           _up           == cam._up              &&
00393           _center       == cam._center          &&
00394           _focal        == cam._focal           &&
00395           _width        == cam._width           &&
00396           _height       == cam._height          &&
00397           _perspective  == cam._perspective     &&
00398           _tilt_up      == cam._tilt_up         &&
00399           _tilt_left    == cam._tilt_left       &&
00400           _iod          == cam._iod;
00401 }
00402 
00403 CAMdata &
00404 CAMdata::operator= (const CAMdata &cam)
00405 {
00406    // Copy values from another CAMdata, then notify
00407    // observers of the change.
00408    //
00409    // BUT, if the camera is identical to this, do nothing.
00410    // (I.e., do not notify observers about a supposed "change").
00411 
00412    if (!(&cam == this || cam == *this)) {
00413       _from        = cam._from;
00414       _at          = cam._at;
00415       _up          = cam._up;
00416       _center      = cam._center;
00417       _focal       = cam._focal;
00418       _width       = cam._width;
00419       _height      = cam._height;
00420       _perspective = cam._perspective;
00421       _tilt_up     = cam._tilt_up;
00422       _tilt_left   = cam._tilt_left;
00423       _iod         = cam._iod;
00424       changed();
00425    }
00426    return *this;
00427 }
00428 
00429 void
00430 CAMdata::rotate(
00431    CWline &axis,
00432    double   ang
00433    )
00434 {
00435    Wtransf combined(Wtransf::rotation(axis, ang));
00436    _from = combined * from();
00437    _at   = combined * at  ();
00438    _up   = combined * up  ();
00439    changed();
00440 }
00441 
00442 void
00443 CAMdata::translate(
00444    CWvec &t
00445    )
00446 {
00447    if (t.length() > 0) {
00448       _from   += t;
00449       _at     += t;
00450       _center += t;
00451       _up     += t;
00452       changed();
00453    }
00454 }
00455 
00456 void
00457 CAMdata::swivel(
00458    double rads
00459    )
00460 {
00461    if (rads != 0) {
00462       Wtransf rot(Wtransf::rotation(Wline(from(), up_v()), rads));
00463       _from = rot * _from;
00464       _at   = rot * _at;
00465       _up   = rot * _up;
00466       changed();
00467    }
00468 }
00469 
00470 STDdstream &
00471 operator<<(STDdstream &ds, CCAMdataptr &cam) 
00472 {
00473    return ds << cam->_from
00474             << cam->_at
00475             << cam->_up
00476             << cam->_center
00477             << cam->_focal
00478             << (int)cam->_perspective
00479             << cam->_iod;
00480 }
00481 
00482 STDdstream &
00483 operator>>(STDdstream &ds, CAMdataptr &cam) 
00484 {
00485    // Fill our camera with incoming data
00486    int persp;
00487    ds >> cam->_from
00488       >> cam->_at
00489       >> cam->_up
00490       >> cam->_center
00491       >> cam->_focal
00492       >> persp
00493       >> cam->_iod;
00494    // _perspective is a bool
00495    cam->_perspective = persp ? true : false;
00496    cam->_loaded_from_file = true;
00497    cam->changed();
00498    return ds;
00499 }
00500 
00501 void
00502 CAM::set_aspect(
00503    double a
00504    )
00505 {
00506    if ( a > 1 ) {
00507       _width  = 2.0/a;
00508       _height = 2.0;
00509       _min    = NDCpt(-a, -1);
00510    } else {
00511       _width  = 2.0;
00512       _height = 2.0*a;
00513       _min    = NDCpt(-1, -1/a);
00514    }
00515    _data->changed();
00516 }
00517 
00518 CAM &
00519 CAM::operator = (const CAM &cam)
00520 {
00521    _min   = cam._min;
00522    _width = cam._width;
00523    _height= cam._height;
00524 
00525    // NDC coords stuff
00526    _min   = cam._min;
00527    _width = cam._width;
00528    _height= cam._height;
00529    _zoom  = cam._zoom;
00530    _ndc_proj_dirty = true;
00531 
00532    *_data = *cam._data;
00533    return *this;
00534 }
00535 
00536 int
00537 CAM::operator == (const CAM &cam)
00538 {
00539    return _min   == cam._min  &&
00540           _width == cam._width && _height == cam._height &&
00541           *_data == *cam._data;
00542 }
00543 
00544 /* 
00545  *   This returns the vector from a point on the film plane, p,
00546  * to the From point of the camera.
00547  *
00548  * the point, p, should be given in NPC (normalized projection 
00549  * coordiantes [-1,-1] to [1,1]) 
00550  *
00551  */
00552 Wvec
00553 CAM::film_dir(
00554    CXYpt    &p
00555    ) const
00556 {
00557    CNDCpt       ndc_p(p);
00558    CCAMdataptr &dat = data();
00559    if (!dat->persp())
00560       return dat->at_v();
00561 
00562    Wpt    fpt(dat->from() + dat->at_v() * dat->focal());
00563    Wvec   fr (dat->right_v() * ndc_p[0]/2 * dat->width() );
00564    Wvec   fu (dat->pup_v()   * ndc_p[1]/2 * dat->height());
00565    return ((fpt + fr + fu) - dat->from()).normalized();
00566 }
00567 
00568 /*
00569  *  This converts a point on the film plane (given in XY) to a
00570  * point in world space.  This is done by projecting the XY 
00571  * point onto a plane in world space that is parallel to the 
00572  * film plane and that contains the world space point, wpt.
00573  *
00574  */
00575 Wpt 
00576 CAM::xy_to_w(
00577    CXYpt     &pt,
00578    CWpt      &wpt
00579   ) const
00580 {
00581    CCAMdataptr &dat = data();
00582    CWvec        wvec   = wpt - dat->from();
00583    double       length = wvec * dat->at_v();
00584 
00585    if (!dat->persp())               // Orthographic camera
00586       return dat->from() + length * dat->at_v() + 
00587              dat->right_v() * pt[0] / width()  * dat->width() +
00588              dat->pup_v()   * pt[1] / height() * dat->height();
00589    else {                            // Perspective camera
00590       Wvec rdir(pt);
00591       return dat->from() + rdir * (length/(rdir* dat->at_v()));
00592    }
00593 }
00594 
00595 /*
00596  *  Same as above, except the point is projected onto a plane 
00597  * parallel to the film plane that is "focal_length"+epsilon 
00598  * units away from the camera's From point.
00599  *
00600  */
00601 Wpt
00602 CAM::xy_to_w(
00603    CXYpt     &pt
00604   ) const
00605 {
00606    CCAMdataptr dat = data();
00607    if (!dat->persp())
00608         return xy_to_w(pt, dat->from());
00609    else return xy_to_w(pt, dat->from() + dat->at_v() * dat->focal() * 1.01);
00610 }
00611 
00612 Wpt
00613 CAM::xy_to_w(
00614    CXYpt  &pt,
00615    double  d
00616    ) const
00617 {
00618    CCAMdataptr dat = data();
00619    if (!d)
00620       d = dat->distance();
00621    return xy_to_w(pt, dat->from() + dat->at_v() * d);
00622 }
00623 
00624 /*
00625  * Converts a point in world space to a point on the camera's film
00626  * plane in XY.
00627  */
00628 XYpt   
00629 CAM::w_to_xy(
00630    CWpt  &wpt
00631   ) const
00632 {
00633    CCAMdataptr &dat = data();
00634    Wvec         wvec(wpt - dat->from());
00635 
00636    if (!dat->persp())
00637       return XYpt(wvec * dat->right_v() / dat->width () * width(),
00638                   wvec * dat->pup_v()   / dat->height() * height());
00639       
00640    else {
00641       NDCpt  aspect(XYpt(1,1)); // convert 1,1 point to NDCpt to 
00642                                 // effectively get aspect ratio
00643 
00644       Wvec svec((wvec.normalized() * 
00645                  (wvec.length() / (wvec * dat->at_v())) - dat->at_v()) * 
00646                  dat->focal());
00647 
00648       return XYpt(svec * dat->right_v()/dat-> width() * 2/aspect[0],
00649                   svec * dat->pup_v  ()/dat->height() * 2/aspect[1]);
00650    }
00651 }
00652 
00653 CWtransf&
00654 CAM::ndc_projection() const
00655 {
00656    if (_ndc_proj_dirty) {
00657       int w, h;
00658       VIEW_SIZE(w,h);
00659       Wvec scale = (w>h) ? Wvec(w/(double)h, 1, 1) : Wvec(1, h/(double) w, 1);
00660       ((CAM*)this)->_ndc_proj = Wtransf::scaling(scale)*projection_xform()*xform();
00661       ((CAM*)this)->_ndc_proj_inv = _ndc_proj.inverse();
00662       ((CAM*)this)->_ndc_proj_dirty = 0;
00663    }
00664    return _ndc_proj;
00665 }
00666 
00667 CWtransf&
00668 CAM::ndc_projection_inv() const
00669 {
00670    // Compute the cached value
00671    ndc_projection();
00672    
00673    return _ndc_proj_inv;
00674 }
00675 
00676 
00677 void
00678 SCREEN::push_eye_offset(
00679    CCAMptr &cam,
00680    CAMdata::eye e
00681    )
00682 {
00683    // Minimize REFptr op's because this function is called a lot
00684    CAMdata *data = (CAMdata *) cam->data_ptr();
00685 
00686    *_saved_cam->data() = *data;
00687 
00688    double clip_ratio = data->focal() / (data->from() - data->at()).length();
00689 
00690    // save the "up vector" to redefine
00691    // the 'up' point after assigning a new 'from' position.
00692    Wvec up_vec  = data->up_v();
00693 
00694    double dist_to_screen = (data->from() - data->at()).length();
00695    data->set_focal(dist_to_screen * clip_ratio);
00696 }
00697 
00698 void 
00699 SCREEN::pop_eye_offset(
00700    const CAM *c
00701    )
00702 {
00703    // This is called a lot, so do not do any REFptr op's
00704    *((CAMdata *)c->data_ptr()) = *_saved_cam->data_ptr();
00705 }
00706 
00707 /* end of file cam.C */

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