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
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 DATA_ITEM*
00062 WORLD::_default_decoder(
00063 STDdstream& ,
00064 Cstr_ptr& name,
00065 DATA_ITEM* hash
00066 )
00067 {
00068
00069
00070 GELptr gel = GEL::upcast(hash);
00071 if (gel && gel->name() == name)
00072 return hash;
00073
00074
00075
00076 gel = EXIST.lookup(name);
00077 if (gel)
00078 return gel;
00079
00080
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
00092
00093
00094 WORLD::WORLD() : _hash(10)
00095 {
00096
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
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
00133 int retval = 0;
00134 if ((retval = pthread_setrunon_np(_view_num+1)) != 0) {
00135
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
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
00182 if (debug_threads) fprintf(stderr, "master syncing twice\n");
00183 _tsync->wait();
00184
00185 if (debug_threads) fprintf(stderr, "master syncing thrice\n");
00186 _tsync->wait();
00187
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
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
00208
00209
00210
00211
00212
00213
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
00234 if (Config::get_var_bool("JOT_REPORT_SIL_STATS",false,true)) {
00235 extern RunningAvg<double> rand_secs;
00236 extern RunningAvg<double> brute_secs;
00237 extern RunningAvg<double> zx_secs;
00238 extern RunningAvg<double> rand_sils;
00239 extern RunningAvg<double> brute_sils;
00240 extern RunningAvg<double> zx_sils;
00241 extern RunningAvg<double> all_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
00325
00326
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
00368
00369
00370
00371 class XF_DRAW : public GEOM {
00372 public:
00373
00374 XF_DRAW(CWtransf& xf, double axis_length) :
00375 _xf(xf), _axis_length(axis_length) {}
00376
00377
00378 virtual int draw(CVIEWptr &v) {
00379 if (!_xf.origin().in_frustum())
00380 return 0;
00381
00382
00383
00384 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT);
00385 glDisable(GL_LIGHTING);
00386 glDisable(GL_DEPTH_TEST);
00387 glLineWidth(2);
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());
00398 glVertex3d(0,0,0);
00399 glVertex3d(s,0,0);
00400
00401 glColor3dv(Color::yellow.data());
00402 glVertex3d(0,0,0);
00403 glVertex3d(0,s,0);
00404
00405 glColor3dv(Color::red.data());
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;
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
00486
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
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
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
00537
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++;
00546 for (i = len; i < len + line_length; i++) {
00547
00548 if (((str[i] == ' ')&&(get_next(str, i, ' ') >= len+line_length))||
00549 (str[i] == '\0'))
00550 break;
00551
00552 line[i - len] = str[i];
00553 }
00554 line[i - len] = '\0';
00555 formatted += line;
00556
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
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
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 {
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
00614
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
00635
00636
00637 void
00638 WORLD::_undo()
00639 {
00640
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
00662
00663
00664 void
00665 WORLD::_redo()
00666 {
00667
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
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
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 }