open_toontown_panda3d/pandatool/src/softegg/soft2Egg.c

4934 lines
170 KiB
C
Executable File

// 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <SAA.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "pandatoolbase.h"
int init_soft2egg(int, char **);
#if 0
// DWD includes
#include "eggBase.h"
#include <eggParametrics.h>
#include <animTable.h>
#include <linMathOutput.h>
// system includes
#include <fstream.h>
#include <strstream.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include <ieeefp.h>
// Performer includes
#include <Performer/pr/pfLinMath.h>
// SoftImage includes
#include <SAA.h>
#include <SI_macros.h>
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> &, 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 <path> - 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 <path> - Database path.\n"
" -s <scene> - Indicates that a scene will be converted.\n"
" -m <model> - Indicates that a model will be converted.\n"
" -t <path> - Specify path to place converted textures.\n"
" -T <name> - Specify filename for texture map listing.\n"
" -S <step> - Specify step for nurbs surface triangulation.\n"
" -M <name> - Specify model output filename. Defaults to scene name.\n"
" -A <name> - Specify anim output filename. Defaults to scene name.\n"
" -N <name> - 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 <frame> - Specify frame number for static pose.\n"
" -b <frame> - Specify starting frame for animation (default = first).\n"
" -e <frame> - Specify ending frame for animation (default = last).\n"
" -f <fps> - 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 <level> - 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 <prefix>- 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<numTri*3; i++ )
fprintf( outStream, "normals[%d] = %f %f %f %f\n", i,
normals[i].x, normals[i].y, normals[i].z, normals[i].w );
}
int uRepeat, vRepeat;
// make sure we have textures before we get t-coords
if ( numTexLoc )
{
// allocate arrays for u & v coords
uCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3);
vCoords = (float *)malloc(sizeof(float)*numTri*numTexLoc*3);
// read the u & v coords into the arrays
if ( uCoords != NULL && vCoords != NULL)
{
for ( i = 0; i < numTri*numTexLoc*3; i++ )
uCoords[i] = vCoords[i] = 0.0f;
SAA_ctrlVertexGetUVTxtCoords( scene, model, numTri*3,
cvertices, numTexLoc*3, uCoords, vCoords );
}
else
fprintf( outStream, "Not enough Memory for texture coords...\n");
if ( verbose >= 2 )
{
for ( i=0; i<numTexLoc*3; i++ )
fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i,
uCoords[i], vCoords[i] );
}
// allocate arrays of texture info
uScale = ( float *)malloc(sizeof(float)*numTri);
vScale = ( float *)malloc(sizeof(float)*numTri);
uOffset = ( float *)malloc(sizeof(float)*numTri);
vOffset = ( float *)malloc(sizeof(float)*numTri);
texNameArray = ( char **)malloc(sizeof(char *)*numTri);
for ( i = 0; i < numTri; i++ )
{
// initialize the array value
texNameArray[i] = NULL;
SAA_Boolean valid = FALSE;
// check to see if texture is present
result = SAA_elementIsValid( scene, &textures[i], &valid );
if ( result != SI_SUCCESS )
fprintf( outStream, "SAA_elementIsValid failed!!!!\n" );
// texture present - get the name and uv info
if ( valid )
{
texNameArray[i] = ConvertTexture( scene, &textures[i] );
if ( verbose >= 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<numTri*numTexGlb*3; i++ )
fprintf( outStream, "texcoords[%d] = ( %f , %f )\n", i,
uCoords[i], vCoords[i] );
}
texNameArray = ( char **)malloc(sizeof(char *));
*texNameArray = ConvertTexture( scene, textures );
if ( verbose >= 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<numVert; k++ )
{
if ( verbose >= 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<numSamples[numCurve]; k++ )
{
pfVec3 eggVert;
// index into the array of samples for this curve
eggVert.set( uSamples[k+offset], vSamples[k+offset], 1.0f );
if ( verbose >= 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, &degree );
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<numCV; k++ )
{
if ( verbose >= 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<double> &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, "<skeleton>" );
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