Panda3D

soft2Egg.c

00001 // Filename: soft2Egg.c
00002 // Created by:  masad (26Sep03)
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 // Includes
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include <SAA.h>
00020 
00021 #ifdef __cplusplus
00022 extern "C" {
00023 #endif
00024 
00025 #include "pandatoolbase.h"
00026 
00027 int init_soft2egg(int, char **);
00028 
00029 #if 0
00030 // DWD includes
00031 #include "eggBase.h"
00032 #include <eggParametrics.h>
00033 #include <animTable.h>
00034 #include <linMathOutput.h>
00035 
00036 // system includes
00037 #include <fstream.h>
00038 #include <strstream.h>
00039 #include <math.h>
00040 #include <assert.h>
00041 #include <unistd.h>
00042 #include <ieeefp.h>
00043 
00044 // Performer includes
00045 #include <Performer/pr/pfLinMath.h>
00046 
00047 // SoftImage includes
00048 #include <SAA.h>
00049 #include <SI_macros.h>
00050 
00051 static const int    TEX_PER_MAT = 1;
00052 static FILE            *outStream  = stdout;
00053 //static FILE        *outStream  = stderr;
00054 
00055 class soft2egg : public EggBase
00056 {
00057   public:
00058 
00059     soft2egg() : EggBase("r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD")
00060     {
00061         rsrc_path = "/ful/ufs/soft371_mips2/3D/rsrc";
00062         database_name = NULL;
00063         scene_name = NULL;
00064         model_name = NULL;
00065         animFileName = NULL;
00066         eggFileName = NULL;
00067         tex_path = NULL;
00068         eggGroupName = NULL;
00069         tex_filename = NULL;
00070         search_prefix = NULL;
00071         result = SI_SUCCESS;
00072     
00073         skeleton = new EggGroup();
00074         foundRoot = FALSE;
00075         animRoot = NULL;
00076         morphRoot = NULL;
00077         geom_as_joint = 0;
00078         make_anim = 0;
00079         make_nurbs = 0;
00080         make_poly = 0;
00081         make_soft = 0;
00082         make_morph = 1;
00083         make_duv = 1;
00084         make_dart = TRUE;
00085         has_morph = 0;
00086         make_pose = 0;
00087         animData.is_z_up = FALSE;
00088         nurbs_step = 1;
00089         anim_start = -1000;
00090         anim_end = -1000;
00091         anim_rate = 24;
00092         pose_frame = -1;
00093         verbose = 0;
00094         flatten = 0;
00095         shift_textures = 0;
00096         ignore_tex_offsets = 0;
00097         use_prefix = 0;
00098     }
00099 
00100     virtual void Help();
00101     virtual void Usage();
00102     virtual void ShowOpts();
00103 
00104     virtual boolean UseOutputSwitch() const {
00105        return false;
00106     }
00107 
00108     virtual boolean
00109     HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv);
00110 
00111     int   isNum( float );
00112     char *GetRootName( const char * );
00113     char *RemovePathName( const char * );
00114     char *GetSliderName( const char * );
00115     char *GetFullName( SAA_Scene *, SAA_Elem * );
00116     char *GetName( SAA_Scene *, SAA_Elem * );
00117     char *GetModelNoteInfo( SAA_Scene *, SAA_Elem * );
00118     char *MakeTableName( const char *, int );
00119     char *DepointellizeName( char * );
00120     SAA_Elem *FindModelByName( char *, SAA_Scene *, SAA_Elem *, int );
00121     char *ConvertTexture( SAA_Scene *, SAA_Elem * );
00122     int  *FindClosestTriVert( EggVertexPool *, SAA_DVector *, int );
00123     int  *MakeIndexMap( int *, int, int );
00124     int     findShapeVert( SAA_DVector, SAA_DVector *, int );
00125     void LoadSoft();
00126     void MakeEgg( EggGroup *, EggJoint *, AnimGroup *, SAA_Scene *, SAA_Elem * );
00127     void MakeSurfaceCurve(  SAA_Scene *, SAA_Elem *, EggGroup *,
00128         EggNurbsSurface *&, int , SAA_SubElem *, bool );
00129 
00130     EggNurbsCurve *MakeUVNurbsCurve( int, long *,  double *, double *, 
00131         EggGroup *, char * );
00132 
00133     EggNurbsCurve *MakeNurbsCurve( SAA_Scene *, SAA_Elem *, EggGroup *,
00134         float [4][4], char * );
00135 
00136     void AddKnots( perf_vector<double> &, double *, int, SAA_Boolean, int );
00137     void MakeJoint( SAA_Scene *, EggJoint *&, AnimGroup *&, SAA_Elem *, char * );
00138     void MakeSoftSkin( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char * );
00139     void CleanUpSoftSkin( SAA_Scene *, SAA_Elem *, char * );
00140     void MakeAnimTable( SAA_Scene *, SAA_Elem *, char * );
00141     void MakeVertexOffsets( SAA_Scene *, SAA_Elem *, SAA_ModelType type,
00142         int, int, SAA_DVector *, float (*)[4], char * );
00143     void MakeMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,  char *, 
00144         float );
00145     void MakeLinearMorphTable( SAA_Scene *, SAA_Elem *, int, char *, float );
00146     void MakeWeightedMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,  
00147         int, char *, float );
00148     void MakeExpressionMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,  
00149         int, char *, float );
00150     void MakeTexAnim( SAA_Scene *, SAA_Elem *, char * );
00151 
00152   private:
00153 
00154     char        *rsrc_path;
00155     char        *database_name;
00156     char        *scene_name;
00157     char        *model_name;
00158     char        *eggFileName;
00159     char         *animFileName;
00160     char         *eggGroupName;
00161     char        *tex_path;
00162     char        *tex_filename;
00163     char        *search_prefix;
00164 
00165     SI_Error            result;
00166     SAA_Scene           scene;
00167     SAA_Elem            model;
00168     SAA_Database        database;
00169     EggGroup           *dart;
00170     EggGroup           *skeleton;
00171     AnimGroup          *rootAnim;
00172     EggJoint           *rootJnt;
00173     AnimGroup          *animRoot;
00174     AnimGroup          *morphRoot;
00175     EggData             animData;
00176 
00177     int                    nurbs_step;
00178     int                    anim_start;
00179     int                    anim_end;
00180     int                    anim_rate;
00181     int                    pose_frame;
00182     int                    verbose;
00183     int                    flatten;
00184     int                    shift_textures;
00185     int                    ignore_tex_offsets;
00186     int                    use_prefix;
00187  
00188     bool                foundRoot;
00189     bool                geom_as_joint;
00190     bool                make_anim;
00191     bool                make_nurbs;
00192     bool                make_poly;
00193     bool                make_soft;
00194     bool                make_morph;
00195     bool                make_duv;
00196     bool                make_dart;
00197     bool                has_morph;
00198     bool                make_pose;
00199 
00200     ofstream    eggFile;
00201     ofstream    animFile;
00202     ofstream    texFile;
00203 
00204 };
00205 
00206 
00207 ////////////////////////////////////////////////////////////////////
00208 //     Function: Help
00209 //       Access: Public, Virtual
00210 //  Description: Displays the "what is this program" message, along
00211 //               with the usage message.  Should be overridden in base
00212 //               classes to describe the current program.
00213 ////////////////////////////////////////////////////////////////////
00214 void soft2egg::
00215 Help() 
00216 {
00217     cerr <<
00218     "soft2egg takes a SoftImage scene or model\n"
00219     "and outputs its contents as an egg file\n";
00220 
00221     Usage();
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: Usage
00226 //       Access: Public, Virtual
00227 //  Description: Displays the usage message.
00228 ////////////////////////////////////////////////////////////////////
00229 void soft2egg::
00230 Usage() {
00231   cerr << "\nUsage:\n"
00232        << _commandName << " [opts] (must specify -m or -s)\n\n"
00233        << "Options:\n";
00234 
00235   ShowOpts();
00236   cerr << "\n";
00237 }
00238 
00239 
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: ShowOpts
00243 //       Access: Public, Virtual
00244 //  Description: Displays the valid options.  Should be extended in
00245 //               base classes to show additional options relevant to
00246 //               the current program.
00247 ////////////////////////////////////////////////////////////////////
00248 void soft2egg::
00249 ShowOpts() 
00250 {
00251     cerr <<
00252     "  -r <path>  - Used to provide soft with the resource\n" 
00253     "               Defaults to 'c:/Softimage/SOFT_3.9.2/3D/test'.\n"
00254       //    "               Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n"
00255     "  -d <path>  - Database path.\n"
00256     "  -s <scene> - Indicates that a scene will be converted.\n"
00257     "  -m <model> - Indicates that a model will be converted.\n"
00258     "  -t <path>  - Specify path to place converted textures.\n"
00259     "  -T <name>  - Specify filename for texture map listing.\n"
00260     "  -S <step>  - Specify step for nurbs surface triangulation.\n"
00261     "  -M <name>  - Specify model output filename. Defaults to scene name.\n"
00262     "  -A <name>  - Specify anim output filename. Defaults to scene name.\n"
00263     "  -N <name>  - Specify egg group name.\n"
00264     "  -k         - Enable soft assignment for geometry.\n"
00265     "  -n         - Specify egg NURBS representation instead of poly's.\n"
00266     "  -p         - Specify egg polygon output for geometry.\n"
00267     "  -P <frame> - Specify frame number for static pose.\n"
00268     "  -b <frame> - Specify starting frame for animation (default = first).\n"
00269     "  -e <frame> - Specify ending frame for animation (default = last).\n"
00270     "  -f <fps>   - Specify frame rate for animation playback.\n"
00271     "  -a         - Compile animation tables if animation present.\n"
00272     "  -F         - Ignore hierarchy and build a completely flat skeleton.\n"
00273     "  -v <level> - Set debug level.\n"
00274     "  -x         - Shift NURBS parameters to preserve Alias textures.\n"
00275     "  -i         - Ignore Soft texture uv offsets.\n"
00276     "  -u         - Use Soft prefix in model names.\n"
00277     "  -c         - Cancel morph conversion.\n"
00278     "  -C         - Cancel duv conversion.\n"
00279     "  -D         - Don't make the output model a character.\n"
00280     "  -o <prefix>- Convert only models with given prefix.\n";
00281 
00282       EggBase::ShowOpts();
00283 }
00284 
00285 
00286 ////////////////////////////////////////////////////////////////////
00287 //     Function: HandleGetopts
00288 //       Access: Public, Virtual
00289 //  Description:
00290 ////////////////////////////////////////////////////////////////////
00291 boolean soft2egg::
00292 HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv) 
00293 {
00294     boolean okflag = true;
00295 
00296     switch (flag) 
00297     {
00298       case 'r':       // Set the resource path for soft.
00299         if ( strcmp( optarg, "" ) )
00300         {
00301             // Get the path.
00302             rsrc_path = optarg;
00303             fprintf( outStream, "using rsrc path %s\n", rsrc_path );
00304         }
00305         break;
00306 
00307     case 'd':       // Set the database path.
00308         if ( strcmp( optarg, "" ) )
00309         {
00310             // Get the path.
00311             database_name = optarg;
00312             fprintf( outStream, "using database %s\n", database_name );
00313         }
00314         break;
00315 
00316     case 's':     // Check if its a scene.
00317         if ( strcmp( optarg, "" ) )
00318         {
00319             // Get scene name.
00320             scene_name = optarg;
00321             fprintf( outStream, "loading scene %s\n", scene_name );
00322         }
00323         break;
00324     
00325     case 'm':     // Check if its a model.
00326         if ( strcmp( optarg, "" ) )
00327         {
00328             // Get model name.
00329             model_name = optarg;
00330             fprintf( outStream, "loading model %s\n", model_name );
00331         }
00332         break;
00333     
00334     case 't':     // Get converted texture path.
00335         if ( strcmp( optarg, "" ) )
00336         {
00337             // Get tex path name.
00338             tex_path = optarg;
00339             fprintf( outStream, "texture path:  %s\n", tex_path );
00340         }
00341         break;
00342 
00343     case 'T':      // Specify texture list filename. 
00344         if ( strcmp( optarg, "") )
00345         {
00346             // Get the name.
00347             tex_filename = optarg;
00348             fprintf( outStream, "creating texture list file: %s\n", 
00349                 tex_filename );
00350         }
00351         break;
00352     case 'S':     // Set NURBS step.
00353         if ( strcmp( optarg, "" ) )
00354         {
00355             nurbs_step = atoi(optarg);
00356             fprintf( outStream, "NURBS step:  %d\n", nurbs_step );
00357         }
00358         break;
00359  
00360     case 'M':     // Set model output file name.
00361         if ( strcmp( optarg, "" ) )
00362         {
00363             eggFileName = optarg;
00364             fprintf( outStream, "Model output filename:  %s\n", eggFileName );
00365         }
00366         break;
00367  
00368     case 'A':     // Set anim output file name.
00369         if ( strcmp( optarg, "" ) )
00370         {
00371             animFileName = optarg;
00372             fprintf( outStream, "Anim output filename:  %s\n", animFileName );
00373         }
00374         break;
00375  
00376     case 'N':     // Set egg model name.
00377         if ( strcmp( optarg, "" ) )
00378         {
00379             eggGroupName = optarg;
00380             fprintf( outStream, "Egg group name:  %s\n", eggGroupName );
00381         }
00382         break;
00383 
00384     case 'o':     // Set search_prefix.
00385         if ( strcmp( optarg, "" ) )
00386         {
00387             search_prefix = optarg;
00388             fprintf( outStream, "Only converting models with prefix:  %s\n", 
00389                 search_prefix );
00390         }
00391         break;
00392  
00393     case 'h':    // print help message
00394         Help();
00395         exit(1);
00396         break;
00397     
00398     case 'c':    // Cancel morph animation conversion
00399         make_morph = FALSE;
00400         fprintf( outStream, "canceling morph conversion\n" );
00401         break;
00402 
00403     case 'C':    // Cancel uv animation conversion
00404         make_duv = FALSE;
00405         fprintf( outStream, "canceling uv animation conversion\n" );
00406         break;
00407     
00408     case 'D':    // Omit the Dart flag
00409         make_dart = FALSE;
00410         fprintf( outStream, "making a non-character model\n" );
00411         break;
00412     
00413     case 'k':    // Enable soft skinning
00414         //make_soft = TRUE;
00415         //fprintf( outStream, "enabling soft skinning\n" );
00416         fprintf( outStream, "-k flag no longer necessary\n" );
00417         break;
00418     
00419     case 'n':    // Generate egg NURBS output
00420         make_nurbs = TRUE;
00421         fprintf( outStream, "outputting egg NURBS info\n" );
00422         break;
00423     
00424     case 'p':    // Generate egg polygon output
00425         make_poly = TRUE;
00426         fprintf( outStream, "outputting egg polygon info\n" );
00427         break;
00428     
00429     case 'P':    // Generate static pose from given frame
00430         if ( strcmp( optarg, "" ) )
00431         {
00432             make_pose = TRUE;
00433             pose_frame = atoi(optarg);
00434             fprintf( outStream, "generating static pose from frame %d\n",
00435                 pose_frame );
00436         }
00437         break;
00438     
00439     case 'a':     // Compile animation tables.
00440         make_anim = TRUE;
00441         fprintf( outStream, "attempting to compile anim tables\n" );
00442         break;
00443 
00444     case 'F':     // Build a flat skeleton.
00445         flatten = TRUE;
00446         fprintf( outStream, "building a flat skeleton!!!\n" );
00447         break;
00448 
00449     case 'x':     // Shift NURBS parameters to preserve Alias textures.
00450         shift_textures = TRUE;
00451         fprintf( outStream, "shifting NURBS parameters...\n" );
00452         break;
00453 
00454     case 'i':     // Ignore Soft uv texture offsets 
00455         ignore_tex_offsets = TRUE;
00456         fprintf( outStream, "ignoring texture offsets...\n" );
00457         break;
00458 
00459     case 'u':     // Use Soft prefix in model names 
00460         use_prefix = TRUE;
00461         fprintf( outStream, "using prefix in model names...\n" );
00462         break;
00463 
00464 
00465     case 'v':     // print debug messages.
00466         if ( strcmp( optarg, "" ) )
00467         {
00468             verbose = atoi(optarg);
00469             fprintf( outStream, "using debug level %d\n", verbose );
00470         }
00471         break;
00472 
00473     case 'b':     // Set animation start frame.
00474         if ( strcmp( optarg, "" ) )
00475         {
00476             anim_start = atoi(optarg);
00477             fprintf( outStream, "animation starting at frame:  %d\n", 
00478                 anim_start );
00479         }
00480         break;
00481 
00482     case 'e':     /// Set animation end frame.
00483         if ( strcmp( optarg, "" ) )
00484         {
00485             anim_end = atoi(optarg);
00486             fprintf( outStream, "animation ending at frame:  %d\n", anim_end );
00487         }
00488         break;
00489  
00490     case 'f':     /// Set animation frame rate.
00491         if ( strcmp( optarg, "" ) )
00492         {
00493             anim_rate = atoi(optarg);
00494             fprintf( outStream, "animation frame rate:  %d\n", anim_rate );
00495         }
00496         break;
00497  
00498     default:
00499         okflag = EggBase::HandleGetopts(flag, optarg, optind, argc, argv);
00500   }
00501 
00502   return (okflag);
00503 }
00504 
00505 
00506 
00507 ////////////////////////////////////////////////////////////////////
00508 //     Function: isNum
00509 //       Access: Public, Virtual
00510 //  Description: Take a float and make sure it is of the body. 
00511 ////////////////////////////////////////////////////////////////////
00512 int soft2egg::
00513 isNum( float num ) 
00514 {
00515     return( ( num < HUGE_VAL ) && finite( num ) );
00516 }
00517 
00518 
00519 ////////////////////////////////////////////////////////////////////
00520 //     Function: GetRootName
00521 //       Access: Public
00522 //  Description: Given a string, return a copy of the string up to
00523 //                 the first occurence of '-'. 
00524 ////////////////////////////////////////////////////////////////////
00525 char *soft2egg::
00526 GetRootName( const char *name )
00527 {
00528     char *hyphen;
00529     char *root;
00530     int      len;
00531 
00532     hyphen = strchr( name, '-' );
00533     len = hyphen-name;
00534 
00535     if ( (hyphen != NULL) && len )
00536     {
00537         root = (char *)malloc(sizeof(char)*(len+1));
00538         strncpy( root, name, len );
00539         root[sizeof(char)*(len)] = '\0';
00540     }
00541     else
00542     {
00543         root = (char *)malloc( sizeof(char)*(strlen(name)+1));
00544         strcpy( root, name );
00545     }
00546 
00547     return( root );
00548 }
00549 
00550 
00551 ////////////////////////////////////////////////////////////////////
00552 //     Function: RemovePathName
00553 //       Access: Public
00554 //  Description: Given a string, return a copy of the string after 
00555 //                 the last occurence of '/ 
00556 ////////////////////////////////////////////////////////////////////
00557 char *soft2egg::
00558 RemovePathName( const char *name )
00559 {
00560     char *slash;
00561     char *root;
00562 
00563     if ( *name != NULL )
00564     {
00565         slash = strrchr( name, '/' );
00566 
00567         root = (char *)malloc( sizeof(char)*(strlen(name)+1));
00568 
00569         if ( slash != NULL )
00570             strcpy( root, ++slash );
00571         else
00572             strcpy( root, name );
00573 
00574         return( root );
00575     }
00576 
00577     fprintf( stderr, "Error: RemovePathName received NULL string!\n" );
00578     return ( (char *)name );
00579 }
00580 
00581 ////////////////////////////////////////////////////////////////////
00582 //     Function: GetSliderName
00583 //       Access: Public
00584 //  Description: Given a string, return that part of the string after 
00585 //               the first occurence of '-' and before the last
00586 //                 occurance of '.' 
00587 ////////////////////////////////////////////////////////////////////
00588 char *soft2egg::
00589 GetSliderName( const char *name )
00590 {
00591     if ( name != NULL )
00592     {
00593         strstream newStr;
00594         char *hyphen;
00595         char *end;
00596 
00597         hyphen = strchr( name, '-' );
00598 
00599         // pull off stuff before first hyphen
00600         if (hyphen != NULL)
00601         {
00602             newStr << ++hyphen;
00603             end = newStr.str();
00604         }
00605 
00606         char *lastPeriod;
00607 
00608         lastPeriod = strrchr( end, '.' );
00609 
00610         // ignore stuff after last period
00611         if ( lastPeriod != NULL )
00612         {
00613             *lastPeriod = '\0';
00614         }
00615 
00616         if ( verbose >= 1 )
00617             fprintf( stdout, "slider name: '%s'\n", end );
00618 
00619         return( end );
00620     }
00621     
00622     return( (char *)name );
00623 }
00624 
00625 ////////////////////////////////////////////////////////////////////
00626 //     Function: GetName
00627 //       Access: Public
00628 //  Description: Given an element, return a copy of the element's 
00629 //                 name WITHOUT prefix. 
00630 ////////////////////////////////////////////////////////////////////
00631 char *soft2egg::
00632 GetName( SAA_Scene *scene, SAA_Elem *element )
00633 {
00634     int    nameLen;
00635     char *name;
00636 
00637     // get the name
00638     SAA_elementGetNameLength( scene, element, &nameLen ); 
00639     name = (char *)malloc(sizeof(char)*++nameLen);
00640     SAA_elementGetName( scene, element, nameLen, name );
00641     
00642     return name;
00643 }
00644 
00645 ////////////////////////////////////////////////////////////////////
00646 //     Function: GetFullName
00647 //       Access: Public
00648 //  Description: Given an element, return a copy of the element's 
00649 //                 name complete with prefix. 
00650 ////////////////////////////////////////////////////////////////////
00651 char *soft2egg::
00652 GetFullName( SAA_Scene *scene, SAA_Elem *element )
00653 {
00654     int    nameLen;
00655     char *name;
00656 
00657     // get the name
00658     SAA_elementGetNameLength( scene, element, &nameLen ); 
00659     name = (char *)malloc(sizeof(char)*++nameLen);
00660     SAA_elementGetName( scene, element, nameLen, name );
00661     
00662     int prefixLen;
00663     char *prefix;
00664 
00665     // get the prefix
00666     SAA_elementGetPrefixLength( scene, element, &prefixLen ); 
00667     prefix = (char *)malloc(sizeof(char)*++prefixLen);
00668     SAA_elementGetPrefix( scene, element, prefixLen, prefix );
00669 
00670     strstream fullNameStrm;
00671 
00672     // add 'em together
00673     fullNameStrm << prefix << "-" << name << ends;
00674 
00675     //free( name );
00676     //free( prefix );
00677     
00678     return fullNameStrm.str();
00679 }
00680 
00681 ////////////////////////////////////////////////////////////////////
00682 //     Function: GetModelNoteInfo
00683 //       Access: Public
00684 //  Description: Given an element, return a string containing the
00685 //                 contents of its MODEL NOTE entry 
00686 ////////////////////////////////////////////////////////////////////
00687 char *soft2egg::
00688 GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model )
00689 {
00690 
00691     int         size;
00692     char     *modelNote = NULL;
00693     SAA_Boolean bigEndian;
00694 
00695 
00696     SAA_elementGetUserDataSize( scene, model, "MNOT", &size );
00697 
00698     if ( size != 0 )
00699     {
00700         // allocate modelNote string
00701         modelNote = (char *)malloc(sizeof(char)*(size + 1));
00702 
00703         // get ModelNote data from this model
00704         SAA_elementGetUserData( scene, model, "MNOT", size, 
00705             &bigEndian, (void *)modelNote );
00706 
00707         //strip off newline, if present
00708         char *eol = strchr( modelNote, '\n' );
00709         if ( eol != NULL)
00710             *eol = '\0';
00711         else
00712             modelNote[size] = '\0';
00713 
00714         if ( verbose >= 1 )
00715             fprintf( outStream, "\nmodelNote = %s\n", 
00716                 modelNote );    
00717     }
00718 
00719     return modelNote;
00720 }
00721 
00722 
00723 ////////////////////////////////////////////////////////////////////
00724 //     Function: MakeTableName
00725 //       Access: Public
00726 //  Description: Given a string, and a number, return a new string
00727 //                 consisting of "string.number". 
00728 ////////////////////////////////////////////////////////////////////
00729 char *soft2egg::
00730 MakeTableName( const char *name, int number )
00731 {
00732     strstream namestrm;
00733 
00734     namestrm << name << "." << number << ends;
00735     return namestrm.str();
00736 }
00737 
00738 ////////////////////////////////////////////////////////////////////
00739 //     Function: FindModelByName
00740 //       Access: Public
00741 //  Description: Given a string, find the model in the scene 
00742 //                 whose name corresponds to the given string.                  
00743 ////////////////////////////////////////////////////////////////////
00744 SAA_Elem *soft2egg::
00745 FindModelByName( char *name, SAA_Scene *scene, SAA_Elem *models, 
00746     int numModels )
00747 {
00748     char     *foundName;
00749     SAA_Elem *foundModel = NULL;
00750     
00751     for ( int model = 0; model < numModels; model++ )
00752     {
00753         foundName = GetName( scene, &models[model] );
00754     
00755         if ( !strcmp( name, foundName ) )
00756         {
00757             if ( verbose >= 1 )
00758                 fprintf( outStream, "foundModel: '%s' = '%s'\n",
00759                     name, foundName );
00760 
00761             foundModel = &models[model];
00762             return( foundModel );
00763         }    
00764     }    
00765 
00766     fprintf( outStream, "findModelByName: failed to find model named: '%s'\n",
00767         name );
00768 
00769     return ( foundModel );    
00770 }
00771 
00772 
00773 ////////////////////////////////////////////////////////////////////
00774 //     Function: DepointellizeName
00775 //       Access: Public
00776 //  Description: Given a string, return the string up to the first
00777 //                 period. 
00778 ////////////////////////////////////////////////////////////////////
00779 char *soft2egg::
00780 DepointellizeName( char *name )
00781 {
00782     char    *endPtr;
00783     char    *newName;
00784 
00785     newName = (char *)malloc(sizeof(char)*(strlen(name)+1));
00786     sprintf( newName, "%s", name );
00787 
00788     endPtr = strchr( newName, '.' );
00789     if ( endPtr != NULL ) 
00790       *endPtr = '\0';
00791 
00792     return ( newName );
00793 }
00794 
00795 
00796 ////////////////////////////////////////////////////////////////////
00797 //     Function: ConvertTexture
00798 //       Access: Public
00799 //  Description: Given a string, return a copy of the string without
00800 //               the leading file path, and make an rgb file of the
00801 //                 same name in the tex_path directory. 
00802 ////////////////////////////////////////////////////////////////////
00803 char *soft2egg::
00804 ConvertTexture( SAA_Scene *scene, SAA_Elem *texture )
00805 {
00806   char *fileName = NULL;
00807   int  fileNameLen = 0;
00808 
00809   // get the texture's name
00810   SAA_texture2DGetPicNameLength( scene, texture, &fileNameLen);
00811 
00812   if ( fileNameLen )
00813   {
00814         fileName = (char *)malloc(sizeof(char)*++fileNameLen);
00815         SAA_texture2DGetPicName( scene, texture, fileNameLen, fileName );
00816   }
00817 
00818   // make sure we are not being passed a NULL image, an empty image
00819   // string or the default image created by egg2soft
00820   if ( (fileName != NULL) && strlen( fileName ) && strcmp( fileName, 
00821         "/fat/people/gregw/new_test/PICTURES/default") &&
00822                                 ( strstr( fileName, "noIcon" ) == NULL) )
00823   {
00824     char *texName = NULL;
00825     char *texNamePath = NULL;
00826     char *tmpName = NULL;
00827     char *fileNameExt = NULL;
00828 
00829     // strip off path and add .rgb
00830     tmpName = strrchr( fileName, '/' );
00831 
00832     if ( tmpName == NULL )
00833         tmpName = fileName;
00834     else
00835         tmpName++;
00836 
00837     float transp;
00838 
00839         // check for alpha
00840         SAA_texture2DGetTransparency( scene, texture, &transp );
00841 
00842         if ( transp != 0.0f ) {
00843         texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+6));
00844         sprintf( texName, "%s.rgba", tmpName );
00845         } else {
00846         texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+5));
00847         sprintf( texName, "%s.rgb", tmpName );
00848         }
00849 
00850     fileNameExt = (char *)malloc(sizeof(char)*(strlen(fileName)+5));
00851     sprintf( fileNameExt, "%s.pic", fileName ); 
00852 
00853     if ( verbose >= 1 )
00854         fprintf( outStream, "Looking for texture file: '%s'\n", fileNameExt );
00855 
00856     // try to make conversion of file
00857     int found_file = ( access( fileNameExt, F_OK ) == 0);
00858     
00859     if ( found_file )
00860     {
00861         if ( tex_path )
00862         {
00863             texNamePath = (char *)malloc(sizeof(char)*(strlen(tex_path) +
00864                 strlen(texName) + 2));
00865 
00866             sprintf( texNamePath, "%s/%s", tex_path, texName );    
00867 
00868             if ( texFile )
00869                 texFile << texNamePath << ": " << fileNameExt << "\n";
00870 
00871             // make sure conversion doesn't already exist    
00872             if ( (access( texNamePath, F_OK ) != 0)  && !texFile )    
00873             {
00874                 char *command = (char *)malloc(sizeof(char)*
00875                     (strlen(fileNameExt) + strlen(texNamePath) + 20));
00876 
00877                 sprintf( command, "image-resize -1 %s %s",  
00878                     fileNameExt, texNamePath );
00879 
00880                 if ( verbose >=1 )
00881                     fprintf( outStream, "executing %s\n", command );
00882             
00883                 system( command );    
00884 
00885                 //free( command );
00886             }
00887             else
00888                 if ( verbose >=1 )
00889                     fprintf( outStream, "%s already exists!\n", texNamePath );
00890         }
00891         else
00892         {
00893             if ( verbose >= 1 )
00894             {
00895                 fprintf( outStream, "Warning: No texture path defined" );
00896                 fprintf( outStream, " - No automatic conversion performed\n" );
00897             }
00898         }
00899     }
00900     else
00901     {
00902         fprintf( outStream, "Warning: Couldn't find texture file: %s\n", 
00903             fileNameExt );
00904     }
00905 
00906     //free( fileNameExt );
00907 
00908     if (tex_path)
00909         return( texNamePath );
00910     else
00911         return( texName );
00912   }
00913   else
00914   {
00915     fprintf( outStream, "Warning: ConvertTexture received NULL fileName\n" );
00916     return( NULL );
00917   }
00918 }
00919 
00920 ////////////////////////////////////////////////////////////////////
00921 //     Function: FindClosestTriVert
00922 //       Access: Public
00923 //  Description: Given an egg vertex pool, map each vertex therein to 
00924 //                 a vertex within an array of SAA model vertices of
00925 //                 size numVert. Mapping is done by closest proximity.
00926 ////////////////////////////////////////////////////////////////////
00927 int *soft2egg::
00928 FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert )
00929 {
00930     int    *vertMap = NULL; 
00931     int     vpoolSize = vpool->NumVertices();
00932     int     i,j;
00933     float   thisDist;
00934     float   closestDist;
00935     int     closest;
00936     
00937 
00938     vertMap = (int *)malloc(sizeof(int)*vpoolSize);
00939 
00940     // for each vertex in vpool
00941     for ( i = 0; i < vpoolSize; i++ )
00942     {
00943         // find closest model vertex 
00944         for ( j = 0; j < numVert-1; j++ ) 
00945         {
00946             // calculate distance
00947             thisDist =    sqrtf( 
00948                 powf( vpool->Vertex(i)->position[0] - vertices[j].x , 2 ) + 
00949                 powf( vpool->Vertex(i)->position[1] - vertices[j].y , 2 ) + 
00950                 powf( vpool->Vertex(i)->position[2] - vertices[j].z , 2 ) ); 
00951 
00952             // remember this if its the closest so far
00953             if ( !j || ( thisDist < closestDist ) )
00954             {
00955                 closest = j;
00956                 closestDist = thisDist;
00957             }
00958         } 
00959         vertMap[i] = closest;
00960 
00961         if ( verbose >= 2 )
00962         {
00963             fprintf( outStream, "mapping v %d of %d:( %f, %f, %f )\n", i, 
00964                 vpoolSize, vpool->Vertex(i)->position[0], 
00965                 vpool->Vertex(i)->position[1],
00966                 vpool->Vertex(i)->position[2] ); 
00967             fprintf( outStream, "to cv %d of %d:( %f, %f, %f )\tdelta = %f\n",
00968                 closest, numVert-1, vertices[closest].x, vertices[closest].y, 
00969                 vertices[closest].z, closestDist );
00970         }
00971                 }
00972 
00973         return( vertMap );
00974 }
00975 
00976 
00977 ////////////////////////////////////////////////////////////////////
00978 //     Function: MakeIndexMap
00979 //       Access: Public
00980 //  Description: Given an array of indices that is a map from one
00981 //                 set of vertices to another, return an array that
00982 //                 performs the reverse mapping of the indices array 
00983 ////////////////////////////////////////////////////////////////////
00984 int *soft2egg::
00985 MakeIndexMap( int *indices, int numIndices, int mapSize )
00986 {
00987     int i, j;
00988 
00989     // allocate map array
00990     int *map = (int *)malloc(sizeof(int)*mapSize); 
00991 
00992     if ( map != NULL )
00993     {
00994         for ( i = 0; i < mapSize; i++ )
00995         {
00996             j = 0;
00997             int found = 0;
00998             while( j < numIndices )
00999             {
01000                 if ( indices[j] == i )
01001                 {
01002                     map[i] = j;
01003                     if ( verbose >= 2 )
01004                         fprintf( outStream, "map[%d] = %d\n", i, map[i] );
01005                     found = 1;
01006                     break;
01007                 }
01008                 j++;
01009             }
01010             if ( !found) 
01011             {
01012                 if ( verbose >= 2 )
01013                     fprintf( outStream, "Warning: orphan vertex (%d)\n", i );
01014                 // default to -1 for now
01015                 map[i] = -1;
01016             }
01017         }
01018     }
01019     else
01020         fprintf( outStream, "Not enough Memory for index Map...\n");
01021     
01022 
01023     return( map );
01024 }
01025 
01026     
01027 ////////////////////////////////////////////////////////////////////
01028 //     Function: findShapeVert
01029 //       Access: Public
01030 //  Description: given a vertex, find its corresponding shape vertex
01031 //                 and return its index.
01032 ////////////////////////////////////////////////////////////////////
01033 int     soft2egg::
01034 findShapeVert( SAA_DVector vertex, SAA_DVector *vertices, int numVert )
01035 {
01036     int i;
01037     int found = 0;
01038 
01039     for ( i = 0; i < numVert && !found ; i++ )
01040     {
01041         if ( ( vertex.x == vertices[i].x ) && 
01042              ( vertex.y == vertices[i].y ) && 
01043              ( vertex.z == vertices[i].z ) )
01044         {
01045             found = 1;
01046 
01047             if ( verbose >= 2)
01048                 fprintf( outStream, "found shape vert at index %d\n", i );
01049         }
01050              
01051     } 
01052 
01053     if (!found )
01054         i = -1;
01055     else
01056         i--;
01057 
01058     return( i );
01059 }
01060 
01061 
01062 ////////////////////////////////////////////////////////////////////
01063 //     Function: LoadSoft
01064 //       Access: Public
01065 //  Description: Open the SI database and grab the scene & model info
01066 ////////////////////////////////////////////////////////////////////
01067 void soft2egg::
01068 LoadSoft()
01069 {
01070     int      i;
01071 
01072     if ( (scene_name == NULL && model_name == NULL) || database_name == NULL )
01073     {
01074         Usage();
01075         exit( 1 );
01076     }
01077 
01078     if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS)
01079     {
01080         fprintf( outStream, "Error: Couldn't get resource path!\n");
01081         exit( 1 );
01082     }
01083 
01084     if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS)
01085     {
01086         fprintf( outStream, "Error: Couldn't load database!\n");
01087         exit( 1 );
01088     }
01089 
01090     if ((result = SAA_sceneGetCurrent(&scene)) == SI_SUCCESS)
01091     {
01092         // load scene if present
01093         if ( scene_name != NULL )
01094         {
01095             SAA_sceneLoad( &database, scene_name, &scene );
01096 
01097             // if no egg filename specified, make up a name
01098             if ( eggFileName == NULL )
01099             {
01100                 eggFileName = (char *)malloc(sizeof(char)*
01101                     (strlen( scene_name ) + 14 ));
01102                 sprintf( eggFileName, "%s", DepointellizeName(scene_name) );
01103                 if ( make_nurbs )
01104                     strcat( eggFileName, "-nurb" );
01105                 strcat( eggFileName, "-mod.egg" );
01106             }
01107 
01108             // open an output file for the geometry if necessary 
01109             if ( make_poly || make_nurbs )
01110             {
01111                 unlink( eggFileName );
01112                 eggFile.open( eggFileName, ios::out, 0666 );
01113 
01114                 if ( !eggFile )
01115                 {
01116                     fprintf( outStream, "Couldn't open output file: %s\n", 
01117                         eggFileName ); 
01118                     exit( 1 );
01119                 }
01120             }
01121 
01122             // open an output file for texture list if specified
01123             if ( tex_filename != NULL )
01124             {
01125                 unlink( tex_filename );
01126                 texFile.open( tex_filename, ios::out, 0666 );
01127                 
01128                 if ( !texFile )
01129                 {    
01130                     fprintf( outStream, "Couldn't open output file: %s\n",
01131                         tex_filename );
01132                     exit( 1 );
01133                 }
01134             }
01135 
01136             if ( SAA_updatelistGet( &scene ) == SI_SUCCESS )
01137             {
01138                 float time;
01139 
01140                 fprintf( outStream, "setting Scene to frame %d...\n", pose_frame );
01141                 //SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame );
01142                 SAA_frame2Seconds( &scene, pose_frame, &time );
01143                 SAA_updatelistEvalScene( &scene, time );
01144                 sginap( 100 );
01145                 SAA_updatelistEvalScene( &scene, time );
01146                 if ( make_pose )
01147                     SAA_sceneFreeze( &scene );
01148             } 
01149 
01150             int            numModels;
01151             SAA_Elem    *models;
01152 
01153             SAA_sceneGetNbModels( &scene, &numModels ); 
01154             fprintf( outStream, "Scene has %d model(s)...\n", numModels );
01155         
01156             if ( numModels )
01157             {
01158                 // allocate array of models
01159                 models = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numModels);
01160 
01161                 if ( models != NULL )
01162                 {
01163                     char *rootName = GetRootName( eggFileName );
01164                     
01165                 
01166                     if ( eggGroupName == NULL )    
01167                         dart = _data.CreateGroup( NULL, rootName );
01168                     else
01169                         dart = _data.CreateGroup( NULL, eggGroupName );
01170 
01171                     if (make_dart)
01172                       dart->flags |= EF_DART;
01173 
01174                     AnimGroup    *rootTable;
01175 
01176                     rootTable = animData.CreateTable( NULL, eggFileName );    
01177 
01178                     if ( eggGroupName == NULL )
01179                         animRoot = animData.CreateBundle( rootTable, rootName );
01180                     else
01181                         animRoot = animData.CreateBundle( rootTable, 
01182                             eggGroupName );
01183 
01184                     // propagate commet to anim data
01185                     animData.root_group.children.push_front(
01186                         new EggComment( _commandLine ) );
01187 
01188                     if ( verbose >= 1 )
01189                         fprintf( outStream, "made animRoot: %s\n", rootName );
01190 
01191                     SAA_sceneGetModels( &scene, numModels, models );
01192 
01193                     for ( i = 0; i < numModels; i++ )
01194                     {
01195                         int level;
01196 
01197                         SAA_elementGetHierarchyLevel( &scene, &models[i], &level );
01198                         if ( !level )
01199                         {
01200                             if ( verbose >= 1 )
01201                                 fprintf( outStream,
01202                                     "\negging scene model[%d]\n", i );
01203 
01204                             MakeEgg( dart, NULL, NULL,  &scene, &models[i] );
01205                         }
01206                     }
01207 
01208             if ( make_poly || make_nurbs )
01209             {
01210                 // generate soft skinning assignments if desired
01211                 //
01212                 //disabled 1/1/99 to streamline joint assignments.
01213                 // all joint assignments now done here. Hard & Soft.
01214                 //if ( make_soft)
01215                 {
01216                     char        *name;
01217                     char        *fullname;
01218                     SAA_Boolean isSkeleton;
01219 
01220                     // search through models and look for skeleton parts
01221                     for ( i = 0; i < numModels; i++ )
01222                     {
01223                         SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton );
01224 
01225                         // get fullname for splitting files, but
01226                         // only use it in file if requested
01227                         fullname = GetFullName( &scene, &models[i] );
01228                         if ( use_prefix )
01229                             name = fullname;
01230                         else
01231                             name = GetName( &scene, &models[i] );
01232 
01233                         // split
01234                         if ( strstr( fullname, search_prefix ) != NULL )
01235                         {
01236                             // for every skel part: get soft skin info 
01237                             if ( isSkeleton )
01238                                 MakeSoftSkin( &scene, &models[i], models,
01239                                     numModels, name );
01240                         }
01241 
01242                         //free( name );
01243                     }
01244 
01245                     // make sure all vertices were assigned
01246                     // via soft skinning - if not hard assign them
01247                     for ( i = 0; i < numModels; i++ )
01248                     {
01249                         // get fullname for splitting files, but
01250                         // only use it in file if requested
01251                         fullname = GetFullName( &scene, &models[i] );
01252                         if ( use_prefix )
01253                             name = fullname;
01254                         else
01255                             name = GetName( &scene, &models[i] );
01256 
01257                         // split
01258                         if ( strstr( fullname, search_prefix ) != NULL )
01259                             CleanUpSoftSkin( &scene, &models[i], name );
01260 
01261                         //free( name );
01262                     }
01263 
01264                 }
01265 
01266 
01267                 // put the skeleton data into the egg data
01268                 dart->StealChildren( *skeleton );
01269 
01270                 // make sure all elements have unique names
01271                 _data.UniquifyNames();
01272     
01273                 // write out the geometry data if requested    
01274                 //if ( make_poly || make_nurbs )
01275                 //{
01276                     eggFile << _data << "\n";
01277                     fprintf( outStream, "\nwriting out %s...\n", eggFileName );
01278                     eggFile.close();
01279                 }
01280 
01281                 // close texture list file if opened
01282                 if ( texFile )
01283                     texFile.close();
01284 
01285                 // generate animation data if desired
01286                 if ( make_anim )
01287                 {
01288                 if ( animFileName == NULL )
01289                 {
01290                     animFileName = (char *)malloc(sizeof(char)*
01291                         (strlen(scene_name)+ 10 ));
01292                     sprintf( animFileName, "%s", DepointellizeName(scene_name) );
01293                     strcat( animFileName, "-chan.egg" );
01294                 }
01295 
01296                 unlink( animFileName );
01297                 animFile.open( animFileName, ios::out, 0666 );
01298 
01299                 if ( !animFile )
01300                 {
01301                     fprintf( outStream, "Couldn't open output file: %s\n", 
01302                         animFileName ); 
01303                     exit( 1 );
01304                 }
01305 
01306                 int frame;
01307                 //int frameStep;
01308                 float time;
01309 
01310                 // get all the animation frame info if not specified
01311                 // on the command line
01312                 if (anim_start == -1000) 
01313                     SAA_sceneGetPlayCtrlStartFrame( &scene, &anim_start );
01314 
01315                 if (anim_end == -1000)
01316                     SAA_sceneGetPlayCtrlEndFrame( &scene, &anim_end );
01317 
01318                 //SAA_sceneGetPlayCtrlFrameStep( &scene, &frameStep );
01319 
01320                 fprintf( outStream, "\nframeStart = %d\n", anim_start );
01321                 fprintf( outStream, "frameEnd = %d\n", anim_end );
01322                 //fprintf( outStream, "frameStep = %d\n", frameStep );
01323 
01324                 // start at first frame and go to last
01325                 for ( frame = anim_start; frame <= anim_end; 
01326                         frame += 1)
01327                 {
01328                     SAA_frame2Seconds( &scene, frame, &time );
01329                     SAA_updatelistEvalScene( &scene, time );
01330                     sginap( 100 );
01331                     SAA_updatelistEvalScene( &scene, time );
01332                     fprintf( outStream, "\n> animating frame %d\n", frame );
01333 
01334                     // for each model
01335                     for ( i = 0; i < numModels; i++ )
01336                     {
01337                         char           *name;
01338                         char           *fullname;
01339                         SAA_Boolean     isSkeleton;
01340                         SAA_ModelType     type;
01341 
01342                         SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton );
01343 
01344                         // get fullname for splitting files, but
01345                         // only use it in file if requested
01346                         fullname = GetFullName( &scene, &models[i] );
01347                         if ( use_prefix )
01348                             name = fullname;
01349                         else
01350                             name = GetName( &scene, &models[i] );
01351 
01352                         // split
01353                         if ( strstr( fullname, search_prefix ) != NULL )
01354                         {
01355                             // make the morph table for this critter
01356                             if ( make_morph )
01357                             {
01358                                 MakeMorphTable( &scene, &models[i], models,
01359                                     numModels, name, time );
01360                             }
01361                         }
01362 
01363                         // find out what type of node we're dealing with
01364                         result = SAA_modelGetType( &scene, &models[i], &type );
01365 
01366                         int size;
01367 
01368                         // check for uv texture animation
01369                         SAA_elementGetUserDataSize( &scene, &models[i], 
01370                             "TEX_OFFSETS", &size );
01371 
01372                         // if so, update for this frame if desired
01373                         if ( ( size != 0 ) && make_duv )    
01374                             MakeTexAnim( &scene, &models[i], name );
01375 
01376                         // if we have a skeleton or something that acts
01377                         // like one - build anim tables
01378                         if ( isSkeleton  ||
01379                             ( strstr( name, "joint") != NULL ) )
01380                                 MakeAnimTable( &scene, &models[i], name ); 
01381 
01382                         //free( name );
01383                     }
01384 
01385                     if ( verbose >= 1 )
01386                         fprintf( outStream, "\n" );
01387                 }
01388 
01389                 animFile << animData << "\n";
01390                 fprintf( outStream, "\nwriting out %s...\n", animFileName );
01391                 animFile.close();
01392                 }
01393 
01394                 //free( models );
01395 
01396                 }
01397                 else
01398                     fprintf( outStream, "Error: Not enough Memory for models...\n");
01399             }
01400         }
01401         // otherwise try to load a model
01402         else if ( model_name != NULL )
01403         {
01404 
01405             if ( eggFileName == NULL )
01406             {    
01407                 eggFileName = 
01408                     (char *)malloc(sizeof(char)*(strlen( model_name )+13));
01409                 sprintf( eggFileName, "%s", DepointellizeName( model_name ) );
01410 
01411                 if ( make_nurbs )
01412                     strcat( eggFileName, "-nurb" );
01413                 strcat( eggFileName, "-mod.egg" );
01414             }
01415 
01416             eggFile.open( eggFileName );    
01417 
01418             if ( !eggFile )
01419             {
01420                 fprintf( outStream, "Couldn't open output file: %s\n", 
01421                     eggFileName ); 
01422                 exit( 1 );
01423             }
01424 
01425             if ((result = 
01426                 SAA_elementLoad(&database, &scene, model_name, &model))
01427                 == SI_SUCCESS)
01428             {
01429                 fprintf( outStream, "Loading single model...\n");
01430                 MakeEgg( NULL, NULL, NULL,  &scene, &model );
01431             }
01432 
01433             eggFile << _data << "\n";
01434         }
01435     }
01436 
01437 }
01438 
01439 ////////////////////////////////////////////////////////////////////
01440 //     Function: MakeEgg
01441 //       Access: Public
01442 //  Description: Make egg geometry from a given model. This include
01443 //                 textures, tex coords, colors, normals, and joints. 
01444 ////////////////////////////////////////////////////////////////////
01445 void soft2egg::
01446 MakeEgg( EggGroup *parent, EggJoint *lastJoint, AnimGroup *lastAnim,
01447             SAA_Scene *scene, SAA_Elem *model )
01448 {
01449     char        *name;
01450     char        *fullname;
01451     SAA_ModelType type;
01452     int         id = 0;
01453     int         numShapes;
01454     int         numTri;
01455     int         numVert;
01456     int         numTexLoc = 0;
01457     int         numTexGlb = 0;
01458     int         i, j;
01459     float        matrix[4][4];
01460     float        *uScale = NULL; 
01461     float        *vScale = NULL;
01462     float        *uOffset = NULL;
01463     float        *vOffset = NULL;
01464     SAA_Boolean    uv_swap = FALSE;
01465     void        *relinfo;
01466     SAA_SubElem *triangles = NULL;
01467     SAA_Elem    *materials = NULL;
01468     SAA_SubElem *cvertices = NULL;
01469     SAA_DVector *cvertPos = NULL;
01470     SAA_DVector *vertices = NULL;
01471     SAA_DVector *normals = NULL;
01472     int            *indices = NULL;
01473     int            *indexMap = NULL;
01474     int            *numTexTri = NULL;
01475     SAA_Elem    *textures = NULL;
01476     char        **texNameArray;
01477     float        *uCoords = NULL;
01478     float        *vCoords = NULL;
01479     SAA_GeomType gtype = SAA_GEOM_ORIGINAL;
01480     SAA_Boolean    visible;
01481 
01482     /////////////////////////////////////////////////
01483     // find out what type of node we're dealing with
01484     /////////////////////////////////////////////////
01485     result = SAA_modelGetType( scene, model, &type );
01486 
01487     if ( verbose >= 1 )
01488     {
01489         if ( type == SAA_MNILL )
01490             fprintf( outStream, "encountered null\n"); 
01491         else if ( type == SAA_MPTCH )
01492             fprintf( outStream, "encountered patch\n" );
01493         else if ( type == SAA_MFACE )
01494             fprintf( outStream, "encountered face\n" );
01495         else if ( type == SAA_MSMSH )
01496             fprintf( outStream, "encountered mesh\n" );
01497         else if ( type == SAA_MJNT )
01498             fprintf( outStream, "encountered joint\n" );
01499         else if ( type == SAA_MSPLN )
01500             fprintf( outStream, "encountered spline\n" );
01501         else if ( type == SAA_MMETA )
01502             fprintf( outStream, "encountered meta element\n" );
01503         else if ( type == SAA_MBALL )
01504             fprintf( outStream, "encountered metaball\n" );
01505         else if ( type == SAA_MNCRV )
01506             fprintf( outStream, "encountered nurb curve\n" );
01507         else if ( type == SAA_MNSRF )
01508             fprintf( outStream, "encountered nurbs surf\n" );
01509         else 
01510             fprintf( outStream, "encountered unknown type: %d\n", type );
01511     }
01512 
01513     /////////////////////////////
01514     // Get the name of the model
01515     /////////////////////////////
01516 
01517     // Get the FULL name of the model
01518     fullname = GetFullName( scene, model );
01519 
01520     if ( use_prefix )
01521     {
01522         // Get the FULL name of the trim curve
01523         name = fullname; 
01524     }
01525     else
01526     {
01527         // Get the name of the trim curve
01528         name = GetName( scene, model );
01529     }
01530 
01531     if ( verbose >= 1 )
01532         fprintf( outStream, "element name <%s>\n", name );
01533 
01534     fflush( outStream );
01535 
01536     // get the model's matrix    
01537     SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL,  matrix );
01538 
01539     if ( verbose >= 2 )
01540     {
01541         fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[0][0],
01542              matrix[0][1],  matrix[0][2],  matrix[0][3] ); 
01543         fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[1][0],
01544              matrix[1][1],  matrix[1][2],  matrix[1][3] ); 
01545         fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[2][0],
01546              matrix[2][1],  matrix[2][2],  matrix[2][3] ); 
01547         fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[3][0],
01548              matrix[3][1],  matrix[3][2],  matrix[3][3] ); 
01549     }
01550     
01551     ///////////////////////////////////////////////////////////////////////
01552     // check to see if this is a branch we don't want to descend - this
01553     // will prevent creating geometry for animation control structures
01554     ///////////////////////////////////////////////////////////////////////
01555     if ( (strstr( name, "con-" ) == NULL) && 
01556          (strstr( name, "con_" ) == NULL) && 
01557          (strstr( name, "fly_" ) == NULL) && 
01558          (strstr( name, "fly-" ) == NULL) && 
01559          (strstr( name, "camRIG" ) == NULL) &&
01560          (strstr( name, "bars" ) == NULL) && 
01561          // split
01562          (strstr( fullname, search_prefix ) != NULL) )
01563     {
01564 
01565     // if making a pose - get deformed geometry
01566     if ( make_pose )
01567         gtype = SAA_GEOM_DEFORMED;
01568         
01569     // Get the number of key shapes
01570     SAA_modelGetNbShapes( scene, model, &numShapes );
01571     if ( verbose >= 1 )
01572         fprintf( outStream, "MakeEgg: num shapes: %d\n", numShapes);
01573 
01574     ///////////////////////////////////////////////////////////////////////
01575     // if multiple key shapes exist create table entries for each
01576     ///////////////////////////////////////////////////////////////////////
01577     if ( (numShapes > 0) && make_morph )
01578     {
01579         has_morph = 1;
01580 
01581         // make sure root morph table exists
01582         if ( morphRoot == NULL )
01583             morphRoot = animData.CreateTable( animRoot, "morph" ); 
01584     
01585         char   *tableName;
01586 
01587         // create morph table entry for each key shape
01588         // (start at second shape - as first is the original geometry)
01589         for ( i = 1; i < numShapes; i++ )
01590         {
01591             tableName = MakeTableName( name, i );
01592             SAnimTable *table = new SAnimTable( );     
01593             table->name = tableName;
01594             table->fps = anim_rate;
01595             morphRoot->children.push_back( table );
01596             if ( verbose >= 1 )
01597                 fprintf( outStream, "created table named: '%s'\n", tableName );    
01598         }
01599 
01600         //free( tableName );
01601     }
01602 
01603     SAA_modelGetNodeVisibility( scene, model, &visible ); 
01604     if ( verbose >= 1 )
01605         fprintf( outStream, "model visibility: %d\n", visible ); 
01606     
01607     ///////////////////////////////////////////////////////////////////////
01608     // Only create egg polygon data if: the node is visible, and its not
01609     // a NULL or a Joint, and we're outputing polys (or if we are outputing 
01610     // NURBS and the model is a poly mesh or a face) 
01611     ///////////////////////////////////////////////////////////////////////
01612     if ( visible &&  
01613          (type != SAA_MNILL) &&
01614          (type != SAA_MJNT) && 
01615          ((make_poly || 
01616          (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) 
01617          || (!make_poly && !make_nurbs && make_duv && 
01618             ((type == SAA_MSMSH) || (type == SAA_MFACE )) ))
01619        )
01620     {
01621       // If the model is a NURBS in soft, set its step before tesselating
01622       if ( type == SAA_MNSRF )
01623         SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
01624 
01625       // If the model is a PATCH in soft, set its step before tesselating
01626       else if ( type == SAA_MPTCH )
01627         SAA_patchSetStep( scene, model, nurbs_step, nurbs_step );
01628  
01629       // Get the number of triangles    
01630       result = SAA_modelGetNbTriangles( scene, model, gtype, id, &numTri);
01631       if ( verbose >= 1 )
01632           fprintf( outStream, "triangles: %d\n", numTri);
01633 
01634       if ( result != SI_SUCCESS )
01635       {
01636         if ( verbose >= 1 ) {
01637             fprintf( outStream, 
01638             "Error: couldn't get number of triangles!\n" );
01639             fprintf( outStream, "\tbailing on model: '%s'\n", name );
01640         }
01641         return;    
01642       }
01643 
01644       // check to see if surface is also skeleton...
01645       SAA_Boolean isSkeleton = FALSE;
01646 
01647       SAA_modelIsSkeleton( scene, model, &isSkeleton );
01648 
01649       // check to see if this surface is used as a skeleton
01650       // or is animated via constraint only ( these nodes are
01651       // tagged by the animator with the keyword "joint"
01652       // somewhere in the nodes name)
01653       if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
01654       {
01655           if ( verbose >= 1 )
01656               fprintf( outStream, "animating Polys as joint!!!\n" );
01657 
01658             MakeJoint( scene, lastJoint, lastAnim, model, name );
01659       }
01660     
01661       // model is not a null and has no triangles!
01662       if ( !numTri )
01663       {
01664         if ( verbose >= 1 )
01665             fprintf( outStream, "no triangles!\n"); 
01666       }
01667       else 
01668       {
01669         // allocate array of triangles
01670         triangles = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri);
01671         if ( triangles != NULL )
01672         {
01673             // triangulate model and read the triangles into array
01674             SAA_modelGetTriangles( scene, model, gtype, id, numTri, triangles );
01675         }
01676         else
01677             fprintf( outStream, "Not enough Memory for triangles...\n");
01678 
01679         // allocate array of materials
01680         materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri);
01681         if ( materials != NULL )
01682         {
01683             // read each triangle's material into array  
01684             SAA_triangleGetMaterials( scene, model, numTri, triangles, 
01685                 materials );
01686         }
01687         else
01688             fprintf( outStream, "Not enough Memory for materials...\n");
01689 
01690         // allocate array of textures per triangle
01691         numTexTri = (int *)malloc(sizeof(int)*numTri);
01692 
01693         // find out how many local textures per triangle
01694         for ( i = 0; i < numTri; i++ )
01695         {    
01696             result = SAA_materialRelationGetT2DLocNbElements( scene, 
01697                                                         &materials[i], FALSE, &relinfo, &numTexTri[i] );
01698 
01699             // polytex    
01700             if ( result == SI_SUCCESS )
01701                 numTexLoc += numTexTri[i];
01702         }
01703 
01704         // don't need this anymore...
01705         //free( numTexTri ); 
01706 
01707         // get local textures if present
01708         if ( numTexLoc )
01709         {
01710             // ASSUME only one texture per material
01711             textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri);
01712 
01713             for ( i = 0; i < numTri; i++ )
01714             {
01715                 // and read all referenced local textures into array
01716                 SAA_materialRelationGetT2DLocElements( scene, &materials[i],
01717                     TEX_PER_MAT , &textures[i] ); 
01718             }
01719 
01720             if ( verbose >= 1 )
01721                 fprintf( outStream, "numTexLoc = %d\n", numTexLoc);    
01722         }
01723         // if no local textures, try to get global textures
01724         else
01725         {
01726             SAA_modelRelationGetT2DGlbNbElements( scene, model,
01727                 FALSE, &relinfo, &numTexGlb );
01728 
01729             if ( numTexGlb )
01730             {
01731                 // ASSUME only one texture per model
01732                 textures = (SAA_Elem *)malloc(sizeof(SAA_Elem));
01733 
01734                 // get the referenced texture
01735                 SAA_modelRelationGetT2DGlbElements( scene, model, 
01736                     TEX_PER_MAT, textures ); 
01737 
01738                 if ( verbose >= 1 )
01739                     fprintf( outStream, "numTexGlb = %d\n", numTexGlb);    
01740             }
01741         }
01742 
01743         // allocate array of control vertices 
01744         cvertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri*3);
01745         if ( cvertices != NULL )
01746         {
01747             // read each triangle's control vertices into array
01748             SAA_triangleGetCtrlVertices( scene, model, gtype, id,
01749                 numTri, triangles, cvertices );
01750 
01751             if ( verbose >= 2 )
01752             {
01753                 cvertPos = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3);
01754                 SAA_ctrlVertexGetPositions(  scene, model, numTri*3, 
01755                     cvertices, cvertPos);
01756 
01757                 for ( i=0; i < numTri*3; i++ )
01758                 {
01759                     fprintf( outStream, "cvert[%d] = %f %f %f %f\n", i, 
01760                         cvertPos[i].x, cvertPos[i].y, cvertPos[i].z, 
01761                         cvertPos[i].w );
01762                 }
01763             }
01764         }
01765         else
01766             fprintf( outStream, "Not enough Memory for control vertices...\n");
01767 
01768         // allocate array of control vertex indices
01769         // this array maps from the redundant cvertices array into
01770         // the unique vertices array (cvertices->vertices)
01771         indices = (int *)malloc(sizeof(int)*numTri*3);
01772         if ( indices != NULL )
01773         {
01774             for ( i=0; i < numTri*3; i++ )
01775                 indices[i] = 0;
01776 
01777             SAA_ctrlVertexGetIndices( scene, model, numTri*3, 
01778                 cvertices, indices );
01779        
01780             if ( verbose >= 2 ) 
01781                 for ( i=0; i < numTri*3; i++ )
01782                     fprintf( outStream, "indices[%d] = %d\n", i, indices[i] );
01783         }
01784         else
01785             fprintf( outStream, "Not enough Memory for indices...\n");
01786 
01787         // get number of UNIQUE vertices in model
01788         SAA_modelGetNbTriVertices( scene, model, &numVert );
01789 
01790         if ( verbose >= 2 )
01791             fprintf( outStream, "num unique verts = %d\n", numVert );
01792 
01793         //allocate array of vertices
01794         vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert);
01795 
01796         // get the UNIQUE vertices of all triangles in model
01797         SAA_modelGetTriVertices( scene, model, numVert, vertices );
01798 
01799         if ( verbose >= 2 )
01800         {
01801             for ( i=0; i < numVert; i++ )
01802             {
01803                 fprintf( outStream, "vertices[%d] = %f ", i, vertices[i].x );
01804                 fprintf( outStream, "%f %f %f\n", vertices[i].y, 
01805                 vertices[i].z, vertices[i].w );
01806             }
01807         }
01808 
01809         // allocate indexMap array
01810         // we contruct this array to map from the unique vertices
01811         // array to the redundant cvertices array - it will save
01812         // us from doing repetitive searches later
01813         indexMap = MakeIndexMap( indices, numTri*3, numVert ); 
01814 
01815         // allocate array of normals
01816         normals = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3);
01817         if ( normals != NULL )
01818         {
01819             // read each control vertex's normals into an array
01820             SAA_ctrlVertexGetNormals( scene, model, numTri*3,
01821                 cvertices, normals );
01822         }
01823         else
01824             fprintf( outStream, "Not enough Memory for normals...\n");
01825 
01826         if ( verbose >= 2 )
01827         {
01828             for ( i=0; i<numTri*3; i++ )
01829                 fprintf( outStream, "normals[%d] = %f %f %f %f\n", i,
01830                     normals[i].x, normals[i].y, normals[i].z, normals[i].w );
01831         }
01832 
01833         int uRepeat, vRepeat;
01834 
01835         // make sure we have textures before we get t-coords
01836         if ( numTexLoc )
01837         {
01838             // allocate arrays for u & v coords
01839             uCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3); 
01840             vCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3); 
01841           
01842             // read the u & v coords into the arrays
01843             if ( uCoords != NULL && vCoords != NULL)
01844             {
01845               for ( i = 0; i < numTri*numTexLoc*3; i++ )
01846                 uCoords[i] = vCoords[i] = 0.0f;
01847  
01848                 SAA_ctrlVertexGetUVTxtCoords( scene, model, numTri*3,
01849                     cvertices, numTexLoc*3, uCoords, vCoords );
01850             }
01851             else
01852                 fprintf( outStream, "Not enough Memory for texture coords...\n");
01853 
01854             if ( verbose >= 2 )
01855             {
01856                 for ( i=0; i<numTexLoc*3; i++ )
01857                     fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i, 
01858                         uCoords[i], vCoords[i] );
01859             }
01860 
01861             // allocate arrays of texture info
01862             uScale = ( float *)malloc(sizeof(float)*numTri);
01863             vScale = ( float *)malloc(sizeof(float)*numTri);
01864             uOffset = ( float *)malloc(sizeof(float)*numTri);
01865             vOffset = ( float *)malloc(sizeof(float)*numTri);
01866             texNameArray = ( char **)malloc(sizeof(char *)*numTri);
01867 
01868             for ( i = 0; i < numTri; i++ )
01869             {
01870                 // initialize the array value
01871                 texNameArray[i] = NULL;
01872 
01873                 SAA_Boolean    valid = FALSE;
01874                 // check to see if texture is present
01875                 result = SAA_elementIsValid( scene, &textures[i], &valid );
01876                
01877                 if ( result != SI_SUCCESS )
01878                     fprintf( outStream, "SAA_elementIsValid failed!!!!\n" );
01879  
01880                 // texture present - get the name and uv info 
01881                 if ( valid )
01882                 {
01883                     texNameArray[i] = ConvertTexture( scene, &textures[i] );
01884                    
01885                     if ( verbose >= 2 ) 
01886                         fprintf( outStream, " tritex[%d] named: %s\n", i, 
01887                             texNameArray[i] );
01888 
01889                     SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap );
01890 
01891                     if ( verbose >= 2 )
01892                         if ( uv_swap == TRUE )
01893                             fprintf( outStream, " swapping u and v...\n" );
01894 
01895                     SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] );
01896                     SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] );
01897                     SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] );
01898                     SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] );
01899 
01900                     if ( verbose >= 2 )
01901                     {    
01902                         fprintf(outStream, "tritex[%d] uScale: %f vScale: %f\n",                             i, uScale[i], vScale[i] );
01903                         fprintf(outStream, " uOffset: %f vOffset: %f\n", 
01904                             uOffset[i], vOffset[i] );
01905                     }
01906 
01907 
01908                     SAA_texture2DGetRepeats(  scene, &textures[i], &uRepeat,
01909                         &vRepeat );
01910 
01911                     if ( verbose >= 2 )
01912                     {
01913                         fprintf(outStream, "uRepeat = %d, vRepeat = %d\n",
01914                             uRepeat, vRepeat );
01915                     }
01916                 }
01917                 else 
01918                 {
01919                     if ( verbose >= 2 ) 
01920                     {
01921                         fprintf( outStream, "Invalid texture...\n");
01922                         fprintf( outStream, " tritex[%d] named: (null)\n", i );
01923                     }
01924                 }
01925             }
01926 
01927             //debug
01928             //for ( i = 0; i < numTri; i++ )
01929             //{
01930                 //if ( texNameArray[i] != NULL )
01931                     //fprintf( outStream, " tritex[%d] named: %s\n", i, 
01932                         //texNameArray[i] );
01933                 //else
01934                     //fprintf( outStream, " tritex[%d] named: (null)\n", i );
01935             //}
01936         }
01937         // make sure we have textures before we get t-coords
01938         else if ( numTexGlb )
01939         {
01940             SAA_Boolean    valid;
01941 
01942             // check to see if texture is present
01943             SAA_elementIsValid( scene, textures, &valid );
01944                 
01945             // texture present - get the name and uv info 
01946             if ( valid )
01947             {
01948                 SAA_texture2DGetUVSwap( scene, textures, &uv_swap );
01949 
01950                 if ( verbose >= 1 )
01951                     if ( uv_swap == TRUE )
01952                         fprintf( outStream, " swapping u and v...\n" );
01953 
01954                 // allocate arrays for u & v coords
01955                 uCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); 
01956                 vCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); 
01957 
01958                 for ( i = 0; i < numTri*numTexGlb*3; i++ )
01959                 {
01960                     uCoords[i] = vCoords[i] = 0.0f;
01961                 }                
01962                     
01963                 // read the u & v coords into the arrays
01964                 if ( uCoords != NULL && vCoords != NULL)
01965                 {
01966                     SAA_triCtrlVertexGetGlobalUVTxtCoords( scene, model, 
01967                         numTri*3, cvertices, numTexGlb, textures, 
01968                         uCoords, vCoords );
01969                 }
01970                 else
01971                     fprintf( outStream, "Not enough Memory for texture coords...\n");
01972 
01973                 if ( verbose >= 2 )
01974                   {
01975                     for ( i=0; i<numTri*numTexGlb*3; i++ )
01976                       fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i, 
01977                                uCoords[i], vCoords[i] );
01978                   }
01979                 
01980                 texNameArray = ( char **)malloc(sizeof(char *));
01981                 *texNameArray = ConvertTexture( scene, textures );
01982 
01983                 if ( verbose >= 1 )    
01984                     fprintf( outStream, " global tex named: %s\n", 
01985                         texNameArray );
01986         
01987                 // allocate arrays of texture info
01988                 uScale = ( float *)malloc(sizeof(float));
01989                 vScale = ( float *)malloc(sizeof(float));
01990                 uOffset = ( float *)malloc(sizeof(float));
01991                 vOffset = ( float *)malloc(sizeof(float));
01992 
01993                 SAA_texture2DGetUScale( scene, textures, uScale );
01994                 SAA_texture2DGetVScale( scene, textures, vScale );
01995                 SAA_texture2DGetUOffset( scene, textures, uOffset );
01996                 SAA_texture2DGetVOffset( scene, textures, vOffset );
01997 
01998                 if ( verbose >= 1 ) 
01999                 {
02000                     fprintf( outStream, " global tex uScale: %f vScale: %f\n", 
02001                         *uScale, *vScale );
02002                     fprintf( outStream, " uOffset: %f vOffset: %f\n", 
02003                         *uOffset, *vOffset );
02004                 }
02005 
02006                 SAA_texture2DGetRepeats(  scene, textures, &uRepeat,
02007                     &vRepeat );
02008 
02009                 if ( verbose >= 2 )
02010                 {
02011                     fprintf(outStream, "uRepeat = %d, vRepeat = %d\n",
02012                         uRepeat, vRepeat );
02013                 }
02014             }
02015             else fprintf( outStream, "Invalid texture...\n");
02016         }
02017 
02018         // make the egg vertex pool 
02019         EggVertexPool *pool = _data.CreateVertexPool( parent, name );
02020 
02021         for ( i = 0; i < numVert; i++ )
02022         {
02023             pfVec3    eggVert; 
02024             pfVec3    eggNorm; 
02025             
02026             //convert to global coords
02027             SAA_DVector local = vertices[i];
02028             SAA_DVector global;
02029 
02030             _VCT_X_MAT( global, local, matrix );
02031 
02032             // set vertices array to reflect global coords
02033             //vertices[i].x = global.x;
02034             //vertices[i].y = global.y;
02035             //vertices[i].z = global.z;
02036 
02037             //eggVert.set( vertices[i].x, vertices[i].y, vertices[i].z );
02038 
02039             // we'll preserve original verts for now
02040             eggVert.set( global.x, global.y, global.z );
02041 
02042             local = normals[indexMap[i]];
02043 
02044             _VCT_X_MAT( global, local, matrix );
02045 
02046             eggNorm.set( global.x, global.y, global.z );
02047             eggNorm.normalize();
02048 
02049             pool->AddVertex( eggVert, i );
02050             pool->Vertex(i)->attrib.SetNormal( eggNorm );
02051 
02052             // translate local uv's to global and add to vertex pool
02053             if ( numTexLoc && (uCoords != NULL && vCoords !=NULL ))
02054             {
02055                 float u, v;
02056 
02057                 if ( ignore_tex_offsets ) {
02058                   u = uCoords[indexMap[i]];
02059                   v = 1.0f - vCoords[indexMap[i]];
02060                 } else {
02061                   u = (uCoords[indexMap[i]] - uOffset[indexMap[i]/3]) /
02062                     uScale[indexMap[i]/3];
02063                   
02064                   v = 1.0f - ((vCoords[indexMap[i]] - vOffset[indexMap[i]/3]) /
02065                               vScale[indexMap[i]/3]);
02066                 }
02067                 
02068                 if ( isNum(u) && isNum(v) )
02069                 { 
02070                     if ( uv_swap == TRUE )
02071                         pool->Vertex(i)->attrib.SetUV( v, u );
02072                     else
02073                         pool->Vertex(i)->attrib.SetUV( u, v );
02074                 }
02075             }
02076             else if ( numTexGlb && (uCoords != NULL && vCoords !=NULL ) )
02077             {
02078                 float u, v;
02079             
02080                 if ( ignore_tex_offsets ) {
02081                   u = uCoords[indexMap[i]];
02082                   v = 1.0f - vCoords[indexMap[i]];
02083                 } else {
02084                   u = (uCoords[indexMap[i]] - *uOffset) / *uScale;
02085                   v = 1.0f - (( vCoords[indexMap[i]] - *vOffset ) / *vScale);
02086                 }
02087 
02088                 if ( isNum(u) && isNum(v) )
02089                 { 
02090                     if ( uv_swap == TRUE )
02091                         pool->Vertex(i)->attrib.SetUV( v, u );
02092                     else
02093                         pool->Vertex(i)->attrib.SetUV( u, v );
02094                 }
02095                         
02096             }
02097              
02098             // if we've encountered textures and we desire duv anims
02099             if (( numTexLoc || numTexGlb ) && make_duv )
02100             {
02101                 int            numExp;
02102                 SAA_Elem   *tex;
02103 
02104                 // grab the current texture
02105                 if ( numTexLoc ) 
02106                     tex = &textures[0];
02107                 else
02108                     tex = textures;
02109 
02110                 // find how many expressions for this shape
02111                 SAA_elementGetNbExpressions( scene, tex, NULL, FALSE, 
02112                     &numExp );
02113 
02114                 // if it has expressions we'll assume its animated
02115                 if ( numExp )
02116                 {
02117                     // if animated object make base duv's, animtables
02118                     // for the duv's and store the original offsets
02119                     strstream uName, vName;
02120 
02121                     // create duv target names
02122                     uName << name << ".u" << ends;
02123                     vName << name << ".v" << ends;
02124 
02125                     // only create tables and store offsets
02126                     // on a per model basis (not per vertex)
02127                     if ( !i )
02128                     {
02129 
02130                         // make sure root morph table exists
02131                         if ( morphRoot == NULL )
02132                             morphRoot = animData.CreateTable( animRoot, 
02133                                 "morph" ); 
02134 
02135                         // create morph table entry for each duv
02136                         SAnimTable *uTable = new SAnimTable( );     
02137                         uTable->name = uName.str();
02138                         uTable->fps = anim_rate;
02139                         morphRoot->children.push_back( uTable );
02140                         if ( verbose >= 1 )
02141                             fprintf( outStream, "created duv table named: %s\n",                                uName.str() );    
02142 
02143                         SAnimTable *vTable = new SAnimTable( );     
02144                         vTable->name = vName.str();
02145                         vTable->fps = anim_rate;
02146                         morphRoot->children.push_back( vTable );
02147                         if ( verbose >= 1 )
02148                             fprintf( outStream, "created duv table named: %s\n",                                vName.str() );    
02149 
02150                         float    texOffsets[4];
02151 
02152                         if ( numTexGlb )
02153                         {
02154                             texOffsets[0] = *uOffset;
02155                             texOffsets[1] = *vOffset;
02156                             texOffsets[2] = *uScale;
02157                             texOffsets[3] = *vScale;
02158                         }
02159                         else
02160                         {
02161                             texOffsets[0] = uOffset[indexMap[i]/3];
02162                             texOffsets[1] = vOffset[indexMap[i]/3];
02163                             texOffsets[2] = uScale[indexMap[i]/3];
02164                             texOffsets[3] = vScale[indexMap[i]/3];
02165                         }
02166 
02167                         // remember original texture offsets future reference
02168                         SAA_elementSetUserData( scene, model, "TEX_OFFSETS", 
02169                             sizeof( texOffsets ), TRUE, (void  **)&texOffsets );
02170                     }
02171 
02172                     EggMorphOffset *duvU;
02173                     EggMorphOffset *duvV;
02174 
02175                     // generate base duv's for this vertex
02176                     duvU = new EggMorphOffset( uName.str(), 1.0 , 0.0 );    
02177                     pool->Vertex(i)->attrib.uv_morphs.push_back( *duvU );
02178             
02179                     duvV = new EggMorphOffset( vName.str(), 0.0 , 1.0 );    
02180                     pool->Vertex(i)->attrib.uv_morphs.push_back( *duvV );
02181 
02182                 } // if ( numExp )
02183 
02184             } // if ( numTexLoc || numTexGlb )
02185 
02186         } // for ( i = 0; i < numVert; i++ )
02187 
02188         // if model has key shapes, generate vertex offsets
02189         if ( has_morph && make_morph )
02190             MakeVertexOffsets( scene, model, type, numShapes, numVert, 
02191                 vertices, matrix,  name );
02192 
02193 
02194         // create vertex ref list for all polygons in the model
02195         EggVertexRef *vref;
02196 
02197         vref = new EggVertexRef( pool);
02198         for ( i = 0; i < numVert; i++ )
02199         {
02200             //add each vert in pool to last joint for hard skinning
02201             vref->indices.push_back( EggVertexIndex( i ) );
02202         }
02203 
02204         // hard assign poly geometry if no soft-skinning requested
02205         //
02206         //disabled 1/1/99 to streamline joint assignments.
02207         // all hard-skinning now done in CleanUpSoftSkin.
02208         //if ( !make_soft )
02209         //{
02210             //if ( lastJoint != NULL )
02211             //{
02212                 //lastJoint->vrefs.AddUniqueNode( *vref );
02213 
02214                 //if ( verbose >= 1 )
02215                     //fprintf( outStream, "hard-skinning %s (%d vertices)\n", 
02216                         //name, i+1 );
02217             //}
02218         //}
02219 
02220         // make an egg group to hold all triangles
02221         EggGroup *group = _data.CreateGroup( parent, name);
02222 
02223         // make this group the current parent
02224         parent = group;
02225 
02226         EggPolygon *poly = NULL;
02227         EggColor *cref = NULL;
02228         EggTexture *tref = NULL;
02229 
02230         // for each triangle
02231         for ( i = 0; i < numTri*3; i+=3 )
02232         {
02233             float    r,g,b,a;
02234             pfVec4    color;
02235 
02236             // make egg poly for each traingle and reference
02237             // the appropriate vertex in the pool
02238             poly = _data.CreatePolygon( group, pool );
02239             poly->AddVertex(indices[i]);
02240             poly->AddVertex(indices[i+1]);
02241             poly->AddVertex(indices[i+2]);
02242 
02243             // check for back face flag in model note info
02244             char *modelNoteStr = GetModelNoteInfo( scene, model );
02245 
02246             if ( modelNoteStr != NULL )
02247             {
02248                 if ( strstr( modelNoteStr, "bface" ) != NULL )
02249                     poly->flags |= EG_BFACE;
02250             }
02251             
02252             // check to see if material is present
02253             SAA_Boolean    valid;
02254             SAA_elementIsValid( scene, &materials[i/3], &valid );
02255 
02256             // material present - get the color 
02257             if ( valid )
02258             {
02259                 SAA_materialGetDiffuse( scene, &materials[i/3], &r, &g, &b );
02260                 SAA_materialGetTransparency( scene, &materials[i/3], &a );
02261                 color.set( r, g, b, 1.0f - a );
02262             }
02263             // no material - default to white
02264             else
02265                 color.set( 1.0, 1.0, 1.0, 1.0 );
02266 
02267             cref = _data.CreateColor(color);
02268             poly->attrib.SetCRef(cref);
02269 
02270             strstream uniqueTexName;
02271 
02272             if (numTexLoc)
02273             {
02274                 // polytex
02275                 if ( (texNameArray[i/3] != NULL) &&
02276                         (strcmp(texNameArray[i/3], "NULL") != 0) )
02277                 {
02278                     // append unique identifier to texname for
02279                     // this particular object
02280                     uniqueTexName << name << "-" 
02281                         << RemovePathName(texNameArray[i/3]);
02282 
02283                     tref = _data.CreateTexture( texNameArray[i/3], 
02284                         uniqueTexName.str() ); 
02285 
02286                     if ( verbose >= 1 )
02287                         fprintf( outStream, " tritex[%d] named: %s\n", i/3, 
02288                             texNameArray[i/3] );
02289                 }
02290             }
02291             else if ( numTexGlb )
02292             {
02293                 if ( texNameArray != NULL )
02294                 {
02295                     // append unique identifier to texname for
02296                     // this particular object
02297                     uniqueTexName << name << "-"
02298                         << RemovePathName(*texNameArray);
02299 
02300                     tref = _data.CreateTexture( *texNameArray, 
02301                         uniqueTexName.str() );
02302 
02303                     if ( verbose >= 1 )
02304                         fprintf( outStream, " tritex named: %s\n",
02305                              *texNameArray );
02306                 }
02307             }
02308 
02309             // set the clamp on the texture
02310             if ( tref != NULL )
02311             {
02312                 if ( uRepeat > 0 )
02313                     tref->wrapu = EggTexture::WM_repeat;
02314                 else
02315                     tref->wrapu = EggTexture::WM_clamp;
02316 
02317                 if ( vRepeat > 1 )
02318                     tref->wrapv = EggTexture::WM_repeat;
02319                 else
02320                     tref->wrapv = EggTexture::WM_clamp;
02321 
02322                 poly->attrib.SetTRef(tref);
02323             }
02324 
02325         }
02326 
02327         // we're done - trash triangles...
02328         SAA_modelClearTriangles( scene, model );
02329 
02330         // free molloc'd memory
02331         //free( triangles );
02332         //free( materials );
02333         //free( normals );
02334         //free( cvertices );
02335         //free( vertices );
02336         //free( indices );
02337         //free( indexMap );
02338 
02339         // free these only if they were malloc'd for textures
02340         if (numTexLoc || numTexGlb)
02341         {
02342             //free( textures );
02343             //free( uCoords );
02344             //free( vCoords );
02345             //free( texNameArray );
02346             //free( uScale );
02347             //free( vScale );
02348             //free( uOffset );
02349             //free( vOffset );
02350         }
02351       }
02352     }
02353     else
02354     {
02355         ///////////////////////////////////////
02356         // check to see if its a nurbs surface
02357         ///////////////////////////////////////
02358         if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs ) 
02359             || ( !make_nurbs && !make_poly &&  make_duv )) )
02360         {
02361             // check to see if NURBS is also skeleton...
02362             SAA_Boolean isSkeleton = FALSE;
02363 
02364             SAA_modelIsSkeleton( scene, model, &isSkeleton );
02365 
02366             // check to see if this NURBS is used as a skeleton
02367             // or is animated via constraint only ( these nodes are
02368             // tagged by the animator with the keyword "joint"
02369             // somewhere in the nodes name)
02370             if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
02371             {
02372                 MakeJoint( scene, lastJoint, lastAnim, model, name );
02373                 geom_as_joint = 1;
02374                 if ( verbose >= 1 )
02375                     fprintf( outStream, "animating NURBS as joint!!!\n" );
02376             }
02377 
02378             EggNurbsSurface    *eggNurbsSurf = new EggNurbsSurface( name );
02379             int uDegree, vDegree;
02380 
02381             // create nurbs representation of surface
02382             SAA_nurbsSurfaceGetDegree( scene, model, &uDegree, &vDegree );
02383             eggNurbsSurf->u_order = uDegree + 1;
02384             eggNurbsSurf->v_order = vDegree + 1;
02385             if ( verbose >= 1 )
02386             {
02387                 fprintf( outStream, "nurbs degree: %d u, %d v\n", 
02388                     uDegree, vDegree );
02389                 fprintf( outStream, "nurbs order: %d u, %d v\n", 
02390                     uDegree + 1, vDegree + 1 );
02391             }
02392 
02393             SAA_Boolean    uClosed = FALSE;
02394             SAA_Boolean    vClosed = FALSE;
02395 
02396             SAA_nurbsSurfaceGetClosed( scene, model, &uClosed, &vClosed);    
02397 
02398             if ( verbose >= 1 )
02399             {    
02400                 if ( uClosed )
02401                     fprintf( outStream, "nurbs is closed in u...\n");
02402                 if ( vClosed )
02403                     fprintf( outStream, "nurbs is closed in v...\n");
02404             }    
02405             
02406             int uRows, vRows;
02407             SAA_nurbsSurfaceGetNbVertices( scene, model, &uRows, &vRows );
02408             if ( verbose >= 1 )
02409                 fprintf( outStream, "nurbs vertices: %d u, %d v\n", 
02410                     uRows, vRows );
02411             
02412             int uCurves, vCurves;
02413             SAA_nurbsSurfaceGetNbCurves( scene, model, &uCurves, &vCurves );
02414             if ( verbose >= 1 )
02415                 fprintf( outStream, "nurbs curves: %d u, %d v\n", 
02416                     uCurves, vCurves );
02417 
02418             if ( shift_textures )
02419             {
02420             if ( uClosed )
02421                 // shift starting point on NURBS surface for correct textures
02422                 SAA_nurbsSurfaceShiftParameterization( scene, model, -2, 0 );
02423 
02424             if ( vClosed )
02425                 // shift starting point on NURBS surface for correct textures
02426                 SAA_nurbsSurfaceShiftParameterization( scene, model, 0, -2 );
02427             }
02428 
02429             SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
02430 
02431             // check for back face flag in model note info
02432             char *modelNoteStr = GetModelNoteInfo( scene, model );
02433 
02434             if ( modelNoteStr != NULL )
02435             {
02436                 if ( strstr( modelNoteStr, "bface" ) != NULL )
02437                     eggNurbsSurf->flags |= EG_BFACE;
02438             }
02439             
02440             int numKnotsU, numKnotsV;
02441             
02442             SAA_nurbsSurfaceGetNbKnots( scene, model, &numKnotsU, &numKnotsV );
02443             if ( verbose >= 1 )
02444                 fprintf( outStream, "nurbs knots: %d u, %d v\n", 
02445                     numKnotsU, numKnotsV );
02446 
02447             double *knotsU, *knotsV;    
02448             knotsU = (double *)malloc(sizeof(double)*numKnotsU);
02449             knotsV = (double *)malloc(sizeof(double)*numKnotsV);
02450             SAA_nurbsSurfaceGetKnots( scene, model, gtype, 0, 
02451                 numKnotsU, numKnotsV, knotsU, knotsV );
02452 
02453             if ( verbose >= 2 )
02454                 fprintf( outStream, "u knots:\n" );
02455 
02456             AddKnots( eggNurbsSurf->u_knots, knotsU, numKnotsU, uClosed, uDegree ); 
02457             if ( verbose >= 2 )
02458                 fprintf( outStream, "v knots:\n" );
02459 
02460             AddKnots( eggNurbsSurf->v_knots, knotsV, numKnotsV, vClosed, vDegree); 
02461 
02462             //free( knotsU );
02463             //free( knotsV );
02464 
02465             // set sub_div so we can see it in perfly
02466             eggNurbsSurf->u_subdiv = (uRows-1)*nurbs_step;
02467             eggNurbsSurf->v_subdiv = (vRows-1)*nurbs_step;
02468 
02469             SAA_modelGetNbVertices( scene, model, &numVert );
02470         
02471             if ( verbose >= 2 )    
02472                 fprintf( outStream, "%d CV's\n", numVert ); 
02473 
02474             // get the CV's
02475             vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert);
02476             SAA_modelGetVertices( scene, model, gtype, 0,
02477                 numVert, vertices );
02478 
02479             // create pool of NURBS vertices 
02480             EggVertexPool *pool = _data.CreateVertexPool( parent, name );
02481             eggNurbsSurf->SetVertexPool( pool );
02482 
02483             // create vertex ref list for all cv's in the model
02484             EggVertexRef *vref;
02485 
02486             vref = new EggVertexRef( pool);
02487 
02488             for ( int k = 0; k<numVert; k++ )
02489             {
02490                 if ( verbose >= 2 )
02491                 {
02492                     fprintf( outStream, "original cv[%d] = %f %f %f %f\n", k, 
02493                         vertices[k].x, vertices[k].y, vertices[k].z, 
02494                         vertices[k].w );
02495                 }
02496 
02497                 pfVec4  eggVert;
02498 
02499                 // convert to global coords
02500                 SAA_DVector global;
02501 
02502                 _VCT_X_MAT( global, vertices[k], matrix );
02503 
02504                 //preserve original weight
02505                 global.w = vertices[k].w;
02506 
02507                 // normalize coords to weight
02508                 global.x *= global.w;
02509                 global.y *= global.w;
02510                 global.z *= global.w;
02511 
02512                 // this code is commented out because I
02513                 // am no longer sending global data to
02514                 // the other routines (ie makevertexoffset)
02515 
02516                 // set vertices array to reflect global coords
02517                 //vertices[k].x = global.x;
02518                 //vertices[k].y = global.y;
02519                 //vertices[k].z = global.z;
02520                 //vertices[k].w = global.w;
02521 
02522                 //if ( verbose >= 2 )
02523                 //{
02524                     //fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k, 
02525                         //vertices[k].x, vertices[k].y, vertices[k].z, 
02526                         //vertices[k].w );
02527                 //}
02528 
02529                 //eggVert.set( vertices[k].x, vertices[k].y, vertices[k].z, 
02530                     //vertices[k].w );
02531 
02532                 if ( verbose >= 2 )
02533                 {
02534                     fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k, 
02535                         global.x, global.y, global.z, 
02536                         global.w );
02537                 }
02538 
02539                 eggVert.set( global.x, global.y, global.z, 
02540                     global.w );
02541 
02542                 // populate vertex pool
02543                 pool->AddVertex( eggVert, k );
02544 
02545                 // add vref's to NURBS info 
02546                 eggNurbsSurf->AddVertex( k ); 
02547 
02548                 //add each vert in pool to vref for hard skinning
02549                 vref->indices.push_back( EggVertexIndex( k ) );
02550                 
02551                 // check to see if the NURB is closed in u    
02552                 if ( uClosed )
02553                 {
02554                     // add first uDegree verts to end of row
02555                     if ( (k % uRows) == ( uRows - 1) )
02556                     for ( int i = 0; i < uDegree; i++ ) 
02557                     {
02558                         // add vref's to NURBS info 
02559                         eggNurbsSurf->AddVertex( i+((k/uRows)*uRows) ); 
02560 
02561                         //add each vert to vref 
02562                         vref->indices.push_back( 
02563                             EggVertexIndex( i+((k/uRows)*uRows) ) );
02564                     }
02565                 } 
02566             }
02567 
02568             // if hard skinned or this nurb is also a joint
02569             //
02570             //disabled 1/1/99 to streamline joint assignments.
02571             // all hard skinning now done in CleanUpSoftSkin.
02572             //if (!make_soft || geom_as_joint)
02573             //{
02574                 //add the new cv references to the last 
02575                 //joint for hard skinning only 
02576                 //if ( lastJoint != NULL )
02577                 //{
02578                     //lastJoint->vrefs.AddUniqueNode( *vref );
02579                     //geom_as_joint = 0;    
02580                     //if ( verbose >= 1 )    
02581                         //fprintf( outStream, "Doing NURBS hard skinning...\n");
02582                 //}
02583             //}
02584 
02585             // check to see if the NURB is closed in v    
02586             if ( vClosed && !uClosed )
02587             {
02588                 // add first vDegree rows of verts to end of list
02589                 for ( int i = 0; i < vDegree*uRows; i++ ) 
02590                     eggNurbsSurf->AddVertex( i ); 
02591             }
02592             // check to see if the NURB is closed in u and v    
02593             else if ( vClosed && uClosed )
02594             {
02595                 // add the first (degree) v verts and a few
02596                 // extra - for good measure
02597                 for ( i = 0; i < vDegree; i++ ) 
02598                 {
02599                     // add first vDegree rows of verts to end of list
02600                     for ( j = 0; j < uRows; j++ )
02601                         eggNurbsSurf->AddVertex( j+(i*uRows) );
02602 
02603                     // if u is closed to we have added uDegree
02604                     // verts onto the ends of the rows - add them here too
02605                     for ( k = 0; k < uDegree; k++ )
02606                         eggNurbsSurf->AddVertex( k+(i*uRows)+((k/uRows)*uRows) );
02607                 }
02608 
02609             }
02610 
02611             // get the color of the NURBS surface
02612             int numNurbMats;
02613             EggColor *nurbCref;
02614             pfVec4    nurbColor;
02615 
02616             SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo,
02617                 &numNurbMats ); 
02618 
02619             if ( verbose >= 1 )
02620                 fprintf( outStream, "nurbs surf has %d materials\n", 
02621                     numNurbMats );
02622 
02623             if ( numNurbMats )
02624             {
02625                 float r,g,b,a;
02626 
02627                 materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numNurbMats);
02628                 
02629                 SAA_modelRelationGetMatElements( scene, model, relinfo, 
02630                     numNurbMats, materials ); 
02631 
02632                 SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b );
02633                 SAA_materialGetTransparency( scene, &materials[0], &a );
02634                 nurbColor.set( r, g, b, 1.0f - a );
02635                 //nurbColor.set( r, g, b, 1.0 );
02636 
02637                 nurbCref = _data.CreateColor(nurbColor);
02638                 eggNurbsSurf->attrib.SetCRef(nurbCref);
02639         
02640                 //get the texture of the NURBS surface from the material
02641                 int numNurbTexLoc = 0;
02642                 int numNurbTexGlb = 0;
02643 
02644                 // ASSUME only one texture per material
02645                 SAA_Elem nurbTex;
02646 
02647                 // find out how many local textures per NURBS surface
02648                 // ASSUME it only has one material
02649                 SAA_materialRelationGetT2DLocNbElements( scene, &materials[0],
02650                     FALSE, &relinfo, &numNurbTexLoc );
02651 
02652                 // if present, get local textures
02653                 if ( numNurbTexLoc )
02654                 {
02655                     if ( verbose >= 1 )
02656                         fprintf( outStream, "%s had %d local tex\n", name, 
02657                             numNurbTexLoc );
02658 
02659                     // get the referenced texture
02660                     SAA_materialRelationGetT2DLocElements( scene, &materials[0],
02661                         TEX_PER_MAT, &nurbTex ); 
02662 
02663                 }
02664                 // if no locals, try to get globals
02665                 else
02666                 {
02667                     SAA_modelRelationGetT2DGlbNbElements( scene, model,
02668                         FALSE, &relinfo, &numNurbTexGlb );
02669 
02670                     if ( numNurbTexGlb )
02671                     {
02672                         if ( verbose >= 1 )
02673                             fprintf( outStream, "%s had %d global tex\n", name, 
02674                                 numNurbTexGlb );
02675 
02676                             // get the referenced texture
02677                             SAA_modelRelationGetT2DGlbElements( scene, 
02678                                 model, TEX_PER_MAT, &nurbTex ); 
02679                         }
02680                 }
02681 
02682                 // add tex ref's if we found any textures
02683                 if ( numNurbTexLoc || numNurbTexGlb) 
02684                 {
02685                     char    *texName = NULL;
02686                     char    *uniqueTexName = NULL;
02687                     EggTexture *tref;
02688                     pfMatrix  nurbTexMat;
02689 
02690 
02691                     // convert the texture to .rgb and adjust name 
02692                     texName = ConvertTexture( scene, &nurbTex );
02693 
02694                     // append unique identifier to texname for
02695                     // this particular object
02696                     uniqueTexName = (char *)malloc(sizeof(char)*
02697                         (strlen(name)+strlen(texName)+3) );
02698                     sprintf( uniqueTexName, "%s-%s", name, 
02699                         RemovePathName(texName) );
02700 
02701                     if ( verbose >= 1 )
02702                     {
02703                         fprintf( outStream, "creating tref %s\n", 
02704                             uniqueTexName );
02705                     }
02706 
02707                     tref = _data.CreateTexture( texName, uniqueTexName );
02708 
02709                     uScale = ( float *)malloc(sizeof(float));
02710                     vScale = ( float *)malloc(sizeof(float));
02711                     uOffset = ( float *)malloc(sizeof(float));
02712                     vOffset = ( float *)malloc(sizeof(float));
02713 
02714                     // get texture offset info
02715                     SAA_texture2DGetUScale( scene, &nurbTex, uScale );
02716                     SAA_texture2DGetVScale( scene, &nurbTex, vScale );
02717                     SAA_texture2DGetUOffset( scene, &nurbTex, uOffset );
02718                     SAA_texture2DGetVOffset( scene, &nurbTex, vOffset );
02719                     SAA_texture2DGetUVSwap( scene, &nurbTex, &uv_swap );
02720 
02721 
02722                     if ( verbose >= 1 )
02723                     {
02724                         fprintf( outStream, "nurbTex uScale: %f\n", *uScale );
02725                         fprintf( outStream, "nurbTex vScale: %f\n", *vScale );
02726                         fprintf( outStream, "nurbTex uOffset: %f\n", *uOffset );
02727                         fprintf( outStream, "nurbTex vOffset: %f\n", *vOffset );
02728                         if ( uv_swap )
02729                             fprintf( outStream, "nurbTex u & v swapped!\n" );
02730                         else
02731                             fprintf( outStream, "nurbTex u & v NOT swapped\n" );
02732                     }
02733 
02734                     nurbTexMat.makeIdent();
02735 
02736                     if ( !ignore_tex_offsets )
02737                     {
02738                         if ( uv_swap )
02739                         {
02740                             nurbTexMat[0][0] = 0.0f;
02741                             nurbTexMat[1][1] = 0.0f;
02742                             nurbTexMat[0][1] = 1 / *vScale;
02743                             nurbTexMat[1][0] = 1 / *uScale;
02744                             nurbTexMat[2][1] = -(*uOffset / *uScale);
02745                             nurbTexMat[2][0] = -(*vOffset / *vScale);
02746                         }
02747                         else
02748                         {
02749                             nurbTexMat[0][0] = 1 / *uScale;
02750                             nurbTexMat[1][1] = 1 / *vScale;
02751                             nurbTexMat[2][0] = -(*uOffset / *uScale);
02752                             nurbTexMat[2][1] = -(*vOffset / *vScale);
02753                         }
02754                     }
02755 
02756 
02757     //call printMat
02758     if ( verbose >= 2 )
02759     {    
02760     fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[0][0],
02761          nurbTexMat[0][1],  nurbTexMat[0][2],  nurbTexMat[0][3] ); 
02762     fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[1][0],
02763          nurbTexMat[1][1],  nurbTexMat[1][2],  nurbTexMat[1][3] ); 
02764     fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[2][0],
02765          nurbTexMat[2][1],  nurbTexMat[2][2],  nurbTexMat[2][3] ); 
02766     fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[3][0],
02767          nurbTexMat[3][1],  nurbTexMat[3][2],  nurbTexMat[3][3] ); 
02768     }
02769 
02770 
02771                     tref->tex_mat = nurbTexMat;
02772                     tref->flags |= EFT_TRANSFORM;
02773 
02774                     eggNurbsSurf->attrib.SetTRef(tref);
02775 
02776                 }
02777 
02778                 // if we've encountered textures and we desire duv anims
02779                 if (( numNurbTexLoc || numNurbTexGlb ) && make_duv )
02780                 {
02781                     int            numExp;
02782 
02783                      // find how many expressions for this shape
02784                     SAA_elementGetNbExpressions( scene, &nurbTex, NULL, FALSE, 
02785                         &numExp );
02786 
02787                     // if it has expressions we'll assume its animated
02788                     if ( numExp )
02789                     {
02790                         if ( verbose > 1 )
02791                             printf( "nurbTex has %d expressions...\n", numExp );
02792 
02793                         // if animated object make base duv's, animtables
02794                         // for the duv's and store the original offsets
02795                         strstream uName, vName;
02796 
02797                         // create duv target names
02798                         uName << name << ".u" << ends;
02799                         vName << name << ".v" << ends;
02800 
02801                         // make sure root morph table exists
02802                         if ( morphRoot == NULL )
02803                             morphRoot = animData.CreateTable( animRoot, 
02804                                 "morph" ); 
02805 
02806                         // create morph table entry for each duv
02807                         SAnimTable *uTable = new SAnimTable( );     
02808                         uTable->name = uName.str();
02809                         uTable->fps = anim_rate;
02810                         morphRoot->children.push_back( uTable );
02811                         if ( verbose >= 1 )
02812                             fprintf( outStream, "created duv table named: %s\n",                                uName.str() );    
02813 
02814                         SAnimTable *vTable = new SAnimTable( );     
02815                         vTable->name = vName.str();
02816                         vTable->fps = anim_rate;
02817                         morphRoot->children.push_back( vTable );
02818                         if ( verbose >= 1 )
02819                             fprintf( outStream, "created duv table named: %s\n",                                vName.str() );    
02820 
02821                         float    texOffsets[4];
02822 
02823                         texOffsets[0] = *uOffset;
02824                         texOffsets[1] = *vOffset;
02825                         texOffsets[2] = *uScale;
02826                         texOffsets[3] = *vScale;
02827 
02828                         // remember original texture offsets future reference
02829                         SAA_elementSetUserData( scene, model, "TEX_OFFSETS", 
02830                             sizeof( texOffsets ), TRUE, (void  **)&texOffsets );
02831 
02832                         // create UV's and duv's for each vertex 
02833                         for( i = 0; i < numVert; i++ )
02834                         {
02835                             pfVec2            tmpUV;
02836                             EggMorphOffset *duvU;
02837                             EggMorphOffset *duvV;
02838 
02839                             //create uv's so we can store duv's
02840                             eggNurbsSurf->CalcActualUV( i, tmpUV );
02841                             pool->Vertex(i)->attrib.SetUV( tmpUV[0], tmpUV[1] );
02842                             
02843                             // generate base duv's for this vertex
02844                             duvU = new EggMorphOffset(uName.str(), 1.0 , 0.0);    
02845                             pool->Vertex(i)->attrib.uv_morphs.push_back(*duvU);
02846                     
02847                             duvV = new EggMorphOffset(vName.str(), 0.0 , 1.0);    
02848                             pool->Vertex(i)->attrib.uv_morphs.push_back(*duvV);
02849                         }
02850 
02851                   } // if ( numExp )
02852                 } // if ( numTexLoc || numTexGlb )
02853 
02854                 //free( uScale );
02855                 //free( vScale );
02856                 //free( uOffset );
02857                 //free( vOffset );
02858 
02859                 //free( materials );
02860             }
02861             else
02862             {
02863                 // no material present - default to white 
02864                 nurbColor.set( 1.0, 1.0, 1.0, 1.0 );
02865             }
02866 
02867             //////////////////////////////////////////
02868             // check NURBS surface for trim curves
02869             //////////////////////////////////////////
02870             int     numTrims;
02871             bool    isTrim = TRUE;
02872             SAA_SubElem *trims;
02873         
02874             SAA_nurbsSurfaceGetNbTrimCurves( scene, model, SAA_TRIMTYPE_TRIM,
02875                 &numTrims );
02876 
02877             if ( verbose >= 1 )
02878                 fprintf( outStream, "nurbs surf has %d trim curves\n", 
02879                     numTrims );
02880 
02881             if ( numTrims)
02882             {
02883                 trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims);
02884 
02885                 if ( trims )
02886                 {
02887                     SAA_nurbsSurfaceGetTrimCurves( scene, model, 
02888                         gtype, 0, SAA_TRIMTYPE_TRIM, numTrims, 
02889                         trims );
02890 
02891                     MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, 
02892                         numTrims, trims, isTrim );
02893                 }
02894 
02895                 //free( trims );
02896             }
02897 
02898             //////////////////////////////////////////
02899             // check NURBS surface for surface curves
02900             //////////////////////////////////////////
02901             isTrim = FALSE;
02902 
02903             SAA_nurbsSurfaceGetNbTrimCurves( scene, model, 
02904                 SAA_TRIMTYPE_PROJECTION, &numTrims );
02905 
02906             if ( verbose >= 1 )
02907                 fprintf( outStream, "nurbs surf has %d surface curves\n", 
02908                     numTrims );
02909 
02910             if ( numTrims)
02911             {
02912                 trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims);
02913 
02914                 if ( trims )
02915                 {
02916                     SAA_nurbsSurfaceGetTrimCurves( scene, model, 
02917                         gtype, 0, SAA_TRIMTYPE_PROJECTION, 
02918                         numTrims, trims );
02919 
02920                     MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, 
02921                         numTrims, trims, isTrim );
02922                 }
02923 
02924                 //free( trims );
02925             }
02926 
02927             // push the NURBS into the egg data
02928             parent->children.push_back( eggNurbsSurf );    
02929 
02930             // if model has key shapes, generate vertex offsets
02931             if ( has_morph && make_morph )
02932                 MakeVertexOffsets( scene, model, type, numShapes, numVert, 
02933                     vertices, matrix, name );
02934 
02935 
02936             //free( vertices );
02937 
02938         }
02939         /////////////////////////////////////
02940         // check to see if its a NURBS curve
02941         /////////////////////////////////////
02942         else if ( (type == SAA_MNCRV) && ( visible ) && ( make_nurbs ) )
02943         {
02944             // ignore for now
02945             // make the NURBS curve and push it into the egg data
02946             //parent->children.push_back( MakeNurbsCurve( scene, model, parent, 
02947                 //matrix, name ) );
02948            }
02949         else if ( type == SAA_MJNT )
02950         {
02951             MakeJoint( scene, lastJoint, lastAnim, model, name );
02952             if ( verbose >= 1 )
02953                 fprintf( outStream, "encountered IK joint: %s\n", name );
02954         }
02955         /////////////////////
02956         // it must be a NULL
02957         /////////////////////
02958         else 
02959         {
02960             SAA_AlgorithmType    algo;
02961         
02962             SAA_modelGetAlgorithm( scene, model, &algo );
02963             if ( verbose >= 1 )
02964                 fprintf( outStream, "null algorithm: %d\n", algo );
02965 
02966             if ( algo == SAA_ALG_INV_KIN )
02967             {
02968                 MakeJoint( scene, lastJoint, lastAnim,  model, name );
02969                 if ( verbose >= 1 )
02970                     fprintf( outStream, "encountered IK root: %s\n", name );
02971             }
02972             else if ( algo == SAA_ALG_INV_KIN_LEAF )
02973             {
02974                 MakeJoint( scene, lastJoint, lastAnim, model, name );
02975                 if ( verbose >= 1 )
02976                     fprintf( outStream, "encountered IK leaf: %s\n", name );
02977             }
02978             else if ( algo == SAA_ALG_STANDARD )
02979             {
02980                 SAA_Boolean isSkeleton = FALSE;
02981 
02982                 if ( verbose >= 1 )
02983                     fprintf( outStream, "encountered Standard null: %s\n", name);
02984 
02985                 SAA_modelIsSkeleton( scene, model, &isSkeleton );
02986 
02987                 // check to see if this NULL is used as a skeleton
02988                 // or is animated via constraint only ( these nodes are
02989                 // tagged by the animator with the keyword "joint"
02990                 // somewhere in the nodes name)
02991                 if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
02992                 {
02993                     MakeJoint( scene, lastJoint, lastAnim, model, name );
02994                     if ( verbose >= 1 )
02995                         fprintf( outStream, "animating Standard null!!!\n" );
02996                 }
02997                 
02998             }
02999             else
03000                 if ( verbose >= 1 )
03001                     fprintf( outStream, "encountered some other NULL: %d\n", 
03002                         algo );
03003         }
03004     }
03005 
03006 
03007     // check for children...
03008     int        numChildren;
03009     int        thisChild;
03010     SAA_Elem *children;
03011 
03012     SAA_modelGetNbChildren( scene, model, &numChildren );
03013     if ( verbose >= 1 )
03014         fprintf( outStream, "Model children: %d\n", numChildren );
03015 
03016     if ( numChildren )
03017     {
03018         children = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numChildren);
03019         SAA_modelGetChildren( scene, model, numChildren, children );
03020         if ( children != NULL )
03021         {
03022             for ( thisChild = 0; thisChild < numChildren; thisChild++ )
03023             {
03024                 if ( verbose >= 1 )
03025                     fprintf( outStream, "\negging child %d...\n", thisChild);
03026                 MakeEgg( parent, lastJoint, lastAnim, scene, 
03027                     &children[thisChild] );
03028             }
03029         }
03030         else
03031             fprintf( outStream, "Not enough Memory for children...\n");
03032         //free( children );
03033     }
03034     fflush( outStream );
03035   }
03036   else
03037     if ( verbose >= 1 )
03038         fprintf( outStream, "Don't descend this branch!\n" );
03039     
03040   // we are done for the most part - start cleaning up memory
03041   //free( name );
03042 }
03043 
03044 
03045 ////////////////////////////////////////////////////////////////////
03046 //     Function: MakeSurfaceCurve
03047 //       Access: Public 
03048 //  Description: Given a scene and lists of u and v samples create a
03049 //                an egg NURBS curve of degree two from the samples 
03050 ////////////////////////////////////////////////////////////////////
03051 void  soft2egg::
03052 MakeSurfaceCurve(  SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, 
03053     EggNurbsSurface *&nurbsSurf, int numTrims, SAA_SubElem *trims,
03054     bool isTrim )
03055 {
03056     int      i;
03057     long      totalSamples = 0;
03058     long    *numSamples;
03059     double    *uSamples;
03060     double    *vSamples;
03061     SAA_Elem *trimCurves;
03062     char    *name;
03063 
03064     //get UV coord data
03065     numSamples = (long *)malloc(sizeof(long)*numTrims);
03066 
03067     SAA_surfaceCurveGetNbLinearSamples( scene, model,  numTrims, trims,
03068         numSamples );
03069 
03070     for ( i = 0; i < numTrims; i++ )
03071     {
03072         totalSamples += numSamples[i];
03073         if ( verbose >= 2 )
03074             fprintf( outStream, "numSamples[%d] = %d\n", i, numSamples[i] );
03075     }
03076 
03077     if ( verbose >= 2 )
03078         fprintf( outStream, "total samples = %ld\n", totalSamples );
03079 
03080     uSamples = (double *)malloc(sizeof(double)*totalSamples);
03081     vSamples = (double *)malloc(sizeof(double)*totalSamples);
03082 
03083     SAA_surfaceCurveGetLinearSamples( scene, model, numTrims, trims,
03084         numSamples, uSamples, vSamples ); 
03085 
03086     if ( verbose >= 2 )
03087         for ( long li = 0; li < totalSamples; li++ )
03088             fprintf( outStream, "master list cv[%ld] = %f, %f\n", li, 
03089                 uSamples[li], vSamples[li] ); 
03090 
03091     trimCurves = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTrims);
03092 
03093     SAA_surfaceCurveExtract( scene, model, numTrims, trims, trimCurves );
03094 
03095     // if it's a trim create a trim to assign trim curves to
03096     EggNurbsSurface::Trim *eggTrim = new EggNurbsSurface::Trim();
03097 
03098     // for each trim curve, make an egg curve and 
03099     // add it to the trims of the NURBS surface
03100     for ( i = 0; i < numTrims; i++ )
03101     {
03102         if ( use_prefix )
03103         {
03104             // Get the FULL name of the trim curve
03105             name = GetFullName( scene, &trimCurves[i] );
03106         }
03107         else
03108         {
03109             // Get the name of the trim curve
03110             name = GetName( scene, &trimCurves[i] );
03111         }
03112 
03113         if ( isTrim )
03114         {
03115             // add to trim list
03116             EggNurbsSurface::Loop *eggLoop = new EggNurbsSurface::Loop();
03117             eggLoop->push_back( MakeUVNurbsCurve( i, numSamples, uSamples, 
03118                 vSamples, parent, name ) );
03119             eggTrim->push_back( *eggLoop );
03120         }
03121         else
03122             // add to curve list
03123             nurbsSurf->curves.push_back( MakeUVNurbsCurve( i, numSamples,                         uSamples, vSamples, parent, name ) );
03124     } 
03125 
03126     if ( isTrim )
03127         // pus trim list onto trims list
03128         nurbsSurf->trims.push_back( *eggTrim );
03129 
03130     //free( name );
03131     //free( trimCurves );
03132     //free( uSamples );
03133     //free( vSamples );
03134 }
03135 
03136 ////////////////////////////////////////////////////////////////////
03137 //     Function: MakeUVNurbsCurve
03138 //       Access: Public 
03139 //  Description: Given a scene and lists of u and v samples create a
03140 //                an egg NURBS curve of degree two from the samples 
03141 ////////////////////////////////////////////////////////////////////
03142 EggNurbsCurve  *soft2egg::
03143 MakeUVNurbsCurve( int numCurve, long *numSamples, double *uSamples, 
03144     double *vSamples, EggGroup *parent, char *name )
03145 {
03146     EggNurbsCurve    *eggNurbsCurve = new EggNurbsCurve( name );
03147 
03148     eggNurbsCurve->order = 2;
03149 
03150 
03151     if ( verbose >= 2 )
03152         fprintf( outStream, "nurbs UV curve %s:\n", name );
03153 
03154     //set sub_div so we can see it in perfly
03155     //eggNurbsCurve->subdiv = numSamples[numCurve]/4;
03156     // perfly chokes on big numbers - keep it reasonable
03157     eggNurbsCurve->subdiv = 150; 
03158 
03159     //create pool of NURBS vertices 
03160     EggVertexPool *pool = _data.CreateVertexPool( parent, name );
03161     eggNurbsCurve->SetVertexPool( pool );
03162 
03163     // calculate offset to this curve's samples
03164     // in list of all curve samples
03165     int offset = 0;
03166 
03167     for ( int o = 0; o < numCurve; o++ )
03168         offset += numSamples[o];
03169     
03170     for ( int k = 0; k<numSamples[numCurve]; k++ )
03171     {
03172         pfVec3  eggVert;
03173 
03174         // index into the array of samples for this curve
03175         eggVert.set( uSamples[k+offset], vSamples[k+offset], 1.0f );
03176 
03177         if ( verbose >= 2 )
03178             fprintf( outStream, "cv[%d] = %f %f %f\n", k, eggVert[0], 
03179                 eggVert[1], eggVert[2] ); 
03180 
03181         //populate vertex pool
03182         pool->AddVertex( eggVert, k );
03183 
03184         //add vref's to NURBS info 
03185         eggNurbsCurve->AddVertex( k ); 
03186     }
03187 
03188     // create numSamples[numCurve]+2 knots
03189     eggNurbsCurve->knots.push_back( 0 );
03190     for ( k = 0; k < numSamples[numCurve]; k++ )
03191         eggNurbsCurve->knots.push_back( k  );
03192     eggNurbsCurve->knots.push_back( numSamples[numCurve] - 1 );
03193 
03194     //set color to bright green for now
03195     EggColor *nurbCref;
03196     pfVec4    nurbColor;
03197 
03198     nurbColor.set( 0.5, 1.0, 0.5, 1.0 );
03199     nurbCref = _data.CreateColor(nurbColor);
03200     eggNurbsCurve->attrib.SetCRef(nurbCref);
03201 
03202     return( eggNurbsCurve );
03203 }
03204 
03205 ////////////////////////////////////////////////////////////////////
03206 //     Function: MakeNurbsCurve
03207 //       Access: Public 
03208 //  Description: Given a scene and a NURBS curve model create the
03209 //                 the appropriate egg structures  
03210 ////////////////////////////////////////////////////////////////////
03211 EggNurbsCurve  *soft2egg::
03212 MakeNurbsCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, 
03213     float matrix[4][4], char *name )
03214 {
03215     EggNurbsCurve    *eggNurbsCurve = new EggNurbsCurve( name );
03216     int degree;
03217 
03218     if ( verbose >= 2 )
03219         fprintf( outStream, "nurbs curve %s:\n", name );
03220 
03221     //create nurbs representation of surface
03222     SAA_nurbsCurveGetDegree( scene, model, &degree );
03223     eggNurbsCurve->order = degree + 1;
03224     if ( verbose >= 2 )
03225         fprintf( outStream, "nurbs curve order: %d\n", degree + 1 );
03226     
03227     SAA_nurbsCurveSetStep( scene, model, nurbs_step );
03228 
03229     SAA_Boolean    closed = FALSE;
03230 
03231     SAA_nurbsCurveGetClosed( scene, model, &closed );    
03232     if ( closed )
03233         if ( verbose >= 2 )
03234             fprintf( outStream, "nurbs curve is closed...\n");
03235 
03236     int numKnots;
03237     
03238     SAA_nurbsCurveGetNbKnots( scene, model, &numKnots );
03239     if ( verbose >= 2 )
03240         fprintf( outStream, "nurbs curve knots: %d\n", numKnots );
03241     double *knots;    
03242     knots = (double *)malloc(sizeof(double)*numKnots);
03243     SAA_nurbsCurveGetKnots( scene, model, SAA_GEOM_ORIGINAL, 0, 
03244         numKnots, knots );
03245 
03246     AddKnots( eggNurbsCurve->knots, knots, numKnots, closed, degree );
03247 
03248     //free( knots );
03249 
03250     int    numCV;
03251 
03252     SAA_modelGetNbVertices( scene, model, &numCV );
03253     if ( verbose >= 2 )
03254         fprintf( outStream, "%d CV's (=? %d)\n", numCV, (numKnots-(degree+1)) );
03255 
03256     //set sub_div so we can see it in perfly
03257     eggNurbsCurve->subdiv = (numCV-1)*nurbs_step;
03258 
03259     // get the CV's
03260     SAA_DVector *cvArray;
03261     cvArray = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
03262     SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
03263         numCV, cvArray );
03264 
03265     //create pool of NURBS vertices 
03266     EggVertexPool *pool = _data.CreateVertexPool( parent, name );
03267     eggNurbsCurve->SetVertexPool( pool );
03268 
03269     for ( int k = 0; k<numCV; k++ )
03270     {
03271         if ( verbose >= 2 )
03272             fprintf( outStream, "cv[%d] = %f %f %f %f\n", k, cvArray[k].x,
03273                 cvArray[k].y, cvArray[k].z, cvArray[k].w );
03274 
03275         pfVec4  eggVert;
03276 
03277         //convert to global coords
03278         SAA_DVector local = cvArray[k];
03279         SAA_DVector global;
03280 
03281         _HVCT_X_MAT( global, local, matrix );
03282 
03283         eggVert.set( global.x, global.y, global.z, global.w );
03284 
03285         //populate vertex pool
03286         pool->AddVertex( eggVert, k );
03287 
03288         //add vref's to NURBS info 
03289         eggNurbsCurve->AddVertex( k ); 
03290     }
03291 
03292     if ( closed )
03293     {
03294         // need to replicate first (degree) vertices
03295         for ( k = 0; k < degree; k++ )
03296         {
03297             eggNurbsCurve->AddVertex( k );
03298             if ( verbose >= 2 )
03299                 fprintf( outStream, "adding cv[%d] = %f %f %f %f\n", k, 
03300                     cvArray[k].x, cvArray[k].y, cvArray[k].z, cvArray[k].w );
03301         }
03302     }
03303 
03304     //free( cvArray );
03305 
03306     //set color to bright green for now
03307     EggColor *nurbCref;
03308     pfVec4    nurbColor;
03309 
03310     nurbColor.set( 0.5, 1.0, 0.5, 1.0 );
03311     nurbCref = _data.CreateColor(nurbColor);
03312     eggNurbsCurve->attrib.SetCRef(nurbCref);
03313 
03314     return( eggNurbsCurve );
03315 }
03316 
03317 ////////////////////////////////////////////////////////////////////
03318 //     Function: AddKnots
03319 //       Access: Public 
03320 //  Description: Given a parametric surface, and its knots, create
03321 //                 the appropriate egg structure by filling in Soft's
03322 //                 implicit knots and assigning the rest to eggKnots. 
03323 ////////////////////////////////////////////////////////////////////
03324 void soft2egg::
03325 AddKnots( perf_vector<double> &eggKnots, double *knots, int numKnots, 
03326     SAA_Boolean closed, int degree ) 
03327 {
03328     int k = 0;
03329     double lastKnot = knots[0];
03330     double    *newKnots;
03331 
03332     // add initial implicit knot(s)
03333     if ( closed ) 
03334     {
03335         int i = 0;
03336         newKnots = (double *)malloc(sizeof(double)*degree);
03337 
03338         // need to add (degree) number of knots 
03339         for ( k = numKnots - 1; k >= numKnots - degree; k-- )
03340         {
03341             // we have to know these in order to calculate
03342             // next knot value so hold them in temp array
03343             newKnots[i] =  lastKnot - (knots[k] - knots[k-1]);
03344             lastKnot = newKnots[i];
03345             i++;
03346         }
03347         for ( k = degree - 1; k >= 0; k-- )
03348         {
03349             eggKnots.push_back( newKnots[k] );
03350             if ( verbose >= 2 )
03351                 fprintf( outStream, "knots[%d] = %f\n", k, newKnots[k] ); 
03352         }
03353 
03354         //free( newKnots );
03355     }
03356     else
03357     {
03358         eggKnots.push_back( knots[k] );
03359         if ( verbose >= 2 )
03360             fprintf( outStream, "knots[%d] = %f\n", k, knots[k] ); 
03361     }
03362 
03363     // add the regular complement of knots
03364     for (k = 0; k < numKnots; k++)
03365     {
03366         eggKnots.push_back( knots[k] );
03367         if ( verbose >= 2 )
03368             fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k] ); 
03369     }
03370 
03371     lastKnot = knots[numKnots-1];
03372 
03373     // add trailing implicit knots
03374     if ( closed ) 
03375     {
03376 
03377         // need to add (degree) number of knots 
03378         for ( k = 1; k <= degree; k++ )
03379         {
03380             eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) );
03381             if ( verbose >= 2 )
03382                 fprintf( outStream, "knots[%d] = %f\n", k, 
03383                     lastKnot + (knots[k] - knots[k-1]) ); 
03384             lastKnot = lastKnot + (knots[k] - knots[k-1]);
03385         }
03386     }
03387     else
03388     {
03389         eggKnots.push_back( knots[k-1] );
03390         if ( verbose >= 2 )
03391             fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k-1] ); 
03392     }
03393 }
03394 
03395 ////////////////////////////////////////////////////////////////////
03396 //     Function: MakeJoint
03397 //       Access: Public 
03398 //  Description: Given a name, a parent and a model create a new 
03399 //                 a new EggJoint for that model. 
03400 ////////////////////////////////////////////////////////////////////
03401 void soft2egg::
03402 MakeJoint( SAA_Scene *scene, EggJoint *&lastJoint, AnimGroup *&lastAnim, 
03403     SAA_Elem *model, char *name )
03404 {
03405     float     matrix[4][4];
03406     pfMatrix  Matrix;
03407     EggJoint *joint;
03408     SAA_Boolean    globalFlag = FALSE;
03409     int    scale_joint = 0;
03410 
03411 
03412     // this is a quick fix to make scaled skeletons possible
03413     // if the parent contains the keyword "scale" make this joint
03414     // a global root joint instead of a child...
03415     if (lastJoint != NULL)
03416     {
03417         if ( strstr( lastJoint->name.Str(), "scale" ) != NULL )
03418         {
03419             scale_joint = 1;    
03420             if ( verbose >= 1 )
03421                 fprintf( outStream, "scale joint flag set!\n" );
03422         }
03423     }
03424 
03425     // if not root, flatten is false, and last joint had no scaling
03426     // applied to it, then create joint in skeleton tree
03427     if ( (lastJoint != NULL) && !flatten && !scale_joint )
03428     {
03429         if ( verbose >= 1 )
03430         {
03431             fprintf( outStream, "lastJoint = %s\n", lastJoint->name.Str() );
03432             fprintf( outStream, "getting local transform\n" );
03433         }
03434 
03435         SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
03436             TRUE, (void  **)&globalFlag );
03437 
03438         // get the local matrix
03439         SAA_modelGetMatrix( scene, model, SAA_COORDSYS_LOCAL,  matrix );
03440 
03441         // make this into a pfMatrix
03442         Matrix[0][0] = matrix[0][0];
03443         Matrix[0][1] = matrix[0][1];
03444         Matrix[0][2] = matrix[0][2];
03445         Matrix[0][3] = matrix[0][3];
03446         Matrix[1][0] = matrix[1][0];
03447         Matrix[1][1] = matrix[1][1];
03448         Matrix[1][2] = matrix[1][2];
03449         Matrix[1][3] = matrix[1][3];
03450         Matrix[2][0] = matrix[2][0];
03451         Matrix[2][1] = matrix[2][1];
03452         Matrix[2][2] = matrix[2][2];
03453         Matrix[2][3] = matrix[2][3];
03454         Matrix[3][0] = matrix[3][0];
03455         Matrix[3][1] = matrix[3][1];
03456         Matrix[3][2] = matrix[3][2];
03457         Matrix[3][3] = matrix[3][3];
03458 
03459         joint = _data.CreateJoint( lastJoint, name ); 
03460         joint->transform = Matrix;
03461     }
03462     // if we already have a root attach this joint to it
03463     else if (foundRoot)
03464     {
03465         if ( verbose >= 1 )
03466             fprintf( outStream, "getting global transform\n" );
03467 
03468         globalFlag = TRUE;
03469 
03470         SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
03471             TRUE, (void *)&globalFlag );
03472 
03473         // get the global matrix
03474         SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL,  matrix );
03475 
03476         // make this into a pfMatrix
03477         Matrix[0][0] = matrix[0][0];
03478         Matrix[0][1] = matrix[0][1];
03479         Matrix[0][2] = matrix[0][2];
03480         Matrix[0][3] = matrix[0][3];
03481         Matrix[1][0] = matrix[1][0];
03482         Matrix[1][1] = matrix[1][1];
03483         Matrix[1][2] = matrix[1][2];
03484         Matrix[1][3] = matrix[1][3];
03485         Matrix[2][0] = matrix[2][0];
03486         Matrix[2][1] = matrix[2][1];
03487         Matrix[2][2] = matrix[2][2];
03488         Matrix[2][3] = matrix[2][3];
03489         Matrix[3][0] = matrix[3][0];
03490         Matrix[3][1] = matrix[3][1];
03491         Matrix[3][2] = matrix[3][2];
03492         Matrix[3][3] = matrix[3][3];
03493 
03494         if ( verbose >= 1 )
03495             fprintf( outStream, "attaching orphan chain to root\n" );
03496 
03497         joint = _data.CreateJoint( rootJnt, name ); 
03498         joint->transform = Matrix;
03499         lastAnim = rootAnim;    
03500     }
03501     // if root, make a seperate tree for skeleton and
03502     // create required Table for the Egg heirarchy
03503     else 
03504     {
03505         if ( verbose >= 1 )
03506             fprintf( outStream, "getting global transform\n" );
03507 
03508         globalFlag = TRUE;
03509 
03510         SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
03511             TRUE, (void *)&globalFlag );
03512 
03513         // get the global matrix
03514         SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL,  matrix );
03515 
03516         // make this into a pfMatrix
03517         Matrix[0][0] = matrix[0][0];
03518         Matrix[0][1] = matrix[0][1];
03519         Matrix[0][2] = matrix[0][2];
03520         Matrix[0][3] = matrix[0][3];
03521         Matrix[1][0] = matrix[1][0];
03522         Matrix[1][1] = matrix[1][1];
03523         Matrix[1][2] = matrix[1][2];
03524         Matrix[1][3] = matrix[1][3];
03525         Matrix[2][0] = matrix[2][0];
03526         Matrix[2][1] = matrix[2][1];
03527         Matrix[2][2] = matrix[2][2];
03528         Matrix[2][3] = matrix[2][3];
03529         Matrix[3][0] = matrix[3][0];
03530         Matrix[3][1] = matrix[3][1];
03531         Matrix[3][2] = matrix[3][2];
03532         Matrix[3][3] = matrix[3][3];
03533 
03534         rootJnt = _data.CreateJoint( skeleton, "root" );
03535         rootJnt->transform.makeIdent();
03536         if ( verbose >= 1 )
03537             fprintf( outStream, "setting skeleton root\n" );
03538         rootJnt->flags |= EF_TRANSFORM;
03539 
03540         joint = _data.CreateJoint( rootJnt, name ); 
03541         joint->transform = Matrix;
03542         foundRoot = TRUE;
03543         if ( verbose >= 1 )
03544             fprintf( outStream, "found first chain\n" );
03545 
03546         // make skeleton table
03547         AnimGroup *skeletonTable;
03548         skeletonTable = animData.CreateTable( animRoot, "<skeleton>" ); 
03549         rootAnim = animData.CreateTable( skeletonTable, "root" ); 
03550         XfmSAnimTable *table = new XfmSAnimTable( );     
03551         table->name = "xform";
03552         table->fps = anim_rate;
03553         rootAnim->children.push_back( table );
03554         lastAnim = rootAnim;    
03555     }
03556 
03557     joint->flags |= EF_TRANSFORM;
03558 
03559     //if ( make_anim)
03560     //{
03561         AnimGroup *anim = animData.CreateTable( lastAnim, name );
03562         XfmSAnimTable *table = new XfmSAnimTable( );     
03563         if ( verbose >= 1 )
03564             fprintf( outStream, "created anim table: %s\n", "xform" );
03565         table->name = "xform";
03566         table->fps = anim_rate;
03567         anim->children.push_back( table );
03568         lastAnim = anim;
03569     //}
03570 
03571     // make this joint current parent of chain
03572     lastJoint = joint;
03573 }
03574 
03575 
03576 ////////////////////////////////////////////////////////////////////
03577 //     Function: MakeSoftSkin
03578 //       Access: Public 
03579 //  Description: Given a skeleton part find its envelopes (if any)
03580 //                 get the vertices associated with the envelopes and
03581 //                 their weights and make vertex ref's for the joint 
03582 ////////////////////////////////////////////////////////////////////
03583 void soft2egg::
03584 MakeSoftSkin( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
03585     int numModels, char *name )
03586 {
03587     int            numEnv;
03588     SAA_ModelType   type;
03589     SAA_Elem    *envelopes;
03590 
03591     if ( verbose >= 1 )
03592         fprintf( outStream, "\n>found skeleton part( %s )!\n", name );
03593 
03594     SAA_skeletonGetNbEnvelopes( scene, model, &numEnv );
03595     
03596     if ( numEnv )
03597     {
03598         // it's got envelopes - must be soft skinned
03599         if ( verbose >= 1 )
03600             fprintf( outStream, "numEnv = %d\n", numEnv );
03601 
03602         // allocate envelope array
03603         envelopes = ( SAA_Elem *)malloc( sizeof( SAA_Elem )*numEnv );
03604 
03605         if ( envelopes != NULL )
03606         {
03607             int         thisEnv;
03608             SAA_EnvType envType;
03609             bool        hasEnvVertices = 0;
03610 
03611             SAA_skeletonGetEnvelopes( scene, model, numEnv, envelopes );
03612 
03613             for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ )
03614             {
03615                 if ( verbose >= 1 )
03616                     fprintf( outStream, "env[%d]: ", thisEnv );
03617 
03618                 SAA_envelopeGetType( scene, &envelopes[thisEnv], &envType );
03619 
03620                 if ( envType == SAA_ENVTYPE_NONE )
03621                 {
03622                     if ( verbose >= 1 )
03623                         fprintf( outStream, "envType = none\n" );
03624                 }
03625                 else if ( envType == SAA_ENVTYPE_FLXLCL )
03626                 {
03627                     if ( verbose >= 1 )
03628                         fprintf( outStream, "envType = flexible, local\n" );
03629                     hasEnvVertices = 1;
03630                 }
03631                 else if ( envType == SAA_ENVTYPE_FLXGLB )
03632                 {
03633                     if ( verbose >= 1 )
03634                         fprintf( outStream, "envType = flexible, global\n" );
03635                     hasEnvVertices = 1;
03636                 }
03637                 else if ( envType == SAA_ENVTYPE_RGDGLB )
03638                 {
03639                     if ( verbose >= 1 )
03640                         fprintf( outStream, "envType = rigid, global\n" );
03641                     hasEnvVertices = 1;
03642                 }
03643                 else
03644                 {
03645                     if ( verbose >= 1 )
03646                         fprintf( outStream, "envType = unknown\n" );
03647                 }
03648             }
03649 
03650             if ( hasEnvVertices)
03651             {
03652                 int            *numEnvVertices;
03653                 SAA_SubElem    *envVertices = NULL;
03654 
03655                 numEnvVertices = (int *)malloc(sizeof(int)*numEnv);
03656 
03657                 SAA_envelopeGetNbCtrlVertices( scene, model, numEnv,
03658                     envelopes, numEnvVertices );
03659 
03660                 if ( numEnvVertices != NULL )
03661                 {
03662                     int totalEnvVertices = 0;
03663                     int    i,j,k;
03664 
03665                     for( i = 0; i < numEnv; i++ )
03666                     {
03667                         totalEnvVertices += numEnvVertices[i];
03668                         if ( verbose >= 1 )
03669                             fprintf( outStream, "numEnvVertices[%d] = %d\n", 
03670                                 i, numEnvVertices[i] );
03671                     }
03672 
03673 
03674                     if ( verbose >= 1 )
03675                         fprintf( outStream, "total env verts = %d\n", 
03676                             totalEnvVertices );    
03677 
03678                     if ( totalEnvVertices )
03679                     {
03680                     envVertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*totalEnvVertices);
03681 
03682                     if ( envVertices != NULL )
03683                     {
03684 
03685                         SAA_envelopeGetCtrlVertices( scene, model,
03686                             numEnv, envelopes, numEnvVertices, envVertices);
03687             
03688                         // loop through for each envelope
03689                         for ( i = 0; i < numEnv; i++ )
03690                         {
03691                             float *weights = NULL;
03692                             int       vertArrayOffset = 0;
03693 
03694                             if ( verbose >= 2 )
03695                                 fprintf( outStream, "\nenvelope[%d]:\n", i );
03696 
03697                             weights = (float *)malloc(sizeof(float)*numEnvVertices[i]);
03698 
03699                             if ( weights )
03700                             {
03701                             char *envName;
03702                             int *vpoolMap = NULL;
03703 
03704                             for ( j = 0; j < i; j++ )
03705                                 vertArrayOffset += numEnvVertices[j];
03706 
03707                             if ( verbose >= 1 )
03708                                 fprintf( outStream, 
03709                                     "envVertArray offset = %d\n", 
03710                                     vertArrayOffset );
03711 
03712                             // get the weights of the envelope vertices
03713                             SAA_ctrlVertexGetEnvelopeWeights( 
03714                                     scene, model, &envelopes[i], 
03715                                     numEnvVertices[i], 
03716                                     &envVertices[vertArrayOffset], weights ); 
03717 
03718                             // Get the name of the envelope model
03719                             if ( use_prefix )
03720                             {
03721                                 // Get the FULL name of the envelope
03722                                 envName = GetFullName( scene, &envelopes[i] );
03723                             }
03724                             else
03725                             {
03726                                 // Get the name of the envelope
03727                                 envName = GetName( scene, &envelopes[i] );
03728                             }
03729 
03730                             if ( verbose >= 1 )
03731                                 fprintf( outStream, "envelope name %s\n", envName );
03732 
03733                             // find out if envelope geometry is poly or nurb
03734                             //SAA_modelGetType( scene, 
03735                                 //FindModelByName( envName, scene, 
03736                                     //models, numModels ), &type );
03737 
03738                             SAA_modelGetType( scene, &envelopes[i], &type );
03739 
03740                             if ( verbose >= 1 )
03741                             {
03742                                 fprintf( outStream, "envelope model type ");
03743 
03744                                 if ( type == SAA_MSMSH )
03745                                         fprintf( outStream, "MESH\n" );
03746                                 else if ( type == SAA_MNSRF )
03747                                         fprintf( outStream, "NURBS\n" );
03748                                 else
03749                                         fprintf( outStream, "OTHER\n" );
03750                            }
03751 
03752                             int *envVtxIndices = NULL;
03753                             envVtxIndices = (int *)malloc(sizeof(int)*numEnvVertices[i]);
03754 
03755                             // Get the envelope vertex indices
03756                             SAA_ctrlVertexGetIndices( scene, &envelopes[i],                                     numEnvVertices[i], 
03757                                 &envVertices[vertArrayOffset], envVtxIndices );
03758 
03759                             // find out how many vertices the model has
03760                             int modelNumVert;
03761 
03762                             SAA_modelGetNbVertices( scene, &envelopes[i], &modelNumVert );
03763                              
03764                             SAA_DVector *modelVertices = NULL;
03765                             modelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert);
03766 
03767                             // get the model vertices
03768                             SAA_modelGetVertices( scene, &envelopes[i],
03769                                 SAA_GEOM_ORIGINAL, 0, modelNumVert, 
03770                                 modelVertices );
03771                             
03772                             // create array of global model coords 
03773                             SAA_DVector *globalModelVertices = NULL;
03774                             globalModelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert);
03775                             float        matrix[4][4];
03776 
03777                             // tranform local model vert coords to global
03778 
03779                             // first get the global matrix
03780                             SAA_modelGetMatrix( scene, &envelopes[i],                                                 SAA_COORDSYS_GLOBAL,  matrix );
03781 
03782                             // populate array of global model verts
03783                             for ( j = 0; j < modelNumVert; j++ )
03784                             {
03785                                 _VCT_X_MAT( globalModelVertices[j], 
03786                                     modelVertices[j], matrix );
03787                             }
03788 
03789                             // find the egg vertex pool that corresponds
03790                             // to this envelope model
03791                             EggVertexPool *envPool = 
03792                                 (EggVertexPool *)(_data.pools.FindName( envName ));
03793                             // If we are outputting triangles:
03794                             // create an array that maps from a referenced
03795                             // vertex in the envelope to a corresponding 
03796                             // vertex in the egg vertex pool
03797                             //if ( (type == SAA_MNSRF) && !make_nurbs ) 
03798                             if ( !make_nurbs || (type == SAA_MSMSH) ) 
03799                             {
03800                                 vpoolMap = FindClosestTriVert( envPool,
03801                                     globalModelVertices, modelNumVert );
03802                             }
03803 
03804 
03805                             if ( envPool != NULL )
03806                             {
03807     
03808                             // find the egg joint that corresponds to this model
03809                             EggJoint *joint = 
03810                                 (EggJoint *)(skeleton->FindDescendent( name ));
03811 
03812                                                                                                                 // this doesn't seem to be necessary 4/7/99
03813                             //EggJoint *parent = (EggJoint *)joint->parent;
03814                                                                                                                 //assert(parent->IsA(NT_EggJoint));
03815 
03816                             // for every envelope vertex 
03817                             for (j = 0; j < numEnvVertices[i]; j++)
03818                             {
03819                                 double scaledWeight =  weights[j]/ 100.0f;
03820 
03821                                 // make sure its in legal range
03822                                 if (( envVtxIndices[j] < modelNumVert )
03823                                     && ( envVtxIndices[j] >= 0 ))
03824                                 {
03825                                   if ( (type == SAA_MNSRF) && make_nurbs ) 
03826                                   { 
03827                                     // assign all referenced control vertices
03828                                     joint->AddVertex( envPool->Vertex(envVtxIndices[j]), scaledWeight );
03829 
03830                                     if ( verbose >= 2 )
03831                                         fprintf( outStream, 
03832                                             "%d: adding vref to cv %d with weight %f\n", 
03833                                             j, envVtxIndices[j], scaledWeight );
03834 
03835                                     envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight );
03836                                     // set flag to show this vertex has
03837                                     // been assigned
03838                                     envPool->Vertex(envVtxIndices[j])->multipleJoints = 1;
03839                                   }
03840                                   else
03841                                   {    
03842                                     //assign all the tri verts associated
03843                                     // with this control vertex to joint 
03844                                     for ( k = 0; k < envPool->NumVertices(); k++ )    
03845                                     {
03846                                       if ( vpoolMap[k] == envVtxIndices[j] ) 
03847                                       {
03848 
03849                                         // add each vert in pool to last 
03850                                         // joint for soft skinning
03851                                         joint->AddVertex(envPool->Vertex(k), 
03852                                             scaledWeight);
03853 
03854                                         if ( verbose >= 2 )
03855                                             fprintf( outStream, 
03856                                                 "%d: adding vref from cv %d to vert %d with weight %f(vpool)\n", 
03857                                                 j, envVtxIndices[j], k, scaledWeight );
03858 
03859                                         envPool->Vertex(k)->AddJoint( joint, scaledWeight );
03860                                         // set flag to show this vertex has
03861                                         // been assigned
03862                                         envPool->Vertex(k)->multipleJoints = 1;
03863                                       }
03864                                     }
03865                                  }
03866                                 }
03867                                 else
03868                                     if ( verbose >= 2 )
03869                                         fprintf( outStream, 
03870                                             "%d: Omitted vref from cv %d with weight %f (out of range 0 to %d )\n",
03871                                             j, envVtxIndices[j], scaledWeight, modelNumVert );
03872                                     
03873                             }
03874 
03875                             }
03876                             else 
03877                                 if ( verbose >= 2 )
03878                                     fprintf( outStream, "Couldn't find vpool %s!\n", envName );
03879 
03880                             //free( modelVertices ); 
03881                             //free( globalModelVertices ); 
03882                             //free( envVtxIndices );
03883                             //free( envName );
03884                             } //if (weights)
03885                             //free( weights );
03886 
03887                         } // for i
03888 
03889                     } // if (envVertices != NULL)
03890                     else
03891                         fprintf( outStream, "Not enough memory for envelope vertices...\n");
03892                     //free( envVertices );
03893                     } // if (totalEnvVertices) 
03894                     else
03895                         if ( verbose >= 1 )
03896                             fprintf( outStream, "No envelope vertices present...\n");
03897 
03898                     //free( numEnvVertices );
03899 
03900             } // if (numEnvVertices != NULL)
03901 
03902           } // if (hasEnvVertices)
03903 
03904         } // if (envelopes != NULL)
03905         else
03906             fprintf( outStream, "Not enough memory for envelopes...\n" );
03907 
03908         //free( envelopes );
03909 
03910     } //if (numEnv)
03911 
03912     else
03913         if ( verbose >= 1 )
03914             fprintf( outStream, "Skeleton member has no envelopes...\n" );
03915 }
03916 
03917 
03918 ////////////////////////////////////////////////////////////////////
03919 //     Function: CleanUpSoftSkin
03920 //       Access: Public 
03921 //  Description: Given a model, make sure all its vertices have been 
03922 //                 soft assigned. If not hard assign to the last
03923 //                 joint we saw.
03924 ////////////////////////////////////////////////////////////////////
03925 void soft2egg::
03926 CleanUpSoftSkin( SAA_Scene *scene, SAA_Elem *model, char *name )
03927 {
03928     static EggJoint *joint;
03929     SAA_Elem        parent;
03930     SAA_ModelType     type;
03931     SAA_Boolean        skel;
03932 
03933     /////////////////////////////////////////////////
03934     // find out what type of node we're dealing with
03935     /////////////////////////////////////////////////
03936     SAA_modelGetType( scene, model, &type );
03937 
03938     char   *parentName;
03939     int        level;
03940     SAA_Elem    *searchNode = model;
03941 
03942     if ( verbose >= 1 )
03943         fprintf( outStream, "\nCleaning up model %s\n", name );
03944 
03945     // this step is weird - I think I want it here but it seems
03946     // to break some models. Files like props-props_wh_cookietime.3-0 in
03947     // /ful/rnd/pub/vrml/chip/chips_adventure/char/zone1/rooms/warehouse_final
03948     // need to do the "if (skel)" bit.
03949 
03950     // am I a skeleton too?
03951     SAA_modelIsSkeleton( scene, model, &skel );
03952 
03953     // if not look for the last skeleton part
03954     if ( skel ) 
03955         parentName = name;
03956     else do 
03957     {
03958         SAA_elementGetHierarchyLevel( scene, searchNode, &level );
03959 
03960         // make sure we don't try to get the root's parent
03961         if ( level )
03962         {
03963             SAA_modelGetParent( scene, searchNode, &parent );
03964 
03965             if ( use_prefix )
03966             {
03967                 // Get the FULL name of the parent
03968                 parentName = GetFullName( scene, &parent );
03969             }
03970             else
03971             {
03972                 // Get the name of the parent
03973                 parentName = GetName( scene, &parent );
03974             }
03975 
03976             SAA_modelGetType( scene, &parent, &type );
03977 
03978             SAA_modelIsSkeleton( scene, &parent, &skel );
03979 
03980             if ( verbose >= 1 )
03981                 fprintf( outStream, "model %s, level %d, type %d, skel %d\n",
03982                     parentName, level, type, skel );
03983 
03984             searchNode = &parent;
03985         }
03986         else
03987         {
03988             // we reached the root of the tree
03989             parentName = NULL;
03990             if ( verbose >= 1 )
03991                 fprintf( outStream, "at root of tree! level %d\n", level );
03992             break;
03993         }
03994 
03995     // look until parent is a joint or acts like one
03996     } while ( !skel && ( strstr( parentName,"joint") == NULL ));
03997 
03998     EggJoint    *thisJoint = NULL;
03999 
04000     if ( parentName != NULL )
04001     {
04002         if ( verbose >= 1 )
04003         {
04004             fprintf( outStream, "found model parent joint %s\n", parentName);
04005             fprintf( outStream, "looking for joint %s\n", parentName );
04006         }
04007         thisJoint = (EggJoint *)(skeleton->FindDescendent( parentName ));
04008     }
04009     else
04010         if ( verbose >= 1 )
04011                 fprintf( outStream, "Couldn't find parent joint!\n");
04012 
04013     if ( thisJoint != NULL )
04014     {
04015         joint = thisJoint;
04016         if ( verbose >= 1 )
04017             fprintf( outStream, "setting joint to %s\n", parentName );
04018 
04019         //find the vpool for this model
04020         EggVertexPool *vPool = 
04021             (EggVertexPool *)(_data.pools.FindName( name ));
04022 
04023         if (vPool != NULL)
04024         {
04025             int i;
04026             double membership;
04027             int numVerts = vPool->NumVertices() ;
04028 
04029 
04030             if ( verbose >= 1 )
04031                 fprintf( outStream, "found vpool %s w/ %d verts\n", 
04032                 name, numVerts );
04033         
04034             for ( i = 0; i < numVerts; i++ )     
04035             {
04036                 if ( vPool->Vertex(i)->multipleJoints != 1 )
04037                 {
04038                     if ( verbose >= 1 )
04039                     {    
04040                         fprintf( outStream, "vpool %s vert %d", name, i );
04041                         fprintf( outStream, " not assigned!\n" );
04042                     }
04043 
04044                     // hard skin this vertex
04045                     joint->AddVertex( vPool->Vertex(i), 1.0f );
04046                 }
04047                 else
04048                 {    
04049                     membership = vPool->Vertex(i)->NetMembership();
04050 
04051 
04052                     if ( verbose >= 1 )
04053                     {
04054                         fprintf( outStream, "vpool %s vert %d", name, 
04055                             i );
04056                         fprintf( outStream, " has membership %f\n", 
04057                             membership );
04058                     }
04059 
04060                     if ( membership == 0 )
04061                     {
04062                         if ( verbose >= 1 )
04063                             fprintf( outStream, "adding full weight..\n" );
04064 
04065                         // hard skin this vertex
04066                         joint->AddVertex( vPool->Vertex(i), 1.0f );
04067                     }
04068                 }
04069             }
04070         }
04071         else
04072             if ( verbose >= 1 )
04073                 fprintf( outStream, "couldn't find vpool %s\n", name );
04074     }
04075     else
04076     {
04077         if ( parentName != NULL )
04078             if ( verbose >= 1 )
04079                 fprintf( outStream, "Couldn't find joint %s\n", parentName );
04080     }
04081 }
04082 
04083 //////////////////////////////////////////////////////////////////////
04084 //     Function: MakeAnimTable
04085 //       Access: Public 
04086 //  Description: Given a scene and a skeleton part ,get all the 
04087 //                   position, rotation, and scale for the skeleton
04088 //                 part for this frame and write them out as Egg
04089 //                 animation tables. 
04090 ////////////////////////////////////////////////////////////////////
04091 void soft2egg::
04092 MakeAnimTable( SAA_Scene *scene, SAA_Elem *skeletonPart, char *name )
04093 {    
04094 
04095     if ( skeletonPart != NULL )
04096     {
04097         float    i,j,k;
04098         float    h,p,r;
04099         float    x,y,z;
04100         int         size;
04101         SAA_Boolean globalFlag = FALSE;
04102         SAA_Boolean bigEndian;
04103 
04104         if ( verbose >= 1 )
04105             fprintf( outStream, "\n\nanimating child %s\n", name );
04106 
04107         SAA_elementGetUserDataSize( scene, skeletonPart, "GLOBAL", &size );
04108         
04109         if ( size != 0 )    
04110             SAA_elementGetUserData( scene, skeletonPart, "GLOBAL", 
04111                 sizeof( SAA_Boolean), &bigEndian, (void *)&globalFlag );
04112  
04113         if ( globalFlag )
04114         {
04115             if ( verbose >= 1 )
04116                 fprintf( outStream, " using global matrix\n" );
04117 
04118             //get SAA orientation
04119             SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, 
04120                 &p, &h, &r ); 
04121 
04122             //get SAA translation
04123             SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, 
04124                 &x, &y, &z ); 
04125 
04126             //get SAA scaling
04127             SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL, 
04128                 &i, &j, &k );
04129         }
04130         else
04131         {
04132             if ( verbose >= 1 )
04133                 fprintf( outStream, "using local matrix\n" );
04134 
04135             //get SAA orientation
04136             SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL, 
04137                 &p, &h, &r ); 
04138 
04139             //get SAA translation
04140             SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL, 
04141                 &x, &y, &z ); 
04142 
04143             //get SAA scaling
04144             SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL, 
04145                 &i, &j, &k );
04146         }
04147 
04148 
04149         if ( verbose >= 2 )
04150             fprintf( outStream, "\nanim data: %f %f %f\n\t%f %f %f\n\t%f %f %f\n",
04151                 i, j, k, h, p, r, x, y, z );  
04152 
04153         // find the appropriate anim table for this skeleton part
04154         AnimGroup     *thisGroup;
04155         XfmSAnimTable *thisTable;
04156 
04157         //find the anim table associated with this group
04158         thisGroup = (AnimGroup *)(animRoot->FindDescendent( name ));
04159         if ( verbose >= 2 )
04160             fprintf( outStream, "\nlooking for anim group %s\n", name );
04161         if ( thisGroup != NULL )
04162         {
04163             thisTable = (XfmSAnimTable *)(thisGroup->FindDescendent( "xform" ));
04164 
04165             if ( thisTable != NULL )
04166             {    
04167                 thisTable->sub_tables[0].AddElement( i );
04168                 thisTable->sub_tables[1].AddElement( j ); 
04169                 thisTable->sub_tables[2].AddElement( k ); 
04170                 thisTable->sub_tables[3].AddElement( p ); 
04171                 thisTable->sub_tables[4].AddElement( h ); 
04172                 thisTable->sub_tables[5].AddElement( r ); 
04173                 thisTable->sub_tables[6].AddElement( x ); 
04174                 thisTable->sub_tables[7].AddElement( y ); 
04175                 thisTable->sub_tables[8].AddElement( z ); 
04176             }
04177             else
04178                 fprintf( outStream, "Couldn't allocate anim table\n" );
04179         }
04180         else
04181             if ( verbose >= 2 )
04182                 fprintf( outStream, "Couldn't find anim group  %s\n",  name );
04183     }
04184     else
04185     {
04186         if ( verbose >= 2 )
04187             fprintf( outStream, "Cannot build anim table - no skeleton\n" );
04188     }
04189     
04190 }
04191 
04192 ////////////////////////////////////////////////////////////////////
04193 //     Function: MakeVertexOffsets
04194 //       Access: Public 
04195 //  Description: Given a scene, a model , the vertices of its original
04196 //                 shape and its name find the difference between the 
04197 //                 geometry of its key shapes and the models original 
04198 //                 geometry and add morph vertices to the egg data to 
04199 //                 reflect these changes.
04200 ////////////////////////////////////////////////////////////////////
04201 void soft2egg::
04202 MakeVertexOffsets( SAA_Scene *scene, SAA_Elem *model, SAA_ModelType type,
04203     int numShapes, int numOrigVert, SAA_DVector *originalVerts, float
04204     matrix[4][4], char *name )
04205 {
04206     int i, j;
04207     int offset;
04208     int    numCV;
04209     char *mTableName;
04210     SAA_DVector *shapeVerts = NULL;
04211     SAA_DVector *uniqueVerts = NULL;
04212 
04213     if ( (type == SAA_MNSRF) && make_nurbs ) 
04214         SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
04215 
04216     SAA_modelGetNbVertices( scene, model, &numCV );
04217 
04218     // get the shape verts
04219     uniqueVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
04220     SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
04221         numCV, uniqueVerts );
04222 
04223     if ( verbose >= 2 )
04224         fprintf( outStream, "%d CV's\n", numCV ); 
04225 
04226     if ( verbose >= 2 )
04227     {    
04228         for ( i = 0; i < numCV; i++ )
04229             fprintf( outStream, "uniqueVerts[%d] = %f %f %f %f\n", i, 
04230                 uniqueVerts[i].x, uniqueVerts[i].y, 
04231                 uniqueVerts[i].z,  uniqueVerts[i].w );
04232     }
04233 
04234     // iterate through for each key shape (except original)
04235     for ( i = 1; i < numShapes; i++ )
04236     {
04237         mTableName = MakeTableName( name, i );
04238 
04239         if ( verbose >= 1 )
04240         {
04241             fprintf( outStream, "\nMaking geometry offsets for %s...\n", 
04242                 mTableName );
04243 
04244             if ( (type == SAA_MNSRF) && make_nurbs ) 
04245                 fprintf( outStream, "calculating NURBS morphs...\n" );
04246             else 
04247                 fprintf( outStream, "calculating triangle morphs...\n" );
04248         }
04249 
04250         // get the shape verts
04251         shapeVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
04252         SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1,
04253             numCV, shapeVerts );
04254 
04255         if ( verbose >= 2 )
04256         { 
04257             for ( j=0; j < numCV; j++ )
04258             {
04259                 fprintf( outStream, "shapeVerts[%d] = %f %f %f\n", j, 
04260                     shapeVerts[j].x, shapeVerts[j].y, shapeVerts[j].z );
04261             }
04262         }
04263 
04264         // find the appropriate vertex pool
04265         EggVertexPool *vPool = 
04266             (EggVertexPool *)(_data.pools.FindName( name ));
04267 
04268         // for every original vertex, compare to the corresponding
04269         // key shape vertex and see if a vertex offset is needed 
04270         for ( j=0; j < numOrigVert; j++ )
04271         {
04272             double    dx, dy, dz;
04273         
04274             if ( (type == SAA_MNSRF) && make_nurbs )
04275             {
04276                 //dx = shapeVerts[j].x - (originalVerts[j].x/originalVerts[j].w); 
04277                 //dy = shapeVerts[j].y - (originalVerts[j].y/originalVerts[j].w); 
04278                 //dz = shapeVerts[j].z - (originalVerts[j].z/originalVerts[j].w); 
04279                 dx = shapeVerts[j].x - originalVerts[j].x; 
04280                 dy = shapeVerts[j].y - originalVerts[j].y; 
04281                 dz = shapeVerts[j].z - originalVerts[j].z; 
04282             }
04283             else 
04284             {
04285                 // we need to map from original vertices
04286                 // to triangle shape vertices here
04287                 offset = findShapeVert( originalVerts[j], uniqueVerts,
04288                     numCV ); 
04289 
04290                 dx = shapeVerts[offset].x - originalVerts[j].x; 
04291                 dy = shapeVerts[offset].y - originalVerts[j].y; 
04292                 dz = shapeVerts[offset].z - originalVerts[j].z; 
04293             }
04294 
04295             if ( verbose >= 2 )
04296             {
04297                 fprintf( outStream, "oVert[%d] = %f %f %f %f\n", j, 
04298                     originalVerts[j].x, originalVerts[j].y, 
04299                     originalVerts[j].z,  originalVerts[j].w );
04300 
04301                 if ( (type == SAA_MNSRF) && make_nurbs )
04302                 {
04303                     fprintf( outStream, "global shapeVerts[%d] = %f %f %f %f\n",                        j, shapeVerts[j].x, shapeVerts[j].y, 
04304                         shapeVerts[j].z, shapeVerts[j].w );
04305                 }
04306                 else
04307                 {
04308                     fprintf( outStream, 
04309                         "global shapeVerts[%d] = %f %f %f\n", offset, 
04310                         shapeVerts[offset].x, 
04311                         shapeVerts[offset].y, 
04312                         shapeVerts[offset].z );
04313                 }
04314 
04315                 fprintf( outStream, "%d: dx = %f, dy = %f, dz = %f\n", j,
04316                     dx, dy, dz );
04317             }
04318 
04319             // if change isn't negligible, make a morph vertex entry 
04320             double total = fabs(dx)+fabs(dy)+fabs(dz);
04321             if ( total > 0.00001 )
04322             {
04323                 if ( vPool != NULL )
04324                 {
04325                     // create offset
04326                     EggMorphOffset *dxyz = 
04327                         new EggMorphOffset( mTableName, dx, dy, dz );
04328 
04329                     EggVertex *eggVert;
04330 
04331                     // get the appropriate egg vertex
04332                     eggVert = vPool->Vertex(j);    
04333 
04334                     // add the offset to the vertex
04335                     eggVert->morphs.push_back( *dxyz );
04336                 }
04337                 else
04338                     fprintf( outStream, "Error: couldn't find vertex pool %s\n", name ); 
04339                 
04340             } // if total
04341         } //for j
04342     } //for i
04343 }
04344 
04345 
04346 ////////////////////////////////////////////////////////////////////
04347 //     Function: MakeMorphTable
04348 //       Access: Public 
04349 //  Description: Given a scene, a model, a name and a frame time,
04350 //                 determine what type of shape interpolation is
04351 //                 used and call the appropriate function to extract
04352 //                 the shape weight info for this frame...
04353 ////////////////////////////////////////////////////////////////////
04354 void soft2egg::
04355 MakeMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
04356     int numModels, char *name, float time )
04357 {
04358     int         numShapes;
04359     SAA_AnimInterpType    type;
04360 
04361     // Get the number of key shapes
04362     SAA_modelGetNbShapes( scene, model, &numShapes );
04363 
04364     if ( numShapes > 0 )
04365     {
04366         if ( verbose >= 1 )
04367             fprintf( outStream, "MakeMorphTable: %s: num shapes: %d\n", 
04368                 name, numShapes);
04369 
04370         SAA_modelGetShapeInterpolation( scene, model, &type );
04371 
04372         if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL )
04373         {
04374             MakeLinearMorphTable( scene, model, numShapes, name, time );
04375         }
04376         else     // must be weighted...
04377         {
04378             // check first for expressions
04379             MakeExpressionMorphTable( scene, model, models, numModels,
04380                 numShapes, name, time );
04381         }
04382 
04383     }
04384     
04385 }
04386 
04387 
04388 ////////////////////////////////////////////////////////////////////
04389 //     Function: MakeLinearMorphTable
04390 //       Access: Public 
04391 //  Description: Given a scene, a model, its name, and the time,
04392 //                 get the shape fcurve for the model and determine
04393 //                 the shape weights for the given time and use them
04394 //                 to populate the morph table.
04395 ////////////////////////////////////////////////////////////////////
04396 void soft2egg::
04397 MakeLinearMorphTable( SAA_Scene *scene, SAA_Elem *model, int numShapes,
04398     char *name, float time )
04399 {    
04400     int            i;
04401     SAA_Elem     fcurve;
04402     float        curveVal;
04403     SAnimTable *thisTable;
04404     char          *tableName;
04405 
04406     if ( verbose >= 1 )
04407         fprintf( outStream, "linear interp, getting fcurve\n" );
04408 
04409     SAA_modelFcurveGetShape( scene, model, &fcurve );
04410 
04411     SAA_fcurveEval( scene, &fcurve, time, &curveVal );    
04412     
04413     if ( verbose >= 2 )
04414         fprintf( outStream, "at time %f, fcurve for %s = %f\n", time,
04415             name, curveVal );
04416 
04417     float nextVal = 0.0f;
04418 
04419     // populate morph table values for this frame
04420     for ( i = 1; i < numShapes; i++ )
04421     {
04422         // derive table name from the model name
04423         tableName = MakeTableName( name, i );
04424 
04425         if ( verbose >= 2 )
04426             fprintf( outStream, "Linear: looking for table '%s'\n", tableName );
04427 
04428         //find the morph table associated with this key shape
04429         thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName ));
04430 
04431         if ( thisTable != NULL )
04432         {    
04433             if ( i == (int)curveVal )
04434             {
04435                 if ( curveVal - i == 0 )
04436                 {
04437                     thisTable->AddElement( 1.0f ); 
04438                     if ( verbose >= 2 )
04439                         fprintf( outStream, "adding element 1.0f\n" );
04440                 }
04441                 else
04442                 {
04443                     thisTable->AddElement( 1.0f - (curveVal - i) );
04444                     nextVal = curveVal - i;
04445                     if ( verbose >= 2 )
04446                         fprintf( outStream, "adding element %f\n",                                                 1.0f - (curveVal - i) );
04447                 }
04448             }
04449             else
04450             {
04451                 if ( nextVal )
04452                 {
04453                     thisTable->AddElement( nextVal );
04454                     nextVal = 0.0f;
04455                     if ( verbose >= 2 )
04456                         fprintf( outStream, "adding element %f\n", nextVal );
04457                 }
04458                 else
04459                 {
04460                     thisTable->AddElement( 0.0f );
04461                     if ( verbose >= 2 )
04462                         fprintf( outStream, "adding element 0.0f\n" );
04463                 }
04464             }
04465 
04466             if ( verbose >= 2 )
04467                 fprintf( outStream, " to '%s'\n", tableName );
04468         }
04469         else
04470             fprintf( outStream, "%d: Couldn't find table '%s'\n", 
04471                 i, tableName );
04472     }    
04473 
04474 }
04475 
04476 ////////////////////////////////////////////////////////////////////
04477 //     Function: MakeWeightedMorphTable
04478 //       Access: Public 
04479 //  Description: Given a scene, a model, a list of all models in the
04480 //                 scene, the number of models in the scece, the number 
04481 //                 of key shapes for this model, the name of the model
04482 //                 and the current time, determine what method of
04483 //                 controlling the shape weights is used and call the
04484 //                 appropriate routine.
04485 ////////////////////////////////////////////////////////////////////
04486 void soft2egg::
04487 MakeWeightedMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, 
04488     int numModels,  int numShapes, char *name, float time )
04489 {
04490     SI_Error     result;
04491     SAA_Elem    *weightCurves;
04492     float         curveVal;
04493     SAnimTable *thisTable;
04494     char          *tableName;
04495 
04496     // allocate array of weight curves (one for each shape)
04497     weightCurves = ( SAA_Elem *)malloc( sizeof( SAA_Elem ) * numShapes ); 
04498 
04499     result = SAA_modelFcurveGetShapeWeights(
04500         scene, model, numShapes, weightCurves );
04501 
04502     if ( result == SI_SUCCESS )
04503     {
04504         for ( int i = 1; i < numShapes; i++ )
04505         {
04506                                                 SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal );    
04507 
04508                                                 // make sure soft gave us a reasonable number
04509                                                 if (!isNum(curveVal))
04510                                                         curveVal = 0.0f;
04511 
04512                                                 if ( verbose >= 2 )
04513                                                                 fprintf( outStream, "at time %f, weightCurve[%d] for %s = %f\n",                     time, i, name, curveVal );
04514 
04515 
04516             // derive table name from the model name
04517             tableName = MakeTableName( name, i );
04518 
04519                                                 // find and populate shape table
04520             if ( verbose >= 2 )
04521                 fprintf( outStream, "Weight: looking for table '%s'\n", 
04522                                                                 tableName );
04523 
04524             //find the morph table associated with this key shape
04525             thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName ));
04526 
04527             if ( thisTable != NULL )
04528             {    
04529                 thisTable->AddElement( curveVal ); 
04530                 if ( verbose >= 2 )
04531                     fprintf( outStream, "adding element %f\n", curveVal );
04532             }
04533             else
04534                 fprintf( outStream, "%d: Couldn't find table '%s'\n", 
04535                     i, tableName );
04536         }
04537     }
04538 }
04539 
04540 
04541 ////////////////////////////////////////////////////////////////////
04542 //     Function: MakeExpressionMorphTable
04543 //       Access: Public 
04544 //  Description: Given a scene, a model and its number of key shapes
04545 //                 generate a morph table describing transitions btwn
04546 //                 the key shapes by evaluating the positions of the
04547 //                 controlling sliders. 
04548 ////////////////////////////////////////////////////////////////////
04549 void soft2egg::
04550 MakeExpressionMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, 
04551     int numModels,  int numShapes, char *name, float time )
04552 {    
04553     int            j;
04554     SAnimTable *thisTable;
04555     char          *tableName;
04556     char          *sliderName;
04557     char        *track;
04558     int            numExp;
04559     SAA_Elem   *expressions;
04560     float        expVal;
04561     float        sliderVal;
04562 
04563     // populate morph table values for this frame
04564 
04565     // compose track name
04566     track = NULL;
04567 
04568     // find how many expressions for this shape
04569     SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp );
04570 
04571     if ( verbose >= 2 )
04572         fprintf( outStream, "%s has %d RHS expressions\n", name, numExp );
04573 
04574     if ( numExp )
04575     {
04576         // get the expressions for this shape
04577         expressions = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numExp);    
04578 
04579         if ( verbose >= 1 )
04580             fprintf( outStream, "getting %d RHS expressions...\n", numExp );
04581 
04582         result = SAA_elementGetExpressions( scene, model, track, FALSE, 
04583             numExp, expressions );
04584 
04585         if ( !result )
04586         {
04587             for ( j = 1; j < numExp; j++ )
04588             {
04589                 if ( verbose >= 2 )
04590                 {
04591                 // debug see what we got
04592                 int numvars;
04593         
04594                 SAA_expressionGetNbVars( scene, &expressions[j], &numvars );
04595 
04596                 int *varnamelen;
04597                 int *varstrlen;
04598                 int  expstrlen;
04599 
04600                 varnamelen = (int *)malloc(sizeof(int)*numvars);
04601                 varstrlen = (int *)malloc(sizeof(int)*numvars);
04602 
04603                 SAA_expressionGetStringLengths( scene, &expressions[j],
04604                     numvars, varnamelen, varstrlen, &expstrlen );    
04605 
04606                 int *varnamesizes;    
04607                 int *varstrsizes;
04608 
04609                 varnamesizes = (int *)malloc(sizeof(int)*numvars);
04610                 varstrsizes = (int *)malloc(sizeof(int)*numvars);
04611 
04612                 for ( int k = 0; k < numvars; k++ )
04613                 {
04614                     varnamesizes[k] = varnamelen[k] + 1;
04615                     varstrsizes[k] = varstrlen[k] + 1;
04616                 }
04617     
04618                 int expstrsize = expstrlen + 1;
04619 
04620                 char **varnames;
04621                 char **varstrs;
04622 
04623                 varnames = (char **)malloc(sizeof(char *)*numvars);
04624                 varstrs = (char **)malloc(sizeof(char *)*numvars);
04625 
04626                 for ( k = 0; k < numvars; k++ )
04627                 {
04628                     varnames[k] = (char *)malloc(sizeof(char)*
04629                         varnamesizes[k]);
04630 
04631                     varstrs[k] = (char *)malloc(sizeof(char)*
04632                         varstrsizes[k]);
04633                 }
04634         
04635                 char *expstr = (char *)malloc(sizeof(char)* expstrsize );    
04636 
04637                 SAA_expressionGetStrings( scene, &expressions[j], numvars,
04638                     varnamesizes, varstrsizes, expstrsize, varnames,
04639                     varstrs, expstr );
04640                 
04641                 if ( verbose >= 2 )
04642                 {
04643                     fprintf( outStream, "expression = '%s'\n", expstr );
04644                     fprintf( outStream, "has %d variables\n", numvars );
04645                 }
04646                 } //if verbose
04647                 
04648                 if ( verbose >= 2 )
04649                     fprintf( outStream, "evaling expression...\n" );
04650 
04651                 SAA_expressionEval( scene, &expressions[j], time, &expVal ); 
04652 
04653                 if ( verbose >= 2 )
04654                     fprintf( outStream, "time %f: exp val %f\n", 
04655                         time, expVal );
04656 
04657                 // derive table name from the model name
04658                 tableName = MakeTableName( name, j );
04659 
04660                 if ( verbose >= 2 )
04661                     fprintf( outStream, "Exp: looking for table '%s'\n", 
04662                         tableName );
04663 
04664                 //find the morph table associated with this key shape
04665                 thisTable = (SAnimTable *)
04666                     (morphRoot->FindDescendent( tableName ));
04667 
04668                 if ( thisTable != NULL )
04669                 {    
04670                     thisTable->AddElement( expVal ); 
04671                     if ( verbose >= 1 )    
04672                         fprintf( outStream, "%d: adding element %f to %s\n",
04673                             j, expVal, tableName );
04674                     fflush( outStream );
04675                 }
04676                 else
04677                 {
04678                     fprintf( outStream, "%d: Couldn't find table '%s'", j, 
04679                             tableName ); 
04680 
04681                     fprintf( outStream, " for value %f\n", expVal );
04682                 }
04683             }
04684         }
04685         else
04686             fprintf( outStream, "couldn't get expressions!!!\n" );
04687     }
04688     else 
04689         // no expression, use weight curves
04690         MakeWeightedMorphTable( scene, model, models, numModels, 
04691             numShapes, name, time );
04692 
04693 }
04694 
04695 
04696 ////////////////////////////////////////////////////////////////////
04697 //     Function: MakeTexAnim
04698 //       Access: Public 
04699 //  Description: Given a scene, a POLYGON model, and the name
04700 //                 of the that model, get the u and v offsets for
04701 //                 the current frame. 
04702 ////////////////////////////////////////////////////////////////////
04703 void soft2egg::
04704 MakeTexAnim( SAA_Scene *scene, SAA_Elem *model, char *modelName )
04705 {
04706     if ( verbose >= 1 )
04707         fprintf( outStream, "\n\nmaking texture animation for %s...\n", 
04708             modelName );
04709 
04710     // get the color of the surface
04711     int         numMats;
04712     pfVec4        Color;
04713     SAA_Elem    *materials;
04714     void        *relinfo;
04715 
04716     SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo,
04717         &numMats ); 
04718 
04719     if ( verbose >= 2 )    
04720         fprintf( outStream, "surface has %d materials\n", numMats );
04721 
04722     if ( numMats )
04723     {
04724         float r,g,b,a;
04725 
04726         materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numMats);
04727         
04728         SAA_modelRelationGetMatElements( scene, model, relinfo, 
04729             numMats, materials ); 
04730 
04731         SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b );
04732         SAA_materialGetTransparency( scene, &materials[0], &a );
04733         Color.set( r, g, b, 1.0f - a );
04734 
04735         int numTexLoc = 0;
04736         int numTexGlb = 0;
04737 
04738         // ASSUME only one texture per material
04739         SAA_Elem tex;
04740 
04741         // find out how many local textures per surface
04742         // ASSUME it only has one material
04743         SAA_materialRelationGetT2DLocNbElements( scene, &materials[0],
04744             FALSE, &relinfo, &numTexLoc );
04745 
04746         // if present, get local textures
04747         if ( numTexLoc )
04748         {
04749             if ( verbose >= 1 )
04750                 fprintf( outStream, "%s had %d local tex\n", modelName, 
04751                     numTexLoc );
04752 
04753             // get the referenced texture
04754             SAA_materialRelationGetT2DLocElements( scene, &materials[0],
04755                 TEX_PER_MAT, &tex ); 
04756 
04757         }
04758         // if no locals, try to get globals
04759         else
04760         {
04761             SAA_modelRelationGetT2DGlbNbElements( scene, model,
04762                 FALSE, &relinfo, &numTexGlb );
04763 
04764             if ( numTexGlb )
04765             {
04766                 if ( verbose >= 1 )
04767                     fprintf( outStream, "%s had %d global tex\n", modelName, numTexGlb );
04768 
04769                 // get the referenced texture
04770                 SAA_modelRelationGetT2DGlbElements( scene, 
04771                     model, TEX_PER_MAT, &tex ); 
04772             }
04773         }
04774 
04775         // add tex ref's if we found any textures
04776         if ( numTexLoc || numTexGlb) 
04777         {
04778             char    *fullTexName = NULL;
04779             char    *texName = NULL;
04780             char    *uniqueTexName = NULL;
04781             int      texNameLen;
04782 
04783             // get its name 
04784             SAA_texture2DGetPicNameLength( scene, &tex, &texNameLen);
04785             fullTexName = (char *)malloc(sizeof(char)*++texNameLen);
04786             SAA_texture2DGetPicName( scene, &tex, texNameLen, 
04787                 fullTexName );
04788 
04789             // append unique identifier to texname for
04790             // this particular object
04791             uniqueTexName = (char *)malloc(sizeof(char)*
04792                 (strlen(modelName)+strlen(texName)+3) );
04793             sprintf( uniqueTexName, "%s-%s", modelName, texName );
04794             if ( verbose >= 2 )
04795                 fprintf( outStream, "referencing tref %s\n", 
04796                     uniqueTexName );
04797 
04798             float uScale;
04799             float vScale;
04800             float uOffset;
04801             float vOffset;
04802             SAA_Boolean    uv_swap = FALSE;
04803 
04804             // get texture offset info
04805             SAA_texture2DGetUScale( scene, &tex, &uScale );
04806             SAA_texture2DGetVScale( scene, &tex, &vScale );
04807             SAA_texture2DGetUOffset( scene, &tex, &uOffset );
04808             SAA_texture2DGetVOffset( scene, &tex, &vOffset );
04809             SAA_texture2DGetUVSwap( scene, &tex, &uv_swap );
04810 
04811 
04812             if ( verbose >= 2 )
04813             {
04814                 fprintf( outStream, "tex uScale: %f\n", uScale );
04815                 fprintf( outStream, "tex vScale: %f\n", vScale );
04816                 fprintf( outStream, "tex uOffset: %f\n", uOffset );
04817                 fprintf( outStream, "tex vOffset: %f\n", vOffset );
04818                 if ( uv_swap )
04819                     fprintf( outStream, "nurbTex u & v swapped!\n" );
04820                 else
04821                     fprintf( outStream, "nurbTex u & v NOT swapped\n" );
04822             }
04823 
04824 
04825             // find the vpool for this model
04826             EggVertexPool *vPool = 
04827                 (EggVertexPool *)(_data.pools.FindName( modelName ));
04828 
04829             // if we found the pool
04830             if ( vPool != NULL )
04831             {
04832                 // generate duv's for model
04833                 float oldOffsets[4];
04834                 double u, v, du, dv;    
04835                 int        size;
04836                 SAA_Boolean bigEndian;
04837 
04838                 SAA_elementGetUserDataSize( scene, model, "TEX_OFFSETS",                                 &size );
04839 
04840                 if ( size != 0 )    
04841                 {
04842                     // remember original texture offsets future reference
04843                     SAA_elementGetUserData( scene, model, "TEX_OFFSETS", 
04844                         size, &bigEndian, (void *)&oldOffsets );
04845 
04846                     // get the original scales and offsets
04847                     u = oldOffsets[0];
04848                     v = oldOffsets[1];
04849 
04850                     du = u - uOffset;
04851                     dv = v - vOffset;
04852 
04853                     if ( verbose >= 1 )
04854                     {
04855                         fprintf( outStream, "original u = %f, v = %f\n",
04856                             u, v );
04857                         fprintf( outStream, "u = %f, v = %f\n",
04858                             uOffset, vOffset );
04859                         fprintf( outStream, "du = %f, dv = %f\n",
04860                             du, dv );
04861                     }
04862 
04863                     strstream uName, vName;
04864 
04865                     // create duv target names
04866                     uName << modelName << ".u" << ends;
04867                     vName << modelName << ".v" << ends;
04868 
04869                     // find the appropriate table to store the
04870                     // duv animation info into
04871                     SAnimTable *thisTable;
04872 
04873                     //find the duv U table associated with this model
04874                     thisTable = (SAnimTable *)(morphRoot->FindDescendent( 
04875                         uName.str() ));
04876 
04877                     if ( thisTable != NULL )
04878                     {    
04879                         thisTable->AddElement( du ); 
04880                         if ( verbose >= 1 )
04881                             fprintf( outStream, "adding element %f to %s\n", 
04882                                 du, uName.str() );
04883                     }
04884                     else
04885                         fprintf( outStream, "Couldn't find uTable %s\n", 
04886                             uName.str() );
04887 
04888                     //find the duv V table associated with this model
04889                     thisTable = (SAnimTable *)(morphRoot->FindDescendent( 
04890                         vName.str() ));
04891 
04892                     if ( thisTable != NULL )
04893                     {    
04894                         thisTable->AddElement( dv ); 
04895                         if ( verbose >= 1 )
04896                             fprintf( outStream, "adding element %f to %s\n", 
04897                                 dv, uName.str() );
04898                     }
04899                     else
04900                         fprintf( outStream, "Couldn't find vTable %s\n", 
04901                             uName.str() );
04902                 }
04903             }
04904             else
04905                 if ( verbose >= 2 )
04906                     fprintf( outStream, "Couldn't find vpool %s\n", modelName );
04907             
04908         }
04909 
04910         //free( materials );
04911 
04912     }
04913 
04914 }
04915 #endif
04916 
04917 ////////////////////////////////////////////////////////////////////
04918 //     Function: Main
04919 //       Access: Private 
04920 //  Description: Instantiate converter and process a file
04921 ////////////////////////////////////////////////////////////////////
04922 EXPCL_MISC SI_Error soft2egg(int argc, char *argv[]) {
04923   // pass control to the c++ system
04924   init_soft2egg(argc, argv);
04925   return SI_SUCCESS;
04926 }
04927 #ifdef __cplusplus
04928 }
04929 #endif
 All Classes Functions Variables Enumerations