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