Panda3D
|
00001 // Filename: softToEggConverter.cxx 00002 // Created by: masad (25Sep03) 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 00016 #include "softToEggConverter.h" 00017 #include "config_softegg.h" 00018 #include "softEggGroupUserData.h" 00019 00020 #include "eggData.h" 00021 #include "eggGroup.h" 00022 #include "eggTable.h" 00023 #include "eggVertex.h" 00024 #include "eggComment.h" 00025 #include "eggVertexPool.h" 00026 #include "eggNurbsSurface.h" 00027 #include "eggNurbsCurve.h" 00028 #include "eggPolygon.h" 00029 #include "eggPrimitive.h" 00030 #include "eggTexture.h" 00031 #include "eggTextureCollection.h" 00032 #include "eggXfmSAnim.h" 00033 #include "eggSAnimData.h" 00034 #include "string_utils.h" 00035 #include "dcast.h" 00036 00037 SoftToEggConverter stec; 00038 00039 const int TEX_PER_MAT = 1; 00040 00041 //////////////////////////////////////////////////////////////////// 00042 // Function: SoftToEggConverter::Constructor 00043 // Access: Public 00044 // Description: 00045 //////////////////////////////////////////////////////////////////// 00046 SoftToEggConverter:: 00047 SoftToEggConverter(const string &program_name) : 00048 _program_name(program_name) 00049 { 00050 _from_selection = false; 00051 _polygon_output = false; 00052 _polygon_tolerance = 0.01; 00053 /* 00054 _respect_maya_double_sided = maya_default_double_sided; 00055 _always_show_vertex_color = maya_default_vertex_color; 00056 */ 00057 _transform_type = TT_model; 00058 00059 database_name = NULL; 00060 scene_name = NULL; 00061 model_name = NULL; 00062 animFileName = NULL; 00063 eggFileName = NULL; 00064 tex_path = NULL; 00065 eggGroupName = NULL; 00066 tex_filename = NULL; 00067 search_prefix = NULL; 00068 result = SI_SUCCESS; 00069 00070 // skeleton = new EggGroup(); 00071 foundRoot = FALSE; 00072 // animRoot = NULL; 00073 // morphRoot = NULL; 00074 geom_as_joint = 0; 00075 make_anim = 0; 00076 make_nurbs = 0; 00077 make_poly = 0; 00078 make_soft = 0; 00079 make_morph = 1; 00080 make_duv = 1; 00081 make_dart = TRUE; 00082 has_morph = 0; 00083 make_pose = 0; 00084 // animData.is_z_up = FALSE; 00085 nurbs_step = 1; 00086 anim_start = -1000; 00087 anim_end = -1000; 00088 anim_rate = 24; 00089 pose_frame = -1; 00090 verbose = 0; 00091 flatten = 0; 00092 shift_textures = 0; 00093 ignore_tex_offsets = 0; 00094 use_prefix = 0; 00095 } 00096 00097 //////////////////////////////////////////////////////////////////// 00098 00099 // Function: SoftToEggConverter::Copy Constructor 00100 // Access: Public 00101 // Description: 00102 //////////////////////////////////////////////////////////////////// 00103 SoftToEggConverter:: 00104 SoftToEggConverter(const SoftToEggConverter ©) : 00105 _from_selection(copy._from_selection), 00106 /* 00107 _maya(copy._maya), 00108 */ 00109 _polygon_output(copy._polygon_output), 00110 _polygon_tolerance(copy._polygon_tolerance), 00111 /* 00112 _respect_maya_double_sided(copy._respect_maya_double_sided), 00113 _always_show_vertex_color(copy._always_show_vertex_color), 00114 */ 00115 _transform_type(copy._transform_type) 00116 { 00117 } 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: SoftToEggConverter::Destructor 00121 // Access: Public, Virtual 00122 // Description: 00123 //////////////////////////////////////////////////////////////////// 00124 SoftToEggConverter:: 00125 ~SoftToEggConverter() { 00126 /* 00127 close_api(); 00128 */ 00129 } 00130 //////////////////////////////////////////////////////////////////// 00131 // Function: Help 00132 // Access: Public 00133 // Description: Displays the "what is this program" message, along 00134 // with the usage message. Should be overridden in base 00135 // classes to describe the current program. 00136 //////////////////////////////////////////////////////////////////// 00137 void SoftToEggConverter:: 00138 Help() 00139 { 00140 softegg_cat.info() << 00141 "soft2egg takes a SoftImage scene or model\n" 00142 "and outputs its contents as an egg file\n"; 00143 00144 Usage(); 00145 } 00146 00147 //////////////////////////////////////////////////////////////////// 00148 // Function: Usage 00149 // Access: Public 00150 // Description: Displays the usage message. 00151 //////////////////////////////////////////////////////////////////// 00152 void SoftToEggConverter:: 00153 Usage() { 00154 softegg_cat.info() 00155 << "\nUsage:\n" 00156 // << _commandName << " [opts] (must specify -m or -s)\n\n" 00157 << "soft" << " [opts] (must specify -m or -s)\n\n" 00158 << "Options:\n"; 00159 00160 ShowOpts(); 00161 softegg_cat.info() << "\n"; 00162 } 00163 00164 //////////////////////////////////////////////////////////////////// 00165 // Function: ShowOpts 00166 // Access: Public 00167 // Description: Displays the valid options. Should be extended in 00168 // base classes to show additional options relevant to 00169 // the current program. 00170 //////////////////////////////////////////////////////////////////// 00171 void SoftToEggConverter:: 00172 ShowOpts() 00173 { 00174 softegg_cat.info() << 00175 " -r <path> - Used to provide soft with the resource\n" 00176 " Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n" 00177 " -d <path> - Database path.\n" 00178 " -s <scene> - Indicates that a scene will be converted.\n" 00179 " -m <model> - Indicates that a model will be converted.\n" 00180 " -t <path> - Specify path to place converted textures.\n" 00181 " -T <name> - Specify filename for texture map listing.\n" 00182 " -S <step> - Specify step for nurbs surface triangulation.\n" 00183 " -M <name> - Specify model output filename. Defaults to scene name.\n" 00184 " -A <name> - Specify anim output filename. Defaults to scene name.\n" 00185 " -N <name> - Specify egg group name.\n" 00186 " -k - Enable soft assignment for geometry.\n" 00187 " -n - Specify egg NURBS representation instead of poly's.\n" 00188 " -p - Specify egg polygon output for geometry.\n" 00189 " -P <frame> - Specify frame number for static pose.\n" 00190 " -b <frame> - Specify starting frame for animation (default = first).\n" 00191 " -e <frame> - Specify ending frame for animation (default = last).\n" 00192 " -f <fps> - Specify frame rate for animation playback.\n" 00193 " -a - Compile animation tables if animation present.\n" 00194 " -F - Ignore hierarchy and build a completely flat skeleton.\n" 00195 " -v <level> - Set debug level.\n" 00196 " -x - Shift NURBS parameters to preserve Alias textures.\n" 00197 " -i - Ignore Soft texture uv offsets.\n" 00198 " -u - Use Soft prefix in model names.\n" 00199 " -c - Cancel morph conversion.\n" 00200 " -C - Cancel duv conversion.\n" 00201 " -D - Don't make the output model a character.\n" 00202 " -o <prefix>- Convert only models with given prefix.\n"; 00203 00204 // EggBase::ShowOpts(); 00205 } 00206 00207 //////////////////////////////////////////////////////////////////// 00208 // Function: DoGetopts 00209 // Access: Public 00210 // Description: Calls getopt() to parse the command-line switches. 00211 // Calls HandleGetopts() to interpret each switch. 00212 // Returns true if the parsing was successful; false if 00213 // there was an error. Adjusts argc and argv to remove 00214 // the switches from the parameter list. 00215 //////////////////////////////////////////////////////////////////// 00216 bool SoftToEggConverter:: 00217 DoGetopts(int &argc, char **&argv) { 00218 bool okflag = true; 00219 int i = 0; 00220 softegg_cat.info() << "argc " << argc << "\n"; 00221 if (argc <2) { 00222 Usage(); 00223 okflag = false; 00224 } 00225 while( i < argc ) { 00226 strcat(_commandLine, argv[i]); 00227 strcat(_commandLine, " "); 00228 ++i; 00229 } 00230 softegg_cat.info() << endl << _commandLine << endl; 00231 00232 i = 1; 00233 while ((i < argc) && (argv[i][0] == '-') && okflag) { 00234 softegg_cat.info() << "arg " << i << " is " << argv[i] << "\n"; 00235 okflag = HandleGetopts(i, argc, argv); 00236 } 00237 return okflag; 00238 } 00239 00240 //////////////////////////////////////////////////////////////////// 00241 // Function: HandleGetopts 00242 // Access: Public 00243 // Description: increment idx based on what kind of option parsed 00244 // Supported options are as follows: 00245 // r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD 00246 //////////////////////////////////////////////////////////////////// 00247 bool SoftToEggConverter:: 00248 HandleGetopts(int &idx, int argc, char **argv) 00249 { 00250 bool okflag = true; 00251 00252 char flag = argv[idx][1]; // skip the '-' from option 00253 00254 switch (flag) 00255 { 00256 case 'r': // Set the resource path for soft. 00257 if ( strcmp( argv[idx+1], "" ) ) { 00258 // Get the path. 00259 rsrc_path = argv[idx+1]; 00260 softegg_cat.info() << "using rsrc path " << rsrc_path << "\n"; 00261 } 00262 ++idx; 00263 break; 00264 00265 case 'd': // Set the database path. 00266 if ( strcmp( argv[idx+1], "" ) ) { 00267 // Get the path. 00268 database_name = argv[idx+1]; 00269 softegg_cat.info() << "using database " << database_name << "\n"; 00270 } 00271 ++idx; 00272 break; 00273 00274 case 's': // Check if its a scene. 00275 if ( strcmp( argv[idx+1], "" ) ) { 00276 // Get scene name. 00277 scene_name = argv[idx+1]; 00278 softegg_cat.info() << "loading scene " << scene_name << "\n"; 00279 } 00280 ++idx; 00281 break; 00282 00283 case 'm': // Check if its a model. 00284 if ( strcmp( argv[idx+1], "" ) ) { 00285 // Get model name. 00286 model_name = argv[idx+1]; 00287 softegg_cat.info() << "loading model " << model_name << endl; 00288 } 00289 ++idx; 00290 break; 00291 00292 case 't': // Get converted texture path. 00293 if ( strcmp( argv[idx+1], "" ) ) { 00294 // Get tex path name. 00295 tex_path = argv[idx+1]; 00296 softegg_cat.info() << "texture path: " << tex_path << endl; 00297 } 00298 ++idx; 00299 break; 00300 00301 case 'T': // Specify texture list filename. 00302 if ( strcmp( argv[idx+1], "") ) { 00303 // Get the name. 00304 tex_filename = argv[idx+1]; 00305 softegg_cat.info() << "creating texture list file: " << tex_filename << endl; 00306 } 00307 ++idx; 00308 break; 00309 00310 case 'S': // Set NURBS step. 00311 if ( strcmp( argv[idx+1], "" ) ) { 00312 nurbs_step = atoi(argv[idx+1]); 00313 softegg_cat.info() << "NURBS step: " << nurbs_step << endl; 00314 } 00315 ++idx; 00316 break; 00317 00318 case 'M': // Set model output file name. 00319 if ( strcmp( argv[idx+1], "" ) ) { 00320 eggFileName = argv[idx+1]; 00321 softegg_cat.info() << "Model output filename: " << eggFileName << endl; 00322 } 00323 ++idx; 00324 break; 00325 00326 case 'A': // Set anim output file name. 00327 if ( strcmp( argv[idx+1], "" ) ) { 00328 animFileName = argv[idx+1]; 00329 softegg_cat.info() << "Anim output filename: " << animFileName << endl; 00330 } 00331 ++idx; 00332 break; 00333 00334 case 'N': // Set egg model name. 00335 if ( strcmp( argv[idx+1], "" ) ) { 00336 eggGroupName = argv[idx+1]; 00337 softegg_cat.info() << "Egg group name: " << eggGroupName << endl; 00338 } 00339 ++idx; 00340 break; 00341 00342 case 'o': // Set search_prefix. 00343 if ( strcmp( argv[idx+1], "" ) ) { 00344 search_prefix = argv[idx+1]; 00345 softegg_cat.info() << "Only converting models with prefix: " << search_prefix << endl; 00346 } 00347 ++idx; 00348 break; 00349 00350 case 'h': // print help message 00351 Help(); 00352 exit(1); 00353 break; 00354 00355 case 'c': // Cancel morph animation conversion 00356 make_morph = FALSE; 00357 softegg_cat.info() << "canceling morph conversion\n"; 00358 break; 00359 00360 case 'C': // Cancel uv animation conversion 00361 make_duv = FALSE; 00362 softegg_cat.info() << "canceling uv animation conversion\n"; 00363 break; 00364 00365 case 'D': // Omit the Dart flag 00366 make_dart = FALSE; 00367 softegg_cat.info() << "making a non-character model\n"; 00368 break; 00369 00370 case 'k': // Enable soft skinning 00371 //make_soft = TRUE; 00372 //fprintf( outStream, "enabling soft skinning\n" ); 00373 softegg_cat.info() << "-k flag no longer necessary\n"; 00374 break; 00375 00376 case 'n': // Generate egg NURBS output 00377 make_nurbs = TRUE; 00378 softegg_cat.info() << "outputting egg NURBS info\n"; 00379 break; 00380 00381 case 'p': // Generate egg polygon output 00382 make_poly = TRUE; 00383 softegg_cat.info() << "outputting egg polygon info\n"; 00384 break; 00385 00386 case 'P': // Generate static pose from given frame 00387 if ( strcmp( argv[idx+1], "" ) ) { 00388 make_pose = TRUE; 00389 pose_frame = atoi(argv[idx+1]); 00390 softegg_cat.info() << "generating static pose from frame " << pose_frame << endl; 00391 } 00392 ++idx; 00393 break; 00394 00395 case 'a': // Compile animation tables. 00396 make_anim = TRUE; 00397 softegg_cat.info() << "attempting to compile anim tables\n"; 00398 break; 00399 00400 case 'F': // Build a flat skeleton. 00401 flatten = TRUE; 00402 softegg_cat.info() << "building a flat skeleton!!!\n"; 00403 break; 00404 00405 case 'x': // Shift NURBS parameters to preserve Alias textures. 00406 shift_textures = TRUE; 00407 softegg_cat.info() << "shifting NURBS parameters...\n"; 00408 break; 00409 00410 case 'i': // Ignore Soft uv texture offsets 00411 ignore_tex_offsets = TRUE; 00412 softegg_cat.info() << "ignoring texture offsets...\n"; 00413 break; 00414 00415 case 'u': // Use Soft prefix in model names 00416 use_prefix = TRUE; 00417 softegg_cat.info() << "using prefix in model names...\n"; 00418 break; 00419 00420 00421 case 'v': // print debug messages. 00422 if ( strcmp( argv[idx+1], "" ) ) { 00423 verbose = atoi(argv[idx+1]); 00424 softegg_cat.info() << "using debug level " << verbose << endl; 00425 } 00426 ++idx; 00427 break; 00428 00429 case 'b': // Set animation start frame. 00430 anim_start = atoi(argv[idx]+2); 00431 softegg_cat.info() << "animation starting at frame: " << anim_start << endl; 00432 break; 00433 00434 case 'e': /// Set animation end frame. 00435 anim_end = atoi(argv[idx]+2); 00436 softegg_cat.info() << "animation ending at frame: " << anim_end << endl; 00437 break; 00438 00439 case 'f': /// Set animation frame rate. 00440 if ( strcmp( argv[idx+1], "" ) ) { 00441 anim_rate = atoi(argv[idx+1]); 00442 softegg_cat.info() << "animation frame rate: " << anim_rate << endl; 00443 } 00444 ++idx; 00445 break; 00446 00447 default: 00448 softegg_cat.info() << flag << " flag not supported\n"; 00449 okflag = false; 00450 } 00451 idx++; 00452 return (okflag); 00453 } 00454 00455 //////////////////////////////////////////////////////////////////// 00456 // Function: SoftToEggConverter::make_copy 00457 // Access: Public, Virtual 00458 // Description: Allocates and returns a new copy of the converter. 00459 //////////////////////////////////////////////////////////////////// 00460 SomethingToEggConverter *SoftToEggConverter:: 00461 make_copy() { 00462 return new SoftToEggConverter(*this); 00463 } 00464 00465 //////////////////////////////////////////////////////////////////// 00466 // Function: SoftToEggConverter::get_name 00467 // Access: Public, Virtual 00468 // Description: Returns the English name of the file type this 00469 // converter supports. 00470 //////////////////////////////////////////////////////////////////// 00471 string SoftToEggConverter:: 00472 get_name() const { 00473 return "Soft"; 00474 } 00475 00476 //////////////////////////////////////////////////////////////////// 00477 // Function: SoftToEggConverter::get_extension 00478 // Access: Public, Virtual 00479 // Description: Returns the common extension of the file type this 00480 // converter supports. 00481 //////////////////////////////////////////////////////////////////// 00482 string SoftToEggConverter:: 00483 get_extension() const { 00484 return "mb"; 00485 } 00486 00487 //////////////////////////////////////////////////////////////////// 00488 // Function: SoftToEggConverter::get_name 00489 // Access: Public, Virtual 00490 // Description: Returns the English name of the file type this 00491 // converter supports. 00492 //////////////////////////////////////////////////////////////////// 00493 SoftNodeDesc *SoftToEggConverter:: 00494 find_node(string name) { 00495 return _tree.get_node(name); 00496 } 00497 00498 //////////////////////////////////////////////////////////////////// 00499 // Function: GetTextureName 00500 // Access: Public 00501 // Description: Given a texture element, return texture name 00502 // with given tex_path 00503 //////////////////////////////////////////////////////////////////// 00504 char *SoftToEggConverter:: 00505 GetTextureName( SAA_Scene *scene, SAA_Elem *texture ) { 00506 char *fileName = new char[_MAX_PATH]; 00507 char tempName[_MAX_PATH]; 00508 SAA_texture2DGetPicName( scene, texture, _MAX_PATH, tempName ); 00509 00510 if (tex_path) { 00511 // softegg_cat.spam() << "tempName :" << tempName << endl; 00512 strcpy(fileName, tex_path); 00513 00514 // do some processing on the name string 00515 char *tmpName = NULL; 00516 tmpName = strrchr(tempName, '/'); 00517 if (tmpName) 00518 tmpName++; 00519 else 00520 tmpName = tempName; 00521 00522 // softegg_cat.spam() << "tmpName : " << tmpName << endl; 00523 strcat(fileName, "/"); 00524 strcat(fileName, tmpName); 00525 } 00526 else { 00527 strcpy(fileName, tempName); 00528 } 00529 00530 strcat(fileName, ".pic"); 00531 // softegg_cat.spam() << "fileName : " << fileName << endl; 00532 00533 return fileName; 00534 } 00535 00536 //////////////////////////////////////////////////////////////////// 00537 // Function: SoftToEggConverter::convert_file 00538 // Access: Public, Virtual 00539 // Description: Handles the reading of the input file and converting 00540 // it to egg. Returns true if successful, false 00541 // otherwise. 00542 // 00543 // This is designed to be as generic as possible, 00544 // generally in support of run-time loading. 00545 // Also see convert_soft(). 00546 //////////////////////////////////////////////////////////////////// 00547 bool SoftToEggConverter:: 00548 convert_file(const Filename &filename) { 00549 if (!open_api()) { 00550 softegg_cat.error() 00551 << "Soft is not available.\n"; 00552 return false; 00553 } 00554 if (_character_name.empty()) { 00555 _character_name = filename.get_basename_wo_extension(); 00556 } 00557 return convert_soft(false); 00558 } 00559 00560 //////////////////////////////////////////////////////////////////// 00561 // Function: SoftToEggConverter::convert_soft 00562 // Access: Public 00563 // Description: Fills up the egg_data structure according to the 00564 // global soft model data. Returns true if successful, 00565 // false if there is an error. If from_selection is 00566 // true, the converted geometry is based on that which 00567 // is selected; otherwise, it is the entire Soft scene. 00568 //////////////////////////////////////////////////////////////////// 00569 bool SoftToEggConverter:: 00570 convert_soft(bool from_selection) { 00571 bool all_ok = true; 00572 00573 _from_selection = from_selection; 00574 _textures.clear(); 00575 00576 PT(EggData) egg_data = new EggData; 00577 set_egg_data(egg_data); 00578 softegg_cat.spam() << "eggData " << get_egg_data() << "\n"; 00579 00580 // append the command line 00581 softegg_cat.info() << _commandLine << endl; 00582 get_egg_data()->insert(get_egg_data()->begin(), new EggComment("", _commandLine)); 00583 00584 if (_egg_data->get_coordinate_system() != CS_default) { 00585 softegg_cat.spam() << "coordinate system is not default\n"; 00586 exit(1); 00587 } 00588 00589 _tree._use_prefix = use_prefix; 00590 _tree._search_prefix = search_prefix; 00591 all_ok = _tree.build_complete_hierarchy(scene, database); 00592 00593 // Lets see if we have gotten the hierarchy right 00594 //_tree.print_hierarchy(); 00595 //exit(1); 00596 00597 char *root_name = _tree.GetRootName( eggFileName ); 00598 00599 softegg_cat.debug() << "main group name: " << root_name << endl; 00600 if (root_name) 00601 _character_name = root_name; 00602 00603 if (make_poly || make_nurbs) { 00604 // Specify that the texture names should be relative to the output 00605 // file. 00606 Filename output_filename(eggFileName); 00607 _path_replace->_path_store = PS_relative; 00608 _path_replace->_path_directory = output_filename.get_dirname(); 00609 00610 if (!convert_char_model()) { 00611 all_ok = false; 00612 } 00613 00614 // generate soft skinning assignments if desired 00615 if (!make_soft_skin()) { 00616 all_ok = false; 00617 } 00618 00619 // sometimes you need to hard assign some vertices 00620 if (!cleanup_soft_skin()) { 00621 all_ok = false; 00622 } 00623 00624 // reparent_decals(get_egg_data()); 00625 softegg_cat.info() << "Converted Softimage file\n"; 00626 00627 // write out the egg model file 00628 _egg_data->write_egg(output_filename); 00629 softegg_cat.info() << "Wrote Egg file " << output_filename << endl; 00630 } 00631 if (make_anim) { 00632 if (!convert_char_chan()) { 00633 all_ok = false; 00634 } 00635 00636 // reparent_decals(get_egg_data()); 00637 softegg_cat.info() << "Converted Softimage file\n"; 00638 00639 // write out the egg model file 00640 _egg_data->write_egg(Filename(animFileName)); 00641 softegg_cat.info() << "Wrote Anim file " << animFileName << endl; 00642 } 00643 return all_ok; 00644 } 00645 00646 //////////////////////////////////////////////////////////////////// 00647 // Function: SoftToEggConverter::open_api 00648 // Access: Public 00649 // Description: Attempts to open the Soft API if it was not already 00650 // open, and returns true if successful, or false if 00651 // there is an error. 00652 //////////////////////////////////////////////////////////////////// 00653 bool SoftToEggConverter:: 00654 open_api() { 00655 if ((scene_name == NULL && model_name == NULL) || database_name == NULL) { 00656 Usage(); 00657 exit( 1 ); 00658 } 00659 if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) { 00660 softegg_cat.info() << "Error: Couldn't get resource path!\n"; 00661 exit( 1 ); 00662 } 00663 // cout << "got past init" << endl; 00664 if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) { 00665 softegg_cat.info() << "Error: Couldn't load database!\n"; 00666 exit( 1 ); 00667 } 00668 // cout << "got past database load" << endl; 00669 if ((result = SAA_sceneGetCurrent(&scene)) != SI_SUCCESS) { 00670 softegg_cat.info() << "Error: Couldn't get current scene!\n"; 00671 exit( 1 ); 00672 } 00673 // cout << "got past get current" << endl; 00674 if ((result = SAA_sceneLoad( &database, scene_name, &scene )) != SI_SUCCESS) { 00675 softegg_cat.info() << "Error: Couldn't load scene " << scene_name << "!\n"; 00676 exit( 1 ); 00677 } 00678 // cout << "got past scene load" << endl; 00679 if ( SAA_updatelistGet( &scene ) == SI_SUCCESS ) { 00680 PN_stdfloat time; 00681 00682 softegg_cat.info() << "setting Scene to frame " << pose_frame << "...\n"; 00683 //SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame ); 00684 SAA_frame2Seconds( &scene, pose_frame, &time ); 00685 SAA_updatelistEvalScene( &scene, time ); 00686 if ( make_pose ) 00687 SAA_sceneFreeze(&scene); 00688 } 00689 00690 // if no egg filename specified, make up a name 00691 if ( eggFileName == NULL ) { 00692 string madeName; 00693 string tempName(scene_name); 00694 string::size_type end = tempName.find(".dsc"); 00695 if (end != string::npos) { 00696 madeName.assign(tempName.substr(0,end)); 00697 if ( make_nurbs ) 00698 madeName.insert(madeName.size(), "-nurb"); 00699 madeName.insert(madeName.size(), ".egg" ); 00700 } 00701 eggFileName = new char[madeName.size()+1]; 00702 strcpy(eggFileName, madeName.c_str()); 00703 00704 // if no anim filename specified, make up a name 00705 if ( animFileName == NULL ) { 00706 madeName.assign(tempName.substr(0,end)); 00707 madeName.insert(madeName.size(), "-chan.egg"); 00708 animFileName = new char[strlen(scene_name)+ 10]; 00709 strcpy(animFileName, madeName.c_str()); 00710 } 00711 } 00712 00713 return true; 00714 } 00715 00716 //////////////////////////////////////////////////////////////////// 00717 // Function: SoftToEggConverter::close_api 00718 // Access: Public 00719 // Description: Closes the Soft API, if it was previously opened. 00720 // Caution! Soft appears to call exit() when its API is 00721 // closed. 00722 //////////////////////////////////////////////////////////////////// 00723 void SoftToEggConverter:: 00724 close_api() { 00725 // don't know yet 00726 } 00727 00728 //////////////////////////////////////////////////////////////////// 00729 // Function: SoftToEggConverter::convert_char_model 00730 // Access: Private 00731 // Description: Converts the file as an animatable character 00732 // model, with joints and vertex membership. 00733 //////////////////////////////////////////////////////////////////// 00734 bool SoftToEggConverter:: 00735 convert_char_model() { 00736 softegg_cat.spam() << "character name " << _character_name << "\n"; 00737 EggGroup *char_node = new EggGroup(eggGroupName); 00738 get_egg_data()->add_child(char_node); 00739 char_node->set_dart_type(EggGroup::DT_default); 00740 00741 return convert_hierarchy(char_node); 00742 } 00743 00744 //////////////////////////////////////////////////////////////////// 00745 // Function: SoftToEggConverter::find_morph_table 00746 // Access: Public 00747 // Description: Given a tablename, it either creates a new 00748 // eggSAnimData structure (if doesn't exist) or 00749 // locates it. 00750 //////////////////////////////////////////////////////////////////// 00751 EggSAnimData *SoftToEggConverter:: 00752 find_morph_table(char *name) { 00753 EggSAnimData *anim = NULL; 00754 MorphTable::iterator mt; 00755 for (mt = _morph_table.begin(); mt != _morph_table.end(); ++mt) { 00756 anim = (*mt); 00757 if (!strcmp(anim->get_name().c_str(), name)) 00758 return anim; 00759 } 00760 00761 // create an entry 00762 anim = new EggSAnimData(name); 00763 anim->set_fps(_tree._fps); 00764 _morph_table.push_back(anim); 00765 morph_node->add_child(anim); 00766 return anim; 00767 } 00768 00769 //////////////////////////////////////////////////////////////////// 00770 // Function: SoftToEggConverter::convert_char_chan 00771 // Access: Private 00772 // Description: Converts the animation as a series of tables to apply 00773 // to the character model, as retrieved earlier via 00774 // AC_model. 00775 //////////////////////////////////////////////////////////////////// 00776 bool SoftToEggConverter:: 00777 convert_char_chan() { 00778 int start_frame = -1; 00779 int end_frame = -1; 00780 int frame_inc, frame; 00781 double output_frame_rate = anim_rate; 00782 00783 PN_stdfloat time; 00784 00785 EggTable *root_table_node = new EggTable(); 00786 get_egg_data()->add_child(root_table_node); 00787 EggTable *bundle_node = new EggTable(eggGroupName); 00788 bundle_node->set_table_type(EggTable::TT_bundle); 00789 root_table_node->add_child(bundle_node); 00790 EggTable *skeleton_node = new EggTable("<skeleton>"); 00791 bundle_node->add_child(skeleton_node); 00792 00793 morph_node = new EggTable("morph"); 00794 00795 // Set the frame rate before we start asking for anim tables to be 00796 // created. 00797 SAA_sceneGetPlayCtrlStartFrame(&scene, &start_frame); 00798 SAA_sceneGetPlayCtrlEndFrame(&scene, &end_frame); 00799 SAA_sceneGetPlayCtrlFrameStep( &scene, &frame_inc ); 00800 if (frame_inc != 1) // Hmmm...some files gave me frame_inc of 0, that can't be good 00801 frame_inc = 1; 00802 00803 softegg_cat.info() << "animation start frame: " << start_frame << " end frame: " << end_frame << endl; 00804 softegg_cat.info() << "animation frame inc: " << frame_inc << endl; 00805 00806 _tree._fps = output_frame_rate / frame_inc; 00807 // _tree.clear_egg(get_egg_data(), NULL, root_node); 00808 _tree.clear_egg(get_egg_data(), NULL, skeleton_node); 00809 00810 // Now we can get the animation data by walking through all of the 00811 // frames, one at a time, and getting the joint angles at each 00812 // frame. 00813 00814 // This is just a temporary EggGroup to receive the transform for 00815 // each joint each frame. 00816 PT(EggGroup) tgroup = new EggGroup; 00817 00818 int num_nodes = _tree.get_num_nodes(); 00819 int i; 00820 00821 // MTime frame(start_frame, MTime::uiUnit()); 00822 // MTime frame_stop(end_frame, MTime::uiUnit()); 00823 // start at first frame and go to last 00824 if (make_pose) { 00825 start_frame = pose_frame; 00826 end_frame = pose_frame; 00827 } 00828 if (anim_start > 0) 00829 start_frame = anim_start; 00830 if (anim_end > 0) 00831 end_frame = anim_end; 00832 for ( frame = start_frame; frame <= end_frame; frame += frame_inc) { 00833 SAA_frame2Seconds( &scene, frame, &time ); 00834 // softegg_cat.spam() << "got time " << time << endl; 00835 if (!make_pose) { 00836 SAA_updatelistEvalScene( &scene, time ); 00837 } 00838 softegg_cat.spam() << "\n> animating frame " << frame << endl; 00839 00840 // if (softegg_cat.is_debug()) { 00841 // softegg_cat.debug(false) 00842 softegg_cat.info() << "frame " << time << "\n"; 00843 //} else { 00844 // We have to write to cerr instead of softegg_cat to allow 00845 // flushing without writing a newline. 00846 // cerr << "." << flush; 00847 // } 00848 // MGlobal::viewFrame(frame); 00849 00850 for (i = 0; i < num_nodes; i++) { 00851 SoftNodeDesc *node_desc = _tree.get_node(i); 00852 00853 if (node_desc->is_partial(search_prefix)) { 00854 softegg_cat.debug() << endl; 00855 continue; 00856 } 00857 if (make_morph) { 00858 node_desc->make_morph_table(time); 00859 } 00860 if (node_desc->is_joint()) { 00861 softegg_cat.spam() << "-----joint " << node_desc->get_name() << "\n"; 00862 EggXfmSAnim *anim = _tree.get_egg_anim(node_desc); 00863 // following function fills in the anim structure 00864 node_desc->get_joint_transform(&scene, tgroup, anim, TRUE); 00865 } 00866 } 00867 00868 // frame += frame_inc; 00869 } 00870 00871 if (has_morph) 00872 bundle_node->add_child(morph_node); 00873 00874 // Now optimize all of the tables we just filled up, for no real 00875 // good reason, except that it makes the resulting egg file a little 00876 // easier to read. 00877 for (i = 0; i < num_nodes; i++) { 00878 SoftNodeDesc *node_desc = _tree.get_node(i); 00879 if (node_desc->is_partial(search_prefix)) 00880 continue; 00881 00882 if (node_desc->is_joint()) { 00883 _tree.get_egg_anim(node_desc)->optimize(); 00884 } 00885 } 00886 00887 softegg_cat.info(false) 00888 << "\n"; 00889 00890 return true; 00891 } 00892 00893 //////////////////////////////////////////////////////////////////// 00894 // Function: SoftToEggConverter::convert_hierarchy 00895 // Access: Private 00896 // Description: Generates egg structures for each node in the Soft 00897 // hierarchy. 00898 //////////////////////////////////////////////////////////////////// 00899 bool SoftToEggConverter:: 00900 convert_hierarchy(EggGroupNode *egg_root) { 00901 int num_nodes = _tree.get_num_nodes(); 00902 00903 _tree.clear_egg(get_egg_data(), egg_root, NULL); 00904 softegg_cat.spam() << "num_nodes = " << num_nodes << endl; 00905 for (int i = 0; i < num_nodes; i++) { 00906 if (!process_model_node(_tree.get_node(i))) { 00907 return false; 00908 } 00909 softegg_cat.debug() << i << endl; 00910 } 00911 return true; 00912 } 00913 00914 //////////////////////////////////////////////////////////////////// 00915 // Function: SoftToEggConverter::process_model_node 00916 // Access: Private 00917 // Description: Converts the indicated Soft node (given a MDagPath, 00918 // similar in concept to Panda's NodePath) to the 00919 // corresponding Egg structure. Returns true if 00920 // successful, false if an error was encountered. 00921 //////////////////////////////////////////////////////////////////// 00922 bool SoftToEggConverter:: 00923 process_model_node(SoftNodeDesc *node_desc) { 00924 EggGroup *egg_group = NULL; 00925 const char *name = NULL; 00926 char *fullname = NULL; 00927 SAA_ModelType type; 00928 00929 name = node_desc->get_name().c_str(); 00930 softegg_cat.debug() << "element name <" << name << ">\n"; 00931 00932 if (node_desc->is_junk()) { 00933 softegg_cat.spam() << "no processing, it is junk\n"; 00934 return true; 00935 } 00936 00937 // split 00938 if (node_desc->is_partial(search_prefix)) { 00939 softegg_cat.debug() << endl; 00940 return true; 00941 } 00942 else 00943 softegg_cat.debug() << endl << name << ":being processed" << endl; 00944 00945 egg_group = _tree.get_egg_group(node_desc); 00946 00947 // find out what type of node we're dealing with 00948 SAA_modelGetType( &scene, node_desc->get_model(), &type ); 00949 00950 softegg_cat.debug() << "encountered "; 00951 switch(type){ 00952 case SAA_MNILL: 00953 softegg_cat.debug() << "null\n"; 00954 break; 00955 case SAA_MPTCH: 00956 softegg_cat.debug() << "patch\n"; 00957 break; 00958 case SAA_MFACE: 00959 softegg_cat.debug() << "face\n"; 00960 //break; 00961 case SAA_MSMSH: 00962 softegg_cat.debug() << "mesh\n"; 00963 node_desc->get_transform(&scene, egg_group, TRUE); 00964 make_polyset(node_desc, egg_group, type); 00965 break; 00966 case SAA_MJNT: 00967 softegg_cat.debug() << "joint"; 00968 softegg_cat.debug() << " joint type " << node_desc->is_joint() << endl; 00969 break; 00970 case SAA_MSPLN: 00971 softegg_cat.debug() << "spline\n"; 00972 break; 00973 case SAA_MMETA: 00974 softegg_cat.debug() << "meta element\n"; 00975 break; 00976 case SAA_MBALL: 00977 softegg_cat.debug() << "meta ball\n"; 00978 break; 00979 case SAA_MNCRV: 00980 softegg_cat.debug() << "nurbs curve\n"; 00981 break; 00982 case SAA_MNSRF: 00983 softegg_cat.debug() << "nurbs surf\n"; 00984 node_desc->get_transform(&scene, egg_group, TRUE); 00985 make_nurb_surface(node_desc, egg_group, type); 00986 break; 00987 default: 00988 softegg_cat.debug() << "unknown type: " << type << "\n"; 00989 } 00990 00991 if (node_desc->is_joint()) 00992 node_desc->get_transform(&scene, egg_group, FALSE); 00993 00994 return true; 00995 } 00996 00997 //////////////////////////////////////////////////////////////////// 00998 // Function: SoftToEggConverter::make_polyset 00999 // Access: Private 01000 // Description: Converts the indicated Soft polyset to a bunch of 01001 // EggPolygons and parents them to the indicated egg 01002 // group. 01003 //////////////////////////////////////////////////////////////////// 01004 void SoftToEggConverter:: 01005 make_polyset(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) { 01006 int id = 0; 01007 int i, idx; 01008 int numShapes; 01009 SAA_Boolean valid; 01010 SAA_Boolean visible; 01011 PN_stdfloat *uCoords = NULL; 01012 PN_stdfloat *vCoords = NULL; 01013 string name = node_desc->get_name(); 01014 01015 SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible ); 01016 softegg_cat.spam() << "model visibility: " << visible << endl; 01017 01018 /////////////////////////////////////////////////////////////////////// 01019 // Only create egg polygon data if: the node is visible, and its not 01020 // a NULL or a Joint, and we're outputing polys (or if we are outputing 01021 // NURBS and the model is a poly mesh or a face) 01022 /////////////////////////////////////////////////////////////////////// 01023 if ( visible && 01024 (type != SAA_MNILL) && 01025 (type != SAA_MJNT) && 01026 ((make_poly || 01027 (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) || 01028 (!make_poly && !make_nurbs && make_duv && 01029 ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) 01030 ) 01031 { 01032 // Get the number of key shapes 01033 SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes ); 01034 softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl; 01035 01036 // load all node data from soft for this node_desc 01037 node_desc->load_poly_model(&scene, type); 01038 01039 string vpool_name = name + ".verts"; 01040 EggVertexPool *vpool = new EggVertexPool(vpool_name); 01041 vpool->set_highest_index(0); 01042 01043 // add the vertices in the _tree._root node, so that 01044 // they will be written out first in egg file. This 01045 // solves a problem of soft-skinning trying to access 01046 // vertex pool before it is defined. 01047 01048 _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool); 01049 01050 // We will need to transform all vertices from world coordinate 01051 // space into the vertex space appropriate to this node. Usually, 01052 // this is the same thing as world coordinate space, and this matrix 01053 // will be identity; but if the node is under an instance 01054 // (particularly, for instance, a billboard) then the vertex space 01055 // will be different from world space. 01056 LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); 01057 01058 // Asad: change from soft2egg.c. Here I am trying to get one triangles vertices not all 01059 for (idx=0; idx<node_desc->numTri; ++idx) { 01060 EggPolygon *egg_poly = new EggPolygon; 01061 egg_group->add_child(egg_poly); 01062 01063 softegg_cat.spam() << "processing polygon " << idx << endl; 01064 01065 // Is this a double sided polygon? meaning check for back face flag 01066 char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() ); 01067 if ( modelNoteStr != NULL ) { 01068 if ( strstr( modelNoteStr, "bface" ) != NULL ) 01069 egg_poly->set_bface_flag(TRUE); 01070 } 01071 01072 // read each triangle's control vertices into array 01073 SAA_SubElem cvertices[3]; 01074 SAA_triangleGetCtrlVertices( &scene, node_desc->get_model(), node_desc->gtype, id, 1, node_desc->triangles+idx, cvertices ); 01075 01076 // read control vertices in this triangle 01077 SAA_DVector cvertPos[3]; 01078 SAA_ctrlVertexGetPositions( &scene, node_desc->get_model(), 3, cvertices, cvertPos); 01079 01080 // read indices of each vertices in this triangle 01081 int indices[3]; 01082 indices[0] = indices[1] = indices[2] = 0; 01083 SAA_ctrlVertexGetIndices( &scene, node_desc->get_model(), 3, cvertices, indices ); 01084 01085 // read each control vertex's normals into an array 01086 SAA_DVector normals[3]; 01087 SAA_ctrlVertexGetNormals( &scene, node_desc->get_model(), 3, cvertices, normals ); 01088 for (i=0; i<3; ++i) 01089 softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " << normals[i].y 01090 << " " << normals[i].z << " " << normals[i].w << "\n"; 01091 01092 // allocate arrays for u & v coords 01093 if (node_desc->textures) { 01094 if (node_desc->numTexLoc && node_desc->numTexTri[idx]) { 01095 // allocate arrays for u & v coords 01096 // I think there are one texture per triangle hence we need only 3 corrdinates 01097 uCoords = new PN_stdfloat[3]; 01098 vCoords = new PN_stdfloat[3]; 01099 01100 // read the u & v coords into the arrays 01101 if ( uCoords != NULL && vCoords != NULL) { 01102 for ( i = 0; i < 3; i++ ) 01103 uCoords[i] = vCoords[i] = 0.0f; 01104 01105 // TODO: investigate the coord_cnt parameter... 01106 SAA_ctrlVertexGetUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices, 01107 3, uCoords, vCoords ); 01108 } 01109 else 01110 softegg_cat.info() << "Not enough Memory for texture coords...\n"; 01111 01112 #if 1 01113 for ( i=0; i<3; i++ ) 01114 softegg_cat.spam() << "texcoords[" << i << "] = ( " << uCoords[i] << " , " << vCoords[i] <<" )\n"; 01115 #endif 01116 } 01117 else if (node_desc->numTexGlb) { 01118 // allocate arrays for u & v coords 01119 uCoords = new PN_stdfloat[node_desc->numTexGlb*3]; 01120 vCoords = new PN_stdfloat[node_desc->numTexGlb*3]; 01121 01122 for ( i = 0; i < node_desc->numTexGlb*3; i++ ) { 01123 uCoords[i] = vCoords[i] = 0.0f; 01124 } 01125 01126 // read the u & v coords into the arrays 01127 if ( uCoords != NULL && vCoords != NULL) { 01128 SAA_triCtrlVertexGetGlobalUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices, 01129 node_desc->numTexGlb, node_desc->textures, uCoords, vCoords ); 01130 } 01131 else 01132 softegg_cat.info() << "Not enough Memory for texture coords...\n"; 01133 } 01134 } 01135 01136 for ( i=0; i < 3; i++ ) { 01137 EggVertex vert; 01138 01139 // There are some conversions needed from local matrix to global coords 01140 SAA_DVector local = cvertPos[i]; 01141 SAA_DVector global = {0}; 01142 01143 _VCT_X_MAT( global, local, node_desc->matrix ); 01144 01145 softegg_cat.spam() << "indices[" << i << "] = " << indices[i] << "\n"; 01146 softegg_cat.spam() << "cvert[" << i << "] = " << cvertPos[i].x << " " << cvertPos[i].y 01147 << " " << cvertPos[i].z << " " << cvertPos[i].w << "\n"; 01148 softegg_cat.spam() << " global cvert[" << i << "] = " << global.x << " " << global.y 01149 << " " << global.z << " " << global.w << "\n"; 01150 01151 // LPoint3d p3d(cvertPos[i].x, cvertPos[i].y, cvertPos[i].z); 01152 LPoint3d p3d(global.x, global.y, global.z); 01153 p3d = p3d * vertex_frame_inv; 01154 vert.set_pos(p3d); 01155 01156 local = normals[i]; 01157 _VCT_X_MAT( global, local, node_desc->matrix ); 01158 01159 softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " << normals[i].y 01160 << " " << normals[i].z << " " << normals[i].w << "\n"; 01161 softegg_cat.spam() << " global normals[" << i <<"] = " << global.x << " " << global.y 01162 << " " << global.z << " " << global.w << "\n"; 01163 01164 LVector3d n3d(global.x, global.y, global.z); 01165 n3d = n3d * vertex_frame_inv; 01166 vert.set_normal(n3d); 01167 01168 // if texture present set the texture coordinates 01169 if (node_desc->textures) { 01170 PN_stdfloat u, v; 01171 01172 if (uCoords && vCoords) { 01173 u = uCoords[i]; 01174 v = 1.0f - vCoords[i]; 01175 softegg_cat.spam() << "texcoords[" << i << "] = " << u << " " 01176 << v << endl; 01177 01178 vert.set_uv(LTexCoordd(u, v)); 01179 //vert.set_uv(LTexCoordd(uCoords[i], vCoords[i])); 01180 } 01181 } 01182 vert.set_external_index(indices[i]); 01183 egg_poly->add_vertex(vpool->create_unique_vertex(vert)); 01184 01185 // check to see if material is present 01186 PN_stdfloat r,g,b,a; 01187 SAA_elementIsValid( &scene, &node_desc->materials[idx], &valid ); 01188 // material present - get the color 01189 if ( valid ) { 01190 SAA_materialGetDiffuse( &scene, &node_desc->materials[idx], &r, &g, &b ); 01191 SAA_materialGetTransparency( &scene, &node_desc->materials[idx], &a ); 01192 egg_poly->set_color(LColor(r, g, b, 1.0f - a)); 01193 softegg_cat.spam() << "color r = " << r << " g = " << g << " b = " << b << " a = " << 1.0f - a << "\n"; 01194 } 01195 else { // no material - default to white 01196 egg_poly->set_color(LColor(1.0, 1.0, 1.0, 1.0)); 01197 softegg_cat.spam() << "default color\n"; 01198 } 01199 01200 /* 01201 // keep a one to one copy in this node's vpool 01202 EggVertex *t_vert = new EggVertex(vert); 01203 if (!t_vert) { 01204 softegg_cat.spam() << "out of memeory " << endl; 01205 nassertv(t_vert != NULL); 01206 } 01207 node_desc->get_vpool()->add_vertex(t_vert, indices[i]); 01208 */ 01209 01210 softegg_cat.spam() << "\n"; 01211 } 01212 01213 // Now apply the shader. 01214 if (node_desc->textures != NULL) { 01215 if (node_desc->numTexLoc && node_desc->numTexTri[idx]) { 01216 if (!strstr(node_desc->texNameArray[idx], "noIcon")) 01217 set_shader_attributes(node_desc, *egg_poly, idx); 01218 else 01219 softegg_cat.spam() << "texname :" << node_desc->texNameArray[idx] << endl; 01220 } 01221 else { 01222 if (!strstr(node_desc->texNameArray[0], "noIcon")) 01223 set_shader_attributes(node_desc, *egg_poly, 0); 01224 else 01225 softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl; 01226 } 01227 } 01228 } 01229 // if model has key shapes, generate vertex offsets 01230 if ( numShapes > 0 && make_morph ) 01231 node_desc->make_vertex_offsets( numShapes); 01232 } 01233 } 01234 01235 //////////////////////////////////////////////////////////////////// 01236 // Function: SoftToEggConverter::make_nurb_surface 01237 // Access: Private 01238 // Description: Converts the indicated Soft nurbs set to a bunch of 01239 // EggPolygons and parents them to the indicated egg 01240 // group. 01241 //////////////////////////////////////////////////////////////////// 01242 void SoftToEggConverter:: 01243 make_nurb_surface(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) { 01244 int id = 0; 01245 int i, j, k; 01246 int numShapes; 01247 SAA_Boolean valid; 01248 SAA_Boolean visible; 01249 PN_stdfloat *uCoords = NULL; 01250 PN_stdfloat *vCoords = NULL; 01251 string name = node_desc->get_name(); 01252 01253 SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible ); 01254 softegg_cat.spam() << "model visibility: " << visible << endl; 01255 softegg_cat.spam() << "nurbs!!!surface!!!" << endl; 01256 01257 /////////////////////////////////////// 01258 // check to see if its a nurbs surface 01259 /////////////////////////////////////// 01260 if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs ) 01261 || ( !make_nurbs && !make_poly && make_duv )) ) 01262 { 01263 // Get the number of key shapes 01264 SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes ); 01265 softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl; 01266 01267 // load all node data from soft for this node_desc 01268 node_desc->load_nurbs_model(&scene, type); 01269 01270 string vpool_name = name + ".verts"; 01271 EggVertexPool *vpool = new EggVertexPool(vpool_name); 01272 vpool->set_highest_index(0); 01273 01274 // add the vertices in the _tree._egg_root node, so that 01275 // they will be written out first in egg file. This 01276 // solves a problem of soft-skinning trying to access 01277 // vertex pool before it is defined. 01278 01279 //_tree.get_egg_root()->add_child(vpool); 01280 _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool); 01281 01282 //egg_group->add_child(vpool); 01283 01284 /* 01285 // create a copy of vpool in node_desc which will be used later 01286 // for soft_skinning 01287 node_desc->create_vpool(vpool_name); 01288 */ 01289 01290 int uRows, vRows; 01291 int uKnots, vKnots; 01292 int uExtra, vExtra; 01293 int uDegree, vDegree; 01294 int uCurves, vCurves; 01295 01296 vector <double> Knots; 01297 01298 EggNurbsSurface *eggNurbs = new EggNurbsSurface( name ); 01299 01300 // create nurbs representation of surface 01301 SAA_nurbsSurfaceGetDegree( &scene, node_desc->get_model(), &uDegree, &vDegree ); 01302 softegg_cat.spam() << "nurbs degree: " << uDegree << " u, " << vDegree << " v\n"; 01303 01304 SAA_nurbsSurfaceGetNbKnots( &scene, node_desc->get_model(), &uKnots, &vKnots ); 01305 softegg_cat.spam() << "nurbs knots: " << uKnots << " u, " << vKnots << " v\n"; 01306 01307 SAA_Boolean uClosed = FALSE; 01308 SAA_Boolean vClosed = FALSE; 01309 01310 SAA_nurbsSurfaceGetClosed( &scene, node_desc->get_model(), &uClosed, &vClosed); 01311 01312 uExtra = vExtra = 2; 01313 if ( uClosed ) { 01314 softegg_cat.spam() << "nurbs is closed in u...\n"; 01315 uExtra += 4; 01316 } 01317 if ( vClosed ) { 01318 softegg_cat.spam() << "nurbs is closed in v...\n"; 01319 vExtra += 4; 01320 } 01321 eggNurbs->setup(uDegree+1, vDegree+1, 01322 uKnots + uExtra, vKnots + vExtra); 01323 01324 softegg_cat.spam() << "from eggNurbs: num u knots " << eggNurbs->get_num_u_knots() << endl; 01325 softegg_cat.spam() << "from eggNurbs: num v knots " << eggNurbs->get_num_v_knots() << endl; 01326 softegg_cat.spam() << "from eggNurbs: num u cvs " << eggNurbs->get_num_u_cvs() << endl; 01327 softegg_cat.spam() << "from eggNurbs: num v cvs " << eggNurbs->get_num_v_cvs() << endl; 01328 01329 SAA_nurbsSurfaceGetNbVertices( &scene, node_desc->get_model(), &uRows, &vRows ); 01330 softegg_cat.spam() << "nurbs vertices: " << uRows << " u, " << vRows << " v\n"; 01331 01332 SAA_nurbsSurfaceGetNbCurves( &scene, node_desc->get_model(), &uCurves, &vCurves ); 01333 softegg_cat.spam() << "nurbs curves: " << uCurves << " u, " << vCurves << " v\n"; 01334 01335 if ( shift_textures ) { 01336 if ( uClosed ) 01337 // shift starting point on NURBS surface for correct textures 01338 SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), -2, 0 ); 01339 01340 if ( vClosed ) 01341 // shift starting point on NURBS surface for correct textures 01342 SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), 0, -2 ); 01343 } 01344 01345 SAA_nurbsSurfaceSetStep( &scene, node_desc->get_model(), nurbs_step, nurbs_step ); 01346 01347 // Is this a double sided polygon? meaning check for back face flag 01348 char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() ); 01349 if ( modelNoteStr != NULL ) { 01350 if ( strstr( modelNoteStr, "bface" ) != NULL ) { 01351 eggNurbs->set_bface_flag(TRUE); 01352 softegg_cat.spam() << "Set backface flag\n"; 01353 } 01354 } 01355 01356 double *uKnotArray = new double[uKnots]; 01357 double *vKnotArray = new double[vKnots]; 01358 result = SAA_nurbsSurfaceGetKnots( &scene, node_desc->get_model(), node_desc->gtype, 0, 01359 uKnots, vKnots, uKnotArray, vKnotArray ); 01360 01361 if (result != SI_SUCCESS) { 01362 softegg_cat.spam() << "Couldn't get knots\n"; 01363 exit(1); 01364 } 01365 01366 // Lets prepare the softimage knots and then assign to eggKnots 01367 add_knots( Knots, uKnotArray, uKnots, uClosed, uDegree ); 01368 softegg_cat.spam() << "u knots: "; 01369 for (i = 0; i < (int)Knots.size(); i++) { 01370 softegg_cat.spam() << Knots[i] << " "; 01371 eggNurbs->set_u_knot(i, Knots[i]); 01372 } 01373 softegg_cat.spam() << endl; 01374 01375 Knots.resize(0); 01376 add_knots( Knots, vKnotArray, vKnots, vClosed, vDegree ); 01377 softegg_cat.spam() << "v knots: "; 01378 for (i = 0; i < (int)Knots.size(); i++) { 01379 softegg_cat.spam() << Knots[i] << " "; 01380 eggNurbs->set_v_knot(i, Knots[i]); 01381 } 01382 softegg_cat.spam() << endl; 01383 01384 // lets get the number of vertices from softimage 01385 int numVert; 01386 SAA_modelGetNbVertices( &scene, node_desc->get_model(), &numVert ); 01387 01388 softegg_cat.spam() << numVert << " CV's\n"; 01389 01390 // get the CV's 01391 SAA_DVector *vertices = NULL; 01392 vertices = new SAA_DVector[numVert]; 01393 01394 SAA_modelGetVertices( &scene, node_desc->get_model(), node_desc->gtype, 0, numVert, vertices ); 01395 01396 LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); 01397 01398 // create the buffer for EggVertices 01399 EggVertex *verts = new EggVertex[numVert]; 01400 01401 softegg_cat.spam() << endl << eggNurbs->get_num_cvs() << endl << endl; 01402 01403 //for ( i = 0; i<eggNurbs->get_num_cvs(); i++ ) { 01404 for ( k = 0; k<numVert; k++ ) { 01405 SAA_DVector global; 01406 01407 /* 01408 int ui = eggNurbs->get_u_index(i); 01409 int vi = eggNurbs->get_v_index(i); 01410 01411 int k = vRows * ui + vi; 01412 01413 softegg_cat.spam() << i << ": ui " << ui << ", vi " << vi << ", k " << k << endl; 01414 01415 softegg_cat.spam() << "original cv[" << k << "] = " 01416 << vertices[k].x << " " << vertices[k].y << " " 01417 << vertices[k].z << " " << vertices[k].w << endl; 01418 */ 01419 01420 // convert to global coords 01421 _VCT_X_MAT( global, vertices[k], node_desc->matrix ); 01422 01423 //preserve original weight 01424 global.w = vertices[k].w; 01425 01426 // normalize coords to weight 01427 global.x *= global.w; 01428 global.y *= global.w; 01429 global.z *= global.w; 01430 01431 /* 01432 softegg_cat.spam() << "global cv[" << k << "] = " 01433 << global.x << " " << global.y << " " 01434 << global.x << " " << global.w << endl; 01435 */ 01436 01437 LPoint4d p4d(global.x, global.y, global.z, global.w); 01438 p4d = p4d * vertex_frame_inv; 01439 verts[k].set_pos(p4d); 01440 01441 // check to see if material is present 01442 if (node_desc->numNurbMats) { 01443 PN_stdfloat r,g,b,a; 01444 SAA_elementIsValid( &scene, &node_desc->materials[0], &valid ); 01445 // material present - get the color 01446 if ( valid ) { 01447 SAA_materialGetDiffuse( &scene, &node_desc->materials[0], &r, &g, &b ); 01448 SAA_materialGetTransparency( &scene, &node_desc->materials[0], &a ); 01449 verts[k].set_color(LColor(r, g, b, 1.0f - a)); 01450 //softegg_cat.spam() << "color r = " << r << " g = " << g << " b = " << b << " a = " << a << "\n"; 01451 } 01452 else { // no material - default to white 01453 verts[k].set_color(LColor(1.0, 1.0, 1.0, 1.0)); 01454 softegg_cat.spam() << "default color\n"; 01455 } 01456 } 01457 vpool->add_vertex(verts+k, k); 01458 eggNurbs->add_vertex(vpool->get_vertex(k)); 01459 01460 if ( uClosed ) { 01461 // add first uDegree verts to end of row 01462 if ( (k % uRows) == ( uRows - 1) ) { 01463 for ( i = 0; i < uDegree; i++ ) { 01464 // add vref's to NURBS info 01465 eggNurbs->add_vertex( vpool->get_vertex(i+((k/uRows)*uRows)) ); 01466 } 01467 } 01468 } 01469 } 01470 01471 // check to see if the NURB is closed in v 01472 if ( vClosed && !uClosed ) { 01473 // add first vDegree rows of verts to end of list 01474 for ( int i = 0; i < vDegree*uRows; i++ ) 01475 eggNurbs->add_vertex( vpool->get_vertex(i) ); 01476 } 01477 // check to see if the NURB is closed in u and v 01478 else if ( vClosed && uClosed ) { 01479 // add the first (degree) v verts and a few 01480 // extra - for good measure 01481 for ( i = 0; i < vDegree; i++ ) { 01482 // add first vDegree rows of verts to end of list 01483 for ( j = 0; j < uRows; j++ ) 01484 eggNurbs->add_vertex( vpool->get_vertex(j+(i*uRows)) ); 01485 01486 // if u is closed to we have added uDegree 01487 // verts onto the ends of the rows - add them here too 01488 for ( k = 0; k < uDegree; k++ ) 01489 eggNurbs->add_vertex( vpool->get_vertex(k+(i*uRows)+((k/uRows)*uRows)) ); 01490 } 01491 } 01492 01493 // We add the NURBS to the group down here, after all of the vpools 01494 // for the trim curves have been added. 01495 egg_group->add_child(eggNurbs); 01496 01497 // Now apply the shader. 01498 if (node_desc->textures != NULL) { 01499 if (!strstr(node_desc->texNameArray[0], "noIcon")) 01500 set_shader_attributes(node_desc, *eggNurbs, 0); 01501 else 01502 softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl; 01503 } 01504 01505 // if model has key shapes, generate vertex offsets 01506 if ( numShapes > 0 && make_morph ) 01507 node_desc->make_vertex_offsets( numShapes); 01508 } 01509 } 01510 01511 //////////////////////////////////////////////////////////////////// 01512 // Function: add_knots 01513 // Access: Public 01514 // Description: Given a parametric surface, and its knots, create 01515 // the appropriate egg structure by filling in Soft's 01516 // implicit knots and assigning the rest to eggKnots. 01517 //////////////////////////////////////////////////////////////////// 01518 void SoftToEggConverter:: 01519 add_knots( vector <double> &eggKnots, double *knots, int numKnots, SAA_Boolean closed, int degree ) { 01520 01521 int k = 0; 01522 double lastKnot = knots[0]; 01523 double *newKnots; 01524 01525 // add initial implicit knot(s) 01526 if ( closed ) { 01527 int i = 0; 01528 newKnots = new double[degree]; 01529 01530 // need to add (degree) number of knots 01531 for ( k = numKnots - 1; k >= numKnots - degree; k-- ) { 01532 // we have to know these in order to calculate 01533 // next knot value so hold them in temp array 01534 newKnots[i] = lastKnot - (knots[k] - knots[k-1]); 01535 lastKnot = newKnots[i]; 01536 i++; 01537 } 01538 for ( k = degree - 1; k >= 0; k-- ) { 01539 eggKnots.push_back( newKnots[k] ); 01540 softegg_cat.spam() << "knots[" << k << "] = " << newKnots[k] << endl; 01541 } 01542 } 01543 else { 01544 eggKnots.push_back( knots[k] ); 01545 softegg_cat.spam() << "knots[" << k << "] = " << knots[k] << endl; 01546 } 01547 01548 // add the regular complement of knots 01549 for (k = 0; k < numKnots; k++) { 01550 eggKnots.push_back( knots[k] ); 01551 softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k] << endl; 01552 } 01553 01554 lastKnot = knots[numKnots-1]; 01555 01556 // add trailing implicit knots 01557 if ( closed ) { 01558 // need to add (degree) number of knots 01559 for ( k = 1; k <= degree; k++ ) { 01560 eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) ); 01561 softegg_cat.spam() << "knots[" << k << "] = " << lastKnot + (knots[k] - knots[k-1]) << endl; 01562 lastKnot = lastKnot + (knots[k] - knots[k-1]); 01563 } 01564 } 01565 else { 01566 eggKnots.push_back( knots[k-1] ); 01567 softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k-1] << endl; 01568 } 01569 } 01570 01571 //////////////////////////////////////////////////////////////////// 01572 // Function: FindClosestTriVert 01573 // Access: Public 01574 // Description: Given an egg vertex pool, map each vertex therein to 01575 // a vertex within an array of SAA model vertices of 01576 // size numVert. Mapping is done by closest proximity. 01577 //////////////////////////////////////////////////////////////////// 01578 int *SoftToEggConverter:: 01579 FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ) { 01580 int i,j; 01581 int *vertMap = NULL; 01582 int vpoolSize = (int)vpool->size(); 01583 PN_stdfloat closestDist; 01584 PN_stdfloat thisDist; 01585 int closest; 01586 01587 vertMap = new int[vpoolSize]; 01588 i = 0; 01589 EggVertexPool::iterator vi; 01590 for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++i) { 01591 EggVertex *vert = (*vi); 01592 softegg_cat.spam() << "vert external index = " << vert->get_external_index() << endl; 01593 // softegg_cat.spam() << "found vert " << vert << endl; 01594 // softegg_cat.spam() << "vert [" << i << "] " << vpool->get_vertex(i+1); 01595 LPoint3d p3d = vert->get_pos3(); 01596 01597 // find closest model vertex 01598 for ( j = 0; j < numVert; j++ ) { 01599 // calculate distance 01600 thisDist = sqrtf( 01601 powf( p3d[0] - vertices[j].x , 2 ) + 01602 powf( p3d[1] - vertices[j].y , 2 ) + 01603 powf( p3d[2] - vertices[j].z , 2 ) ); 01604 01605 // remember this if its the closest so far 01606 if ( !j || ( thisDist < closestDist ) ) { 01607 closest = j; 01608 closestDist = thisDist; 01609 } 01610 } 01611 01612 vertMap[i] = closest; 01613 softegg_cat.spam() << "mapping v " << i << " of " << vpoolSize-1 << ":( " 01614 << p3d[0] << " " 01615 << p3d[1] << " " 01616 << p3d[2] << ")\n"; 01617 01618 softegg_cat.spam() << " to cv " << closest << " of " << numVert-1 << ":( " 01619 << vertices[closest].x << " " 01620 << vertices[closest].y << " " 01621 << vertices[closest].z << " )\tdelta = " << closestDist << endl; 01622 } 01623 return vertMap; 01624 } 01625 01626 //////////////////////////////////////////////////////////////////// 01627 // Function: SoftToEggConverter::make_soft_skin 01628 // Access: Private 01629 // Description: make soft skin assignments to the mesh 01630 // finally call cleanup_soft_skin to clean it up 01631 //////////////////////////////////////////////////////////////////// 01632 bool SoftToEggConverter:: 01633 make_soft_skin() { 01634 int num_nodes = _tree.get_num_nodes(); 01635 SoftNodeDesc *node_desc; 01636 SAA_Boolean isSkeleton; 01637 01638 softegg_cat.spam() << endl << "----------------------------------------------------------------" << endl; 01639 01640 for (int i = 0; i < num_nodes; i++) { 01641 node_desc = _tree.get_node(i); 01642 SAA_modelIsSkeleton( &scene, node_desc->get_model(), &isSkeleton ); 01643 01644 softegg_cat.spam() << "??checking node " << node_desc->get_name() << " isSkel " << isSkeleton << " isJoint " << node_desc->is_joint() << endl; 01645 if (isSkeleton && node_desc->is_joint()) { 01646 01647 if (node_desc->is_partial(search_prefix)) 01648 continue; 01649 01650 // Now that we've added all the polygons (and created all the 01651 // vertices), go back through the vertex pool and set up the 01652 // appropriate joint membership for each of the vertices. 01653 01654 // check for envelops 01655 int numEnv; 01656 SAA_ModelType type; 01657 SAA_Elem *envelopes; 01658 SAA_Elem *model = node_desc->get_model(); 01659 EggGroup *joint = NULL; 01660 EggVertexPool *vpool; 01661 01662 SAA_skeletonGetNbEnvelopes( &scene, model, &numEnv ); 01663 if ( numEnv == 0 ) { 01664 softegg_cat.spam() << "no soft skinning for joint " << node_desc->get_name() << endl; 01665 continue; 01666 } 01667 01668 // it's got envelopes - must be soft skinned 01669 softegg_cat.spam() << endl << "found skeleton part( " << node_desc->get_name() << ")!\n"; 01670 softegg_cat.spam() << "numEnv = " << numEnv << endl; 01671 // allocate envelope array 01672 envelopes = new SAA_Elem[numEnv]; 01673 if ( envelopes == NULL ) { 01674 softegg_cat.info() << "Out Of Memory" << endl; 01675 exit(1); 01676 } 01677 int thisEnv; 01678 SAA_EnvType envType; 01679 bool hasEnvVertices = 0; 01680 01681 SAA_skeletonGetEnvelopes( &scene, model, numEnv, envelopes ); 01682 for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ ) { 01683 softegg_cat.spam() << "env[" << thisEnv << "]: "; 01684 SAA_envelopeGetType( &scene, &envelopes[thisEnv], &envType ); 01685 01686 if ( envType == SAA_ENVTYPE_NONE ) { 01687 softegg_cat.spam() << "envType = none\n"; 01688 } 01689 else if ( envType == SAA_ENVTYPE_FLXLCL ) { 01690 softegg_cat.spam() << "envType = flexible, local\n"; 01691 hasEnvVertices = 1; 01692 } 01693 else if ( envType == SAA_ENVTYPE_FLXGLB ) { 01694 softegg_cat.spam() << "envType = flexible, global\n"; 01695 hasEnvVertices = 1; 01696 } 01697 else if ( envType == SAA_ENVTYPE_RGDGLB ) { 01698 softegg_cat.spam() << "envType = rigid, global\n"; 01699 hasEnvVertices = 1; 01700 } 01701 else { 01702 softegg_cat.spam() << "envType = unknown\n"; 01703 } 01704 01705 } 01706 if ( !hasEnvVertices ) 01707 continue; 01708 01709 SAA_SubElem *envVertices = NULL; 01710 int *numEnvVertices; 01711 int i,j,k; 01712 01713 numEnvVertices = new int[numEnv]; 01714 01715 if ( numEnvVertices != NULL ) { 01716 SAA_envelopeGetNbCtrlVertices( &scene, model, numEnv, envelopes, numEnvVertices ); 01717 int totalEnvVertices = 0; 01718 for( i = 0; i < numEnv; i++ ) { 01719 totalEnvVertices += numEnvVertices[i]; 01720 softegg_cat.spam() << "numEnvVertices[" << i << "] = " << numEnvVertices[i] << endl; 01721 } 01722 softegg_cat.spam() << "total env verts = " << totalEnvVertices << endl; 01723 if ( totalEnvVertices == 0 ) 01724 continue; 01725 01726 envVertices = new SAA_SubElem[totalEnvVertices]; 01727 if ( envVertices != NULL ) { 01728 result = SAA_envelopeGetCtrlVertices( &scene, model, 01729 numEnv, envelopes, numEnvVertices, envVertices); 01730 if (result != SI_SUCCESS) { 01731 softegg_cat.spam() << "error: GetCtrlVertices\n"; 01732 exit(1); 01733 } 01734 // loop through for each envelope 01735 for ( i = 0; i < numEnv; i++ ) { 01736 PN_stdfloat *weights = NULL; 01737 int vertArrayOffset = 0; 01738 softegg_cat.spam() << "envelope[" << i << "]: "; 01739 weights = new PN_stdfloat[numEnvVertices[i]]; 01740 if ( weights ) { 01741 char *envName; 01742 int *vpoolMap = NULL; 01743 for ( j = 0; j < i; j++ ) 01744 vertArrayOffset += numEnvVertices[j]; 01745 softegg_cat.spam() << "envVertArray offset = " << vertArrayOffset; 01746 01747 /* 01748 if (vertArrayOffset == totalEnvVertices) { 01749 softegg_cat.spam() << endl; vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert ); 01750 01751 break; 01752 } 01753 */ 01754 01755 // get the weights of the envelope vertices 01756 result = SAA_ctrlVertexGetEnvelopeWeights( &scene, model, &envelopes[i], 01757 numEnvVertices[i], 01758 &envVertices[vertArrayOffset], weights ); 01759 01760 // Get the name of the envelope model 01761 if ( use_prefix ) { 01762 // Get the FULL name of the envelope 01763 envName = _tree.GetFullName( &scene, &envelopes[i] ); 01764 } 01765 else { 01766 // Get the name of the envelope 01767 envName = _tree.GetName( &scene, &envelopes[i] ); 01768 } 01769 01770 softegg_cat.spam() << " envelop name is [" << envName << "]" << endl; 01771 01772 if (result != SI_SUCCESS) { 01773 softegg_cat.spam() << "warning: this envelop doesn't have any weights\n"; 01774 continue; 01775 } 01776 01777 result = SAA_modelGetType( &scene, &envelopes[i], &type ); 01778 if (result != SI_SUCCESS) { 01779 softegg_cat.debug() << "choked on get type\n"; 01780 exit(1); 01781 } 01782 01783 softegg_cat.spam() << "envelope model type "; 01784 if ( type == SAA_MSMSH ) 01785 softegg_cat.spam() << "MESH\n"; 01786 else if ( type == SAA_MNSRF ) 01787 softegg_cat.spam() << "NURBS\n"; 01788 else 01789 softegg_cat.spam() << "OTHER\n"; 01790 01791 int *envVtxIndices = NULL; 01792 envVtxIndices = new int[numEnvVertices[i]]; 01793 01794 // Get the envelope vertex indices 01795 result = SAA_ctrlVertexGetIndices( &scene, &envelopes[i], numEnvVertices[i], 01796 &envVertices[vertArrayOffset], envVtxIndices ); 01797 01798 if (result != SI_SUCCESS) { 01799 softegg_cat.debug() << "error: choked on get indices\n"; 01800 exit(1); 01801 } 01802 01803 // find out how many vertices the model has 01804 int modelNumVert; 01805 01806 SAA_modelGetNbVertices( &scene, &envelopes[i], &modelNumVert ); 01807 01808 SAA_DVector *modelVertices = NULL; 01809 modelVertices = new SAA_DVector[modelNumVert]; 01810 01811 // get the model vertices 01812 SAA_modelGetVertices( &scene, &envelopes[i], 01813 SAA_GEOM_ORIGINAL, 0, modelNumVert, 01814 modelVertices ); 01815 01816 // create array of global model coords 01817 SAA_DVector *globalModelVertices = NULL; 01818 globalModelVertices = new SAA_DVector[modelNumVert]; 01819 PN_stdfloat matrix[4][4]; 01820 01821 // tranform local model vert coords to global 01822 01823 // first get the global matrix 01824 SAA_modelGetMatrix( &scene, &envelopes[i], SAA_COORDSYS_GLOBAL, matrix ); 01825 01826 // populate array of global model verts 01827 for ( j = 0; j < modelNumVert; j++ ) { 01828 _VCT_X_MAT( globalModelVertices[j], 01829 modelVertices[j], matrix ); 01830 } 01831 01832 // Get the vpool 01833 string s_name = envName; 01834 SoftNodeDesc *mesh_node = find_node(s_name); 01835 if (!mesh_node) { 01836 softegg_cat.debug() << "error: node " << s_name << " not found in tree\n"; 01837 exit(1); 01838 } 01839 string vpool_name = s_name + ".verts"; 01840 EggNode *t = _tree.get_egg_root()->find_child(vpool_name); 01841 if (t) 01842 DCAST_INTO_R(vpool, t, NULL); 01843 01844 // find the mapping of the vertices that match this envelop 01845 if (vpool) { 01846 softegg_cat.spam() << "found vpool of size " << vpool->size() << endl; 01847 if ( !make_nurbs || (type == SAA_MSMSH) ) { 01848 vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert ); 01849 } 01850 } 01851 else { 01852 softegg_cat.debug() << "warning: vpool " << vpool_name << " not found\n"; 01853 continue; // could be because of not visible 01854 } 01855 01856 joint = node_desc->get_egg_group(); 01857 // for every envelope vertex 01858 for (j = 0; j < numEnvVertices[i]; j++) { 01859 double scaledWeight = weights[j]/ 100.0f; 01860 01861 // make sure its in legal range 01862 if (( envVtxIndices[j] < modelNumVert ) 01863 && ( envVtxIndices[j] >= 0 )) { 01864 if ( (type == SAA_MNSRF) && make_nurbs ) { 01865 // assign all referenced control vertices 01866 EggVertex *vert = vpool->get_vertex(envVtxIndices[j]); 01867 if (!vert) { 01868 softegg_cat.debug() << "possible error: index " << envVtxIndices[j] << ": vert is " << vert << endl; 01869 continue; 01870 } 01871 joint->ref_vertex( vert, scaledWeight ); 01872 softegg_cat.spam() << j << ": adding vref to cv " << envVtxIndices[j] 01873 << " with weight " << scaledWeight << endl; 01874 01875 /* 01876 envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight ); 01877 // set flag to show this vertex has 01878 // been assigned 01879 envPool->Vertex(envVtxIndices[j])->multipleJoints = 1; 01880 */ 01881 } 01882 else { 01883 //assign all the tri verts associated 01884 // with this control vertex to joint 01885 softegg_cat.spam() << j << "--trying to find " << envVtxIndices[j] << endl; 01886 for ( k = 0; k < (int)vpool->size(); k++ ) { 01887 if ( vpoolMap[k] == envVtxIndices[j] ) { 01888 EggVertex *vert = vpool->get_vertex(k+1); 01889 // EggVertex *vert = mesh_node->get_vpool()->get_vertex(vpoolMap[k]+1); 01890 if (!vert) { 01891 softegg_cat.debug() << "possible error: index " << k+1 << ": vert is " << vert << endl; 01892 break; 01893 } 01894 01895 joint->ref_vertex(vert, scaledWeight); 01896 softegg_cat.spam() << j << ": adding vref from cv " << envVtxIndices[j] 01897 << " to vert " << k+1 << " with weight " << scaledWeight 01898 << "(vpool)\n"; 01899 /* 01900 envPool->Vertex(k)->AddJoint( joint, scaledWeight ); 01901 // set flag to show this vertex has 01902 // been assigned 01903 envPool->Vertex(k)->multipleJoints = 1; 01904 */ 01905 } 01906 } 01907 } 01908 } 01909 } 01910 } 01911 } 01912 } 01913 } 01914 } 01915 } 01916 return true; 01917 } 01918 //////////////////////////////////////////////////////////////////// 01919 // Function: cleanup_soft_skin 01920 // Access: Public 01921 // Description: Given a model, make sure all its vertices have been 01922 // soft assigned. If not hard assign to the last 01923 // joint we saw. 01924 //////////////////////////////////////////////////////////////////// 01925 bool SoftToEggConverter:: 01926 cleanup_soft_skin() 01927 { 01928 int num_nodes = _tree.get_num_nodes(); 01929 SoftNodeDesc *node_desc; 01930 01931 softegg_cat.spam() << endl << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl; 01932 01933 for (int i = 0; i < num_nodes; i++) { 01934 node_desc = _tree.get_node(i); 01935 if (node_desc->is_partial(search_prefix)) 01936 continue; 01937 01938 SAA_Elem *model = node_desc->get_model(); 01939 EggGroup *joint = NULL; 01940 EggVertexPool *vpool = NULL; 01941 SAA_ModelType type; 01942 01943 // find out what type of node we're dealing with 01944 01945 SAA_modelGetType( &scene, model, &type ); 01946 01947 softegg_cat.debug() << "Cleaning up model------- " << node_desc->get_name() << endl; 01948 01949 // this step is weird - I think I want it here but it seems 01950 // to break some models. Files like props-props_wh_cookietime.3-0 in 01951 // /ful/rnd/pub/vrml/chip/chips_adventure/char/zone1/rooms/warehouse_final 01952 // need to do the "if (skel)" bit. 01953 01954 //find the vpool for this model 01955 string vpool_name = node_desc->get_name() + ".verts"; 01956 EggNode *t = _tree.get_egg_root()->find_child(vpool_name); 01957 if (t) 01958 DCAST_INTO_R(vpool, t, NULL); 01959 01960 if (!vpool) { 01961 //softegg_cat.spam() << "couldn't find vpool " << vpool_name << endl; 01962 continue; 01963 } 01964 01965 int numVerts = (int)vpool->size(); 01966 softegg_cat.spam() << "found vpool " << vpool_name << " w/ " << numVerts << " verts\n"; 01967 01968 // if this node is a joint, then these vertices belong 01969 // to this joint 01970 if (node_desc->is_joint()) 01971 joint = node_desc->get_egg_group(); 01972 else { 01973 // find the closest _parentJoint 01974 SoftNodeDesc *parentJ = node_desc; 01975 while( parentJ && !parentJ->_parentJoint) { 01976 if ( parentJ->_parent) { 01977 SAA_Boolean isSkeleton; 01978 //softegg_cat.spam() << " checking parent " << parentJ->_parent->get_name() << endl; 01979 if (parentJ->_parent->has_model()) 01980 SAA_modelIsSkeleton( &scene, parentJ->_parent->get_model(), &isSkeleton ); 01981 01982 if (isSkeleton) { 01983 joint = parentJ->_parent->get_egg_group(); 01984 softegg_cat.spam() << "parent to " << parentJ->_parent->get_name() << endl; 01985 break; 01986 } 01987 01988 parentJ = parentJ->_parent; 01989 } 01990 else 01991 break; 01992 } 01993 if (!joint && (!parentJ || !parentJ->_parentJoint)) { 01994 softegg_cat.spam() << node_desc->get_name() << " has no _parentJoint?!" << endl; 01995 continue; 01996 } 01997 01998 if (!joint) { 01999 softegg_cat.spam() << "parent joint to " << parentJ->_parentJoint->get_name() << endl; 02000 joint = parentJ->_parentJoint->get_egg_group(); 02001 } 02002 } 02003 EggVertexPool::iterator vi; 02004 double membership = 1.0f; 02005 for ( vi = vpool->begin(); vi != vpool->end(); ++vi) { 02006 EggVertex *vert = (*vi); 02007 02008 // if this vertex has not been soft assigned, then hard assign it to the parentJoint 02009 if ( vert->gref_size() == 0 ) { 02010 02011 softegg_cat.spam() << "vert " << vert->get_external_index() << " not assigned!\n"; 02012 02013 // hard skin this vertex 02014 joint->ref_vertex( vert, 1.0f ); 02015 } 02016 } 02017 } 02018 return true; 02019 } 02020 02021 //////////////////////////////////////////////////////////////////// 02022 // Function: SoftShader::set_shader_attributes 02023 // Access: Private 02024 // Description: Applies the known shader attributes to the indicated 02025 // egg primitive. 02026 //////////////////////////////////////////////////////////////////// 02027 void SoftToEggConverter:: 02028 set_shader_attributes(SoftNodeDesc *node_desc, EggPrimitive &primitive, int idx) { 02029 char *texName = node_desc->texNameArray[idx]; 02030 EggTexture tex(texName, ""); 02031 02032 Filename filename = Filename::from_os_specific(texName); 02033 Filename fullpath = _path_replace->match_path(filename, get_model_path()); 02034 tex.set_filename(_path_replace->store_path(fullpath)); 02035 tex.set_fullpath(fullpath); 02036 // tex.set_format(EggTexture::F_rgb); 02037 apply_texture_properties(tex, node_desc->uRepeat[idx], node_desc->vRepeat[idx]); 02038 02039 EggTexture *new_tex = _textures.create_unique_texture(tex, ~EggTexture::E_tref_name); 02040 primitive.set_texture(new_tex); 02041 } 02042 02043 //////////////////////////////////////////////////////////////////// 02044 // Function: SoftShader::apply_texture_properties 02045 // Access: Private 02046 // Description: Applies all the appropriate texture properties to the 02047 // EggTexture object, including wrap modes and texture 02048 // matrix. 02049 //////////////////////////////////////////////////////////////////// 02050 void SoftToEggConverter:: 02051 apply_texture_properties(EggTexture &tex, int uRepeat, int vRepeat) { 02052 // Let's mipmap all textures by default. 02053 tex.set_minfilter(EggTexture::FT_linear_mipmap_linear); 02054 tex.set_magfilter(EggTexture::FT_linear); 02055 02056 EggTexture::WrapMode wrap_u = uRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp; 02057 EggTexture::WrapMode wrap_v = vRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp; 02058 02059 tex.set_wrap_u(wrap_u); 02060 tex.set_wrap_v(wrap_v); 02061 /* 02062 LMatrix3d mat = color_def.compute_texture_matrix(); 02063 if (!mat.almost_equal(LMatrix3d::ident_mat())) { 02064 tex.set_transform(mat); 02065 } 02066 */ 02067 } 02068 #if 0 02069 //////////////////////////////////////////////////////////////////// 02070 // Function: SoftShader::compare_texture_properties 02071 // Access: Private 02072 // Description: Compares the texture properties already on the 02073 // texture (presumably set by a previous call to 02074 // apply_texture_properties()) and returns false if they 02075 // differ from that specified by the indicated color_def 02076 // object, or true if they match. 02077 //////////////////////////////////////////////////////////////////// 02078 bool SoftToEggConverter:: 02079 compare_texture_properties(EggTexture &tex, 02080 const SoftShaderColorDef &color_def) { 02081 bool okflag = true; 02082 02083 EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp; 02084 EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp; 02085 02086 if (wrap_u != tex.determine_wrap_u()) { 02087 // Choose the more general of the two. 02088 if (wrap_u == EggTexture::WM_repeat) { 02089 tex.set_wrap_u(wrap_u); 02090 } 02091 okflag = false; 02092 } 02093 if (wrap_v != tex.determine_wrap_v()) { 02094 if (wrap_v == EggTexture::WM_repeat) { 02095 tex.set_wrap_v(wrap_v); 02096 } 02097 okflag = false; 02098 } 02099 02100 LMatrix3d mat = color_def.compute_texture_matrix(); 02101 if (!mat.almost_equal(tex.get_transform())) { 02102 okflag = false; 02103 } 02104 02105 return okflag; 02106 } 02107 #endif 02108 //////////////////////////////////////////////////////////////////// 02109 // Function: SoftShader::reparent_decals 02110 // Access: Private 02111 // Description: Recursively walks the egg hierarchy, reparenting 02112 // "decal" type nodes below their corresponding 02113 // "decalbase" type nodes, and setting the flags. 02114 // 02115 // Returns true on success, false if some nodes were 02116 // incorrect. 02117 //////////////////////////////////////////////////////////////////// 02118 bool SoftToEggConverter:: 02119 reparent_decals(EggGroupNode *egg_parent) { 02120 bool okflag = true; 02121 02122 // First, walk through all children of this node, looking for the 02123 // one decal base, if any. 02124 EggGroup *decal_base = (EggGroup *)NULL; 02125 pvector<EggGroup *> decal_children; 02126 02127 EggGroupNode::iterator ci; 02128 for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { 02129 EggNode *child = (*ci); 02130 if (child->is_of_type(EggGroup::get_class_type())) { 02131 EggGroup *child_group = DCAST(EggGroup, child); 02132 if (child_group->has_object_type("decalbase")) { 02133 if (decal_base != (EggNode *)NULL) { 02134 softegg_cat.error() 02135 << "Two children of " << egg_parent->get_name() 02136 << " both have decalbase set: " << decal_base->get_name() 02137 << " and " << child_group->get_name() << "\n"; 02138 okflag = false; 02139 } 02140 child_group->remove_object_type("decalbase"); 02141 decal_base = child_group; 02142 02143 } else if (child_group->has_object_type("decal")) { 02144 child_group->remove_object_type("decal"); 02145 decal_children.push_back(child_group); 02146 } 02147 } 02148 } 02149 02150 if (decal_base == (EggGroup *)NULL) { 02151 if (!decal_children.empty()) { 02152 softegg_cat.warning() 02153 << decal_children.front()->get_name() 02154 << " has decal, but no sibling node has decalbase.\n"; 02155 } 02156 02157 } else { 02158 if (decal_children.empty()) { 02159 softegg_cat.warning() 02160 << decal_base->get_name() 02161 << " has decalbase, but no sibling nodes have decal.\n"; 02162 02163 } else { 02164 // All the decal children get moved to be a child of decal base. 02165 // This usually will not affect the vertex positions, but it 02166 // could if the decal base has a transform and the decal child 02167 // is an instance node. So don't do that. 02168 pvector<EggGroup *>::iterator di; 02169 for (di = decal_children.begin(); di != decal_children.end(); ++di) { 02170 EggGroup *child_group = (*di); 02171 decal_base->add_child(child_group); 02172 } 02173 02174 // Also set the decal state on the base. 02175 decal_base->set_decal_flag(true); 02176 } 02177 } 02178 02179 // Now recurse on each of the child nodes. 02180 for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { 02181 EggNode *child = (*ci); 02182 if (child->is_of_type(EggGroupNode::get_class_type())) { 02183 EggGroupNode *child_group = DCAST(EggGroupNode, child); 02184 if (!reparent_decals(child_group)) { 02185 okflag = false; 02186 } 02187 } 02188 } 02189 02190 return okflag; 02191 } 02192 02193 //////////////////////////////////////////////////////////////////// 02194 // Function: SoftShader::string_transform_type 02195 // Access: Public, Static 02196 // Description: Returns the TransformType value corresponding to the 02197 // indicated string, or TT_invalid. 02198 //////////////////////////////////////////////////////////////////// 02199 SoftToEggConverter::TransformType SoftToEggConverter:: 02200 string_transform_type(const string &arg) { 02201 if (cmp_nocase(arg, "all") == 0) { 02202 return TT_all; 02203 } else if (cmp_nocase(arg, "model") == 0) { 02204 return TT_model; 02205 } else if (cmp_nocase(arg, "dcs") == 0) { 02206 return TT_dcs; 02207 } else if (cmp_nocase(arg, "none") == 0) { 02208 return TT_none; 02209 } else { 02210 return TT_invalid; 02211 } 02212 } 02213 02214 ///////////////////////////////////////////////////////////////////////// 02215 // Function: init_soft2egg 02216 // Access: 02217 // Description: Invokes the softToEggConverter class 02218 ///////////////////////////////////////////////////////////////////////// 02219 extern "C" int init_soft2egg (int argc, char **argv) 02220 { 02221 stec._commandName = argv[0]; 02222 stec.rsrc_path = "c:\\Softimage\\SOFT3D_3.9.2\\3D\\rsrc"; 02223 if (stec.DoGetopts(argc, argv)) { 02224 02225 // create a Filename object and convert the file 02226 Filename softFile(argv[1]); 02227 stec.convert_file(softFile); 02228 } 02229 02230 return 0; 02231 } 02232 // 02233 // 02234 //