Panda3D
|
00001 // Filename: pgrid.cxx 00002 // Created by: drose (03Apr02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pandaFramework.h" 00016 #include "pandaNode.h" 00017 #include "transformState.h" 00018 #include "clockObject.h" 00019 #include "string_utils.h" 00020 #include "pvector.h" 00021 #include "panda_getopt.h" 00022 #include "preprocess_argv.h" 00023 00024 #define RANDFRAC (rand()/(PN_stdfloat)(RAND_MAX)) 00025 00026 class GriddedFilename { 00027 public: 00028 Filename _filename; 00029 int _count; 00030 NodePath _model; 00031 }; 00032 typedef pvector<GriddedFilename> GriddedFilenames; 00033 00034 typedef struct { 00035 // for rot moving 00036 PN_stdfloat xcenter,ycenter; 00037 PN_stdfloat xoffset,yoffset; 00038 PN_stdfloat ang1,ang1_vel; 00039 PN_stdfloat ang2,ang2_vel; 00040 00041 PN_stdfloat radius; 00042 00043 // for moving 00044 PN_stdfloat xstart,ystart; 00045 PN_stdfloat xend,yend; 00046 PN_stdfloat xdel,ydel,timedel; 00047 double starttime,endtime; 00048 double vel; 00049 LMatrix4 rotmat; 00050 00051 PandaNode *node; 00052 } gridded_file_info; 00053 00054 typedef pvector<gridded_file_info> GriddedInfoArray; 00055 00056 typedef enum {None,Rotation,LinearMotion} GriddedMotionType; 00057 00058 #define GRIDCELLSIZE 5.0 00059 static int gridwidth; // cells/side 00060 00061 #define MIN_WANDERAREA_DIMENSION 120.0f 00062 00063 static PN_stdfloat grid_pos_offset; // origin of grid 00064 static PN_stdfloat wander_area_pos_offset; 00065 00066 static GriddedMotionType gridmotiontype = None; 00067 00068 00069 // making these fns to get around ridiculous VC++ matrix inlining bugs at Opt2 00070 static void 00071 move_gridded_stuff(GriddedMotionType gridmotiontype, 00072 gridded_file_info *InfoArr, int size) { 00073 double now = ClockObject::get_global_clock()->get_frame_time(); 00074 00075 LMatrix4 tmat1,tmat2,xfm_mat; 00076 00077 for(int i = 0; i < size; i++) { 00078 double time_delta = (now-InfoArr[i].starttime); 00079 #define DO_FP_MODULUS(VAL,MAXVAL) \ 00080 {if(VAL > MAXVAL) {int idivresult = (int)(VAL / (PN_stdfloat)MAXVAL); VAL=VAL-idivresult*MAXVAL;} else \ 00081 if(VAL < -MAXVAL) {int idivresult = (int)(VAL / (PN_stdfloat)MAXVAL); VAL=VAL+idivresult*MAXVAL;}} 00082 00083 // probably should use panda lerps for this stuff, but I don't understand how 00084 00085 if(gridmotiontype==Rotation) { 00086 00087 InfoArr[i].ang1=time_delta*InfoArr[i].ang1_vel; 00088 DO_FP_MODULUS(InfoArr[i].ang1,360.0); 00089 InfoArr[i].ang2=time_delta*InfoArr[i].ang2_vel; 00090 DO_FP_MODULUS(InfoArr[i].ang2,360.0); 00091 00092 // xforms happen left to right 00093 LVector2 new_center = LVector2(InfoArr[i].radius,0.0) * 00094 LMatrix3::rotate_mat(InfoArr[i].ang1); 00095 00096 LVector3 translate_vec(InfoArr[i].xcenter+new_center._v.v._0, 00097 InfoArr[i].ycenter+new_center._v.v._1, 00098 0.0); 00099 00100 const LVector3 rotation_axis(0.0, 0.0, 1.0); 00101 00102 tmat1 = LMatrix4::rotate_mat_normaxis(InfoArr[i].ang2,rotation_axis); 00103 tmat2 = LMatrix4::translate_mat(translate_vec); 00104 xfm_mat = tmat1 * tmat2; 00105 } else { 00106 00107 PN_stdfloat xpos,ypos; 00108 00109 if(now>InfoArr[i].endtime) { 00110 InfoArr[i].starttime = now; 00111 00112 xpos = InfoArr[i].xstart = InfoArr[i].xend; 00113 ypos = InfoArr[i].ystart = InfoArr[i].yend; 00114 00115 InfoArr[i].xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset; 00116 InfoArr[i].yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset; 00117 00118 PN_stdfloat xdel = InfoArr[i].xdel = InfoArr[i].xend-InfoArr[i].xstart; 00119 PN_stdfloat ydel = InfoArr[i].ydel = InfoArr[i].yend-InfoArr[i].ystart; 00120 00121 InfoArr[i].endtime = now + csqrt(xdel*xdel+ydel*ydel)/InfoArr[i].vel; 00122 InfoArr[i].timedel = InfoArr[i].endtime - InfoArr[i].starttime; 00123 00124 const LVector3 rotate_axis(0.0, 0.0, 1.0); 00125 00126 PN_stdfloat ang = rad_2_deg(atan2(-xdel,ydel)); 00127 00128 InfoArr[i].rotmat= LMatrix4::rotate_mat_normaxis(ang,rotate_axis); 00129 } else { 00130 PN_stdfloat timefrac= time_delta/InfoArr[i].timedel; 00131 00132 xpos = InfoArr[i].xdel*timefrac+InfoArr[i].xstart; 00133 ypos = InfoArr[i].ydel*timefrac+InfoArr[i].ystart; 00134 } 00135 00136 LVector3 translate_vec(xpos, ypos, 0.0); 00137 LMatrix4 tmat2 = LMatrix4::translate_mat(translate_vec); 00138 00139 xfm_mat = InfoArr[i].rotmat * tmat2; 00140 } 00141 InfoArr[i].node->set_transform(TransformState::make_mat(xfm_mat)); 00142 } 00143 } 00144 00145 bool 00146 get_command_line_opts(int &argc, char **&argv) { 00147 // Use getopt() to decode the optional command-line parameters. 00148 // extern char *optarg; 00149 extern int optind; 00150 const char *options = "rm"; 00151 int flag = getopt(argc, argv, options); 00152 while (flag != EOF) { 00153 switch (flag) { 00154 case 'r': 00155 gridmotiontype = Rotation; 00156 break; 00157 00158 case 'm': 00159 gridmotiontype = LinearMotion; 00160 break; 00161 00162 case '?': 00163 nout << "Invalid parameter.\n"; 00164 return false; 00165 } 00166 00167 flag = getopt(argc, argv, options); 00168 } 00169 00170 argv += (optind - 1); 00171 argc -= (optind - 1); 00172 00173 return true; 00174 } 00175 00176 void 00177 get_command_line_filenames(int argc, char *argv[], 00178 pvector<Filename> &static_filenames, 00179 GriddedFilenames &gridded_filenames) { 00180 for (int i = 1; i < argc && argv[i] != (char *)NULL; i++) { 00181 const string &arg = argv[i]; 00182 size_t comma = arg.find(','); 00183 if (comma == string::npos) { 00184 // No comma in the filename, so it must be an ordinary static file. 00185 static_filenames.push_back(Filename::from_os_specific(arg)); 00186 00187 } else { 00188 // A comma in the filename indicates a gridded file. The syntax 00189 // is filename,count where count represents the number of times 00190 // the file is repeated. 00191 string name = arg.substr(0, comma); 00192 string count_str = arg.substr(comma + 1); 00193 int count; 00194 if (!string_to_int(count_str, count)) { 00195 nout << "Ignoring invalid number: " << count_str << "\n"; 00196 count = 1; 00197 } else if (count <= 0) { 00198 nout << "Ignoring inappropriate number: " << count << "\n"; 00199 count = 1; 00200 } 00201 00202 GriddedFilename gf; 00203 gf._filename = Filename::from_os_specific(name); 00204 gf._count = count; 00205 gridded_filenames.push_back(gf); 00206 } 00207 } 00208 } 00209 00210 void 00211 load_gridded_models(WindowFramework *window, 00212 GriddedFilenames &filenames, 00213 GriddedInfoArray &info_arr) { 00214 // Load up all the files indicated in the list of gridded filenames 00215 // and store them in the given vector. 00216 00217 Loader loader; 00218 LoaderOptions options; 00219 // options.set_flags(options.get_flags() | LoaderOptions::LF_no_ram_cache); 00220 00221 // First, load up each model from disk once, and store them all 00222 // separate from the scene graph. Also count up the total number of 00223 // models we'll be putting in the grid. 00224 int grid_count = 0; 00225 GriddedFilenames::iterator fi; 00226 for (fi = filenames.begin(); fi != filenames.end(); ++fi) { 00227 GriddedFilename &gf = (*fi); 00228 PT(PandaNode) node = loader.load_sync(gf._filename, options); 00229 if (node != (PandaNode *)NULL) { 00230 gf._model = NodePath(node); 00231 grid_count += gf._count; 00232 } 00233 } 00234 00235 info_arr.clear(); 00236 info_arr.reserve(grid_count); 00237 00238 // Compute the integer square root of grid_count, so that we put our 00239 // models in a nice square grid. 00240 00241 gridwidth=1; 00242 while(gridwidth*gridwidth < grid_count) { 00243 gridwidth++; 00244 } 00245 00246 grid_pos_offset = -gridwidth*GRIDCELLSIZE/2.0; 00247 wander_area_pos_offset = -max((PN_stdfloat)fabs(grid_pos_offset), MIN_WANDERAREA_DIMENSION/2.0f); 00248 00249 // Now walk through the list again, copying models into the scene 00250 // graph as we go. 00251 00252 PN_stdfloat xpos = grid_pos_offset; 00253 PN_stdfloat ypos = grid_pos_offset; 00254 00255 srand( (unsigned)time( NULL ) ); 00256 double now = ClockObject::get_global_clock()->get_frame_time(); 00257 00258 int model_count = 0; 00259 int passnum = 0; 00260 bool loaded_any; 00261 00262 NodePath root = window->get_panda_framework()->get_models(); 00263 do { 00264 loaded_any = false; 00265 00266 for (fi = filenames.begin(); fi != filenames.end(); ++fi) { 00267 const GriddedFilename &gf = (*fi); 00268 if (!gf._model.is_empty() && gf._count > passnum) { 00269 loaded_any = true; 00270 // Copy this model into the scene graph, and assign it a 00271 // position on the grid. 00272 00273 ++model_count; 00274 PT(PandaNode) node = loader.load_sync(gf._filename, options); 00275 NodePath model; 00276 if (node == (PandaNode *)NULL) { 00277 model = gf._model.copy_to(NodePath()); 00278 } else { 00279 model = NodePath(node); 00280 } 00281 model.reparent_to(root); 00282 00283 gridded_file_info info; 00284 info.node = model.node(); 00285 00286 LMatrix4 xfm_mat,tmat1,tmat2; 00287 00288 if(gridmotiontype==Rotation) { 00289 00290 #define MIN_REVOLUTION_ANGVEL 30 00291 #define MAX_REVOLUTION_ANGVEL 60 00292 00293 #define MIN_ROTATION_ANGVEL 30 00294 #define MAX_ROTATION_ANGVEL 600 00295 00296 #define MAX_RADIUS 4.0*GRIDCELLSIZE 00297 #define MIN_RADIUS 0.1*GRIDCELLSIZE 00298 00299 info.starttime = now; 00300 00301 info.xcenter=xpos; 00302 info.ycenter=ypos; 00303 info.ang1=RANDFRAC * 360.0; 00304 info.ang1_vel=((MAX_REVOLUTION_ANGVEL-MIN_REVOLUTION_ANGVEL) * RANDFRAC) + MIN_REVOLUTION_ANGVEL; 00305 00306 info.ang2=RANDFRAC * 360.0; 00307 info.ang2_vel=((MAX_ROTATION_ANGVEL-MIN_ROTATION_ANGVEL) * RANDFRAC) + MIN_ROTATION_ANGVEL; 00308 00309 info.radius = (RANDFRAC * (MAX_RADIUS-MIN_RADIUS)) + MIN_RADIUS; 00310 00311 if(RANDFRAC>0.5) { 00312 info.ang1_vel=-info.ang1_vel; 00313 } 00314 00315 if(RANDFRAC>0.5) { 00316 info.ang2_vel=-info.ang2_vel; 00317 } 00318 00319 // xforms happen left to right 00320 LVector2 new_center = LVector2(info.radius,0.0) * 00321 LMatrix3::rotate_mat(info.ang1); 00322 00323 const LVector3 rotate_axis(0.0, 0.0, 1.0); 00324 00325 LVector3 translate_vec(xpos+new_center._v.v._0, 00326 ypos+new_center._v.v._1, 00327 0.0); 00328 00329 tmat1.set_rotate_mat_normaxis(info.ang2,rotate_axis); 00330 tmat2 = LMatrix4::translate_mat(translate_vec); 00331 xfm_mat = tmat1 * tmat2; 00332 } else if(gridmotiontype==LinearMotion) { 00333 00334 #define MIN_VEL 2.0 00335 #define MAX_VEL (fabs(wander_area_pos_offset)) 00336 00337 info.vel=((MAX_VEL-MIN_VEL) * RANDFRAC) + MIN_VEL; 00338 00339 info.xstart=xpos; 00340 info.ystart=ypos; 00341 00342 info.xend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset; 00343 info.yend = RANDFRAC*fabs(2.0*wander_area_pos_offset) + wander_area_pos_offset; 00344 00345 info.starttime = now; 00346 00347 PN_stdfloat xdel = info.xdel = info.xend-info.xstart; 00348 PN_stdfloat ydel = info.ydel = info.yend-info.ystart; 00349 00350 info.endtime = csqrt(xdel*xdel+ydel*ydel)/info.vel; 00351 00352 info.timedel = info.endtime - info.starttime; 00353 00354 const LVector3 rotate_axis(0.0, 0.0, 1.0); 00355 PN_stdfloat ang = rad_2_deg(atan2(-xdel,ydel)); 00356 00357 info.rotmat.set_rotate_mat_normaxis(ang,rotate_axis); 00358 00359 LVector3 translate_vec(xpos, ypos, 0.0); 00360 LMatrix4 tmat2 = LMatrix4::translate_mat(translate_vec); 00361 00362 xfm_mat = info.rotmat * tmat2; 00363 } else { 00364 LVector3 translate_vec(xpos, ypos, 0.0); 00365 xfm_mat = LMatrix4::translate_mat(translate_vec); 00366 } 00367 00368 info.node->set_transform(TransformState::make_mat(xfm_mat)); 00369 00370 info_arr.push_back(info); 00371 00372 if((model_count % gridwidth) == 0) { 00373 xpos= -gridwidth*GRIDCELLSIZE/2.0; 00374 ypos+=GRIDCELLSIZE; 00375 } else { 00376 xpos+=GRIDCELLSIZE; 00377 } 00378 } 00379 } 00380 00381 passnum++; 00382 } while (loaded_any); 00383 } 00384 00385 int 00386 main(int argc, char **argv) { 00387 preprocess_argv(argc, argv); 00388 PandaFramework framework; 00389 framework.open_framework(argc, argv); 00390 framework.set_window_title("Gridded Object Viewer"); 00391 00392 if (!get_command_line_opts(argc, argv)) { 00393 return (1); 00394 } 00395 00396 // Extract the remaining arguments into two lists of files: those 00397 // with a grid parameter, and those without. 00398 pvector<Filename> static_filenames; 00399 GriddedFilenames gridded_filenames; 00400 get_command_line_filenames(argc, argv, static_filenames, gridded_filenames); 00401 00402 WindowFramework *window = framework.open_window(); 00403 if (window != (WindowFramework *)NULL) { 00404 // We've successfully opened a window. 00405 00406 window->enable_keyboard(); 00407 window->setup_trackball(); 00408 window->load_models(framework.get_models(), static_filenames); 00409 framework.get_models().instance_to(window->get_render()); 00410 00411 GriddedInfoArray info_arr; 00412 load_gridded_models(window, gridded_filenames, info_arr); 00413 00414 window->loop_animations(); 00415 window->stagger_animations(); 00416 window->center_trackball(framework.get_models()); 00417 00418 framework.enable_default_keys(); 00419 00420 Thread *current_thread = Thread::get_current_thread(); 00421 while (framework.do_frame(current_thread)) { 00422 if (!info_arr.empty() && gridmotiontype) { 00423 move_gridded_stuff(gridmotiontype, &info_arr[0], info_arr.size()); 00424 } 00425 } 00426 } 00427 00428 framework.report_frame_rate(nout); 00429 return (0); 00430 }