00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00045 float xcenter,ycenter;
00046 float xoffset,yoffset;
00047 float ang1,ang1_vel;
00048 float ang2,ang2_vel;
00049
00050 float radius;
00051
00052
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;
00069
00070 #define MIN_WANDERAREA_DIMENSION 120.0f
00071
00072 static float grid_pos_offset;
00073 static float wander_area_pos_offset;
00074
00075 static GriddedMotionType gridmotiontype = None;
00076
00077
00078
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
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
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
00157
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
00194 static_filenames.push_back(Filename::from_os_specific(arg));
00195
00196 } else {
00197
00198
00199
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
00224
00225
00226
00227
00228
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
00244
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
00255
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
00276
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
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
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
00404
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
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 }