From 5d5cc31024f596e3c6e98e6fc32b557e61b95dcd Mon Sep 17 00:00:00 2001 From: "Asad M. Zaman" Date: Wed, 15 Oct 2003 18:52:55 +0000 Subject: [PATCH] initial softimage extractor tool port: only model, no animation yet --- pandatool/src/softegg/soft2Egg.c | 4933 ++++++++++++++++++++++++++++++ 1 file changed, 4933 insertions(+) create mode 100755 pandatool/src/softegg/soft2Egg.c diff --git a/pandatool/src/softegg/soft2Egg.c b/pandatool/src/softegg/soft2Egg.c new file mode 100755 index 0000000000..aa62d9c505 --- /dev/null +++ b/pandatool/src/softegg/soft2Egg.c @@ -0,0 +1,4933 @@ +// Filename: soft2Egg.c +// Created by: masad (26Sep03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2003, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Includes +//////////////////////////////////////////////////////////////////// + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pandatoolbase.h" + +int init_soft2egg(int, char **); + +#if 0 +// DWD includes +#include "eggBase.h" +#include +#include +#include + +// system includes +#include +#include +#include +#include +#include +#include + +// Performer includes +#include + +// SoftImage includes +#include +#include + +static const int TEX_PER_MAT = 1; +static FILE *outStream = stdout; +//static FILE *outStream = stderr; + +class soft2egg : public EggBase +{ + public: + + soft2egg() : EggBase("r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD") + { + rsrc_path = "/ful/ufs/soft371_mips2/3D/rsrc"; + database_name = NULL; + scene_name = NULL; + model_name = NULL; + animFileName = NULL; + eggFileName = NULL; + tex_path = NULL; + eggGroupName = NULL; + tex_filename = NULL; + search_prefix = NULL; + result = SI_SUCCESS; + + skeleton = new EggGroup(); + foundRoot = FALSE; + animRoot = NULL; + morphRoot = NULL; + geom_as_joint = 0; + make_anim = 0; + make_nurbs = 0; + make_poly = 0; + make_soft = 0; + make_morph = 1; + make_duv = 1; + make_dart = TRUE; + has_morph = 0; + make_pose = 0; + animData.is_z_up = FALSE; + nurbs_step = 1; + anim_start = -1000; + anim_end = -1000; + anim_rate = 24; + pose_frame = -1; + verbose = 0; + flatten = 0; + shift_textures = 0; + ignore_tex_offsets = 0; + use_prefix = 0; + } + + virtual void Help(); + virtual void Usage(); + virtual void ShowOpts(); + + virtual boolean UseOutputSwitch() const { + return false; + } + + virtual boolean + HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv); + + int isNum( float ); + char *GetRootName( const char * ); + char *RemovePathName( const char * ); + char *GetSliderName( const char * ); + char *GetFullName( SAA_Scene *, SAA_Elem * ); + char *GetName( SAA_Scene *, SAA_Elem * ); + char *GetModelNoteInfo( SAA_Scene *, SAA_Elem * ); + char *MakeTableName( const char *, int ); + char *DepointellizeName( char * ); + SAA_Elem *FindModelByName( char *, SAA_Scene *, SAA_Elem *, int ); + char *ConvertTexture( SAA_Scene *, SAA_Elem * ); + int *FindClosestTriVert( EggVertexPool *, SAA_DVector *, int ); + int *MakeIndexMap( int *, int, int ); + int findShapeVert( SAA_DVector, SAA_DVector *, int ); + void LoadSoft(); + void MakeEgg( EggGroup *, EggJoint *, AnimGroup *, SAA_Scene *, SAA_Elem * ); + void MakeSurfaceCurve( SAA_Scene *, SAA_Elem *, EggGroup *, + EggNurbsSurface *&, int , SAA_SubElem *, bool ); + + EggNurbsCurve *MakeUVNurbsCurve( int, long *, double *, double *, + EggGroup *, char * ); + + EggNurbsCurve *MakeNurbsCurve( SAA_Scene *, SAA_Elem *, EggGroup *, + float [4][4], char * ); + + void AddKnots( perf_vector &, double *, int, SAA_Boolean, int ); + void MakeJoint( SAA_Scene *, EggJoint *&, AnimGroup *&, SAA_Elem *, char * ); + void MakeSoftSkin( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char * ); + void CleanUpSoftSkin( SAA_Scene *, SAA_Elem *, char * ); + void MakeAnimTable( SAA_Scene *, SAA_Elem *, char * ); + void MakeVertexOffsets( SAA_Scene *, SAA_Elem *, SAA_ModelType type, + int, int, SAA_DVector *, float (*)[4], char * ); + void MakeMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char *, + float ); + void MakeLinearMorphTable( SAA_Scene *, SAA_Elem *, int, char *, float ); + void MakeWeightedMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, + int, char *, float ); + void MakeExpressionMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, + int, char *, float ); + void MakeTexAnim( SAA_Scene *, SAA_Elem *, char * ); + + private: + + char *rsrc_path; + char *database_name; + char *scene_name; + char *model_name; + char *eggFileName; + char *animFileName; + char *eggGroupName; + char *tex_path; + char *tex_filename; + char *search_prefix; + + SI_Error result; + SAA_Scene scene; + SAA_Elem model; + SAA_Database database; + EggGroup *dart; + EggGroup *skeleton; + AnimGroup *rootAnim; + EggJoint *rootJnt; + AnimGroup *animRoot; + AnimGroup *morphRoot; + EggData animData; + + int nurbs_step; + int anim_start; + int anim_end; + int anim_rate; + int pose_frame; + int verbose; + int flatten; + int shift_textures; + int ignore_tex_offsets; + int use_prefix; + + bool foundRoot; + bool geom_as_joint; + bool make_anim; + bool make_nurbs; + bool make_poly; + bool make_soft; + bool make_morph; + bool make_duv; + bool make_dart; + bool has_morph; + bool make_pose; + + ofstream eggFile; + ofstream animFile; + ofstream texFile; + +}; + + +//////////////////////////////////////////////////////////////////// +// Function: Help +// Access: Public, Virtual +// Description: Displays the "what is this program" message, along +// with the usage message. Should be overridden in base +// classes to describe the current program. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +Help() +{ + cerr << + "soft2egg takes a SoftImage scene or model\n" + "and outputs its contents as an egg file\n"; + + Usage(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Usage +// Access: Public, Virtual +// Description: Displays the usage message. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +Usage() { + cerr << "\nUsage:\n" + << _commandName << " [opts] (must specify -m or -s)\n\n" + << "Options:\n"; + + ShowOpts(); + cerr << "\n"; +} + + + +//////////////////////////////////////////////////////////////////// +// Function: ShowOpts +// Access: Public, Virtual +// Description: Displays the valid options. Should be extended in +// base classes to show additional options relevant to +// the current program. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +ShowOpts() +{ + cerr << + " -r - Used to provide soft with the resource\n" + " Defaults to 'c:/Softimage/SOFT_3.9.2/3D/test'.\n" + // " Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n" + " -d - Database path.\n" + " -s - Indicates that a scene will be converted.\n" + " -m - Indicates that a model will be converted.\n" + " -t - Specify path to place converted textures.\n" + " -T - Specify filename for texture map listing.\n" + " -S - Specify step for nurbs surface triangulation.\n" + " -M - Specify model output filename. Defaults to scene name.\n" + " -A - Specify anim output filename. Defaults to scene name.\n" + " -N - Specify egg group name.\n" + " -k - Enable soft assignment for geometry.\n" + " -n - Specify egg NURBS representation instead of poly's.\n" + " -p - Specify egg polygon output for geometry.\n" + " -P - Specify frame number for static pose.\n" + " -b - Specify starting frame for animation (default = first).\n" + " -e - Specify ending frame for animation (default = last).\n" + " -f - Specify frame rate for animation playback.\n" + " -a - Compile animation tables if animation present.\n" + " -F - Ignore hierarchy and build a completely flat skeleton.\n" + " -v - Set debug level.\n" + " -x - Shift NURBS parameters to preserve Alias textures.\n" + " -i - Ignore Soft texture uv offsets.\n" + " -u - Use Soft prefix in model names.\n" + " -c - Cancel morph conversion.\n" + " -C - Cancel duv conversion.\n" + " -D - Don't make the output model a character.\n" + " -o - Convert only models with given prefix.\n"; + + EggBase::ShowOpts(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: HandleGetopts +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +boolean soft2egg:: +HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv) +{ + boolean okflag = true; + + switch (flag) + { + case 'r': // Set the resource path for soft. + if ( strcmp( optarg, "" ) ) + { + // Get the path. + rsrc_path = optarg; + fprintf( outStream, "using rsrc path %s\n", rsrc_path ); + } + break; + + case 'd': // Set the database path. + if ( strcmp( optarg, "" ) ) + { + // Get the path. + database_name = optarg; + fprintf( outStream, "using database %s\n", database_name ); + } + break; + + case 's': // Check if its a scene. + if ( strcmp( optarg, "" ) ) + { + // Get scene name. + scene_name = optarg; + fprintf( outStream, "loading scene %s\n", scene_name ); + } + break; + + case 'm': // Check if its a model. + if ( strcmp( optarg, "" ) ) + { + // Get model name. + model_name = optarg; + fprintf( outStream, "loading model %s\n", model_name ); + } + break; + + case 't': // Get converted texture path. + if ( strcmp( optarg, "" ) ) + { + // Get tex path name. + tex_path = optarg; + fprintf( outStream, "texture path: %s\n", tex_path ); + } + break; + + case 'T': // Specify texture list filename. + if ( strcmp( optarg, "") ) + { + // Get the name. + tex_filename = optarg; + fprintf( outStream, "creating texture list file: %s\n", + tex_filename ); + } + break; + case 'S': // Set NURBS step. + if ( strcmp( optarg, "" ) ) + { + nurbs_step = atoi(optarg); + fprintf( outStream, "NURBS step: %d\n", nurbs_step ); + } + break; + + case 'M': // Set model output file name. + if ( strcmp( optarg, "" ) ) + { + eggFileName = optarg; + fprintf( outStream, "Model output filename: %s\n", eggFileName ); + } + break; + + case 'A': // Set anim output file name. + if ( strcmp( optarg, "" ) ) + { + animFileName = optarg; + fprintf( outStream, "Anim output filename: %s\n", animFileName ); + } + break; + + case 'N': // Set egg model name. + if ( strcmp( optarg, "" ) ) + { + eggGroupName = optarg; + fprintf( outStream, "Egg group name: %s\n", eggGroupName ); + } + break; + + case 'o': // Set search_prefix. + if ( strcmp( optarg, "" ) ) + { + search_prefix = optarg; + fprintf( outStream, "Only converting models with prefix: %s\n", + search_prefix ); + } + break; + + case 'h': // print help message + Help(); + exit(1); + break; + + case 'c': // Cancel morph animation conversion + make_morph = FALSE; + fprintf( outStream, "canceling morph conversion\n" ); + break; + + case 'C': // Cancel uv animation conversion + make_duv = FALSE; + fprintf( outStream, "canceling uv animation conversion\n" ); + break; + + case 'D': // Omit the Dart flag + make_dart = FALSE; + fprintf( outStream, "making a non-character model\n" ); + break; + + case 'k': // Enable soft skinning + //make_soft = TRUE; + //fprintf( outStream, "enabling soft skinning\n" ); + fprintf( outStream, "-k flag no longer necessary\n" ); + break; + + case 'n': // Generate egg NURBS output + make_nurbs = TRUE; + fprintf( outStream, "outputting egg NURBS info\n" ); + break; + + case 'p': // Generate egg polygon output + make_poly = TRUE; + fprintf( outStream, "outputting egg polygon info\n" ); + break; + + case 'P': // Generate static pose from given frame + if ( strcmp( optarg, "" ) ) + { + make_pose = TRUE; + pose_frame = atoi(optarg); + fprintf( outStream, "generating static pose from frame %d\n", + pose_frame ); + } + break; + + case 'a': // Compile animation tables. + make_anim = TRUE; + fprintf( outStream, "attempting to compile anim tables\n" ); + break; + + case 'F': // Build a flat skeleton. + flatten = TRUE; + fprintf( outStream, "building a flat skeleton!!!\n" ); + break; + + case 'x': // Shift NURBS parameters to preserve Alias textures. + shift_textures = TRUE; + fprintf( outStream, "shifting NURBS parameters...\n" ); + break; + + case 'i': // Ignore Soft uv texture offsets + ignore_tex_offsets = TRUE; + fprintf( outStream, "ignoring texture offsets...\n" ); + break; + + case 'u': // Use Soft prefix in model names + use_prefix = TRUE; + fprintf( outStream, "using prefix in model names...\n" ); + break; + + + case 'v': // print debug messages. + if ( strcmp( optarg, "" ) ) + { + verbose = atoi(optarg); + fprintf( outStream, "using debug level %d\n", verbose ); + } + break; + + case 'b': // Set animation start frame. + if ( strcmp( optarg, "" ) ) + { + anim_start = atoi(optarg); + fprintf( outStream, "animation starting at frame: %d\n", + anim_start ); + } + break; + + case 'e': /// Set animation end frame. + if ( strcmp( optarg, "" ) ) + { + anim_end = atoi(optarg); + fprintf( outStream, "animation ending at frame: %d\n", anim_end ); + } + break; + + case 'f': /// Set animation frame rate. + if ( strcmp( optarg, "" ) ) + { + anim_rate = atoi(optarg); + fprintf( outStream, "animation frame rate: %d\n", anim_rate ); + } + break; + + default: + okflag = EggBase::HandleGetopts(flag, optarg, optind, argc, argv); + } + + return (okflag); +} + + + +//////////////////////////////////////////////////////////////////// +// Function: isNum +// Access: Public, Virtual +// Description: Take a float and make sure it is of the body. +//////////////////////////////////////////////////////////////////// +int soft2egg:: +isNum( float num ) +{ + return( ( num < HUGE_VAL ) && finite( num ) ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: GetRootName +// Access: Public +// Description: Given a string, return a copy of the string up to +// the first occurence of '-'. +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +GetRootName( const char *name ) +{ + char *hyphen; + char *root; + int len; + + hyphen = strchr( name, '-' ); + len = hyphen-name; + + if ( (hyphen != NULL) && len ) + { + root = (char *)malloc(sizeof(char)*(len+1)); + strncpy( root, name, len ); + root[sizeof(char)*(len)] = '\0'; + } + else + { + root = (char *)malloc( sizeof(char)*(strlen(name)+1)); + strcpy( root, name ); + } + + return( root ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: RemovePathName +// Access: Public +// Description: Given a string, return a copy of the string after +// the last occurence of '/ +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +RemovePathName( const char *name ) +{ + char *slash; + char *root; + + if ( *name != NULL ) + { + slash = strrchr( name, '/' ); + + root = (char *)malloc( sizeof(char)*(strlen(name)+1)); + + if ( slash != NULL ) + strcpy( root, ++slash ); + else + strcpy( root, name ); + + return( root ); + } + + fprintf( stderr, "Error: RemovePathName received NULL string!\n" ); + return ( (char *)name ); +} + +//////////////////////////////////////////////////////////////////// +// Function: GetSliderName +// Access: Public +// Description: Given a string, return that part of the string after +// the first occurence of '-' and before the last +// occurance of '.' +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +GetSliderName( const char *name ) +{ + if ( name != NULL ) + { + strstream newStr; + char *hyphen; + char *end; + + hyphen = strchr( name, '-' ); + + // pull off stuff before first hyphen + if (hyphen != NULL) + { + newStr << ++hyphen; + end = newStr.str(); + } + + char *lastPeriod; + + lastPeriod = strrchr( end, '.' ); + + // ignore stuff after last period + if ( lastPeriod != NULL ) + { + *lastPeriod = '\0'; + } + + if ( verbose >= 1 ) + fprintf( stdout, "slider name: '%s'\n", end ); + + return( end ); + } + + return( (char *)name ); +} + +//////////////////////////////////////////////////////////////////// +// Function: GetName +// Access: Public +// Description: Given an element, return a copy of the element's +// name WITHOUT prefix. +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +GetName( SAA_Scene *scene, SAA_Elem *element ) +{ + int nameLen; + char *name; + + // get the name + SAA_elementGetNameLength( scene, element, &nameLen ); + name = (char *)malloc(sizeof(char)*++nameLen); + SAA_elementGetName( scene, element, nameLen, name ); + + return name; +} + +//////////////////////////////////////////////////////////////////// +// Function: GetFullName +// Access: Public +// Description: Given an element, return a copy of the element's +// name complete with prefix. +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +GetFullName( SAA_Scene *scene, SAA_Elem *element ) +{ + int nameLen; + char *name; + + // get the name + SAA_elementGetNameLength( scene, element, &nameLen ); + name = (char *)malloc(sizeof(char)*++nameLen); + SAA_elementGetName( scene, element, nameLen, name ); + + int prefixLen; + char *prefix; + + // get the prefix + SAA_elementGetPrefixLength( scene, element, &prefixLen ); + prefix = (char *)malloc(sizeof(char)*++prefixLen); + SAA_elementGetPrefix( scene, element, prefixLen, prefix ); + + strstream fullNameStrm; + + // add 'em together + fullNameStrm << prefix << "-" << name << ends; + + //free( name ); + //free( prefix ); + + return fullNameStrm.str(); +} + +//////////////////////////////////////////////////////////////////// +// Function: GetModelNoteInfo +// Access: Public +// Description: Given an element, return a string containing the +// contents of its MODEL NOTE entry +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) +{ + + int size; + char *modelNote = NULL; + SAA_Boolean bigEndian; + + + SAA_elementGetUserDataSize( scene, model, "MNOT", &size ); + + if ( size != 0 ) + { + // allocate modelNote string + modelNote = (char *)malloc(sizeof(char)*(size + 1)); + + // get ModelNote data from this model + SAA_elementGetUserData( scene, model, "MNOT", size, + &bigEndian, (void *)modelNote ); + + //strip off newline, if present + char *eol = strchr( modelNote, '\n' ); + if ( eol != NULL) + *eol = '\0'; + else + modelNote[size] = '\0'; + + if ( verbose >= 1 ) + fprintf( outStream, "\nmodelNote = %s\n", + modelNote ); + } + + return modelNote; +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeTableName +// Access: Public +// Description: Given a string, and a number, return a new string +// consisting of "string.number". +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +MakeTableName( const char *name, int number ) +{ + strstream namestrm; + + namestrm << name << "." << number << ends; + return namestrm.str(); +} + +//////////////////////////////////////////////////////////////////// +// Function: FindModelByName +// Access: Public +// Description: Given a string, find the model in the scene +// whose name corresponds to the given string. +//////////////////////////////////////////////////////////////////// +SAA_Elem *soft2egg:: +FindModelByName( char *name, SAA_Scene *scene, SAA_Elem *models, + int numModels ) +{ + char *foundName; + SAA_Elem *foundModel = NULL; + + for ( int model = 0; model < numModels; model++ ) + { + foundName = GetName( scene, &models[model] ); + + if ( !strcmp( name, foundName ) ) + { + if ( verbose >= 1 ) + fprintf( outStream, "foundModel: '%s' = '%s'\n", + name, foundName ); + + foundModel = &models[model]; + return( foundModel ); + } + } + + fprintf( outStream, "findModelByName: failed to find model named: '%s'\n", + name ); + + return ( foundModel ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: DepointellizeName +// Access: Public +// Description: Given a string, return the string up to the first +// period. +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +DepointellizeName( char *name ) +{ + char *endPtr; + char *newName; + + newName = (char *)malloc(sizeof(char)*(strlen(name)+1)); + sprintf( newName, "%s", name ); + + endPtr = strchr( newName, '.' ); + if ( endPtr != NULL ) + *endPtr = '\0'; + + return ( newName ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: ConvertTexture +// Access: Public +// Description: Given a string, return a copy of the string without +// the leading file path, and make an rgb file of the +// same name in the tex_path directory. +//////////////////////////////////////////////////////////////////// +char *soft2egg:: +ConvertTexture( SAA_Scene *scene, SAA_Elem *texture ) +{ + char *fileName = NULL; + int fileNameLen = 0; + + // get the texture's name + SAA_texture2DGetPicNameLength( scene, texture, &fileNameLen); + + if ( fileNameLen ) + { + fileName = (char *)malloc(sizeof(char)*++fileNameLen); + SAA_texture2DGetPicName( scene, texture, fileNameLen, fileName ); + } + + // make sure we are not being passed a NULL image, an empty image + // string or the default image created by egg2soft + if ( (fileName != NULL) && strlen( fileName ) && strcmp( fileName, + "/fat/people/gregw/new_test/PICTURES/default") && + ( strstr( fileName, "noIcon" ) == NULL) ) + { + char *texName = NULL; + char *texNamePath = NULL; + char *tmpName = NULL; + char *fileNameExt = NULL; + + // strip off path and add .rgb + tmpName = strrchr( fileName, '/' ); + + if ( tmpName == NULL ) + tmpName = fileName; + else + tmpName++; + + float transp; + + // check for alpha + SAA_texture2DGetTransparency( scene, texture, &transp ); + + if ( transp != 0.0f ) { + texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+6)); + sprintf( texName, "%s.rgba", tmpName ); + } else { + texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+5)); + sprintf( texName, "%s.rgb", tmpName ); + } + + fileNameExt = (char *)malloc(sizeof(char)*(strlen(fileName)+5)); + sprintf( fileNameExt, "%s.pic", fileName ); + + if ( verbose >= 1 ) + fprintf( outStream, "Looking for texture file: '%s'\n", fileNameExt ); + + // try to make conversion of file + int found_file = ( access( fileNameExt, F_OK ) == 0); + + if ( found_file ) + { + if ( tex_path ) + { + texNamePath = (char *)malloc(sizeof(char)*(strlen(tex_path) + + strlen(texName) + 2)); + + sprintf( texNamePath, "%s/%s", tex_path, texName ); + + if ( texFile ) + texFile << texNamePath << ": " << fileNameExt << "\n"; + + // make sure conversion doesn't already exist + if ( (access( texNamePath, F_OK ) != 0) && !texFile ) + { + char *command = (char *)malloc(sizeof(char)* + (strlen(fileNameExt) + strlen(texNamePath) + 20)); + + sprintf( command, "image-resize -1 %s %s", + fileNameExt, texNamePath ); + + if ( verbose >=1 ) + fprintf( outStream, "executing %s\n", command ); + + system( command ); + + //free( command ); + } + else + if ( verbose >=1 ) + fprintf( outStream, "%s already exists!\n", texNamePath ); + } + else + { + if ( verbose >= 1 ) + { + fprintf( outStream, "Warning: No texture path defined" ); + fprintf( outStream, " - No automatic conversion performed\n" ); + } + } + } + else + { + fprintf( outStream, "Warning: Couldn't find texture file: %s\n", + fileNameExt ); + } + + //free( fileNameExt ); + + if (tex_path) + return( texNamePath ); + else + return( texName ); + } + else + { + fprintf( outStream, "Warning: ConvertTexture received NULL fileName\n" ); + return( NULL ); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: FindClosestTriVert +// Access: Public +// Description: Given an egg vertex pool, map each vertex therein to +// a vertex within an array of SAA model vertices of +// size numVert. Mapping is done by closest proximity. +//////////////////////////////////////////////////////////////////// +int *soft2egg:: +FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ) +{ + int *vertMap = NULL; + int vpoolSize = vpool->NumVertices(); + int i,j; + float thisDist; + float closestDist; + int closest; + + + vertMap = (int *)malloc(sizeof(int)*vpoolSize); + + // for each vertex in vpool + for ( i = 0; i < vpoolSize; i++ ) + { + // find closest model vertex + for ( j = 0; j < numVert-1; j++ ) + { + // calculate distance + thisDist = sqrtf( + powf( vpool->Vertex(i)->position[0] - vertices[j].x , 2 ) + + powf( vpool->Vertex(i)->position[1] - vertices[j].y , 2 ) + + powf( vpool->Vertex(i)->position[2] - vertices[j].z , 2 ) ); + + // remember this if its the closest so far + if ( !j || ( thisDist < closestDist ) ) + { + closest = j; + closestDist = thisDist; + } + } + vertMap[i] = closest; + + if ( verbose >= 2 ) + { + fprintf( outStream, "mapping v %d of %d:( %f, %f, %f )\n", i, + vpoolSize, vpool->Vertex(i)->position[0], + vpool->Vertex(i)->position[1], + vpool->Vertex(i)->position[2] ); + fprintf( outStream, "to cv %d of %d:( %f, %f, %f )\tdelta = %f\n", + closest, numVert-1, vertices[closest].x, vertices[closest].y, + vertices[closest].z, closestDist ); + } + } + + return( vertMap ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeIndexMap +// Access: Public +// Description: Given an array of indices that is a map from one +// set of vertices to another, return an array that +// performs the reverse mapping of the indices array +//////////////////////////////////////////////////////////////////// +int *soft2egg:: +MakeIndexMap( int *indices, int numIndices, int mapSize ) +{ + int i, j; + + // allocate map array + int *map = (int *)malloc(sizeof(int)*mapSize); + + if ( map != NULL ) + { + for ( i = 0; i < mapSize; i++ ) + { + j = 0; + int found = 0; + while( j < numIndices ) + { + if ( indices[j] == i ) + { + map[i] = j; + if ( verbose >= 2 ) + fprintf( outStream, "map[%d] = %d\n", i, map[i] ); + found = 1; + break; + } + j++; + } + if ( !found) + { + if ( verbose >= 2 ) + fprintf( outStream, "Warning: orphan vertex (%d)\n", i ); + // default to -1 for now + map[i] = -1; + } + } + } + else + fprintf( outStream, "Not enough Memory for index Map...\n"); + + + return( map ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: findShapeVert +// Access: Public +// Description: given a vertex, find its corresponding shape vertex +// and return its index. +//////////////////////////////////////////////////////////////////// +int soft2egg:: +findShapeVert( SAA_DVector vertex, SAA_DVector *vertices, int numVert ) +{ + int i; + int found = 0; + + for ( i = 0; i < numVert && !found ; i++ ) + { + if ( ( vertex.x == vertices[i].x ) && + ( vertex.y == vertices[i].y ) && + ( vertex.z == vertices[i].z ) ) + { + found = 1; + + if ( verbose >= 2) + fprintf( outStream, "found shape vert at index %d\n", i ); + } + + } + + if (!found ) + i = -1; + else + i--; + + return( i ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: LoadSoft +// Access: Public +// Description: Open the SI database and grab the scene & model info +//////////////////////////////////////////////////////////////////// +void soft2egg:: +LoadSoft() +{ + int i; + + if ( (scene_name == NULL && model_name == NULL) || database_name == NULL ) + { + Usage(); + exit( 1 ); + } + + if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) + { + fprintf( outStream, "Error: Couldn't get resource path!\n"); + exit( 1 ); + } + + if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) + { + fprintf( outStream, "Error: Couldn't load database!\n"); + exit( 1 ); + } + + if ((result = SAA_sceneGetCurrent(&scene)) == SI_SUCCESS) + { + // load scene if present + if ( scene_name != NULL ) + { + SAA_sceneLoad( &database, scene_name, &scene ); + + // if no egg filename specified, make up a name + if ( eggFileName == NULL ) + { + eggFileName = (char *)malloc(sizeof(char)* + (strlen( scene_name ) + 14 )); + sprintf( eggFileName, "%s", DepointellizeName(scene_name) ); + if ( make_nurbs ) + strcat( eggFileName, "-nurb" ); + strcat( eggFileName, "-mod.egg" ); + } + + // open an output file for the geometry if necessary + if ( make_poly || make_nurbs ) + { + unlink( eggFileName ); + eggFile.open( eggFileName, ios::out, 0666 ); + + if ( !eggFile ) + { + fprintf( outStream, "Couldn't open output file: %s\n", + eggFileName ); + exit( 1 ); + } + } + + // open an output file for texture list if specified + if ( tex_filename != NULL ) + { + unlink( tex_filename ); + texFile.open( tex_filename, ios::out, 0666 ); + + if ( !texFile ) + { + fprintf( outStream, "Couldn't open output file: %s\n", + tex_filename ); + exit( 1 ); + } + } + + if ( SAA_updatelistGet( &scene ) == SI_SUCCESS ) + { + float time; + + fprintf( outStream, "setting Scene to frame %d...\n", pose_frame ); + //SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame ); + SAA_frame2Seconds( &scene, pose_frame, &time ); + SAA_updatelistEvalScene( &scene, time ); + sginap( 100 ); + SAA_updatelistEvalScene( &scene, time ); + if ( make_pose ) + SAA_sceneFreeze( &scene ); + } + + int numModels; + SAA_Elem *models; + + SAA_sceneGetNbModels( &scene, &numModels ); + fprintf( outStream, "Scene has %d model(s)...\n", numModels ); + + if ( numModels ) + { + // allocate array of models + models = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numModels); + + if ( models != NULL ) + { + char *rootName = GetRootName( eggFileName ); + + + if ( eggGroupName == NULL ) + dart = _data.CreateGroup( NULL, rootName ); + else + dart = _data.CreateGroup( NULL, eggGroupName ); + + if (make_dart) + dart->flags |= EF_DART; + + AnimGroup *rootTable; + + rootTable = animData.CreateTable( NULL, eggFileName ); + + if ( eggGroupName == NULL ) + animRoot = animData.CreateBundle( rootTable, rootName ); + else + animRoot = animData.CreateBundle( rootTable, + eggGroupName ); + + // propagate commet to anim data + animData.root_group.children.push_front( + new EggComment( _commandLine ) ); + + if ( verbose >= 1 ) + fprintf( outStream, "made animRoot: %s\n", rootName ); + + SAA_sceneGetModels( &scene, numModels, models ); + + for ( i = 0; i < numModels; i++ ) + { + int level; + + SAA_elementGetHierarchyLevel( &scene, &models[i], &level ); + if ( !level ) + { + if ( verbose >= 1 ) + fprintf( outStream, + "\negging scene model[%d]\n", i ); + + MakeEgg( dart, NULL, NULL, &scene, &models[i] ); + } + } + + if ( make_poly || make_nurbs ) + { + // generate soft skinning assignments if desired + // + //disabled 1/1/99 to streamline joint assignments. + // all joint assignments now done here. Hard & Soft. + //if ( make_soft) + { + char *name; + char *fullname; + SAA_Boolean isSkeleton; + + // search through models and look for skeleton parts + for ( i = 0; i < numModels; i++ ) + { + SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton ); + + // get fullname for splitting files, but + // only use it in file if requested + fullname = GetFullName( &scene, &models[i] ); + if ( use_prefix ) + name = fullname; + else + name = GetName( &scene, &models[i] ); + + // split + if ( strstr( fullname, search_prefix ) != NULL ) + { + // for every skel part: get soft skin info + if ( isSkeleton ) + MakeSoftSkin( &scene, &models[i], models, + numModels, name ); + } + + //free( name ); + } + + // make sure all vertices were assigned + // via soft skinning - if not hard assign them + for ( i = 0; i < numModels; i++ ) + { + // get fullname for splitting files, but + // only use it in file if requested + fullname = GetFullName( &scene, &models[i] ); + if ( use_prefix ) + name = fullname; + else + name = GetName( &scene, &models[i] ); + + // split + if ( strstr( fullname, search_prefix ) != NULL ) + CleanUpSoftSkin( &scene, &models[i], name ); + + //free( name ); + } + + } + + + // put the skeleton data into the egg data + dart->StealChildren( *skeleton ); + + // make sure all elements have unique names + _data.UniquifyNames(); + + // write out the geometry data if requested + //if ( make_poly || make_nurbs ) + //{ + eggFile << _data << "\n"; + fprintf( outStream, "\nwriting out %s...\n", eggFileName ); + eggFile.close(); + } + + // close texture list file if opened + if ( texFile ) + texFile.close(); + + // generate animation data if desired + if ( make_anim ) + { + if ( animFileName == NULL ) + { + animFileName = (char *)malloc(sizeof(char)* + (strlen(scene_name)+ 10 )); + sprintf( animFileName, "%s", DepointellizeName(scene_name) ); + strcat( animFileName, "-chan.egg" ); + } + + unlink( animFileName ); + animFile.open( animFileName, ios::out, 0666 ); + + if ( !animFile ) + { + fprintf( outStream, "Couldn't open output file: %s\n", + animFileName ); + exit( 1 ); + } + + int frame; + //int frameStep; + float time; + + // get all the animation frame info if not specified + // on the command line + if (anim_start == -1000) + SAA_sceneGetPlayCtrlStartFrame( &scene, &anim_start ); + + if (anim_end == -1000) + SAA_sceneGetPlayCtrlEndFrame( &scene, &anim_end ); + + //SAA_sceneGetPlayCtrlFrameStep( &scene, &frameStep ); + + fprintf( outStream, "\nframeStart = %d\n", anim_start ); + fprintf( outStream, "frameEnd = %d\n", anim_end ); + //fprintf( outStream, "frameStep = %d\n", frameStep ); + + // start at first frame and go to last + for ( frame = anim_start; frame <= anim_end; + frame += 1) + { + SAA_frame2Seconds( &scene, frame, &time ); + SAA_updatelistEvalScene( &scene, time ); + sginap( 100 ); + SAA_updatelistEvalScene( &scene, time ); + fprintf( outStream, "\n> animating frame %d\n", frame ); + + // for each model + for ( i = 0; i < numModels; i++ ) + { + char *name; + char *fullname; + SAA_Boolean isSkeleton; + SAA_ModelType type; + + SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton ); + + // get fullname for splitting files, but + // only use it in file if requested + fullname = GetFullName( &scene, &models[i] ); + if ( use_prefix ) + name = fullname; + else + name = GetName( &scene, &models[i] ); + + // split + if ( strstr( fullname, search_prefix ) != NULL ) + { + // make the morph table for this critter + if ( make_morph ) + { + MakeMorphTable( &scene, &models[i], models, + numModels, name, time ); + } + } + + // find out what type of node we're dealing with + result = SAA_modelGetType( &scene, &models[i], &type ); + + int size; + + // check for uv texture animation + SAA_elementGetUserDataSize( &scene, &models[i], + "TEX_OFFSETS", &size ); + + // if so, update for this frame if desired + if ( ( size != 0 ) && make_duv ) + MakeTexAnim( &scene, &models[i], name ); + + // if we have a skeleton or something that acts + // like one - build anim tables + if ( isSkeleton || + ( strstr( name, "joint") != NULL ) ) + MakeAnimTable( &scene, &models[i], name ); + + //free( name ); + } + + if ( verbose >= 1 ) + fprintf( outStream, "\n" ); + } + + animFile << animData << "\n"; + fprintf( outStream, "\nwriting out %s...\n", animFileName ); + animFile.close(); + } + + //free( models ); + + } + else + fprintf( outStream, "Error: Not enough Memory for models...\n"); + } + } + // otherwise try to load a model + else if ( model_name != NULL ) + { + + if ( eggFileName == NULL ) + { + eggFileName = + (char *)malloc(sizeof(char)*(strlen( model_name )+13)); + sprintf( eggFileName, "%s", DepointellizeName( model_name ) ); + + if ( make_nurbs ) + strcat( eggFileName, "-nurb" ); + strcat( eggFileName, "-mod.egg" ); + } + + eggFile.open( eggFileName ); + + if ( !eggFile ) + { + fprintf( outStream, "Couldn't open output file: %s\n", + eggFileName ); + exit( 1 ); + } + + if ((result = + SAA_elementLoad(&database, &scene, model_name, &model)) + == SI_SUCCESS) + { + fprintf( outStream, "Loading single model...\n"); + MakeEgg( NULL, NULL, NULL, &scene, &model ); + } + + eggFile << _data << "\n"; + } + } + +} + +//////////////////////////////////////////////////////////////////// +// Function: MakeEgg +// Access: Public +// Description: Make egg geometry from a given model. This include +// textures, tex coords, colors, normals, and joints. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeEgg( EggGroup *parent, EggJoint *lastJoint, AnimGroup *lastAnim, + SAA_Scene *scene, SAA_Elem *model ) +{ + char *name; + char *fullname; + SAA_ModelType type; + int id = 0; + int numShapes; + int numTri; + int numVert; + int numTexLoc = 0; + int numTexGlb = 0; + int i, j; + float matrix[4][4]; + float *uScale = NULL; + float *vScale = NULL; + float *uOffset = NULL; + float *vOffset = NULL; + SAA_Boolean uv_swap = FALSE; + void *relinfo; + SAA_SubElem *triangles = NULL; + SAA_Elem *materials = NULL; + SAA_SubElem *cvertices = NULL; + SAA_DVector *cvertPos = NULL; + SAA_DVector *vertices = NULL; + SAA_DVector *normals = NULL; + int *indices = NULL; + int *indexMap = NULL; + int *numTexTri = NULL; + SAA_Elem *textures = NULL; + char **texNameArray; + float *uCoords = NULL; + float *vCoords = NULL; + SAA_GeomType gtype = SAA_GEOM_ORIGINAL; + SAA_Boolean visible; + + ///////////////////////////////////////////////// + // find out what type of node we're dealing with + ///////////////////////////////////////////////// + result = SAA_modelGetType( scene, model, &type ); + + if ( verbose >= 1 ) + { + if ( type == SAA_MNILL ) + fprintf( outStream, "encountered null\n"); + else if ( type == SAA_MPTCH ) + fprintf( outStream, "encountered patch\n" ); + else if ( type == SAA_MFACE ) + fprintf( outStream, "encountered face\n" ); + else if ( type == SAA_MSMSH ) + fprintf( outStream, "encountered mesh\n" ); + else if ( type == SAA_MJNT ) + fprintf( outStream, "encountered joint\n" ); + else if ( type == SAA_MSPLN ) + fprintf( outStream, "encountered spline\n" ); + else if ( type == SAA_MMETA ) + fprintf( outStream, "encountered meta element\n" ); + else if ( type == SAA_MBALL ) + fprintf( outStream, "encountered metaball\n" ); + else if ( type == SAA_MNCRV ) + fprintf( outStream, "encountered nurb curve\n" ); + else if ( type == SAA_MNSRF ) + fprintf( outStream, "encountered nurbs surf\n" ); + else + fprintf( outStream, "encountered unknown type: %d\n", type ); + } + + ///////////////////////////// + // Get the name of the model + ///////////////////////////// + + // Get the FULL name of the model + fullname = GetFullName( scene, model ); + + if ( use_prefix ) + { + // Get the FULL name of the trim curve + name = fullname; + } + else + { + // Get the name of the trim curve + name = GetName( scene, model ); + } + + if ( verbose >= 1 ) + fprintf( outStream, "element name <%s>\n", name ); + + fflush( outStream ); + + // get the model's matrix + SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); + + if ( verbose >= 2 ) + { + fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[0][0], + matrix[0][1], matrix[0][2], matrix[0][3] ); + fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[1][0], + matrix[1][1], matrix[1][2], matrix[1][3] ); + fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[2][0], + matrix[2][1], matrix[2][2], matrix[2][3] ); + fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[3][0], + matrix[3][1], matrix[3][2], matrix[3][3] ); + } + + /////////////////////////////////////////////////////////////////////// + // check to see if this is a branch we don't want to descend - this + // will prevent creating geometry for animation control structures + /////////////////////////////////////////////////////////////////////// + if ( (strstr( name, "con-" ) == NULL) && + (strstr( name, "con_" ) == NULL) && + (strstr( name, "fly_" ) == NULL) && + (strstr( name, "fly-" ) == NULL) && + (strstr( name, "camRIG" ) == NULL) && + (strstr( name, "bars" ) == NULL) && + // split + (strstr( fullname, search_prefix ) != NULL) ) + { + + // if making a pose - get deformed geometry + if ( make_pose ) + gtype = SAA_GEOM_DEFORMED; + + // Get the number of key shapes + SAA_modelGetNbShapes( scene, model, &numShapes ); + if ( verbose >= 1 ) + fprintf( outStream, "MakeEgg: num shapes: %d\n", numShapes); + + /////////////////////////////////////////////////////////////////////// + // if multiple key shapes exist create table entries for each + /////////////////////////////////////////////////////////////////////// + if ( (numShapes > 0) && make_morph ) + { + has_morph = 1; + + // make sure root morph table exists + if ( morphRoot == NULL ) + morphRoot = animData.CreateTable( animRoot, "morph" ); + + char *tableName; + + // create morph table entry for each key shape + // (start at second shape - as first is the original geometry) + for ( i = 1; i < numShapes; i++ ) + { + tableName = MakeTableName( name, i ); + SAnimTable *table = new SAnimTable( ); + table->name = tableName; + table->fps = anim_rate; + morphRoot->children.push_back( table ); + if ( verbose >= 1 ) + fprintf( outStream, "created table named: '%s'\n", tableName ); + } + + //free( tableName ); + } + + SAA_modelGetNodeVisibility( scene, model, &visible ); + if ( verbose >= 1 ) + fprintf( outStream, "model visibility: %d\n", visible ); + + /////////////////////////////////////////////////////////////////////// + // Only create egg polygon data if: the node is visible, and its not + // a NULL or a Joint, and we're outputing polys (or if we are outputing + // NURBS and the model is a poly mesh or a face) + /////////////////////////////////////////////////////////////////////// + if ( visible && + (type != SAA_MNILL) && + (type != SAA_MJNT) && + ((make_poly || + (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) + || (!make_poly && !make_nurbs && make_duv && + ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) + ) + { + // If the model is a NURBS in soft, set its step before tesselating + if ( type == SAA_MNSRF ) + SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); + + // If the model is a PATCH in soft, set its step before tesselating + else if ( type == SAA_MPTCH ) + SAA_patchSetStep( scene, model, nurbs_step, nurbs_step ); + + // Get the number of triangles + result = SAA_modelGetNbTriangles( scene, model, gtype, id, &numTri); + if ( verbose >= 1 ) + fprintf( outStream, "triangles: %d\n", numTri); + + if ( result != SI_SUCCESS ) + { + if ( verbose >= 1 ) { + fprintf( outStream, + "Error: couldn't get number of triangles!\n" ); + fprintf( outStream, "\tbailing on model: '%s'\n", name ); + } + return; + } + + // check to see if surface is also skeleton... + SAA_Boolean isSkeleton = FALSE; + + SAA_modelIsSkeleton( scene, model, &isSkeleton ); + + // check to see if this surface is used as a skeleton + // or is animated via constraint only ( these nodes are + // tagged by the animator with the keyword "joint" + // somewhere in the nodes name) + if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) + { + if ( verbose >= 1 ) + fprintf( outStream, "animating Polys as joint!!!\n" ); + + MakeJoint( scene, lastJoint, lastAnim, model, name ); + } + + // model is not a null and has no triangles! + if ( !numTri ) + { + if ( verbose >= 1 ) + fprintf( outStream, "no triangles!\n"); + } + else + { + // allocate array of triangles + triangles = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri); + if ( triangles != NULL ) + { + // triangulate model and read the triangles into array + SAA_modelGetTriangles( scene, model, gtype, id, numTri, triangles ); + } + else + fprintf( outStream, "Not enough Memory for triangles...\n"); + + // allocate array of materials + materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri); + if ( materials != NULL ) + { + // read each triangle's material into array + SAA_triangleGetMaterials( scene, model, numTri, triangles, + materials ); + } + else + fprintf( outStream, "Not enough Memory for materials...\n"); + + // allocate array of textures per triangle + numTexTri = (int *)malloc(sizeof(int)*numTri); + + // find out how many local textures per triangle + for ( i = 0; i < numTri; i++ ) + { + result = SAA_materialRelationGetT2DLocNbElements( scene, + &materials[i], FALSE, &relinfo, &numTexTri[i] ); + + // polytex + if ( result == SI_SUCCESS ) + numTexLoc += numTexTri[i]; + } + + // don't need this anymore... + //free( numTexTri ); + + // get local textures if present + if ( numTexLoc ) + { + // ASSUME only one texture per material + textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri); + + for ( i = 0; i < numTri; i++ ) + { + // and read all referenced local textures into array + SAA_materialRelationGetT2DLocElements( scene, &materials[i], + TEX_PER_MAT , &textures[i] ); + } + + if ( verbose >= 1 ) + fprintf( outStream, "numTexLoc = %d\n", numTexLoc); + } + // if no local textures, try to get global textures + else + { + SAA_modelRelationGetT2DGlbNbElements( scene, model, + FALSE, &relinfo, &numTexGlb ); + + if ( numTexGlb ) + { + // ASSUME only one texture per model + textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)); + + // get the referenced texture + SAA_modelRelationGetT2DGlbElements( scene, model, + TEX_PER_MAT, textures ); + + if ( verbose >= 1 ) + fprintf( outStream, "numTexGlb = %d\n", numTexGlb); + } + } + + // allocate array of control vertices + cvertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri*3); + if ( cvertices != NULL ) + { + // read each triangle's control vertices into array + SAA_triangleGetCtrlVertices( scene, model, gtype, id, + numTri, triangles, cvertices ); + + if ( verbose >= 2 ) + { + cvertPos = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3); + SAA_ctrlVertexGetPositions( scene, model, numTri*3, + cvertices, cvertPos); + + for ( i=0; i < numTri*3; i++ ) + { + fprintf( outStream, "cvert[%d] = %f %f %f %f\n", i, + cvertPos[i].x, cvertPos[i].y, cvertPos[i].z, + cvertPos[i].w ); + } + } + } + else + fprintf( outStream, "Not enough Memory for control vertices...\n"); + + // allocate array of control vertex indices + // this array maps from the redundant cvertices array into + // the unique vertices array (cvertices->vertices) + indices = (int *)malloc(sizeof(int)*numTri*3); + if ( indices != NULL ) + { + for ( i=0; i < numTri*3; i++ ) + indices[i] = 0; + + SAA_ctrlVertexGetIndices( scene, model, numTri*3, + cvertices, indices ); + + if ( verbose >= 2 ) + for ( i=0; i < numTri*3; i++ ) + fprintf( outStream, "indices[%d] = %d\n", i, indices[i] ); + } + else + fprintf( outStream, "Not enough Memory for indices...\n"); + + // get number of UNIQUE vertices in model + SAA_modelGetNbTriVertices( scene, model, &numVert ); + + if ( verbose >= 2 ) + fprintf( outStream, "num unique verts = %d\n", numVert ); + + //allocate array of vertices + vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert); + + // get the UNIQUE vertices of all triangles in model + SAA_modelGetTriVertices( scene, model, numVert, vertices ); + + if ( verbose >= 2 ) + { + for ( i=0; i < numVert; i++ ) + { + fprintf( outStream, "vertices[%d] = %f ", i, vertices[i].x ); + fprintf( outStream, "%f %f %f\n", vertices[i].y, + vertices[i].z, vertices[i].w ); + } + } + + // allocate indexMap array + // we contruct this array to map from the unique vertices + // array to the redundant cvertices array - it will save + // us from doing repetitive searches later + indexMap = MakeIndexMap( indices, numTri*3, numVert ); + + // allocate array of normals + normals = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3); + if ( normals != NULL ) + { + // read each control vertex's normals into an array + SAA_ctrlVertexGetNormals( scene, model, numTri*3, + cvertices, normals ); + } + else + fprintf( outStream, "Not enough Memory for normals...\n"); + + if ( verbose >= 2 ) + { + for ( i=0; i= 2 ) + { + for ( i=0; i= 2 ) + fprintf( outStream, " tritex[%d] named: %s\n", i, + texNameArray[i] ); + + SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap ); + + if ( verbose >= 2 ) + if ( uv_swap == TRUE ) + fprintf( outStream, " swapping u and v...\n" ); + + SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] ); + SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] ); + SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] ); + SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] ); + + if ( verbose >= 2 ) + { + fprintf(outStream, "tritex[%d] uScale: %f vScale: %f\n", i, uScale[i], vScale[i] ); + fprintf(outStream, " uOffset: %f vOffset: %f\n", + uOffset[i], vOffset[i] ); + } + + + SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat, + &vRepeat ); + + if ( verbose >= 2 ) + { + fprintf(outStream, "uRepeat = %d, vRepeat = %d\n", + uRepeat, vRepeat ); + } + } + else + { + if ( verbose >= 2 ) + { + fprintf( outStream, "Invalid texture...\n"); + fprintf( outStream, " tritex[%d] named: (null)\n", i ); + } + } + } + + //debug + //for ( i = 0; i < numTri; i++ ) + //{ + //if ( texNameArray[i] != NULL ) + //fprintf( outStream, " tritex[%d] named: %s\n", i, + //texNameArray[i] ); + //else + //fprintf( outStream, " tritex[%d] named: (null)\n", i ); + //} + } + // make sure we have textures before we get t-coords + else if ( numTexGlb ) + { + SAA_Boolean valid; + + // check to see if texture is present + SAA_elementIsValid( scene, textures, &valid ); + + // texture present - get the name and uv info + if ( valid ) + { + SAA_texture2DGetUVSwap( scene, textures, &uv_swap ); + + if ( verbose >= 1 ) + if ( uv_swap == TRUE ) + fprintf( outStream, " swapping u and v...\n" ); + + // allocate arrays for u & v coords + uCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); + vCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); + + for ( i = 0; i < numTri*numTexGlb*3; i++ ) + { + uCoords[i] = vCoords[i] = 0.0f; + } + + // read the u & v coords into the arrays + if ( uCoords != NULL && vCoords != NULL) + { + SAA_triCtrlVertexGetGlobalUVTxtCoords( scene, model, + numTri*3, cvertices, numTexGlb, textures, + uCoords, vCoords ); + } + else + fprintf( outStream, "Not enough Memory for texture coords...\n"); + + if ( verbose >= 2 ) + { + for ( i=0; i= 1 ) + fprintf( outStream, " global tex named: %s\n", + texNameArray ); + + // allocate arrays of texture info + uScale = ( float *)malloc(sizeof(float)); + vScale = ( float *)malloc(sizeof(float)); + uOffset = ( float *)malloc(sizeof(float)); + vOffset = ( float *)malloc(sizeof(float)); + + SAA_texture2DGetUScale( scene, textures, uScale ); + SAA_texture2DGetVScale( scene, textures, vScale ); + SAA_texture2DGetUOffset( scene, textures, uOffset ); + SAA_texture2DGetVOffset( scene, textures, vOffset ); + + if ( verbose >= 1 ) + { + fprintf( outStream, " global tex uScale: %f vScale: %f\n", + *uScale, *vScale ); + fprintf( outStream, " uOffset: %f vOffset: %f\n", + *uOffset, *vOffset ); + } + + SAA_texture2DGetRepeats( scene, textures, &uRepeat, + &vRepeat ); + + if ( verbose >= 2 ) + { + fprintf(outStream, "uRepeat = %d, vRepeat = %d\n", + uRepeat, vRepeat ); + } + } + else fprintf( outStream, "Invalid texture...\n"); + } + + // make the egg vertex pool + EggVertexPool *pool = _data.CreateVertexPool( parent, name ); + + for ( i = 0; i < numVert; i++ ) + { + pfVec3 eggVert; + pfVec3 eggNorm; + + //convert to global coords + SAA_DVector local = vertices[i]; + SAA_DVector global; + + _VCT_X_MAT( global, local, matrix ); + + // set vertices array to reflect global coords + //vertices[i].x = global.x; + //vertices[i].y = global.y; + //vertices[i].z = global.z; + + //eggVert.set( vertices[i].x, vertices[i].y, vertices[i].z ); + + // we'll preserve original verts for now + eggVert.set( global.x, global.y, global.z ); + + local = normals[indexMap[i]]; + + _VCT_X_MAT( global, local, matrix ); + + eggNorm.set( global.x, global.y, global.z ); + eggNorm.normalize(); + + pool->AddVertex( eggVert, i ); + pool->Vertex(i)->attrib.SetNormal( eggNorm ); + + // translate local uv's to global and add to vertex pool + if ( numTexLoc && (uCoords != NULL && vCoords !=NULL )) + { + float u, v; + + if ( ignore_tex_offsets ) { + u = uCoords[indexMap[i]]; + v = 1.0f - vCoords[indexMap[i]]; + } else { + u = (uCoords[indexMap[i]] - uOffset[indexMap[i]/3]) / + uScale[indexMap[i]/3]; + + v = 1.0f - ((vCoords[indexMap[i]] - vOffset[indexMap[i]/3]) / + vScale[indexMap[i]/3]); + } + + if ( isNum(u) && isNum(v) ) + { + if ( uv_swap == TRUE ) + pool->Vertex(i)->attrib.SetUV( v, u ); + else + pool->Vertex(i)->attrib.SetUV( u, v ); + } + } + else if ( numTexGlb && (uCoords != NULL && vCoords !=NULL ) ) + { + float u, v; + + if ( ignore_tex_offsets ) { + u = uCoords[indexMap[i]]; + v = 1.0f - vCoords[indexMap[i]]; + } else { + u = (uCoords[indexMap[i]] - *uOffset) / *uScale; + v = 1.0f - (( vCoords[indexMap[i]] - *vOffset ) / *vScale); + } + + if ( isNum(u) && isNum(v) ) + { + if ( uv_swap == TRUE ) + pool->Vertex(i)->attrib.SetUV( v, u ); + else + pool->Vertex(i)->attrib.SetUV( u, v ); + } + + } + + // if we've encountered textures and we desire duv anims + if (( numTexLoc || numTexGlb ) && make_duv ) + { + int numExp; + SAA_Elem *tex; + + // grab the current texture + if ( numTexLoc ) + tex = &textures[0]; + else + tex = textures; + + // find how many expressions for this shape + SAA_elementGetNbExpressions( scene, tex, NULL, FALSE, + &numExp ); + + // if it has expressions we'll assume its animated + if ( numExp ) + { + // if animated object make base duv's, animtables + // for the duv's and store the original offsets + strstream uName, vName; + + // create duv target names + uName << name << ".u" << ends; + vName << name << ".v" << ends; + + // only create tables and store offsets + // on a per model basis (not per vertex) + if ( !i ) + { + + // make sure root morph table exists + if ( morphRoot == NULL ) + morphRoot = animData.CreateTable( animRoot, + "morph" ); + + // create morph table entry for each duv + SAnimTable *uTable = new SAnimTable( ); + uTable->name = uName.str(); + uTable->fps = anim_rate; + morphRoot->children.push_back( uTable ); + if ( verbose >= 1 ) + fprintf( outStream, "created duv table named: %s\n", uName.str() ); + + SAnimTable *vTable = new SAnimTable( ); + vTable->name = vName.str(); + vTable->fps = anim_rate; + morphRoot->children.push_back( vTable ); + if ( verbose >= 1 ) + fprintf( outStream, "created duv table named: %s\n", vName.str() ); + + float texOffsets[4]; + + if ( numTexGlb ) + { + texOffsets[0] = *uOffset; + texOffsets[1] = *vOffset; + texOffsets[2] = *uScale; + texOffsets[3] = *vScale; + } + else + { + texOffsets[0] = uOffset[indexMap[i]/3]; + texOffsets[1] = vOffset[indexMap[i]/3]; + texOffsets[2] = uScale[indexMap[i]/3]; + texOffsets[3] = vScale[indexMap[i]/3]; + } + + // remember original texture offsets future reference + SAA_elementSetUserData( scene, model, "TEX_OFFSETS", + sizeof( texOffsets ), TRUE, (void **)&texOffsets ); + } + + EggMorphOffset *duvU; + EggMorphOffset *duvV; + + // generate base duv's for this vertex + duvU = new EggMorphOffset( uName.str(), 1.0 , 0.0 ); + pool->Vertex(i)->attrib.uv_morphs.push_back( *duvU ); + + duvV = new EggMorphOffset( vName.str(), 0.0 , 1.0 ); + pool->Vertex(i)->attrib.uv_morphs.push_back( *duvV ); + + } // if ( numExp ) + + } // if ( numTexLoc || numTexGlb ) + + } // for ( i = 0; i < numVert; i++ ) + + // if model has key shapes, generate vertex offsets + if ( has_morph && make_morph ) + MakeVertexOffsets( scene, model, type, numShapes, numVert, + vertices, matrix, name ); + + + // create vertex ref list for all polygons in the model + EggVertexRef *vref; + + vref = new EggVertexRef( pool); + for ( i = 0; i < numVert; i++ ) + { + //add each vert in pool to last joint for hard skinning + vref->indices.push_back( EggVertexIndex( i ) ); + } + + // hard assign poly geometry if no soft-skinning requested + // + //disabled 1/1/99 to streamline joint assignments. + // all hard-skinning now done in CleanUpSoftSkin. + //if ( !make_soft ) + //{ + //if ( lastJoint != NULL ) + //{ + //lastJoint->vrefs.AddUniqueNode( *vref ); + + //if ( verbose >= 1 ) + //fprintf( outStream, "hard-skinning %s (%d vertices)\n", + //name, i+1 ); + //} + //} + + // make an egg group to hold all triangles + EggGroup *group = _data.CreateGroup( parent, name); + + // make this group the current parent + parent = group; + + EggPolygon *poly = NULL; + EggColor *cref = NULL; + EggTexture *tref = NULL; + + // for each triangle + for ( i = 0; i < numTri*3; i+=3 ) + { + float r,g,b,a; + pfVec4 color; + + // make egg poly for each traingle and reference + // the appropriate vertex in the pool + poly = _data.CreatePolygon( group, pool ); + poly->AddVertex(indices[i]); + poly->AddVertex(indices[i+1]); + poly->AddVertex(indices[i+2]); + + // check for back face flag in model note info + char *modelNoteStr = GetModelNoteInfo( scene, model ); + + if ( modelNoteStr != NULL ) + { + if ( strstr( modelNoteStr, "bface" ) != NULL ) + poly->flags |= EG_BFACE; + } + + // check to see if material is present + SAA_Boolean valid; + SAA_elementIsValid( scene, &materials[i/3], &valid ); + + // material present - get the color + if ( valid ) + { + SAA_materialGetDiffuse( scene, &materials[i/3], &r, &g, &b ); + SAA_materialGetTransparency( scene, &materials[i/3], &a ); + color.set( r, g, b, 1.0f - a ); + } + // no material - default to white + else + color.set( 1.0, 1.0, 1.0, 1.0 ); + + cref = _data.CreateColor(color); + poly->attrib.SetCRef(cref); + + strstream uniqueTexName; + + if (numTexLoc) + { + // polytex + if ( (texNameArray[i/3] != NULL) && + (strcmp(texNameArray[i/3], "NULL") != 0) ) + { + // append unique identifier to texname for + // this particular object + uniqueTexName << name << "-" + << RemovePathName(texNameArray[i/3]); + + tref = _data.CreateTexture( texNameArray[i/3], + uniqueTexName.str() ); + + if ( verbose >= 1 ) + fprintf( outStream, " tritex[%d] named: %s\n", i/3, + texNameArray[i/3] ); + } + } + else if ( numTexGlb ) + { + if ( texNameArray != NULL ) + { + // append unique identifier to texname for + // this particular object + uniqueTexName << name << "-" + << RemovePathName(*texNameArray); + + tref = _data.CreateTexture( *texNameArray, + uniqueTexName.str() ); + + if ( verbose >= 1 ) + fprintf( outStream, " tritex named: %s\n", + *texNameArray ); + } + } + + // set the clamp on the texture + if ( tref != NULL ) + { + if ( uRepeat > 0 ) + tref->wrapu = EggTexture::WM_repeat; + else + tref->wrapu = EggTexture::WM_clamp; + + if ( vRepeat > 1 ) + tref->wrapv = EggTexture::WM_repeat; + else + tref->wrapv = EggTexture::WM_clamp; + + poly->attrib.SetTRef(tref); + } + + } + + // we're done - trash triangles... + SAA_modelClearTriangles( scene, model ); + + // free molloc'd memory + //free( triangles ); + //free( materials ); + //free( normals ); + //free( cvertices ); + //free( vertices ); + //free( indices ); + //free( indexMap ); + + // free these only if they were malloc'd for textures + if (numTexLoc || numTexGlb) + { + //free( textures ); + //free( uCoords ); + //free( vCoords ); + //free( texNameArray ); + //free( uScale ); + //free( vScale ); + //free( uOffset ); + //free( vOffset ); + } + } + } + else + { + /////////////////////////////////////// + // check to see if its a nurbs surface + /////////////////////////////////////// + if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs ) + || ( !make_nurbs && !make_poly && make_duv )) ) + { + // check to see if NURBS is also skeleton... + SAA_Boolean isSkeleton = FALSE; + + SAA_modelIsSkeleton( scene, model, &isSkeleton ); + + // check to see if this NURBS is used as a skeleton + // or is animated via constraint only ( these nodes are + // tagged by the animator with the keyword "joint" + // somewhere in the nodes name) + if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) + { + MakeJoint( scene, lastJoint, lastAnim, model, name ); + geom_as_joint = 1; + if ( verbose >= 1 ) + fprintf( outStream, "animating NURBS as joint!!!\n" ); + } + + EggNurbsSurface *eggNurbsSurf = new EggNurbsSurface( name ); + int uDegree, vDegree; + + // create nurbs representation of surface + SAA_nurbsSurfaceGetDegree( scene, model, &uDegree, &vDegree ); + eggNurbsSurf->u_order = uDegree + 1; + eggNurbsSurf->v_order = vDegree + 1; + if ( verbose >= 1 ) + { + fprintf( outStream, "nurbs degree: %d u, %d v\n", + uDegree, vDegree ); + fprintf( outStream, "nurbs order: %d u, %d v\n", + uDegree + 1, vDegree + 1 ); + } + + SAA_Boolean uClosed = FALSE; + SAA_Boolean vClosed = FALSE; + + SAA_nurbsSurfaceGetClosed( scene, model, &uClosed, &vClosed); + + if ( verbose >= 1 ) + { + if ( uClosed ) + fprintf( outStream, "nurbs is closed in u...\n"); + if ( vClosed ) + fprintf( outStream, "nurbs is closed in v...\n"); + } + + int uRows, vRows; + SAA_nurbsSurfaceGetNbVertices( scene, model, &uRows, &vRows ); + if ( verbose >= 1 ) + fprintf( outStream, "nurbs vertices: %d u, %d v\n", + uRows, vRows ); + + int uCurves, vCurves; + SAA_nurbsSurfaceGetNbCurves( scene, model, &uCurves, &vCurves ); + if ( verbose >= 1 ) + fprintf( outStream, "nurbs curves: %d u, %d v\n", + uCurves, vCurves ); + + if ( shift_textures ) + { + if ( uClosed ) + // shift starting point on NURBS surface for correct textures + SAA_nurbsSurfaceShiftParameterization( scene, model, -2, 0 ); + + if ( vClosed ) + // shift starting point on NURBS surface for correct textures + SAA_nurbsSurfaceShiftParameterization( scene, model, 0, -2 ); + } + + SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); + + // check for back face flag in model note info + char *modelNoteStr = GetModelNoteInfo( scene, model ); + + if ( modelNoteStr != NULL ) + { + if ( strstr( modelNoteStr, "bface" ) != NULL ) + eggNurbsSurf->flags |= EG_BFACE; + } + + int numKnotsU, numKnotsV; + + SAA_nurbsSurfaceGetNbKnots( scene, model, &numKnotsU, &numKnotsV ); + if ( verbose >= 1 ) + fprintf( outStream, "nurbs knots: %d u, %d v\n", + numKnotsU, numKnotsV ); + + double *knotsU, *knotsV; + knotsU = (double *)malloc(sizeof(double)*numKnotsU); + knotsV = (double *)malloc(sizeof(double)*numKnotsV); + SAA_nurbsSurfaceGetKnots( scene, model, gtype, 0, + numKnotsU, numKnotsV, knotsU, knotsV ); + + if ( verbose >= 2 ) + fprintf( outStream, "u knots:\n" ); + + AddKnots( eggNurbsSurf->u_knots, knotsU, numKnotsU, uClosed, uDegree ); + if ( verbose >= 2 ) + fprintf( outStream, "v knots:\n" ); + + AddKnots( eggNurbsSurf->v_knots, knotsV, numKnotsV, vClosed, vDegree); + + //free( knotsU ); + //free( knotsV ); + + // set sub_div so we can see it in perfly + eggNurbsSurf->u_subdiv = (uRows-1)*nurbs_step; + eggNurbsSurf->v_subdiv = (vRows-1)*nurbs_step; + + SAA_modelGetNbVertices( scene, model, &numVert ); + + if ( verbose >= 2 ) + fprintf( outStream, "%d CV's\n", numVert ); + + // get the CV's + vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert); + SAA_modelGetVertices( scene, model, gtype, 0, + numVert, vertices ); + + // create pool of NURBS vertices + EggVertexPool *pool = _data.CreateVertexPool( parent, name ); + eggNurbsSurf->SetVertexPool( pool ); + + // create vertex ref list for all cv's in the model + EggVertexRef *vref; + + vref = new EggVertexRef( pool); + + for ( int k = 0; k= 2 ) + { + fprintf( outStream, "original cv[%d] = %f %f %f %f\n", k, + vertices[k].x, vertices[k].y, vertices[k].z, + vertices[k].w ); + } + + pfVec4 eggVert; + + // convert to global coords + SAA_DVector global; + + _VCT_X_MAT( global, vertices[k], matrix ); + + //preserve original weight + global.w = vertices[k].w; + + // normalize coords to weight + global.x *= global.w; + global.y *= global.w; + global.z *= global.w; + + // this code is commented out because I + // am no longer sending global data to + // the other routines (ie makevertexoffset) + + // set vertices array to reflect global coords + //vertices[k].x = global.x; + //vertices[k].y = global.y; + //vertices[k].z = global.z; + //vertices[k].w = global.w; + + //if ( verbose >= 2 ) + //{ + //fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k, + //vertices[k].x, vertices[k].y, vertices[k].z, + //vertices[k].w ); + //} + + //eggVert.set( vertices[k].x, vertices[k].y, vertices[k].z, + //vertices[k].w ); + + if ( verbose >= 2 ) + { + fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k, + global.x, global.y, global.z, + global.w ); + } + + eggVert.set( global.x, global.y, global.z, + global.w ); + + // populate vertex pool + pool->AddVertex( eggVert, k ); + + // add vref's to NURBS info + eggNurbsSurf->AddVertex( k ); + + //add each vert in pool to vref for hard skinning + vref->indices.push_back( EggVertexIndex( k ) ); + + // check to see if the NURB is closed in u + if ( uClosed ) + { + // add first uDegree verts to end of row + if ( (k % uRows) == ( uRows - 1) ) + for ( int i = 0; i < uDegree; i++ ) + { + // add vref's to NURBS info + eggNurbsSurf->AddVertex( i+((k/uRows)*uRows) ); + + //add each vert to vref + vref->indices.push_back( + EggVertexIndex( i+((k/uRows)*uRows) ) ); + } + } + } + + // if hard skinned or this nurb is also a joint + // + //disabled 1/1/99 to streamline joint assignments. + // all hard skinning now done in CleanUpSoftSkin. + //if (!make_soft || geom_as_joint) + //{ + //add the new cv references to the last + //joint for hard skinning only + //if ( lastJoint != NULL ) + //{ + //lastJoint->vrefs.AddUniqueNode( *vref ); + //geom_as_joint = 0; + //if ( verbose >= 1 ) + //fprintf( outStream, "Doing NURBS hard skinning...\n"); + //} + //} + + // check to see if the NURB is closed in v + if ( vClosed && !uClosed ) + { + // add first vDegree rows of verts to end of list + for ( int i = 0; i < vDegree*uRows; i++ ) + eggNurbsSurf->AddVertex( i ); + } + // check to see if the NURB is closed in u and v + else if ( vClosed && uClosed ) + { + // add the first (degree) v verts and a few + // extra - for good measure + for ( i = 0; i < vDegree; i++ ) + { + // add first vDegree rows of verts to end of list + for ( j = 0; j < uRows; j++ ) + eggNurbsSurf->AddVertex( j+(i*uRows) ); + + // if u is closed to we have added uDegree + // verts onto the ends of the rows - add them here too + for ( k = 0; k < uDegree; k++ ) + eggNurbsSurf->AddVertex( k+(i*uRows)+((k/uRows)*uRows) ); + } + + } + + // get the color of the NURBS surface + int numNurbMats; + EggColor *nurbCref; + pfVec4 nurbColor; + + SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo, + &numNurbMats ); + + if ( verbose >= 1 ) + fprintf( outStream, "nurbs surf has %d materials\n", + numNurbMats ); + + if ( numNurbMats ) + { + float r,g,b,a; + + materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numNurbMats); + + SAA_modelRelationGetMatElements( scene, model, relinfo, + numNurbMats, materials ); + + SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b ); + SAA_materialGetTransparency( scene, &materials[0], &a ); + nurbColor.set( r, g, b, 1.0f - a ); + //nurbColor.set( r, g, b, 1.0 ); + + nurbCref = _data.CreateColor(nurbColor); + eggNurbsSurf->attrib.SetCRef(nurbCref); + + //get the texture of the NURBS surface from the material + int numNurbTexLoc = 0; + int numNurbTexGlb = 0; + + // ASSUME only one texture per material + SAA_Elem nurbTex; + + // find out how many local textures per NURBS surface + // ASSUME it only has one material + SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], + FALSE, &relinfo, &numNurbTexLoc ); + + // if present, get local textures + if ( numNurbTexLoc ) + { + if ( verbose >= 1 ) + fprintf( outStream, "%s had %d local tex\n", name, + numNurbTexLoc ); + + // get the referenced texture + SAA_materialRelationGetT2DLocElements( scene, &materials[0], + TEX_PER_MAT, &nurbTex ); + + } + // if no locals, try to get globals + else + { + SAA_modelRelationGetT2DGlbNbElements( scene, model, + FALSE, &relinfo, &numNurbTexGlb ); + + if ( numNurbTexGlb ) + { + if ( verbose >= 1 ) + fprintf( outStream, "%s had %d global tex\n", name, + numNurbTexGlb ); + + // get the referenced texture + SAA_modelRelationGetT2DGlbElements( scene, + model, TEX_PER_MAT, &nurbTex ); + } + } + + // add tex ref's if we found any textures + if ( numNurbTexLoc || numNurbTexGlb) + { + char *texName = NULL; + char *uniqueTexName = NULL; + EggTexture *tref; + pfMatrix nurbTexMat; + + + // convert the texture to .rgb and adjust name + texName = ConvertTexture( scene, &nurbTex ); + + // append unique identifier to texname for + // this particular object + uniqueTexName = (char *)malloc(sizeof(char)* + (strlen(name)+strlen(texName)+3) ); + sprintf( uniqueTexName, "%s-%s", name, + RemovePathName(texName) ); + + if ( verbose >= 1 ) + { + fprintf( outStream, "creating tref %s\n", + uniqueTexName ); + } + + tref = _data.CreateTexture( texName, uniqueTexName ); + + uScale = ( float *)malloc(sizeof(float)); + vScale = ( float *)malloc(sizeof(float)); + uOffset = ( float *)malloc(sizeof(float)); + vOffset = ( float *)malloc(sizeof(float)); + + // get texture offset info + SAA_texture2DGetUScale( scene, &nurbTex, uScale ); + SAA_texture2DGetVScale( scene, &nurbTex, vScale ); + SAA_texture2DGetUOffset( scene, &nurbTex, uOffset ); + SAA_texture2DGetVOffset( scene, &nurbTex, vOffset ); + SAA_texture2DGetUVSwap( scene, &nurbTex, &uv_swap ); + + + if ( verbose >= 1 ) + { + fprintf( outStream, "nurbTex uScale: %f\n", *uScale ); + fprintf( outStream, "nurbTex vScale: %f\n", *vScale ); + fprintf( outStream, "nurbTex uOffset: %f\n", *uOffset ); + fprintf( outStream, "nurbTex vOffset: %f\n", *vOffset ); + if ( uv_swap ) + fprintf( outStream, "nurbTex u & v swapped!\n" ); + else + fprintf( outStream, "nurbTex u & v NOT swapped\n" ); + } + + nurbTexMat.makeIdent(); + + if ( !ignore_tex_offsets ) + { + if ( uv_swap ) + { + nurbTexMat[0][0] = 0.0f; + nurbTexMat[1][1] = 0.0f; + nurbTexMat[0][1] = 1 / *vScale; + nurbTexMat[1][0] = 1 / *uScale; + nurbTexMat[2][1] = -(*uOffset / *uScale); + nurbTexMat[2][0] = -(*vOffset / *vScale); + } + else + { + nurbTexMat[0][0] = 1 / *uScale; + nurbTexMat[1][1] = 1 / *vScale; + nurbTexMat[2][0] = -(*uOffset / *uScale); + nurbTexMat[2][1] = -(*vOffset / *vScale); + } + } + + + //call printMat + if ( verbose >= 2 ) + { + fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[0][0], + nurbTexMat[0][1], nurbTexMat[0][2], nurbTexMat[0][3] ); + fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[1][0], + nurbTexMat[1][1], nurbTexMat[1][2], nurbTexMat[1][3] ); + fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[2][0], + nurbTexMat[2][1], nurbTexMat[2][2], nurbTexMat[2][3] ); + fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[3][0], + nurbTexMat[3][1], nurbTexMat[3][2], nurbTexMat[3][3] ); + } + + + tref->tex_mat = nurbTexMat; + tref->flags |= EFT_TRANSFORM; + + eggNurbsSurf->attrib.SetTRef(tref); + + } + + // if we've encountered textures and we desire duv anims + if (( numNurbTexLoc || numNurbTexGlb ) && make_duv ) + { + int numExp; + + // find how many expressions for this shape + SAA_elementGetNbExpressions( scene, &nurbTex, NULL, FALSE, + &numExp ); + + // if it has expressions we'll assume its animated + if ( numExp ) + { + if ( verbose > 1 ) + printf( "nurbTex has %d expressions...\n", numExp ); + + // if animated object make base duv's, animtables + // for the duv's and store the original offsets + strstream uName, vName; + + // create duv target names + uName << name << ".u" << ends; + vName << name << ".v" << ends; + + // make sure root morph table exists + if ( morphRoot == NULL ) + morphRoot = animData.CreateTable( animRoot, + "morph" ); + + // create morph table entry for each duv + SAnimTable *uTable = new SAnimTable( ); + uTable->name = uName.str(); + uTable->fps = anim_rate; + morphRoot->children.push_back( uTable ); + if ( verbose >= 1 ) + fprintf( outStream, "created duv table named: %s\n", uName.str() ); + + SAnimTable *vTable = new SAnimTable( ); + vTable->name = vName.str(); + vTable->fps = anim_rate; + morphRoot->children.push_back( vTable ); + if ( verbose >= 1 ) + fprintf( outStream, "created duv table named: %s\n", vName.str() ); + + float texOffsets[4]; + + texOffsets[0] = *uOffset; + texOffsets[1] = *vOffset; + texOffsets[2] = *uScale; + texOffsets[3] = *vScale; + + // remember original texture offsets future reference + SAA_elementSetUserData( scene, model, "TEX_OFFSETS", + sizeof( texOffsets ), TRUE, (void **)&texOffsets ); + + // create UV's and duv's for each vertex + for( i = 0; i < numVert; i++ ) + { + pfVec2 tmpUV; + EggMorphOffset *duvU; + EggMorphOffset *duvV; + + //create uv's so we can store duv's + eggNurbsSurf->CalcActualUV( i, tmpUV ); + pool->Vertex(i)->attrib.SetUV( tmpUV[0], tmpUV[1] ); + + // generate base duv's for this vertex + duvU = new EggMorphOffset(uName.str(), 1.0 , 0.0); + pool->Vertex(i)->attrib.uv_morphs.push_back(*duvU); + + duvV = new EggMorphOffset(vName.str(), 0.0 , 1.0); + pool->Vertex(i)->attrib.uv_morphs.push_back(*duvV); + } + + } // if ( numExp ) + } // if ( numTexLoc || numTexGlb ) + + //free( uScale ); + //free( vScale ); + //free( uOffset ); + //free( vOffset ); + + //free( materials ); + } + else + { + // no material present - default to white + nurbColor.set( 1.0, 1.0, 1.0, 1.0 ); + } + + ////////////////////////////////////////// + // check NURBS surface for trim curves + ////////////////////////////////////////// + int numTrims; + bool isTrim = TRUE; + SAA_SubElem *trims; + + SAA_nurbsSurfaceGetNbTrimCurves( scene, model, SAA_TRIMTYPE_TRIM, + &numTrims ); + + if ( verbose >= 1 ) + fprintf( outStream, "nurbs surf has %d trim curves\n", + numTrims ); + + if ( numTrims) + { + trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims); + + if ( trims ) + { + SAA_nurbsSurfaceGetTrimCurves( scene, model, + gtype, 0, SAA_TRIMTYPE_TRIM, numTrims, + trims ); + + MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, + numTrims, trims, isTrim ); + } + + //free( trims ); + } + + ////////////////////////////////////////// + // check NURBS surface for surface curves + ////////////////////////////////////////// + isTrim = FALSE; + + SAA_nurbsSurfaceGetNbTrimCurves( scene, model, + SAA_TRIMTYPE_PROJECTION, &numTrims ); + + if ( verbose >= 1 ) + fprintf( outStream, "nurbs surf has %d surface curves\n", + numTrims ); + + if ( numTrims) + { + trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims); + + if ( trims ) + { + SAA_nurbsSurfaceGetTrimCurves( scene, model, + gtype, 0, SAA_TRIMTYPE_PROJECTION, + numTrims, trims ); + + MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, + numTrims, trims, isTrim ); + } + + //free( trims ); + } + + // push the NURBS into the egg data + parent->children.push_back( eggNurbsSurf ); + + // if model has key shapes, generate vertex offsets + if ( has_morph && make_morph ) + MakeVertexOffsets( scene, model, type, numShapes, numVert, + vertices, matrix, name ); + + + //free( vertices ); + + } + ///////////////////////////////////// + // check to see if its a NURBS curve + ///////////////////////////////////// + else if ( (type == SAA_MNCRV) && ( visible ) && ( make_nurbs ) ) + { + // ignore for now + // make the NURBS curve and push it into the egg data + //parent->children.push_back( MakeNurbsCurve( scene, model, parent, + //matrix, name ) ); + } + else if ( type == SAA_MJNT ) + { + MakeJoint( scene, lastJoint, lastAnim, model, name ); + if ( verbose >= 1 ) + fprintf( outStream, "encountered IK joint: %s\n", name ); + } + ///////////////////// + // it must be a NULL + ///////////////////// + else + { + SAA_AlgorithmType algo; + + SAA_modelGetAlgorithm( scene, model, &algo ); + if ( verbose >= 1 ) + fprintf( outStream, "null algorithm: %d\n", algo ); + + if ( algo == SAA_ALG_INV_KIN ) + { + MakeJoint( scene, lastJoint, lastAnim, model, name ); + if ( verbose >= 1 ) + fprintf( outStream, "encountered IK root: %s\n", name ); + } + else if ( algo == SAA_ALG_INV_KIN_LEAF ) + { + MakeJoint( scene, lastJoint, lastAnim, model, name ); + if ( verbose >= 1 ) + fprintf( outStream, "encountered IK leaf: %s\n", name ); + } + else if ( algo == SAA_ALG_STANDARD ) + { + SAA_Boolean isSkeleton = FALSE; + + if ( verbose >= 1 ) + fprintf( outStream, "encountered Standard null: %s\n", name); + + SAA_modelIsSkeleton( scene, model, &isSkeleton ); + + // check to see if this NULL is used as a skeleton + // or is animated via constraint only ( these nodes are + // tagged by the animator with the keyword "joint" + // somewhere in the nodes name) + if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) + { + MakeJoint( scene, lastJoint, lastAnim, model, name ); + if ( verbose >= 1 ) + fprintf( outStream, "animating Standard null!!!\n" ); + } + + } + else + if ( verbose >= 1 ) + fprintf( outStream, "encountered some other NULL: %d\n", + algo ); + } + } + + + // check for children... + int numChildren; + int thisChild; + SAA_Elem *children; + + SAA_modelGetNbChildren( scene, model, &numChildren ); + if ( verbose >= 1 ) + fprintf( outStream, "Model children: %d\n", numChildren ); + + if ( numChildren ) + { + children = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numChildren); + SAA_modelGetChildren( scene, model, numChildren, children ); + if ( children != NULL ) + { + for ( thisChild = 0; thisChild < numChildren; thisChild++ ) + { + if ( verbose >= 1 ) + fprintf( outStream, "\negging child %d...\n", thisChild); + MakeEgg( parent, lastJoint, lastAnim, scene, + &children[thisChild] ); + } + } + else + fprintf( outStream, "Not enough Memory for children...\n"); + //free( children ); + } + fflush( outStream ); + } + else + if ( verbose >= 1 ) + fprintf( outStream, "Don't descend this branch!\n" ); + + // we are done for the most part - start cleaning up memory + //free( name ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeSurfaceCurve +// Access: Public +// Description: Given a scene and lists of u and v samples create a +// an egg NURBS curve of degree two from the samples +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeSurfaceCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, + EggNurbsSurface *&nurbsSurf, int numTrims, SAA_SubElem *trims, + bool isTrim ) +{ + int i; + long totalSamples = 0; + long *numSamples; + double *uSamples; + double *vSamples; + SAA_Elem *trimCurves; + char *name; + + //get UV coord data + numSamples = (long *)malloc(sizeof(long)*numTrims); + + SAA_surfaceCurveGetNbLinearSamples( scene, model, numTrims, trims, + numSamples ); + + for ( i = 0; i < numTrims; i++ ) + { + totalSamples += numSamples[i]; + if ( verbose >= 2 ) + fprintf( outStream, "numSamples[%d] = %d\n", i, numSamples[i] ); + } + + if ( verbose >= 2 ) + fprintf( outStream, "total samples = %ld\n", totalSamples ); + + uSamples = (double *)malloc(sizeof(double)*totalSamples); + vSamples = (double *)malloc(sizeof(double)*totalSamples); + + SAA_surfaceCurveGetLinearSamples( scene, model, numTrims, trims, + numSamples, uSamples, vSamples ); + + if ( verbose >= 2 ) + for ( long li = 0; li < totalSamples; li++ ) + fprintf( outStream, "master list cv[%ld] = %f, %f\n", li, + uSamples[li], vSamples[li] ); + + trimCurves = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTrims); + + SAA_surfaceCurveExtract( scene, model, numTrims, trims, trimCurves ); + + // if it's a trim create a trim to assign trim curves to + EggNurbsSurface::Trim *eggTrim = new EggNurbsSurface::Trim(); + + // for each trim curve, make an egg curve and + // add it to the trims of the NURBS surface + for ( i = 0; i < numTrims; i++ ) + { + if ( use_prefix ) + { + // Get the FULL name of the trim curve + name = GetFullName( scene, &trimCurves[i] ); + } + else + { + // Get the name of the trim curve + name = GetName( scene, &trimCurves[i] ); + } + + if ( isTrim ) + { + // add to trim list + EggNurbsSurface::Loop *eggLoop = new EggNurbsSurface::Loop(); + eggLoop->push_back( MakeUVNurbsCurve( i, numSamples, uSamples, + vSamples, parent, name ) ); + eggTrim->push_back( *eggLoop ); + } + else + // add to curve list + nurbsSurf->curves.push_back( MakeUVNurbsCurve( i, numSamples, uSamples, vSamples, parent, name ) ); + } + + if ( isTrim ) + // pus trim list onto trims list + nurbsSurf->trims.push_back( *eggTrim ); + + //free( name ); + //free( trimCurves ); + //free( uSamples ); + //free( vSamples ); +} + +//////////////////////////////////////////////////////////////////// +// Function: MakeUVNurbsCurve +// Access: Public +// Description: Given a scene and lists of u and v samples create a +// an egg NURBS curve of degree two from the samples +//////////////////////////////////////////////////////////////////// +EggNurbsCurve *soft2egg:: +MakeUVNurbsCurve( int numCurve, long *numSamples, double *uSamples, + double *vSamples, EggGroup *parent, char *name ) +{ + EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name ); + + eggNurbsCurve->order = 2; + + + if ( verbose >= 2 ) + fprintf( outStream, "nurbs UV curve %s:\n", name ); + + //set sub_div so we can see it in perfly + //eggNurbsCurve->subdiv = numSamples[numCurve]/4; + // perfly chokes on big numbers - keep it reasonable + eggNurbsCurve->subdiv = 150; + + //create pool of NURBS vertices + EggVertexPool *pool = _data.CreateVertexPool( parent, name ); + eggNurbsCurve->SetVertexPool( pool ); + + // calculate offset to this curve's samples + // in list of all curve samples + int offset = 0; + + for ( int o = 0; o < numCurve; o++ ) + offset += numSamples[o]; + + for ( int k = 0; k= 2 ) + fprintf( outStream, "cv[%d] = %f %f %f\n", k, eggVert[0], + eggVert[1], eggVert[2] ); + + //populate vertex pool + pool->AddVertex( eggVert, k ); + + //add vref's to NURBS info + eggNurbsCurve->AddVertex( k ); + } + + // create numSamples[numCurve]+2 knots + eggNurbsCurve->knots.push_back( 0 ); + for ( k = 0; k < numSamples[numCurve]; k++ ) + eggNurbsCurve->knots.push_back( k ); + eggNurbsCurve->knots.push_back( numSamples[numCurve] - 1 ); + + //set color to bright green for now + EggColor *nurbCref; + pfVec4 nurbColor; + + nurbColor.set( 0.5, 1.0, 0.5, 1.0 ); + nurbCref = _data.CreateColor(nurbColor); + eggNurbsCurve->attrib.SetCRef(nurbCref); + + return( eggNurbsCurve ); +} + +//////////////////////////////////////////////////////////////////// +// Function: MakeNurbsCurve +// Access: Public +// Description: Given a scene and a NURBS curve model create the +// the appropriate egg structures +//////////////////////////////////////////////////////////////////// +EggNurbsCurve *soft2egg:: +MakeNurbsCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, + float matrix[4][4], char *name ) +{ + EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name ); + int degree; + + if ( verbose >= 2 ) + fprintf( outStream, "nurbs curve %s:\n", name ); + + //create nurbs representation of surface + SAA_nurbsCurveGetDegree( scene, model, °ree ); + eggNurbsCurve->order = degree + 1; + if ( verbose >= 2 ) + fprintf( outStream, "nurbs curve order: %d\n", degree + 1 ); + + SAA_nurbsCurveSetStep( scene, model, nurbs_step ); + + SAA_Boolean closed = FALSE; + + SAA_nurbsCurveGetClosed( scene, model, &closed ); + if ( closed ) + if ( verbose >= 2 ) + fprintf( outStream, "nurbs curve is closed...\n"); + + int numKnots; + + SAA_nurbsCurveGetNbKnots( scene, model, &numKnots ); + if ( verbose >= 2 ) + fprintf( outStream, "nurbs curve knots: %d\n", numKnots ); + double *knots; + knots = (double *)malloc(sizeof(double)*numKnots); + SAA_nurbsCurveGetKnots( scene, model, SAA_GEOM_ORIGINAL, 0, + numKnots, knots ); + + AddKnots( eggNurbsCurve->knots, knots, numKnots, closed, degree ); + + //free( knots ); + + int numCV; + + SAA_modelGetNbVertices( scene, model, &numCV ); + if ( verbose >= 2 ) + fprintf( outStream, "%d CV's (=? %d)\n", numCV, (numKnots-(degree+1)) ); + + //set sub_div so we can see it in perfly + eggNurbsCurve->subdiv = (numCV-1)*nurbs_step; + + // get the CV's + SAA_DVector *cvArray; + cvArray = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); + SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, + numCV, cvArray ); + + //create pool of NURBS vertices + EggVertexPool *pool = _data.CreateVertexPool( parent, name ); + eggNurbsCurve->SetVertexPool( pool ); + + for ( int k = 0; k= 2 ) + fprintf( outStream, "cv[%d] = %f %f %f %f\n", k, cvArray[k].x, + cvArray[k].y, cvArray[k].z, cvArray[k].w ); + + pfVec4 eggVert; + + //convert to global coords + SAA_DVector local = cvArray[k]; + SAA_DVector global; + + _HVCT_X_MAT( global, local, matrix ); + + eggVert.set( global.x, global.y, global.z, global.w ); + + //populate vertex pool + pool->AddVertex( eggVert, k ); + + //add vref's to NURBS info + eggNurbsCurve->AddVertex( k ); + } + + if ( closed ) + { + // need to replicate first (degree) vertices + for ( k = 0; k < degree; k++ ) + { + eggNurbsCurve->AddVertex( k ); + if ( verbose >= 2 ) + fprintf( outStream, "adding cv[%d] = %f %f %f %f\n", k, + cvArray[k].x, cvArray[k].y, cvArray[k].z, cvArray[k].w ); + } + } + + //free( cvArray ); + + //set color to bright green for now + EggColor *nurbCref; + pfVec4 nurbColor; + + nurbColor.set( 0.5, 1.0, 0.5, 1.0 ); + nurbCref = _data.CreateColor(nurbColor); + eggNurbsCurve->attrib.SetCRef(nurbCref); + + return( eggNurbsCurve ); +} + +//////////////////////////////////////////////////////////////////// +// Function: AddKnots +// Access: Public +// Description: Given a parametric surface, and its knots, create +// the appropriate egg structure by filling in Soft's +// implicit knots and assigning the rest to eggKnots. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +AddKnots( perf_vector &eggKnots, double *knots, int numKnots, + SAA_Boolean closed, int degree ) +{ + int k = 0; + double lastKnot = knots[0]; + double *newKnots; + + // add initial implicit knot(s) + if ( closed ) + { + int i = 0; + newKnots = (double *)malloc(sizeof(double)*degree); + + // need to add (degree) number of knots + for ( k = numKnots - 1; k >= numKnots - degree; k-- ) + { + // we have to know these in order to calculate + // next knot value so hold them in temp array + newKnots[i] = lastKnot - (knots[k] - knots[k-1]); + lastKnot = newKnots[i]; + i++; + } + for ( k = degree - 1; k >= 0; k-- ) + { + eggKnots.push_back( newKnots[k] ); + if ( verbose >= 2 ) + fprintf( outStream, "knots[%d] = %f\n", k, newKnots[k] ); + } + + //free( newKnots ); + } + else + { + eggKnots.push_back( knots[k] ); + if ( verbose >= 2 ) + fprintf( outStream, "knots[%d] = %f\n", k, knots[k] ); + } + + // add the regular complement of knots + for (k = 0; k < numKnots; k++) + { + eggKnots.push_back( knots[k] ); + if ( verbose >= 2 ) + fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k] ); + } + + lastKnot = knots[numKnots-1]; + + // add trailing implicit knots + if ( closed ) + { + + // need to add (degree) number of knots + for ( k = 1; k <= degree; k++ ) + { + eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) ); + if ( verbose >= 2 ) + fprintf( outStream, "knots[%d] = %f\n", k, + lastKnot + (knots[k] - knots[k-1]) ); + lastKnot = lastKnot + (knots[k] - knots[k-1]); + } + } + else + { + eggKnots.push_back( knots[k-1] ); + if ( verbose >= 2 ) + fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k-1] ); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MakeJoint +// Access: Public +// Description: Given a name, a parent and a model create a new +// a new EggJoint for that model. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeJoint( SAA_Scene *scene, EggJoint *&lastJoint, AnimGroup *&lastAnim, + SAA_Elem *model, char *name ) +{ + float matrix[4][4]; + pfMatrix Matrix; + EggJoint *joint; + SAA_Boolean globalFlag = FALSE; + int scale_joint = 0; + + + // this is a quick fix to make scaled skeletons possible + // if the parent contains the keyword "scale" make this joint + // a global root joint instead of a child... + if (lastJoint != NULL) + { + if ( strstr( lastJoint->name.Str(), "scale" ) != NULL ) + { + scale_joint = 1; + if ( verbose >= 1 ) + fprintf( outStream, "scale joint flag set!\n" ); + } + } + + // if not root, flatten is false, and last joint had no scaling + // applied to it, then create joint in skeleton tree + if ( (lastJoint != NULL) && !flatten && !scale_joint ) + { + if ( verbose >= 1 ) + { + fprintf( outStream, "lastJoint = %s\n", lastJoint->name.Str() ); + fprintf( outStream, "getting local transform\n" ); + } + + SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), + TRUE, (void **)&globalFlag ); + + // get the local matrix + SAA_modelGetMatrix( scene, model, SAA_COORDSYS_LOCAL, matrix ); + + // make this into a pfMatrix + Matrix[0][0] = matrix[0][0]; + Matrix[0][1] = matrix[0][1]; + Matrix[0][2] = matrix[0][2]; + Matrix[0][3] = matrix[0][3]; + Matrix[1][0] = matrix[1][0]; + Matrix[1][1] = matrix[1][1]; + Matrix[1][2] = matrix[1][2]; + Matrix[1][3] = matrix[1][3]; + Matrix[2][0] = matrix[2][0]; + Matrix[2][1] = matrix[2][1]; + Matrix[2][2] = matrix[2][2]; + Matrix[2][3] = matrix[2][3]; + Matrix[3][0] = matrix[3][0]; + Matrix[3][1] = matrix[3][1]; + Matrix[3][2] = matrix[3][2]; + Matrix[3][3] = matrix[3][3]; + + joint = _data.CreateJoint( lastJoint, name ); + joint->transform = Matrix; + } + // if we already have a root attach this joint to it + else if (foundRoot) + { + if ( verbose >= 1 ) + fprintf( outStream, "getting global transform\n" ); + + globalFlag = TRUE; + + SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), + TRUE, (void *)&globalFlag ); + + // get the global matrix + SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); + + // make this into a pfMatrix + Matrix[0][0] = matrix[0][0]; + Matrix[0][1] = matrix[0][1]; + Matrix[0][2] = matrix[0][2]; + Matrix[0][3] = matrix[0][3]; + Matrix[1][0] = matrix[1][0]; + Matrix[1][1] = matrix[1][1]; + Matrix[1][2] = matrix[1][2]; + Matrix[1][3] = matrix[1][3]; + Matrix[2][0] = matrix[2][0]; + Matrix[2][1] = matrix[2][1]; + Matrix[2][2] = matrix[2][2]; + Matrix[2][3] = matrix[2][3]; + Matrix[3][0] = matrix[3][0]; + Matrix[3][1] = matrix[3][1]; + Matrix[3][2] = matrix[3][2]; + Matrix[3][3] = matrix[3][3]; + + if ( verbose >= 1 ) + fprintf( outStream, "attaching orphan chain to root\n" ); + + joint = _data.CreateJoint( rootJnt, name ); + joint->transform = Matrix; + lastAnim = rootAnim; + } + // if root, make a seperate tree for skeleton and + // create required Table for the Egg heirarchy + else + { + if ( verbose >= 1 ) + fprintf( outStream, "getting global transform\n" ); + + globalFlag = TRUE; + + SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), + TRUE, (void *)&globalFlag ); + + // get the global matrix + SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); + + // make this into a pfMatrix + Matrix[0][0] = matrix[0][0]; + Matrix[0][1] = matrix[0][1]; + Matrix[0][2] = matrix[0][2]; + Matrix[0][3] = matrix[0][3]; + Matrix[1][0] = matrix[1][0]; + Matrix[1][1] = matrix[1][1]; + Matrix[1][2] = matrix[1][2]; + Matrix[1][3] = matrix[1][3]; + Matrix[2][0] = matrix[2][0]; + Matrix[2][1] = matrix[2][1]; + Matrix[2][2] = matrix[2][2]; + Matrix[2][3] = matrix[2][3]; + Matrix[3][0] = matrix[3][0]; + Matrix[3][1] = matrix[3][1]; + Matrix[3][2] = matrix[3][2]; + Matrix[3][3] = matrix[3][3]; + + rootJnt = _data.CreateJoint( skeleton, "root" ); + rootJnt->transform.makeIdent(); + if ( verbose >= 1 ) + fprintf( outStream, "setting skeleton root\n" ); + rootJnt->flags |= EF_TRANSFORM; + + joint = _data.CreateJoint( rootJnt, name ); + joint->transform = Matrix; + foundRoot = TRUE; + if ( verbose >= 1 ) + fprintf( outStream, "found first chain\n" ); + + // make skeleton table + AnimGroup *skeletonTable; + skeletonTable = animData.CreateTable( animRoot, "" ); + rootAnim = animData.CreateTable( skeletonTable, "root" ); + XfmSAnimTable *table = new XfmSAnimTable( ); + table->name = "xform"; + table->fps = anim_rate; + rootAnim->children.push_back( table ); + lastAnim = rootAnim; + } + + joint->flags |= EF_TRANSFORM; + + //if ( make_anim) + //{ + AnimGroup *anim = animData.CreateTable( lastAnim, name ); + XfmSAnimTable *table = new XfmSAnimTable( ); + if ( verbose >= 1 ) + fprintf( outStream, "created anim table: %s\n", "xform" ); + table->name = "xform"; + table->fps = anim_rate; + anim->children.push_back( table ); + lastAnim = anim; + //} + + // make this joint current parent of chain + lastJoint = joint; +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeSoftSkin +// Access: Public +// Description: Given a skeleton part find its envelopes (if any) +// get the vertices associated with the envelopes and +// their weights and make vertex ref's for the joint +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeSoftSkin( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, + int numModels, char *name ) +{ + int numEnv; + SAA_ModelType type; + SAA_Elem *envelopes; + + if ( verbose >= 1 ) + fprintf( outStream, "\n>found skeleton part( %s )!\n", name ); + + SAA_skeletonGetNbEnvelopes( scene, model, &numEnv ); + + if ( numEnv ) + { + // it's got envelopes - must be soft skinned + if ( verbose >= 1 ) + fprintf( outStream, "numEnv = %d\n", numEnv ); + + // allocate envelope array + envelopes = ( SAA_Elem *)malloc( sizeof( SAA_Elem )*numEnv ); + + if ( envelopes != NULL ) + { + int thisEnv; + SAA_EnvType envType; + bool hasEnvVertices = 0; + + SAA_skeletonGetEnvelopes( scene, model, numEnv, envelopes ); + + for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ ) + { + if ( verbose >= 1 ) + fprintf( outStream, "env[%d]: ", thisEnv ); + + SAA_envelopeGetType( scene, &envelopes[thisEnv], &envType ); + + if ( envType == SAA_ENVTYPE_NONE ) + { + if ( verbose >= 1 ) + fprintf( outStream, "envType = none\n" ); + } + else if ( envType == SAA_ENVTYPE_FLXLCL ) + { + if ( verbose >= 1 ) + fprintf( outStream, "envType = flexible, local\n" ); + hasEnvVertices = 1; + } + else if ( envType == SAA_ENVTYPE_FLXGLB ) + { + if ( verbose >= 1 ) + fprintf( outStream, "envType = flexible, global\n" ); + hasEnvVertices = 1; + } + else if ( envType == SAA_ENVTYPE_RGDGLB ) + { + if ( verbose >= 1 ) + fprintf( outStream, "envType = rigid, global\n" ); + hasEnvVertices = 1; + } + else + { + if ( verbose >= 1 ) + fprintf( outStream, "envType = unknown\n" ); + } + } + + if ( hasEnvVertices) + { + int *numEnvVertices; + SAA_SubElem *envVertices = NULL; + + numEnvVertices = (int *)malloc(sizeof(int)*numEnv); + + SAA_envelopeGetNbCtrlVertices( scene, model, numEnv, + envelopes, numEnvVertices ); + + if ( numEnvVertices != NULL ) + { + int totalEnvVertices = 0; + int i,j,k; + + for( i = 0; i < numEnv; i++ ) + { + totalEnvVertices += numEnvVertices[i]; + if ( verbose >= 1 ) + fprintf( outStream, "numEnvVertices[%d] = %d\n", + i, numEnvVertices[i] ); + } + + + if ( verbose >= 1 ) + fprintf( outStream, "total env verts = %d\n", + totalEnvVertices ); + + if ( totalEnvVertices ) + { + envVertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*totalEnvVertices); + + if ( envVertices != NULL ) + { + + SAA_envelopeGetCtrlVertices( scene, model, + numEnv, envelopes, numEnvVertices, envVertices); + + // loop through for each envelope + for ( i = 0; i < numEnv; i++ ) + { + float *weights = NULL; + int vertArrayOffset = 0; + + if ( verbose >= 2 ) + fprintf( outStream, "\nenvelope[%d]:\n", i ); + + weights = (float *)malloc(sizeof(float)*numEnvVertices[i]); + + if ( weights ) + { + char *envName; + int *vpoolMap = NULL; + + for ( j = 0; j < i; j++ ) + vertArrayOffset += numEnvVertices[j]; + + if ( verbose >= 1 ) + fprintf( outStream, + "envVertArray offset = %d\n", + vertArrayOffset ); + + // get the weights of the envelope vertices + SAA_ctrlVertexGetEnvelopeWeights( + scene, model, &envelopes[i], + numEnvVertices[i], + &envVertices[vertArrayOffset], weights ); + + // Get the name of the envelope model + if ( use_prefix ) + { + // Get the FULL name of the envelope + envName = GetFullName( scene, &envelopes[i] ); + } + else + { + // Get the name of the envelope + envName = GetName( scene, &envelopes[i] ); + } + + if ( verbose >= 1 ) + fprintf( outStream, "envelope name %s\n", envName ); + + // find out if envelope geometry is poly or nurb + //SAA_modelGetType( scene, + //FindModelByName( envName, scene, + //models, numModels ), &type ); + + SAA_modelGetType( scene, &envelopes[i], &type ); + + if ( verbose >= 1 ) + { + fprintf( outStream, "envelope model type "); + + if ( type == SAA_MSMSH ) + fprintf( outStream, "MESH\n" ); + else if ( type == SAA_MNSRF ) + fprintf( outStream, "NURBS\n" ); + else + fprintf( outStream, "OTHER\n" ); + } + + int *envVtxIndices = NULL; + envVtxIndices = (int *)malloc(sizeof(int)*numEnvVertices[i]); + + // Get the envelope vertex indices + SAA_ctrlVertexGetIndices( scene, &envelopes[i], numEnvVertices[i], + &envVertices[vertArrayOffset], envVtxIndices ); + + // find out how many vertices the model has + int modelNumVert; + + SAA_modelGetNbVertices( scene, &envelopes[i], &modelNumVert ); + + SAA_DVector *modelVertices = NULL; + modelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert); + + // get the model vertices + SAA_modelGetVertices( scene, &envelopes[i], + SAA_GEOM_ORIGINAL, 0, modelNumVert, + modelVertices ); + + // create array of global model coords + SAA_DVector *globalModelVertices = NULL; + globalModelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert); + float matrix[4][4]; + + // tranform local model vert coords to global + + // first get the global matrix + SAA_modelGetMatrix( scene, &envelopes[i], SAA_COORDSYS_GLOBAL, matrix ); + + // populate array of global model verts + for ( j = 0; j < modelNumVert; j++ ) + { + _VCT_X_MAT( globalModelVertices[j], + modelVertices[j], matrix ); + } + + // find the egg vertex pool that corresponds + // to this envelope model + EggVertexPool *envPool = + (EggVertexPool *)(_data.pools.FindName( envName )); + // If we are outputting triangles: + // create an array that maps from a referenced + // vertex in the envelope to a corresponding + // vertex in the egg vertex pool + //if ( (type == SAA_MNSRF) && !make_nurbs ) + if ( !make_nurbs || (type == SAA_MSMSH) ) + { + vpoolMap = FindClosestTriVert( envPool, + globalModelVertices, modelNumVert ); + } + + + if ( envPool != NULL ) + { + + // find the egg joint that corresponds to this model + EggJoint *joint = + (EggJoint *)(skeleton->FindDescendent( name )); + + // this doesn't seem to be necessary 4/7/99 + //EggJoint *parent = (EggJoint *)joint->parent; + //assert(parent->IsA(NT_EggJoint)); + + // for every envelope vertex + for (j = 0; j < numEnvVertices[i]; j++) + { + double scaledWeight = weights[j]/ 100.0f; + + // make sure its in legal range + if (( envVtxIndices[j] < modelNumVert ) + && ( envVtxIndices[j] >= 0 )) + { + if ( (type == SAA_MNSRF) && make_nurbs ) + { + // assign all referenced control vertices + joint->AddVertex( envPool->Vertex(envVtxIndices[j]), scaledWeight ); + + if ( verbose >= 2 ) + fprintf( outStream, + "%d: adding vref to cv %d with weight %f\n", + j, envVtxIndices[j], scaledWeight ); + + envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight ); + // set flag to show this vertex has + // been assigned + envPool->Vertex(envVtxIndices[j])->multipleJoints = 1; + } + else + { + //assign all the tri verts associated + // with this control vertex to joint + for ( k = 0; k < envPool->NumVertices(); k++ ) + { + if ( vpoolMap[k] == envVtxIndices[j] ) + { + + // add each vert in pool to last + // joint for soft skinning + joint->AddVertex(envPool->Vertex(k), + scaledWeight); + + if ( verbose >= 2 ) + fprintf( outStream, + "%d: adding vref from cv %d to vert %d with weight %f(vpool)\n", + j, envVtxIndices[j], k, scaledWeight ); + + envPool->Vertex(k)->AddJoint( joint, scaledWeight ); + // set flag to show this vertex has + // been assigned + envPool->Vertex(k)->multipleJoints = 1; + } + } + } + } + else + if ( verbose >= 2 ) + fprintf( outStream, + "%d: Omitted vref from cv %d with weight %f (out of range 0 to %d )\n", + j, envVtxIndices[j], scaledWeight, modelNumVert ); + + } + + } + else + if ( verbose >= 2 ) + fprintf( outStream, "Couldn't find vpool %s!\n", envName ); + + //free( modelVertices ); + //free( globalModelVertices ); + //free( envVtxIndices ); + //free( envName ); + } //if (weights) + //free( weights ); + + } // for i + + } // if (envVertices != NULL) + else + fprintf( outStream, "Not enough memory for envelope vertices...\n"); + //free( envVertices ); + } // if (totalEnvVertices) + else + if ( verbose >= 1 ) + fprintf( outStream, "No envelope vertices present...\n"); + + //free( numEnvVertices ); + + } // if (numEnvVertices != NULL) + + } // if (hasEnvVertices) + + } // if (envelopes != NULL) + else + fprintf( outStream, "Not enough memory for envelopes...\n" ); + + //free( envelopes ); + + } //if (numEnv) + + else + if ( verbose >= 1 ) + fprintf( outStream, "Skeleton member has no envelopes...\n" ); +} + + +//////////////////////////////////////////////////////////////////// +// Function: CleanUpSoftSkin +// Access: Public +// Description: Given a model, make sure all its vertices have been +// soft assigned. If not hard assign to the last +// joint we saw. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +CleanUpSoftSkin( SAA_Scene *scene, SAA_Elem *model, char *name ) +{ + static EggJoint *joint; + SAA_Elem parent; + SAA_ModelType type; + SAA_Boolean skel; + + ///////////////////////////////////////////////// + // find out what type of node we're dealing with + ///////////////////////////////////////////////// + SAA_modelGetType( scene, model, &type ); + + char *parentName; + int level; + SAA_Elem *searchNode = model; + + if ( verbose >= 1 ) + fprintf( outStream, "\nCleaning up model %s\n", name ); + + // this step is weird - I think I want it here but it seems + // to break some models. Files like props-props_wh_cookietime.3-0 in + // /ful/rnd/pub/vrml/chip/chips_adventure/char/zone1/rooms/warehouse_final + // need to do the "if (skel)" bit. + + // am I a skeleton too? + SAA_modelIsSkeleton( scene, model, &skel ); + + // if not look for the last skeleton part + if ( skel ) + parentName = name; + else do + { + SAA_elementGetHierarchyLevel( scene, searchNode, &level ); + + // make sure we don't try to get the root's parent + if ( level ) + { + SAA_modelGetParent( scene, searchNode, &parent ); + + if ( use_prefix ) + { + // Get the FULL name of the parent + parentName = GetFullName( scene, &parent ); + } + else + { + // Get the name of the parent + parentName = GetName( scene, &parent ); + } + + SAA_modelGetType( scene, &parent, &type ); + + SAA_modelIsSkeleton( scene, &parent, &skel ); + + if ( verbose >= 1 ) + fprintf( outStream, "model %s, level %d, type %d, skel %d\n", + parentName, level, type, skel ); + + searchNode = &parent; + } + else + { + // we reached the root of the tree + parentName = NULL; + if ( verbose >= 1 ) + fprintf( outStream, "at root of tree! level %d\n", level ); + break; + } + + // look until parent is a joint or acts like one + } while ( !skel && ( strstr( parentName,"joint") == NULL )); + + EggJoint *thisJoint = NULL; + + if ( parentName != NULL ) + { + if ( verbose >= 1 ) + { + fprintf( outStream, "found model parent joint %s\n", parentName); + fprintf( outStream, "looking for joint %s\n", parentName ); + } + thisJoint = (EggJoint *)(skeleton->FindDescendent( parentName )); + } + else + if ( verbose >= 1 ) + fprintf( outStream, "Couldn't find parent joint!\n"); + + if ( thisJoint != NULL ) + { + joint = thisJoint; + if ( verbose >= 1 ) + fprintf( outStream, "setting joint to %s\n", parentName ); + + //find the vpool for this model + EggVertexPool *vPool = + (EggVertexPool *)(_data.pools.FindName( name )); + + if (vPool != NULL) + { + int i; + double membership; + int numVerts = vPool->NumVertices() ; + + + if ( verbose >= 1 ) + fprintf( outStream, "found vpool %s w/ %d verts\n", + name, numVerts ); + + for ( i = 0; i < numVerts; i++ ) + { + if ( vPool->Vertex(i)->multipleJoints != 1 ) + { + if ( verbose >= 1 ) + { + fprintf( outStream, "vpool %s vert %d", name, i ); + fprintf( outStream, " not assigned!\n" ); + } + + // hard skin this vertex + joint->AddVertex( vPool->Vertex(i), 1.0f ); + } + else + { + membership = vPool->Vertex(i)->NetMembership(); + + + if ( verbose >= 1 ) + { + fprintf( outStream, "vpool %s vert %d", name, + i ); + fprintf( outStream, " has membership %f\n", + membership ); + } + + if ( membership == 0 ) + { + if ( verbose >= 1 ) + fprintf( outStream, "adding full weight..\n" ); + + // hard skin this vertex + joint->AddVertex( vPool->Vertex(i), 1.0f ); + } + } + } + } + else + if ( verbose >= 1 ) + fprintf( outStream, "couldn't find vpool %s\n", name ); + } + else + { + if ( parentName != NULL ) + if ( verbose >= 1 ) + fprintf( outStream, "Couldn't find joint %s\n", parentName ); + } +} + +////////////////////////////////////////////////////////////////////// +// Function: MakeAnimTable +// Access: Public +// Description: Given a scene and a skeleton part ,get all the +// position, rotation, and scale for the skeleton +// part for this frame and write them out as Egg +// animation tables. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeAnimTable( SAA_Scene *scene, SAA_Elem *skeletonPart, char *name ) +{ + + if ( skeletonPart != NULL ) + { + float i,j,k; + float h,p,r; + float x,y,z; + int size; + SAA_Boolean globalFlag = FALSE; + SAA_Boolean bigEndian; + + if ( verbose >= 1 ) + fprintf( outStream, "\n\nanimating child %s\n", name ); + + SAA_elementGetUserDataSize( scene, skeletonPart, "GLOBAL", &size ); + + if ( size != 0 ) + SAA_elementGetUserData( scene, skeletonPart, "GLOBAL", + sizeof( SAA_Boolean), &bigEndian, (void *)&globalFlag ); + + if ( globalFlag ) + { + if ( verbose >= 1 ) + fprintf( outStream, " using global matrix\n" ); + + //get SAA orientation + SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, + &p, &h, &r ); + + //get SAA translation + SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, + &x, &y, &z ); + + //get SAA scaling + SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL, + &i, &j, &k ); + } + else + { + if ( verbose >= 1 ) + fprintf( outStream, "using local matrix\n" ); + + //get SAA orientation + SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL, + &p, &h, &r ); + + //get SAA translation + SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL, + &x, &y, &z ); + + //get SAA scaling + SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL, + &i, &j, &k ); + } + + + if ( verbose >= 2 ) + fprintf( outStream, "\nanim data: %f %f %f\n\t%f %f %f\n\t%f %f %f\n", + i, j, k, h, p, r, x, y, z ); + + // find the appropriate anim table for this skeleton part + AnimGroup *thisGroup; + XfmSAnimTable *thisTable; + + //find the anim table associated with this group + thisGroup = (AnimGroup *)(animRoot->FindDescendent( name )); + if ( verbose >= 2 ) + fprintf( outStream, "\nlooking for anim group %s\n", name ); + if ( thisGroup != NULL ) + { + thisTable = (XfmSAnimTable *)(thisGroup->FindDescendent( "xform" )); + + if ( thisTable != NULL ) + { + thisTable->sub_tables[0].AddElement( i ); + thisTable->sub_tables[1].AddElement( j ); + thisTable->sub_tables[2].AddElement( k ); + thisTable->sub_tables[3].AddElement( p ); + thisTable->sub_tables[4].AddElement( h ); + thisTable->sub_tables[5].AddElement( r ); + thisTable->sub_tables[6].AddElement( x ); + thisTable->sub_tables[7].AddElement( y ); + thisTable->sub_tables[8].AddElement( z ); + } + else + fprintf( outStream, "Couldn't allocate anim table\n" ); + } + else + if ( verbose >= 2 ) + fprintf( outStream, "Couldn't find anim group %s\n", name ); + } + else + { + if ( verbose >= 2 ) + fprintf( outStream, "Cannot build anim table - no skeleton\n" ); + } + +} + +//////////////////////////////////////////////////////////////////// +// Function: MakeVertexOffsets +// Access: Public +// Description: Given a scene, a model , the vertices of its original +// shape and its name find the difference between the +// geometry of its key shapes and the models original +// geometry and add morph vertices to the egg data to +// reflect these changes. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeVertexOffsets( SAA_Scene *scene, SAA_Elem *model, SAA_ModelType type, + int numShapes, int numOrigVert, SAA_DVector *originalVerts, float + matrix[4][4], char *name ) +{ + int i, j; + int offset; + int numCV; + char *mTableName; + SAA_DVector *shapeVerts = NULL; + SAA_DVector *uniqueVerts = NULL; + + if ( (type == SAA_MNSRF) && make_nurbs ) + SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); + + SAA_modelGetNbVertices( scene, model, &numCV ); + + // get the shape verts + uniqueVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); + SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, + numCV, uniqueVerts ); + + if ( verbose >= 2 ) + fprintf( outStream, "%d CV's\n", numCV ); + + if ( verbose >= 2 ) + { + for ( i = 0; i < numCV; i++ ) + fprintf( outStream, "uniqueVerts[%d] = %f %f %f %f\n", i, + uniqueVerts[i].x, uniqueVerts[i].y, + uniqueVerts[i].z, uniqueVerts[i].w ); + } + + // iterate through for each key shape (except original) + for ( i = 1; i < numShapes; i++ ) + { + mTableName = MakeTableName( name, i ); + + if ( verbose >= 1 ) + { + fprintf( outStream, "\nMaking geometry offsets for %s...\n", + mTableName ); + + if ( (type == SAA_MNSRF) && make_nurbs ) + fprintf( outStream, "calculating NURBS morphs...\n" ); + else + fprintf( outStream, "calculating triangle morphs...\n" ); + } + + // get the shape verts + shapeVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); + SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, + numCV, shapeVerts ); + + if ( verbose >= 2 ) + { + for ( j=0; j < numCV; j++ ) + { + fprintf( outStream, "shapeVerts[%d] = %f %f %f\n", j, + shapeVerts[j].x, shapeVerts[j].y, shapeVerts[j].z ); + } + } + + // find the appropriate vertex pool + EggVertexPool *vPool = + (EggVertexPool *)(_data.pools.FindName( name )); + + // for every original vertex, compare to the corresponding + // key shape vertex and see if a vertex offset is needed + for ( j=0; j < numOrigVert; j++ ) + { + double dx, dy, dz; + + if ( (type == SAA_MNSRF) && make_nurbs ) + { + //dx = shapeVerts[j].x - (originalVerts[j].x/originalVerts[j].w); + //dy = shapeVerts[j].y - (originalVerts[j].y/originalVerts[j].w); + //dz = shapeVerts[j].z - (originalVerts[j].z/originalVerts[j].w); + dx = shapeVerts[j].x - originalVerts[j].x; + dy = shapeVerts[j].y - originalVerts[j].y; + dz = shapeVerts[j].z - originalVerts[j].z; + } + else + { + // we need to map from original vertices + // to triangle shape vertices here + offset = findShapeVert( originalVerts[j], uniqueVerts, + numCV ); + + dx = shapeVerts[offset].x - originalVerts[j].x; + dy = shapeVerts[offset].y - originalVerts[j].y; + dz = shapeVerts[offset].z - originalVerts[j].z; + } + + if ( verbose >= 2 ) + { + fprintf( outStream, "oVert[%d] = %f %f %f %f\n", j, + originalVerts[j].x, originalVerts[j].y, + originalVerts[j].z, originalVerts[j].w ); + + if ( (type == SAA_MNSRF) && make_nurbs ) + { + fprintf( outStream, "global shapeVerts[%d] = %f %f %f %f\n", j, shapeVerts[j].x, shapeVerts[j].y, + shapeVerts[j].z, shapeVerts[j].w ); + } + else + { + fprintf( outStream, + "global shapeVerts[%d] = %f %f %f\n", offset, + shapeVerts[offset].x, + shapeVerts[offset].y, + shapeVerts[offset].z ); + } + + fprintf( outStream, "%d: dx = %f, dy = %f, dz = %f\n", j, + dx, dy, dz ); + } + + // if change isn't negligible, make a morph vertex entry + double total = fabs(dx)+fabs(dy)+fabs(dz); + if ( total > 0.00001 ) + { + if ( vPool != NULL ) + { + // create offset + EggMorphOffset *dxyz = + new EggMorphOffset( mTableName, dx, dy, dz ); + + EggVertex *eggVert; + + // get the appropriate egg vertex + eggVert = vPool->Vertex(j); + + // add the offset to the vertex + eggVert->morphs.push_back( *dxyz ); + } + else + fprintf( outStream, "Error: couldn't find vertex pool %s\n", name ); + + } // if total + } //for j + } //for i +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeMorphTable +// Access: Public +// Description: Given a scene, a model, a name and a frame time, +// determine what type of shape interpolation is +// used and call the appropriate function to extract +// the shape weight info for this frame... +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, + int numModels, char *name, float time ) +{ + int numShapes; + SAA_AnimInterpType type; + + // Get the number of key shapes + SAA_modelGetNbShapes( scene, model, &numShapes ); + + if ( numShapes > 0 ) + { + if ( verbose >= 1 ) + fprintf( outStream, "MakeMorphTable: %s: num shapes: %d\n", + name, numShapes); + + SAA_modelGetShapeInterpolation( scene, model, &type ); + + if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) + { + MakeLinearMorphTable( scene, model, numShapes, name, time ); + } + else // must be weighted... + { + // check first for expressions + MakeExpressionMorphTable( scene, model, models, numModels, + numShapes, name, time ); + } + + } + +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeLinearMorphTable +// Access: Public +// Description: Given a scene, a model, its name, and the time, +// get the shape fcurve for the model and determine +// the shape weights for the given time and use them +// to populate the morph table. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeLinearMorphTable( SAA_Scene *scene, SAA_Elem *model, int numShapes, + char *name, float time ) +{ + int i; + SAA_Elem fcurve; + float curveVal; + SAnimTable *thisTable; + char *tableName; + + if ( verbose >= 1 ) + fprintf( outStream, "linear interp, getting fcurve\n" ); + + SAA_modelFcurveGetShape( scene, model, &fcurve ); + + SAA_fcurveEval( scene, &fcurve, time, &curveVal ); + + if ( verbose >= 2 ) + fprintf( outStream, "at time %f, fcurve for %s = %f\n", time, + name, curveVal ); + + float nextVal = 0.0f; + + // populate morph table values for this frame + for ( i = 1; i < numShapes; i++ ) + { + // derive table name from the model name + tableName = MakeTableName( name, i ); + + if ( verbose >= 2 ) + fprintf( outStream, "Linear: looking for table '%s'\n", tableName ); + + //find the morph table associated with this key shape + thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName )); + + if ( thisTable != NULL ) + { + if ( i == (int)curveVal ) + { + if ( curveVal - i == 0 ) + { + thisTable->AddElement( 1.0f ); + if ( verbose >= 2 ) + fprintf( outStream, "adding element 1.0f\n" ); + } + else + { + thisTable->AddElement( 1.0f - (curveVal - i) ); + nextVal = curveVal - i; + if ( verbose >= 2 ) + fprintf( outStream, "adding element %f\n", 1.0f - (curveVal - i) ); + } + } + else + { + if ( nextVal ) + { + thisTable->AddElement( nextVal ); + nextVal = 0.0f; + if ( verbose >= 2 ) + fprintf( outStream, "adding element %f\n", nextVal ); + } + else + { + thisTable->AddElement( 0.0f ); + if ( verbose >= 2 ) + fprintf( outStream, "adding element 0.0f\n" ); + } + } + + if ( verbose >= 2 ) + fprintf( outStream, " to '%s'\n", tableName ); + } + else + fprintf( outStream, "%d: Couldn't find table '%s'\n", + i, tableName ); + } + +} + +//////////////////////////////////////////////////////////////////// +// Function: MakeWeightedMorphTable +// Access: Public +// Description: Given a scene, a model, a list of all models in the +// scene, the number of models in the scece, the number +// of key shapes for this model, the name of the model +// and the current time, determine what method of +// controlling the shape weights is used and call the +// appropriate routine. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeWeightedMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, + int numModels, int numShapes, char *name, float time ) +{ + SI_Error result; + SAA_Elem *weightCurves; + float curveVal; + SAnimTable *thisTable; + char *tableName; + + // allocate array of weight curves (one for each shape) + weightCurves = ( SAA_Elem *)malloc( sizeof( SAA_Elem ) * numShapes ); + + result = SAA_modelFcurveGetShapeWeights( + scene, model, numShapes, weightCurves ); + + if ( result == SI_SUCCESS ) + { + for ( int i = 1; i < numShapes; i++ ) + { + SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal ); + + // make sure soft gave us a reasonable number + if (!isNum(curveVal)) + curveVal = 0.0f; + + if ( verbose >= 2 ) + fprintf( outStream, "at time %f, weightCurve[%d] for %s = %f\n", time, i, name, curveVal ); + + + // derive table name from the model name + tableName = MakeTableName( name, i ); + + // find and populate shape table + if ( verbose >= 2 ) + fprintf( outStream, "Weight: looking for table '%s'\n", + tableName ); + + //find the morph table associated with this key shape + thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName )); + + if ( thisTable != NULL ) + { + thisTable->AddElement( curveVal ); + if ( verbose >= 2 ) + fprintf( outStream, "adding element %f\n", curveVal ); + } + else + fprintf( outStream, "%d: Couldn't find table '%s'\n", + i, tableName ); + } + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeExpressionMorphTable +// Access: Public +// Description: Given a scene, a model and its number of key shapes +// generate a morph table describing transitions btwn +// the key shapes by evaluating the positions of the +// controlling sliders. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeExpressionMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, + int numModels, int numShapes, char *name, float time ) +{ + int j; + SAnimTable *thisTable; + char *tableName; + char *sliderName; + char *track; + int numExp; + SAA_Elem *expressions; + float expVal; + float sliderVal; + + // populate morph table values for this frame + + // compose track name + track = NULL; + + // find how many expressions for this shape + SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp ); + + if ( verbose >= 2 ) + fprintf( outStream, "%s has %d RHS expressions\n", name, numExp ); + + if ( numExp ) + { + // get the expressions for this shape + expressions = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numExp); + + if ( verbose >= 1 ) + fprintf( outStream, "getting %d RHS expressions...\n", numExp ); + + result = SAA_elementGetExpressions( scene, model, track, FALSE, + numExp, expressions ); + + if ( !result ) + { + for ( j = 1; j < numExp; j++ ) + { + if ( verbose >= 2 ) + { + // debug see what we got + int numvars; + + SAA_expressionGetNbVars( scene, &expressions[j], &numvars ); + + int *varnamelen; + int *varstrlen; + int expstrlen; + + varnamelen = (int *)malloc(sizeof(int)*numvars); + varstrlen = (int *)malloc(sizeof(int)*numvars); + + SAA_expressionGetStringLengths( scene, &expressions[j], + numvars, varnamelen, varstrlen, &expstrlen ); + + int *varnamesizes; + int *varstrsizes; + + varnamesizes = (int *)malloc(sizeof(int)*numvars); + varstrsizes = (int *)malloc(sizeof(int)*numvars); + + for ( int k = 0; k < numvars; k++ ) + { + varnamesizes[k] = varnamelen[k] + 1; + varstrsizes[k] = varstrlen[k] + 1; + } + + int expstrsize = expstrlen + 1; + + char **varnames; + char **varstrs; + + varnames = (char **)malloc(sizeof(char *)*numvars); + varstrs = (char **)malloc(sizeof(char *)*numvars); + + for ( k = 0; k < numvars; k++ ) + { + varnames[k] = (char *)malloc(sizeof(char)* + varnamesizes[k]); + + varstrs[k] = (char *)malloc(sizeof(char)* + varstrsizes[k]); + } + + char *expstr = (char *)malloc(sizeof(char)* expstrsize ); + + SAA_expressionGetStrings( scene, &expressions[j], numvars, + varnamesizes, varstrsizes, expstrsize, varnames, + varstrs, expstr ); + + if ( verbose >= 2 ) + { + fprintf( outStream, "expression = '%s'\n", expstr ); + fprintf( outStream, "has %d variables\n", numvars ); + } + } //if verbose + + if ( verbose >= 2 ) + fprintf( outStream, "evaling expression...\n" ); + + SAA_expressionEval( scene, &expressions[j], time, &expVal ); + + if ( verbose >= 2 ) + fprintf( outStream, "time %f: exp val %f\n", + time, expVal ); + + // derive table name from the model name + tableName = MakeTableName( name, j ); + + if ( verbose >= 2 ) + fprintf( outStream, "Exp: looking for table '%s'\n", + tableName ); + + //find the morph table associated with this key shape + thisTable = (SAnimTable *) + (morphRoot->FindDescendent( tableName )); + + if ( thisTable != NULL ) + { + thisTable->AddElement( expVal ); + if ( verbose >= 1 ) + fprintf( outStream, "%d: adding element %f to %s\n", + j, expVal, tableName ); + fflush( outStream ); + } + else + { + fprintf( outStream, "%d: Couldn't find table '%s'", j, + tableName ); + + fprintf( outStream, " for value %f\n", expVal ); + } + } + } + else + fprintf( outStream, "couldn't get expressions!!!\n" ); + } + else + // no expression, use weight curves + MakeWeightedMorphTable( scene, model, models, numModels, + numShapes, name, time ); + +} + + +//////////////////////////////////////////////////////////////////// +// Function: MakeTexAnim +// Access: Public +// Description: Given a scene, a POLYGON model, and the name +// of the that model, get the u and v offsets for +// the current frame. +//////////////////////////////////////////////////////////////////// +void soft2egg:: +MakeTexAnim( SAA_Scene *scene, SAA_Elem *model, char *modelName ) +{ + if ( verbose >= 1 ) + fprintf( outStream, "\n\nmaking texture animation for %s...\n", + modelName ); + + // get the color of the surface + int numMats; + pfVec4 Color; + SAA_Elem *materials; + void *relinfo; + + SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo, + &numMats ); + + if ( verbose >= 2 ) + fprintf( outStream, "surface has %d materials\n", numMats ); + + if ( numMats ) + { + float r,g,b,a; + + materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numMats); + + SAA_modelRelationGetMatElements( scene, model, relinfo, + numMats, materials ); + + SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b ); + SAA_materialGetTransparency( scene, &materials[0], &a ); + Color.set( r, g, b, 1.0f - a ); + + int numTexLoc = 0; + int numTexGlb = 0; + + // ASSUME only one texture per material + SAA_Elem tex; + + // find out how many local textures per surface + // ASSUME it only has one material + SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], + FALSE, &relinfo, &numTexLoc ); + + // if present, get local textures + if ( numTexLoc ) + { + if ( verbose >= 1 ) + fprintf( outStream, "%s had %d local tex\n", modelName, + numTexLoc ); + + // get the referenced texture + SAA_materialRelationGetT2DLocElements( scene, &materials[0], + TEX_PER_MAT, &tex ); + + } + // if no locals, try to get globals + else + { + SAA_modelRelationGetT2DGlbNbElements( scene, model, + FALSE, &relinfo, &numTexGlb ); + + if ( numTexGlb ) + { + if ( verbose >= 1 ) + fprintf( outStream, "%s had %d global tex\n", modelName, numTexGlb ); + + // get the referenced texture + SAA_modelRelationGetT2DGlbElements( scene, + model, TEX_PER_MAT, &tex ); + } + } + + // add tex ref's if we found any textures + if ( numTexLoc || numTexGlb) + { + char *fullTexName = NULL; + char *texName = NULL; + char *uniqueTexName = NULL; + int texNameLen; + + // get its name + SAA_texture2DGetPicNameLength( scene, &tex, &texNameLen); + fullTexName = (char *)malloc(sizeof(char)*++texNameLen); + SAA_texture2DGetPicName( scene, &tex, texNameLen, + fullTexName ); + + // append unique identifier to texname for + // this particular object + uniqueTexName = (char *)malloc(sizeof(char)* + (strlen(modelName)+strlen(texName)+3) ); + sprintf( uniqueTexName, "%s-%s", modelName, texName ); + if ( verbose >= 2 ) + fprintf( outStream, "referencing tref %s\n", + uniqueTexName ); + + float uScale; + float vScale; + float uOffset; + float vOffset; + SAA_Boolean uv_swap = FALSE; + + // get texture offset info + SAA_texture2DGetUScale( scene, &tex, &uScale ); + SAA_texture2DGetVScale( scene, &tex, &vScale ); + SAA_texture2DGetUOffset( scene, &tex, &uOffset ); + SAA_texture2DGetVOffset( scene, &tex, &vOffset ); + SAA_texture2DGetUVSwap( scene, &tex, &uv_swap ); + + + if ( verbose >= 2 ) + { + fprintf( outStream, "tex uScale: %f\n", uScale ); + fprintf( outStream, "tex vScale: %f\n", vScale ); + fprintf( outStream, "tex uOffset: %f\n", uOffset ); + fprintf( outStream, "tex vOffset: %f\n", vOffset ); + if ( uv_swap ) + fprintf( outStream, "nurbTex u & v swapped!\n" ); + else + fprintf( outStream, "nurbTex u & v NOT swapped\n" ); + } + + + // find the vpool for this model + EggVertexPool *vPool = + (EggVertexPool *)(_data.pools.FindName( modelName )); + + // if we found the pool + if ( vPool != NULL ) + { + // generate duv's for model + float oldOffsets[4]; + double u, v, du, dv; + int size; + SAA_Boolean bigEndian; + + SAA_elementGetUserDataSize( scene, model, "TEX_OFFSETS", &size ); + + if ( size != 0 ) + { + // remember original texture offsets future reference + SAA_elementGetUserData( scene, model, "TEX_OFFSETS", + size, &bigEndian, (void *)&oldOffsets ); + + // get the original scales and offsets + u = oldOffsets[0]; + v = oldOffsets[1]; + + du = u - uOffset; + dv = v - vOffset; + + if ( verbose >= 1 ) + { + fprintf( outStream, "original u = %f, v = %f\n", + u, v ); + fprintf( outStream, "u = %f, v = %f\n", + uOffset, vOffset ); + fprintf( outStream, "du = %f, dv = %f\n", + du, dv ); + } + + strstream uName, vName; + + // create duv target names + uName << modelName << ".u" << ends; + vName << modelName << ".v" << ends; + + // find the appropriate table to store the + // duv animation info into + SAnimTable *thisTable; + + //find the duv U table associated with this model + thisTable = (SAnimTable *)(morphRoot->FindDescendent( + uName.str() )); + + if ( thisTable != NULL ) + { + thisTable->AddElement( du ); + if ( verbose >= 1 ) + fprintf( outStream, "adding element %f to %s\n", + du, uName.str() ); + } + else + fprintf( outStream, "Couldn't find uTable %s\n", + uName.str() ); + + //find the duv V table associated with this model + thisTable = (SAnimTable *)(morphRoot->FindDescendent( + vName.str() )); + + if ( thisTable != NULL ) + { + thisTable->AddElement( dv ); + if ( verbose >= 1 ) + fprintf( outStream, "adding element %f to %s\n", + dv, uName.str() ); + } + else + fprintf( outStream, "Couldn't find vTable %s\n", + uName.str() ); + } + } + else + if ( verbose >= 2 ) + fprintf( outStream, "Couldn't find vpool %s\n", modelName ); + + } + + //free( materials ); + + } + +} +#endif + +//////////////////////////////////////////////////////////////////// +// Function: Main +// Access: Private +// Description: Instantiate converter and process a file +//////////////////////////////////////////////////////////////////// +EXPCL_MISC SI_Error soft2egg(int argc, char *argv[]) { + // pass control to the c++ system + init_soft2egg(argc, argv); + return SI_SUCCESS; +} +#ifdef __cplusplus +} +#endif