Panda3D
Loading...
Searching...
No Matches
pgrid.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file pgrid.cxx
10 * @author drose
11 * @date 2002-04-03
12 */
13
14#include "pandaFramework.h"
15#include "pandaNode.h"
16#include "transformState.h"
17#include "clockObject.h"
18#include "string_utils.h"
19#include "pvector.h"
20#include "panda_getopt.h"
21#include "preprocess_argv.h"
22
23#define RANDFRAC (rand()/(PN_stdfloat)(RAND_MAX))
24
25using std::string;
26
27class GriddedFilename {
28public:
29 Filename _filename;
30 int _count;
31 NodePath _model;
32};
34
35typedef struct {
36 // for rot moving
37 PN_stdfloat xcenter,ycenter;
38 PN_stdfloat xoffset,yoffset;
39 PN_stdfloat ang1,ang1_vel;
40 PN_stdfloat ang2,ang2_vel;
41
42 PN_stdfloat radius;
43
44 // for moving
45 PN_stdfloat xstart,ystart;
46 PN_stdfloat xend,yend;
47 PN_stdfloat xdel,ydel,timedel;
48 double starttime,endtime;
49 double vel;
50 LMatrix4 rotmat;
51
52 PandaNode *node;
53} gridded_file_info;
54
56
57typedef enum {None,Rotation,LinearMotion} GriddedMotionType;
58
59#define GRIDCELLSIZE 5.0
60static int gridwidth; // cells/side
61
62#define MIN_WANDERAREA_DIMENSION 120.0f
63
64static PN_stdfloat grid_pos_offset; // origin of grid
65static PN_stdfloat wander_area_pos_offset;
66
67static GriddedMotionType gridmotiontype = None;
68
69
70// making these fns to get around ridiculous VC++ matrix inlining bugs at Opt2
71static void
72move_gridded_stuff(GriddedMotionType gridmotiontype,
73 gridded_file_info *InfoArr, int size) {
75
76 LMatrix4 tmat1,tmat2,xfm_mat;
77
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;}}
83
84 // probably should use panda lerps for this stuff, but I don't understand
85 // how
86
87 if(gridmotiontype==Rotation) {
88
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);
93
94 // xforms happen left to right
95 LVector2 new_center = LVector2(InfoArr[i].radius,0.0) *
96 LMatrix3::rotate_mat(InfoArr[i].ang1);
97
98 LVector3 translate_vec(InfoArr[i].xcenter+new_center._v.v._0,
99 InfoArr[i].ycenter+new_center._v.v._1,
100 0.0);
101
102 const LVector3 rotation_axis(0.0, 0.0, 1.0);
103
104 tmat1 = LMatrix4::rotate_mat_normaxis(InfoArr[i].ang2,rotation_axis);
105 tmat2 = LMatrix4::translate_mat(translate_vec);
106 xfm_mat = tmat1 * tmat2;
107 } else {
108
109 PN_stdfloat xpos,ypos;
110
111 if(now>InfoArr[i].endtime) {
112 InfoArr[i].starttime = now;
113
114 xpos = InfoArr[i].xstart = InfoArr[i].xend;
115 ypos = InfoArr[i].ystart = InfoArr[i].yend;
116
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;
119
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;
122
123 InfoArr[i].endtime = now + csqrt(xdel*xdel+ydel*ydel)/InfoArr[i].vel;
124 InfoArr[i].timedel = InfoArr[i].endtime - InfoArr[i].starttime;
125
126 const LVector3 rotate_axis(0.0, 0.0, 1.0);
127
128 PN_stdfloat ang = rad_2_deg(atan2(-xdel,ydel));
129
130 InfoArr[i].rotmat= LMatrix4::rotate_mat_normaxis(ang,rotate_axis);
131 } else {
132 PN_stdfloat timefrac= time_delta/InfoArr[i].timedel;
133
134 xpos = InfoArr[i].xdel*timefrac+InfoArr[i].xstart;
135 ypos = InfoArr[i].ydel*timefrac+InfoArr[i].ystart;
136 }
137
138 LVector3 translate_vec(xpos, ypos, 0.0);
139 LMatrix4 tmat2 = LMatrix4::translate_mat(translate_vec);
140
141 xfm_mat = InfoArr[i].rotmat * tmat2;
142 }
143 InfoArr[i].node->set_transform(TransformState::make_mat(xfm_mat));
144 }
145}
146
147bool
148get_command_line_opts(int &argc, char **&argv) {
149 // Use getopt() to decode the optional command-line parameters. extern char
150 // *optarg;
151 extern int optind;
152 const char *options = "rm";
153 int flag = getopt(argc, argv, options);
154 while (flag != EOF) {
155 switch (flag) {
156 case 'r':
157 gridmotiontype = Rotation;
158 break;
159
160 case 'm':
161 gridmotiontype = LinearMotion;
162 break;
163
164 case '?':
165 nout << "Invalid parameter.\n";
166 return false;
167 }
168
169 flag = getopt(argc, argv, options);
170 }
171
172 argv += (optind - 1);
173 argc -= (optind - 1);
174
175 return true;
176}
177
178void
179get_command_line_filenames(int argc, char *argv[],
180 pvector<Filename> &static_filenames,
181 GriddedFilenames &gridded_filenames) {
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) {
186 // No comma in the filename, so it must be an ordinary static file.
187 static_filenames.push_back(Filename::from_os_specific(arg));
188
189 } else {
190 // A comma in the filename indicates a gridded file. The syntax is
191 // filename,count where count represents the number of times the file is
192 // repeated.
193 string name = arg.substr(0, comma);
194 string count_str = arg.substr(comma + 1);
195 int count;
196 if (!string_to_int(count_str, count)) {
197 nout << "Ignoring invalid number: " << count_str << "\n";
198 count = 1;
199 } else if (count <= 0) {
200 nout << "Ignoring inappropriate number: " << count << "\n";
201 count = 1;
202 }
203
204 GriddedFilename gf;
205 gf._filename = Filename::from_os_specific(name);
206 gf._count = count;
207 gridded_filenames.push_back(gf);
208 }
209 }
210}
211
212void
213load_gridded_models(WindowFramework *window,
214 GriddedFilenames &filenames,
215 GriddedInfoArray &info_arr) {
216 // Load up all the files indicated in the list of gridded filenames and
217 // store them in the given vector.
218
219 Loader loader;
220 LoaderOptions options;
221 // options.set_flags(options.get_flags() | LoaderOptions::LF_no_ram_cache);
222
223 // First, load up each model from disk once, and store them all separate
224 // from the scene graph. Also count up the total number of models we'll be
225 // putting in the grid.
226 int grid_count = 0;
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) {
232 gf._model = NodePath(node);
233 grid_count += gf._count;
234 }
235 }
236
237 info_arr.clear();
238 info_arr.reserve(grid_count);
239
240 // Compute the integer square root of grid_count, so that we put our models
241 // in a nice square grid.
242
243 gridwidth=1;
244 while(gridwidth*gridwidth < grid_count) {
245 gridwidth++;
246 }
247
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);
250
251 // Now walk through the list again, copying models into the scene graph as
252 // we go.
253
254 PN_stdfloat xpos = grid_pos_offset;
255 PN_stdfloat ypos = grid_pos_offset;
256
257 srand( (unsigned)time( nullptr ) );
259
260 int model_count = 0;
261 int passnum = 0;
262 bool loaded_any;
263
264 NodePath root = window->get_panda_framework()->get_models();
265 do {
266 loaded_any = false;
267
268 for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
269 const GriddedFilename &gf = (*fi);
270 if (!gf._model.is_empty() && gf._count > passnum) {
271 loaded_any = true;
272 // Copy this model into the scene graph, and assign it a position on
273 // the grid.
274
275 ++model_count;
276 PT(PandaNode) node = loader.load_sync(gf._filename, options);
277 NodePath model;
278 if (node == nullptr) {
279 model = gf._model.copy_to(NodePath());
280 } else {
281 model = NodePath(node);
282 }
283 model.reparent_to(root);
284
285 gridded_file_info info;
286 info.node = model.node();
287
288 LMatrix4 xfm_mat,tmat1,tmat2;
289
290 if(gridmotiontype==Rotation) {
291
292#define MIN_REVOLUTION_ANGVEL 30
293#define MAX_REVOLUTION_ANGVEL 60
294
295#define MIN_ROTATION_ANGVEL 30
296#define MAX_ROTATION_ANGVEL 600
297
298#define MAX_RADIUS 4.0*GRIDCELLSIZE
299#define MIN_RADIUS 0.1*GRIDCELLSIZE
300
301 info.starttime = now;
302
303 info.xcenter=xpos;
304 info.ycenter=ypos;
305 info.ang1=RANDFRAC * 360.0;
306 info.ang1_vel=((MAX_REVOLUTION_ANGVEL-MIN_REVOLUTION_ANGVEL) * RANDFRAC) + MIN_REVOLUTION_ANGVEL;
307
308 info.ang2=RANDFRAC * 360.0;
309 info.ang2_vel=((MAX_ROTATION_ANGVEL-MIN_ROTATION_ANGVEL) * RANDFRAC) + MIN_ROTATION_ANGVEL;
310
311 info.radius = (RANDFRAC * (MAX_RADIUS-MIN_RADIUS)) + MIN_RADIUS;
312
313 if(RANDFRAC>0.5) {
314 info.ang1_vel=-info.ang1_vel;
315 }
316
317 if(RANDFRAC>0.5) {
318 info.ang2_vel=-info.ang2_vel;
319 }
320
321 // xforms happen left to right
322 LVector2 new_center = LVector2(info.radius,0.0) *
323 LMatrix3::rotate_mat(info.ang1);
324
325 const LVector3 rotate_axis(0.0, 0.0, 1.0);
326
327 LVector3 translate_vec(xpos+new_center._v.v._0,
328 ypos+new_center._v.v._1,
329 0.0);
330
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) {
335
336#define MIN_VEL 2.0
337#define MAX_VEL (fabs(wander_area_pos_offset))
338
339 info.vel=((MAX_VEL-MIN_VEL) * RANDFRAC) + MIN_VEL;
340
341 info.xstart=xpos;
342 info.ystart=ypos;
343
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;
346
347 info.starttime = now;
348
349 PN_stdfloat xdel = info.xdel = info.xend-info.xstart;
350 PN_stdfloat ydel = info.ydel = info.yend-info.ystart;
351
352 info.endtime = csqrt(xdel*xdel+ydel*ydel)/info.vel;
353
354 info.timedel = info.endtime - info.starttime;
355
356 const LVector3 rotate_axis(0.0, 0.0, 1.0);
357 PN_stdfloat ang = rad_2_deg(atan2(-xdel,ydel));
358
359 info.rotmat.set_rotate_mat_normaxis(ang,rotate_axis);
360
361 LVector3 translate_vec(xpos, ypos, 0.0);
362 LMatrix4 tmat2 = LMatrix4::translate_mat(translate_vec);
363
364 xfm_mat = info.rotmat * tmat2;
365 } else {
366 LVector3 translate_vec(xpos, ypos, 0.0);
367 xfm_mat = LMatrix4::translate_mat(translate_vec);
368 }
369
370 info.node->set_transform(TransformState::make_mat(xfm_mat));
371
372 info_arr.push_back(info);
373
374 if((model_count % gridwidth) == 0) {
375 xpos= -gridwidth*GRIDCELLSIZE/2.0;
376 ypos+=GRIDCELLSIZE;
377 } else {
378 xpos+=GRIDCELLSIZE;
379 }
380 }
381 }
382
383 passnum++;
384 } while (loaded_any);
385}
386
387int
388main(int argc, char **argv) {
389 preprocess_argv(argc, argv);
390 PandaFramework framework;
391 framework.open_framework(argc, argv);
392 framework.set_window_title("Gridded Object Viewer");
393
394 if (!get_command_line_opts(argc, argv)) {
395 return (1);
396 }
397
398 // Extract the remaining arguments into two lists of files: those with a
399 // grid parameter, and those without.
400 pvector<Filename> static_filenames;
401 GriddedFilenames gridded_filenames;
402 get_command_line_filenames(argc, argv, static_filenames, gridded_filenames);
403
404 WindowFramework *window = framework.open_window();
405 if (window != nullptr) {
406 // We've successfully opened a window.
407
408 window->enable_keyboard();
409 window->setup_trackball();
410 window->load_models(framework.get_models(), static_filenames);
411 framework.get_models().instance_to(window->get_render());
412
413 GriddedInfoArray info_arr;
414 load_gridded_models(window, gridded_filenames, info_arr);
415
416 window->loop_animations();
417 window->stagger_animations();
418 window->center_trackball(framework.get_models());
419
420 framework.enable_default_keys();
421
422 Thread *current_thread = Thread::get_current_thread();
423 while (framework.do_frame(current_thread)) {
424 if (!info_arr.empty() && gridmotiontype) {
425 move_gridded_stuff(gridmotiontype, &info_arr[0], info_arr.size());
426 }
427 }
428 }
429
430 framework.report_frame_rate(nout);
431 return (0);
432}
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition clockObject.h:91
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.
Definition filename.h:44
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,...
Definition filename.cxx:328
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...
Definition loader.h:42
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
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...
Definition nodePath.cxx:538
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition nodePath.I:188
PandaNode * node() const
Returns the referenced node of the path.
Definition nodePath.I:227
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...
Definition nodePath.cxx:394
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...
Definition nodePath.cxx:474
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.
Definition pandaNode.h:65
set_transform
Sets the transform that will be applied to this node and below.
Definition pandaNode.h:183
A thread; that is, a lightweight process.
Definition thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
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.
Definition pvector.h:42
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.