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());
int string_to_int(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
void report_frame_rate(std::ostream &out) const
Reports the currently measured average frame rate to the indicated ostream.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A basic node of the scene graph or data graph.
void stagger_animations()
Walks through all the animations that were bound by loop_animations() and staggers their play rate sl...
void loop_animations(int hierarchy_match_flags=PartGroup::HMF_ok_part_extra|PartGroup::HMF_ok_anim_extra)
Looks for characters and their matching animation files in the scene graph; binds and loops any match...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void enable_default_keys()
Sets callbacks on the event handler to handle all of the normal viewer keys, like t to toggle texture...
NodePath & get_models()
Returns the root of the scene graph normally reserved for parenting models and such.
NodePath get_render()
Returns the root of the 3-d scene graph.
Specifies parameters that may be passed to the loader.
This encapsulates the data that is normally associated with a single window, or with a single display...
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
void open_framework()
Should be called once at the beginning of the application to initialize Panda (and the framework) for...
NodePath instance_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Adds the referenced node of the NodePath as a child of the referenced node of the indicated other Nod...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void reparent_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread())
Removes the referenced node of the NodePath from its current parent and attaches it to the referenced...
get_current_thread
Returns a pointer to the currently-executing Thread object.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
The name of a file, such as a texture file or an Egg file.
void center_trackball(const NodePath &object)
Centers the trackball on the indicated object, and scales the trackball motion suitably.
PandaFramework * get_panda_framework() const
Returns a pointer to the associated PandaFramework object.
void enable_keyboard()
Creates a ButtonThrower to listen to button presses and throw them as events.
WindowFramework * open_window()
Opens a window on the default graphics pipe.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void preprocess_argv(int &argc, char **&argv)
Processes the argc, argv pair as needed before passing it to getopt().
PandaNode * node() const
Returns the referenced node of the path.
A thread; that is, a lightweight process.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool load_models(const NodePath &parent, int argc, char *argv[], int first_arg=1)
Loads up all the model files listed in the indicated argument list.
void set_window_title(const std::string &title)
Specifies the title that is set for all subsequently created windows.
This class serves to provide a high-level framework for basic applications that use Panda in simple w...
void setup_trackball()
Sets up the mouse to trackball around the camera.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
virtual bool do_frame(Thread *current_thread)
Renders one frame and performs all associated processing.