Panda3D

pgrid.cxx

00001 // Filename: pgrid.cxx
00002 // Created by:  drose (03Apr02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pandaFramework.h"
00016 #include "pandaNode.h"
00017 #include "transformState.h"
00018 #include "clockObject.h"
00019 #include "string_utils.h"
00020 #include "pvector.h"
00021 
00022 #ifdef HAVE_GETOPT
00023 #include <getopt.h>
00024 #else
00025 #include "gnu_getopt.h"
00026 #endif
00027 
00028 
00029 #define RANDFRAC (rand()/(float)(RAND_MAX))
00030 
00031 class GriddedFilename {
00032 public:
00033   Filename _filename;
00034   int _count;
00035   NodePath _model;
00036 };
00037 typedef pvector<GriddedFilename> GriddedFilenames;
00038 
00039 typedef struct {
00040   // for rot moving
00041   float xcenter,ycenter;
00042   float xoffset,yoffset;
00043   float ang1,ang1_vel;
00044   float ang2,ang2_vel;
00045   
00046   float radius;
00047   
00048   // for moving
00049   float xstart,ystart;
00050   float xend,yend;
00051   float xdel,ydel,timedel;
00052   double starttime,endtime;
00053   double vel;
00054   LMatrix4f rotmat;
00055 
00056   PandaNode *node;
00057 } gridded_file_info;
00058 
00059 typedef pvector<gridded_file_info> GriddedInfoArray;
00060 
00061 typedef enum {None,Rotation,LinearMotion} GriddedMotionType;
00062 
00063 #define GRIDCELLSIZE 5.0
00064 static int gridwidth;  // cells/side
00065 
00066 #define MIN_WANDERAREA_DIMENSION 120.0f
00067 
00068 static float grid_pos_offset;  // origin of grid
00069 static float wander_area_pos_offset;
00070 
00071 static GriddedMotionType gridmotiontype = None;
00072 
00073 
00074 // making these fns to get around ridiculous VC++ matrix inlining bugs at Opt2
00075 static void
00076 move_gridded_stuff(GriddedMotionType gridmotiontype,
00077                    gridded_file_info *InfoArr, int size) {
00078   double now = ClockObject::get_global_clock()->get_frame_time();
00079 
00080   LMatrix4f tmat1,tmat2,xfm_mat;
00081 
00082   for(int i = 0; i < size; i++) {
00083     double time_delta = (now-InfoArr[i].starttime);
00084 #define DO_FP_MODULUS(VAL,MAXVAL)  \
00085     {if(VAL > MAXVAL) {int idivresult = (int)(VAL / (float)MAXVAL);  VAL=VAL-idivresult*MAXVAL;} else  \
00086     if(VAL < -MAXVAL) {int idivresult = (int)(VAL / (float)MAXVAL);  VAL=VAL+idivresult*MAXVAL;}}
00087   
00088     // probably should use panda lerps for this stuff, but I dont understand how
00089 
00090     if(gridmotiontype==Rotation) {
00091 
00092       InfoArr[i].ang1=time_delta*InfoArr[i].ang1_vel;
00093       DO_FP_MODULUS(InfoArr[i].ang1,360.0);
00094       InfoArr[i].ang2=time_delta*InfoArr[i].ang2_vel;
00095       DO_FP_MODULUS(InfoArr[i].ang2,360.0);
00096 
00097       // xforms happen left to right
00098       LVector2f new_center = LVector2f(InfoArr[i].radius,0.0) *
00099         LMatrix3f::rotate_mat(InfoArr[i].ang1);
00100 
00101       LVector3f translate_vec(InfoArr[i].xcenter+new_center._v.v._0,
00102                               InfoArr[i].ycenter+new_center._v.v._1,
00103                               0.0);
00104 
00105       const LVector3f rotation_axis(0.0, 0.0, 1.0);
00106 
00107       tmat1 = LMatrix4f::rotate_mat_normaxis(InfoArr[i].ang2,rotation_axis);
00108       tmat2 = LMatrix4f::translate_mat(translate_vec);
00109       xfm_mat = tmat1 * tmat2;
00110     } else {
00111 
00112       float xpos,ypos;
00113 
00114       if(now>InfoArr[i].endtime) {
00115         InfoArr[i].starttime = now;
00116 
00117         xpos = InfoArr[i].xstart = InfoArr[i].xend;
00118         ypos = InfoArr[i].ystart = InfoArr[i].yend;
00119 
00120         InfoArr[i].xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
00121         InfoArr[i].yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
00122 
00123         float xdel = InfoArr[i].xdel = InfoArr[i].xend-InfoArr[i].xstart;
00124         float ydel = InfoArr[i].ydel = InfoArr[i].yend-InfoArr[i].ystart;
00125 
00126         InfoArr[i].endtime = now + csqrt(xdel*xdel+ydel*ydel)/InfoArr[i].vel;
00127         InfoArr[i].timedel = InfoArr[i].endtime - InfoArr[i].starttime;
00128 
00129         const LVector3f rotate_axis(0.0, 0.0, 1.0);
00130 
00131         float ang = rad_2_deg(atan2(-xdel,ydel));
00132 
00133         InfoArr[i].rotmat= LMatrix4f::rotate_mat_normaxis(ang,rotate_axis);
00134       } else {
00135         float timefrac= time_delta/InfoArr[i].timedel;
00136 
00137         xpos = InfoArr[i].xdel*timefrac+InfoArr[i].xstart;
00138         ypos = InfoArr[i].ydel*timefrac+InfoArr[i].ystart;
00139       }
00140 
00141       LVector3f translate_vec(xpos, ypos, 0.0);
00142       LMatrix4f tmat2 = LMatrix4f::translate_mat(translate_vec);
00143 
00144       xfm_mat = InfoArr[i].rotmat * tmat2;
00145     }
00146     InfoArr[i].node->set_transform(TransformState::make_mat(xfm_mat));
00147   }
00148 }
00149 
00150 bool
00151 get_command_line_opts(int &argc, char **&argv) {
00152   // Use getopt() to decode the optional command-line parameters.
00153   //  extern char *optarg;
00154   extern int optind;
00155   const char *options = "rm";
00156   int flag = getopt(argc, argv, options);
00157   while (flag != EOF) {
00158     switch (flag) {
00159     case 'r':
00160       gridmotiontype = Rotation;
00161       break;
00162 
00163     case 'm':
00164       gridmotiontype = LinearMotion;
00165       break;
00166 
00167     case '?':
00168       nout << "Invalid parameter.\n";
00169       return false;
00170     }
00171 
00172     flag = getopt(argc, argv, options);
00173   }
00174 
00175   argv += (optind - 1);
00176   argc -= (optind - 1);
00177 
00178   return true;
00179 }
00180 
00181 void
00182 get_command_line_filenames(int argc, char *argv[],
00183                            pvector<Filename> &static_filenames,
00184                            GriddedFilenames &gridded_filenames) {
00185   for (int i = 1; i < argc && argv[i] != (char *)NULL; i++) {
00186     const string &arg = argv[i];
00187     size_t comma = arg.find(',');
00188     if (comma == string::npos) {
00189       // No comma in the filename, so it must be an ordinary static file.
00190       static_filenames.push_back(Filename::from_os_specific(arg));
00191 
00192     } else {
00193       // A comma in the filename indicates a gridded file.  The syntax
00194       // is filename,count where count represents the number of times
00195       // the file is repeated.
00196       string name = arg.substr(0, comma);
00197       string count_str = arg.substr(comma + 1);
00198       int count;
00199       if (!string_to_int(count_str, count)) {
00200         nout << "Ignoring invalid number: " << count_str << "\n";
00201         count = 1;
00202       } else if (count <= 0) {
00203         nout << "Ignoring inappropriate number: " << count << "\n";
00204         count = 1;
00205       }
00206 
00207       GriddedFilename gf;
00208       gf._filename = Filename::from_os_specific(name);
00209       gf._count = count;
00210       gridded_filenames.push_back(gf);
00211     }
00212   }
00213 }
00214 
00215 void
00216 load_gridded_models(WindowFramework *window, 
00217                     GriddedFilenames &filenames,
00218                     GriddedInfoArray &info_arr) {
00219   // Load up all the files indicated in the list of gridded filenames
00220   // and store them in the given vector.
00221 
00222   // First, load up each model from disk once, and store them all
00223   // separate from the scene graph.  Also count up the total number of
00224   // models we'll be putting in the grid.
00225   int grid_count = 0;
00226   NodePath models("models");
00227   GriddedFilenames::iterator fi;
00228   for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
00229     GriddedFilename &gf = (*fi);
00230     gf._model = window->load_model(models, gf._filename);
00231     if (!gf._model.is_empty()) {
00232       grid_count += gf._count;
00233     }
00234   }
00235 
00236   info_arr.clear();
00237   info_arr.reserve(grid_count);
00238 
00239   // Compute the integer square root of grid_count, so that we put our
00240   // models in a nice square grid.
00241       
00242   gridwidth=1;
00243   while(gridwidth*gridwidth < grid_count) {
00244     gridwidth++;
00245   }
00246   
00247   grid_pos_offset = -gridwidth*GRIDCELLSIZE/2.0;
00248   wander_area_pos_offset = -max((float)fabs(grid_pos_offset), MIN_WANDERAREA_DIMENSION/2.0f);
00249 
00250   // Now walk through the list again, copying models into the scene
00251   // graph as we go.
00252   
00253   float xpos = grid_pos_offset;
00254   float ypos = grid_pos_offset;
00255       
00256   srand( (unsigned)time( NULL ) );
00257   double now = ClockObject::get_global_clock()->get_frame_time();
00258 
00259   int model_count = 0;
00260   int passnum = 0;
00261   bool loaded_any;
00262 
00263   NodePath render = window->get_render();
00264   do {
00265     loaded_any = false;
00266 
00267     for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
00268       const GriddedFilename &gf = (*fi);
00269       if (!gf._model.is_empty() && gf._count > passnum) {
00270         loaded_any = true;
00271         // Copy this model into the scene graph, and assign it a
00272         // position on the grid.
00273 
00274         string model_name = format_string(++model_count);
00275         NodePath model = render.attach_new_node(model_name);
00276         gf._model.copy_to(model);
00277 
00278         gridded_file_info info;
00279         info.node = model.node();
00280 
00281         LMatrix4f xfm_mat,tmat1,tmat2;
00282 
00283         if(gridmotiontype==Rotation) {
00284 
00285 #define MIN_REVOLUTION_ANGVEL 30
00286 #define MAX_REVOLUTION_ANGVEL 60
00287 
00288 #define MIN_ROTATION_ANGVEL 30
00289 #define MAX_ROTATION_ANGVEL 600
00290 
00291 #define MAX_RADIUS 4.0*GRIDCELLSIZE
00292 #define MIN_RADIUS 0.1*GRIDCELLSIZE
00293 
00294           info.starttime = now;
00295 
00296           info.xcenter=xpos;
00297           info.ycenter=ypos;
00298           info.ang1=RANDFRAC * 360.0;
00299           info.ang1_vel=((MAX_REVOLUTION_ANGVEL-MIN_REVOLUTION_ANGVEL) * RANDFRAC) + MIN_REVOLUTION_ANGVEL;
00300 
00301           info.ang2=RANDFRAC * 360.0;
00302           info.ang2_vel=((MAX_ROTATION_ANGVEL-MIN_ROTATION_ANGVEL) * RANDFRAC) + MIN_ROTATION_ANGVEL;
00303 
00304           info.radius = (RANDFRAC * (MAX_RADIUS-MIN_RADIUS)) + MIN_RADIUS;
00305 
00306           if(RANDFRAC>0.5) {
00307             info.ang1_vel=-info.ang1_vel;
00308           }
00309 
00310           if(RANDFRAC>0.5) {
00311             info.ang2_vel=-info.ang2_vel;
00312           }
00313 
00314           // xforms happen left to right
00315           LVector2f new_center = LVector2f(info.radius,0.0) *
00316             LMatrix3f::rotate_mat(info.ang1);
00317 
00318           const LVector3f rotate_axis(0.0, 0.0, 1.0);
00319 
00320           LVector3f translate_vec(xpos+new_center._v.v._0,
00321                                   ypos+new_center._v.v._1,
00322                                   0.0);
00323 
00324           tmat1.set_rotate_mat_normaxis(info.ang2,rotate_axis);
00325           tmat2 = LMatrix4f::translate_mat(translate_vec);
00326           xfm_mat = tmat1 * tmat2;
00327         } else if(gridmotiontype==LinearMotion) {
00328 
00329 #define MIN_VEL 2.0
00330 #define MAX_VEL (fabs(wander_area_pos_offset))
00331 
00332           info.vel=((MAX_VEL-MIN_VEL) * RANDFRAC) + MIN_VEL;
00333 
00334           info.xstart=xpos;
00335           info.ystart=ypos;
00336 
00337           info.xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
00338           info.yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
00339 
00340           info.starttime = now;
00341 
00342           float xdel = info.xdel = info.xend-info.xstart;
00343           float ydel = info.ydel = info.yend-info.ystart;
00344 
00345           info.endtime = csqrt(xdel*xdel+ydel*ydel)/info.vel;
00346 
00347           info.timedel = info.endtime - info.starttime;
00348 
00349           const LVector3f rotate_axis(0.0, 0.0, 1.0);
00350           float ang = rad_2_deg(atan2(-xdel,ydel));
00351 
00352           info.rotmat.set_rotate_mat_normaxis(ang,rotate_axis);
00353 
00354           LVector3f translate_vec(xpos, ypos, 0.0);
00355           LMatrix4f tmat2 = LMatrix4f::translate_mat(translate_vec);
00356 
00357           xfm_mat = info.rotmat * tmat2;
00358         } else {
00359           LVector3f translate_vec(xpos, ypos, 0.0);
00360           xfm_mat = LMatrix4f::translate_mat(translate_vec);
00361         }
00362 
00363         info.node->set_transform(TransformState::make_mat(xfm_mat));
00364 
00365         info_arr.push_back(info);
00366 
00367         if((model_count % gridwidth) == 0) {
00368           xpos= -gridwidth*GRIDCELLSIZE/2.0;
00369           ypos+=GRIDCELLSIZE;
00370         } else {
00371           xpos+=GRIDCELLSIZE;
00372         }
00373       }
00374     }
00375 
00376     passnum++;
00377   } while (loaded_any);
00378 
00379   // Finally, remove the source models we loaded up.  Not a real big deal.
00380   for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
00381     GriddedFilename &gf = (*fi);
00382     if (!gf._model.is_empty()) {
00383       gf._model.remove_node();
00384     }
00385   }
00386 }
00387 
00388 int
00389 main(int argc, char *argv[]) {
00390   PandaFramework framework;
00391   vector_string args;
00392   framework.open_framework(argc, argv);
00393   framework.set_window_title("Gridded Object Viewer");
00394 
00395   if (!get_command_line_opts(argc, argv)) {
00396     return (1);
00397   }
00398 
00399   // Extract the remaining arguments into two lists of files: those
00400   // with a grid parameter, and those without.
00401   pvector<Filename> static_filenames;
00402   GriddedFilenames gridded_filenames;
00403   get_command_line_filenames(argc, argv, static_filenames, gridded_filenames);
00404 
00405   WindowFramework *window = framework.open_window();
00406   if (window != (WindowFramework *)NULL) {
00407     // We've successfully opened a window.
00408 
00409     window->enable_keyboard();
00410     window->setup_trackball();
00411     window->load_models(window->get_render(), static_filenames);
00412 
00413     GriddedInfoArray info_arr;
00414     load_gridded_models(window, gridded_filenames, info_arr);
00415 
00416     window->loop_animations();
00417     window->stagger_animations();
00418 
00419     framework.enable_default_keys();
00420 
00421     Thread *current_thread = Thread::get_current_thread();
00422     while (framework.do_frame(current_thread)) {
00423       if (!info_arr.empty() && gridmotiontype) {
00424         move_gridded_stuff(gridmotiontype, &info_arr[0], info_arr.size());
00425       }
00426     }
00427   }
00428 
00429   framework.report_frame_rate(nout);
00430   return (0);
00431 }
 All Classes Functions Variables Enumerations