00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
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
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;
00060
00061 #define MIN_WANDERAREA_DIMENSION 120.0f
00062
00063 static PN_stdfloat grid_pos_offset;
00064 static PN_stdfloat wander_area_pos_offset;
00065
00066 static GriddedMotionType gridmotiontype = None;
00067
00068
00069
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
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
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
00148
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
00185 static_filenames.push_back(Filename::from_os_specific(arg));
00186
00187 } else {
00188
00189
00190
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
00215
00216
00217 Loader loader;
00218 LoaderOptions options;
00219
00220
00221
00222
00223
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
00239
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
00250
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
00271
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
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
00397
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
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 }