model.cc
Go to the documentation of this file.
00001 
00133 #ifndef _GNU_SOURCE
00134 #define _GNU_SOURCE
00135 #endif
00136 
00137 #include <map>
00138 #include <sstream> // for converting values to strings
00139 #include <ltdl.h> // for library module loading
00140 
00141 #include "config.h" // for build-time config
00142 #include "stage.hh"
00143 #include "worldfile.hh"
00144 #include "file_manager.hh"
00145 using namespace Stg;
00146 
00147 // static members
00148 uint32_t Model::count(0);
00149 uint32_t Model::trail_length(50);
00150 uint64_t Model::trail_interval(5);
00151 std::map<Stg::id_t,Model*> Model::modelsbyid;
00152 std::map<std::string, creator_t> Model::name_map;
00153 
00154 //static const members
00155 static const double DEFAULT_FRICTION = 0.0;
00156 
00157 
00158 Bounds& Bounds::Load( Worldfile* wf, const int section, const char* keyword )
00159 {
00160   wf->ReadTuple( section, keyword, 0, 2, "ll", &min, &max );
00161   return *this;
00162 }
00163 
00164 double Bounds::Constrain( double value )
00165 {
00166   return Stg::constrain( value, min, max );
00167 }
00168 
00169 Stg::Size& Stg::Size::Load( Worldfile* wf, const int section, const char* keyword )
00170 {
00171   wf->ReadTuple( section, keyword, 0, 3, "lll", &x, &y, &z );
00172   return *this;
00173 }
00174 
00175 void Stg::Size::Save( Worldfile* wf, int section, const char* keyword ) const
00176 {
00177   wf->WriteTuple( section, keyword, 0, 3, "lll", x, y, z );
00178 }
00179 
00180 Pose& Pose::Load( Worldfile* wf, const int section, const char* keyword )
00181 {
00182   wf->ReadTuple( section, keyword, 0, 4, "llla", &x, &y, &z, &a );
00183   normalize( a );
00184   return *this;
00185 }
00186 
00187 void Pose::Save( Worldfile* wf, const int section, const char* keyword )
00188 {
00189   wf->WriteTuple( section, keyword, 0, 4, "llla", x, y, z, a );
00190 }
00191 
00192 Model::Visibility::Visibility() : 
00193   blob_return( true ),
00194   fiducial_key( 0 ),
00195   fiducial_return( 0 ),
00196   gripper_return( false ),
00197   obstacle_return( true ),
00198   ranger_return( 1.0 )
00199 { /* nothing to do */ }
00200 
00201 
00202 Model::Visibility& Model::Visibility::Load( Worldfile* wf, int wf_entity )
00203 {
00204   blob_return = wf->ReadInt( wf_entity, "blob_return", blob_return);    
00205   fiducial_key = wf->ReadInt( wf_entity, "fiducial_key", fiducial_key);
00206   fiducial_return = wf->ReadInt( wf_entity, "fiducial_return", fiducial_return);
00207   gripper_return = wf->ReadInt( wf_entity, "gripper_return", gripper_return);    
00208   obstacle_return = wf->ReadInt( wf_entity, "obstacle_return", obstacle_return);    
00209   ranger_return = wf->ReadFloat( wf_entity, "ranger_return", ranger_return);    
00210 
00211   return *this;
00212 }    
00213 
00214 void Model::Visibility::Save( Worldfile* wf, int wf_entity )
00215 {
00216   wf->WriteInt( wf_entity, "blob_return", blob_return);    
00217   wf->WriteInt( wf_entity, "fiducial_key", fiducial_key);
00218   wf->WriteInt( wf_entity, "fiducial_return", fiducial_return);
00219   wf->WriteInt( wf_entity, "gripper_return", gripper_return);    
00220   wf->WriteInt( wf_entity, "obstacle_return", obstacle_return);    
00221   wf->WriteFloat( wf_entity, "ranger_return", ranger_return);    
00222 }    
00223 
00224 
00225 Model::GuiState::GuiState() :
00226   grid( false ),
00227   move( false ),  
00228   nose( false ),
00229   outline( false )
00230 { /* nothing to do */}
00231 
00232 Model::GuiState& Model::GuiState::Load( Worldfile* wf, int wf_entity )
00233 {
00234   nose = wf->ReadInt( wf_entity, "gui_nose", nose);    
00235   grid = wf->ReadInt( wf_entity, "gui_grid", grid);    
00236   outline = wf->ReadInt( wf_entity, "gui_outline", outline);    
00237   move = wf->ReadInt( wf_entity, "gui_move", move );    
00238  
00239   return *this;
00240 }    
00241 
00242 // constructor
00243 Model::Model( World* world,
00244               Model* parent,
00245               const std::string& type,
00246               const std::string& name ) :
00247   Ancestor(),    
00248   mapped(false),
00249   drawOptions(),
00250   alwayson(false),
00251   blockgroup(),
00252   blocks_dl(0),
00253   boundary(false),
00254   callbacks(__CB_TYPE_COUNT), // one slot in the vector for each type
00255   color( 1,0,0 ), // red
00256   data_fresh(false),
00257   disabled(false),
00258   cv_list(),
00259   flag_list(),
00260   friction(DEFAULT_FRICTION),
00261   geom(),
00262   has_default_block(true),
00263   id(Model::count++),
00264   interval((usec_t)1e5), // 100msec
00265   interval_energy((usec_t)1e5), // 100msec
00266   last_update(0),
00267   log_state(false),
00268   map_resolution(0.1),
00269   mass(0),
00270   parent(parent),
00271   pose(),
00272   power_pack(NULL),
00273   pps_charging(),
00274   rastervis(),
00275   rebuild_displaylist(true),
00276   say_string(),
00277   stack_children(true),
00278   stall(false),  
00279   subs(0),
00280   thread_safe(false),
00281   trail(trail_length),
00282   trail_index(0),
00283   type(type),   
00284   event_queue_num(0),
00285   used(false),
00286   watts(0.0),
00287   watts_give(0.0),
00288   watts_take(0.0),       
00289   wf(NULL),
00290   wf_entity(0),
00291   world(world),
00292   world_gui( dynamic_cast<WorldGui*>( world ) )
00293 {
00294   assert( world );
00295   
00296   PRINT_DEBUG3( "Constructing model world: %s parent: %s type: %s \n",
00297                 world->Token(), 
00298                 parent ? parent->Token() : "(null)",
00299                 type.c_str() );
00300   
00301   modelsbyid[id] = this;
00302   
00303   if( name.size() ) // use a name if specified
00304     {
00305       //printf( "name set %s\n", name.c_str() );
00306       SetToken( name );
00307     }
00308   else   // if a name was not specified make up a name based on the parent's
00309     // name,  model type and the number of instances so far    
00310     {
00311       char buf[2048];
00312       //  printf( "adding child of type %d token %s\n", mod->type, mod->Token() );
00313       
00314       // prefix with parent name if any, followed by the type name
00315       // with a suffix of a colon and the parent's number of children
00316       // of this type
00317       if( parent )
00318         {
00319           snprintf( buf, 2048, "%s.%s:%u",
00320                     parent->Token(),
00321                     type.c_str(),
00322                     parent->child_type_counts[type] ); 
00323         } 
00324       else // no parent, so use the count of this type in the world
00325         {
00326           snprintf( buf, 2048, "%s:%u",
00327                     type.c_str() ,
00328                     world->child_type_counts[type] ); 
00329         }
00330       
00331       //printf( "generated name %s\n", buf );
00332       SetToken( buf );
00333     }
00334   
00335   //  printf( "%s generated a name for my child %s\n", Token(),  name.str().c_str() );
00336   
00337   world->AddModel( this );
00338 
00339   if ( parent ) 
00340     parent->AddChild( this );
00341   else
00342     {
00343       world->AddChild( this );
00344       // top level models are draggable in the GUI by default
00345       gui.move = true;
00346     }        
00347 
00348   // now we can add the basic square shape
00349   AddBlockRect( -0.5, -0.5, 1.0, 1.0, 1.0 );
00350 
00351   AddVisualizer( &rastervis, false );
00352 
00353   PRINT_DEBUG2( "finished model %s @ %p", this->Token(), this );
00354 }
00355 
00356 Model::~Model( void )
00357 {
00358   // children are removed in ancestor class
00359   
00360   if( world ) // if I'm not a worldless dummy model
00361     {
00362       UnMap(); // remove from all layers
00363       
00364       // remove myself from my parent's child list, or the world's child
00365       // list if I have no parent               
00366       EraseAll( this, parent ? parent->children : world->children );                          
00367       // erase from the static map of all models
00368       modelsbyid.erase(id);                     
00369       
00370       world->RemoveModel( this );
00371     }
00372 }
00373 
00374 
00375 void Model::InitControllers()
00376 {
00377   CallCallbacks( CB_INIT );
00378 }
00379 
00380 
00381 void Model::AddFlag( Flag* flag )
00382 {
00383   if( flag )
00384     {
00385       flag_list.push_back( flag );              
00386       CallCallbacks( CB_FLAGINCR );
00387     }
00388 }
00389 
00390 void Model::RemoveFlag( Flag* flag )
00391 {
00392   if( flag )
00393     {
00394       EraseAll( flag, flag_list );
00395       CallCallbacks( CB_FLAGDECR );
00396     }
00397 }
00398 
00399 void Model::PushFlag( Flag* flag )
00400 {
00401   if( flag )
00402     {
00403       flag_list.push_front( flag);
00404       CallCallbacks( CB_FLAGINCR );
00405     }
00406 }
00407 
00408 Model::Flag* Model::PopFlag()
00409 {
00410   if( flag_list.size() == 0 )
00411     return NULL;
00412   
00413   Flag* flag = flag_list.front();
00414   flag_list.pop_front();
00415   
00416   CallCallbacks( CB_FLAGDECR );
00417 
00418   return flag;
00419 }
00420 
00421 void Model::ClearBlocks()
00422 {
00423   blockgroup.UnMap(0);
00424   blockgroup.UnMap(1);  
00425   blockgroup.Clear();
00426   //no need to Map() -  we have no blocks
00427   NeedRedraw();
00428 }
00429 
00430 void Model::LoadBlock( Worldfile* wf, int entity )
00431 {
00432   if( has_default_block )
00433     {
00434       blockgroup.Clear(); 
00435       has_default_block = false;
00436     }
00437   
00438   blockgroup.LoadBlock( this, wf, entity );  
00439 }
00440 
00441 
00442 Block* Model::AddBlockRect( meters_t x, 
00443                             meters_t y, 
00444                             meters_t dx, 
00445                             meters_t dy,
00446                             meters_t dz )
00447 {  
00448   UnMap();
00449 
00450   std::vector<point_t> pts(4);
00451   pts[0].x = x;
00452   pts[0].y = y;
00453   pts[1].x = x + dx;
00454   pts[1].y = y;
00455   pts[2].x = x + dx;
00456   pts[2].y = y + dy;
00457   pts[3].x = x;
00458   pts[3].y = y + dy;
00459   
00460   Block* newblock =  new Block( this,
00461                                 pts,
00462                                 0, dz, 
00463                                 color,
00464                                 true, 
00465                                 false );
00466   
00467   blockgroup.AppendBlock( newblock );
00468   
00469   Map();
00470   
00471   return newblock;
00472 }
00473 
00474 
00475 RaytraceResult Model::Raytrace( const Pose &pose,
00476                                 const meters_t range, 
00477                                 const ray_test_func_t func,
00478                                 const void* arg,
00479                                 const bool ztest )
00480 {
00481   return world->Raytrace( LocalToGlobal(pose),
00482                           range,
00483                           func,
00484                           this,
00485                           arg,
00486                           ztest );
00487 }
00488 
00489 RaytraceResult Model::Raytrace( const radians_t bearing,
00490                                 const meters_t range, 
00491                                 const ray_test_func_t func,
00492                                 const void* arg,
00493                                 const bool ztest )
00494 {
00495   return world->Raytrace( LocalToGlobal(Pose(0,0,0,bearing)),
00496                           range,
00497                           func,
00498                           this,
00499                           arg,
00500                           ztest );
00501 }
00502 
00503 
00504 void Model::Raytrace( const radians_t bearing,
00505                       const meters_t range, 
00506                       const radians_t fov,
00507                       const ray_test_func_t func,
00508                       const void* arg,
00509                       RaytraceResult* samples,
00510                       const uint32_t sample_count,
00511                       const bool ztest )
00512 {
00513   world->Raytrace( LocalToGlobal(Pose( 0,0,0,bearing)),
00514                    range,                  
00515                    fov,
00516                    func,
00517                    this,
00518                    arg,
00519                    samples,
00520                    sample_count,
00521                    ztest );
00522 }
00523 
00524 // convert a global pose into the model's local coordinate system
00525 Pose Model::GlobalToLocal( const Pose& pose ) const
00526 {
00527   // get model's global pose
00528   const Pose org( GetGlobalPose() );
00529   const double cosa(cos(org.a));
00530   const double sina(sin(org.a));
00531   
00532   // compute global pose in local coords
00533   return Pose( (pose.x - org.x) * cosa + (pose.y - org.y) * sina,
00534                -(pose.x - org.x) * sina + (pose.y - org.y) * cosa,
00535                pose.z - org.z,
00536                pose.a - org.a );
00537 }
00538 
00539 void Model::Say( const std::string& str )
00540 {
00541   say_string = str;
00542 }
00543 
00544 // returns true iff model [testmod] is an antecedent of this model
00545 bool Model::IsAntecedent( const Model* testmod ) const
00546 {
00547   if( parent == NULL )
00548     return false;
00549   
00550   if( parent == testmod )
00551     return true;
00552   
00553   return parent->IsAntecedent( testmod );
00554 }
00555 
00556 // returns true iff model [testmod] is a descendent of this model
00557 bool Model::IsDescendent( const Model* testmod ) const
00558 {
00559   if( this == testmod )
00560     return true;
00561   
00562   FOR_EACH( it, children )
00563     if( (*it)->IsDescendent( testmod ) )
00564       return true;
00565   
00566   // neither mod nor a child of this matches testmod
00567   return false;
00568 }
00569 
00570 bool Model::IsRelated( const Model* that ) const
00571 {
00572   // is it me?
00573   if( this == that )
00574     return true;
00575   
00576   // wind up to top-level object
00577   Model* candidate = (Model*)this;
00578   while( candidate->parent )
00579     {
00580       // shortcut out if we found it on the way up the tree
00581       if( candidate->parent == that )
00582         return true;
00583       
00584       candidate = candidate->parent;      
00585     }
00586   
00587   // we got to our root, so recurse down the tree    
00588   return candidate->IsDescendent( that );
00589   // TODO: recursive solution is costing us 3% of all compute time! try an
00590   // iterative solution?
00591 }
00592 
00593 point_t Model::LocalToGlobal( const point_t& pt) const
00594 {  
00595   const Pose gpose = LocalToGlobal( Pose( pt.x, pt.y, 0, 0 ) );
00596   return point_t( gpose.x, gpose.y );
00597 }
00598 
00599 
00600 std::vector<point_int_t> Model::LocalToPixels( const std::vector<point_t>& local ) const
00601 {
00602   std::vector<point_int_t> global;
00603   
00604   const Pose gpose( GetGlobalPose() + geom.pose );
00605   Pose ptpose;
00606   
00607   FOR_EACH( it, local )
00608     {
00609       ptpose = gpose + Pose( it->x, it->y, 0, 0 );
00610       global.push_back( point_int_t( (int32_t)floor( ptpose.x * world->ppm) ,
00611                                      (int32_t)floor( ptpose.y * world->ppm) ));
00612     }
00613 
00614   return global;
00615 }
00616 
00617 void Model::MapWithChildren( unsigned int layer )
00618 {
00619   UnMap(layer);
00620   Map(layer);
00621 
00622   // recursive call for all the model's children
00623   FOR_EACH( it, children )
00624     (*it)->MapWithChildren(layer);
00625 }
00626 
00627 void Model::MapFromRoot( unsigned int layer )
00628 {
00629   Root()->MapWithChildren(layer);
00630 }
00631 
00632 void Model::UnMapWithChildren(unsigned int layer)
00633 {
00634   UnMap(layer);
00635 
00636   // recursive call for all the model's children
00637   FOR_EACH( it, children )
00638     (*it)->UnMapWithChildren(layer);
00639 }
00640 
00641 void Model::UnMapFromRoot(unsigned int layer)
00642 {
00643   Root()->UnMapWithChildren(layer);
00644 }
00645 
00646 void Model::Subscribe( void )
00647 {
00648   subs++;
00649   world->total_subs++;
00650   world->dirty = true; // need redraw
00651   
00652   //printf( "subscribe to %s %d\n", Token(), subs );
00653   
00654   // if this is the first sub, call startup
00655   if( subs == 1 )
00656     Startup();
00657 }
00658 
00659 void Model::Unsubscribe( void )
00660 {
00661   subs--;
00662   world->total_subs--;
00663   world->dirty = true; // need redraw
00664 
00665   //printf( "unsubscribe from %s %d\n", Token(), subs );
00666 
00667   // if this is the last sub, call shutdown
00668   if( subs == 0 )
00669     this->Shutdown();
00670 }
00671 
00672 
00673 // void pose_invert( Pose* pose )
00674 // {
00675 //   pose->x = -pose->x;
00676 //   pose->y = -pose->y;
00677 //   // pose->a = pose->a;
00678 // }
00679 
00680 void Model::Print( char* prefix ) const
00681 {
00682   if( prefix )
00683     printf( "%s model ", prefix );
00684   else
00685     printf( "Model ");
00686   
00687   printf( "%s:%s\n", 
00688           world->Token(), 
00689           Token() );
00690   
00691   FOR_EACH( it, children )
00692     (*it)->Print( prefix );
00693 }
00694 
00695 const char* Model::PrintWithPose() const
00696 {
00697   const Pose gpose = GetGlobalPose();
00698         
00699   static char txt[256];
00700   snprintf(txt, sizeof(txt), "%s @ [%.2f,%.2f,%.2f,%.2f]",  
00701            Token(), 
00702            gpose.x, gpose.y, gpose.z, gpose.a  );
00703 
00704   return txt;
00705 }
00706 
00707 void Model::Startup( void )
00708 {
00709   //printf( "Startup model %s\n", this->token );  
00710   //printf( "model %s using queue %d\n", token, event_queue_num );
00711   
00712   // iff we're thread safe, we can use an event queue >0, else 0
00713   event_queue_num =  thread_safe ? world->GetEventQueue( this ) : 0;
00714   
00715   world->Enqueue( event_queue_num, interval, this, UpdateWrapper, NULL );
00716     
00717   if( FindPowerPack() )
00718     world->EnableEnergy( this );
00719   
00720   CallCallbacks( CB_STARTUP );
00721 }
00722 
00723 void Model::Shutdown( void )
00724 {
00725   //printf( "Shutdown model %s\n", this->token );
00726   CallCallbacks( CB_SHUTDOWN );
00727   
00728   world->DisableEnergy( this );
00729 
00730   // allows data visualizations to be cleared.
00731   NeedRedraw();
00732 }
00733 
00734 
00735 void Model::Update( void )
00736 { 
00737   //printf( "Q%d model %p %s update\n", event_queue_num, this, Token() );
00738 
00739   //    CallCallbacks( CB_UPDATE );
00740         
00741   last_update = world->sim_time;  
00742         
00743   if( subs > 0 ) // no subscriptions means we don't need to be updated
00744     world->Enqueue( event_queue_num, interval, this, UpdateWrapper, NULL );
00745         
00746   // if we updated the model then it needs to have its update
00747   // callback called in series back in the main thread. It's
00748   // not safe to run user callbacks in a worker thread, as
00749   // they may make OpenGL calls or unsafe Stage API calls,
00750   // etc. We queue up the callback into a queue specific to
00751 
00752   if( ! callbacks[Model::CB_UPDATE].empty() )
00753     world->pending_update_callbacks[event_queue_num].push(this);                                        
00754 }
00755 
00756 void Model::CallUpdateCallbacks( void )
00757 {
00758   CallCallbacks( CB_UPDATE );
00759 }
00760 
00761 meters_t Model::ModelHeight() const
00762 {       
00763   meters_t m_child = 0; //max size of any child
00764   FOR_EACH( it, children )
00765     m_child = std::max( m_child, (*it)->ModelHeight() );
00766         
00767   //height of model + max( child height )
00768   return geom.size.z + m_child;
00769 }
00770 
00771 void Model::AddToPose( double dx, double dy, double dz, double da )
00772 {
00773   Pose p( this->pose );
00774   p.x += dx;
00775   p.y += dy;
00776   p.z += dz;
00777   p.a += da;
00778   
00779   this->SetPose( p );
00780 }
00781 
00782 void Model::AddToPose( const Pose& pose )
00783 {
00784   this->AddToPose( pose.x, pose.y, pose.z, pose.a );
00785 }
00786 
00787 void Model::PlaceInFreeSpace( meters_t xmin, meters_t xmax, 
00788                               meters_t ymin, meters_t ymax )
00789 {
00790   while( TestCollision() )
00791     SetPose( Pose::Random( xmin,xmax, ymin, ymax ));            
00792 }
00793 
00794 void Model::AppendTouchingModels( std::set<Model*>& touchers )
00795 {
00796   blockgroup.AppendTouchingModels( touchers );
00797 }
00798 
00799 
00800 Model* Model::TestCollision()
00801 {  
00802   Model* hitmod( blockgroup.TestCollision() );
00803   
00804   if( hitmod == NULL )   
00805     FOR_EACH( it, children )
00806       { 
00807         hitmod = (*it)->TestCollision();
00808         if( hitmod )
00809           break;
00810       }
00811   
00812   //printf( "mod %s test collision done.\n", token );
00813   return hitmod;  
00814 }  
00815 
00816 void Model::UpdateCharge()
00817 {  
00818   PowerPack* mypp = FindPowerPack();
00819   assert( mypp );
00820   
00821   if( watts > 0 ) // dissipation rate
00822     {
00823       // consume  energy stored in the power pack
00824       mypp->Dissipate( watts * (interval_energy * 1e-6), GetGlobalPose() );      
00825     }  
00826   
00827   if( watts_give > 0 ) // transmission to other powerpacks max rate
00828     {  
00829       // detach charger from all the packs charged last time
00830       FOR_EACH( it, pps_charging )
00831         (*it)->ChargeStop();
00832       pps_charging.clear();
00833                 
00834       // run through and update all appropriate touchers
00835       std::set<Model*> touchers;
00836       AppendTouchingModels( touchers );
00837                 
00838       FOR_EACH( it, touchers )
00839         {
00840           Model* toucher = (*it);
00841           PowerPack* hispp =toucher->FindPowerPack();           
00842                          
00843           if( hispp && toucher->watts_take > 0.0) 
00844             {           
00845               //printf( "   toucher %s can take up to %.2f wats\n", 
00846               //                toucher->Token(), toucher->watts_take );
00847                                   
00848               const watts_t rate = std::min( watts_give, toucher->watts_take );
00849               const joules_t amount =  rate * interval_energy * 1e-6;
00850                                   
00851               //printf ( "moving %.2f joules from %s to %s\n",
00852               //                 amount, token, toucher->token );
00853                                   
00854               // set his charging flag
00855               hispp->ChargeStart();
00856                                   
00857               // move some joules from me to him
00858               mypp->TransferTo( hispp, amount );
00859                                   
00860               // remember who we are charging so we can detatch next time
00861               pps_charging.push_front( hispp );
00862             }
00863         }
00864     }
00865 }
00866 
00867 
00868 void Model::UpdateTrail()
00869 {
00870   // get the current item and increment the counter
00871   TrailItem* item = &trail[trail_index++];
00872         
00873   // record the current info
00874   item->time = world->sim_time;
00875   item->pose = GetGlobalPose();
00876   item->color = color;
00877 
00878   // wrap around ring buffer
00879   trail_index %= trail_length;
00880 }
00881 
00882 Model* Model::GetUnsubscribedModelOfType( const std::string& type ) const
00883 {  
00884   if( (this->type == type) && (this->subs == 0) )
00885     return const_cast<Model*> (this); // discard const
00886 
00887   // this model is no use. try children recursively
00888   FOR_EACH( it, children )
00889     {
00890       Model* found = (*it)->GetUnsubscribedModelOfType( type );
00891       if( found )
00892         return found;
00893     }
00894   
00895   // nothing matching below this model
00896   return NULL;
00897 }
00898 
00899 void Model::NeedRedraw( void )
00900 {
00901   this->rebuild_displaylist = true;
00902 
00903   if( parent )
00904     parent->NeedRedraw();
00905   else
00906     world->NeedRedraw();
00907 }
00908 
00909 void Model::Redraw( void )
00910 {
00911   world->Redraw();
00912 }
00913 
00914 Model* Model::GetUnusedModelOfType( const std::string& type )
00915 {
00916   //printf( "searching for type %d in model %s type %d\n", type, token, this->type );
00917   
00918   if( (this->type == type) && (!this->used ) )
00919     {
00920       this->used = true;
00921       return this;
00922     }
00923 
00924   // this model is no use. try children recursively
00925   FOR_EACH( it, children )
00926     {
00927       Model* found = (*it)->GetUnusedModelOfType( type );
00928       if( found )
00929         return found;
00930     }
00931   
00932   // nothing matching below this model
00933   if( ! parent )  PRINT_WARN1( "Request for unused model of type %s failed", type.c_str() );
00934   return NULL;
00935 }
00936 
00937 kg_t Model::GetTotalMass() const
00938 {
00939   kg_t sum = mass;
00940   
00941   FOR_EACH( it, children )
00942     sum += (*it)->GetTotalMass();
00943 
00944   return sum;
00945 }
00946 
00947 kg_t Model::GetMassOfChildren() const
00948 {
00949   return( GetTotalMass() - mass);
00950 }
00951 
00952 void Model::Map( unsigned int layer )
00953 {
00954   if( ! mapped )
00955     {
00956       // render all blocks in the group at my global pose and size
00957       blockgroup.Map( layer );
00958       mapped = true;
00959     }
00960 } 
00961 
00962 void Model::UnMap( unsigned int layer )
00963 {
00964   if( mapped )
00965     {
00966       blockgroup.UnMap(layer);
00967       mapped = false;
00968     }
00969 }
00970 
00971 void Model::BecomeParentOf( Model* child )
00972 {
00973   if( child->parent )
00974     child->parent->RemoveChild( child );
00975   else
00976     world->RemoveChild( child );
00977   
00978   child->parent = this;
00979   
00980   this->AddChild( child );
00981   
00982   world->dirty = true; 
00983 }
00984 
00985 PowerPack* Model::FindPowerPack() const
00986 {
00987   if( power_pack )
00988     return power_pack;
00989   
00990   if( parent )
00991     return parent->FindPowerPack();
00992 
00993   return NULL;
00994 }
00995 
00996 void Model::RegisterOption( Option* opt )
00997 { 
00998   world->RegisterOption( opt );
00999 }
01000 
01001 
01002 void Model::Rasterize( uint8_t* data, 
01003                        unsigned int width, 
01004                        unsigned int height, 
01005                        meters_t cellwidth,
01006                        meters_t cellheight )
01007 {
01008   rastervis.ClearPts();
01009   blockgroup.Rasterize( data, width, height, cellwidth, cellheight );
01010   rastervis.SetData( data, width, height, cellwidth, cellheight );
01011 }
01012 
01013 void Model::SetFriction( double friction )
01014 {
01015   this->friction = friction;
01016 }
01017 
01018 Model* Model::GetChild( const std::string& modelname ) const
01019 {
01020   // construct the full model name and look it up
01021   
01022   const std::string fullname = token + "." + modelname;
01023   
01024   Model* mod = world->GetModel( fullname );
01025   
01026   if( mod == NULL )
01027     PRINT_WARN1( "Model %s not found", fullname.c_str() );
01028   
01029   return mod;
01030 }
01031 
01032 
01033 //***************************************************************
01034 // Raster data visualizer
01035 //
01036 Model::RasterVis::RasterVis() 
01037   : Visualizer( "Rasterization", "raster_vis" ),
01038     data(NULL),
01039     width(0),
01040     height(0),
01041     cellwidth(0),
01042     cellheight(0),
01043     pts()
01044 {
01045   
01046 }
01047 
01048 void Model::RasterVis::Visualize( Model* mod, Camera* cam ) 
01049 {
01050   (void)cam; // avoid warning about unused var
01051 
01052   if( data == NULL )
01053     return;
01054 
01055   // go into world coordinates  
01056   glPushMatrix();
01057   mod->PushColor( 1,0,0,0.5 );
01058 
01059   Gl::pose_inverse_shift( mod->GetGlobalPose() );
01060   
01061   if( pts.size() > 0 )
01062     {
01063       glPushMatrix();
01064       //Size sz = mod->blockgroup.GetSize();
01065       //glTranslatef( -mod->geom.size.x / 2.0, -mod->geom.size.y/2.0, 0 );
01066       //glScalef( mod->geom.size.x / sz.x, mod->geom.size.y / sz.y, 1 );
01067                 
01068       // now we're in world meters coordinates
01069       glPointSize( 4 );
01070       glBegin( GL_POINTS );
01071                 
01072       FOR_EACH( it, pts )
01073         {
01074           point_t& pt = *it;
01075           glVertex2f( pt.x, pt.y );
01076                          
01077           char buf[128];
01078           snprintf( buf, 127, "[%.2f x %.2f]", pt.x, pt.y );
01079           Gl::draw_string( pt.x, pt.y, 0, buf );                  
01080         }
01081       glEnd();
01082                 
01083       mod->PopColor();
01084                 
01085       glPopMatrix();
01086     }
01087 
01088   // go into bitmap pixel coords
01089   glTranslatef( -mod->geom.size.x / 2.0, -mod->geom.size.y/2.0, 0 );
01090   //glScalef( mod->geom.size.x / width, mod->geom.size.y / height, 1 );
01091 
01092   glScalef( cellwidth, cellheight, 1 );
01093 
01094   mod->PushColor( 0,0,0,0.5 );
01095   glPolygonMode( GL_FRONT, GL_FILL );
01096   for( unsigned int y=0; y<height; ++y )
01097     for( unsigned int x=0; x<width; ++x )
01098       {
01099         // printf( "[%u %u] ", x, y );
01100         if( data[ x + y*width ] )
01101           glRectf( x, y, x+1, y+1 );
01102       }
01103 
01104   glTranslatef( 0,0,0.01 );
01105 
01106   mod->PushColor( 0,0,0,1 );
01107   glPolygonMode( GL_FRONT, GL_LINE );
01108   for( unsigned int y=0; y<height; ++y )
01109     for( unsigned int x=0; x<width; ++x )
01110       {
01111         if( data[ x + y*width ] )
01112           glRectf( x, y, x+1, y+1 );
01113                   
01114         //                char buf[128];
01115         //                snprintf( buf, 127, "[%u x %u]", x, y );
01116         //                Gl::draw_string( x, y, 0, buf );                
01117       }
01118 
01119         
01120   glPolygonMode( GL_FRONT, GL_FILL );
01121         
01122   mod->PopColor();
01123   mod->PopColor();
01124 
01125   mod->PushColor( 0,0,0,1 );
01126   char buf[128];
01127   snprintf( buf, 127, "[%u x %u]", width, height );
01128   glTranslatef( 0,0,0.01 );
01129   Gl::draw_string( 1, height-1, 0, buf );
01130   
01131   mod->PopColor();
01132 
01133   glPopMatrix();
01134 }
01135 
01136 void Model::RasterVis::SetData( uint8_t* data, 
01137                                 const unsigned int width, 
01138                                 const unsigned int height,
01139                                 const meters_t cellwidth, 
01140                                 const meters_t cellheight )
01141 {
01142   // copy the raster for test visualization
01143   if( this->data ) 
01144     delete[] this->data;  
01145   size_t len = sizeof(uint8_t) * width * height;
01146   //printf( "allocating %lu bytes\n", len );
01147   this->data = new uint8_t[len];
01148   memcpy( this->data, data, len );
01149   this->width = width;
01150   this->height = height;
01151   this->cellwidth = cellwidth;
01152   this->cellheight = cellheight;
01153 }
01154 
01155 
01156 void Model::RasterVis::AddPoint( const meters_t x, const meters_t y )
01157 {
01158   pts.push_back( point_t( x, y ) );
01159 }
01160 
01161 void Model::RasterVis::ClearPts()
01162 {
01163   pts.clear();
01164 }
01165 
01166 
01167 Model::Flag::Flag( const Color& color, const double size ) 
01168   : color(color), size(size), displaylist(0)
01169 { 
01170 }
01171 
01172 Model::Flag* Model::Flag::Nibble( double chunk )
01173 {
01174   Flag* piece = NULL;
01175 
01176   if( size > 0 )
01177     {
01178       chunk = std::min( chunk, this->size );
01179       piece = new Flag( this->color, chunk );
01180       this->size -= chunk;
01181     }
01182 
01183   return piece;
01184 }
01185 
01186 
01187 void Model::Flag::SetColor( const Color& c )
01188 {
01189   color = c;
01190         
01191   if( displaylist )
01192     {
01193       // force recreation of list
01194       glDeleteLists( displaylist, 1 );
01195       displaylist = 0;
01196     }
01197 }
01198 
01199 void Model::Flag::SetSize( double sz )
01200 {
01201   size = sz;
01202         
01203   if( displaylist )
01204     {
01205       // force recreation of list
01206       glDeleteLists( displaylist, 1 );
01207       displaylist = 0;
01208     }
01209 }
01210 
01211 
01212 void Model::Flag::Draw(  GLUquadric* quadric )
01213 {
01214   if( displaylist == 0 )
01215     {
01216       displaylist = glGenLists(1);
01217       assert( displaylist > 0 );
01218                         
01219       glNewList( displaylist, GL_COMPILE );     
01220                         
01221       glColor4f( color.r, color.g, color.b, color.a );
01222                         
01223       glEnable(GL_POLYGON_OFFSET_FILL);
01224       glPolygonOffset(1.0, 1.0);
01225       gluQuadricDrawStyle( quadric, GLU_FILL );
01226       gluSphere( quadric, size/2.0, 4,2  );
01227       glDisable(GL_POLYGON_OFFSET_FILL);
01228                         
01229       // draw the edges darker version of the same color
01230       glColor4f( color.r/2.0, color.g/2.0, color.b/2.0, color.a/2.0 );
01231                         
01232       gluQuadricDrawStyle( quadric, GLU_LINE );
01233       gluSphere( quadric, size/2.0, 4,2 );
01234 
01235       glEndList();
01236     }
01237 
01238   glCallList( displaylist );
01239 }
01240 
01241 
01242 
01243 void Model::SetGeom( const Geom& val )
01244 {  
01245   UnMapWithChildren(0);
01246   UnMapWithChildren(1);
01247   
01248   geom = val;
01249   
01250   blockgroup.CalcSize();
01251   
01252   NeedRedraw();
01253   
01254   MapWithChildren(0);
01255   MapWithChildren(1);
01256     
01257   CallCallbacks( CB_GEOM );
01258 }
01259 
01260 void Model::SetColor( Color val )
01261 {
01262   color = val;
01263   NeedRedraw();
01264 }
01265 
01266 void Model::SetMass( kg_t val )
01267 {
01268   mass = val;
01269 }
01270 
01271 void Model::SetStall( bool val )
01272 {
01273   stall = val;
01274 }
01275 
01276 void Model::SetGripperReturn( bool val )
01277 {
01278   vis.gripper_return = val;
01279 }
01280 
01281 void Model::SetFiducialReturn(  int val )
01282 {
01283   vis.fiducial_return = val;
01284   
01285   // non-zero values mean we need to be in the world's set of
01286   // detectable models
01287   if( val == 0 )
01288     world->FiducialErase( this );
01289   else
01290     world->FiducialInsert( this );
01291 }
01292 
01293 void Model::SetFiducialKey( int val )
01294 {
01295   vis.fiducial_key = val;
01296 }
01297 
01298 void Model::SetObstacleReturn( bool val )
01299 {
01300   vis.obstacle_return = val;
01301 }
01302 
01303 void Model::SetBlobReturn( bool val )
01304 {
01305   vis.blob_return = val;
01306 }
01307 
01308 void Model::SetRangerReturn( double val )
01309 {
01310   vis.ranger_return = val;
01311 }
01312 
01313 void Model::SetBoundary( bool val )
01314 {
01315   boundary = val;
01316 }
01317 
01318 void Model::SetGuiNose(  bool val )
01319 {
01320   gui.nose = val;
01321 }
01322 
01323 void Model::SetGuiMove( bool val )
01324 {
01325   gui.move = val;
01326 }
01327 
01328 void Model::SetGuiGrid(  bool val )
01329 {
01330   gui.grid = val;
01331 }
01332 
01333 void Model::SetGuiOutline( bool val )
01334 {
01335   gui.outline = val;
01336 }
01337 
01338 void Model::SetWatts( watts_t val )
01339 {
01340   watts = val;
01341 }
01342 
01343 void Model::SetMapResolution(  meters_t val )
01344 {
01345   map_resolution = val;
01346 }
01347 
01348 // set the pose of model in global coordinates 
01349 void Model::SetGlobalPose( const Pose& gpose )
01350 {
01351   SetPose( parent ? parent->GlobalToLocal( gpose ) : gpose );
01352 }
01353 
01354 int Model::SetParent( Model* newparent)
01355 {  
01356   Pose oldPose = GetGlobalPose();
01357 
01358   // remove the model from its old parent (if it has one)
01359   if( parent )
01360     parent->RemoveChild( this );
01361   else
01362     world->RemoveChild( this );
01363   // link from the model to its new parent
01364   this->parent = newparent;
01365   
01366   if( newparent )
01367     newparent->AddChild( this );
01368   else
01369     world->AddModel( this );
01370 
01371   CallCallbacks( CB_PARENT );
01372 
01373   SetGlobalPose( oldPose ); // Needs to recalculate position due to change in parent
01374   
01375   return 0; //ok
01376 }
01377 
01378 // get the model's position in the global frame
01379 Pose Model::GetGlobalPose() const
01380 { 
01381   // if I'm a top level model, my global pose is my local pose
01382   if( parent == NULL )
01383     return pose;
01384   
01385   // otherwise    
01386   Pose global_pose = parent->GetGlobalPose() + pose;            
01387   
01388   if ( parent->stack_children ) // should we be on top of our parent?
01389     global_pose.z += parent->geom.size.z;
01390   
01391   return global_pose;
01392 }
01393 
01394 
01395 // set the model's pose in the local frame
01396 void Model::SetPose( const Pose& newpose )
01397 {
01398   // if the pose has changed, we need to do some work
01399   if( memcmp( &pose, &newpose, sizeof(Pose) ) != 0 )
01400     {
01401       pose = newpose;
01402       pose.a = normalize(pose.a);
01403 
01404       //       if( isnan( pose.a ) )
01405       //                  printf( "SetPose bad angle %s [%.2f %.2f %.2f %.2f]\n",
01406       //                                         token, pose.x, pose.y, pose.z, pose.a );
01407                         
01408       NeedRedraw();
01409 
01410       UnMapWithChildren(0);
01411       UnMapWithChildren(1);
01412 
01413       MapWithChildren(0);
01414       MapWithChildren(1);
01415 
01416       world->dirty = true;
01417     }
01418         
01419   CallCallbacks( CB_POSE );
01420 }
01421 
01422 void Model::Load()
01423 {  
01424   assert( wf );
01425   assert( wf_entity );
01426   
01427   PRINT_DEBUG1( "Model \"%s\" loading...", token.c_str() );
01428   
01429   // choose the thread to run in, if thread_safe > 0 
01430   event_queue_num = wf->ReadInt( wf_entity, "event_queue", event_queue_num );
01431 
01432   if( wf->PropertyExists( wf_entity, "joules" ) )
01433     {
01434       if( !power_pack )
01435         power_pack = new PowerPack( this );
01436                 
01437       joules_t j = wf->ReadFloat( wf_entity, "joules", 
01438                                   power_pack->GetStored() ) ;    
01439                 
01440       /* assume that the store is full, so the capacity is the same as
01441          the charge */
01442       power_pack->SetStored( j );
01443       power_pack->SetCapacity( j );
01444     }
01445 
01446   if( wf->PropertyExists( wf_entity, "joules_capacity" ) )
01447     {
01448       if( !power_pack )
01449         power_pack = new PowerPack( this );
01450                 
01451       power_pack->SetCapacity( wf->ReadFloat( wf_entity, "joules_capacity",
01452                                               power_pack->GetCapacity() ) );            
01453     }
01454 
01455   if( wf->PropertyExists( wf_entity, "kjoules" ) )
01456     {
01457       if( !power_pack )
01458         power_pack = new PowerPack( this );
01459                 
01460       joules_t j = 1000.0 * wf->ReadFloat( wf_entity, "kjoules", 
01461                                            power_pack->GetStored() ) ;   
01462                 
01463       /* assume that the store is full, so the capacity is the same as
01464          the charge */
01465       power_pack->SetStored( j );
01466       power_pack->SetCapacity( j );
01467     }
01468   
01469   if( wf->PropertyExists( wf_entity, "kjoules_capacity" ) )
01470     {
01471       if( !power_pack )
01472         power_pack = new PowerPack( this );
01473                 
01474       power_pack->SetCapacity( 1000.0 * wf->ReadFloat( wf_entity, "kjoules_capacity",
01475                                                        power_pack->GetCapacity() ) );           
01476     }
01477 
01478     
01479   watts = wf->ReadFloat( wf_entity, "watts", watts );    
01480   watts_give = wf->ReadFloat( wf_entity, "give_watts", watts_give );    
01481   watts_take = wf->ReadFloat( wf_entity, "take_watts", watts_take );
01482   
01483   debug = wf->ReadInt( wf_entity, "debug", debug );
01484   
01485   const std::string& name = wf->ReadString(wf_entity, "name", token );
01486   if( name != token )
01487     SetToken( name );
01488   
01489   //PRINT_WARN1( "%s::Load", token );
01490   
01491   Geom g( GetGeom() );
01492   
01493   if( wf->PropertyExists( wf_entity, "origin" ) )
01494     g.pose.Load( wf, wf_entity, "origin" );
01495   
01496   if( wf->PropertyExists( wf_entity, "size" ) )
01497     g.size.Load( wf, wf_entity, "size" );
01498   
01499   SetGeom( g );
01500 
01501   if( wf->PropertyExists( wf_entity, "pose" ))
01502     SetPose( GetPose().Load( wf, wf_entity, "pose" ) );
01503   
01504 
01505   if( wf->PropertyExists( wf_entity, "color" ))
01506     {      
01507       Color col( 1,0,0 ); // red;
01508       const std::string& colorstr = wf->ReadString( wf_entity, "color", "" );
01509       if( colorstr != "" )
01510         {
01511           if( colorstr == "random" )
01512             col = Color( drand48(), drand48(), drand48() );
01513           else
01514             col = Color( colorstr );
01515         }
01516       this->SetColor( col );
01517     }        
01518   
01519   this->SetColor( GetColor().Load( wf, wf_entity ) );
01520   
01521   if( wf->ReadInt( wf_entity, "noblocks", 0 ) )
01522     {
01523       if( has_default_block )
01524         {
01525           blockgroup.Clear();
01526           has_default_block = false;
01527           blockgroup.CalcSize();
01528         }               
01529     }
01530   
01531   if( wf->PropertyExists( wf_entity, "bitmap" ) )
01532     {
01533       const std::string bitmapfile = wf->ReadString( wf_entity, "bitmap", "" );
01534       if( bitmapfile == "" )
01535         PRINT_WARN1( "model %s specified empty bitmap filename\n", Token() );
01536                 
01537       if( has_default_block )
01538         {
01539           blockgroup.Clear();
01540           has_default_block = false;
01541         }
01542                 
01543       blockgroup.LoadBitmap( this, bitmapfile, wf );
01544     }
01545   
01546   if( wf->PropertyExists( wf_entity, "boundary" ))
01547     {
01548       this->SetBoundary( wf->ReadInt(wf_entity, "boundary", this->boundary  ));
01549                 
01550       if( boundary )
01551         {
01552           //PRINT_WARN1( "setting boundary for %s\n", token );
01553                          
01554           blockgroup.CalcSize();
01555                          
01556           double epsilon = 0.01;              
01557           Size bgsize = blockgroup.GetSize();
01558                          
01559           AddBlockRect(blockgroup.minx,blockgroup.miny, epsilon, bgsize.y, bgsize.z );        
01560           AddBlockRect(blockgroup.minx,blockgroup.miny, bgsize.x, epsilon, bgsize.z );        
01561           AddBlockRect(blockgroup.minx,blockgroup.maxy-epsilon, bgsize.x, epsilon, bgsize.z );        
01562           AddBlockRect(blockgroup.maxx-epsilon,blockgroup.miny, epsilon, bgsize.y, bgsize.z );        
01563         }     
01564     }     
01565   
01566   this->stack_children =
01567     wf->ReadInt( wf_entity, "stack_children", this->stack_children );
01568   
01569   kg_t m = wf->ReadFloat(wf_entity, "mass", this->mass );
01570   if( m != this->mass ) 
01571     SetMass( m );
01572         
01573   vis.Load( wf, wf_entity );
01574   SetFiducialReturn( vis.fiducial_return ); // may have some work to do
01575   
01576   gui.Load( wf, wf_entity );
01577 
01578   double res = wf->ReadFloat(wf_entity, "map_resolution", this->map_resolution );
01579   if( res != this->map_resolution )
01580     SetMapResolution( res );
01581   
01582   if( wf->PropertyExists( wf_entity, "friction" ))
01583     {
01584       this->SetFriction( wf->ReadFloat(wf_entity, "friction", this->friction ));
01585     }
01586   
01587   if( CProperty* ctrlp = wf->GetProperty( wf_entity, "ctrl" ) )
01588     {
01589       for( unsigned int index=0; index < ctrlp->values.size(); index++ )
01590         {
01591                          
01592           const char* lib = wf->GetPropertyValue( ctrlp, index );
01593                          
01594           if( !lib )
01595             printf( "Error - NULL library name specified for model %s\n", Token() );
01596           else
01597             LoadControllerModule( lib );
01598         }
01599     }
01600     
01601   // internally interval is in usec, but we use msec in worldfiles
01602   interval = 1000 * wf->ReadInt( wf_entity, "update_interval", interval/1000 );
01603 
01604   Say( wf->ReadString(wf_entity, "say", "" ));
01605   
01606   trail_length = wf->ReadInt( wf_entity, "trail_length", trail_length );
01607   trail.resize( trail_length );
01608 
01609   trail_interval = wf->ReadInt( wf_entity, "trail_interval", trail_interval );
01610 
01611   this->alwayson = wf->ReadInt( wf_entity, "alwayson",  alwayson );
01612   if( alwayson )
01613     Subscribe();
01614         
01615   // call any type-specific load callbacks
01616   this->CallCallbacks( CB_LOAD );
01617   
01618   // we may well have changed blocks or geometry
01619   blockgroup.CalcSize();
01620   
01621   UnMapWithChildren(0);
01622   UnMapWithChildren(1);
01623   MapWithChildren(0);
01624   MapWithChildren(1);
01625   
01626   if( this->debug )
01627     printf( "Model \"%s\" is in debug mode\n", Token() );
01628 
01629   PRINT_DEBUG1( "Model \"%s\" loading complete", Token() );
01630 }
01631 
01632 
01633 void Model::Save( void )
01634 {  
01635   //printf( "Model \"%s\" saving...\n", Token() );
01636 
01637   // some models were not loaded, so have no worldfile. Just bail here.
01638   if( wf == NULL )
01639     return;
01640 
01641   assert( wf_entity );
01642         
01643   PRINT_DEBUG5( "saving model %s pose [ %.2f, %.2f, %.2f, %.2f]",
01644                 token.c_str(),
01645                 pose.x,
01646                 pose.y,
01647                 pose.z,
01648                 pose.a );
01649         
01650   // just in case
01651   pose.a = normalize( pose.a );
01652   geom.pose.a = normalize( geom.pose.a );
01653   
01654   if( wf->PropertyExists( wf_entity, "pose" ) )
01655     pose.Save( wf, wf_entity, "pose" );
01656   
01657   if( wf->PropertyExists( wf_entity, "size" ) )
01658     geom.size.Save( wf, wf_entity, "size" );
01659   
01660   if( wf->PropertyExists( wf_entity, "origin" ) )
01661     geom.pose.Save( wf, wf_entity, "origin" );
01662 
01663   vis.Save( wf, wf_entity );
01664 
01665   // call any type-specific save callbacks
01666   CallCallbacks( CB_SAVE );
01667 
01668   PRINT_DEBUG1( "Model \"%s\" saving complete.", token.c_str() );
01669 }
01670 
01671 
01672 void Model::LoadControllerModule( const char* lib )
01673 {
01674   //printf( "[Ctrl \"%s\"", lib );
01675   //fflush(stdout);
01676 
01677   /* Initialise libltdl. */
01678   int errors = lt_dlinit();
01679   if (errors)
01680     {
01681       printf( "Libtool error: %s. Failed to init libtool. Quitting\n",
01682               lt_dlerror() ); // report the error from libtool
01683       puts( "libtool error #1" );
01684       fflush( stdout );
01685       exit(-1);
01686     }
01687 
01688   lt_dlsetsearchpath( FileManager::stagePath().c_str() );
01689 
01690   // PLUGIN_PATH now defined in config.h
01691   lt_dladdsearchdir( PLUGIN_PATH );
01692 
01693   lt_dlhandle handle = NULL;
01694   
01695   // the library name is the first word in the string
01696   char libname[256];
01697   sscanf( lib, "%s %*s", libname );
01698   
01699   if(( handle = lt_dlopenext( libname ) ))
01700     {
01701       //printf( "]" );
01702                 
01703       model_callback_t initfunc = (model_callback_t)lt_dlsym( handle, "Init" );
01704       if( initfunc  == NULL )
01705         {
01706           printf( "Libtool error: %s. Something is wrong with your plugin. Quitting\n",
01707                   lt_dlerror() ); // report the error from libtool
01708           puts( "libtool error #1" );
01709           fflush( stdout );
01710           exit(-1);
01711         }
01712                 
01713       AddCallback( CB_INIT, initfunc, new CtrlArgs(lib,World::ctrlargs) ); // pass complete string into initfunc
01714     }
01715   else
01716     {
01717       printf( "Libtool error: %s. Can't open your plugin controller. Quitting\n",
01718               lt_dlerror() ); // report the error from libtool
01719                 
01720       PRINT_ERR1( "Failed to open \"%s\". Check that it can be found by searching the directories in your STAGEPATH environment variable, or the current directory if STAGEPATH is not set.]\n", lib );
01721       puts( "libtool error #2" );
01722       fflush( stdout );
01723       exit(-1);
01724     }
01725   
01726   fflush(stdout);
01727 }
01728 


stage
Author(s): Richard Vaughan , Brian Gerkey , Reed Hedges , Andrew Howard , Toby Collett , Pooya Karimian , Jeremy Asher , Alex Couture-Beil , Geoff Biggs , Rich Mattes , Abbas Sadat
autogenerated on Thu Aug 27 2015 15:20:57