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

world.C

Go to the documentation of this file.
00001 #include "std/support.H"
00002 #include "glew/glew.H"
00003 
00004 #include "dev/devpoll.H"
00005 #include "disp/colors.H"
00006 #include "geom/body.H"
00007 #include "geom/text2d.H"
00008 #include "geom/line3d.H"
00009 #include "geom/world.H"
00010 #include "geom/winsys.H"
00011 
00012 #include "std/config.H"
00013 #include "std/thread.H"
00014 #include "std/time.H"
00015 #include "std/run_avg.H"
00016 
00017 using namespace mlib;
00018 
00019 WORLD*  WORLD::_w       = 0;
00020 bool    WORLD::_is_over = false;
00021 
00022 bool debug_threads = Config::get_var_bool("JOT_DEBUG_THREADS") != 0;
00023 
00024 LOADER *LOADER::_all;
00025 
00026 LOADER::LOADER()
00027 {
00028    _next = _all;
00029    _all  = this;
00030 }
00031 
00032 bool
00033 LOADER::load(
00034    Cstr_ptr &path
00035    )
00036 {
00037    bool loaded = 0;
00038    for (LOADER *l = _all; l != 0 && !loaded; l = l->_next) {
00039       loaded = l->try_load(path);
00040    }
00041    return loaded;
00042 }
00043 
00044 //
00045 //  When a stream encounters a data object identified by a name
00046 // that doesn't match the class name of the object registered to
00047 // decode it, then this function is called to resolve the conflict.  
00048 //
00049 // It's possible the registered object actually *is* the object
00050 // to be decoded in which case this verifies the match and returns
00051 // the object.   (In this case, the object to be decoded will only
00052 // have its name on the stream and no additional data).
00053 //
00054 // Alternatively, it's possible that the object to be decoded does 
00055 // exist in the EXIST database, in which case nothing needs to 
00056 // explicitly decode the object -- just return the object from EXIST.
00057 // (Again, the only data on the stream will be the object's name).
00058 //
00059 // If these two fail, then the object can't be decoded.
00060 //
00061 DATA_ITEM*
00062 WORLD::_default_decoder(
00063    STDdstream& , 
00064    Cstr_ptr&  name, 
00065    DATA_ITEM* hash
00066    )
00067 {
00068    // Use the object that's registered to decode 'name' only if that 
00069    // object's name is 'name' also.
00070    GELptr gel = GEL::upcast(hash);
00071    if (gel && gel->name() == name)
00072       return hash;
00073 
00074    // If nothing was registered to decode 'name', then check to see
00075    // if an object called 'name' exists and return it if it does.
00076    gel = EXIST.lookup(name);
00077    if (gel)
00078       return gel;
00079 
00080    // Report failure:
00081    cerr << "WORLD::_default_decoder: can't find object named "
00082         << name << endl;
00083    if (hash)
00084       cerr << hash->class_name() << " vs. " << name << endl;
00085 
00086    return 0;
00087 }
00088 
00089 //
00090 //
00091 // WORLD
00092 //
00093 //
00094 WORLD::WORLD() : _hash(10)
00095 {
00096    // Set up the clean up routine
00097    atexit(WORLD::Clean_On_Exit);
00098 
00099    DATA_ITEM::set_default_decoder(_default_decoder);
00100 
00101 #ifdef USE_PTHREAD
00102    _tsync = 0;
00103    _threads = 0;
00104    _doMultithread = Config::get_var_bool("JOT_MULTITHREAD",false,true);
00105 #endif
00106 }
00107 
00108 // call 'exec_poll()' on all pollable device objects
00109 void
00110 WORLD::poll(void)
00111 {
00112    ARRAY<DEVpoll *> &p = DEVpoll::pollable();
00113    for(int i=0;i<p.num();i++)
00114       p[i]->exec_poll();
00115 }
00116 
00117 #ifdef USE_PTHREAD
00118 class RenderThread : public Thread {
00119  public:
00120    void set_view_num(int view_num) { _view_num = view_num; }
00121  protected:
00122    int _view_num;
00123    void threadProc();
00124 };
00125 
00126 void
00127 RenderThread::threadProc()
00128 {
00129    ThreadSync *sync = WORLD::get_world()->get_threadsync();
00130    bool need_set = true;
00131 #ifdef sgi
00132    // FIXME - should make sure that there is a cpu per VIEW
00133    int retval = 0;
00134    if ((retval = pthread_setrunon_np(_view_num+1)) != 0) {
00135       // On the SGI errno is cleared, so we have to use strerror
00136       err_msg("RenderThread::threadProc - pthread_setrunon_np: %s", 
00137               strerror(retval));
00138    }
00139 #endif
00140 
00141    for (;;) {
00142       if (debug_threads) fprintf(stderr, "slave-%d syncing once\n", _view_num);
00143       sync->wait();
00144       if (need_set) {
00145          ThreadObs::notify_render_thread_obs(VIEWS[_view_num]);
00146          need_set = false;
00147       }
00148       if (debug_threads) fprintf(stderr, "slave-%d painting\n", _view_num);
00149       VIEWS[_view_num]->paint();
00150       // this second sync shouldn't be needed on a multipipe IR
00151       if (debug_threads) fprintf(stderr, "slave-%d syncing twice\n", _view_num);
00152       sync->wait();
00153       if (debug_threads) fprintf(stderr, "slave-%d swapping\n", _view_num);
00154       VIEWS[_view_num]->impl()->swap_buffers();
00155       if (debug_threads) fprintf(stderr,"slave-%d syncing thrice\n", _view_num);
00156       sync->wait();
00157    }
00158 }
00159 #endif
00160 
00161 void
00162 WORLD::draw(void)
00163 {
00164 #ifdef USE_PTHREAD
00165    if (_doMultithread) {
00166       if (!_threads) {
00167          _tsync = new ThreadSync(VIEWS.num()+1);
00168          _threads = new RenderThread[VIEWS.num()];
00169          pthread_setconcurrency(VIEWS.num());
00170          for (int i=0; i < VIEWS.num(); i++) {
00171             _threads[i].set_view_num(i);
00172             _threads[i].start();
00173          }
00174       }
00175 
00176       if (debug_threads) fprintf(stderr, "master unlocking\n");
00177       VIEWS[0]->win()->unlock();
00178       VIEWS[0]->win()->unlock();
00179       if (debug_threads) fprintf(stderr, "master syncing once\n");
00180       _tsync->wait();
00181       // render threads paint
00182       if (debug_threads) fprintf(stderr, "master syncing twice\n");
00183       _tsync->wait();
00184       // render threads swap
00185       if (debug_threads) fprintf(stderr, "master syncing thrice\n");
00186       _tsync->wait();
00187       // need to wait until swaps finish so we can grab the display again
00188       if (debug_threads) fprintf(stderr, "master locking\n");
00189       VIEWS[0]->win()->lock();
00190       VIEWS[0]->win()->lock();
00191    } else
00192 #endif
00193       {
00194          for (int i =0; i < VIEWS.num(); i++) {
00195             VIEWS[i]->paint();
00196          }
00197       }
00198 }
00199 
00200 // Deactivate all our connects, turn off stereo, and quit
00201 void
00202 WORLD::clean_on_exit() const
00203 {
00204    static bool debug = Config::get_var_bool("DEBUG_CLEAN_ON_EXIT",false);
00205    err_adv(debug, "WORLD::clean_on_exit");
00206 
00207    // Kill off all the ref counted GELs in the EXIST list to
00208    // ensure they properly die off while all the required static
00209    // observed HASHes are still around. See draw/floor.H for an
00210    // example where one must explicitly add another clean_on_exit
00211    // routine via onexit() to ensure extra static ref counted
00212    // GEL pointers are killed off to ensure object destruction
00213    // prior to total termination.
00214 
00215    while (!EXIST.empty()) {
00216       GELptr g = EXIST.pop();
00217       if (debug)
00218          cerr << " Trashing '" << g->name() << "' "
00219               << "(" << g->class_name() << ")" << endl;
00220       destroy(g, false);
00221    }
00222 
00223    int i;
00224    for (i = 0; i<_fds.num(); i++)
00225       _fds[i]->deactivate();
00226    for (i = 0; i < VIEWS.num(); i++)
00227       VIEWS[i]->stereo(VIEWimpl::NONE);
00228 }
00229 
00230 void
00231 WORLD::quit() const
00232 {
00233    // Report on silhouette statistics if asked
00234    if (Config::get_var_bool("JOT_REPORT_SIL_STATS",false,true)) {
00235       extern RunningAvg<double> rand_secs;  // secs per randomized extraction
00236       extern RunningAvg<double> brute_secs; // secs per brute-force extraction
00237       extern RunningAvg<double> zx_secs;    // secs per zx extraction (rand)
00238       extern RunningAvg<double> rand_sils;  // avg num sils found randomized
00239       extern RunningAvg<double> brute_sils; // avg num sils found brute-force
00240       extern RunningAvg<double> zx_sils;    // avg num sils found zx (rand) 
00241       extern RunningAvg<double> all_edges;  // avg number of total mesh edges
00242 
00243       if (!(isZero( all_edges.val()) &&
00244             isZero(brute_secs.val()) &&
00245             isZero( rand_secs.val()) &&
00246             isZero(   zx_secs.val()))) {
00247 
00248          err_msg("\n**** Silhouette statistics ****\n");
00249          err_msg("Total number of edges:  %d", (int)all_edges.val());
00250 
00251          if (!isZero(brute_secs.val())) {
00252             err_msg("Brute force:");
00253             err_msg("  Avg sils extracted:     %d", (int)brute_sils.val());
00254             err_msg("  Seconds per extraction: %f", brute_secs.val());
00255             err_msg("  Extractions per second: %f", 1.0/brute_secs.val());
00256          }
00257 
00258          if (!isZero(rand_secs.val() > 0)) {
00259             err_msg("Randomized:");
00260             err_msg("  Avg sils extracted:     %d", (int)rand_sils.val());
00261             err_msg("  Seconds per extraction: %f", rand_secs.val());
00262             err_msg("  Extractions per second: %f", 1.0/rand_secs.val());
00263             err_msg("Speedup: %2.1f", brute_secs.val()/rand_secs.val());
00264          }
00265 
00266          if (!isZero(brute_secs.val())) {
00267             err_msg("ZX:");
00268             err_msg("  Avg segments extracted: %d", (int)zx_sils.val());
00269             err_msg("  Seconds per extraction: %f",      zx_secs.val());
00270             err_msg("  Extractions per second: %f",  1.0/zx_secs.val());
00271          }
00272 
00273          err_msg("\n*******************************\n");
00274       }
00275    }
00276 
00277    exit(0);
00278 }
00279 
00280 GEOMptr
00281 map_obj(
00282    CGEOMptr  &name,
00283    CGEOMlist &mapfrom,
00284    CGEOMlist &mapto
00285    )
00286 {
00287    for (int n = 0; n < mapfrom.num(); n++)
00288       if (name == mapfrom[n])
00289          return mapto[n];
00290 
00291    return GEOMptr();
00292 }
00293 
00294 
00295 GEOMptr
00296 WORLD::lookup(
00297    Cstr_ptr &s 
00298    )
00299 {   
00300    GELptr g = EXIST.lookup(s);
00301    if (GEOM::isa(g))
00302       return GEOMptr((GEOM *) &* g);
00303    return GEOMptr();
00304 }
00305 
00306 GELptr
00307 WORLD::show(CWpt& p, double width, CCOLOR& c, double alpha, bool depth_test)
00308 {
00309    LINE3Dptr line = new LINE3D;
00310    line->add(p);
00311    line->set_width(width);
00312    line->set_color(c);
00313    line->set_alpha(alpha);
00314    line->set_no_depth(!depth_test);
00315    create(line,false);
00316    return line;
00317 }
00318 
00319 GELptr 
00320 WORLD::show_pts(
00321    CWpt_list& pts, double width, CCOLOR& col, double alpha, bool depth_test
00322    )
00323 {
00324    // XXX - Should have dedicated GEL class for this.
00325    //       This is done in a hurry to get something that
00326    //       works but is not efficient.
00327 
00328    for (int i=0; i<pts.num(); i++)
00329       show(pts[i], width, col, alpha, depth_test);
00330 
00331    return 0;
00332 }
00333 
00334 GELptr
00335 WORLD::show(
00336    CWpt& a, CWpt& b, double width, CCOLOR& c, double alpha, bool depth_test
00337    )
00338 {
00339    LINE3Dptr line = new LINE3D;
00340    line->add(a);
00341    line->add(b);
00342    line->set_width(width);
00343    line->set_color(c);
00344    line->set_alpha(alpha);
00345    line->set_no_depth(!depth_test);
00346    create(line,false);
00347    return line;
00348 }
00349 
00350 GELptr 
00351 WORLD::show_polyline(
00352    CWpt_list& pts, double width, CCOLOR& col, double alpha, bool depth_test
00353    )
00354 {
00355    LINE3Dptr line = new LINE3D;
00356    line->add(pts);
00357    line->set_width(width);
00358    line->set_color(col);
00359    line->set_alpha(alpha);
00360    line->set_no_depth(!depth_test);
00361    create(line,false);
00362 
00363    return 0;
00364 }
00365 
00366 /*******************************************************
00367  * XF_DRAW:
00368  * 
00369  *   Draws the coordinate frame described by a Wtransf.
00370  ********************************************************/
00371 class XF_DRAW : public GEOM {
00372  public:
00373    //******** MANAGERS ********
00374    XF_DRAW(CWtransf& xf, double axis_length) :
00375       _xf(xf), _axis_length(axis_length) {}
00376    
00377    //******** GEOM METHODS ********
00378    virtual int draw(CVIEWptr &v) {
00379       if (!_xf.origin().in_frustum())
00380          return 0;
00381 
00382       // Draw x, y, and z axes in yellow, blue, and tan
00383 
00384       glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT);
00385       glDisable(GL_LIGHTING);   // GL_ENABLE_BIT
00386       glDisable(GL_DEPTH_TEST); // GL_ENABLE_BIT
00387       glLineWidth(2);           // GL_LINE_BIT
00388 
00389       glMatrixMode(GL_MODELVIEW);
00390       glPushMatrix();
00391       glMultMatrixd(_xf.transpose().matrix());
00392 
00393       double s = world_length(_xf.origin(), _axis_length);
00394 
00395       glBegin(GL_LINES);
00396 
00397       glColor3dv(Color::blue.data());  // GL_CURRENT_BIT
00398       glVertex3d(0,0,0);
00399       glVertex3d(s,0,0);
00400 
00401       glColor3dv(Color::yellow.data());// GL_CURRENT_BIT
00402       glVertex3d(0,0,0);
00403       glVertex3d(0,s,0);
00404 
00405       glColor3dv(Color::red.data());   // GL_CURRENT_BIT
00406       glVertex3d(0,0,0);
00407       glVertex3d(0,0,s);
00408 
00409       glEnd();
00410 
00411       glPopMatrix();
00412 
00413       glPopAttrib();
00414 
00415       return 1; 
00416    }
00417 
00418  protected:
00419    Wtransf _xf;
00420    double  _axis_length;     // Target screen length for axes
00421 };
00422 
00423 GELptr
00424 WORLD::show(CWtransf& xf, double axis_length)
00425 {
00426    GELptr ret = new XF_DRAW(xf, axis_length);
00427    create(ret,false);
00428    return ret;
00429 }
00430 
00431 class REF_CLASS(WMSG) : public FRAMEobs {
00432   protected:
00433    TEXT2Dptr    _text;
00434    double       _end_time;
00435    static WMSG *_msg;
00436 
00437   public:
00438    WMSG(CTEXT2Dptr &msg) : _text(msg), _end_time(0) { _msg = this;}
00439    int tick() {
00440       if (_end_time && the_time() > _end_time) {
00441          _text->set_string(NULL_STR);
00442          _msg = 0;
00443          return -1;
00444       } else return 1;
00445    }
00446    void elapsed(double sec) {_end_time = sec > 0 ? the_time() + sec : 0;}
00447    static WMSG *msg() {return _msg;}
00448 };
00449 
00450 WMSG *WMSG::_msg=0;
00451 TEXT2Dptr msgtext;
00452 
00453 void
00454 WORLD::_Message(
00455    Cstr_ptr &str,
00456    double   secs,
00457    CXYpt    &pos
00458    )
00459 {   
00460    _Multi_Message(0);
00461    if (!msgtext) {
00462       msgtext = new TEXT2D(unique_name("msg"), str, pos);
00463       GEOMptr g = msgtext;
00464       g->set_color(Color::firebrick);
00465       NETWORK.set(g, 0);
00466       create(g, false);
00467    } else {
00468       msgtext->set_string(str);
00469       msgtext->set_loc   (pos);
00470    }
00471 
00472    if (pos == XYpt(0,.9))
00473       msgtext->centered() = true;
00474    else
00475       msgtext->centered() = false;
00476 
00477    if (!WMSG::msg()) {
00478       new WMSG(msgtext);
00479       FRAMEobsptr m(WMSG::msg());
00480       _w->schedule(m);
00481    }
00482    WMSG::msg()->elapsed(secs);
00483 }
00484 
00485 /*multiple messages can be displayed on multiple lines.  They are formatted
00486   to fit the screen*/
00487 const int MAXLINES = 6;
00488 class REF_CLASS(WMMSG) : public FRAMEobs {
00489   protected:
00490    TEXT2Dptr    _text[MAXLINES];
00491    double       _end_time;
00492    int          _num_msgs;
00493    static WMMSG *_msg;
00494 
00495   public:
00496    WMMSG(TEXT2Dptr msg[]) : _end_time(0) {
00497       int i;
00498       for (i = 0; ((msg[i])&&(i < MAXLINES)); i++) {
00499          _text[i] = *(new TEXT2Dptr(msg[i])); 
00500       }
00501       _num_msgs = i;          
00502       _msg = this;
00503    } 
00504 
00505    int tick() {
00506       if (_end_time && the_time() > _end_time) {
00507          //clear away all messages begin displayed
00508          str_list list;
00509          list += "";
00510          WORLD::multi_message(list);
00511          for (int i = 0; i < _num_msgs; i++) 
00512             _text[i]->set_string(NULL_STR);
00513 
00514          _msg = 0;
00515          return -1;
00516       } else return 1;
00517    }
00518    void elapsed(double sec) {_end_time = sec > 0 ? the_time() + sec : 0;}
00519    static WMMSG *msg() {return _msg;}
00520 };
00521 
00522 WMMSG *WMMSG::_msg=0;
00523 TEXT2Dptr mmsgtext[MAXLINES];
00524 
00525 //returns the location of the next instance of chr in the string
00526 int
00527 WORLD::get_next(Cstr_ptr &str, int loc, char chr) {
00528    while (str[loc] != '\0') {
00529       loc++;
00530       if ((str[loc] == chr)||(str[loc] == '\0'))
00531          return loc;
00532    }
00533    return 1000;
00534 }
00535 
00536 /*given a string, returns an array such that each of its elements contains
00537   a maximum of line_length characters*/
00538 str_list
00539 WORLD::format_str(Cstr_ptr &str, const int line_length)
00540 {
00541    int i = 0, len = 0;
00542    char *line = new char[line_length];
00543    str_list formatted;
00544    while (str[len] != '\0') {
00545       if (str[i] == ' ') len++; //go on to next character if new line
00546       for (i = len; i < len + line_length; i++) {
00547          //conditions that end the line
00548          if (((str[i] == ' ')&&(get_next(str, i, ' ') >= len+line_length))||
00549              (str[i] == '\0'))
00550             break;            
00551          //add a good charcter to the output string
00552          line[i - len] = str[i];
00553       }
00554       line[i - len] = '\0';
00555       formatted += line;
00556       //this many characters formatted
00557       len = i;
00558    } 
00559    delete [] line;
00560    return formatted;
00561 }
00562 
00563 void
00564 WORLD::_Multi_Message(
00565    Cstr_list &str,
00566    double     secs,
00567    CXYpt     &pos
00568    )
00569 {
00570    int i, w, h;
00571    //read each string into a single array
00572    str_list formatted;
00573    TEXT2Dptr msg;
00574    VIEW::peek_size(w, h);
00575    int line_length = w / 10;
00576    for (i = 0; i < str.num(); i++) 
00577       formatted.operator+=(format_str(str[i], line_length));
00578 
00579 
00580    //delete old messages
00581    if (msgtext) 
00582       msgtext->set_string(NULL_STR);
00583    for (i = 0; i < MAXLINES; i++)
00584       if (mmsgtext[i])
00585          mmsgtext[i]->set_string(NULL_STR);
00586 
00587    XYpt pos2 = pos, jVec(0, -.08);
00588 
00589    for (i = 0; ((i < formatted.num())&&(i < MAXLINES)); i++) 
00590       if (!mmsgtext[i]) {
00591          msg = new TEXT2D(unique_name("msg"), formatted[i], pos2);
00592          GEOMptr g = msg;
00593          g->set_color(Color::firebrick);
00594          NETWORK.set(g, 0);
00595          create(g);
00596          msg->centered() = true;
00597          mmsgtext[i] = msg;
00598          pos2 += jVec;
00599       } else {    //move text if it is currently being shown 
00600          mmsgtext[i]->set_string(formatted[i]);
00601          mmsgtext[i]->set_loc   (pos2);
00602          pos2 += jVec;
00603       }
00604 
00605    if (!WMMSG::msg()) {
00606       new WMMSG(mmsgtext);
00607       FRAMEobsptr m(WMMSG::msg());
00608       _w->schedule(m);
00609    }
00610    WMMSG::msg()->elapsed(secs);
00611 }
00612 
00613 // Calls doit() on a command, adds it to the undo list,
00614 // and clears the redo list.
00615 // 
00616 void
00617 WORLD::_add_command(COMMANDptr c)
00618 {
00619    if (!c) {
00620       err_msg("WORLD::_add_command: null command");
00621       return;
00622    }
00623    if (Config::get_var_bool("DEBUG_JOT_CMD")) {
00624       cerr << "Adding command: ";
00625       c->print();
00626       cerr << endl;
00627    }
00628 
00629    _clear_redoable();
00630    c->doit();
00631    _undoable += c;
00632 }
00633 
00634 // Pops a command from the undoable list, calls
00635 // undo on it, and appends it to the redoable list.
00636 //
00637 void
00638 WORLD::_undo()
00639 {
00640    // if there are no commands to undo, notify user and return
00641    if (_undoable.empty()) {
00642       WORLD::message("Can't undo anymore");
00643       return;
00644    } else {
00645       WORLD::message("Undo");
00646    }
00647    
00648    COMMANDptr c = _undoable.pop(); 
00649    if (!c->undoit()) {
00650       
00651    }
00652    _redoable += c;
00653 
00654    if (Config::get_var_bool("DEBUG_JOT_CMD")) {
00655       cerr << "Undoing command: ";
00656       c->print();
00657       cerr << endl;
00658    }
00659 }
00660 
00661 // Pops a command from the redoable list, calls
00662 // redo on it, and appends it to the undoable list.
00663 //
00664 void
00665 WORLD::_redo()
00666 {
00667    // if there are no commands to redo, notify user and return
00668    if (_redoable.empty()) {
00669       WORLD::message("Can't redo anymore");
00670       return;
00671    } else {
00672       WORLD::message("Redo");
00673    }
00674 
00675    COMMANDptr c = _redoable.pop(); 
00676    c->doit();
00677    _undoable += c;
00678 
00679    if (Config::get_var_bool("DEBUG_JOT_CMD")) {
00680       cerr << "Redoing command: ";
00681       c->print();
00682       cerr << endl;
00683    }
00684 }
00685 
00686 // Clears the redoable list
00687 //
00688 void
00689 WORLD::_clear_redoable()
00690 {
00691    COMMANDptr c;
00692    while( !_redoable.empty() )
00693       _redoable.pop()->clear();
00694    _redoable.clear();
00695 }
00696 
00697 void       
00698 WORLD::create(CGELptr &o, bool display_undoable)  
00699 { 
00700    if (NETWORK.is_default(o))
00701       NETWORK.set(o,1);
00702   
00703    if (! EXIST.contains(o) )
00704       EXIST.add(o);
00705    EXISTobs::notify_exist_obs(o,1);
00706    display(o, display_undoable); 
00707 }
00708 
00709 void
00710 WORLD::destroy(CGELptr &o, bool undoable)  
00711 { 
00712    undisplay(o, undoable); 
00713    EXIST.rem(o);
00714    EXISTobs::notify_exist_obs(o,0);
00715 }
00716 
00717 void
00718 WORLD::destroy(CGELlist &gels, bool undoable)  
00719 {
00720    // XXX - should make a single undo command here
00721    for (int i=0; i<gels.num(); i++)
00722       destroy(gels[i], undoable);
00723 }
00724 
00725 bool
00726 WORLD::is_displayed(CGELptr& o)
00727 {
00728    return o && DRAWN.contains(o);
00729 }
00730 
00731 void
00732 WORLD::display(CGELptr &o, bool undoable)  
00733 {
00734    if (!o) 
00735       return;
00736 
00737    if (undoable) {
00738       add_command( new DISPLAY_CMD(o) );
00739    } else {
00740       DRAWN.add(o); 
00741    }
00742 }
00743 
00744 void
00745 WORLD::display_gels(CGELlist& gels, bool undoable)  
00746 {
00747    if (gels.empty()) 
00748       return;
00749 
00750    if (undoable) {
00751       add_command( new DISPLAY_CMD(gels) );
00752    } else {
00753       for (int i=0; i<gels.num(); i++)
00754          DRAWN.add(gels[i]); 
00755    }
00756 }
00757 
00758 void
00759 WORLD::undisplay(CGELptr &o, bool undoable)  
00760 { 
00761    if (!o) 
00762       return;
00763 
00764    if (undoable) {
00765       add_command( new UNDISPLAY_CMD(o) );
00766    } else {
00767       DRAWN.rem(o); 
00768    }
00769 }
00770 
00771 void
00772 WORLD::undisplay_gels(CGELlist& gels, bool undoable)  
00773 { 
00774    if (gels.empty()) 
00775       return;
00776 
00777    if (undoable) {
00778       add_command( new UNDISPLAY_CMD(gels) );
00779    } else {
00780       for (int i=0; i<gels.num(); i++)
00781          DRAWN.rem(gels[i]); 
00782    }
00783 }
00784 
00785 int
00786 WORLD::toggle_display(CGELptr &o, bool undoable)  
00787 { 
00788    if (DRAWN.contains(o)){ 
00789       undisplay(o, undoable);
00790       return 0; 
00791    } 
00792   
00793    display(o, undoable);
00794    return 1;
00795 }

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