23 #define RANDFRAC (rand()/(PN_stdfloat)(RAND_MAX))
27 class GriddedFilename {
37 PN_stdfloat xcenter,ycenter;
38 PN_stdfloat xoffset,yoffset;
39 PN_stdfloat ang1,ang1_vel;
40 PN_stdfloat ang2,ang2_vel;
45 PN_stdfloat xstart,ystart;
46 PN_stdfloat xend,yend;
47 PN_stdfloat xdel,ydel,timedel;
48 double starttime,endtime;
57 typedef enum {None,Rotation,LinearMotion} GriddedMotionType;
59 #define GRIDCELLSIZE 5.0
62 #define MIN_WANDERAREA_DIMENSION 120.0f
64 static PN_stdfloat grid_pos_offset;
65 static PN_stdfloat wander_area_pos_offset;
67 static GriddedMotionType gridmotiontype = None;
72 move_gridded_stuff(GriddedMotionType gridmotiontype,
73 gridded_file_info *InfoArr,
int size) {
76 LMatrix4 tmat1,tmat2,xfm_mat;
78 for(
int i = 0; i < size; i++) {
79 double time_delta = (now-InfoArr[i].starttime);
80 #define DO_FP_MODULUS(VAL,MAXVAL) \
81 {if(VAL > MAXVAL) {int idivresult = (int)(VAL / (PN_stdfloat)MAXVAL); VAL=VAL-idivresult*MAXVAL;} else \
82 if(VAL < -MAXVAL) {int idivresult = (int)(VAL / (PN_stdfloat)MAXVAL); VAL=VAL+idivresult*MAXVAL;}}
87 if(gridmotiontype==Rotation) {
89 InfoArr[i].ang1=time_delta*InfoArr[i].ang1_vel;
90 DO_FP_MODULUS(InfoArr[i].ang1,360.0);
91 InfoArr[i].ang2=time_delta*InfoArr[i].ang2_vel;
92 DO_FP_MODULUS(InfoArr[i].ang2,360.0);
95 LVector2 new_center = LVector2(InfoArr[i].radius,0.0) *
96 LMatrix3::rotate_mat(InfoArr[i].ang1);
98 LVector3 translate_vec(InfoArr[i].xcenter+new_center._v.v._0,
99 InfoArr[i].ycenter+new_center._v.v._1,
102 const LVector3 rotation_axis(0.0, 0.0, 1.0);
104 tmat1 = LMatrix4::rotate_mat_normaxis(InfoArr[i].ang2,rotation_axis);
105 tmat2 = LMatrix4::translate_mat(translate_vec);
106 xfm_mat = tmat1 * tmat2;
109 PN_stdfloat xpos,ypos;
111 if(now>InfoArr[i].endtime) {
112 InfoArr[i].starttime = now;
114 xpos = InfoArr[i].xstart = InfoArr[i].xend;
115 ypos = InfoArr[i].ystart = InfoArr[i].yend;
117 InfoArr[i].xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
118 InfoArr[i].yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
120 PN_stdfloat xdel = InfoArr[i].xdel = InfoArr[i].xend-InfoArr[i].xstart;
121 PN_stdfloat ydel = InfoArr[i].ydel = InfoArr[i].yend-InfoArr[i].ystart;
123 InfoArr[i].endtime = now + csqrt(xdel*xdel+ydel*ydel)/InfoArr[i].vel;
124 InfoArr[i].timedel = InfoArr[i].endtime - InfoArr[i].starttime;
126 const LVector3 rotate_axis(0.0, 0.0, 1.0);
128 PN_stdfloat ang = rad_2_deg(atan2(-xdel,ydel));
130 InfoArr[i].rotmat= LMatrix4::rotate_mat_normaxis(ang,rotate_axis);
132 PN_stdfloat timefrac= time_delta/InfoArr[i].timedel;
134 xpos = InfoArr[i].xdel*timefrac+InfoArr[i].xstart;
135 ypos = InfoArr[i].ydel*timefrac+InfoArr[i].ystart;
138 LVector3 translate_vec(xpos, ypos, 0.0);
139 LMatrix4 tmat2 = LMatrix4::translate_mat(translate_vec);
141 xfm_mat = InfoArr[i].rotmat * tmat2;
143 InfoArr[i].node->set_transform(TransformState::make_mat(xfm_mat));
148 get_command_line_opts(
int &argc,
char **&argv) {
152 const char *options =
"rm";
153 int flag = getopt(argc, argv, options);
154 while (flag != EOF) {
157 gridmotiontype = Rotation;
161 gridmotiontype = LinearMotion;
165 nout <<
"Invalid parameter.\n";
169 flag = getopt(argc, argv, options);
172 argv += (optind - 1);
173 argc -= (optind - 1);
179 get_command_line_filenames(
int argc,
char *argv[],
182 for (
int i = 1; i < argc && argv[i] !=
nullptr; i++) {
183 const string &arg = argv[i];
184 size_t comma = arg.find(
',');
185 if (comma == string::npos) {
193 string name = arg.substr(0, comma);
194 string count_str = arg.substr(comma + 1);
197 nout <<
"Ignoring invalid number: " << count_str <<
"\n";
199 }
else if (count <= 0) {
200 nout <<
"Ignoring inappropriate number: " << count <<
"\n";
207 gridded_filenames.push_back(gf);
227 GriddedFilenames::iterator fi;
228 for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
229 GriddedFilename &gf = (*fi);
230 PT(
PandaNode) node = loader.load_sync(gf._filename, options);
231 if (node !=
nullptr) {
233 grid_count += gf._count;
238 info_arr.reserve(grid_count);
244 while(gridwidth*gridwidth < grid_count) {
248 grid_pos_offset = -gridwidth*GRIDCELLSIZE/2.0;
249 wander_area_pos_offset = -std::max((PN_stdfloat)fabs(grid_pos_offset), MIN_WANDERAREA_DIMENSION/2.0f);
254 PN_stdfloat xpos = grid_pos_offset;
255 PN_stdfloat ypos = grid_pos_offset;
257 srand( (
unsigned)time(
nullptr ) );
268 for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
269 const GriddedFilename &gf = (*fi);
270 if (!gf._model.is_empty() && gf._count > passnum) {
276 PT(
PandaNode) node = loader.load_sync(gf._filename, options);
278 if (node ==
nullptr) {
279 model = gf._model.copy_to(
NodePath());
285 gridded_file_info info;
286 info.node = model.
node();
288 LMatrix4 xfm_mat,tmat1,tmat2;
290 if(gridmotiontype==Rotation) {
292 #define MIN_REVOLUTION_ANGVEL 30
293 #define MAX_REVOLUTION_ANGVEL 60
295 #define MIN_ROTATION_ANGVEL 30
296 #define MAX_ROTATION_ANGVEL 600
298 #define MAX_RADIUS 4.0*GRIDCELLSIZE
299 #define MIN_RADIUS 0.1*GRIDCELLSIZE
301 info.starttime = now;
305 info.ang1=RANDFRAC * 360.0;
306 info.ang1_vel=((MAX_REVOLUTION_ANGVEL-MIN_REVOLUTION_ANGVEL) * RANDFRAC) + MIN_REVOLUTION_ANGVEL;
308 info.ang2=RANDFRAC * 360.0;
309 info.ang2_vel=((MAX_ROTATION_ANGVEL-MIN_ROTATION_ANGVEL) * RANDFRAC) + MIN_ROTATION_ANGVEL;
311 info.radius = (RANDFRAC * (MAX_RADIUS-MIN_RADIUS)) + MIN_RADIUS;
314 info.ang1_vel=-info.ang1_vel;
318 info.ang2_vel=-info.ang2_vel;
322 LVector2 new_center = LVector2(info.radius,0.0) *
323 LMatrix3::rotate_mat(info.ang1);
325 const LVector3 rotate_axis(0.0, 0.0, 1.0);
327 LVector3 translate_vec(xpos+new_center._v.v._0,
328 ypos+new_center._v.v._1,
331 tmat1.set_rotate_mat_normaxis(info.ang2,rotate_axis);
332 tmat2 = LMatrix4::translate_mat(translate_vec);
333 xfm_mat = tmat1 * tmat2;
334 }
else if(gridmotiontype==LinearMotion) {
337 #define MAX_VEL (fabs(wander_area_pos_offset))
339 info.vel=((MAX_VEL-MIN_VEL) * RANDFRAC) + MIN_VEL;
344 info.xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
345 info.yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset;
347 info.starttime = now;
349 PN_stdfloat xdel = info.xdel = info.xend-info.xstart;
350 PN_stdfloat ydel = info.ydel = info.yend-info.ystart;
352 info.endtime = csqrt(xdel*xdel+ydel*ydel)/info.vel;
354 info.timedel = info.endtime - info.starttime;
356 const LVector3 rotate_axis(0.0, 0.0, 1.0);
357 PN_stdfloat ang = rad_2_deg(atan2(-xdel,ydel));
359 info.rotmat.set_rotate_mat_normaxis(ang,rotate_axis);
361 LVector3 translate_vec(xpos, ypos, 0.0);
362 LMatrix4 tmat2 = LMatrix4::translate_mat(translate_vec);
364 xfm_mat = info.rotmat * tmat2;
366 LVector3 translate_vec(xpos, ypos, 0.0);
367 xfm_mat = LMatrix4::translate_mat(translate_vec);
370 info.node->set_transform(TransformState::make_mat(xfm_mat));
372 info_arr.push_back(info);
374 if((model_count % gridwidth) == 0) {
375 xpos= -gridwidth*GRIDCELLSIZE/2.0;
384 }
while (loaded_any);
388 main(
int argc,
char **argv) {
394 if (!get_command_line_opts(argc, argv)) {
402 get_command_line_filenames(argc, argv, static_filenames, gridded_filenames);
405 if (window !=
nullptr) {
414 load_gridded_models(window, gridded_filenames, info_arr);
423 while (framework.
do_frame(current_thread)) {
424 if (!info_arr.empty() && gridmotiontype) {
425 move_gridded_stuff(gridmotiontype, &info_arr[0], info_arr.size());