Panda3D
 All Classes Functions Variables Enumerations
soft2Egg.c
1 // Filename: soft2Egg.c
2 // Created by: masad (26Sep03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 ////////////////////////////////////////////////////////////////////
16 // Includes
17 ////////////////////////////////////////////////////////////////////
18 
19 #include <SAA.h>
20 
21 #ifdef __cplusplus
22 extern "C" {
23 #endif
24 
25 #include "pandatoolbase.h"
26 
27 int init_soft2egg(int, char **);
28 
29 #if 0
30 // DWD includes
31 #include "eggBase.h"
32 #include <eggParametrics.h>
33 #include <animTable.h>
34 #include <linMathOutput.h>
35 
36 // system includes
37 #include <fstream.h>
38 #include <strstream.h>
39 #include <math.h>
40 #include <assert.h>
41 #include <unistd.h>
42 #include <ieeefp.h>
43 
44 // Performer includes
45 #include <Performer/pr/pfLinMath.h>
46 
47 // SoftImage includes
48 #include <SAA.h>
49 #include <SI_macros.h>
50 
51 static const int TEX_PER_MAT = 1;
52 static FILE *outStream = stdout;
53 //static FILE *outStream = stderr;
54 
55 class soft2egg : public EggBase
56 {
57  public:
58 
59  soft2egg() : EggBase("r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD")
60  {
61  rsrc_path = "/ful/ufs/soft371_mips2/3D/rsrc";
62  database_name = NULL;
63  scene_name = NULL;
64  model_name = NULL;
65  animFileName = NULL;
66  eggFileName = NULL;
67  tex_path = NULL;
68  eggGroupName = NULL;
69  tex_filename = NULL;
70  search_prefix = NULL;
71  result = SI_SUCCESS;
72 
73  skeleton = new EggGroup();
74  foundRoot = FALSE;
75  animRoot = NULL;
76  morphRoot = NULL;
77  geom_as_joint = 0;
78  make_anim = 0;
79  make_nurbs = 0;
80  make_poly = 0;
81  make_soft = 0;
82  make_morph = 1;
83  make_duv = 1;
84  make_dart = TRUE;
85  has_morph = 0;
86  make_pose = 0;
87  animData.is_z_up = FALSE;
88  nurbs_step = 1;
89  anim_start = -1000;
90  anim_end = -1000;
91  anim_rate = 24;
92  pose_frame = -1;
93  verbose = 0;
94  flatten = 0;
95  shift_textures = 0;
96  ignore_tex_offsets = 0;
97  use_prefix = 0;
98  }
99 
100  virtual void Help();
101  virtual void Usage();
102  virtual void ShowOpts();
103 
104  virtual boolean UseOutputSwitch() const {
105  return false;
106  }
107 
108  virtual boolean
109  HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv);
110 
111  int isNum( float );
112  char *GetRootName( const char * );
113  char *RemovePathName( const char * );
114  char *GetSliderName( const char * );
115  char *GetFullName( SAA_Scene *, SAA_Elem * );
116  char *GetName( SAA_Scene *, SAA_Elem * );
117  char *GetModelNoteInfo( SAA_Scene *, SAA_Elem * );
118  char *MakeTableName( const char *, int );
119  char *DepointellizeName( char * );
120  SAA_Elem *FindModelByName( char *, SAA_Scene *, SAA_Elem *, int );
121  char *ConvertTexture( SAA_Scene *, SAA_Elem * );
122  int *FindClosestTriVert( EggVertexPool *, SAA_DVector *, int );
123  int *MakeIndexMap( int *, int, int );
124  int findShapeVert( SAA_DVector, SAA_DVector *, int );
125  void LoadSoft();
126  void MakeEgg( EggGroup *, EggJoint *, AnimGroup *, SAA_Scene *, SAA_Elem * );
127  void MakeSurfaceCurve( SAA_Scene *, SAA_Elem *, EggGroup *,
128  EggNurbsSurface *&, int , SAA_SubElem *, bool );
129 
130  EggNurbsCurve *MakeUVNurbsCurve( int, long *, double *, double *,
131  EggGroup *, char * );
132 
133  EggNurbsCurve *MakeNurbsCurve( SAA_Scene *, SAA_Elem *, EggGroup *,
134  float [4][4], char * );
135 
136  void AddKnots( perf_vector<double> &, double *, int, SAA_Boolean, int );
137  void MakeJoint( SAA_Scene *, EggJoint *&, AnimGroup *&, SAA_Elem *, char * );
138  void MakeSoftSkin( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char * );
139  void CleanUpSoftSkin( SAA_Scene *, SAA_Elem *, char * );
140  void MakeAnimTable( SAA_Scene *, SAA_Elem *, char * );
141  void MakeVertexOffsets( SAA_Scene *, SAA_Elem *, SAA_ModelType type,
142  int, int, SAA_DVector *, float (*)[4], char * );
143  void MakeMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char *,
144  float );
145  void MakeLinearMorphTable( SAA_Scene *, SAA_Elem *, int, char *, float );
146  void MakeWeightedMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,
147  int, char *, float );
148  void MakeExpressionMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int,
149  int, char *, float );
150  void MakeTexAnim( SAA_Scene *, SAA_Elem *, char * );
151 
152  private:
153 
154  char *rsrc_path;
155  char *database_name;
156  char *scene_name;
157  char *model_name;
158  char *eggFileName;
159  char *animFileName;
160  char *eggGroupName;
161  char *tex_path;
162  char *tex_filename;
163  char *search_prefix;
164 
165  SI_Error result;
166  SAA_Scene scene;
167  SAA_Elem model;
168  SAA_Database database;
169  EggGroup *dart;
170  EggGroup *skeleton;
171  AnimGroup *rootAnim;
172  EggJoint *rootJnt;
173  AnimGroup *animRoot;
174  AnimGroup *morphRoot;
175  EggData animData;
176 
177  int nurbs_step;
178  int anim_start;
179  int anim_end;
180  int anim_rate;
181  int pose_frame;
182  int verbose;
183  int flatten;
184  int shift_textures;
185  int ignore_tex_offsets;
186  int use_prefix;
187 
188  bool foundRoot;
189  bool geom_as_joint;
190  bool make_anim;
191  bool make_nurbs;
192  bool make_poly;
193  bool make_soft;
194  bool make_morph;
195  bool make_duv;
196  bool make_dart;
197  bool has_morph;
198  bool make_pose;
199 
200  ofstream eggFile;
201  ofstream animFile;
202  ofstream texFile;
203 
204 };
205 
206 
207 ////////////////////////////////////////////////////////////////////
208 // Function: Help
209 // Access: Public, Virtual
210 // Description: Displays the "what is this program" message, along
211 // with the usage message. Should be overridden in base
212 // classes to describe the current program.
213 ////////////////////////////////////////////////////////////////////
214 void soft2egg::
215 Help()
216 {
217  cerr <<
218  "soft2egg takes a SoftImage scene or model\n"
219  "and outputs its contents as an egg file\n";
220 
221  Usage();
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: Usage
226 // Access: Public, Virtual
227 // Description: Displays the usage message.
228 ////////////////////////////////////////////////////////////////////
229 void soft2egg::
230 Usage() {
231  cerr << "\nUsage:\n"
232  << _commandName << " [opts] (must specify -m or -s)\n\n"
233  << "Options:\n";
234 
235  ShowOpts();
236  cerr << "\n";
237 }
238 
239 
240 
241 ////////////////////////////////////////////////////////////////////
242 // Function: ShowOpts
243 // Access: Public, Virtual
244 // Description: Displays the valid options. Should be extended in
245 // base classes to show additional options relevant to
246 // the current program.
247 ////////////////////////////////////////////////////////////////////
248 void soft2egg::
249 ShowOpts()
250 {
251  cerr <<
252  " -r <path> - Used to provide soft with the resource\n"
253  " Defaults to 'c:/Softimage/SOFT_3.9.2/3D/test'.\n"
254  // " Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n"
255  " -d <path> - Database path.\n"
256  " -s <scene> - Indicates that a scene will be converted.\n"
257  " -m <model> - Indicates that a model will be converted.\n"
258  " -t <path> - Specify path to place converted textures.\n"
259  " -T <name> - Specify filename for texture map listing.\n"
260  " -S <step> - Specify step for nurbs surface triangulation.\n"
261  " -M <name> - Specify model output filename. Defaults to scene name.\n"
262  " -A <name> - Specify anim output filename. Defaults to scene name.\n"
263  " -N <name> - Specify egg group name.\n"
264  " -k - Enable soft assignment for geometry.\n"
265  " -n - Specify egg NURBS representation instead of poly's.\n"
266  " -p - Specify egg polygon output for geometry.\n"
267  " -P <frame> - Specify frame number for static pose.\n"
268  " -b <frame> - Specify starting frame for animation (default = first).\n"
269  " -e <frame> - Specify ending frame for animation (default = last).\n"
270  " -f <fps> - Specify frame rate for animation playback.\n"
271  " -a - Compile animation tables if animation present.\n"
272  " -F - Ignore hierarchy and build a completely flat skeleton.\n"
273  " -v <level> - Set debug level.\n"
274  " -x - Shift NURBS parameters to preserve Alias textures.\n"
275  " -i - Ignore Soft texture uv offsets.\n"
276  " -u - Use Soft prefix in model names.\n"
277  " -c - Cancel morph conversion.\n"
278  " -C - Cancel duv conversion.\n"
279  " -D - Don't make the output model a character.\n"
280  " -o <prefix>- Convert only models with given prefix.\n";
281 
282  EggBase::ShowOpts();
283 }
284 
285 
286 ////////////////////////////////////////////////////////////////////
287 // Function: HandleGetopts
288 // Access: Public, Virtual
289 // Description:
290 ////////////////////////////////////////////////////////////////////
291 boolean soft2egg::
292 HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv)
293 {
294  boolean okflag = true;
295 
296  switch (flag)
297  {
298  case 'r': // Set the resource path for soft.
299  if ( strcmp( optarg, "" ) )
300  {
301  // Get the path.
302  rsrc_path = optarg;
303  fprintf( outStream, "using rsrc path %s\n", rsrc_path );
304  }
305  break;
306 
307  case 'd': // Set the database path.
308  if ( strcmp( optarg, "" ) )
309  {
310  // Get the path.
311  database_name = optarg;
312  fprintf( outStream, "using database %s\n", database_name );
313  }
314  break;
315 
316  case 's': // Check if its a scene.
317  if ( strcmp( optarg, "" ) )
318  {
319  // Get scene name.
320  scene_name = optarg;
321  fprintf( outStream, "loading scene %s\n", scene_name );
322  }
323  break;
324 
325  case 'm': // Check if its a model.
326  if ( strcmp( optarg, "" ) )
327  {
328  // Get model name.
329  model_name = optarg;
330  fprintf( outStream, "loading model %s\n", model_name );
331  }
332  break;
333 
334  case 't': // Get converted texture path.
335  if ( strcmp( optarg, "" ) )
336  {
337  // Get tex path name.
338  tex_path = optarg;
339  fprintf( outStream, "texture path: %s\n", tex_path );
340  }
341  break;
342 
343  case 'T': // Specify texture list filename.
344  if ( strcmp( optarg, "") )
345  {
346  // Get the name.
347  tex_filename = optarg;
348  fprintf( outStream, "creating texture list file: %s\n",
349  tex_filename );
350  }
351  break;
352  case 'S': // Set NURBS step.
353  if ( strcmp( optarg, "" ) )
354  {
355  nurbs_step = atoi(optarg);
356  fprintf( outStream, "NURBS step: %d\n", nurbs_step );
357  }
358  break;
359 
360  case 'M': // Set model output file name.
361  if ( strcmp( optarg, "" ) )
362  {
363  eggFileName = optarg;
364  fprintf( outStream, "Model output filename: %s\n", eggFileName );
365  }
366  break;
367 
368  case 'A': // Set anim output file name.
369  if ( strcmp( optarg, "" ) )
370  {
371  animFileName = optarg;
372  fprintf( outStream, "Anim output filename: %s\n", animFileName );
373  }
374  break;
375 
376  case 'N': // Set egg model name.
377  if ( strcmp( optarg, "" ) )
378  {
379  eggGroupName = optarg;
380  fprintf( outStream, "Egg group name: %s\n", eggGroupName );
381  }
382  break;
383 
384  case 'o': // Set search_prefix.
385  if ( strcmp( optarg, "" ) )
386  {
387  search_prefix = optarg;
388  fprintf( outStream, "Only converting models with prefix: %s\n",
389  search_prefix );
390  }
391  break;
392 
393  case 'h': // print help message
394  Help();
395  exit(1);
396  break;
397 
398  case 'c': // Cancel morph animation conversion
399  make_morph = FALSE;
400  fprintf( outStream, "canceling morph conversion\n" );
401  break;
402 
403  case 'C': // Cancel uv animation conversion
404  make_duv = FALSE;
405  fprintf( outStream, "canceling uv animation conversion\n" );
406  break;
407 
408  case 'D': // Omit the Dart flag
409  make_dart = FALSE;
410  fprintf( outStream, "making a non-character model\n" );
411  break;
412 
413  case 'k': // Enable soft skinning
414  //make_soft = TRUE;
415  //fprintf( outStream, "enabling soft skinning\n" );
416  fprintf( outStream, "-k flag no longer necessary\n" );
417  break;
418 
419  case 'n': // Generate egg NURBS output
420  make_nurbs = TRUE;
421  fprintf( outStream, "outputting egg NURBS info\n" );
422  break;
423 
424  case 'p': // Generate egg polygon output
425  make_poly = TRUE;
426  fprintf( outStream, "outputting egg polygon info\n" );
427  break;
428 
429  case 'P': // Generate static pose from given frame
430  if ( strcmp( optarg, "" ) )
431  {
432  make_pose = TRUE;
433  pose_frame = atoi(optarg);
434  fprintf( outStream, "generating static pose from frame %d\n",
435  pose_frame );
436  }
437  break;
438 
439  case 'a': // Compile animation tables.
440  make_anim = TRUE;
441  fprintf( outStream, "attempting to compile anim tables\n" );
442  break;
443 
444  case 'F': // Build a flat skeleton.
445  flatten = TRUE;
446  fprintf( outStream, "building a flat skeleton!!!\n" );
447  break;
448 
449  case 'x': // Shift NURBS parameters to preserve Alias textures.
450  shift_textures = TRUE;
451  fprintf( outStream, "shifting NURBS parameters...\n" );
452  break;
453 
454  case 'i': // Ignore Soft uv texture offsets
455  ignore_tex_offsets = TRUE;
456  fprintf( outStream, "ignoring texture offsets...\n" );
457  break;
458 
459  case 'u': // Use Soft prefix in model names
460  use_prefix = TRUE;
461  fprintf( outStream, "using prefix in model names...\n" );
462  break;
463 
464 
465  case 'v': // print debug messages.
466  if ( strcmp( optarg, "" ) )
467  {
468  verbose = atoi(optarg);
469  fprintf( outStream, "using debug level %d\n", verbose );
470  }
471  break;
472 
473  case 'b': // Set animation start frame.
474  if ( strcmp( optarg, "" ) )
475  {
476  anim_start = atoi(optarg);
477  fprintf( outStream, "animation starting at frame: %d\n",
478  anim_start );
479  }
480  break;
481 
482  case 'e': /// Set animation end frame.
483  if ( strcmp( optarg, "" ) )
484  {
485  anim_end = atoi(optarg);
486  fprintf( outStream, "animation ending at frame: %d\n", anim_end );
487  }
488  break;
489 
490  case 'f': /// Set animation frame rate.
491  if ( strcmp( optarg, "" ) )
492  {
493  anim_rate = atoi(optarg);
494  fprintf( outStream, "animation frame rate: %d\n", anim_rate );
495  }
496  break;
497 
498  default:
499  okflag = EggBase::HandleGetopts(flag, optarg, optind, argc, argv);
500  }
501 
502  return (okflag);
503 }
504 
505 
506 
507 ////////////////////////////////////////////////////////////////////
508 // Function: isNum
509 // Access: Public, Virtual
510 // Description: Take a float and make sure it is of the body.
511 ////////////////////////////////////////////////////////////////////
512 int soft2egg::
513 isNum( float num )
514 {
515  return( ( num < HUGE_VAL ) && finite( num ) );
516 }
517 
518 
519 ////////////////////////////////////////////////////////////////////
520 // Function: GetRootName
521 // Access: Public
522 // Description: Given a string, return a copy of the string up to
523 // the first occurence of '-'.
524 ////////////////////////////////////////////////////////////////////
525 char *soft2egg::
526 GetRootName( const char *name )
527 {
528  char *hyphen;
529  char *root;
530  int len;
531 
532  hyphen = strchr( name, '-' );
533  len = hyphen-name;
534 
535  if ( (hyphen != NULL) && len )
536  {
537  root = (char *)malloc(sizeof(char)*(len+1));
538  strncpy( root, name, len );
539  root[sizeof(char)*(len)] = '\0';
540  }
541  else
542  {
543  root = (char *)malloc( sizeof(char)*(strlen(name)+1));
544  strcpy( root, name );
545  }
546 
547  return( root );
548 }
549 
550 
551 ////////////////////////////////////////////////////////////////////
552 // Function: RemovePathName
553 // Access: Public
554 // Description: Given a string, return a copy of the string after
555 // the last occurence of '/
556 ////////////////////////////////////////////////////////////////////
557 char *soft2egg::
558 RemovePathName( const char *name )
559 {
560  char *slash;
561  char *root;
562 
563  if ( *name != NULL )
564  {
565  slash = strrchr( name, '/' );
566 
567  root = (char *)malloc( sizeof(char)*(strlen(name)+1));
568 
569  if ( slash != NULL )
570  strcpy( root, ++slash );
571  else
572  strcpy( root, name );
573 
574  return( root );
575  }
576 
577  fprintf( stderr, "Error: RemovePathName received NULL string!\n" );
578  return ( (char *)name );
579 }
580 
581 ////////////////////////////////////////////////////////////////////
582 // Function: GetSliderName
583 // Access: Public
584 // Description: Given a string, return that part of the string after
585 // the first occurence of '-' and before the last
586 // occurance of '.'
587 ////////////////////////////////////////////////////////////////////
588 char *soft2egg::
589 GetSliderName( const char *name )
590 {
591  if ( name != NULL )
592  {
593  strstream newStr;
594  char *hyphen;
595  char *end;
596 
597  hyphen = strchr( name, '-' );
598 
599  // pull off stuff before first hyphen
600  if (hyphen != NULL)
601  {
602  newStr << ++hyphen;
603  end = newStr.str();
604  }
605 
606  char *lastPeriod;
607 
608  lastPeriod = strrchr( end, '.' );
609 
610  // ignore stuff after last period
611  if ( lastPeriod != NULL )
612  {
613  *lastPeriod = '\0';
614  }
615 
616  if ( verbose >= 1 )
617  fprintf( stdout, "slider name: '%s'\n", end );
618 
619  return( end );
620  }
621 
622  return( (char *)name );
623 }
624 
625 ////////////////////////////////////////////////////////////////////
626 // Function: GetName
627 // Access: Public
628 // Description: Given an element, return a copy of the element's
629 // name WITHOUT prefix.
630 ////////////////////////////////////////////////////////////////////
631 char *soft2egg::
632 GetName( SAA_Scene *scene, SAA_Elem *element )
633 {
634  int nameLen;
635  char *name;
636 
637  // get the name
638  SAA_elementGetNameLength( scene, element, &nameLen );
639  name = (char *)malloc(sizeof(char)*++nameLen);
640  SAA_elementGetName( scene, element, nameLen, name );
641 
642  return name;
643 }
644 
645 ////////////////////////////////////////////////////////////////////
646 // Function: GetFullName
647 // Access: Public
648 // Description: Given an element, return a copy of the element's
649 // name complete with prefix.
650 ////////////////////////////////////////////////////////////////////
651 char *soft2egg::
652 GetFullName( SAA_Scene *scene, SAA_Elem *element )
653 {
654  int nameLen;
655  char *name;
656 
657  // get the name
658  SAA_elementGetNameLength( scene, element, &nameLen );
659  name = (char *)malloc(sizeof(char)*++nameLen);
660  SAA_elementGetName( scene, element, nameLen, name );
661 
662  int prefixLen;
663  char *prefix;
664 
665  // get the prefix
666  SAA_elementGetPrefixLength( scene, element, &prefixLen );
667  prefix = (char *)malloc(sizeof(char)*++prefixLen);
668  SAA_elementGetPrefix( scene, element, prefixLen, prefix );
669 
670  strstream fullNameStrm;
671 
672  // add 'em together
673  fullNameStrm << prefix << "-" << name << ends;
674 
675  //free( name );
676  //free( prefix );
677 
678  return fullNameStrm.str();
679 }
680 
681 ////////////////////////////////////////////////////////////////////
682 // Function: GetModelNoteInfo
683 // Access: Public
684 // Description: Given an element, return a string containing the
685 // contents of its MODEL NOTE entry
686 ////////////////////////////////////////////////////////////////////
687 char *soft2egg::
688 GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model )
689 {
690 
691  int size;
692  char *modelNote = NULL;
693  SAA_Boolean bigEndian;
694 
695 
696  SAA_elementGetUserDataSize( scene, model, "MNOT", &size );
697 
698  if ( size != 0 )
699  {
700  // allocate modelNote string
701  modelNote = (char *)malloc(sizeof(char)*(size + 1));
702 
703  // get ModelNote data from this model
704  SAA_elementGetUserData( scene, model, "MNOT", size,
705  &bigEndian, (void *)modelNote );
706 
707  //strip off newline, if present
708  char *eol = strchr( modelNote, '\n' );
709  if ( eol != NULL)
710  *eol = '\0';
711  else
712  modelNote[size] = '\0';
713 
714  if ( verbose >= 1 )
715  fprintf( outStream, "\nmodelNote = %s\n",
716  modelNote );
717  }
718 
719  return modelNote;
720 }
721 
722 
723 ////////////////////////////////////////////////////////////////////
724 // Function: MakeTableName
725 // Access: Public
726 // Description: Given a string, and a number, return a new string
727 // consisting of "string.number".
728 ////////////////////////////////////////////////////////////////////
729 char *soft2egg::
730 MakeTableName( const char *name, int number )
731 {
732  strstream namestrm;
733 
734  namestrm << name << "." << number << ends;
735  return namestrm.str();
736 }
737 
738 ////////////////////////////////////////////////////////////////////
739 // Function: FindModelByName
740 // Access: Public
741 // Description: Given a string, find the model in the scene
742 // whose name corresponds to the given string.
743 ////////////////////////////////////////////////////////////////////
744 SAA_Elem *soft2egg::
745 FindModelByName( char *name, SAA_Scene *scene, SAA_Elem *models,
746  int numModels )
747 {
748  char *foundName;
749  SAA_Elem *foundModel = NULL;
750 
751  for ( int model = 0; model < numModels; model++ )
752  {
753  foundName = GetName( scene, &models[model] );
754 
755  if ( !strcmp( name, foundName ) )
756  {
757  if ( verbose >= 1 )
758  fprintf( outStream, "foundModel: '%s' = '%s'\n",
759  name, foundName );
760 
761  foundModel = &models[model];
762  return( foundModel );
763  }
764  }
765 
766  fprintf( outStream, "findModelByName: failed to find model named: '%s'\n",
767  name );
768 
769  return ( foundModel );
770 }
771 
772 
773 ////////////////////////////////////////////////////////////////////
774 // Function: DepointellizeName
775 // Access: Public
776 // Description: Given a string, return the string up to the first
777 // period.
778 ////////////////////////////////////////////////////////////////////
779 char *soft2egg::
780 DepointellizeName( char *name )
781 {
782  char *endPtr;
783  char *newName;
784 
785  newName = (char *)malloc(sizeof(char)*(strlen(name)+1));
786  sprintf( newName, "%s", name );
787 
788  endPtr = strchr( newName, '.' );
789  if ( endPtr != NULL )
790  *endPtr = '\0';
791 
792  return ( newName );
793 }
794 
795 
796 ////////////////////////////////////////////////////////////////////
797 // Function: ConvertTexture
798 // Access: Public
799 // Description: Given a string, return a copy of the string without
800 // the leading file path, and make an rgb file of the
801 // same name in the tex_path directory.
802 ////////////////////////////////////////////////////////////////////
803 char *soft2egg::
804 ConvertTexture( SAA_Scene *scene, SAA_Elem *texture )
805 {
806  char *fileName = NULL;
807  int fileNameLen = 0;
808 
809  // get the texture's name
810  SAA_texture2DGetPicNameLength( scene, texture, &fileNameLen);
811 
812  if ( fileNameLen )
813  {
814  fileName = (char *)malloc(sizeof(char)*++fileNameLen);
815  SAA_texture2DGetPicName( scene, texture, fileNameLen, fileName );
816  }
817 
818  // make sure we are not being passed a NULL image, an empty image
819  // string or the default image created by egg2soft
820  if ( (fileName != NULL) && strlen( fileName ) && strcmp( fileName,
821  "/fat/people/gregw/new_test/PICTURES/default") &&
822  ( strstr( fileName, "noIcon" ) == NULL) )
823  {
824  char *texName = NULL;
825  char *texNamePath = NULL;
826  char *tmpName = NULL;
827  char *fileNameExt = NULL;
828 
829  // strip off path and add .rgb
830  tmpName = strrchr( fileName, '/' );
831 
832  if ( tmpName == NULL )
833  tmpName = fileName;
834  else
835  tmpName++;
836 
837  float transp;
838 
839  // check for alpha
840  SAA_texture2DGetTransparency( scene, texture, &transp );
841 
842  if ( transp != 0.0f ) {
843  texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+6));
844  sprintf( texName, "%s.rgba", tmpName );
845  } else {
846  texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+5));
847  sprintf( texName, "%s.rgb", tmpName );
848  }
849 
850  fileNameExt = (char *)malloc(sizeof(char)*(strlen(fileName)+5));
851  sprintf( fileNameExt, "%s.pic", fileName );
852 
853  if ( verbose >= 1 )
854  fprintf( outStream, "Looking for texture file: '%s'\n", fileNameExt );
855 
856  // try to make conversion of file
857  int found_file = ( access( fileNameExt, F_OK ) == 0);
858 
859  if ( found_file )
860  {
861  if ( tex_path )
862  {
863  texNamePath = (char *)malloc(sizeof(char)*(strlen(tex_path) +
864  strlen(texName) + 2));
865 
866  sprintf( texNamePath, "%s/%s", tex_path, texName );
867 
868  if ( texFile )
869  texFile << texNamePath << ": " << fileNameExt << "\n";
870 
871  // make sure conversion doesn't already exist
872  if ( (access( texNamePath, F_OK ) != 0) && !texFile )
873  {
874  char *command = (char *)malloc(sizeof(char)*
875  (strlen(fileNameExt) + strlen(texNamePath) + 20));
876 
877  sprintf( command, "image-resize -1 %s %s",
878  fileNameExt, texNamePath );
879 
880  if ( verbose >=1 )
881  fprintf( outStream, "executing %s\n", command );
882 
883  system( command );
884 
885  //free( command );
886  }
887  else
888  if ( verbose >=1 )
889  fprintf( outStream, "%s already exists!\n", texNamePath );
890  }
891  else
892  {
893  if ( verbose >= 1 )
894  {
895  fprintf( outStream, "Warning: No texture path defined" );
896  fprintf( outStream, " - No automatic conversion performed\n" );
897  }
898  }
899  }
900  else
901  {
902  fprintf( outStream, "Warning: Couldn't find texture file: %s\n",
903  fileNameExt );
904  }
905 
906  //free( fileNameExt );
907 
908  if (tex_path)
909  return( texNamePath );
910  else
911  return( texName );
912  }
913  else
914  {
915  fprintf( outStream, "Warning: ConvertTexture received NULL fileName\n" );
916  return( NULL );
917  }
918 }
919 
920 ////////////////////////////////////////////////////////////////////
921 // Function: FindClosestTriVert
922 // Access: Public
923 // Description: Given an egg vertex pool, map each vertex therein to
924 // a vertex within an array of SAA model vertices of
925 // size numVert. Mapping is done by closest proximity.
926 ////////////////////////////////////////////////////////////////////
927 int *soft2egg::
928 FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert )
929 {
930  int *vertMap = NULL;
931  int vpoolSize = vpool->NumVertices();
932  int i,j;
933  float thisDist;
934  float closestDist;
935  int closest;
936 
937 
938  vertMap = (int *)malloc(sizeof(int)*vpoolSize);
939 
940  // for each vertex in vpool
941  for ( i = 0; i < vpoolSize; i++ )
942  {
943  // find closest model vertex
944  for ( j = 0; j < numVert-1; j++ )
945  {
946  // calculate distance
947  thisDist = sqrtf(
948  powf( vpool->Vertex(i)->position[0] - vertices[j].x , 2 ) +
949  powf( vpool->Vertex(i)->position[1] - vertices[j].y , 2 ) +
950  powf( vpool->Vertex(i)->position[2] - vertices[j].z , 2 ) );
951 
952  // remember this if its the closest so far
953  if ( !j || ( thisDist < closestDist ) )
954  {
955  closest = j;
956  closestDist = thisDist;
957  }
958  }
959  vertMap[i] = closest;
960 
961  if ( verbose >= 2 )
962  {
963  fprintf( outStream, "mapping v %d of %d:( %f, %f, %f )\n", i,
964  vpoolSize, vpool->Vertex(i)->position[0],
965  vpool->Vertex(i)->position[1],
966  vpool->Vertex(i)->position[2] );
967  fprintf( outStream, "to cv %d of %d:( %f, %f, %f )\tdelta = %f\n",
968  closest, numVert-1, vertices[closest].x, vertices[closest].y,
969  vertices[closest].z, closestDist );
970  }
971  }
972 
973  return( vertMap );
974 }
975 
976 
977 ////////////////////////////////////////////////////////////////////
978 // Function: MakeIndexMap
979 // Access: Public
980 // Description: Given an array of indices that is a map from one
981 // set of vertices to another, return an array that
982 // performs the reverse mapping of the indices array
983 ////////////////////////////////////////////////////////////////////
984 int *soft2egg::
985 MakeIndexMap( int *indices, int numIndices, int mapSize )
986 {
987  int i, j;
988 
989  // allocate map array
990  int *map = (int *)malloc(sizeof(int)*mapSize);
991 
992  if ( map != NULL )
993  {
994  for ( i = 0; i < mapSize; i++ )
995  {
996  j = 0;
997  int found = 0;
998  while( j < numIndices )
999  {
1000  if ( indices[j] == i )
1001  {
1002  map[i] = j;
1003  if ( verbose >= 2 )
1004  fprintf( outStream, "map[%d] = %d\n", i, map[i] );
1005  found = 1;
1006  break;
1007  }
1008  j++;
1009  }
1010  if ( !found)
1011  {
1012  if ( verbose >= 2 )
1013  fprintf( outStream, "Warning: orphan vertex (%d)\n", i );
1014  // default to -1 for now
1015  map[i] = -1;
1016  }
1017  }
1018  }
1019  else
1020  fprintf( outStream, "Not enough Memory for index Map...\n");
1021 
1022 
1023  return( map );
1024 }
1025 
1026 
1027 ////////////////////////////////////////////////////////////////////
1028 // Function: findShapeVert
1029 // Access: Public
1030 // Description: given a vertex, find its corresponding shape vertex
1031 // and return its index.
1032 ////////////////////////////////////////////////////////////////////
1033 int soft2egg::
1034 findShapeVert( SAA_DVector vertex, SAA_DVector *vertices, int numVert )
1035 {
1036  int i;
1037  int found = 0;
1038 
1039  for ( i = 0; i < numVert && !found ; i++ )
1040  {
1041  if ( ( vertex.x == vertices[i].x ) &&
1042  ( vertex.y == vertices[i].y ) &&
1043  ( vertex.z == vertices[i].z ) )
1044  {
1045  found = 1;
1046 
1047  if ( verbose >= 2)
1048  fprintf( outStream, "found shape vert at index %d\n", i );
1049  }
1050 
1051  }
1052 
1053  if (!found )
1054  i = -1;
1055  else
1056  i--;
1057 
1058  return( i );
1059 }
1060 
1061 
1062 ////////////////////////////////////////////////////////////////////
1063 // Function: LoadSoft
1064 // Access: Public
1065 // Description: Open the SI database and grab the scene & model info
1066 ////////////////////////////////////////////////////////////////////
1067 void soft2egg::
1068 LoadSoft()
1069 {
1070  int i;
1071 
1072  if ( (scene_name == NULL && model_name == NULL) || database_name == NULL )
1073  {
1074  Usage();
1075  exit( 1 );
1076  }
1077 
1078  if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS)
1079  {
1080  fprintf( outStream, "Error: Couldn't get resource path!\n");
1081  exit( 1 );
1082  }
1083 
1084  if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS)
1085  {
1086  fprintf( outStream, "Error: Couldn't load database!\n");
1087  exit( 1 );
1088  }
1089 
1090  if ((result = SAA_sceneGetCurrent(&scene)) == SI_SUCCESS)
1091  {
1092  // load scene if present
1093  if ( scene_name != NULL )
1094  {
1095  SAA_sceneLoad( &database, scene_name, &scene );
1096 
1097  // if no egg filename specified, make up a name
1098  if ( eggFileName == NULL )
1099  {
1100  eggFileName = (char *)malloc(sizeof(char)*
1101  (strlen( scene_name ) + 14 ));
1102  sprintf( eggFileName, "%s", DepointellizeName(scene_name) );
1103  if ( make_nurbs )
1104  strcat( eggFileName, "-nurb" );
1105  strcat( eggFileName, "-mod.egg" );
1106  }
1107 
1108  // open an output file for the geometry if necessary
1109  if ( make_poly || make_nurbs )
1110  {
1111  unlink( eggFileName );
1112  eggFile.open( eggFileName, ios::out, 0666 );
1113 
1114  if ( !eggFile )
1115  {
1116  fprintf( outStream, "Couldn't open output file: %s\n",
1117  eggFileName );
1118  exit( 1 );
1119  }
1120  }
1121 
1122  // open an output file for texture list if specified
1123  if ( tex_filename != NULL )
1124  {
1125  unlink( tex_filename );
1126  texFile.open( tex_filename, ios::out, 0666 );
1127 
1128  if ( !texFile )
1129  {
1130  fprintf( outStream, "Couldn't open output file: %s\n",
1131  tex_filename );
1132  exit( 1 );
1133  }
1134  }
1135 
1136  if ( SAA_updatelistGet( &scene ) == SI_SUCCESS )
1137  {
1138  float time;
1139 
1140  fprintf( outStream, "setting Scene to frame %d...\n", pose_frame );
1141  //SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame );
1142  SAA_frame2Seconds( &scene, pose_frame, &time );
1143  SAA_updatelistEvalScene( &scene, time );
1144  sginap( 100 );
1145  SAA_updatelistEvalScene( &scene, time );
1146  if ( make_pose )
1147  SAA_sceneFreeze( &scene );
1148  }
1149 
1150  int numModels;
1151  SAA_Elem *models;
1152 
1153  SAA_sceneGetNbModels( &scene, &numModels );
1154  fprintf( outStream, "Scene has %d model(s)...\n", numModels );
1155 
1156  if ( numModels )
1157  {
1158  // allocate array of models
1159  models = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numModels);
1160 
1161  if ( models != NULL )
1162  {
1163  char *rootName = GetRootName( eggFileName );
1164 
1165 
1166  if ( eggGroupName == NULL )
1167  dart = _data.CreateGroup( NULL, rootName );
1168  else
1169  dart = _data.CreateGroup( NULL, eggGroupName );
1170 
1171  if (make_dart)
1172  dart->flags |= EF_DART;
1173 
1174  AnimGroup *rootTable;
1175 
1176  rootTable = animData.CreateTable( NULL, eggFileName );
1177 
1178  if ( eggGroupName == NULL )
1179  animRoot = animData.CreateBundle( rootTable, rootName );
1180  else
1181  animRoot = animData.CreateBundle( rootTable,
1182  eggGroupName );
1183 
1184  // propagate commet to anim data
1185  animData.root_group.children.push_front(
1186  new EggComment( _commandLine ) );
1187 
1188  if ( verbose >= 1 )
1189  fprintf( outStream, "made animRoot: %s\n", rootName );
1190 
1191  SAA_sceneGetModels( &scene, numModels, models );
1192 
1193  for ( i = 0; i < numModels; i++ )
1194  {
1195  int level;
1196 
1197  SAA_elementGetHierarchyLevel( &scene, &models[i], &level );
1198  if ( !level )
1199  {
1200  if ( verbose >= 1 )
1201  fprintf( outStream,
1202  "\negging scene model[%d]\n", i );
1203 
1204  MakeEgg( dart, NULL, NULL, &scene, &models[i] );
1205  }
1206  }
1207 
1208  if ( make_poly || make_nurbs )
1209  {
1210  // generate soft skinning assignments if desired
1211  //
1212  //disabled 1/1/99 to streamline joint assignments.
1213  // all joint assignments now done here. Hard & Soft.
1214  //if ( make_soft)
1215  {
1216  char *name;
1217  char *fullname;
1218  SAA_Boolean isSkeleton;
1219 
1220  // search through models and look for skeleton parts
1221  for ( i = 0; i < numModels; i++ )
1222  {
1223  SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton );
1224 
1225  // get fullname for splitting files, but
1226  // only use it in file if requested
1227  fullname = GetFullName( &scene, &models[i] );
1228  if ( use_prefix )
1229  name = fullname;
1230  else
1231  name = GetName( &scene, &models[i] );
1232 
1233  // split
1234  if ( strstr( fullname, search_prefix ) != NULL )
1235  {
1236  // for every skel part: get soft skin info
1237  if ( isSkeleton )
1238  MakeSoftSkin( &scene, &models[i], models,
1239  numModels, name );
1240  }
1241 
1242  //free( name );
1243  }
1244 
1245  // make sure all vertices were assigned
1246  // via soft skinning - if not hard assign them
1247  for ( i = 0; i < numModels; i++ )
1248  {
1249  // get fullname for splitting files, but
1250  // only use it in file if requested
1251  fullname = GetFullName( &scene, &models[i] );
1252  if ( use_prefix )
1253  name = fullname;
1254  else
1255  name = GetName( &scene, &models[i] );
1256 
1257  // split
1258  if ( strstr( fullname, search_prefix ) != NULL )
1259  CleanUpSoftSkin( &scene, &models[i], name );
1260 
1261  //free( name );
1262  }
1263 
1264  }
1265 
1266 
1267  // put the skeleton data into the egg data
1268  dart->StealChildren( *skeleton );
1269 
1270  // make sure all elements have unique names
1271  _data.UniquifyNames();
1272 
1273  // write out the geometry data if requested
1274  //if ( make_poly || make_nurbs )
1275  //{
1276  eggFile << _data << "\n";
1277  fprintf( outStream, "\nwriting out %s...\n", eggFileName );
1278  eggFile.close();
1279  }
1280 
1281  // close texture list file if opened
1282  if ( texFile )
1283  texFile.close();
1284 
1285  // generate animation data if desired
1286  if ( make_anim )
1287  {
1288  if ( animFileName == NULL )
1289  {
1290  animFileName = (char *)malloc(sizeof(char)*
1291  (strlen(scene_name)+ 10 ));
1292  sprintf( animFileName, "%s", DepointellizeName(scene_name) );
1293  strcat( animFileName, "-chan.egg" );
1294  }
1295 
1296  unlink( animFileName );
1297  animFile.open( animFileName, ios::out, 0666 );
1298 
1299  if ( !animFile )
1300  {
1301  fprintf( outStream, "Couldn't open output file: %s\n",
1302  animFileName );
1303  exit( 1 );
1304  }
1305 
1306  int frame;
1307  //int frameStep;
1308  float time;
1309 
1310  // get all the animation frame info if not specified
1311  // on the command line
1312  if (anim_start == -1000)
1313  SAA_sceneGetPlayCtrlStartFrame( &scene, &anim_start );
1314 
1315  if (anim_end == -1000)
1316  SAA_sceneGetPlayCtrlEndFrame( &scene, &anim_end );
1317 
1318  //SAA_sceneGetPlayCtrlFrameStep( &scene, &frameStep );
1319 
1320  fprintf( outStream, "\nframeStart = %d\n", anim_start );
1321  fprintf( outStream, "frameEnd = %d\n", anim_end );
1322  //fprintf( outStream, "frameStep = %d\n", frameStep );
1323 
1324  // start at first frame and go to last
1325  for ( frame = anim_start; frame <= anim_end;
1326  frame += 1)
1327  {
1328  SAA_frame2Seconds( &scene, frame, &time );
1329  SAA_updatelistEvalScene( &scene, time );
1330  sginap( 100 );
1331  SAA_updatelistEvalScene( &scene, time );
1332  fprintf( outStream, "\n> animating frame %d\n", frame );
1333 
1334  // for each model
1335  for ( i = 0; i < numModels; i++ )
1336  {
1337  char *name;
1338  char *fullname;
1339  SAA_Boolean isSkeleton;
1340  SAA_ModelType type;
1341 
1342  SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton );
1343 
1344  // get fullname for splitting files, but
1345  // only use it in file if requested
1346  fullname = GetFullName( &scene, &models[i] );
1347  if ( use_prefix )
1348  name = fullname;
1349  else
1350  name = GetName( &scene, &models[i] );
1351 
1352  // split
1353  if ( strstr( fullname, search_prefix ) != NULL )
1354  {
1355  // make the morph table for this critter
1356  if ( make_morph )
1357  {
1358  MakeMorphTable( &scene, &models[i], models,
1359  numModels, name, time );
1360  }
1361  }
1362 
1363  // find out what type of node we're dealing with
1364  result = SAA_modelGetType( &scene, &models[i], &type );
1365 
1366  int size;
1367 
1368  // check for uv texture animation
1369  SAA_elementGetUserDataSize( &scene, &models[i],
1370  "TEX_OFFSETS", &size );
1371 
1372  // if so, update for this frame if desired
1373  if ( ( size != 0 ) && make_duv )
1374  MakeTexAnim( &scene, &models[i], name );
1375 
1376  // if we have a skeleton or something that acts
1377  // like one - build anim tables
1378  if ( isSkeleton ||
1379  ( strstr( name, "joint") != NULL ) )
1380  MakeAnimTable( &scene, &models[i], name );
1381 
1382  //free( name );
1383  }
1384 
1385  if ( verbose >= 1 )
1386  fprintf( outStream, "\n" );
1387  }
1388 
1389  animFile << animData << "\n";
1390  fprintf( outStream, "\nwriting out %s...\n", animFileName );
1391  animFile.close();
1392  }
1393 
1394  //free( models );
1395 
1396  }
1397  else
1398  fprintf( outStream, "Error: Not enough Memory for models...\n");
1399  }
1400  }
1401  // otherwise try to load a model
1402  else if ( model_name != NULL )
1403  {
1404 
1405  if ( eggFileName == NULL )
1406  {
1407  eggFileName =
1408  (char *)malloc(sizeof(char)*(strlen( model_name )+13));
1409  sprintf( eggFileName, "%s", DepointellizeName( model_name ) );
1410 
1411  if ( make_nurbs )
1412  strcat( eggFileName, "-nurb" );
1413  strcat( eggFileName, "-mod.egg" );
1414  }
1415 
1416  eggFile.open( eggFileName );
1417 
1418  if ( !eggFile )
1419  {
1420  fprintf( outStream, "Couldn't open output file: %s\n",
1421  eggFileName );
1422  exit( 1 );
1423  }
1424 
1425  if ((result =
1426  SAA_elementLoad(&database, &scene, model_name, &model))
1427  == SI_SUCCESS)
1428  {
1429  fprintf( outStream, "Loading single model...\n");
1430  MakeEgg( NULL, NULL, NULL, &scene, &model );
1431  }
1432 
1433  eggFile << _data << "\n";
1434  }
1435  }
1436 
1437 }
1438 
1439 ////////////////////////////////////////////////////////////////////
1440 // Function: MakeEgg
1441 // Access: Public
1442 // Description: Make egg geometry from a given model. This include
1443 // textures, tex coords, colors, normals, and joints.
1444 ////////////////////////////////////////////////////////////////////
1445 void soft2egg::
1446 MakeEgg( EggGroup *parent, EggJoint *lastJoint, AnimGroup *lastAnim,
1447  SAA_Scene *scene, SAA_Elem *model )
1448 {
1449  char *name;
1450  char *fullname;
1451  SAA_ModelType type;
1452  int id = 0;
1453  int numShapes;
1454  int numTri;
1455  int numVert;
1456  int numTexLoc = 0;
1457  int numTexGlb = 0;
1458  int i, j;
1459  float matrix[4][4];
1460  float *uScale = NULL;
1461  float *vScale = NULL;
1462  float *uOffset = NULL;
1463  float *vOffset = NULL;
1464  SAA_Boolean uv_swap = FALSE;
1465  void *relinfo;
1466  SAA_SubElem *triangles = NULL;
1467  SAA_Elem *materials = NULL;
1468  SAA_SubElem *cvertices = NULL;
1469  SAA_DVector *cvertPos = NULL;
1470  SAA_DVector *vertices = NULL;
1471  SAA_DVector *normals = NULL;
1472  int *indices = NULL;
1473  int *indexMap = NULL;
1474  int *numTexTri = NULL;
1475  SAA_Elem *textures = NULL;
1476  char **texNameArray;
1477  float *uCoords = NULL;
1478  float *vCoords = NULL;
1479  SAA_GeomType gtype = SAA_GEOM_ORIGINAL;
1480  SAA_Boolean visible;
1481 
1482  /////////////////////////////////////////////////
1483  // find out what type of node we're dealing with
1484  /////////////////////////////////////////////////
1485  result = SAA_modelGetType( scene, model, &type );
1486 
1487  if ( verbose >= 1 )
1488  {
1489  if ( type == SAA_MNILL )
1490  fprintf( outStream, "encountered null\n");
1491  else if ( type == SAA_MPTCH )
1492  fprintf( outStream, "encountered patch\n" );
1493  else if ( type == SAA_MFACE )
1494  fprintf( outStream, "encountered face\n" );
1495  else if ( type == SAA_MSMSH )
1496  fprintf( outStream, "encountered mesh\n" );
1497  else if ( type == SAA_MJNT )
1498  fprintf( outStream, "encountered joint\n" );
1499  else if ( type == SAA_MSPLN )
1500  fprintf( outStream, "encountered spline\n" );
1501  else if ( type == SAA_MMETA )
1502  fprintf( outStream, "encountered meta element\n" );
1503  else if ( type == SAA_MBALL )
1504  fprintf( outStream, "encountered metaball\n" );
1505  else if ( type == SAA_MNCRV )
1506  fprintf( outStream, "encountered nurb curve\n" );
1507  else if ( type == SAA_MNSRF )
1508  fprintf( outStream, "encountered nurbs surf\n" );
1509  else
1510  fprintf( outStream, "encountered unknown type: %d\n", type );
1511  }
1512 
1513  /////////////////////////////
1514  // Get the name of the model
1515  /////////////////////////////
1516 
1517  // Get the FULL name of the model
1518  fullname = GetFullName( scene, model );
1519 
1520  if ( use_prefix )
1521  {
1522  // Get the FULL name of the trim curve
1523  name = fullname;
1524  }
1525  else
1526  {
1527  // Get the name of the trim curve
1528  name = GetName( scene, model );
1529  }
1530 
1531  if ( verbose >= 1 )
1532  fprintf( outStream, "element name <%s>\n", name );
1533 
1534  fflush( outStream );
1535 
1536  // get the model's matrix
1537  SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix );
1538 
1539  if ( verbose >= 2 )
1540  {
1541  fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[0][0],
1542  matrix[0][1], matrix[0][2], matrix[0][3] );
1543  fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[1][0],
1544  matrix[1][1], matrix[1][2], matrix[1][3] );
1545  fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[2][0],
1546  matrix[2][1], matrix[2][2], matrix[2][3] );
1547  fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[3][0],
1548  matrix[3][1], matrix[3][2], matrix[3][3] );
1549  }
1550 
1551  ///////////////////////////////////////////////////////////////////////
1552  // check to see if this is a branch we don't want to descend - this
1553  // will prevent creating geometry for animation control structures
1554  ///////////////////////////////////////////////////////////////////////
1555  if ( (strstr( name, "con-" ) == NULL) &&
1556  (strstr( name, "con_" ) == NULL) &&
1557  (strstr( name, "fly_" ) == NULL) &&
1558  (strstr( name, "fly-" ) == NULL) &&
1559  (strstr( name, "camRIG" ) == NULL) &&
1560  (strstr( name, "bars" ) == NULL) &&
1561  // split
1562  (strstr( fullname, search_prefix ) != NULL) )
1563  {
1564 
1565  // if making a pose - get deformed geometry
1566  if ( make_pose )
1567  gtype = SAA_GEOM_DEFORMED;
1568 
1569  // Get the number of key shapes
1570  SAA_modelGetNbShapes( scene, model, &numShapes );
1571  if ( verbose >= 1 )
1572  fprintf( outStream, "MakeEgg: num shapes: %d\n", numShapes);
1573 
1574  ///////////////////////////////////////////////////////////////////////
1575  // if multiple key shapes exist create table entries for each
1576  ///////////////////////////////////////////////////////////////////////
1577  if ( (numShapes > 0) && make_morph )
1578  {
1579  has_morph = 1;
1580 
1581  // make sure root morph table exists
1582  if ( morphRoot == NULL )
1583  morphRoot = animData.CreateTable( animRoot, "morph" );
1584 
1585  char *tableName;
1586 
1587  // create morph table entry for each key shape
1588  // (start at second shape - as first is the original geometry)
1589  for ( i = 1; i < numShapes; i++ )
1590  {
1591  tableName = MakeTableName( name, i );
1592  SAnimTable *table = new SAnimTable( );
1593  table->name = tableName;
1594  table->fps = anim_rate;
1595  morphRoot->children.push_back( table );
1596  if ( verbose >= 1 )
1597  fprintf( outStream, "created table named: '%s'\n", tableName );
1598  }
1599 
1600  //free( tableName );
1601  }
1602 
1603  SAA_modelGetNodeVisibility( scene, model, &visible );
1604  if ( verbose >= 1 )
1605  fprintf( outStream, "model visibility: %d\n", visible );
1606 
1607  ///////////////////////////////////////////////////////////////////////
1608  // Only create egg polygon data if: the node is visible, and its not
1609  // a NULL or a Joint, and we're outputing polys (or if we are outputing
1610  // NURBS and the model is a poly mesh or a face)
1611  ///////////////////////////////////////////////////////////////////////
1612  if ( visible &&
1613  (type != SAA_MNILL) &&
1614  (type != SAA_MJNT) &&
1615  ((make_poly ||
1616  (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) ))
1617  || (!make_poly && !make_nurbs && make_duv &&
1618  ((type == SAA_MSMSH) || (type == SAA_MFACE )) ))
1619  )
1620  {
1621  // If the model is a NURBS in soft, set its step before tesselating
1622  if ( type == SAA_MNSRF )
1623  SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
1624 
1625  // If the model is a PATCH in soft, set its step before tesselating
1626  else if ( type == SAA_MPTCH )
1627  SAA_patchSetStep( scene, model, nurbs_step, nurbs_step );
1628 
1629  // Get the number of triangles
1630  result = SAA_modelGetNbTriangles( scene, model, gtype, id, &numTri);
1631  if ( verbose >= 1 )
1632  fprintf( outStream, "triangles: %d\n", numTri);
1633 
1634  if ( result != SI_SUCCESS )
1635  {
1636  if ( verbose >= 1 ) {
1637  fprintf( outStream,
1638  "Error: couldn't get number of triangles!\n" );
1639  fprintf( outStream, "\tbailing on model: '%s'\n", name );
1640  }
1641  return;
1642  }
1643 
1644  // check to see if surface is also skeleton...
1645  SAA_Boolean isSkeleton = FALSE;
1646 
1647  SAA_modelIsSkeleton( scene, model, &isSkeleton );
1648 
1649  // check to see if this surface is used as a skeleton
1650  // or is animated via constraint only ( these nodes are
1651  // tagged by the animator with the keyword "joint"
1652  // somewhere in the nodes name)
1653  if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
1654  {
1655  if ( verbose >= 1 )
1656  fprintf( outStream, "animating Polys as joint!!!\n" );
1657 
1658  MakeJoint( scene, lastJoint, lastAnim, model, name );
1659  }
1660 
1661  // model is not a null and has no triangles!
1662  if ( !numTri )
1663  {
1664  if ( verbose >= 1 )
1665  fprintf( outStream, "no triangles!\n");
1666  }
1667  else
1668  {
1669  // allocate array of triangles
1670  triangles = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri);
1671  if ( triangles != NULL )
1672  {
1673  // triangulate model and read the triangles into array
1674  SAA_modelGetTriangles( scene, model, gtype, id, numTri, triangles );
1675  }
1676  else
1677  fprintf( outStream, "Not enough Memory for triangles...\n");
1678 
1679  // allocate array of materials
1680  materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri);
1681  if ( materials != NULL )
1682  {
1683  // read each triangle's material into array
1684  SAA_triangleGetMaterials( scene, model, numTri, triangles,
1685  materials );
1686  }
1687  else
1688  fprintf( outStream, "Not enough Memory for materials...\n");
1689 
1690  // allocate array of textures per triangle
1691  numTexTri = (int *)malloc(sizeof(int)*numTri);
1692 
1693  // find out how many local textures per triangle
1694  for ( i = 0; i < numTri; i++ )
1695  {
1696  result = SAA_materialRelationGetT2DLocNbElements( scene,
1697  &materials[i], FALSE, &relinfo, &numTexTri[i] );
1698 
1699  // polytex
1700  if ( result == SI_SUCCESS )
1701  numTexLoc += numTexTri[i];
1702  }
1703 
1704  // don't need this anymore...
1705  //free( numTexTri );
1706 
1707  // get local textures if present
1708  if ( numTexLoc )
1709  {
1710  // ASSUME only one texture per material
1711  textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri);
1712 
1713  for ( i = 0; i < numTri; i++ )
1714  {
1715  // and read all referenced local textures into array
1716  SAA_materialRelationGetT2DLocElements( scene, &materials[i],
1717  TEX_PER_MAT , &textures[i] );
1718  }
1719 
1720  if ( verbose >= 1 )
1721  fprintf( outStream, "numTexLoc = %d\n", numTexLoc);
1722  }
1723  // if no local textures, try to get global textures
1724  else
1725  {
1726  SAA_modelRelationGetT2DGlbNbElements( scene, model,
1727  FALSE, &relinfo, &numTexGlb );
1728 
1729  if ( numTexGlb )
1730  {
1731  // ASSUME only one texture per model
1732  textures = (SAA_Elem *)malloc(sizeof(SAA_Elem));
1733 
1734  // get the referenced texture
1735  SAA_modelRelationGetT2DGlbElements( scene, model,
1736  TEX_PER_MAT, textures );
1737 
1738  if ( verbose >= 1 )
1739  fprintf( outStream, "numTexGlb = %d\n", numTexGlb);
1740  }
1741  }
1742 
1743  // allocate array of control vertices
1744  cvertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri*3);
1745  if ( cvertices != NULL )
1746  {
1747  // read each triangle's control vertices into array
1748  SAA_triangleGetCtrlVertices( scene, model, gtype, id,
1749  numTri, triangles, cvertices );
1750 
1751  if ( verbose >= 2 )
1752  {
1753  cvertPos = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3);
1754  SAA_ctrlVertexGetPositions( scene, model, numTri*3,
1755  cvertices, cvertPos);
1756 
1757  for ( i=0; i < numTri*3; i++ )
1758  {
1759  fprintf( outStream, "cvert[%d] = %f %f %f %f\n", i,
1760  cvertPos[i].x, cvertPos[i].y, cvertPos[i].z,
1761  cvertPos[i].w );
1762  }
1763  }
1764  }
1765  else
1766  fprintf( outStream, "Not enough Memory for control vertices...\n");
1767 
1768  // allocate array of control vertex indices
1769  // this array maps from the redundant cvertices array into
1770  // the unique vertices array (cvertices->vertices)
1771  indices = (int *)malloc(sizeof(int)*numTri*3);
1772  if ( indices != NULL )
1773  {
1774  for ( i=0; i < numTri*3; i++ )
1775  indices[i] = 0;
1776 
1777  SAA_ctrlVertexGetIndices( scene, model, numTri*3,
1778  cvertices, indices );
1779 
1780  if ( verbose >= 2 )
1781  for ( i=0; i < numTri*3; i++ )
1782  fprintf( outStream, "indices[%d] = %d\n", i, indices[i] );
1783  }
1784  else
1785  fprintf( outStream, "Not enough Memory for indices...\n");
1786 
1787  // get number of UNIQUE vertices in model
1788  SAA_modelGetNbTriVertices( scene, model, &numVert );
1789 
1790  if ( verbose >= 2 )
1791  fprintf( outStream, "num unique verts = %d\n", numVert );
1792 
1793  //allocate array of vertices
1794  vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert);
1795 
1796  // get the UNIQUE vertices of all triangles in model
1797  SAA_modelGetTriVertices( scene, model, numVert, vertices );
1798 
1799  if ( verbose >= 2 )
1800  {
1801  for ( i=0; i < numVert; i++ )
1802  {
1803  fprintf( outStream, "vertices[%d] = %f ", i, vertices[i].x );
1804  fprintf( outStream, "%f %f %f\n", vertices[i].y,
1805  vertices[i].z, vertices[i].w );
1806  }
1807  }
1808 
1809  // allocate indexMap array
1810  // we contruct this array to map from the unique vertices
1811  // array to the redundant cvertices array - it will save
1812  // us from doing repetitive searches later
1813  indexMap = MakeIndexMap( indices, numTri*3, numVert );
1814 
1815  // allocate array of normals
1816  normals = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3);
1817  if ( normals != NULL )
1818  {
1819  // read each control vertex's normals into an array
1820  SAA_ctrlVertexGetNormals( scene, model, numTri*3,
1821  cvertices, normals );
1822  }
1823  else
1824  fprintf( outStream, "Not enough Memory for normals...\n");
1825 
1826  if ( verbose >= 2 )
1827  {
1828  for ( i=0; i<numTri*3; i++ )
1829  fprintf( outStream, "normals[%d] = %f %f %f %f\n", i,
1830  normals[i].x, normals[i].y, normals[i].z, normals[i].w );
1831  }
1832 
1833  int uRepeat, vRepeat;
1834 
1835  // make sure we have textures before we get t-coords
1836  if ( numTexLoc )
1837  {
1838  // allocate arrays for u & v coords
1839  uCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3);
1840  vCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3);
1841 
1842  // read the u & v coords into the arrays
1843  if ( uCoords != NULL && vCoords != NULL)
1844  {
1845  for ( i = 0; i < numTri*numTexLoc*3; i++ )
1846  uCoords[i] = vCoords[i] = 0.0f;
1847 
1848  SAA_ctrlVertexGetUVTxtCoords( scene, model, numTri*3,
1849  cvertices, numTexLoc*3, uCoords, vCoords );
1850  }
1851  else
1852  fprintf( outStream, "Not enough Memory for texture coords...\n");
1853 
1854  if ( verbose >= 2 )
1855  {
1856  for ( i=0; i<numTexLoc*3; i++ )
1857  fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i,
1858  uCoords[i], vCoords[i] );
1859  }
1860 
1861  // allocate arrays of texture info
1862  uScale = ( float *)malloc(sizeof(float)*numTri);
1863  vScale = ( float *)malloc(sizeof(float)*numTri);
1864  uOffset = ( float *)malloc(sizeof(float)*numTri);
1865  vOffset = ( float *)malloc(sizeof(float)*numTri);
1866  texNameArray = ( char **)malloc(sizeof(char *)*numTri);
1867 
1868  for ( i = 0; i < numTri; i++ )
1869  {
1870  // initialize the array value
1871  texNameArray[i] = NULL;
1872 
1873  SAA_Boolean valid = FALSE;
1874  // check to see if texture is present
1875  result = SAA_elementIsValid( scene, &textures[i], &valid );
1876 
1877  if ( result != SI_SUCCESS )
1878  fprintf( outStream, "SAA_elementIsValid failed!!!!\n" );
1879 
1880  // texture present - get the name and uv info
1881  if ( valid )
1882  {
1883  texNameArray[i] = ConvertTexture( scene, &textures[i] );
1884 
1885  if ( verbose >= 2 )
1886  fprintf( outStream, " tritex[%d] named: %s\n", i,
1887  texNameArray[i] );
1888 
1889  SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap );
1890 
1891  if ( verbose >= 2 )
1892  if ( uv_swap == TRUE )
1893  fprintf( outStream, " swapping u and v...\n" );
1894 
1895  SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] );
1896  SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] );
1897  SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] );
1898  SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] );
1899 
1900  if ( verbose >= 2 )
1901  {
1902  fprintf(outStream, "tritex[%d] uScale: %f vScale: %f\n", i, uScale[i], vScale[i] );
1903  fprintf(outStream, " uOffset: %f vOffset: %f\n",
1904  uOffset[i], vOffset[i] );
1905  }
1906 
1907 
1908  SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat,
1909  &vRepeat );
1910 
1911  if ( verbose >= 2 )
1912  {
1913  fprintf(outStream, "uRepeat = %d, vRepeat = %d\n",
1914  uRepeat, vRepeat );
1915  }
1916  }
1917  else
1918  {
1919  if ( verbose >= 2 )
1920  {
1921  fprintf( outStream, "Invalid texture...\n");
1922  fprintf( outStream, " tritex[%d] named: (null)\n", i );
1923  }
1924  }
1925  }
1926 
1927  //debug
1928  //for ( i = 0; i < numTri; i++ )
1929  //{
1930  //if ( texNameArray[i] != NULL )
1931  //fprintf( outStream, " tritex[%d] named: %s\n", i,
1932  //texNameArray[i] );
1933  //else
1934  //fprintf( outStream, " tritex[%d] named: (null)\n", i );
1935  //}
1936  }
1937  // make sure we have textures before we get t-coords
1938  else if ( numTexGlb )
1939  {
1940  SAA_Boolean valid;
1941 
1942  // check to see if texture is present
1943  SAA_elementIsValid( scene, textures, &valid );
1944 
1945  // texture present - get the name and uv info
1946  if ( valid )
1947  {
1948  SAA_texture2DGetUVSwap( scene, textures, &uv_swap );
1949 
1950  if ( verbose >= 1 )
1951  if ( uv_swap == TRUE )
1952  fprintf( outStream, " swapping u and v...\n" );
1953 
1954  // allocate arrays for u & v coords
1955  uCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3);
1956  vCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3);
1957 
1958  for ( i = 0; i < numTri*numTexGlb*3; i++ )
1959  {
1960  uCoords[i] = vCoords[i] = 0.0f;
1961  }
1962 
1963  // read the u & v coords into the arrays
1964  if ( uCoords != NULL && vCoords != NULL)
1965  {
1966  SAA_triCtrlVertexGetGlobalUVTxtCoords( scene, model,
1967  numTri*3, cvertices, numTexGlb, textures,
1968  uCoords, vCoords );
1969  }
1970  else
1971  fprintf( outStream, "Not enough Memory for texture coords...\n");
1972 
1973  if ( verbose >= 2 )
1974  {
1975  for ( i=0; i<numTri*numTexGlb*3; i++ )
1976  fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i,
1977  uCoords[i], vCoords[i] );
1978  }
1979 
1980  texNameArray = ( char **)malloc(sizeof(char *));
1981  *texNameArray = ConvertTexture( scene, textures );
1982 
1983  if ( verbose >= 1 )
1984  fprintf( outStream, " global tex named: %s\n",
1985  texNameArray );
1986 
1987  // allocate arrays of texture info
1988  uScale = ( float *)malloc(sizeof(float));
1989  vScale = ( float *)malloc(sizeof(float));
1990  uOffset = ( float *)malloc(sizeof(float));
1991  vOffset = ( float *)malloc(sizeof(float));
1992 
1993  SAA_texture2DGetUScale( scene, textures, uScale );
1994  SAA_texture2DGetVScale( scene, textures, vScale );
1995  SAA_texture2DGetUOffset( scene, textures, uOffset );
1996  SAA_texture2DGetVOffset( scene, textures, vOffset );
1997 
1998  if ( verbose >= 1 )
1999  {
2000  fprintf( outStream, " global tex uScale: %f vScale: %f\n",
2001  *uScale, *vScale );
2002  fprintf( outStream, " uOffset: %f vOffset: %f\n",
2003  *uOffset, *vOffset );
2004  }
2005 
2006  SAA_texture2DGetRepeats( scene, textures, &uRepeat,
2007  &vRepeat );
2008 
2009  if ( verbose >= 2 )
2010  {
2011  fprintf(outStream, "uRepeat = %d, vRepeat = %d\n",
2012  uRepeat, vRepeat );
2013  }
2014  }
2015  else fprintf( outStream, "Invalid texture...\n");
2016  }
2017 
2018  // make the egg vertex pool
2019  EggVertexPool *pool = _data.CreateVertexPool( parent, name );
2020 
2021  for ( i = 0; i < numVert; i++ )
2022  {
2023  pfVec3 eggVert;
2024  pfVec3 eggNorm;
2025 
2026  //convert to global coords
2027  SAA_DVector local = vertices[i];
2028  SAA_DVector global;
2029 
2030  _VCT_X_MAT( global, local, matrix );
2031 
2032  // set vertices array to reflect global coords
2033  //vertices[i].x = global.x;
2034  //vertices[i].y = global.y;
2035  //vertices[i].z = global.z;
2036 
2037  //eggVert.set( vertices[i].x, vertices[i].y, vertices[i].z );
2038 
2039  // we'll preserve original verts for now
2040  eggVert.set( global.x, global.y, global.z );
2041 
2042  local = normals[indexMap[i]];
2043 
2044  _VCT_X_MAT( global, local, matrix );
2045 
2046  eggNorm.set( global.x, global.y, global.z );
2047  eggNorm.normalize();
2048 
2049  pool->AddVertex( eggVert, i );
2050  pool->Vertex(i)->attrib.SetNormal( eggNorm );
2051 
2052  // translate local uv's to global and add to vertex pool
2053  if ( numTexLoc && (uCoords != NULL && vCoords !=NULL ))
2054  {
2055  float u, v;
2056 
2057  if ( ignore_tex_offsets ) {
2058  u = uCoords[indexMap[i]];
2059  v = 1.0f - vCoords[indexMap[i]];
2060  } else {
2061  u = (uCoords[indexMap[i]] - uOffset[indexMap[i]/3]) /
2062  uScale[indexMap[i]/3];
2063 
2064  v = 1.0f - ((vCoords[indexMap[i]] - vOffset[indexMap[i]/3]) /
2065  vScale[indexMap[i]/3]);
2066  }
2067 
2068  if ( isNum(u) && isNum(v) )
2069  {
2070  if ( uv_swap == TRUE )
2071  pool->Vertex(i)->attrib.SetUV( v, u );
2072  else
2073  pool->Vertex(i)->attrib.SetUV( u, v );
2074  }
2075  }
2076  else if ( numTexGlb && (uCoords != NULL && vCoords !=NULL ) )
2077  {
2078  float u, v;
2079 
2080  if ( ignore_tex_offsets ) {
2081  u = uCoords[indexMap[i]];
2082  v = 1.0f - vCoords[indexMap[i]];
2083  } else {
2084  u = (uCoords[indexMap[i]] - *uOffset) / *uScale;
2085  v = 1.0f - (( vCoords[indexMap[i]] - *vOffset ) / *vScale);
2086  }
2087 
2088  if ( isNum(u) && isNum(v) )
2089  {
2090  if ( uv_swap == TRUE )
2091  pool->Vertex(i)->attrib.SetUV( v, u );
2092  else
2093  pool->Vertex(i)->attrib.SetUV( u, v );
2094  }
2095 
2096  }
2097 
2098  // if we've encountered textures and we desire duv anims
2099  if (( numTexLoc || numTexGlb ) && make_duv )
2100  {
2101  int numExp;
2102  SAA_Elem *tex;
2103 
2104  // grab the current texture
2105  if ( numTexLoc )
2106  tex = &textures[0];
2107  else
2108  tex = textures;
2109 
2110  // find how many expressions for this shape
2111  SAA_elementGetNbExpressions( scene, tex, NULL, FALSE,
2112  &numExp );
2113 
2114  // if it has expressions we'll assume its animated
2115  if ( numExp )
2116  {
2117  // if animated object make base duv's, animtables
2118  // for the duv's and store the original offsets
2119  strstream uName, vName;
2120 
2121  // create duv target names
2122  uName << name << ".u" << ends;
2123  vName << name << ".v" << ends;
2124 
2125  // only create tables and store offsets
2126  // on a per model basis (not per vertex)
2127  if ( !i )
2128  {
2129 
2130  // make sure root morph table exists
2131  if ( morphRoot == NULL )
2132  morphRoot = animData.CreateTable( animRoot,
2133  "morph" );
2134 
2135  // create morph table entry for each duv
2136  SAnimTable *uTable = new SAnimTable( );
2137  uTable->name = uName.str();
2138  uTable->fps = anim_rate;
2139  morphRoot->children.push_back( uTable );
2140  if ( verbose >= 1 )
2141  fprintf( outStream, "created duv table named: %s\n", uName.str() );
2142 
2143  SAnimTable *vTable = new SAnimTable( );
2144  vTable->name = vName.str();
2145  vTable->fps = anim_rate;
2146  morphRoot->children.push_back( vTable );
2147  if ( verbose >= 1 )
2148  fprintf( outStream, "created duv table named: %s\n", vName.str() );
2149 
2150  float texOffsets[4];
2151 
2152  if ( numTexGlb )
2153  {
2154  texOffsets[0] = *uOffset;
2155  texOffsets[1] = *vOffset;
2156  texOffsets[2] = *uScale;
2157  texOffsets[3] = *vScale;
2158  }
2159  else
2160  {
2161  texOffsets[0] = uOffset[indexMap[i]/3];
2162  texOffsets[1] = vOffset[indexMap[i]/3];
2163  texOffsets[2] = uScale[indexMap[i]/3];
2164  texOffsets[3] = vScale[indexMap[i]/3];
2165  }
2166 
2167  // remember original texture offsets future reference
2168  SAA_elementSetUserData( scene, model, "TEX_OFFSETS",
2169  sizeof( texOffsets ), TRUE, (void **)&texOffsets );
2170  }
2171 
2172  EggMorphOffset *duvU;
2173  EggMorphOffset *duvV;
2174 
2175  // generate base duv's for this vertex
2176  duvU = new EggMorphOffset( uName.str(), 1.0 , 0.0 );
2177  pool->Vertex(i)->attrib.uv_morphs.push_back( *duvU );
2178 
2179  duvV = new EggMorphOffset( vName.str(), 0.0 , 1.0 );
2180  pool->Vertex(i)->attrib.uv_morphs.push_back( *duvV );
2181 
2182  } // if ( numExp )
2183 
2184  } // if ( numTexLoc || numTexGlb )
2185 
2186  } // for ( i = 0; i < numVert; i++ )
2187 
2188  // if model has key shapes, generate vertex offsets
2189  if ( has_morph && make_morph )
2190  MakeVertexOffsets( scene, model, type, numShapes, numVert,
2191  vertices, matrix, name );
2192 
2193 
2194  // create vertex ref list for all polygons in the model
2195  EggVertexRef *vref;
2196 
2197  vref = new EggVertexRef( pool);
2198  for ( i = 0; i < numVert; i++ )
2199  {
2200  //add each vert in pool to last joint for hard skinning
2201  vref->indices.push_back( EggVertexIndex( i ) );
2202  }
2203 
2204  // hard assign poly geometry if no soft-skinning requested
2205  //
2206  //disabled 1/1/99 to streamline joint assignments.
2207  // all hard-skinning now done in CleanUpSoftSkin.
2208  //if ( !make_soft )
2209  //{
2210  //if ( lastJoint != NULL )
2211  //{
2212  //lastJoint->vrefs.AddUniqueNode( *vref );
2213 
2214  //if ( verbose >= 1 )
2215  //fprintf( outStream, "hard-skinning %s (%d vertices)\n",
2216  //name, i+1 );
2217  //}
2218  //}
2219 
2220  // make an egg group to hold all triangles
2221  EggGroup *group = _data.CreateGroup( parent, name);
2222 
2223  // make this group the current parent
2224  parent = group;
2225 
2226  EggPolygon *poly = NULL;
2227  EggColor *cref = NULL;
2228  EggTexture *tref = NULL;
2229 
2230  // for each triangle
2231  for ( i = 0; i < numTri*3; i+=3 )
2232  {
2233  float r,g,b,a;
2234  pfVec4 color;
2235 
2236  // make egg poly for each traingle and reference
2237  // the appropriate vertex in the pool
2238  poly = _data.CreatePolygon( group, pool );
2239  poly->AddVertex(indices[i]);
2240  poly->AddVertex(indices[i+1]);
2241  poly->AddVertex(indices[i+2]);
2242 
2243  // check for back face flag in model note info
2244  char *modelNoteStr = GetModelNoteInfo( scene, model );
2245 
2246  if ( modelNoteStr != NULL )
2247  {
2248  if ( strstr( modelNoteStr, "bface" ) != NULL )
2249  poly->flags |= EG_BFACE;
2250  }
2251 
2252  // check to see if material is present
2253  SAA_Boolean valid;
2254  SAA_elementIsValid( scene, &materials[i/3], &valid );
2255 
2256  // material present - get the color
2257  if ( valid )
2258  {
2259  SAA_materialGetDiffuse( scene, &materials[i/3], &r, &g, &b );
2260  SAA_materialGetTransparency( scene, &materials[i/3], &a );
2261  color.set( r, g, b, 1.0f - a );
2262  }
2263  // no material - default to white
2264  else
2265  color.set( 1.0, 1.0, 1.0, 1.0 );
2266 
2267  cref = _data.CreateColor(color);
2268  poly->attrib.SetCRef(cref);
2269 
2270  strstream uniqueTexName;
2271 
2272  if (numTexLoc)
2273  {
2274  // polytex
2275  if ( (texNameArray[i/3] != NULL) &&
2276  (strcmp(texNameArray[i/3], "NULL") != 0) )
2277  {
2278  // append unique identifier to texname for
2279  // this particular object
2280  uniqueTexName << name << "-"
2281  << RemovePathName(texNameArray[i/3]);
2282 
2283  tref = _data.CreateTexture( texNameArray[i/3],
2284  uniqueTexName.str() );
2285 
2286  if ( verbose >= 1 )
2287  fprintf( outStream, " tritex[%d] named: %s\n", i/3,
2288  texNameArray[i/3] );
2289  }
2290  }
2291  else if ( numTexGlb )
2292  {
2293  if ( texNameArray != NULL )
2294  {
2295  // append unique identifier to texname for
2296  // this particular object
2297  uniqueTexName << name << "-"
2298  << RemovePathName(*texNameArray);
2299 
2300  tref = _data.CreateTexture( *texNameArray,
2301  uniqueTexName.str() );
2302 
2303  if ( verbose >= 1 )
2304  fprintf( outStream, " tritex named: %s\n",
2305  *texNameArray );
2306  }
2307  }
2308 
2309  // set the clamp on the texture
2310  if ( tref != NULL )
2311  {
2312  if ( uRepeat > 0 )
2313  tref->wrapu = EggTexture::WM_repeat;
2314  else
2315  tref->wrapu = EggTexture::WM_clamp;
2316 
2317  if ( vRepeat > 1 )
2318  tref->wrapv = EggTexture::WM_repeat;
2319  else
2320  tref->wrapv = EggTexture::WM_clamp;
2321 
2322  poly->attrib.SetTRef(tref);
2323  }
2324 
2325  }
2326 
2327  // we're done - trash triangles...
2328  SAA_modelClearTriangles( scene, model );
2329 
2330  // free molloc'd memory
2331  //free( triangles );
2332  //free( materials );
2333  //free( normals );
2334  //free( cvertices );
2335  //free( vertices );
2336  //free( indices );
2337  //free( indexMap );
2338 
2339  // free these only if they were malloc'd for textures
2340  if (numTexLoc || numTexGlb)
2341  {
2342  //free( textures );
2343  //free( uCoords );
2344  //free( vCoords );
2345  //free( texNameArray );
2346  //free( uScale );
2347  //free( vScale );
2348  //free( uOffset );
2349  //free( vOffset );
2350  }
2351  }
2352  }
2353  else
2354  {
2355  ///////////////////////////////////////
2356  // check to see if its a nurbs surface
2357  ///////////////////////////////////////
2358  if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs )
2359  || ( !make_nurbs && !make_poly && make_duv )) )
2360  {
2361  // check to see if NURBS is also skeleton...
2362  SAA_Boolean isSkeleton = FALSE;
2363 
2364  SAA_modelIsSkeleton( scene, model, &isSkeleton );
2365 
2366  // check to see if this NURBS is used as a skeleton
2367  // or is animated via constraint only ( these nodes are
2368  // tagged by the animator with the keyword "joint"
2369  // somewhere in the nodes name)
2370  if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
2371  {
2372  MakeJoint( scene, lastJoint, lastAnim, model, name );
2373  geom_as_joint = 1;
2374  if ( verbose >= 1 )
2375  fprintf( outStream, "animating NURBS as joint!!!\n" );
2376  }
2377 
2378  EggNurbsSurface *eggNurbsSurf = new EggNurbsSurface( name );
2379  int uDegree, vDegree;
2380 
2381  // create nurbs representation of surface
2382  SAA_nurbsSurfaceGetDegree( scene, model, &uDegree, &vDegree );
2383  eggNurbsSurf->u_order = uDegree + 1;
2384  eggNurbsSurf->v_order = vDegree + 1;
2385  if ( verbose >= 1 )
2386  {
2387  fprintf( outStream, "nurbs degree: %d u, %d v\n",
2388  uDegree, vDegree );
2389  fprintf( outStream, "nurbs order: %d u, %d v\n",
2390  uDegree + 1, vDegree + 1 );
2391  }
2392 
2393  SAA_Boolean uClosed = FALSE;
2394  SAA_Boolean vClosed = FALSE;
2395 
2396  SAA_nurbsSurfaceGetClosed( scene, model, &uClosed, &vClosed);
2397 
2398  if ( verbose >= 1 )
2399  {
2400  if ( uClosed )
2401  fprintf( outStream, "nurbs is closed in u...\n");
2402  if ( vClosed )
2403  fprintf( outStream, "nurbs is closed in v...\n");
2404  }
2405 
2406  int uRows, vRows;
2407  SAA_nurbsSurfaceGetNbVertices( scene, model, &uRows, &vRows );
2408  if ( verbose >= 1 )
2409  fprintf( outStream, "nurbs vertices: %d u, %d v\n",
2410  uRows, vRows );
2411 
2412  int uCurves, vCurves;
2413  SAA_nurbsSurfaceGetNbCurves( scene, model, &uCurves, &vCurves );
2414  if ( verbose >= 1 )
2415  fprintf( outStream, "nurbs curves: %d u, %d v\n",
2416  uCurves, vCurves );
2417 
2418  if ( shift_textures )
2419  {
2420  if ( uClosed )
2421  // shift starting point on NURBS surface for correct textures
2422  SAA_nurbsSurfaceShiftParameterization( scene, model, -2, 0 );
2423 
2424  if ( vClosed )
2425  // shift starting point on NURBS surface for correct textures
2426  SAA_nurbsSurfaceShiftParameterization( scene, model, 0, -2 );
2427  }
2428 
2429  SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
2430 
2431  // check for back face flag in model note info
2432  char *modelNoteStr = GetModelNoteInfo( scene, model );
2433 
2434  if ( modelNoteStr != NULL )
2435  {
2436  if ( strstr( modelNoteStr, "bface" ) != NULL )
2437  eggNurbsSurf->flags |= EG_BFACE;
2438  }
2439 
2440  int numKnotsU, numKnotsV;
2441 
2442  SAA_nurbsSurfaceGetNbKnots( scene, model, &numKnotsU, &numKnotsV );
2443  if ( verbose >= 1 )
2444  fprintf( outStream, "nurbs knots: %d u, %d v\n",
2445  numKnotsU, numKnotsV );
2446 
2447  double *knotsU, *knotsV;
2448  knotsU = (double *)malloc(sizeof(double)*numKnotsU);
2449  knotsV = (double *)malloc(sizeof(double)*numKnotsV);
2450  SAA_nurbsSurfaceGetKnots( scene, model, gtype, 0,
2451  numKnotsU, numKnotsV, knotsU, knotsV );
2452 
2453  if ( verbose >= 2 )
2454  fprintf( outStream, "u knots:\n" );
2455 
2456  AddKnots( eggNurbsSurf->u_knots, knotsU, numKnotsU, uClosed, uDegree );
2457  if ( verbose >= 2 )
2458  fprintf( outStream, "v knots:\n" );
2459 
2460  AddKnots( eggNurbsSurf->v_knots, knotsV, numKnotsV, vClosed, vDegree);
2461 
2462  //free( knotsU );
2463  //free( knotsV );
2464 
2465  // set sub_div so we can see it in perfly
2466  eggNurbsSurf->u_subdiv = (uRows-1)*nurbs_step;
2467  eggNurbsSurf->v_subdiv = (vRows-1)*nurbs_step;
2468 
2469  SAA_modelGetNbVertices( scene, model, &numVert );
2470 
2471  if ( verbose >= 2 )
2472  fprintf( outStream, "%d CV's\n", numVert );
2473 
2474  // get the CV's
2475  vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert);
2476  SAA_modelGetVertices( scene, model, gtype, 0,
2477  numVert, vertices );
2478 
2479  // create pool of NURBS vertices
2480  EggVertexPool *pool = _data.CreateVertexPool( parent, name );
2481  eggNurbsSurf->SetVertexPool( pool );
2482 
2483  // create vertex ref list for all cv's in the model
2484  EggVertexRef *vref;
2485 
2486  vref = new EggVertexRef( pool);
2487 
2488  for ( int k = 0; k<numVert; k++ )
2489  {
2490  if ( verbose >= 2 )
2491  {
2492  fprintf( outStream, "original cv[%d] = %f %f %f %f\n", k,
2493  vertices[k].x, vertices[k].y, vertices[k].z,
2494  vertices[k].w );
2495  }
2496 
2497  pfVec4 eggVert;
2498 
2499  // convert to global coords
2500  SAA_DVector global;
2501 
2502  _VCT_X_MAT( global, vertices[k], matrix );
2503 
2504  //preserve original weight
2505  global.w = vertices[k].w;
2506 
2507  // normalize coords to weight
2508  global.x *= global.w;
2509  global.y *= global.w;
2510  global.z *= global.w;
2511 
2512  // this code is commented out because I
2513  // am no longer sending global data to
2514  // the other routines (ie makevertexoffset)
2515 
2516  // set vertices array to reflect global coords
2517  //vertices[k].x = global.x;
2518  //vertices[k].y = global.y;
2519  //vertices[k].z = global.z;
2520  //vertices[k].w = global.w;
2521 
2522  //if ( verbose >= 2 )
2523  //{
2524  //fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k,
2525  //vertices[k].x, vertices[k].y, vertices[k].z,
2526  //vertices[k].w );
2527  //}
2528 
2529  //eggVert.set( vertices[k].x, vertices[k].y, vertices[k].z,
2530  //vertices[k].w );
2531 
2532  if ( verbose >= 2 )
2533  {
2534  fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k,
2535  global.x, global.y, global.z,
2536  global.w );
2537  }
2538 
2539  eggVert.set( global.x, global.y, global.z,
2540  global.w );
2541 
2542  // populate vertex pool
2543  pool->AddVertex( eggVert, k );
2544 
2545  // add vref's to NURBS info
2546  eggNurbsSurf->AddVertex( k );
2547 
2548  //add each vert in pool to vref for hard skinning
2549  vref->indices.push_back( EggVertexIndex( k ) );
2550 
2551  // check to see if the NURB is closed in u
2552  if ( uClosed )
2553  {
2554  // add first uDegree verts to end of row
2555  if ( (k % uRows) == ( uRows - 1) )
2556  for ( int i = 0; i < uDegree; i++ )
2557  {
2558  // add vref's to NURBS info
2559  eggNurbsSurf->AddVertex( i+((k/uRows)*uRows) );
2560 
2561  //add each vert to vref
2562  vref->indices.push_back(
2563  EggVertexIndex( i+((k/uRows)*uRows) ) );
2564  }
2565  }
2566  }
2567 
2568  // if hard skinned or this nurb is also a joint
2569  //
2570  //disabled 1/1/99 to streamline joint assignments.
2571  // all hard skinning now done in CleanUpSoftSkin.
2572  //if (!make_soft || geom_as_joint)
2573  //{
2574  //add the new cv references to the last
2575  //joint for hard skinning only
2576  //if ( lastJoint != NULL )
2577  //{
2578  //lastJoint->vrefs.AddUniqueNode( *vref );
2579  //geom_as_joint = 0;
2580  //if ( verbose >= 1 )
2581  //fprintf( outStream, "Doing NURBS hard skinning...\n");
2582  //}
2583  //}
2584 
2585  // check to see if the NURB is closed in v
2586  if ( vClosed && !uClosed )
2587  {
2588  // add first vDegree rows of verts to end of list
2589  for ( int i = 0; i < vDegree*uRows; i++ )
2590  eggNurbsSurf->AddVertex( i );
2591  }
2592  // check to see if the NURB is closed in u and v
2593  else if ( vClosed && uClosed )
2594  {
2595  // add the first (degree) v verts and a few
2596  // extra - for good measure
2597  for ( i = 0; i < vDegree; i++ )
2598  {
2599  // add first vDegree rows of verts to end of list
2600  for ( j = 0; j < uRows; j++ )
2601  eggNurbsSurf->AddVertex( j+(i*uRows) );
2602 
2603  // if u is closed to we have added uDegree
2604  // verts onto the ends of the rows - add them here too
2605  for ( k = 0; k < uDegree; k++ )
2606  eggNurbsSurf->AddVertex( k+(i*uRows)+((k/uRows)*uRows) );
2607  }
2608 
2609  }
2610 
2611  // get the color of the NURBS surface
2612  int numNurbMats;
2613  EggColor *nurbCref;
2614  pfVec4 nurbColor;
2615 
2616  SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo,
2617  &numNurbMats );
2618 
2619  if ( verbose >= 1 )
2620  fprintf( outStream, "nurbs surf has %d materials\n",
2621  numNurbMats );
2622 
2623  if ( numNurbMats )
2624  {
2625  float r,g,b,a;
2626 
2627  materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numNurbMats);
2628 
2629  SAA_modelRelationGetMatElements( scene, model, relinfo,
2630  numNurbMats, materials );
2631 
2632  SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b );
2633  SAA_materialGetTransparency( scene, &materials[0], &a );
2634  nurbColor.set( r, g, b, 1.0f - a );
2635  //nurbColor.set( r, g, b, 1.0 );
2636 
2637  nurbCref = _data.CreateColor(nurbColor);
2638  eggNurbsSurf->attrib.SetCRef(nurbCref);
2639 
2640  //get the texture of the NURBS surface from the material
2641  int numNurbTexLoc = 0;
2642  int numNurbTexGlb = 0;
2643 
2644  // ASSUME only one texture per material
2645  SAA_Elem nurbTex;
2646 
2647  // find out how many local textures per NURBS surface
2648  // ASSUME it only has one material
2649  SAA_materialRelationGetT2DLocNbElements( scene, &materials[0],
2650  FALSE, &relinfo, &numNurbTexLoc );
2651 
2652  // if present, get local textures
2653  if ( numNurbTexLoc )
2654  {
2655  if ( verbose >= 1 )
2656  fprintf( outStream, "%s had %d local tex\n", name,
2657  numNurbTexLoc );
2658 
2659  // get the referenced texture
2660  SAA_materialRelationGetT2DLocElements( scene, &materials[0],
2661  TEX_PER_MAT, &nurbTex );
2662 
2663  }
2664  // if no locals, try to get globals
2665  else
2666  {
2667  SAA_modelRelationGetT2DGlbNbElements( scene, model,
2668  FALSE, &relinfo, &numNurbTexGlb );
2669 
2670  if ( numNurbTexGlb )
2671  {
2672  if ( verbose >= 1 )
2673  fprintf( outStream, "%s had %d global tex\n", name,
2674  numNurbTexGlb );
2675 
2676  // get the referenced texture
2677  SAA_modelRelationGetT2DGlbElements( scene,
2678  model, TEX_PER_MAT, &nurbTex );
2679  }
2680  }
2681 
2682  // add tex ref's if we found any textures
2683  if ( numNurbTexLoc || numNurbTexGlb)
2684  {
2685  char *texName = NULL;
2686  char *uniqueTexName = NULL;
2687  EggTexture *tref;
2688  pfMatrix nurbTexMat;
2689 
2690 
2691  // convert the texture to .rgb and adjust name
2692  texName = ConvertTexture( scene, &nurbTex );
2693 
2694  // append unique identifier to texname for
2695  // this particular object
2696  uniqueTexName = (char *)malloc(sizeof(char)*
2697  (strlen(name)+strlen(texName)+3) );
2698  sprintf( uniqueTexName, "%s-%s", name,
2699  RemovePathName(texName) );
2700 
2701  if ( verbose >= 1 )
2702  {
2703  fprintf( outStream, "creating tref %s\n",
2704  uniqueTexName );
2705  }
2706 
2707  tref = _data.CreateTexture( texName, uniqueTexName );
2708 
2709  uScale = ( float *)malloc(sizeof(float));
2710  vScale = ( float *)malloc(sizeof(float));
2711  uOffset = ( float *)malloc(sizeof(float));
2712  vOffset = ( float *)malloc(sizeof(float));
2713 
2714  // get texture offset info
2715  SAA_texture2DGetUScale( scene, &nurbTex, uScale );
2716  SAA_texture2DGetVScale( scene, &nurbTex, vScale );
2717  SAA_texture2DGetUOffset( scene, &nurbTex, uOffset );
2718  SAA_texture2DGetVOffset( scene, &nurbTex, vOffset );
2719  SAA_texture2DGetUVSwap( scene, &nurbTex, &uv_swap );
2720 
2721 
2722  if ( verbose >= 1 )
2723  {
2724  fprintf( outStream, "nurbTex uScale: %f\n", *uScale );
2725  fprintf( outStream, "nurbTex vScale: %f\n", *vScale );
2726  fprintf( outStream, "nurbTex uOffset: %f\n", *uOffset );
2727  fprintf( outStream, "nurbTex vOffset: %f\n", *vOffset );
2728  if ( uv_swap )
2729  fprintf( outStream, "nurbTex u & v swapped!\n" );
2730  else
2731  fprintf( outStream, "nurbTex u & v NOT swapped\n" );
2732  }
2733 
2734  nurbTexMat.makeIdent();
2735 
2736  if ( !ignore_tex_offsets )
2737  {
2738  if ( uv_swap )
2739  {
2740  nurbTexMat[0][0] = 0.0f;
2741  nurbTexMat[1][1] = 0.0f;
2742  nurbTexMat[0][1] = 1 / *vScale;
2743  nurbTexMat[1][0] = 1 / *uScale;
2744  nurbTexMat[2][1] = -(*uOffset / *uScale);
2745  nurbTexMat[2][0] = -(*vOffset / *vScale);
2746  }
2747  else
2748  {
2749  nurbTexMat[0][0] = 1 / *uScale;
2750  nurbTexMat[1][1] = 1 / *vScale;
2751  nurbTexMat[2][0] = -(*uOffset / *uScale);
2752  nurbTexMat[2][1] = -(*vOffset / *vScale);
2753  }
2754  }
2755 
2756 
2757  //call printMat
2758  if ( verbose >= 2 )
2759  {
2760  fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[0][0],
2761  nurbTexMat[0][1], nurbTexMat[0][2], nurbTexMat[0][3] );
2762  fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[1][0],
2763  nurbTexMat[1][1], nurbTexMat[1][2], nurbTexMat[1][3] );
2764  fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[2][0],
2765  nurbTexMat[2][1], nurbTexMat[2][2], nurbTexMat[2][3] );
2766  fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[3][0],
2767  nurbTexMat[3][1], nurbTexMat[3][2], nurbTexMat[3][3] );
2768  }
2769 
2770 
2771  tref->tex_mat = nurbTexMat;
2772  tref->flags |= EFT_TRANSFORM;
2773 
2774  eggNurbsSurf->attrib.SetTRef(tref);
2775 
2776  }
2777 
2778  // if we've encountered textures and we desire duv anims
2779  if (( numNurbTexLoc || numNurbTexGlb ) && make_duv )
2780  {
2781  int numExp;
2782 
2783  // find how many expressions for this shape
2784  SAA_elementGetNbExpressions( scene, &nurbTex, NULL, FALSE,
2785  &numExp );
2786 
2787  // if it has expressions we'll assume its animated
2788  if ( numExp )
2789  {
2790  if ( verbose > 1 )
2791  printf( "nurbTex has %d expressions...\n", numExp );
2792 
2793  // if animated object make base duv's, animtables
2794  // for the duv's and store the original offsets
2795  strstream uName, vName;
2796 
2797  // create duv target names
2798  uName << name << ".u" << ends;
2799  vName << name << ".v" << ends;
2800 
2801  // make sure root morph table exists
2802  if ( morphRoot == NULL )
2803  morphRoot = animData.CreateTable( animRoot,
2804  "morph" );
2805 
2806  // create morph table entry for each duv
2807  SAnimTable *uTable = new SAnimTable( );
2808  uTable->name = uName.str();
2809  uTable->fps = anim_rate;
2810  morphRoot->children.push_back( uTable );
2811  if ( verbose >= 1 )
2812  fprintf( outStream, "created duv table named: %s\n", uName.str() );
2813 
2814  SAnimTable *vTable = new SAnimTable( );
2815  vTable->name = vName.str();
2816  vTable->fps = anim_rate;
2817  morphRoot->children.push_back( vTable );
2818  if ( verbose >= 1 )
2819  fprintf( outStream, "created duv table named: %s\n", vName.str() );
2820 
2821  float texOffsets[4];
2822 
2823  texOffsets[0] = *uOffset;
2824  texOffsets[1] = *vOffset;
2825  texOffsets[2] = *uScale;
2826  texOffsets[3] = *vScale;
2827 
2828  // remember original texture offsets future reference
2829  SAA_elementSetUserData( scene, model, "TEX_OFFSETS",
2830  sizeof( texOffsets ), TRUE, (void **)&texOffsets );
2831 
2832  // create UV's and duv's for each vertex
2833  for( i = 0; i < numVert; i++ )
2834  {
2835  pfVec2 tmpUV;
2836  EggMorphOffset *duvU;
2837  EggMorphOffset *duvV;
2838 
2839  //create uv's so we can store duv's
2840  eggNurbsSurf->CalcActualUV( i, tmpUV );
2841  pool->Vertex(i)->attrib.SetUV( tmpUV[0], tmpUV[1] );
2842 
2843  // generate base duv's for this vertex
2844  duvU = new EggMorphOffset(uName.str(), 1.0 , 0.0);
2845  pool->Vertex(i)->attrib.uv_morphs.push_back(*duvU);
2846 
2847  duvV = new EggMorphOffset(vName.str(), 0.0 , 1.0);
2848  pool->Vertex(i)->attrib.uv_morphs.push_back(*duvV);
2849  }
2850 
2851  } // if ( numExp )
2852  } // if ( numTexLoc || numTexGlb )
2853 
2854  //free( uScale );
2855  //free( vScale );
2856  //free( uOffset );
2857  //free( vOffset );
2858 
2859  //free( materials );
2860  }
2861  else
2862  {
2863  // no material present - default to white
2864  nurbColor.set( 1.0, 1.0, 1.0, 1.0 );
2865  }
2866 
2867  //////////////////////////////////////////
2868  // check NURBS surface for trim curves
2869  //////////////////////////////////////////
2870  int numTrims;
2871  bool isTrim = TRUE;
2872  SAA_SubElem *trims;
2873 
2874  SAA_nurbsSurfaceGetNbTrimCurves( scene, model, SAA_TRIMTYPE_TRIM,
2875  &numTrims );
2876 
2877  if ( verbose >= 1 )
2878  fprintf( outStream, "nurbs surf has %d trim curves\n",
2879  numTrims );
2880 
2881  if ( numTrims)
2882  {
2883  trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims);
2884 
2885  if ( trims )
2886  {
2887  SAA_nurbsSurfaceGetTrimCurves( scene, model,
2888  gtype, 0, SAA_TRIMTYPE_TRIM, numTrims,
2889  trims );
2890 
2891  MakeSurfaceCurve( scene, model, parent, eggNurbsSurf,
2892  numTrims, trims, isTrim );
2893  }
2894 
2895  //free( trims );
2896  }
2897 
2898  //////////////////////////////////////////
2899  // check NURBS surface for surface curves
2900  //////////////////////////////////////////
2901  isTrim = FALSE;
2902 
2903  SAA_nurbsSurfaceGetNbTrimCurves( scene, model,
2904  SAA_TRIMTYPE_PROJECTION, &numTrims );
2905 
2906  if ( verbose >= 1 )
2907  fprintf( outStream, "nurbs surf has %d surface curves\n",
2908  numTrims );
2909 
2910  if ( numTrims)
2911  {
2912  trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims);
2913 
2914  if ( trims )
2915  {
2916  SAA_nurbsSurfaceGetTrimCurves( scene, model,
2917  gtype, 0, SAA_TRIMTYPE_PROJECTION,
2918  numTrims, trims );
2919 
2920  MakeSurfaceCurve( scene, model, parent, eggNurbsSurf,
2921  numTrims, trims, isTrim );
2922  }
2923 
2924  //free( trims );
2925  }
2926 
2927  // push the NURBS into the egg data
2928  parent->children.push_back( eggNurbsSurf );
2929 
2930  // if model has key shapes, generate vertex offsets
2931  if ( has_morph && make_morph )
2932  MakeVertexOffsets( scene, model, type, numShapes, numVert,
2933  vertices, matrix, name );
2934 
2935 
2936  //free( vertices );
2937 
2938  }
2939  /////////////////////////////////////
2940  // check to see if its a NURBS curve
2941  /////////////////////////////////////
2942  else if ( (type == SAA_MNCRV) && ( visible ) && ( make_nurbs ) )
2943  {
2944  // ignore for now
2945  // make the NURBS curve and push it into the egg data
2946  //parent->children.push_back( MakeNurbsCurve( scene, model, parent,
2947  //matrix, name ) );
2948  }
2949  else if ( type == SAA_MJNT )
2950  {
2951  MakeJoint( scene, lastJoint, lastAnim, model, name );
2952  if ( verbose >= 1 )
2953  fprintf( outStream, "encountered IK joint: %s\n", name );
2954  }
2955  /////////////////////
2956  // it must be a NULL
2957  /////////////////////
2958  else
2959  {
2960  SAA_AlgorithmType algo;
2961 
2962  SAA_modelGetAlgorithm( scene, model, &algo );
2963  if ( verbose >= 1 )
2964  fprintf( outStream, "null algorithm: %d\n", algo );
2965 
2966  if ( algo == SAA_ALG_INV_KIN )
2967  {
2968  MakeJoint( scene, lastJoint, lastAnim, model, name );
2969  if ( verbose >= 1 )
2970  fprintf( outStream, "encountered IK root: %s\n", name );
2971  }
2972  else if ( algo == SAA_ALG_INV_KIN_LEAF )
2973  {
2974  MakeJoint( scene, lastJoint, lastAnim, model, name );
2975  if ( verbose >= 1 )
2976  fprintf( outStream, "encountered IK leaf: %s\n", name );
2977  }
2978  else if ( algo == SAA_ALG_STANDARD )
2979  {
2980  SAA_Boolean isSkeleton = FALSE;
2981 
2982  if ( verbose >= 1 )
2983  fprintf( outStream, "encountered Standard null: %s\n", name);
2984 
2985  SAA_modelIsSkeleton( scene, model, &isSkeleton );
2986 
2987  // check to see if this NULL is used as a skeleton
2988  // or is animated via constraint only ( these nodes are
2989  // tagged by the animator with the keyword "joint"
2990  // somewhere in the nodes name)
2991  if ( isSkeleton || (strstr( name, "joint" ) != NULL) )
2992  {
2993  MakeJoint( scene, lastJoint, lastAnim, model, name );
2994  if ( verbose >= 1 )
2995  fprintf( outStream, "animating Standard null!!!\n" );
2996  }
2997 
2998  }
2999  else
3000  if ( verbose >= 1 )
3001  fprintf( outStream, "encountered some other NULL: %d\n",
3002  algo );
3003  }
3004  }
3005 
3006 
3007  // check for children...
3008  int numChildren;
3009  int thisChild;
3010  SAA_Elem *children;
3011 
3012  SAA_modelGetNbChildren( scene, model, &numChildren );
3013  if ( verbose >= 1 )
3014  fprintf( outStream, "Model children: %d\n", numChildren );
3015 
3016  if ( numChildren )
3017  {
3018  children = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numChildren);
3019  SAA_modelGetChildren( scene, model, numChildren, children );
3020  if ( children != NULL )
3021  {
3022  for ( thisChild = 0; thisChild < numChildren; thisChild++ )
3023  {
3024  if ( verbose >= 1 )
3025  fprintf( outStream, "\negging child %d...\n", thisChild);
3026  MakeEgg( parent, lastJoint, lastAnim, scene,
3027  &children[thisChild] );
3028  }
3029  }
3030  else
3031  fprintf( outStream, "Not enough Memory for children...\n");
3032  //free( children );
3033  }
3034  fflush( outStream );
3035  }
3036  else
3037  if ( verbose >= 1 )
3038  fprintf( outStream, "Don't descend this branch!\n" );
3039 
3040  // we are done for the most part - start cleaning up memory
3041  //free( name );
3042 }
3043 
3044 
3045 ////////////////////////////////////////////////////////////////////
3046 // Function: MakeSurfaceCurve
3047 // Access: Public
3048 // Description: Given a scene and lists of u and v samples create a
3049 // an egg NURBS curve of degree two from the samples
3050 ////////////////////////////////////////////////////////////////////
3051 void soft2egg::
3052 MakeSurfaceCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent,
3053  EggNurbsSurface *&nurbsSurf, int numTrims, SAA_SubElem *trims,
3054  bool isTrim )
3055 {
3056  int i;
3057  long totalSamples = 0;
3058  long *numSamples;
3059  double *uSamples;
3060  double *vSamples;
3061  SAA_Elem *trimCurves;
3062  char *name;
3063 
3064  //get UV coord data
3065  numSamples = (long *)malloc(sizeof(long)*numTrims);
3066 
3067  SAA_surfaceCurveGetNbLinearSamples( scene, model, numTrims, trims,
3068  numSamples );
3069 
3070  for ( i = 0; i < numTrims; i++ )
3071  {
3072  totalSamples += numSamples[i];
3073  if ( verbose >= 2 )
3074  fprintf( outStream, "numSamples[%d] = %d\n", i, numSamples[i] );
3075  }
3076 
3077  if ( verbose >= 2 )
3078  fprintf( outStream, "total samples = %ld\n", totalSamples );
3079 
3080  uSamples = (double *)malloc(sizeof(double)*totalSamples);
3081  vSamples = (double *)malloc(sizeof(double)*totalSamples);
3082 
3083  SAA_surfaceCurveGetLinearSamples( scene, model, numTrims, trims,
3084  numSamples, uSamples, vSamples );
3085 
3086  if ( verbose >= 2 )
3087  for ( long li = 0; li < totalSamples; li++ )
3088  fprintf( outStream, "master list cv[%ld] = %f, %f\n", li,
3089  uSamples[li], vSamples[li] );
3090 
3091  trimCurves = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTrims);
3092 
3093  SAA_surfaceCurveExtract( scene, model, numTrims, trims, trimCurves );
3094 
3095  // if it's a trim create a trim to assign trim curves to
3097 
3098  // for each trim curve, make an egg curve and
3099  // add it to the trims of the NURBS surface
3100  for ( i = 0; i < numTrims; i++ )
3101  {
3102  if ( use_prefix )
3103  {
3104  // Get the FULL name of the trim curve
3105  name = GetFullName( scene, &trimCurves[i] );
3106  }
3107  else
3108  {
3109  // Get the name of the trim curve
3110  name = GetName( scene, &trimCurves[i] );
3111  }
3112 
3113  if ( isTrim )
3114  {
3115  // add to trim list
3117  eggLoop->push_back( MakeUVNurbsCurve( i, numSamples, uSamples,
3118  vSamples, parent, name ) );
3119  eggTrim->push_back( *eggLoop );
3120  }
3121  else
3122  // add to curve list
3123  nurbsSurf->curves.push_back( MakeUVNurbsCurve( i, numSamples, uSamples, vSamples, parent, name ) );
3124  }
3125 
3126  if ( isTrim )
3127  // pus trim list onto trims list
3128  nurbsSurf->trims.push_back( *eggTrim );
3129 
3130  //free( name );
3131  //free( trimCurves );
3132  //free( uSamples );
3133  //free( vSamples );
3134 }
3135 
3136 ////////////////////////////////////////////////////////////////////
3137 // Function: MakeUVNurbsCurve
3138 // Access: Public
3139 // Description: Given a scene and lists of u and v samples create a
3140 // an egg NURBS curve of degree two from the samples
3141 ////////////////////////////////////////////////////////////////////
3142 EggNurbsCurve *soft2egg::
3143 MakeUVNurbsCurve( int numCurve, long *numSamples, double *uSamples,
3144  double *vSamples, EggGroup *parent, char *name )
3145 {
3146  EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name );
3147 
3148  eggNurbsCurve->order = 2;
3149 
3150 
3151  if ( verbose >= 2 )
3152  fprintf( outStream, "nurbs UV curve %s:\n", name );
3153 
3154  //set sub_div so we can see it in perfly
3155  //eggNurbsCurve->subdiv = numSamples[numCurve]/4;
3156  // perfly chokes on big numbers - keep it reasonable
3157  eggNurbsCurve->subdiv = 150;
3158 
3159  //create pool of NURBS vertices
3160  EggVertexPool *pool = _data.CreateVertexPool( parent, name );
3161  eggNurbsCurve->SetVertexPool( pool );
3162 
3163  // calculate offset to this curve's samples
3164  // in list of all curve samples
3165  int offset = 0;
3166 
3167  for ( int o = 0; o < numCurve; o++ )
3168  offset += numSamples[o];
3169 
3170  for ( int k = 0; k<numSamples[numCurve]; k++ )
3171  {
3172  pfVec3 eggVert;
3173 
3174  // index into the array of samples for this curve
3175  eggVert.set( uSamples[k+offset], vSamples[k+offset], 1.0f );
3176 
3177  if ( verbose >= 2 )
3178  fprintf( outStream, "cv[%d] = %f %f %f\n", k, eggVert[0],
3179  eggVert[1], eggVert[2] );
3180 
3181  //populate vertex pool
3182  pool->AddVertex( eggVert, k );
3183 
3184  //add vref's to NURBS info
3185  eggNurbsCurve->AddVertex( k );
3186  }
3187 
3188  // create numSamples[numCurve]+2 knots
3189  eggNurbsCurve->knots.push_back( 0 );
3190  for ( k = 0; k < numSamples[numCurve]; k++ )
3191  eggNurbsCurve->knots.push_back( k );
3192  eggNurbsCurve->knots.push_back( numSamples[numCurve] - 1 );
3193 
3194  //set color to bright green for now
3195  EggColor *nurbCref;
3196  pfVec4 nurbColor;
3197 
3198  nurbColor.set( 0.5, 1.0, 0.5, 1.0 );
3199  nurbCref = _data.CreateColor(nurbColor);
3200  eggNurbsCurve->attrib.SetCRef(nurbCref);
3201 
3202  return( eggNurbsCurve );
3203 }
3204 
3205 ////////////////////////////////////////////////////////////////////
3206 // Function: MakeNurbsCurve
3207 // Access: Public
3208 // Description: Given a scene and a NURBS curve model create the
3209 // the appropriate egg structures
3210 ////////////////////////////////////////////////////////////////////
3211 EggNurbsCurve *soft2egg::
3212 MakeNurbsCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent,
3213  float matrix[4][4], char *name )
3214 {
3215  EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name );
3216  int degree;
3217 
3218  if ( verbose >= 2 )
3219  fprintf( outStream, "nurbs curve %s:\n", name );
3220 
3221  //create nurbs representation of surface
3222  SAA_nurbsCurveGetDegree( scene, model, &degree );
3223  eggNurbsCurve->order = degree + 1;
3224  if ( verbose >= 2 )
3225  fprintf( outStream, "nurbs curve order: %d\n", degree + 1 );
3226 
3227  SAA_nurbsCurveSetStep( scene, model, nurbs_step );
3228 
3229  SAA_Boolean closed = FALSE;
3230 
3231  SAA_nurbsCurveGetClosed( scene, model, &closed );
3232  if ( closed )
3233  if ( verbose >= 2 )
3234  fprintf( outStream, "nurbs curve is closed...\n");
3235 
3236  int numKnots;
3237 
3238  SAA_nurbsCurveGetNbKnots( scene, model, &numKnots );
3239  if ( verbose >= 2 )
3240  fprintf( outStream, "nurbs curve knots: %d\n", numKnots );
3241  double *knots;
3242  knots = (double *)malloc(sizeof(double)*numKnots);
3243  SAA_nurbsCurveGetKnots( scene, model, SAA_GEOM_ORIGINAL, 0,
3244  numKnots, knots );
3245 
3246  AddKnots( eggNurbsCurve->knots, knots, numKnots, closed, degree );
3247 
3248  //free( knots );
3249 
3250  int numCV;
3251 
3252  SAA_modelGetNbVertices( scene, model, &numCV );
3253  if ( verbose >= 2 )
3254  fprintf( outStream, "%d CV's (=? %d)\n", numCV, (numKnots-(degree+1)) );
3255 
3256  //set sub_div so we can see it in perfly
3257  eggNurbsCurve->subdiv = (numCV-1)*nurbs_step;
3258 
3259  // get the CV's
3260  SAA_DVector *cvArray;
3261  cvArray = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
3262  SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
3263  numCV, cvArray );
3264 
3265  //create pool of NURBS vertices
3266  EggVertexPool *pool = _data.CreateVertexPool( parent, name );
3267  eggNurbsCurve->SetVertexPool( pool );
3268 
3269  for ( int k = 0; k<numCV; k++ )
3270  {
3271  if ( verbose >= 2 )
3272  fprintf( outStream, "cv[%d] = %f %f %f %f\n", k, cvArray[k].x,
3273  cvArray[k].y, cvArray[k].z, cvArray[k].w );
3274 
3275  pfVec4 eggVert;
3276 
3277  //convert to global coords
3278  SAA_DVector local = cvArray[k];
3279  SAA_DVector global;
3280 
3281  _HVCT_X_MAT( global, local, matrix );
3282 
3283  eggVert.set( global.x, global.y, global.z, global.w );
3284 
3285  //populate vertex pool
3286  pool->AddVertex( eggVert, k );
3287 
3288  //add vref's to NURBS info
3289  eggNurbsCurve->AddVertex( k );
3290  }
3291 
3292  if ( closed )
3293  {
3294  // need to replicate first (degree) vertices
3295  for ( k = 0; k < degree; k++ )
3296  {
3297  eggNurbsCurve->AddVertex( k );
3298  if ( verbose >= 2 )
3299  fprintf( outStream, "adding cv[%d] = %f %f %f %f\n", k,
3300  cvArray[k].x, cvArray[k].y, cvArray[k].z, cvArray[k].w );
3301  }
3302  }
3303 
3304  //free( cvArray );
3305 
3306  //set color to bright green for now
3307  EggColor *nurbCref;
3308  pfVec4 nurbColor;
3309 
3310  nurbColor.set( 0.5, 1.0, 0.5, 1.0 );
3311  nurbCref = _data.CreateColor(nurbColor);
3312  eggNurbsCurve->attrib.SetCRef(nurbCref);
3313 
3314  return( eggNurbsCurve );
3315 }
3316 
3317 ////////////////////////////////////////////////////////////////////
3318 // Function: AddKnots
3319 // Access: Public
3320 // Description: Given a parametric surface, and its knots, create
3321 // the appropriate egg structure by filling in Soft's
3322 // implicit knots and assigning the rest to eggKnots.
3323 ////////////////////////////////////////////////////////////////////
3324 void soft2egg::
3325 AddKnots( perf_vector<double> &eggKnots, double *knots, int numKnots,
3326  SAA_Boolean closed, int degree )
3327 {
3328  int k = 0;
3329  double lastKnot = knots[0];
3330  double *newKnots;
3331 
3332  // add initial implicit knot(s)
3333  if ( closed )
3334  {
3335  int i = 0;
3336  newKnots = (double *)malloc(sizeof(double)*degree);
3337 
3338  // need to add (degree) number of knots
3339  for ( k = numKnots - 1; k >= numKnots - degree; k-- )
3340  {
3341  // we have to know these in order to calculate
3342  // next knot value so hold them in temp array
3343  newKnots[i] = lastKnot - (knots[k] - knots[k-1]);
3344  lastKnot = newKnots[i];
3345  i++;
3346  }
3347  for ( k = degree - 1; k >= 0; k-- )
3348  {
3349  eggKnots.push_back( newKnots[k] );
3350  if ( verbose >= 2 )
3351  fprintf( outStream, "knots[%d] = %f\n", k, newKnots[k] );
3352  }
3353 
3354  //free( newKnots );
3355  }
3356  else
3357  {
3358  eggKnots.push_back( knots[k] );
3359  if ( verbose >= 2 )
3360  fprintf( outStream, "knots[%d] = %f\n", k, knots[k] );
3361  }
3362 
3363  // add the regular complement of knots
3364  for (k = 0; k < numKnots; k++)
3365  {
3366  eggKnots.push_back( knots[k] );
3367  if ( verbose >= 2 )
3368  fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k] );
3369  }
3370 
3371  lastKnot = knots[numKnots-1];
3372 
3373  // add trailing implicit knots
3374  if ( closed )
3375  {
3376 
3377  // need to add (degree) number of knots
3378  for ( k = 1; k <= degree; k++ )
3379  {
3380  eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) );
3381  if ( verbose >= 2 )
3382  fprintf( outStream, "knots[%d] = %f\n", k,
3383  lastKnot + (knots[k] - knots[k-1]) );
3384  lastKnot = lastKnot + (knots[k] - knots[k-1]);
3385  }
3386  }
3387  else
3388  {
3389  eggKnots.push_back( knots[k-1] );
3390  if ( verbose >= 2 )
3391  fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k-1] );
3392  }
3393 }
3394 
3395 ////////////////////////////////////////////////////////////////////
3396 // Function: MakeJoint
3397 // Access: Public
3398 // Description: Given a name, a parent and a model create a new
3399 // a new EggJoint for that model.
3400 ////////////////////////////////////////////////////////////////////
3401 void soft2egg::
3402 MakeJoint( SAA_Scene *scene, EggJoint *&lastJoint, AnimGroup *&lastAnim,
3403  SAA_Elem *model, char *name )
3404 {
3405  float matrix[4][4];
3406  pfMatrix Matrix;
3407  EggJoint *joint;
3408  SAA_Boolean globalFlag = FALSE;
3409  int scale_joint = 0;
3410 
3411 
3412  // this is a quick fix to make scaled skeletons possible
3413  // if the parent contains the keyword "scale" make this joint
3414  // a global root joint instead of a child...
3415  if (lastJoint != NULL)
3416  {
3417  if ( strstr( lastJoint->name.Str(), "scale" ) != NULL )
3418  {
3419  scale_joint = 1;
3420  if ( verbose >= 1 )
3421  fprintf( outStream, "scale joint flag set!\n" );
3422  }
3423  }
3424 
3425  // if not root, flatten is false, and last joint had no scaling
3426  // applied to it, then create joint in skeleton tree
3427  if ( (lastJoint != NULL) && !flatten && !scale_joint )
3428  {
3429  if ( verbose >= 1 )
3430  {
3431  fprintf( outStream, "lastJoint = %s\n", lastJoint->name.Str() );
3432  fprintf( outStream, "getting local transform\n" );
3433  }
3434 
3435  SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
3436  TRUE, (void **)&globalFlag );
3437 
3438  // get the local matrix
3439  SAA_modelGetMatrix( scene, model, SAA_COORDSYS_LOCAL, matrix );
3440 
3441  // make this into a pfMatrix
3442  Matrix[0][0] = matrix[0][0];
3443  Matrix[0][1] = matrix[0][1];
3444  Matrix[0][2] = matrix[0][2];
3445  Matrix[0][3] = matrix[0][3];
3446  Matrix[1][0] = matrix[1][0];
3447  Matrix[1][1] = matrix[1][1];
3448  Matrix[1][2] = matrix[1][2];
3449  Matrix[1][3] = matrix[1][3];
3450  Matrix[2][0] = matrix[2][0];
3451  Matrix[2][1] = matrix[2][1];
3452  Matrix[2][2] = matrix[2][2];
3453  Matrix[2][3] = matrix[2][3];
3454  Matrix[3][0] = matrix[3][0];
3455  Matrix[3][1] = matrix[3][1];
3456  Matrix[3][2] = matrix[3][2];
3457  Matrix[3][3] = matrix[3][3];
3458 
3459  joint = _data.CreateJoint( lastJoint, name );
3460  joint->transform = Matrix;
3461  }
3462  // if we already have a root attach this joint to it
3463  else if (foundRoot)
3464  {
3465  if ( verbose >= 1 )
3466  fprintf( outStream, "getting global transform\n" );
3467 
3468  globalFlag = TRUE;
3469 
3470  SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
3471  TRUE, (void *)&globalFlag );
3472 
3473  // get the global matrix
3474  SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix );
3475 
3476  // make this into a pfMatrix
3477  Matrix[0][0] = matrix[0][0];
3478  Matrix[0][1] = matrix[0][1];
3479  Matrix[0][2] = matrix[0][2];
3480  Matrix[0][3] = matrix[0][3];
3481  Matrix[1][0] = matrix[1][0];
3482  Matrix[1][1] = matrix[1][1];
3483  Matrix[1][2] = matrix[1][2];
3484  Matrix[1][3] = matrix[1][3];
3485  Matrix[2][0] = matrix[2][0];
3486  Matrix[2][1] = matrix[2][1];
3487  Matrix[2][2] = matrix[2][2];
3488  Matrix[2][3] = matrix[2][3];
3489  Matrix[3][0] = matrix[3][0];
3490  Matrix[3][1] = matrix[3][1];
3491  Matrix[3][2] = matrix[3][2];
3492  Matrix[3][3] = matrix[3][3];
3493 
3494  if ( verbose >= 1 )
3495  fprintf( outStream, "attaching orphan chain to root\n" );
3496 
3497  joint = _data.CreateJoint( rootJnt, name );
3498  joint->transform = Matrix;
3499  lastAnim = rootAnim;
3500  }
3501  // if root, make a seperate tree for skeleton and
3502  // create required Table for the Egg heirarchy
3503  else
3504  {
3505  if ( verbose >= 1 )
3506  fprintf( outStream, "getting global transform\n" );
3507 
3508  globalFlag = TRUE;
3509 
3510  SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ),
3511  TRUE, (void *)&globalFlag );
3512 
3513  // get the global matrix
3514  SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix );
3515 
3516  // make this into a pfMatrix
3517  Matrix[0][0] = matrix[0][0];
3518  Matrix[0][1] = matrix[0][1];
3519  Matrix[0][2] = matrix[0][2];
3520  Matrix[0][3] = matrix[0][3];
3521  Matrix[1][0] = matrix[1][0];
3522  Matrix[1][1] = matrix[1][1];
3523  Matrix[1][2] = matrix[1][2];
3524  Matrix[1][3] = matrix[1][3];
3525  Matrix[2][0] = matrix[2][0];
3526  Matrix[2][1] = matrix[2][1];
3527  Matrix[2][2] = matrix[2][2];
3528  Matrix[2][3] = matrix[2][3];
3529  Matrix[3][0] = matrix[3][0];
3530  Matrix[3][1] = matrix[3][1];
3531  Matrix[3][2] = matrix[3][2];
3532  Matrix[3][3] = matrix[3][3];
3533 
3534  rootJnt = _data.CreateJoint( skeleton, "root" );
3535  rootJnt->transform.makeIdent();
3536  if ( verbose >= 1 )
3537  fprintf( outStream, "setting skeleton root\n" );
3538  rootJnt->flags |= EF_TRANSFORM;
3539 
3540  joint = _data.CreateJoint( rootJnt, name );
3541  joint->transform = Matrix;
3542  foundRoot = TRUE;
3543  if ( verbose >= 1 )
3544  fprintf( outStream, "found first chain\n" );
3545 
3546  // make skeleton table
3547  AnimGroup *skeletonTable;
3548  skeletonTable = animData.CreateTable( animRoot, "<skeleton>" );
3549  rootAnim = animData.CreateTable( skeletonTable, "root" );
3550  XfmSAnimTable *table = new XfmSAnimTable( );
3551  table->name = "xform";
3552  table->fps = anim_rate;
3553  rootAnim->children.push_back( table );
3554  lastAnim = rootAnim;
3555  }
3556 
3557  joint->flags |= EF_TRANSFORM;
3558 
3559  //if ( make_anim)
3560  //{
3561  AnimGroup *anim = animData.CreateTable( lastAnim, name );
3562  XfmSAnimTable *table = new XfmSAnimTable( );
3563  if ( verbose >= 1 )
3564  fprintf( outStream, "created anim table: %s\n", "xform" );
3565  table->name = "xform";
3566  table->fps = anim_rate;
3567  anim->children.push_back( table );
3568  lastAnim = anim;
3569  //}
3570 
3571  // make this joint current parent of chain
3572  lastJoint = joint;
3573 }
3574 
3575 
3576 ////////////////////////////////////////////////////////////////////
3577 // Function: MakeSoftSkin
3578 // Access: Public
3579 // Description: Given a skeleton part find its envelopes (if any)
3580 // get the vertices associated with the envelopes and
3581 // their weights and make vertex ref's for the joint
3582 ////////////////////////////////////////////////////////////////////
3583 void soft2egg::
3584 MakeSoftSkin( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
3585  int numModels, char *name )
3586 {
3587  int numEnv;
3588  SAA_ModelType type;
3589  SAA_Elem *envelopes;
3590 
3591  if ( verbose >= 1 )
3592  fprintf( outStream, "\n>found skeleton part( %s )!\n", name );
3593 
3594  SAA_skeletonGetNbEnvelopes( scene, model, &numEnv );
3595 
3596  if ( numEnv )
3597  {
3598  // it's got envelopes - must be soft skinned
3599  if ( verbose >= 1 )
3600  fprintf( outStream, "numEnv = %d\n", numEnv );
3601 
3602  // allocate envelope array
3603  envelopes = ( SAA_Elem *)malloc( sizeof( SAA_Elem )*numEnv );
3604 
3605  if ( envelopes != NULL )
3606  {
3607  int thisEnv;
3608  SAA_EnvType envType;
3609  bool hasEnvVertices = 0;
3610 
3611  SAA_skeletonGetEnvelopes( scene, model, numEnv, envelopes );
3612 
3613  for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ )
3614  {
3615  if ( verbose >= 1 )
3616  fprintf( outStream, "env[%d]: ", thisEnv );
3617 
3618  SAA_envelopeGetType( scene, &envelopes[thisEnv], &envType );
3619 
3620  if ( envType == SAA_ENVTYPE_NONE )
3621  {
3622  if ( verbose >= 1 )
3623  fprintf( outStream, "envType = none\n" );
3624  }
3625  else if ( envType == SAA_ENVTYPE_FLXLCL )
3626  {
3627  if ( verbose >= 1 )
3628  fprintf( outStream, "envType = flexible, local\n" );
3629  hasEnvVertices = 1;
3630  }
3631  else if ( envType == SAA_ENVTYPE_FLXGLB )
3632  {
3633  if ( verbose >= 1 )
3634  fprintf( outStream, "envType = flexible, global\n" );
3635  hasEnvVertices = 1;
3636  }
3637  else if ( envType == SAA_ENVTYPE_RGDGLB )
3638  {
3639  if ( verbose >= 1 )
3640  fprintf( outStream, "envType = rigid, global\n" );
3641  hasEnvVertices = 1;
3642  }
3643  else
3644  {
3645  if ( verbose >= 1 )
3646  fprintf( outStream, "envType = unknown\n" );
3647  }
3648  }
3649 
3650  if ( hasEnvVertices)
3651  {
3652  int *numEnvVertices;
3653  SAA_SubElem *envVertices = NULL;
3654 
3655  numEnvVertices = (int *)malloc(sizeof(int)*numEnv);
3656 
3657  SAA_envelopeGetNbCtrlVertices( scene, model, numEnv,
3658  envelopes, numEnvVertices );
3659 
3660  if ( numEnvVertices != NULL )
3661  {
3662  int totalEnvVertices = 0;
3663  int i,j,k;
3664 
3665  for( i = 0; i < numEnv; i++ )
3666  {
3667  totalEnvVertices += numEnvVertices[i];
3668  if ( verbose >= 1 )
3669  fprintf( outStream, "numEnvVertices[%d] = %d\n",
3670  i, numEnvVertices[i] );
3671  }
3672 
3673 
3674  if ( verbose >= 1 )
3675  fprintf( outStream, "total env verts = %d\n",
3676  totalEnvVertices );
3677 
3678  if ( totalEnvVertices )
3679  {
3680  envVertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*totalEnvVertices);
3681 
3682  if ( envVertices != NULL )
3683  {
3684 
3685  SAA_envelopeGetCtrlVertices( scene, model,
3686  numEnv, envelopes, numEnvVertices, envVertices);
3687 
3688  // loop through for each envelope
3689  for ( i = 0; i < numEnv; i++ )
3690  {
3691  float *weights = NULL;
3692  int vertArrayOffset = 0;
3693 
3694  if ( verbose >= 2 )
3695  fprintf( outStream, "\nenvelope[%d]:\n", i );
3696 
3697  weights = (float *)malloc(sizeof(float)*numEnvVertices[i]);
3698 
3699  if ( weights )
3700  {
3701  char *envName;
3702  int *vpoolMap = NULL;
3703 
3704  for ( j = 0; j < i; j++ )
3705  vertArrayOffset += numEnvVertices[j];
3706 
3707  if ( verbose >= 1 )
3708  fprintf( outStream,
3709  "envVertArray offset = %d\n",
3710  vertArrayOffset );
3711 
3712  // get the weights of the envelope vertices
3713  SAA_ctrlVertexGetEnvelopeWeights(
3714  scene, model, &envelopes[i],
3715  numEnvVertices[i],
3716  &envVertices[vertArrayOffset], weights );
3717 
3718  // Get the name of the envelope model
3719  if ( use_prefix )
3720  {
3721  // Get the FULL name of the envelope
3722  envName = GetFullName( scene, &envelopes[i] );
3723  }
3724  else
3725  {
3726  // Get the name of the envelope
3727  envName = GetName( scene, &envelopes[i] );
3728  }
3729 
3730  if ( verbose >= 1 )
3731  fprintf( outStream, "envelope name %s\n", envName );
3732 
3733  // find out if envelope geometry is poly or nurb
3734  //SAA_modelGetType( scene,
3735  //FindModelByName( envName, scene,
3736  //models, numModels ), &type );
3737 
3738  SAA_modelGetType( scene, &envelopes[i], &type );
3739 
3740  if ( verbose >= 1 )
3741  {
3742  fprintf( outStream, "envelope model type ");
3743 
3744  if ( type == SAA_MSMSH )
3745  fprintf( outStream, "MESH\n" );
3746  else if ( type == SAA_MNSRF )
3747  fprintf( outStream, "NURBS\n" );
3748  else
3749  fprintf( outStream, "OTHER\n" );
3750  }
3751 
3752  int *envVtxIndices = NULL;
3753  envVtxIndices = (int *)malloc(sizeof(int)*numEnvVertices[i]);
3754 
3755  // Get the envelope vertex indices
3756  SAA_ctrlVertexGetIndices( scene, &envelopes[i], numEnvVertices[i],
3757  &envVertices[vertArrayOffset], envVtxIndices );
3758 
3759  // find out how many vertices the model has
3760  int modelNumVert;
3761 
3762  SAA_modelGetNbVertices( scene, &envelopes[i], &modelNumVert );
3763 
3764  SAA_DVector *modelVertices = NULL;
3765  modelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert);
3766 
3767  // get the model vertices
3768  SAA_modelGetVertices( scene, &envelopes[i],
3769  SAA_GEOM_ORIGINAL, 0, modelNumVert,
3770  modelVertices );
3771 
3772  // create array of global model coords
3773  SAA_DVector *globalModelVertices = NULL;
3774  globalModelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert);
3775  float matrix[4][4];
3776 
3777  // tranform local model vert coords to global
3778 
3779  // first get the global matrix
3780  SAA_modelGetMatrix( scene, &envelopes[i], SAA_COORDSYS_GLOBAL, matrix );
3781 
3782  // populate array of global model verts
3783  for ( j = 0; j < modelNumVert; j++ )
3784  {
3785  _VCT_X_MAT( globalModelVertices[j],
3786  modelVertices[j], matrix );
3787  }
3788 
3789  // find the egg vertex pool that corresponds
3790  // to this envelope model
3791  EggVertexPool *envPool =
3792  (EggVertexPool *)(_data.pools.FindName( envName ));
3793  // If we are outputting triangles:
3794  // create an array that maps from a referenced
3795  // vertex in the envelope to a corresponding
3796  // vertex in the egg vertex pool
3797  //if ( (type == SAA_MNSRF) && !make_nurbs )
3798  if ( !make_nurbs || (type == SAA_MSMSH) )
3799  {
3800  vpoolMap = FindClosestTriVert( envPool,
3801  globalModelVertices, modelNumVert );
3802  }
3803 
3804 
3805  if ( envPool != NULL )
3806  {
3807 
3808  // find the egg joint that corresponds to this model
3809  EggJoint *joint =
3810  (EggJoint *)(skeleton->FindDescendent( name ));
3811 
3812  // this doesn't seem to be necessary 4/7/99
3813  //EggJoint *parent = (EggJoint *)joint->parent;
3814  //assert(parent->IsA(NT_EggJoint));
3815 
3816  // for every envelope vertex
3817  for (j = 0; j < numEnvVertices[i]; j++)
3818  {
3819  double scaledWeight = weights[j]/ 100.0f;
3820 
3821  // make sure its in legal range
3822  if (( envVtxIndices[j] < modelNumVert )
3823  && ( envVtxIndices[j] >= 0 ))
3824  {
3825  if ( (type == SAA_MNSRF) && make_nurbs )
3826  {
3827  // assign all referenced control vertices
3828  joint->AddVertex( envPool->Vertex(envVtxIndices[j]), scaledWeight );
3829 
3830  if ( verbose >= 2 )
3831  fprintf( outStream,
3832  "%d: adding vref to cv %d with weight %f\n",
3833  j, envVtxIndices[j], scaledWeight );
3834 
3835  envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight );
3836  // set flag to show this vertex has
3837  // been assigned
3838  envPool->Vertex(envVtxIndices[j])->multipleJoints = 1;
3839  }
3840  else
3841  {
3842  //assign all the tri verts associated
3843  // with this control vertex to joint
3844  for ( k = 0; k < envPool->NumVertices(); k++ )
3845  {
3846  if ( vpoolMap[k] == envVtxIndices[j] )
3847  {
3848 
3849  // add each vert in pool to last
3850  // joint for soft skinning
3851  joint->AddVertex(envPool->Vertex(k),
3852  scaledWeight);
3853 
3854  if ( verbose >= 2 )
3855  fprintf( outStream,
3856  "%d: adding vref from cv %d to vert %d with weight %f(vpool)\n",
3857  j, envVtxIndices[j], k, scaledWeight );
3858 
3859  envPool->Vertex(k)->AddJoint( joint, scaledWeight );
3860  // set flag to show this vertex has
3861  // been assigned
3862  envPool->Vertex(k)->multipleJoints = 1;
3863  }
3864  }
3865  }
3866  }
3867  else
3868  if ( verbose >= 2 )
3869  fprintf( outStream,
3870  "%d: Omitted vref from cv %d with weight %f (out of range 0 to %d )\n",
3871  j, envVtxIndices[j], scaledWeight, modelNumVert );
3872 
3873  }
3874 
3875  }
3876  else
3877  if ( verbose >= 2 )
3878  fprintf( outStream, "Couldn't find vpool %s!\n", envName );
3879 
3880  //free( modelVertices );
3881  //free( globalModelVertices );
3882  //free( envVtxIndices );
3883  //free( envName );
3884  } //if (weights)
3885  //free( weights );
3886 
3887  } // for i
3888 
3889  } // if (envVertices != NULL)
3890  else
3891  fprintf( outStream, "Not enough memory for envelope vertices...\n");
3892  //free( envVertices );
3893  } // if (totalEnvVertices)
3894  else
3895  if ( verbose >= 1 )
3896  fprintf( outStream, "No envelope vertices present...\n");
3897 
3898  //free( numEnvVertices );
3899 
3900  } // if (numEnvVertices != NULL)
3901 
3902  } // if (hasEnvVertices)
3903 
3904  } // if (envelopes != NULL)
3905  else
3906  fprintf( outStream, "Not enough memory for envelopes...\n" );
3907 
3908  //free( envelopes );
3909 
3910  } //if (numEnv)
3911 
3912  else
3913  if ( verbose >= 1 )
3914  fprintf( outStream, "Skeleton member has no envelopes...\n" );
3915 }
3916 
3917 
3918 ////////////////////////////////////////////////////////////////////
3919 // Function: CleanUpSoftSkin
3920 // Access: Public
3921 // Description: Given a model, make sure all its vertices have been
3922 // soft assigned. If not hard assign to the last
3923 // joint we saw.
3924 ////////////////////////////////////////////////////////////////////
3925 void soft2egg::
3926 CleanUpSoftSkin( SAA_Scene *scene, SAA_Elem *model, char *name )
3927 {
3928  static EggJoint *joint;
3929  SAA_Elem parent;
3930  SAA_ModelType type;
3931  SAA_Boolean skel;
3932 
3933  /////////////////////////////////////////////////
3934  // find out what type of node we're dealing with
3935  /////////////////////////////////////////////////
3936  SAA_modelGetType( scene, model, &type );
3937 
3938  char *parentName;
3939  int level;
3940  SAA_Elem *searchNode = model;
3941 
3942  if ( verbose >= 1 )
3943  fprintf( outStream, "\nCleaning up model %s\n", name );
3944 
3945  // this step is weird - I think I want it here but it seems
3946  // to break some models. Files like props-props_wh_cookietime.3-0 in
3947  // /ful/rnd/pub/vrml/chip/chips_adventure/char/zone1/rooms/warehouse_final
3948  // need to do the "if (skel)" bit.
3949 
3950  // am I a skeleton too?
3951  SAA_modelIsSkeleton( scene, model, &skel );
3952 
3953  // if not look for the last skeleton part
3954  if ( skel )
3955  parentName = name;
3956  else do
3957  {
3958  SAA_elementGetHierarchyLevel( scene, searchNode, &level );
3959 
3960  // make sure we don't try to get the root's parent
3961  if ( level )
3962  {
3963  SAA_modelGetParent( scene, searchNode, &parent );
3964 
3965  if ( use_prefix )
3966  {
3967  // Get the FULL name of the parent
3968  parentName = GetFullName( scene, &parent );
3969  }
3970  else
3971  {
3972  // Get the name of the parent
3973  parentName = GetName( scene, &parent );
3974  }
3975 
3976  SAA_modelGetType( scene, &parent, &type );
3977 
3978  SAA_modelIsSkeleton( scene, &parent, &skel );
3979 
3980  if ( verbose >= 1 )
3981  fprintf( outStream, "model %s, level %d, type %d, skel %d\n",
3982  parentName, level, type, skel );
3983 
3984  searchNode = &parent;
3985  }
3986  else
3987  {
3988  // we reached the root of the tree
3989  parentName = NULL;
3990  if ( verbose >= 1 )
3991  fprintf( outStream, "at root of tree! level %d\n", level );
3992  break;
3993  }
3994 
3995  // look until parent is a joint or acts like one
3996  } while ( !skel && ( strstr( parentName,"joint") == NULL ));
3997 
3998  EggJoint *thisJoint = NULL;
3999 
4000  if ( parentName != NULL )
4001  {
4002  if ( verbose >= 1 )
4003  {
4004  fprintf( outStream, "found model parent joint %s\n", parentName);
4005  fprintf( outStream, "looking for joint %s\n", parentName );
4006  }
4007  thisJoint = (EggJoint *)(skeleton->FindDescendent( parentName ));
4008  }
4009  else
4010  if ( verbose >= 1 )
4011  fprintf( outStream, "Couldn't find parent joint!\n");
4012 
4013  if ( thisJoint != NULL )
4014  {
4015  joint = thisJoint;
4016  if ( verbose >= 1 )
4017  fprintf( outStream, "setting joint to %s\n", parentName );
4018 
4019  //find the vpool for this model
4020  EggVertexPool *vPool =
4021  (EggVertexPool *)(_data.pools.FindName( name ));
4022 
4023  if (vPool != NULL)
4024  {
4025  int i;
4026  double membership;
4027  int numVerts = vPool->NumVertices() ;
4028 
4029 
4030  if ( verbose >= 1 )
4031  fprintf( outStream, "found vpool %s w/ %d verts\n",
4032  name, numVerts );
4033 
4034  for ( i = 0; i < numVerts; i++ )
4035  {
4036  if ( vPool->Vertex(i)->multipleJoints != 1 )
4037  {
4038  if ( verbose >= 1 )
4039  {
4040  fprintf( outStream, "vpool %s vert %d", name, i );
4041  fprintf( outStream, " not assigned!\n" );
4042  }
4043 
4044  // hard skin this vertex
4045  joint->AddVertex( vPool->Vertex(i), 1.0f );
4046  }
4047  else
4048  {
4049  membership = vPool->Vertex(i)->NetMembership();
4050 
4051 
4052  if ( verbose >= 1 )
4053  {
4054  fprintf( outStream, "vpool %s vert %d", name,
4055  i );
4056  fprintf( outStream, " has membership %f\n",
4057  membership );
4058  }
4059 
4060  if ( membership == 0 )
4061  {
4062  if ( verbose >= 1 )
4063  fprintf( outStream, "adding full weight..\n" );
4064 
4065  // hard skin this vertex
4066  joint->AddVertex( vPool->Vertex(i), 1.0f );
4067  }
4068  }
4069  }
4070  }
4071  else
4072  if ( verbose >= 1 )
4073  fprintf( outStream, "couldn't find vpool %s\n", name );
4074  }
4075  else
4076  {
4077  if ( parentName != NULL )
4078  if ( verbose >= 1 )
4079  fprintf( outStream, "Couldn't find joint %s\n", parentName );
4080  }
4081 }
4082 
4083 //////////////////////////////////////////////////////////////////////
4084 // Function: MakeAnimTable
4085 // Access: Public
4086 // Description: Given a scene and a skeleton part ,get all the
4087 // position, rotation, and scale for the skeleton
4088 // part for this frame and write them out as Egg
4089 // animation tables.
4090 ////////////////////////////////////////////////////////////////////
4091 void soft2egg::
4092 MakeAnimTable( SAA_Scene *scene, SAA_Elem *skeletonPart, char *name )
4093 {
4094 
4095  if ( skeletonPart != NULL )
4096  {
4097  float i,j,k;
4098  float h,p,r;
4099  float x,y,z;
4100  int size;
4101  SAA_Boolean globalFlag = FALSE;
4102  SAA_Boolean bigEndian;
4103 
4104  if ( verbose >= 1 )
4105  fprintf( outStream, "\n\nanimating child %s\n", name );
4106 
4107  SAA_elementGetUserDataSize( scene, skeletonPart, "GLOBAL", &size );
4108 
4109  if ( size != 0 )
4110  SAA_elementGetUserData( scene, skeletonPart, "GLOBAL",
4111  sizeof( SAA_Boolean), &bigEndian, (void *)&globalFlag );
4112 
4113  if ( globalFlag )
4114  {
4115  if ( verbose >= 1 )
4116  fprintf( outStream, " using global matrix\n" );
4117 
4118  //get SAA orientation
4119  SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
4120  &p, &h, &r );
4121 
4122  //get SAA translation
4123  SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
4124  &x, &y, &z );
4125 
4126  //get SAA scaling
4127  SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL,
4128  &i, &j, &k );
4129  }
4130  else
4131  {
4132  if ( verbose >= 1 )
4133  fprintf( outStream, "using local matrix\n" );
4134 
4135  //get SAA orientation
4136  SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
4137  &p, &h, &r );
4138 
4139  //get SAA translation
4140  SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL,
4141  &x, &y, &z );
4142 
4143  //get SAA scaling
4144  SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL,
4145  &i, &j, &k );
4146  }
4147 
4148 
4149  if ( verbose >= 2 )
4150  fprintf( outStream, "\nanim data: %f %f %f\n\t%f %f %f\n\t%f %f %f\n",
4151  i, j, k, h, p, r, x, y, z );
4152 
4153  // find the appropriate anim table for this skeleton part
4154  AnimGroup *thisGroup;
4155  XfmSAnimTable *thisTable;
4156 
4157  //find the anim table associated with this group
4158  thisGroup = (AnimGroup *)(animRoot->FindDescendent( name ));
4159  if ( verbose >= 2 )
4160  fprintf( outStream, "\nlooking for anim group %s\n", name );
4161  if ( thisGroup != NULL )
4162  {
4163  thisTable = (XfmSAnimTable *)(thisGroup->FindDescendent( "xform" ));
4164 
4165  if ( thisTable != NULL )
4166  {
4167  thisTable->sub_tables[0].AddElement( i );
4168  thisTable->sub_tables[1].AddElement( j );
4169  thisTable->sub_tables[2].AddElement( k );
4170  thisTable->sub_tables[3].AddElement( p );
4171  thisTable->sub_tables[4].AddElement( h );
4172  thisTable->sub_tables[5].AddElement( r );
4173  thisTable->sub_tables[6].AddElement( x );
4174  thisTable->sub_tables[7].AddElement( y );
4175  thisTable->sub_tables[8].AddElement( z );
4176  }
4177  else
4178  fprintf( outStream, "Couldn't allocate anim table\n" );
4179  }
4180  else
4181  if ( verbose >= 2 )
4182  fprintf( outStream, "Couldn't find anim group %s\n", name );
4183  }
4184  else
4185  {
4186  if ( verbose >= 2 )
4187  fprintf( outStream, "Cannot build anim table - no skeleton\n" );
4188  }
4189 
4190 }
4191 
4192 ////////////////////////////////////////////////////////////////////
4193 // Function: MakeVertexOffsets
4194 // Access: Public
4195 // Description: Given a scene, a model , the vertices of its original
4196 // shape and its name find the difference between the
4197 // geometry of its key shapes and the models original
4198 // geometry and add morph vertices to the egg data to
4199 // reflect these changes.
4200 ////////////////////////////////////////////////////////////////////
4201 void soft2egg::
4202 MakeVertexOffsets( SAA_Scene *scene, SAA_Elem *model, SAA_ModelType type,
4203  int numShapes, int numOrigVert, SAA_DVector *originalVerts, float
4204  matrix[4][4], char *name )
4205 {
4206  int i, j;
4207  int offset;
4208  int numCV;
4209  char *mTableName;
4210  SAA_DVector *shapeVerts = NULL;
4211  SAA_DVector *uniqueVerts = NULL;
4212 
4213  if ( (type == SAA_MNSRF) && make_nurbs )
4214  SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step );
4215 
4216  SAA_modelGetNbVertices( scene, model, &numCV );
4217 
4218  // get the shape verts
4219  uniqueVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
4220  SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0,
4221  numCV, uniqueVerts );
4222 
4223  if ( verbose >= 2 )
4224  fprintf( outStream, "%d CV's\n", numCV );
4225 
4226  if ( verbose >= 2 )
4227  {
4228  for ( i = 0; i < numCV; i++ )
4229  fprintf( outStream, "uniqueVerts[%d] = %f %f %f %f\n", i,
4230  uniqueVerts[i].x, uniqueVerts[i].y,
4231  uniqueVerts[i].z, uniqueVerts[i].w );
4232  }
4233 
4234  // iterate through for each key shape (except original)
4235  for ( i = 1; i < numShapes; i++ )
4236  {
4237  mTableName = MakeTableName( name, i );
4238 
4239  if ( verbose >= 1 )
4240  {
4241  fprintf( outStream, "\nMaking geometry offsets for %s...\n",
4242  mTableName );
4243 
4244  if ( (type == SAA_MNSRF) && make_nurbs )
4245  fprintf( outStream, "calculating NURBS morphs...\n" );
4246  else
4247  fprintf( outStream, "calculating triangle morphs...\n" );
4248  }
4249 
4250  // get the shape verts
4251  shapeVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV);
4252  SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1,
4253  numCV, shapeVerts );
4254 
4255  if ( verbose >= 2 )
4256  {
4257  for ( j=0; j < numCV; j++ )
4258  {
4259  fprintf( outStream, "shapeVerts[%d] = %f %f %f\n", j,
4260  shapeVerts[j].x, shapeVerts[j].y, shapeVerts[j].z );
4261  }
4262  }
4263 
4264  // find the appropriate vertex pool
4265  EggVertexPool *vPool =
4266  (EggVertexPool *)(_data.pools.FindName( name ));
4267 
4268  // for every original vertex, compare to the corresponding
4269  // key shape vertex and see if a vertex offset is needed
4270  for ( j=0; j < numOrigVert; j++ )
4271  {
4272  double dx, dy, dz;
4273 
4274  if ( (type == SAA_MNSRF) && make_nurbs )
4275  {
4276  //dx = shapeVerts[j].x - (originalVerts[j].x/originalVerts[j].w);
4277  //dy = shapeVerts[j].y - (originalVerts[j].y/originalVerts[j].w);
4278  //dz = shapeVerts[j].z - (originalVerts[j].z/originalVerts[j].w);
4279  dx = shapeVerts[j].x - originalVerts[j].x;
4280  dy = shapeVerts[j].y - originalVerts[j].y;
4281  dz = shapeVerts[j].z - originalVerts[j].z;
4282  }
4283  else
4284  {
4285  // we need to map from original vertices
4286  // to triangle shape vertices here
4287  offset = findShapeVert( originalVerts[j], uniqueVerts,
4288  numCV );
4289 
4290  dx = shapeVerts[offset].x - originalVerts[j].x;
4291  dy = shapeVerts[offset].y - originalVerts[j].y;
4292  dz = shapeVerts[offset].z - originalVerts[j].z;
4293  }
4294 
4295  if ( verbose >= 2 )
4296  {
4297  fprintf( outStream, "oVert[%d] = %f %f %f %f\n", j,
4298  originalVerts[j].x, originalVerts[j].y,
4299  originalVerts[j].z, originalVerts[j].w );
4300 
4301  if ( (type == SAA_MNSRF) && make_nurbs )
4302  {
4303  fprintf( outStream, "global shapeVerts[%d] = %f %f %f %f\n", j, shapeVerts[j].x, shapeVerts[j].y,
4304  shapeVerts[j].z, shapeVerts[j].w );
4305  }
4306  else
4307  {
4308  fprintf( outStream,
4309  "global shapeVerts[%d] = %f %f %f\n", offset,
4310  shapeVerts[offset].x,
4311  shapeVerts[offset].y,
4312  shapeVerts[offset].z );
4313  }
4314 
4315  fprintf( outStream, "%d: dx = %f, dy = %f, dz = %f\n", j,
4316  dx, dy, dz );
4317  }
4318 
4319  // if change isn't negligible, make a morph vertex entry
4320  double total = fabs(dx)+fabs(dy)+fabs(dz);
4321  if ( total > 0.00001 )
4322  {
4323  if ( vPool != NULL )
4324  {
4325  // create offset
4326  EggMorphOffset *dxyz =
4327  new EggMorphOffset( mTableName, dx, dy, dz );
4328 
4329  EggVertex *eggVert;
4330 
4331  // get the appropriate egg vertex
4332  eggVert = vPool->Vertex(j);
4333 
4334  // add the offset to the vertex
4335  eggVert->morphs.push_back( *dxyz );
4336  }
4337  else
4338  fprintf( outStream, "Error: couldn't find vertex pool %s\n", name );
4339 
4340  } // if total
4341  } //for j
4342  } //for i
4343 }
4344 
4345 
4346 ////////////////////////////////////////////////////////////////////
4347 // Function: MakeMorphTable
4348 // Access: Public
4349 // Description: Given a scene, a model, a name and a frame time,
4350 // determine what type of shape interpolation is
4351 // used and call the appropriate function to extract
4352 // the shape weight info for this frame...
4353 ////////////////////////////////////////////////////////////////////
4354 void soft2egg::
4355 MakeMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
4356  int numModels, char *name, float time )
4357 {
4358  int numShapes;
4359  SAA_AnimInterpType type;
4360 
4361  // Get the number of key shapes
4362  SAA_modelGetNbShapes( scene, model, &numShapes );
4363 
4364  if ( numShapes > 0 )
4365  {
4366  if ( verbose >= 1 )
4367  fprintf( outStream, "MakeMorphTable: %s: num shapes: %d\n",
4368  name, numShapes);
4369 
4370  SAA_modelGetShapeInterpolation( scene, model, &type );
4371 
4372  if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL )
4373  {
4374  MakeLinearMorphTable( scene, model, numShapes, name, time );
4375  }
4376  else // must be weighted...
4377  {
4378  // check first for expressions
4379  MakeExpressionMorphTable( scene, model, models, numModels,
4380  numShapes, name, time );
4381  }
4382 
4383  }
4384 
4385 }
4386 
4387 
4388 ////////////////////////////////////////////////////////////////////
4389 // Function: MakeLinearMorphTable
4390 // Access: Public
4391 // Description: Given a scene, a model, its name, and the time,
4392 // get the shape fcurve for the model and determine
4393 // the shape weights for the given time and use them
4394 // to populate the morph table.
4395 ////////////////////////////////////////////////////////////////////
4396 void soft2egg::
4397 MakeLinearMorphTable( SAA_Scene *scene, SAA_Elem *model, int numShapes,
4398  char *name, float time )
4399 {
4400  int i;
4401  SAA_Elem fcurve;
4402  float curveVal;
4403  SAnimTable *thisTable;
4404  char *tableName;
4405 
4406  if ( verbose >= 1 )
4407  fprintf( outStream, "linear interp, getting fcurve\n" );
4408 
4409  SAA_modelFcurveGetShape( scene, model, &fcurve );
4410 
4411  SAA_fcurveEval( scene, &fcurve, time, &curveVal );
4412 
4413  if ( verbose >= 2 )
4414  fprintf( outStream, "at time %f, fcurve for %s = %f\n", time,
4415  name, curveVal );
4416 
4417  float nextVal = 0.0f;
4418 
4419  // populate morph table values for this frame
4420  for ( i = 1; i < numShapes; i++ )
4421  {
4422  // derive table name from the model name
4423  tableName = MakeTableName( name, i );
4424 
4425  if ( verbose >= 2 )
4426  fprintf( outStream, "Linear: looking for table '%s'\n", tableName );
4427 
4428  //find the morph table associated with this key shape
4429  thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName ));
4430 
4431  if ( thisTable != NULL )
4432  {
4433  if ( i == (int)curveVal )
4434  {
4435  if ( curveVal - i == 0 )
4436  {
4437  thisTable->AddElement( 1.0f );
4438  if ( verbose >= 2 )
4439  fprintf( outStream, "adding element 1.0f\n" );
4440  }
4441  else
4442  {
4443  thisTable->AddElement( 1.0f - (curveVal - i) );
4444  nextVal = curveVal - i;
4445  if ( verbose >= 2 )
4446  fprintf( outStream, "adding element %f\n", 1.0f - (curveVal - i) );
4447  }
4448  }
4449  else
4450  {
4451  if ( nextVal )
4452  {
4453  thisTable->AddElement( nextVal );
4454  nextVal = 0.0f;
4455  if ( verbose >= 2 )
4456  fprintf( outStream, "adding element %f\n", nextVal );
4457  }
4458  else
4459  {
4460  thisTable->AddElement( 0.0f );
4461  if ( verbose >= 2 )
4462  fprintf( outStream, "adding element 0.0f\n" );
4463  }
4464  }
4465 
4466  if ( verbose >= 2 )
4467  fprintf( outStream, " to '%s'\n", tableName );
4468  }
4469  else
4470  fprintf( outStream, "%d: Couldn't find table '%s'\n",
4471  i, tableName );
4472  }
4473 
4474 }
4475 
4476 ////////////////////////////////////////////////////////////////////
4477 // Function: MakeWeightedMorphTable
4478 // Access: Public
4479 // Description: Given a scene, a model, a list of all models in the
4480 // scene, the number of models in the scece, the number
4481 // of key shapes for this model, the name of the model
4482 // and the current time, determine what method of
4483 // controlling the shape weights is used and call the
4484 // appropriate routine.
4485 ////////////////////////////////////////////////////////////////////
4486 void soft2egg::
4487 MakeWeightedMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
4488  int numModels, int numShapes, char *name, float time )
4489 {
4490  SI_Error result;
4491  SAA_Elem *weightCurves;
4492  float curveVal;
4493  SAnimTable *thisTable;
4494  char *tableName;
4495 
4496  // allocate array of weight curves (one for each shape)
4497  weightCurves = ( SAA_Elem *)malloc( sizeof( SAA_Elem ) * numShapes );
4498 
4499  result = SAA_modelFcurveGetShapeWeights(
4500  scene, model, numShapes, weightCurves );
4501 
4502  if ( result == SI_SUCCESS )
4503  {
4504  for ( int i = 1; i < numShapes; i++ )
4505  {
4506  SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal );
4507 
4508  // make sure soft gave us a reasonable number
4509  if (!isNum(curveVal))
4510  curveVal = 0.0f;
4511 
4512  if ( verbose >= 2 )
4513  fprintf( outStream, "at time %f, weightCurve[%d] for %s = %f\n", time, i, name, curveVal );
4514 
4515 
4516  // derive table name from the model name
4517  tableName = MakeTableName( name, i );
4518 
4519  // find and populate shape table
4520  if ( verbose >= 2 )
4521  fprintf( outStream, "Weight: looking for table '%s'\n",
4522  tableName );
4523 
4524  //find the morph table associated with this key shape
4525  thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName ));
4526 
4527  if ( thisTable != NULL )
4528  {
4529  thisTable->AddElement( curveVal );
4530  if ( verbose >= 2 )
4531  fprintf( outStream, "adding element %f\n", curveVal );
4532  }
4533  else
4534  fprintf( outStream, "%d: Couldn't find table '%s'\n",
4535  i, tableName );
4536  }
4537  }
4538 }
4539 
4540 
4541 ////////////////////////////////////////////////////////////////////
4542 // Function: MakeExpressionMorphTable
4543 // Access: Public
4544 // Description: Given a scene, a model and its number of key shapes
4545 // generate a morph table describing transitions btwn
4546 // the key shapes by evaluating the positions of the
4547 // controlling sliders.
4548 ////////////////////////////////////////////////////////////////////
4549 void soft2egg::
4550 MakeExpressionMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models,
4551  int numModels, int numShapes, char *name, float time )
4552 {
4553  int j;
4554  SAnimTable *thisTable;
4555  char *tableName;
4556  char *sliderName;
4557  char *track;
4558  int numExp;
4559  SAA_Elem *expressions;
4560  float expVal;
4561  float sliderVal;
4562 
4563  // populate morph table values for this frame
4564 
4565  // compose track name
4566  track = NULL;
4567 
4568  // find how many expressions for this shape
4569  SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp );
4570 
4571  if ( verbose >= 2 )
4572  fprintf( outStream, "%s has %d RHS expressions\n", name, numExp );
4573 
4574  if ( numExp )
4575  {
4576  // get the expressions for this shape
4577  expressions = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numExp);
4578 
4579  if ( verbose >= 1 )
4580  fprintf( outStream, "getting %d RHS expressions...\n", numExp );
4581 
4582  result = SAA_elementGetExpressions( scene, model, track, FALSE,
4583  numExp, expressions );
4584 
4585  if ( !result )
4586  {
4587  for ( j = 1; j < numExp; j++ )
4588  {
4589  if ( verbose >= 2 )
4590  {
4591  // debug see what we got
4592  int numvars;
4593 
4594  SAA_expressionGetNbVars( scene, &expressions[j], &numvars );
4595 
4596  int *varnamelen;
4597  int *varstrlen;
4598  int expstrlen;
4599 
4600  varnamelen = (int *)malloc(sizeof(int)*numvars);
4601  varstrlen = (int *)malloc(sizeof(int)*numvars);
4602 
4603  SAA_expressionGetStringLengths( scene, &expressions[j],
4604  numvars, varnamelen, varstrlen, &expstrlen );
4605 
4606  int *varnamesizes;
4607  int *varstrsizes;
4608 
4609  varnamesizes = (int *)malloc(sizeof(int)*numvars);
4610  varstrsizes = (int *)malloc(sizeof(int)*numvars);
4611 
4612  for ( int k = 0; k < numvars; k++ )
4613  {
4614  varnamesizes[k] = varnamelen[k] + 1;
4615  varstrsizes[k] = varstrlen[k] + 1;
4616  }
4617 
4618  int expstrsize = expstrlen + 1;
4619 
4620  char **varnames;
4621  char **varstrs;
4622 
4623  varnames = (char **)malloc(sizeof(char *)*numvars);
4624  varstrs = (char **)malloc(sizeof(char *)*numvars);
4625 
4626  for ( k = 0; k < numvars; k++ )
4627  {
4628  varnames[k] = (char *)malloc(sizeof(char)*
4629  varnamesizes[k]);
4630 
4631  varstrs[k] = (char *)malloc(sizeof(char)*
4632  varstrsizes[k]);
4633  }
4634 
4635  char *expstr = (char *)malloc(sizeof(char)* expstrsize );
4636 
4637  SAA_expressionGetStrings( scene, &expressions[j], numvars,
4638  varnamesizes, varstrsizes, expstrsize, varnames,
4639  varstrs, expstr );
4640 
4641  if ( verbose >= 2 )
4642  {
4643  fprintf( outStream, "expression = '%s'\n", expstr );
4644  fprintf( outStream, "has %d variables\n", numvars );
4645  }
4646  } //if verbose
4647 
4648  if ( verbose >= 2 )
4649  fprintf( outStream, "evaling expression...\n" );
4650 
4651  SAA_expressionEval( scene, &expressions[j], time, &expVal );
4652 
4653  if ( verbose >= 2 )
4654  fprintf( outStream, "time %f: exp val %f\n",
4655  time, expVal );
4656 
4657  // derive table name from the model name
4658  tableName = MakeTableName( name, j );
4659 
4660  if ( verbose >= 2 )
4661  fprintf( outStream, "Exp: looking for table '%s'\n",
4662  tableName );
4663 
4664  //find the morph table associated with this key shape
4665  thisTable = (SAnimTable *)
4666  (morphRoot->FindDescendent( tableName ));
4667 
4668  if ( thisTable != NULL )
4669  {
4670  thisTable->AddElement( expVal );
4671  if ( verbose >= 1 )
4672  fprintf( outStream, "%d: adding element %f to %s\n",
4673  j, expVal, tableName );
4674  fflush( outStream );
4675  }
4676  else
4677  {
4678  fprintf( outStream, "%d: Couldn't find table '%s'", j,
4679  tableName );
4680 
4681  fprintf( outStream, " for value %f\n", expVal );
4682  }
4683  }
4684  }
4685  else
4686  fprintf( outStream, "couldn't get expressions!!!\n" );
4687  }
4688  else
4689  // no expression, use weight curves
4690  MakeWeightedMorphTable( scene, model, models, numModels,
4691  numShapes, name, time );
4692 
4693 }
4694 
4695 
4696 ////////////////////////////////////////////////////////////////////
4697 // Function: MakeTexAnim
4698 // Access: Public
4699 // Description: Given a scene, a POLYGON model, and the name
4700 // of the that model, get the u and v offsets for
4701 // the current frame.
4702 ////////////////////////////////////////////////////////////////////
4703 void soft2egg::
4704 MakeTexAnim( SAA_Scene *scene, SAA_Elem *model, char *modelName )
4705 {
4706  if ( verbose >= 1 )
4707  fprintf( outStream, "\n\nmaking texture animation for %s...\n",
4708  modelName );
4709 
4710  // get the color of the surface
4711  int numMats;
4712  pfVec4 Color;
4713  SAA_Elem *materials;
4714  void *relinfo;
4715 
4716  SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo,
4717  &numMats );
4718 
4719  if ( verbose >= 2 )
4720  fprintf( outStream, "surface has %d materials\n", numMats );
4721 
4722  if ( numMats )
4723  {
4724  float r,g,b,a;
4725 
4726  materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numMats);
4727 
4728  SAA_modelRelationGetMatElements( scene, model, relinfo,
4729  numMats, materials );
4730 
4731  SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b );
4732  SAA_materialGetTransparency( scene, &materials[0], &a );
4733  Color.set( r, g, b, 1.0f - a );
4734 
4735  int numTexLoc = 0;
4736  int numTexGlb = 0;
4737 
4738  // ASSUME only one texture per material
4739  SAA_Elem tex;
4740 
4741  // find out how many local textures per surface
4742  // ASSUME it only has one material
4743  SAA_materialRelationGetT2DLocNbElements( scene, &materials[0],
4744  FALSE, &relinfo, &numTexLoc );
4745 
4746  // if present, get local textures
4747  if ( numTexLoc )
4748  {
4749  if ( verbose >= 1 )
4750  fprintf( outStream, "%s had %d local tex\n", modelName,
4751  numTexLoc );
4752 
4753  // get the referenced texture
4754  SAA_materialRelationGetT2DLocElements( scene, &materials[0],
4755  TEX_PER_MAT, &tex );
4756 
4757  }
4758  // if no locals, try to get globals
4759  else
4760  {
4761  SAA_modelRelationGetT2DGlbNbElements( scene, model,
4762  FALSE, &relinfo, &numTexGlb );
4763 
4764  if ( numTexGlb )
4765  {
4766  if ( verbose >= 1 )
4767  fprintf( outStream, "%s had %d global tex\n", modelName, numTexGlb );
4768 
4769  // get the referenced texture
4770  SAA_modelRelationGetT2DGlbElements( scene,
4771  model, TEX_PER_MAT, &tex );
4772  }
4773  }
4774 
4775  // add tex ref's if we found any textures
4776  if ( numTexLoc || numTexGlb)
4777  {
4778  char *fullTexName = NULL;
4779  char *texName = NULL;
4780  char *uniqueTexName = NULL;
4781  int texNameLen;
4782 
4783  // get its name
4784  SAA_texture2DGetPicNameLength( scene, &tex, &texNameLen);
4785  fullTexName = (char *)malloc(sizeof(char)*++texNameLen);
4786  SAA_texture2DGetPicName( scene, &tex, texNameLen,
4787  fullTexName );
4788 
4789  // append unique identifier to texname for
4790  // this particular object
4791  uniqueTexName = (char *)malloc(sizeof(char)*
4792  (strlen(modelName)+strlen(texName)+3) );
4793  sprintf( uniqueTexName, "%s-%s", modelName, texName );
4794  if ( verbose >= 2 )
4795  fprintf( outStream, "referencing tref %s\n",
4796  uniqueTexName );
4797 
4798  float uScale;
4799  float vScale;
4800  float uOffset;
4801  float vOffset;
4802  SAA_Boolean uv_swap = FALSE;
4803 
4804  // get texture offset info
4805  SAA_texture2DGetUScale( scene, &tex, &uScale );
4806  SAA_texture2DGetVScale( scene, &tex, &vScale );
4807  SAA_texture2DGetUOffset( scene, &tex, &uOffset );
4808  SAA_texture2DGetVOffset( scene, &tex, &vOffset );
4809  SAA_texture2DGetUVSwap( scene, &tex, &uv_swap );
4810 
4811 
4812  if ( verbose >= 2 )
4813  {
4814  fprintf( outStream, "tex uScale: %f\n", uScale );
4815  fprintf( outStream, "tex vScale: %f\n", vScale );
4816  fprintf( outStream, "tex uOffset: %f\n", uOffset );
4817  fprintf( outStream, "tex vOffset: %f\n", vOffset );
4818  if ( uv_swap )
4819  fprintf( outStream, "nurbTex u & v swapped!\n" );
4820  else
4821  fprintf( outStream, "nurbTex u & v NOT swapped\n" );
4822  }
4823 
4824 
4825  // find the vpool for this model
4826  EggVertexPool *vPool =
4827  (EggVertexPool *)(_data.pools.FindName( modelName ));
4828 
4829  // if we found the pool
4830  if ( vPool != NULL )
4831  {
4832  // generate duv's for model
4833  float oldOffsets[4];
4834  double u, v, du, dv;
4835  int size;
4836  SAA_Boolean bigEndian;
4837 
4838  SAA_elementGetUserDataSize( scene, model, "TEX_OFFSETS", &size );
4839 
4840  if ( size != 0 )
4841  {
4842  // remember original texture offsets future reference
4843  SAA_elementGetUserData( scene, model, "TEX_OFFSETS",
4844  size, &bigEndian, (void *)&oldOffsets );
4845 
4846  // get the original scales and offsets
4847  u = oldOffsets[0];
4848  v = oldOffsets[1];
4849 
4850  du = u - uOffset;
4851  dv = v - vOffset;
4852 
4853  if ( verbose >= 1 )
4854  {
4855  fprintf( outStream, "original u = %f, v = %f\n",
4856  u, v );
4857  fprintf( outStream, "u = %f, v = %f\n",
4858  uOffset, vOffset );
4859  fprintf( outStream, "du = %f, dv = %f\n",
4860  du, dv );
4861  }
4862 
4863  strstream uName, vName;
4864 
4865  // create duv target names
4866  uName << modelName << ".u" << ends;
4867  vName << modelName << ".v" << ends;
4868 
4869  // find the appropriate table to store the
4870  // duv animation info into
4871  SAnimTable *thisTable;
4872 
4873  //find the duv U table associated with this model
4874  thisTable = (SAnimTable *)(morphRoot->FindDescendent(
4875  uName.str() ));
4876 
4877  if ( thisTable != NULL )
4878  {
4879  thisTable->AddElement( du );
4880  if ( verbose >= 1 )
4881  fprintf( outStream, "adding element %f to %s\n",
4882  du, uName.str() );
4883  }
4884  else
4885  fprintf( outStream, "Couldn't find uTable %s\n",
4886  uName.str() );
4887 
4888  //find the duv V table associated with this model
4889  thisTable = (SAnimTable *)(morphRoot->FindDescendent(
4890  vName.str() ));
4891 
4892  if ( thisTable != NULL )
4893  {
4894  thisTable->AddElement( dv );
4895  if ( verbose >= 1 )
4896  fprintf( outStream, "adding element %f to %s\n",
4897  dv, uName.str() );
4898  }
4899  else
4900  fprintf( outStream, "Couldn't find vTable %s\n",
4901  uName.str() );
4902  }
4903  }
4904  else
4905  if ( verbose >= 2 )
4906  fprintf( outStream, "Couldn't find vpool %s\n", modelName );
4907 
4908  }
4909 
4910  //free( materials );
4911 
4912  }
4913 
4914 }
4915 #endif
4916 
4917 ////////////////////////////////////////////////////////////////////
4918 // Function: Main
4919 // Access: Private
4920 // Description: Instantiate converter and process a file
4921 ////////////////////////////////////////////////////////////////////
4922 EXPCL_MISC SI_Error soft2egg(int argc, char *argv[]) {
4923  // pass control to the c++ system
4924  init_soft2egg(argc, argv);
4925  return SI_SUCCESS;
4926 }
4927 #ifdef __cplusplus
4928 }
4929 #endif
A comment that appears in an egg file within a &lt;Comment&gt; entry.
Definition: eggComment.h:27
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
This is our own Panda specialization on the default STL list.
Definition: plist.h:38
This is the primary interface into all the egg data, and the root of the egg file structure...
Definition: eggData.h:41
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
This is the base class for AnimChannel and AnimBundle.
Definition: animGroup.h:36
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
A parametric NURBS curve.
Definition: eggNurbsCurve.h:28
A single polygon.
Definition: eggPolygon.h:26
A parametric NURBS surface.
This is a base class for both EggSingleBase and EggMultiBase.
Definition: eggBase.h:32
A collection of vertices.
Definition: eggVertexPool.h:46