Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/testbed/pgrid.cxx

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

Generated on Fri May 2 00:44:10 2003 for Panda by doxygen1.3