Panda3D

softToEggConverter.cxx

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 &copy) :
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 //
 All Classes Functions Variables Enumerations