23#define RANDFRAC (rand()/(PN_stdfloat)(RAND_MAX))
27class 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;
57typedef enum {None,Rotation,LinearMotion} GriddedMotionType;
59#define GRIDCELLSIZE 5.0
62#define MIN_WANDERAREA_DIMENSION 120.0f
64static PN_stdfloat grid_pos_offset;
65static PN_stdfloat wander_area_pos_offset;
67static GriddedMotionType gridmotiontype = None;
72move_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));
148get_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);
179get_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) {
187 static_filenames.push_back(Filename::from_os_specific(arg));
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) {
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);
388main(
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());
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
The name of a file, such as a texture file or an Egg file.
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,...
Specifies parameters that may be passed to the loader.
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
NodePath copy_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Functions like instance_to(), except a deep copy is made of the referenced node and all of its descen...
bool is_empty() const
Returns true if the NodePath contains no nodes.
PandaNode * node() const
Returns the referenced node of the path.
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...
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...
This class serves to provide a high-level framework for basic applications that use Panda in simple w...
WindowFramework * open_window()
Opens a window on the default graphics pipe.
void enable_default_keys()
Sets callbacks on the event handler to handle all of the normal viewer keys, like t to toggle texture...
void open_framework()
Should be called once at the beginning of the application to initialize Panda (and the framework) for...
void report_frame_rate(std::ostream &out) const
Reports the currently measured average frame rate to the indicated ostream.
void set_window_title(const std::string &title)
Specifies the title that is set for all subsequently created windows.
NodePath & get_models()
Returns the root of the scene graph normally reserved for parenting models and such.
virtual bool do_frame(Thread *current_thread)
Renders one frame and performs all associated processing.
A basic node of the scene graph or data graph.
set_transform
Sets the transform that will be applied to this node and below.
A thread; that is, a lightweight process.
get_current_thread
Returns a pointer to the currently-executing Thread object.
This encapsulates the data that is normally associated with a single window, or with a single display...
void setup_trackball()
Sets up the mouse to trackball around the camera.
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...
void enable_keyboard()
Creates a ButtonThrower to listen to button presses and throw them as events.
NodePath get_render()
Returns the root of the 3-d scene graph.
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.
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.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int string_to_int(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.