doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
maya_main.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "Maya5.0/maya.h"
33 //#include "Maya6.0/maya.h" // must also change include directory in project from "MayaImport\Maya4.5\include" to "MayaImport\Maya6.0\include" (requires MSDev 7.1)
34 #include "exporter.h"
35 #include "maya_main.h"
36 
38 bool initialized = false;
39 
40 #define DEFAULT_ANIM_EPSILON 0.125f
41 #define DEFAULT_QUAT_EPSILON ( 1.0f / 8192.0f )
42 
43 #define SLOP_VERTEX 0.01f // merge xyz coordinates this far apart
44 #define SLOP_TEXCOORD 0.001f // merge texture coordinates this far apart
45 
46 const char *componentNames[ 6 ] = { "Tx", "Ty", "Tz", "Qx", "Qy", "Qz" };
47 
51 
53 
54 /*
55 =================
56 MayaError
57 =================
58 */
59 void MayaError( const char *fmt, ... ) {
60  va_list argptr;
61  char text[ 8192 ];
62 
63  va_start( argptr, fmt );
64  idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
65  va_end( argptr );
66 
67  throw idException( text );
68 }
69 
70 /*
71 =================
72 FS_WriteFloatString
73 =================
74 */
75 #define MAX_PRINT_MSG 4096
76 static int WriteFloatString( FILE *file, const char *fmt, ... ) {
77  long i;
78  unsigned long u;
79  double f;
80  char *str;
81  int index;
82  idStr tmp, format;
83  va_list argPtr;
84 
85  va_start( argPtr, fmt );
86 
87  index = 0;
88 
89  while( *fmt ) {
90  switch( *fmt ) {
91  case '%':
92  format = "";
93  format += *fmt++;
94  while ( (*fmt >= '0' && *fmt <= '9') ||
95  *fmt == '.' || *fmt == '-' || *fmt == '+' || *fmt == '#') {
96  format += *fmt++;
97  }
98  format += *fmt;
99  switch( *fmt ) {
100  case 'f':
101  case 'e':
102  case 'E':
103  case 'g':
104  case 'G':
105  f = va_arg( argPtr, double );
106  if ( format.Length() <= 2 ) {
107  // high precision floating point number without trailing zeros
108  sprintf( tmp, "%1.10f", f );
109  tmp.StripTrailing( '0' );
110  tmp.StripTrailing( '.' );
111  index += fprintf( file, "%s", tmp.c_str() );
112  }
113  else {
114  index += fprintf( file, format.c_str(), f );
115  }
116  break;
117  case 'd':
118  case 'i':
119  i = va_arg( argPtr, long );
120  index += fprintf( file, format.c_str(), i );
121  break;
122  case 'u':
123  u = va_arg( argPtr, unsigned long );
124  index += fprintf( file, format.c_str(), u );
125  break;
126  case 'o':
127  u = va_arg( argPtr, unsigned long );
128  index += fprintf( file, format.c_str(), u );
129  break;
130  case 'x':
131  u = va_arg( argPtr, unsigned long );
132  index += fprintf( file, format.c_str(), u );
133  break;
134  case 'X':
135  u = va_arg( argPtr, unsigned long );
136  index += fprintf( file, format.c_str(), u );
137  break;
138  case 'c':
139  i = va_arg( argPtr, long );
140  index += fprintf( file, format.c_str(), (char) i );
141  break;
142  case 's':
143  str = va_arg( argPtr, char * );
144  index += fprintf( file, format.c_str(), str );
145  break;
146  case '%':
147  index += fprintf( file, format.c_str() );
148  break;
149  default:
150  MayaError( "WriteFloatString: invalid format %s", format.c_str() );
151  break;
152  }
153  fmt++;
154  break;
155  case '\\':
156  fmt++;
157  switch( *fmt ) {
158  case 't':
159  index += fprintf( file, "\t" );
160  break;
161  case 'n':
162  index += fprintf( file, "\n" );
163  default:
164  MayaError( "WriteFloatString: unknown escape character \'%c\'", *fmt );
165  break;
166  }
167  fmt++;
168  break;
169  default:
170  index += fprintf( file, "%c", *fmt );
171  fmt++;
172  break;
173  }
174  }
175 
176  va_end( argPtr );
177 
178  return index;
179 }
180 
181 /*
182 ================
183 OSPathToRelativePath
184 
185 takes a full OS path, as might be found in data from a media creation
186 program, and converts it to a qpath by stripping off directories
187 
188 Returns false if the osPath tree doesn't match any of the existing
189 search paths.
190 ================
191 */
192 bool OSPathToRelativePath( const char *osPath, idStr &qpath, const char *game ) {
193  char *s, *base;
194 
195  // skip a drive letter?
196 
197  // search for anything with BASE_GAMEDIR in it
198  // Ase files from max may have the form of:
199  // "//Purgatory/purgatory/doom/base/models/mapobjects/bitch/hologirl.tga"
200  // which won't match any of our drive letter based search paths
201  base = (char *)strstr( osPath, BASE_GAMEDIR );
202 
203  // _D3XP added mod support
204  if ( base == NULL && strlen(game) > 0 ) {
205 
206  base = s = (char *)strstr( osPath, game );
207 
208  while( s = strstr( s, game ) ) {
209  s += strlen( game );
210  if ( s[0] == '/' || s[0] == '\\' ) {
211  base = s;
212  }
213  }
214  }
215 
216  if ( base ) {
217  s = strstr( base, "/" );
218  if ( !s ) {
219  s = strstr( base, "\\" );
220  }
221  if ( s ) {
222  qpath = s + 1;
223  return true;
224  }
225  }
226 
227  common->Printf( "OSPathToRelativePath failed on %s\n", osPath );
228  qpath = osPath;
229 
230  return false;
231 }
232 
233 /*
234 ===============
235 ConvertFromIdSpace
236 ===============
237 */
239  idMat3 mat;
240 
241  mat[ 0 ][ 0 ] = idmat[ 0 ][ 0 ];
242  mat[ 0 ][ 2 ] = -idmat[ 0 ][ 1 ];
243  mat[ 0 ][ 1 ] = idmat[ 0 ][ 2 ];
244 
245  mat[ 1 ][ 0 ] = idmat[ 1 ][ 0 ];
246  mat[ 1 ][ 2 ] = -idmat[ 1 ][ 1 ];
247  mat[ 1 ][ 1 ] = idmat[ 1 ][ 2 ];
248 
249  mat[ 2 ][ 0 ] = idmat[ 2 ][ 0 ];
250  mat[ 2 ][ 2 ] = -idmat[ 2 ][ 1 ];
251  mat[ 2 ][ 1 ] = idmat[ 2 ][ 2 ];
252 
253  return mat;
254 }
255 
256 /*
257 ===============
258 ConvertFromIdSpace
259 ===============
260 */
262  idVec3 pos;
263 
264  pos.x = idpos.x;
265  pos.z = -idpos.y;
266  pos.y = idpos.z;
267 
268  return pos;
269 }
270 
271 /*
272 ===============
273 ConvertToIdSpace
274 ===============
275 */
277  idMat3 idmat;
278 
279  idmat[ 0 ][ 0 ] = mat[ 0 ][ 0 ];
280  idmat[ 0 ][ 1 ] = -mat[ 0 ][ 2 ];
281  idmat[ 0 ][ 2 ] = mat[ 0 ][ 1 ];
282 
283  idmat[ 1 ][ 0 ] = mat[ 1 ][ 0 ];
284  idmat[ 1 ][ 1 ] = -mat[ 1 ][ 2 ];
285  idmat[ 1 ][ 2 ] = mat[ 1 ][ 1 ];
286 
287  idmat[ 2 ][ 0 ] = mat[ 2 ][ 0 ];
288  idmat[ 2 ][ 1 ] = -mat[ 2 ][ 2 ];
289  idmat[ 2 ][ 2 ] = mat[ 2 ][ 1 ];
290 
291  return idmat;
292 }
293 
294 /*
295 ===============
296 ConvertToIdSpace
297 ===============
298 */
300  idVec3 idpos;
301 
302  idpos.x = pos.x;
303  idpos.y = -pos.z;
304  idpos.z = pos.y;
305 
306  return idpos;
307 }
308 
309 /*
310 ===============
311 idVec
312 ===============
313 */
314 idVec3 idVec( const MFloatPoint &point ) {
315  return idVec3( point[ 0 ], point[ 1 ], point[ 2 ] );
316 }
317 
318 /*
319 ===============
320 idVec
321 ===============
322 */
323 idVec3 idVec( const MMatrix &matrix ) {
324  return idVec3( matrix[ 3 ][ 0 ], matrix[ 3 ][ 1 ], matrix[ 3 ][ 2 ] );
325 }
326 
327 /*
328 ===============
329 idMat
330 ===============
331 */
332 idMat3 idMat( const MMatrix &matrix ) {
333  int j, k;
334  idMat3 mat;
335 
336  for( j = 0; j < 3; j++ ) {
337  for( k = 0; k < 3; k++ ) {
338  mat[ j ][ k ] = matrix[ j ][ k ];
339  }
340  }
341 
342  return mat;
343 }
344 
345 /*
346 ===============
347 GetParent
348 ===============
349 */
350 MFnDagNode *GetParent( MFnDagNode *joint ) {
351  MStatus status;
352  MObject parentObject;
353 
354  parentObject = joint->parent( 0, &status );
355  if ( !status && status.statusCode() == MStatus::kInvalidParameter ) {
356  return NULL;
357  }
358 
359  while( !parentObject.hasFn( MFn::kTransform ) ) {
360  MFnDagNode parentNode( parentObject, &status );
361  if ( !status ) {
362  return NULL;
363  }
364 
365  parentObject = parentNode.parent( 0, &status );
366  if ( !status && status.statusCode() == MStatus::kInvalidParameter ) {
367  return NULL;
368  }
369  }
370 
371  MFnDagNode *parentNode;
372 
373  parentNode = new MFnDagNode( parentObject, &status );
374  if ( !status ) {
375  delete parentNode;
376  return NULL;
377  }
378 
379  return parentNode;
380 }
381 
382 /*
383 ==============================================================================================
384 
385  idTokenizer
386 
387 ==============================================================================================
388 */
389 
390 /*
391 ====================
392 idTokenizer::SetTokens
393 ====================
394 */
395 int idTokenizer::SetTokens( const char *buffer ) {
396  const char *cmd;
397 
398  Clear();
399 
400  // tokenize commandline
401  cmd = buffer;
402  while ( *cmd ) {
403  // skip whitespace
404  while( *cmd && isspace( *cmd ) ) {
405  cmd++;
406  }
407 
408  if ( !*cmd ) {
409  break;
410  }
411 
412  idStr &current = tokens.Alloc();
413  while( *cmd && !isspace( *cmd ) ) {
414  current += *cmd;
415  cmd++;
416  }
417  }
418 
419  return tokens.Num();
420 }
421 
422 /*
423 ====================
424 idTokenizer::NextToken
425 ====================
426 */
427 const char *idTokenizer::NextToken( const char *errorstring ) {
428  if ( currentToken < tokens.Num() ) {
429  return tokens[ currentToken++ ];
430  }
431 
432  if ( errorstring ) {
433  MayaError( "Error: %s", errorstring );
434  }
435 
436  return NULL;
437 }
438 
439 /*
440 ==============================================================================================
441 
442  idExportOptions
443 
444 ==============================================================================================
445 */
446 
447 /*
448 ====================
449 idExportOptions::Reset
450 ====================
451 */
452 void idExportOptions::Reset( const char *commandline ) {
453  scale = 1.0f;
454  type = WRITE_MESH;
455  startframe = -1;
456  endframe = -1;
457  ignoreMeshes = false;
458  clearOrigin = false;
459  clearOriginAxis = false;
460  framerate = 24;
461  align = "";
462  rotate = 0.0f;
463  commandLine = commandline;
464  prefix = "";
465  jointThreshold = 0.05f;
466  ignoreScale = false;
469  cycleStart = -1;
470 
471  src.Clear();
472  dest.Clear();
473 
474  tokens.SetTokens( commandline );
475 
476  keepjoints.Clear();
478  remapjoints.Clear();
480  skipmeshes.Clear();
481  keepmeshes.Clear();
482  groups.Clear();
483 }
484 
485 /*
486 ====================
487 idExportOptions::idExportOptions
488 ====================
489 */
490 idExportOptions::idExportOptions( const char *commandline, const char *ospath ) {
491  idStr token;
492  idNamePair joints;
493  int i;
494  idAnimGroup *group;
495  idStr sourceDir;
496  idStr destDir;
497 
498  Reset( commandline );
499 
500  token = tokens.NextToken( "Missing export command" );
501  if ( token == "mesh" ) {
502  type = WRITE_MESH;
503  } else if ( token == "anim" ) {
504  type = WRITE_ANIM;
505  } else if ( token == "camera" ) {
506  type = WRITE_CAMERA;
507  } else {
508  MayaError( "Unknown export command '%s'", token.c_str() );
509  }
510 
511  src = tokens.NextToken( "Missing source filename" );
512  dest = src;
513 
514  for( token = tokens.NextToken(); token != ""; token = tokens.NextToken() ) {
515  if ( token == "-force" ) {
516  // skip
517  } else if ( token == "-game" ) {
518  // parse game name
519  game = tokens.NextToken( "Expecting game name after -game" );
520 
521  } else if ( token == "-rename" ) {
522  // parse joint to rename
523  joints.from = tokens.NextToken( "Missing joint name for -rename. Usage: -rename [joint name] [new name]" );
524  joints.to = tokens.NextToken( "Missing new name for -rename. Usage: -rename [joint name] [new name]" );
525  renamejoints.Append( joints );
526 
527  } else if ( token == "-prefix" ) {
528  prefix = tokens.NextToken( "Missing name for -prefix. Usage: -prefix [joint prefix]" );
529 
530  } else if ( token == "-parent" ) {
531  // parse joint to reparent
532  joints.from = tokens.NextToken( "Missing joint name for -parent. Usage: -parent [joint name] [new parent]" );
533  joints.to = tokens.NextToken( "Missing new parent for -parent. Usage: -parent [joint name] [new parent]" );
534  remapjoints.Append( joints );
535 
536  } else if ( !token.Icmp( "-sourcedir" ) ) {
537  // parse source directory
538  sourceDir = tokens.NextToken( "Missing filename for -sourcedir. Usage: -sourcedir [directory]" );
539 
540  } else if ( !token.Icmp( "-destdir" ) ) {
541  // parse destination directory
542  destDir = tokens.NextToken( "Missing filename for -destdir. Usage: -destdir [directory]" );
543 
544  } else if ( token == "-dest" ) {
545  // parse destination filename
546  dest = tokens.NextToken( "Missing filename for -dest. Usage: -dest [filename]" );
547 
548  } else if ( token == "-range" ) {
549  // parse frame range to export
550  token = tokens.NextToken( "Missing start frame for -range. Usage: -range [start frame] [end frame]" );
551  startframe = atoi( token );
552  token = tokens.NextToken( "Missing end frame for -range. Usage: -range [start frame] [end frame]" );
553  endframe = atoi( token );
554 
555  if ( startframe > endframe ) {
556  MayaError( "Start frame is greater than end frame." );
557  }
558 
559  } else if ( !token.Icmp( "-cycleStart" ) ) {
560  // parse start frame of cycle
561  token = tokens.NextToken( "Missing cycle start frame for -cycleStart. Usage: -cycleStart [first frame of cycle]" );
562  cycleStart = atoi( token );
563 
564  } else if ( token == "-scale" ) {
565  // parse scale
566  token = tokens.NextToken( "Missing scale amount for -scale. Usage: -scale [scale amount]" );
567  scale = atof( token );
568 
569  } else if ( token == "-align" ) {
570  // parse align joint
571  align = tokens.NextToken( "Missing joint name for -align. Usage: -align [joint name]" );
572 
573  } else if ( token == "-rotate" ) {
574  // parse angle rotation
575  token = tokens.NextToken( "Missing value for -rotate. Usage: -rotate [yaw]" );
576  rotate = -atof( token );
577 
578  } else if ( token == "-nomesh" ) {
579  ignoreMeshes = true;
580 
581  } else if ( token == "-clearorigin" ) {
582  clearOrigin = true;
583  clearOriginAxis = true;
584 
585  } else if ( token == "-clearoriginaxis" ) {
586  clearOriginAxis = true;
587 
588  } else if ( token == "-ignorescale" ) {
589  ignoreScale = true;
590 
591  } else if ( token == "-xyzprecision" ) {
592  // parse quaternion precision
593  token = tokens.NextToken( "Missing value for -xyzprecision. Usage: -xyzprecision [precision]" );
594  xyzPrecision = atof( token );
595  if ( xyzPrecision < 0.0f ) {
596  MayaError( "Invalid value for -xyzprecision. Must be >= 0" );
597  }
598 
599  } else if ( token == "-quatprecision" ) {
600  // parse quaternion precision
601  token = tokens.NextToken( "Missing value for -quatprecision. Usage: -quatprecision [precision]" );
602  quatPrecision = atof( token );
603  if ( quatPrecision < 0.0f ) {
604  MayaError( "Invalid value for -quatprecision. Must be >= 0" );
605  }
606 
607  } else if ( token == "-jointthreshold" ) {
608  // parse joint threshold
609  token = tokens.NextToken( "Missing weight for -jointthreshold. Usage: -jointthreshold [minimum joint weight]" );
610  jointThreshold = atof( token );
611 
612  } else if ( token == "-skipmesh" ) {
613  token = tokens.NextToken( "Missing name for -skipmesh. Usage: -skipmesh [name of mesh to skip]" );
614  skipmeshes.AddUnique( token );
615 
616  } else if ( token == "-keepmesh" ) {
617  token = tokens.NextToken( "Missing name for -keepmesh. Usage: -keepmesh [name of mesh to keep]" );
618  keepmeshes.AddUnique( token );
619 
620  } else if ( token == "-jointgroup" ) {
621  token = tokens.NextToken( "Missing name for -jointgroup. Usage: -jointgroup [group name] [joint1] [joint2]...[joint n]" );
622  group = groups.Ptr();
623  for( i = 0; i < groups.Num(); i++, group++ ) {
624  if ( group->name == token ) {
625  break;
626  }
627  }
628 
629  if ( i >= groups.Num() ) {
630  // create a new group
631  group = &groups.Alloc();
632  group->name = token;
633  }
634 
635  while( tokens.TokenAvailable() ) {
636  token = tokens.NextToken();
637  if ( token[ 0 ] == '-' ) {
638  tokens.UnGetToken();
639  break;
640  }
641 
642  group->joints.AddUnique( token );
643  }
644  } else if ( token == "-group" ) {
645  // add the list of groups to export (these don't affect the hierarchy)
646  while( tokens.TokenAvailable() ) {
647  token = tokens.NextToken();
648  if ( token[ 0 ] == '-' ) {
649  tokens.UnGetToken();
650  break;
651  }
652 
653  group = groups.Ptr();
654  for( i = 0; i < groups.Num(); i++, group++ ) {
655  if ( group->name == token ) {
656  break;
657  }
658  }
659 
660  if ( i >= groups.Num() ) {
661  MayaError( "Unknown group '%s'", token.c_str() );
662  }
663 
664  exportgroups.AddUnique( group );
665  }
666  } else if ( token == "-keep" ) {
667  // add joints that are kept whether they're used by a mesh or not
668  while( tokens.TokenAvailable() ) {
669  token = tokens.NextToken();
670  if ( token[ 0 ] == '-' ) {
671  tokens.UnGetToken();
672  break;
673  }
674  keepjoints.AddUnique( token );
675  }
676  } else {
677  MayaError( "Unknown option '%s'", token.c_str() );
678  }
679  }
680 
681  token = src;
682  src = ospath;
684  src.AppendPath( sourceDir );
685  src.AppendPath( token );
686 
687  token = dest;
688  dest = ospath;
690  dest.AppendPath( destDir );
691  dest.AppendPath( token );
692 
693  // Maya only accepts unix style path separators
694  src.BackSlashesToSlashes();
696 
697  if ( skipmeshes.Num() && keepmeshes.Num() ) {
698  MayaError( "Can't use -keepmesh and -skipmesh together." );
699  }
700 }
701 
702 /*
703 ====================
704 idExportOptions::jointInExportGroup
705 ====================
706 */
707 bool idExportOptions::jointInExportGroup( const char *jointname ) {
708  int i;
709  int j;
710  idAnimGroup *group;
711 
712  if ( !exportgroups.Num() ) {
713  // if we don't have any groups specified as export then export every joint
714  return true;
715  }
716 
717  // search through all exported groups to see if this joint is exported
718  for( i = 0; i < exportgroups.Num(); i++ ) {
719  group = exportgroups[ i ];
720  for( j = 0; j < group->joints.Num(); j++ ) {
721  if ( group->joints[ j ] == jointname ) {
722  return true;
723  }
724  }
725  }
726 
727  return false;
728 }
729 
730 /*
731 ==============================================================================
732 
733 idExportJoint
734 
735 ==============================================================================
736 */
737 
739  index = 0;
740  exportNum = 0;
741 
742  mayaNode.SetOwner( this );
743  exportNode.SetOwner( this );
744 
745  dagnode = NULL;
746 
747  t = vec3_zero;
748  wm = mat3_default;
749  bindpos = vec3_zero;
751  keep = false;
752  scale = 1.0f;
753  invscale = 1.0f;
754  animBits = 0;
755  firstComponent = 0;
756  baseFrame.q.Set( 0.0f, 0.0f, 0.0f );
757  baseFrame.t.Zero();
758 }
759 
761  name = other.name;
762  realname = other.realname;
763  longname = other.longname;
764  index = other.index;
765  exportNum = other.exportNum;
766  keep = other.keep;
767 
768  scale = other.scale;
769  invscale = other.invscale;
770 
771  dagnode = other.dagnode;
772 
773  mayaNode = other.mayaNode;
774  exportNode = other.exportNode;
775 
776  t = other.t;
777  idt = other.idt;
778  wm = other.wm;
779  idwm = other.idwm;
780  bindpos = other.bindpos;
781  bindmat = other.bindmat;
782 
783  animBits = other.animBits;
785  baseFrame = other.baseFrame;
786 
787  mayaNode.SetOwner( this );
788  exportNode.SetOwner( this );
789 
790  return *this;
791 }
792 
793 /*
794 ==============================================================================
795 
796 idExportMesh
797 
798 ==============================================================================
799 */
800 
802  int i, j, k;
803  exportVertex_t vert;
805 
806  v = verts;
807  verts.Clear();
808  for( i = 0; i < tris.Num(); i++ ) {
809  for( j = 0; j < 3; j++ ) {
810  vert = v[ tris[ i ].indexes[ j ] ];
811  vert.texCoords[ 0 ] = uv[ i ].uv[ j ][ 0 ];
812  vert.texCoords[ 1 ] = 1.0f - uv[ i ].uv[ j ][ 1 ];
813 
814  for( k = 0; k < verts.Num(); k++ ) {
815  if ( vert.numWeights != verts[ k ].numWeights ) {
816  continue;
817  }
818  if ( vert.startweight != verts[ k ].startweight ) {
819  continue;
820  }
821  if ( !vert.pos.Compare( verts[ k ].pos, SLOP_VERTEX ) ) {
822  continue;
823  }
824  if ( !vert.texCoords.Compare( verts[ k ].texCoords, SLOP_TEXCOORD ) ) {
825  continue;
826  }
827 
828  break;
829  }
830 
831  if ( k < verts.Num() ) {
832  tris[ i ].indexes[ j ] = k;
833  } else {
834  tris[ i ].indexes[ j ] = verts.Append( vert );
835  }
836  }
837  }
838 }
839 
841  int i;
842  int numverts;
843  int numtris;
844  int numweights;
845  int numuvs;
846 
847  // merge name
848  sprintf( name, "%s, %s", name.c_str(), mesh->name.c_str() );
849 
850  // merge verts
851  numverts = verts.Num();
852  verts.SetNum( numverts + mesh->verts.Num() );
853  for( i = 0; i < mesh->verts.Num(); i++ ) {
854  verts[ numverts + i ] = mesh->verts[ i ];
855  verts[ numverts + i ].startweight += weights.Num();
856  }
857 
858  // merge triangles
859  numtris = tris.Num();
860  tris.SetNum( numtris + mesh->tris.Num() );
861  for( i = 0; i < mesh->tris.Num(); i++ ) {
862  tris[ numtris + i ].indexes[ 0 ] = mesh->tris[ i ].indexes[ 0 ] + numverts;
863  tris[ numtris + i ].indexes[ 1 ] = mesh->tris[ i ].indexes[ 1 ] + numverts;
864  tris[ numtris + i ].indexes[ 2 ] = mesh->tris[ i ].indexes[ 2 ] + numverts;
865  }
866 
867  // merge weights
868  numweights = weights.Num();
869  weights.SetNum( numweights + mesh->weights.Num() );
870  for( i = 0; i < mesh->weights.Num(); i++ ) {
871  weights[ numweights + i ] = mesh->weights[ i ];
872  }
873 
874  // merge uvs
875  numuvs = uv.Num();
876  uv .SetNum( numuvs + mesh->uv.Num() );
877  for( i = 0; i < mesh->uv.Num(); i++ ) {
878  uv[ numuvs + i ] = mesh->uv[ i ];
879  }
880 }
881 
882 void idExportMesh::GetBounds( idBounds &bounds ) const {
883  int i;
884  int j;
885  idVec3 pos;
886  const exportWeight_t *weight;
887  const exportVertex_t *vert;
888 
889  bounds.Clear();
890 
891  weight = weights.Ptr();
892  vert = verts.Ptr();
893  for( i = 0; i < verts.Num(); i++, vert++ ) {
894  pos.Zero();
895  weight = &weights[ vert->startweight ];
896  for( j = 0; j < vert->numWeights; j++, weight++ ) {
897  pos += weight->jointWeight * ( weight->joint->idwm * weight->offset + weight->joint->idt );
898  }
899  bounds.AddPoint( pos );
900  }
901 }
902 
903 /*
904 ==============================================================================
905 
906 idExportModel
907 
908 ==============================================================================
909 */
910 
911 /*
912 ====================
913 idExportModel::idExportModel
914 ====================
915 */
917  export_joints = 0;
918  skipjoints = 0;
919  frameRate = 24;
920  numFrames = 0;
921  exportOrigin = NULL;
922 }
923 
924 /*
925 ====================
926 idExportModel::~idExportModel
927 ====================
928 */
930  meshes.DeleteContents( true );
931 }
932 
934  idExportJoint *joint;
935  int i;
936 
937  joint = joints.Ptr();
938  for( i = 0; i < joints.Num(); i++, joint++ ) {
939  if ( joint->realname == name ) {
940  return joint;
941  }
942  }
943 
944  return NULL;
945 }
946 
948  idExportJoint *joint;
949  int i;
950 
951  joint = joints.Ptr();
952  for( i = 0; i < joints.Num(); i++, joint++ ) {
953  if ( joint->name == name ) {
954  return joint;
955  }
956  }
957 
958  return NULL;
959 }
960 
961 bool idExportModel::WriteMesh( const char *filename, idExportOptions &options ) {
962  int i, j;
963  int numMeshes;
964  idExportMesh *mesh;
965  idExportJoint *joint;
966  idExportJoint *parent;
967  idExportJoint *sibling;
968  FILE *file;
969  const char *parentName;
970  int parentNum;
971  idList<idExportJoint *> jointList;
972 
973  file = fopen( filename, "w" );
974  if ( !file ) {
975  return false;
976  }
977 
978  for( joint = exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
979  jointList.Append( joint );
980  }
981 
982  for( i = 0; i < jointList.Num(); i++ ) {
983  joint = jointList[ i ];
984  sibling = joint->exportNode.GetSibling();
985  while( sibling ) {
986  if ( idStr::Cmp( joint->name, sibling->name ) > 0 ) {
987  joint->exportNode.MakeSiblingAfter( sibling->exportNode );
988  sibling = joint->exportNode.GetSibling();
989  } else {
990  sibling = sibling->exportNode.GetSibling();
991  }
992  }
993  }
994 
995  jointList.Clear();
996  for( joint = exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
997  joint->exportNum = jointList.Append( joint );
998  }
999 
1000  numMeshes = 0;
1001  if ( !options.ignoreMeshes ) {
1002  for( i = 0; i < meshes.Num(); i++ ) {
1003  if ( meshes[ i ]->keep ) {
1004  numMeshes++;
1005  }
1006  }
1007  }
1008 
1009  // write version info
1010  WriteFloatString( file, MD5_VERSION_STRING " %d\n", MD5_VERSION );
1011  WriteFloatString( file, "commandline \"%s\"\n\n", options.commandLine.c_str() );
1012 
1013  // write joints
1014  WriteFloatString( file, "numJoints %d\n", jointList.Num() );
1015  WriteFloatString( file, "numMeshes %d\n\n", numMeshes );
1016 
1017  WriteFloatString( file, "joints {\n" );
1018  for( i = 0; i < jointList.Num(); i++ ) {
1019  joint = jointList[ i ];
1020  parent = joint->exportNode.GetParent();
1021  if ( parent ) {
1022  parentNum = parent->exportNum;
1023  parentName = parent->name.c_str();
1024  } else {
1025  parentNum = -1;
1026  parentName = "";
1027  }
1028 
1029  idCQuat bindQuat = joint->bindmat.ToQuat().ToCQuat();
1030  WriteFloatString( file, "\t\"%s\"\t%d ( %f %f %f ) ( %f %f %f )\t\t// %s\n", joint->name.c_str(), parentNum,
1031  joint->bindpos.x, joint->bindpos.y, joint->bindpos.z, bindQuat[ 0 ], bindQuat[ 1 ], bindQuat[ 2 ], parentName );
1032  }
1033  WriteFloatString( file, "}\n" );
1034 
1035  // write meshes
1036  for( i = 0; i < meshes.Num(); i++ ) {
1037  mesh = meshes[ i ];
1038  if ( !mesh->keep ) {
1039  continue;
1040  }
1041 
1042  WriteFloatString( file, "\nmesh {\n" );
1043  WriteFloatString( file, "\t// meshes: %s\n", mesh->name.c_str() );
1044  WriteFloatString( file, "\tshader \"%s\"\n", mesh->shader.c_str() );
1045 
1046  WriteFloatString( file, "\n\tnumverts %d\n", mesh->verts.Num() );
1047  for( j = 0; j < mesh->verts.Num(); j++ ) {
1048  WriteFloatString( file, "\tvert %d ( %f %f ) %d %d\n", j, mesh->verts[ j ].texCoords[ 0 ], mesh->verts[ j ].texCoords[ 1 ],
1049  mesh->verts[ j ].startweight, mesh->verts[ j ].numWeights );
1050  }
1051 
1052  WriteFloatString( file, "\n\tnumtris %d\n", mesh->tris.Num() );
1053  for( j = 0; j < mesh->tris.Num(); j++ ) {
1054  WriteFloatString( file, "\ttri %d %d %d %d\n", j, mesh->tris[ j ].indexes[ 2 ], mesh->tris[ j ].indexes[ 1 ], mesh->tris[ j ].indexes[ 0 ] );
1055  }
1056 
1057  WriteFloatString( file, "\n\tnumweights %d\n", mesh->weights.Num() );
1058  for( j = 0; j < mesh->weights.Num(); j++ ) {
1059  exportWeight_t *weight;
1060 
1061  weight = &mesh->weights[ j ];
1062  WriteFloatString( file, "\tweight %d %d %f ( %f %f %f )\n", j,
1063  weight->joint->exportNum, weight->jointWeight, weight->offset.x, weight->offset.y, weight->offset.z );
1064  }
1065 
1066  WriteFloatString( file, "}\n" );
1067  }
1068 
1069  fclose( file );
1070 
1071  return true;
1072 }
1073 
1074 bool idExportModel::WriteAnim( const char *filename, idExportOptions &options ) {
1075  int i, j;
1076  idExportJoint *joint;
1077  idExportJoint *parent;
1078  idExportJoint *sibling;
1079  jointFrame_t *frame;
1080  FILE *file;
1081  int numAnimatedComponents;
1082  idList<idExportJoint *> jointList;
1083 
1084  file = fopen( filename, "w" );
1085  if ( !file ) {
1086  return false;
1087  }
1088 
1089  for( joint = exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
1090  jointList.Append( joint );
1091  }
1092 
1093  for( i = 0; i < jointList.Num(); i++ ) {
1094  joint = jointList[ i ];
1095  sibling = joint->exportNode.GetSibling();
1096  while( sibling ) {
1097  if ( idStr::Cmp( joint->name, sibling->name ) > 0 ) {
1098  joint->exportNode.MakeSiblingAfter( sibling->exportNode );
1099  sibling = joint->exportNode.GetSibling();
1100  } else {
1101  sibling = sibling->exportNode.GetSibling();
1102  }
1103  }
1104  }
1105 
1106  jointList.Clear();
1107  for( joint = exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
1108  joint->exportNum = jointList.Append( joint );
1109  }
1110 
1111  numAnimatedComponents = 0;
1112  for( i = 0; i < jointList.Num(); i++ ) {
1113  joint = jointList[ i ];
1114  joint->exportNum = i;
1115  joint->baseFrame = frames[ 0 ][ joint->index ];
1116  joint->animBits = 0;
1117  for( j = 1; j < numFrames; j++ ) {
1118  frame = &frames[ j ][ joint->index ];
1119  if ( fabs( frame->t[ 0 ] - joint->baseFrame.t[ 0 ] ) > options.xyzPrecision ) {
1120  joint->animBits |= ANIM_TX;
1121  }
1122  if ( fabs( frame->t[ 1 ] - joint->baseFrame.t[ 1 ] ) > options.xyzPrecision ) {
1123  joint->animBits |= ANIM_TY;
1124  }
1125  if ( fabs( frame->t[ 2 ] - joint->baseFrame.t[ 2 ] ) > options.xyzPrecision ) {
1126  joint->animBits |= ANIM_TZ;
1127  }
1128  if ( fabs( frame->q[ 0 ] - joint->baseFrame.q[ 0 ] ) > options.quatPrecision ) {
1129  joint->animBits |= ANIM_QX;
1130  }
1131  if ( fabs( frame->q[ 1 ] - joint->baseFrame.q[ 1 ] ) > options.quatPrecision ) {
1132  joint->animBits |= ANIM_QY;
1133  }
1134  if ( fabs( frame->q[ 2 ] - joint->baseFrame.q[ 2 ] ) > options.quatPrecision ) {
1135  joint->animBits |= ANIM_QZ;
1136  }
1137  if ( ( joint->animBits & 63 ) == 63 ) {
1138  break;
1139  }
1140  }
1141  if ( joint->animBits ) {
1142  joint->firstComponent = numAnimatedComponents;
1143  for( j = 0; j < 6; j++ ) {
1144  if ( joint->animBits & BIT( j ) ) {
1145  numAnimatedComponents++;
1146  }
1147  }
1148  }
1149  }
1150 
1151  // write version info
1152  WriteFloatString( file, MD5_VERSION_STRING " %d\n", MD5_VERSION );
1153  WriteFloatString( file, "commandline \"%s\"\n\n", options.commandLine.c_str() );
1154 
1155  WriteFloatString( file, "numFrames %d\n", numFrames );
1156  WriteFloatString( file, "numJoints %d\n", jointList.Num() );
1157  WriteFloatString( file, "frameRate %d\n", frameRate );
1158  WriteFloatString( file, "numAnimatedComponents %d\n", numAnimatedComponents );
1159 
1160  // write out the hierarchy
1161  WriteFloatString( file, "\nhierarchy {\n" );
1162  for( i = 0; i < jointList.Num(); i++ ) {
1163  joint = jointList[ i ];
1164  parent = joint->exportNode.GetParent();
1165  if ( parent ) {
1166  WriteFloatString( file, "\t\"%s\"\t%d %d %d\t// %s", joint->name.c_str(), parent->exportNum, joint->animBits, joint->firstComponent, parent->name.c_str() );
1167  } else {
1168  WriteFloatString( file, "\t\"%s\"\t-1 %d %d\t//", joint->name.c_str(), joint->animBits, joint->firstComponent );
1169  }
1170 
1171  if ( !joint->animBits ) {
1172  WriteFloatString( file, "\n" );
1173  } else {
1174  WriteFloatString( file, " ( " );
1175  for( j = 0; j < 6; j++ ) {
1176  if ( joint->animBits & BIT( j ) ) {
1177  WriteFloatString( file, "%s ", componentNames[ j ] );
1178  }
1179  }
1180  WriteFloatString( file, ")\n" );
1181  }
1182  }
1183  WriteFloatString( file, "}\n" );
1184 
1185  // write the frame bounds
1186  WriteFloatString( file, "\nbounds {\n" );
1187  for( i = 0; i < numFrames; i++ ) {
1188  WriteFloatString( file, "\t( %f %f %f ) ( %f %f %f )\n", bounds[ i ][ 0 ].x, bounds[ i ][ 0 ].y, bounds[ i ][ 0 ].z, bounds[ i ][ 1 ].x, bounds[ i ][ 1 ].y, bounds[ i ][ 1 ].z );
1189  }
1190  WriteFloatString( file, "}\n" );
1191 
1192  // write the base frame
1193  WriteFloatString( file, "\nbaseframe {\n" );
1194  for( i = 0; i < jointList.Num(); i++ ) {
1195  joint = jointList[ i ];
1196  WriteFloatString( file, "\t( %f %f %f ) ( %f %f %f )\n", joint->baseFrame.t[ 0 ], joint->baseFrame.t[ 1 ], joint->baseFrame.t[ 2 ],
1197  joint->baseFrame.q[ 0 ], joint->baseFrame.q[ 1 ], joint->baseFrame.q[ 2 ] );
1198  }
1199  WriteFloatString( file, "}\n" );
1200 
1201  // write the frames
1202  for( i = 0; i < numFrames; i++ ) {
1203  WriteFloatString( file, "\nframe %d {\n", i );
1204  for( j = 0; j < jointList.Num(); j++ ) {
1205  joint = jointList[ j ];
1206  frame = &frames[ i ][ joint->index ];
1207  if ( joint->animBits ) {
1208  WriteFloatString( file, "\t" );
1209  if ( joint->animBits & ANIM_TX ) {
1210  WriteFloatString( file, " %f", frame->t[ 0 ] );
1211  }
1212  if ( joint->animBits & ANIM_TY ) {
1213  WriteFloatString( file, " %f", frame->t[ 1 ] );
1214  }
1215  if ( joint->animBits & ANIM_TZ ) {
1216  WriteFloatString( file, " %f", frame->t[ 2 ] );
1217  }
1218  if ( joint->animBits & ANIM_QX ) {
1219  WriteFloatString( file, " %f", frame->q[ 0 ] );
1220  }
1221  if ( joint->animBits & ANIM_QY ) {
1222  WriteFloatString( file, " %f", frame->q[ 1 ] );
1223  }
1224  if ( joint->animBits & ANIM_QZ ) {
1225  WriteFloatString( file, " %f", frame->q[ 2 ] );
1226  }
1227  WriteFloatString( file, "\n" );
1228  }
1229  }
1230  WriteFloatString( file, "}\n" );
1231  }
1232 
1233  fclose( file );
1234 
1235  return true;
1236 }
1237 
1238 bool idExportModel::WriteCamera( const char *filename, idExportOptions &options ) {
1239  int i;
1240  FILE *file;
1241 
1242  file = fopen( filename, "w" );
1243  if ( !file ) {
1244  return false;
1245  }
1246 
1247  // write version info
1248  WriteFloatString( file, MD5_VERSION_STRING " %d\n", MD5_VERSION );
1249  WriteFloatString( file, "commandline \"%s\"\n\n", options.commandLine.c_str() );
1250 
1251  WriteFloatString( file, "numFrames %d\n", camera.Num() );
1252  WriteFloatString( file, "frameRate %d\n", frameRate );
1253  WriteFloatString( file, "numCuts %d\n", cameraCuts.Num() );
1254 
1255  // write out the cuts
1256  WriteFloatString( file, "\ncuts {\n" );
1257  for( i = 0; i < cameraCuts.Num(); i++ ) {
1258  WriteFloatString( file, "\t%d\n", cameraCuts[ i ] );
1259  }
1260  WriteFloatString( file, "}\n" );
1261 
1262  // write out the frames
1263  WriteFloatString( file, "\ncamera {\n" );
1264  cameraFrame_t *frame = camera.Ptr();
1265  for( i = 0; i < camera.Num(); i++, frame++ ) {
1266  WriteFloatString( file, "\t( %f %f %f ) ( %f %f %f ) %f\n", frame->t.x, frame->t.y, frame->t.z, frame->q[ 0 ], frame->q[ 1 ], frame->q[ 2 ], frame->fov );
1267  }
1268  WriteFloatString( file, "}\n" );
1269 
1270  fclose( file );
1271 
1272  return true;
1273 }
1274 
1275 /*
1276 ==============================================================================
1277 
1278 Maya
1279 
1280 ==============================================================================
1281 */
1282 
1283 /*
1284 ===============
1285 idMayaExport::~idMayaExport
1286 
1287 ===============
1288 */
1290  FreeDagNodes();
1291 
1292  // free up the file in Maya
1293  MFileIO::newFile( true );
1294 }
1295 
1296 /*
1297 ===============
1298 idMayaExport::TimeForFrame
1299 ===============
1300 */
1301 float idMayaExport::TimeForFrame( int num ) const {
1302  MTime time;
1303 
1304  // set time unit to 24 frames per second
1305  time.setUnit( MTime::kFilm );
1306  time.setValue( num );
1307  return time.as( MTime::kSeconds );
1308 }
1309 
1310 /*
1311 ===============
1312 idMayaExport::GetMayaFrameNum
1313 ===============
1314 */
1316  int frameNum;
1317 
1319  // in cycles, the last frame is a duplicate of the first frame, so with cycleStart we need to
1320  // duplicate one of the interior frames instead and chop off the first frame.
1321  frameNum = options.cycleStart + num;
1322  if ( frameNum > options.endframe ) {
1323  frameNum -= options.endframe - options.startframe;
1324  }
1325  if ( frameNum < options.startframe ) {
1326  frameNum = options.startframe + 1;
1327  }
1328  } else {
1329  frameNum = options.startframe + num;
1330  if ( frameNum > options.endframe ) {
1331  frameNum -= options.endframe + 1 - options.startframe;
1332  }
1333  if ( frameNum < options.startframe ) {
1334  frameNum = options.startframe;
1335  }
1336  }
1337 
1338  return frameNum;
1339 }
1340 
1341 /*
1342 ===============
1343 idMayaExport::SetFrame
1344 ===============
1345 */
1347  MTime time;
1348  int frameNum;
1349 
1350  frameNum = GetMayaFrameNum( num );
1351 
1352  // set time unit to 24 frames per second
1353  time.setUnit( MTime::kFilm );
1354  time.setValue( frameNum );
1355  MGlobal::viewFrame( time );
1356 }
1357 
1358 /*
1359 ===============
1360 idMayaExport::PruneJoints
1361 ===============
1362 */
1363 void idMayaExport::PruneJoints( idStrList &keepjoints, idStr &prefix ) {
1364  int i;
1365  int j;
1366  idExportMesh *mesh;
1367  idExportJoint *joint;
1368  idExportJoint *joint2;
1369  idExportJoint *parent;
1370  int num_weights;
1371 
1372  // if we don't have any joints specified to keep, mark the ones used by the meshes as keep
1373  if ( !keepjoints.Num() && !prefix.Length() ) {
1374  if ( !model.meshes.Num() || options.ignoreMeshes ) {
1375  // export all joints
1376  joint = model.joints.Ptr();
1377  for( i = 0; i < model.joints.Num(); i++, joint++ ) {
1378  joint->keep = true;
1379  }
1380  } else {
1381  for( i = 0; i < model.meshes.Num(); i++, mesh++ ) {
1382  mesh = model.meshes[ i ];
1383  for( j = 0; j < mesh->weights.Num(); j++ ) {
1384  mesh->weights[ j ].joint->keep = true;
1385  }
1386  }
1387  }
1388  } else {
1389  // mark the joints to keep
1390  for( i = 0; i < keepjoints.Num(); i++ ) {
1391  joint = model.FindJoint( keepjoints[ i ] );
1392  if ( joint ) {
1393  joint->keep = true;
1394  }
1395  }
1396 
1397  // count valid meshes
1398  for( i = 0; i < model.meshes.Num(); i++ ) {
1399  mesh = model.meshes[ i ];
1400  num_weights = 0;
1401  for( j = 0; j < mesh->weights.Num(); j++ ) {
1402  if ( mesh->weights[ j ].joint->keep ) {
1403  num_weights++;
1404  } else if ( prefix.Length() && !mesh->weights[ j ].joint->realname.Cmpn( prefix, prefix.Length() ) ) {
1405  // keep the joint if it's used by the mesh and it has the right prefix
1406  mesh->weights[ j ].joint->keep = true;
1407  num_weights++;
1408  }
1409  }
1410 
1411  if ( num_weights != mesh->weights.Num() ) {
1412  mesh->keep = false;
1413  }
1414  }
1415  }
1416 
1417  // find all joints aren't exported and reparent joint's children
1418  model.export_joints = 0;
1419  joint = model.joints.Ptr();
1420  for( i = 0; i < model.joints.Num(); i++, joint++ ) {
1421  if ( !joint->keep ) {
1423  } else {
1424  joint->index = model.export_joints;
1425  model.export_joints++;
1426 
1427  // make sure we are parented to an exported joint
1428  for( parent = joint->exportNode.GetParent(); parent != NULL; parent = parent->exportNode.GetParent() ) {
1429  if ( parent->keep ) {
1430  break;
1431  }
1432  }
1433 
1434  if ( parent != NULL ) {
1435  joint->exportNode.ParentTo( parent->exportNode );
1436  } else {
1437  joint->exportNode.ParentTo( model.exportHead );
1438  }
1439  }
1440  }
1441 
1442  // check if we have any duplicate joint names
1443  for( joint = model.exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
1444  if ( !joint->keep ) {
1445  MayaError( "Non-kept joint in export tree ('%s')", joint->name.c_str() );
1446  }
1447 
1448  for( joint2 = model.exportHead.GetNext(); joint2 != NULL; joint2 = joint2->exportNode.GetNext() ) {
1449  if ( ( joint2 != joint ) && ( joint2->name == joint->name ) ) {
1450  MayaError( "Two joints found with the same name ('%s')", joint->name.c_str() );
1451  }
1452  }
1453  }
1454 }
1455 
1456 /*
1457 ===============
1458 idMayaExport::FreeDagNodes
1459 ===============
1460 */
1462  int i;
1463 
1464  for( i = 0; i < model.joints.Num(); i++ ) {
1465  delete model.joints[ i ].dagnode;
1466  model.joints[ i ].dagnode = NULL;
1467  }
1468 }
1469 
1470 /*
1471 ===============
1472 idMayaExport::GetBindPose
1473 ===============
1474 */
1475 void idMayaExport::GetBindPose( MObject &jointNode, idExportJoint *joint, float scale ) {
1476  MStatus status;
1477  MFnDependencyNode fnJoint( jointNode );
1478  MObject aBindPose = fnJoint.attribute( "bindPose", &status );
1479 
1480  joint->bindpos = vec3_zero;
1481  joint->bindmat = mat3_default;
1482 
1483  if ( MS::kSuccess == status ) {
1484  unsigned ii;
1485  unsigned jointIndex;
1486  unsigned connLength;
1487  MPlugArray connPlugs;
1488  MPlug pBindPose( jointNode, aBindPose );
1489 
1490  pBindPose.connectedTo( connPlugs, false, true );
1491  connLength = connPlugs.length();
1492  for( ii = 0; ii < connLength; ++ii ) {
1493  if ( connPlugs[ ii ].node().apiType() == MFn::kDagPose ) {
1494  MObject aMember = connPlugs[ ii ].attribute();
1495  MFnAttribute fnAttr( aMember );
1496 
1497  if ( fnAttr.name() == "worldMatrix" ) {
1498  jointIndex = connPlugs[ ii ].logicalIndex();
1499 
1500  MFnDependencyNode nDagPose( connPlugs[ ii ].node() );
1501 
1502  // construct plugs for this joint's world matrix
1503  MObject aWorldMatrix = nDagPose.attribute( "worldMatrix" );
1504  MPlug pWorldMatrix( connPlugs[ ii ].node(), aWorldMatrix );
1505 
1506  pWorldMatrix.selectAncestorLogicalIndex( jointIndex, aWorldMatrix );
1507 
1508  // get the world matrix data
1509  MObject worldMatrix;
1510  MStatus status = pWorldMatrix.getValue( worldMatrix );
1511  if ( MS::kSuccess != status ) {
1512  // Problem retrieving world matrix
1513  return;
1514  }
1515 
1516  MFnMatrixData dMatrix( worldMatrix );
1517  MMatrix wMatrix = dMatrix.matrix( &status );
1518 
1519  joint->bindmat = ConvertToIdSpace( idMat( wMatrix ) );
1520  joint->bindpos = ConvertToIdSpace( idVec( wMatrix ) ) * scale;
1521  if ( !options.ignoreScale ) {
1522  joint->bindpos *= joint->scale;
1523  } else {
1524  joint->bindmat[ 0 ].Normalize();
1525  joint->bindmat[ 1 ].Normalize();
1526  joint->bindmat[ 2 ].Normalize();
1527  }
1528 
1529  return;
1530  }
1531  }
1532  }
1533  }
1534 }
1535 
1536 /*
1537 ===============
1538 idMayaExport::GetLocalTransform
1539 ===============
1540 */
1542  MStatus status;
1543  MDagPath dagPath;
1544 
1545  pos.Zero();
1546  mat.Identity();
1547 
1548  if ( !joint->dagnode ) {
1549  return;
1550  }
1551 
1552  status = joint->dagnode->getPath( dagPath );
1553  if ( !status ) {
1554  return;
1555  }
1556 
1557  MObject transformNode = dagPath.transform( &status );
1558  if ( !status && ( status.statusCode () == MStatus::kInvalidParameter ) ) {
1559  return;
1560  }
1561 
1562  MFnDagNode transform( transformNode, &status );
1563  if ( !status ) {
1564  return;
1565  }
1566 
1567  pos = idVec( transform.transformationMatrix() );
1568  mat = idMat( transform.transformationMatrix() );
1569 }
1570 
1571 /*
1572 ===============
1573 idMayaExport::GetWorldTransform
1574 ===============
1575 */
1577  idExportJoint *parent;
1578 
1579  GetLocalTransform( joint, pos, mat );
1580  mat.OrthoNormalizeSelf();
1581  pos *= scale;
1582 
1583  parent = joint->mayaNode.GetParent();
1584  if ( parent ) {
1585  idVec3 parentpos;
1586  idMat3 parentmat;
1587 
1588  GetWorldTransform( parent, parentpos, parentmat, scale );
1589 
1590  pos = parentpos + ( parentmat * ( pos * parent->scale ) );
1591  mat = mat * parentmat;
1592  }
1593 }
1594 
1595 /*
1596 ===============
1597 idMayaExport::CreateJoints
1598 ===============
1599 */
1601  int i;
1602  int j;
1603  idExportJoint *joint;
1604  idExportJoint *parent;
1605  MStatus status;
1606  MDagPath dagPath;
1607  MFnDagNode *parentNode;
1608 
1609  SetFrame( 0 );
1610 
1611  // create an initial list with all of the transformable nodes in the scene
1612  MItDag dagIterator( MItDag::kDepthFirst, MFn::kTransform, &status );
1613  for ( ; !dagIterator.isDone(); dagIterator.next() ) {
1614  status = dagIterator.getPath( dagPath );
1615  if ( !status ) {
1616  MayaError( "CreateJoints: MItDag::getPath failed (%s)", status.errorString().asChar() );
1617  continue;
1618  }
1619 
1620  joint = &model.joints.Alloc();
1621  joint->index = model.joints.Num() - 1;
1622  joint->dagnode = new MFnDagNode( dagPath, &status );
1623  if ( !status ) {
1624  MayaError( "CreateJoints: MFnDagNode constructor failed (%s)", status.errorString().asChar() );
1625  continue;
1626  }
1627 
1628  joint->name = joint->dagnode->name().asChar();
1629  joint->realname = joint->name;
1630  }
1631 
1632  // allocate an extra joint in case we need to add an origin later
1635 
1636  // create scene hierarchy
1637  joint = model.joints.Ptr();
1638  for( i = 0; i < model.joints.Num(); i++, joint++ ) {
1639  if ( !joint->dagnode ) {
1640  continue;
1641  }
1642  joint->mayaNode.ParentTo( model.mayaHead );
1643  joint->exportNode.ParentTo( model.exportHead );
1644 
1645  parentNode = GetParent( joint->dagnode );
1646  if ( parentNode ) {
1647  // find the parent joint in our jointlist
1648  for( j = 0; j < model.joints.Num(); j++ ) {
1649  if ( !model.joints[ j ].dagnode ) {
1650  continue;
1651  }
1652  if ( model.joints[ j ].dagnode->name() == parentNode->name() ) {
1653  joint->mayaNode.ParentTo( model.joints[ j ].mayaNode );
1654  joint->exportNode.ParentTo( model.joints[ j ].exportNode );
1655  break;
1656  }
1657  }
1658 
1659  delete parentNode;
1660  }
1661 
1662  // create long name
1663  parent = joint->mayaNode.GetParent();
1664  if ( parent ) {
1665  joint->longname = parent->longname + "/" + joint->name;
1666  } else {
1667  joint->longname = joint->name;
1668  }
1669 
1670  // get the joint's scale
1671  GetLocalTransform( &model.joints[ i ], joint->t, joint->wm );
1672  joint->scale = joint->wm[ 0 ].Length();
1673 
1674  if ( parent ) {
1675  joint->scale *= parent->scale;
1676  if ( joint->scale != 0 ) {
1677  joint->invscale = 1.0f / joint->scale;
1678  } else {
1679  joint->invscale = 0;
1680  }
1681  }
1682 
1683  joint->dagnode->getPath( dagPath );
1684  GetBindPose( dagPath.node( &status ), joint, scale );
1685  }
1686 }
1687 
1688 /*
1689 ===============
1690 idMayaExport::RenameJoints
1691 ===============
1692 */
1693 void idMayaExport::RenameJoints( idList<idNamePair> &renamejoints, idStr &prefix ) {
1694  int i;
1695  idExportJoint *joint;
1696 
1697  // rename joints that match the prefix
1698  if ( prefix.Length() ) {
1699  joint = model.joints.Ptr();
1700  for( i = 0; i < model.joints.Num(); i++, joint++ ) {
1701  if ( !joint->name.Cmpn( prefix, prefix.Length() ) ) {
1702  // remove the prefix from the name
1703  joint->name = joint->name.Right( joint->name.Length() - prefix.Length() );
1704  }
1705  }
1706  }
1707 
1708  // rename joints if necessary
1709  for( i = 0; i < renamejoints.Num(); i++ ) {
1710  joint = model.FindJoint( renamejoints[ i ].from );
1711  if ( joint ) {
1712  joint->name = renamejoints[ i ].to;
1713  }
1714  }
1715 }
1716 
1717 /*
1718 ===============
1719 idMayaExport::RemapParents
1720 ===============
1721 */
1723  int i;
1724  idExportJoint *joint;
1725  idExportJoint *parent;
1726  idExportJoint *origin;
1727  idExportJoint *sibling;
1728 
1729  for( i = 0; i < remapjoints.Num(); i++ ) {
1730  // find joint to reparent
1731  joint = model.FindJoint( remapjoints[ i ].from );
1732  if ( !joint ) {
1733  // couldn't find joint, fail
1734  MayaError( "Couldn't find joint '%s' to reparent\n", remapjoints[ i ].from.c_str() );
1735  }
1736 
1737  // find new parent joint
1738  parent = model.FindJoint( remapjoints[ i ].to );
1739  if ( !parent ) {
1740  // couldn't find parent, fail
1741  MayaError( "Couldn't find joint '%s' to be new parent for '%s'\n", remapjoints[ i ].to.c_str(), remapjoints[ i ].from.c_str() );
1742  }
1743 
1744  if ( parent->exportNode.ParentedBy( joint->exportNode ) ) {
1745  MayaError( "Joint '%s' is a child of joint '%s' and can't become the parent.", joint->name.c_str(), parent->name.c_str() );
1746  }
1747  joint->exportNode.ParentTo( parent->exportNode );
1748  }
1749 
1750  // if we have an origin, make it the first node in the export list, otherwise add one
1751  origin = model.FindJoint( "origin" );
1752  if ( !origin ) {
1753  origin = model.exportOrigin;
1754  origin->dagnode = NULL;
1755  origin->name = "origin";
1756  origin->realname = "origin";
1757  origin->bindmat.Identity();
1758  origin->bindpos.Zero();
1759  }
1760 
1761  origin->exportNode.ParentTo( model.exportHead );
1762 
1763  // force the joint to be kept
1764  origin->keep = true;
1765 
1766  // make all root joints children of the origin joint
1767  joint = model.exportHead.GetChild();
1768  while( joint ) {
1769  sibling = joint->exportNode.GetSibling();
1770  if ( joint != origin ) {
1771  joint->exportNode.ParentTo( origin->exportNode );
1772  }
1773  joint = sibling;
1774  }
1775 
1776  return true;
1777 }
1778 
1779 /*
1780 ===============
1781 idMayaExport::FindShader
1782 
1783 Find the shading node for the given shading group set node.
1784 ===============
1785 */
1786 MObject idMayaExport::FindShader( MObject& setNode ) {
1787  MStatus status;
1788  MFnDependencyNode fnNode( setNode );
1789  MPlug shaderPlug;
1790 
1791  shaderPlug = fnNode.findPlug( "surfaceShader" );
1792  if ( !shaderPlug.isNull() ) {
1793  MPlugArray connectedPlugs;
1794  bool asSrc = false;
1795  bool asDst = true;
1796  shaderPlug.connectedTo( connectedPlugs, asDst, asSrc, &status );
1797 
1798  if ( connectedPlugs.length() != 1 ) {
1799  MayaError( "FindShader: Error getting shader (%s)", status.errorString().asChar() );
1800  } else {
1801  return connectedPlugs[ 0 ].node();
1802  }
1803  }
1804 
1805  return MObject::kNullObj;
1806 }
1807 
1808 /*
1809 ===============
1810 idMayaExport::GetTextureForMesh
1811 
1812 Find the texture files that apply to the color of each polygon of
1813 a selected shape if the shape has its polygons organized into sets.
1814 ===============
1815 */
1816 void idMayaExport::GetTextureForMesh( idExportMesh *mesh, MFnDagNode &dagNode ) {
1817  MStatus status;
1818  MDagPath path;
1819  int i;
1820  int instanceNum;
1821 
1822  status = dagNode.getPath( path );
1823  if ( !status ) {
1824  return;
1825  }
1826 
1827  path.extendToShape();
1828 
1829  // If the shape is instanced then we need to determine which
1830  // instance this path refers to.
1831  //
1832  instanceNum = 0;
1833  if ( path.isInstanced() ) {
1834  instanceNum = path.instanceNumber();
1835  }
1836 
1837  // Get a list of all sets pertaining to the selected shape and the
1838  // members of those sets.
1839  //
1840  MFnMesh fnMesh( path );
1841  MObjectArray sets;
1842  MObjectArray comps;
1843  status = fnMesh.getConnectedSetsAndMembers( instanceNum, sets, comps, true );
1844  if ( !status ) {
1845  MayaError( "GetTextureForMesh: MFnMesh::getConnectedSetsAndMembers failed (%s)", status.errorString().asChar() );
1846  }
1847 
1848  // Loop through all the sets. If the set is a polygonal set, find the
1849  // shader attached to the and print out the texture file name for the
1850  // set along with the polygons in the set.
1851  //
1852  for ( i = 0; i < ( int )sets.length(); i++ ) {
1853  MObject set = sets[i];
1854  MObject comp = comps[i];
1855 
1856  MFnSet fnSet( set, &status );
1857  if ( status == MS::kFailure ) {
1858  MayaError( "GetTextureForMesh: MFnSet constructor failed (%s)", status.errorString().asChar() );
1859  continue;
1860  }
1861 
1862  // Make sure the set is a polygonal set. If not, continue.
1863  MItMeshPolygon piter(path, comp, &status);
1864  if (status == MS::kFailure) {
1865  continue;
1866  }
1867 
1868  // Find the texture that is applied to this set. First, get the
1869  // shading node connected to the set. Then, if there is an input
1870  // attribute called "color", search upstream from it for a texture
1871  // file node.
1872  //
1873  MObject shaderNode = FindShader( set );
1874  if ( shaderNode == MObject::kNullObj ) {
1875  continue;
1876  }
1877 
1878  MPlug colorPlug = MFnDependencyNode(shaderNode).findPlug("color", &status);
1879  if ( status == MS::kFailure ) {
1880  continue;
1881  }
1882 
1883  MItDependencyGraph dgIt(colorPlug, MFn::kFileTexture,
1884  MItDependencyGraph::kUpstream,
1885  MItDependencyGraph::kBreadthFirst,
1886  MItDependencyGraph::kNodeLevel,
1887  &status);
1888 
1889  if ( status == MS::kFailure ) {
1890  continue;
1891  }
1892 
1893  dgIt.disablePruningOnFilter();
1894 
1895  // If no texture file node was found, just continue.
1896  //
1897  if ( dgIt.isDone() ) {
1898  continue;
1899  }
1900 
1901  // Print out the texture node name and texture file that it references.
1902  //
1903  MObject textureNode = dgIt.thisNode();
1904  MPlug filenamePlug = MFnDependencyNode( textureNode ).findPlug( "fileTextureName" );
1905  MString textureName;
1906  filenamePlug.getValue( textureName );
1907 
1908  // remove the OS path and save it in the mesh
1909  OSPathToRelativePath( textureName.asChar(), mesh->shader, options.game );
1910  mesh->shader.StripFileExtension();
1911 
1912  return;
1913  }
1914 }
1915 
1916 /*
1917 ===============
1918 idMayaExport::CopyMesh
1919 ===============
1920 */
1921 idExportMesh *idMayaExport::CopyMesh( MFnSkinCluster &skinCluster, float scale ) {
1922  MStatus status;
1923  MObjectArray objarray;
1924  MObjectArray outputarray;
1925  int nGeom;
1926  int i, j, k;
1927  idExportMesh *mesh;
1928  float uv_u, uv_v;
1929  idStr name, altname;
1930  int pos;
1931 
1932  status = skinCluster.getInputGeometry( objarray );
1933  if ( !status ) {
1934  MayaError( "CopyMesh: Error getting input geometry (%s)", status.errorString().asChar() );
1935  return NULL;
1936  }
1937 
1938  nGeom = objarray.length();
1939  for( i = 0; i < nGeom; i++ ) {
1940  MFnDagNode dagNode( objarray[ i ], &status );
1941  if ( !status ) {
1942  common->Printf( "CopyMesh: MFnDagNode Constructor failed (%s)", status.errorString().asChar() );
1943  continue;
1944  }
1945 
1946  MFnMesh fnmesh( objarray[ i ], &status );
1947  if ( !status ) {
1948  // object isn't an MFnMesh
1949  continue;
1950  }
1951 
1952  status = skinCluster.getOutputGeometry( outputarray );
1953  if ( !status ) {
1954  common->Printf( "CopyMesh: Error getting output geometry (%s)", status.errorString().asChar() );
1955  return NULL;
1956  }
1957 
1958  if ( outputarray.length() < 1 ) {
1959  return NULL;
1960  }
1961 
1962  name = fnmesh.name().asChar();
1963  if ( options.prefix.Length() ) {
1964  if ( !name.Cmpn( options.prefix, options.prefix.Length() ) ) {
1965  // remove the prefix from the name
1966  name = name.Right( name.Length() - options.prefix.Length() );
1967  } else {
1968  // name doesn't match prefix, so don't use this mesh
1969  //return NULL;
1970  }
1971  }
1972 
1973  pos = name.Find( "ShapeOrig" );
1974  if ( pos >= 0 ) {
1975  name.CapLength( pos );
1976  }
1977 
1978  MFnDagNode dagNode2( outputarray[ 0 ], &status );
1979  if ( !status ) {
1980  common->Printf( "CopyMesh: MFnDagNode Constructor failed (%s)", status.errorString().asChar() );
1981  continue;
1982  }
1983 
1984  altname = name;
1985  MObject parent = fnmesh.parent( 0, &status );
1986  if ( status ) {
1987  MFnDagNode parentNode( parent, &status );
1988  if ( status ) {
1989  altname = parentNode.name().asChar();
1990  }
1991  }
1992 
1994  altname.StripLeadingOnce( options.prefix );
1995  if ( options.keepmeshes.Num() ) {
1996  if ( !options.keepmeshes.Find( name ) && !options.keepmeshes.Find( altname ) ) {
1997  if ( altname != name ) {
1998  common->Printf( "Skipping mesh '%s' ('%s')\n", name.c_str(), altname.c_str() );
1999  } else {
2000  common->Printf( "Skipping mesh '%s'\n", name.c_str() );
2001  }
2002  return NULL;
2003  }
2004  }
2005 
2006  if ( options.skipmeshes.Find( name ) || options.skipmeshes.Find( altname ) ) {
2007  common->Printf( "Skipping mesh '%s' ('%s')\n", name.c_str(), altname.c_str() );
2008  return NULL;
2009  }
2010 
2011  mesh = new idExportMesh();
2012  model.meshes.Append( mesh );
2013 
2014  if ( altname.Length() ) {
2015  mesh->name = altname;
2016  } else {
2017  mesh->name = name;
2018  }
2019  GetTextureForMesh( mesh, dagNode2 );
2020 
2021  int v = fnmesh.numVertices( &status );
2022  mesh->verts.SetNum( v );
2023 
2024  MFloatPointArray vertexArray;
2025 
2026  fnmesh.getPoints( vertexArray, MSpace::kPreTransform );
2027 
2028  for( j = 0; j < v; j++ ) {
2029  memset( &mesh->verts[ j ], 0, sizeof( mesh->verts[ j ] ) );
2030  mesh->verts[ j ].pos = ConvertToIdSpace( idVec( vertexArray[ j ] ) ) * scale;
2031  }
2032 
2033  MIntArray vertexList;
2034  int p;
2035 
2036  p = fnmesh.numPolygons( &status );
2037  mesh->tris.SetNum( p );
2038  mesh->uv.SetNum( p );
2039 
2040  MString setName;
2041 
2042  status = fnmesh.getCurrentUVSetName( setName );
2043  if ( !status ) {
2044  MayaError( "CopyMesh: MFnMesh::getCurrentUVSetName failed (%s)", status.errorString().asChar() );
2045  }
2046 
2047  for( j = 0; j < p; j++ ) {
2048  fnmesh.getPolygonVertices( j, vertexList );
2049  if ( vertexList.length() != 3 ) {
2050  MayaError( "CopyMesh: Too many vertices on a face (%d)\n", vertexList.length() );
2051  }
2052 
2053  for( k = 0; k < 3; k++ ) {
2054  mesh->tris[ j ].indexes[ k ] = vertexList[ k ];
2055 
2056  status = fnmesh.getPolygonUV( j, k, uv_u, uv_v, &setName );
2057  if ( !status ) {
2058  MayaError( "CopyMesh: MFnMesh::getPolygonUV failed (%s)", status.errorString().asChar() );
2059  }
2060 
2061  mesh->uv[ j ].uv[ k ][ 0 ] = uv_u;
2062  mesh->uv[ j ].uv[ k ][ 1 ] = uv_v;
2063  }
2064  }
2065 
2066  return mesh;
2067  }
2068 
2069  return NULL;
2070 }
2071 
2072 /*
2073 ===============
2074 idMayaExport::CreateMesh
2075 ===============
2076 */
2078  size_t count;
2079  idExportMesh *mesh;
2080  MStatus status;
2081  exportWeight_t weight;
2082  unsigned int nGeoms;
2083 
2084  // Iterate through graph and search for skinCluster nodes
2085  MItDependencyNodes iter( MFn::kSkinClusterFilter );
2086  count = 0;
2087  for ( ; !iter.isDone(); iter.next() ) {
2088  MObject object = iter.item();
2089 
2090  count++;
2091 
2092  // For each skinCluster node, get the list of influence objects
2093  MFnSkinCluster skinCluster( object, &status );
2094  if ( !status ) {
2095  MayaError( "%s: Error getting skin cluster (%s)", object.apiTypeStr(), status.errorString().asChar() );
2096  }
2097 
2098  mesh = CopyMesh( skinCluster, scale );
2099  if ( !mesh ) {
2100  continue;
2101  }
2102 
2103  MDagPathArray infs;
2104  unsigned int nInfs = skinCluster.influenceObjects(infs, &status);
2105  if ( !status ) {
2106  MayaError( "Mesh '%s': Error getting influence objects (%s)", mesh->name.c_str(), status.errorString().asChar() );
2107  }
2108 
2109  if ( 0 == nInfs ) {
2110  MayaError( "Mesh '%s': No influence objects found", mesh->name.c_str() );
2111  }
2112 
2113  // loop through the geometries affected by this cluster
2114  nGeoms = skinCluster.numOutputConnections();
2115  for (size_t ii = 0; ii < nGeoms; ++ii) {
2116  unsigned int index = skinCluster.indexForOutputConnection(ii,&status);
2117 
2118  if ( !status ) {
2119  MayaError( "Mesh '%s': Error getting geometry index (%s)", mesh->name.c_str(), status.errorString().asChar() );
2120  }
2121 
2122  // get the dag path of the ii'th geometry
2123  MDagPath skinPath;
2124  status = skinCluster.getPathAtIndex(index,skinPath);
2125  if ( !status ) {
2126  MayaError( "Mesh '%s': Error getting geometry path (%s)", mesh->name.c_str(), status.errorString().asChar() );
2127  }
2128 
2129  // iterate through the components of this geometry
2130  MItGeometry gIter( skinPath );
2131 
2132  // print out the influence objects
2133  idList<idExportJoint *> joints;
2134  idExportJoint *joint;
2135  exportVertex_t *vert;
2136 
2137  joints.Resize( nInfs );
2138  for (size_t kk = 0; kk < nInfs; ++kk) {
2139  const char *c;
2140  MString s;
2141 
2142  s = infs[kk].partialPathName();
2143  c = s.asChar();
2144  joint = model.FindJointReal( c );
2145  if ( !joint ) {
2146  MayaError( "Mesh '%s': joint %s not found", mesh->name.c_str(), c );
2147  }
2148 
2149  joints.Append( joint );
2150  }
2151 
2152  for ( /* nothing */ ; !gIter.isDone(); gIter.next() ) {
2153  MObject comp = gIter.component( &status );
2154  if ( !status ) {
2155  MayaError( "Mesh '%s': Error getting component (%s)", mesh->name.c_str(), status.errorString().asChar() );
2156  }
2157 
2158  // Get the weights for this vertex (one per influence object)
2159  MFloatArray wts;
2160  unsigned infCount;
2161  status = skinCluster.getWeights(skinPath,comp,wts,infCount);
2162  if ( !status ) {
2163  MayaError( "Mesh '%s': Error getting weights (%s)", mesh->name.c_str(), status.errorString().asChar() );
2164  }
2165  if (0 == infCount) {
2166  MayaError( "Mesh '%s': Error: 0 influence objects.", mesh->name.c_str() );
2167  }
2168 
2169  int num = gIter.index();
2170  vert = &mesh->verts[ num ];
2171  vert->startweight = mesh->weights.Num();
2172 
2173  float totalweight = 0.0f;
2174 
2175  // copy the weight data for this vertex
2176  int numNonZeroWeights = 0;
2177  int jj;
2178  for ( jj = 0; jj < (int)infCount ; ++jj ) {
2179  float w = ( float )wts[ jj ];
2180  if ( w > 0.0f ) {
2181  numNonZeroWeights++;
2182  }
2183  if ( w > options.jointThreshold ) {
2184  weight.joint = joints[ jj ];
2185  weight.jointWeight = wts[ jj ];
2186 
2187  if ( !options.ignoreScale ) {
2188  weight.joint->bindmat.ProjectVector( vert->pos - ( weight.joint->bindpos * weight.joint->invscale ), weight.offset );
2189  weight.offset *= weight.joint->scale;
2190  } else {
2191  weight.joint->bindmat.ProjectVector( vert->pos - weight.joint->bindpos, weight.offset );
2192  }
2193  mesh->weights.Append( weight );
2194  totalweight += weight.jointWeight;
2195  }
2196  }
2197 
2198  vert->numWeights = mesh->weights.Num() - vert->startweight;
2199  if ( !vert->numWeights ) {
2200  if ( numNonZeroWeights ) {
2201  MayaError( "Error on mesh '%s': Vertex %d doesn't have any joint weights exceeding jointThreshold (%f).", mesh->name.c_str(), num, options.jointThreshold );
2202  } else {
2203  MayaError( "Error on mesh '%s': Vertex %d doesn't have any joint weights.", mesh->name.c_str(), num );
2204  }
2205  } else if ( !totalweight ) {
2206  MayaError( "Error on mesh '%s': Combined weight of 0 on vertex %d.", mesh->name.c_str(), num );
2207  }
2208  //if ( numNonZeroWeights ) {
2209  // common->Printf( "Mesh '%s': skipped %d out of %d weights on vertex %d\n", mesh->name.c_str(), numNonZeroWeights, numNonZeroWeights + vert->numWeights, num );
2210  //}
2211 
2212  // normalize the joint weights
2213  for( jj = 0; jj < vert->numWeights; jj++ ) {
2214  mesh->weights[ vert->startweight + jj ].jointWeight /= totalweight;
2215  }
2216  }
2217  break;
2218  }
2219  }
2220 
2221  if ( !count && !options.ignoreMeshes ) {
2222  MayaError( "CreateMesh: No skinClusters found in this scene.\n" );
2223  }
2224 }
2225 
2226 /*
2227 ===============
2228 idMayaExport::CombineMeshes
2229 
2230 combine surfaces with the same shader.
2231 ===============
2232 */
2234  int i, j;
2235  int count;
2236  idExportMesh *mesh;
2237  idExportMesh *combine;
2238  idList<idExportMesh *> oldmeshes;
2239 
2240  oldmeshes = model.meshes;
2241  model.meshes.Clear();
2242 
2243  count = 0;
2244  for( i = 0; i < oldmeshes.Num(); i++ ) {
2245  mesh = oldmeshes[ i ];
2246  if ( !mesh->keep ) {
2247  delete mesh;
2248  continue;
2249  }
2250 
2251  combine = NULL;
2252  for( j = 0; j < model.meshes.Num(); j++ ) {
2253  if ( model.meshes[ j ]->shader == mesh->shader ) {
2254  combine = model.meshes[ j ];
2255  break;
2256  }
2257  }
2258 
2259  if ( combine ) {
2260  combine->Merge( mesh );
2261  delete mesh;
2262  count++;
2263  } else {
2264  model.meshes.Append( mesh );
2265  }
2266  }
2267 
2268  // share verts
2269  for( i = 0; i < model.meshes.Num(); i++ ) {
2270  model.meshes[ i ]->ShareVerts();
2271  }
2272 
2273  common->Printf( "Merged %d meshes\n", count );
2274 }
2275 
2276 /*
2277 ===============
2278 idMayaExport::GetAlignment
2279 ===============
2280 */
2281 void idMayaExport::GetAlignment( idStr &alignName, idMat3 &align, float rotate, int startframe ) {
2282  idVec3 pos;
2283  idExportJoint *joint;
2284  idAngles ang( 0, rotate, 0 );
2285  idMat3 mat;
2286 
2287  align.Identity();
2288 
2289  if ( alignName.Length() ) {
2290  SetFrame( 0 );
2291 
2292  joint = model.FindJoint( alignName );
2293  if ( !joint ) {
2294  MayaError( "could not find joint '%s' to align model to.\n", alignName.c_str() );
2295  }
2296 
2297  // found it
2298  GetWorldTransform( joint, pos, mat, 1.0f );
2299  align[ 0 ][ 0 ] = mat[ 2 ][ 0 ];
2300  align[ 0 ][ 1 ] = -mat[ 2 ][ 2 ];
2301  align[ 0 ][ 2 ] = mat[ 2 ][ 1 ];
2302 
2303  align[ 1 ][ 0 ] = mat[ 0 ][ 0 ];
2304  align[ 1 ][ 1 ] = -mat[ 0 ][ 2 ];
2305  align[ 1 ][ 2 ] = mat[ 0 ][ 1 ];
2306 
2307  align[ 2 ][ 0 ] = mat[ 1 ][ 0 ];
2308  align[ 2 ][ 1 ] = -mat[ 1 ][ 2 ];
2309  align[ 2 ][ 2 ] = mat[ 1 ][ 1 ];
2310 
2311  if ( rotate ) {
2312  align *= ang.ToMat3();
2313  }
2314  } else if ( rotate ) {
2315  align = ang.ToMat3();
2316  }
2317 
2318  align.TransposeSelf();
2319 }
2320 
2321 /*
2322 ===============
2323 idMayaExport::GetObjectType
2324 
2325 return the type of the object
2326 ===============
2327 */
2328 const char *idMayaExport::GetObjectType( MObject object ) {
2329  if( object.isNull() ) {
2330  return "(Null)";
2331  }
2332 
2333  MStatus stat;
2334  MFnDependencyNode dgNode;
2335  MString typeName;
2336 
2337  stat = dgNode.setObject( object );
2338  typeName = dgNode.typeName( &stat );
2339  if( MS::kSuccess != stat ) {
2340  // can not get the type name of this object
2341  return "(Unknown)";
2342  }
2343 
2344  return typeName.asChar();
2345 }
2346 
2347 /*
2348 ===============
2349 idMayaExport::GetCameraFov
2350 ===============
2351 */
2353  int childCount;
2354  int j;
2355  double horiz;
2356  double focal;
2357  MStatus status;
2358  const char *n1, *n2;
2359  MFnDagNode *dagnode;
2360  float fov;
2361 
2362  dagnode = joint->dagnode;
2363 
2364  MObject cameraNode = dagnode->object();
2365  childCount = dagnode->childCount();
2366 
2367  fov = 90.0f;
2368  for( j = 0; j < childCount; j++ ) {
2369  MObject childNode = dagnode->child( j );
2370 
2371  n1 = GetObjectType( cameraNode );
2372  n2 = GetObjectType( childNode );
2373  if ( ( !strcmp( "transform", n1 ) ) && ( !strcmp( "camera", n2 ) ) ) {
2374  MFnCamera camera( childNode );
2375  focal = camera.focalLength();
2376  horiz = camera.horizontalFilmAperture();
2377  fov = RAD2DEG( 2 * atan( ( horiz * 0.5 ) / ( focal / 25.4 ) ) );
2378  break;
2379  }
2380  }
2381 
2382  return fov;
2383 }
2384 
2385 /*
2386 ===============
2387 idMayaExport::GetCameraFrame
2388 ===============
2389 */
2391  idMat3 mat;
2392  idMat3 axis;
2393  idVec3 pos;
2394 
2395  // get the worldspace positions of the joint
2396  GetWorldTransform( camera, pos, axis, 1.0f );
2397 
2398  // convert to id coordinates
2399  cam->t = ConvertToIdSpace( pos ) * align;
2400 
2401  // correct the orientation for the game
2402  axis = ConvertToIdSpace( axis ) * align;
2403  mat[ 0 ] = -axis[ 2 ];
2404  mat[ 1 ] = -axis[ 0 ];
2405  mat[ 2 ] = axis[ 1 ];
2406  cam->q = mat.ToQuat().ToCQuat();
2407 
2408  // get it's fov
2409  cam->fov = GetCameraFov( camera );
2410 }
2411 
2412 /*
2413 ===============
2414 idMayaExport::CreateCameraAnim
2415 ===============
2416 */
2418  float start, end;
2419  MDagPath dagPath;
2420  int frameNum;
2421  short v;
2422  MStatus status;
2423  cameraFrame_t cam;
2424  idExportJoint *refCam;
2425  idExportJoint *camJoint;
2426  idStr currentCam;
2427  idStr newCam;
2428  MPlug plug;
2429  MFnEnumAttribute cameraAttribute;
2430 
2431  start = TimeForFrame( options.startframe );
2432  end = TimeForFrame( options.endframe );
2433 
2434 #if 0
2435  options.framerate = 60;
2436  model.numFrames = ( int )( ( end - start ) * ( float )options.framerate ) + 1;
2438 #else
2441 #endif
2442 
2443  common->Printf( "start frame = %d\n end frame = %d\n", options.startframe, options.endframe );
2444  common->Printf( " start time = %f\n end time = %f\n total time = %f\n", start, end, end - start );
2445 
2446  if ( start > end ) {
2447  MayaError( "Start frame is greater than end frame." );
2448  }
2449 
2450  refCam = model.FindJoint( "refcam" );
2451  if ( refCam == NULL ) {
2452  currentCam = MAYA_DEFAULT_CAMERA;
2453  } else {
2454  MObject cameraNode = refCam->dagnode->object();
2455  MFnDependencyNode cameraDG( cameraNode, &status );
2456  if( MS::kSuccess != status ) {
2457  MayaError( "Can't find 'refcam' dependency node." );
2458  return;
2459  }
2460 
2461  MObject attr = cameraDG.attribute( MString( "Camera" ), &status );
2462  if( MS::kSuccess != status ) {
2463  MayaError( "Can't find 'Camera' attribute on 'refcam'." );
2464  return;
2465  }
2466 
2467  plug = MPlug( cameraNode, attr );
2468  status = cameraAttribute.setObject( attr );
2469  if( MS::kSuccess != status ) {
2470  MayaError( "Bad 'Camera' attribute on 'refcam'." );
2471  return;
2472  }
2473 
2474  model.camera.Clear();
2476 
2477  SetFrame( 0 );
2478  status = plug.getValue( v );
2479  currentCam = cameraAttribute.fieldName( v, &status ).asChar();
2480  if( MS::kSuccess != status ) {
2481  MayaError( "Error getting camera name on frame %d", GetMayaFrameNum( 0 ) );
2482  }
2483  }
2484 
2485  camJoint = model.FindJoint( currentCam );
2486  if ( !camJoint ) {
2487  MayaError( "Couldn't find camera '%s'", currentCam.c_str() );
2488  }
2489 
2490  for( frameNum = 0; frameNum < model.numFrames; frameNum++ ) {
2491  common->Printf( "\rFrame %d/%d...", options.startframe + frameNum, options.endframe );
2492 
2493 #if 0
2494  MTime time;
2495  time.setUnit( MTime::kSeconds );
2496  time.setValue( start + ( ( float )frameNum / ( float )options.framerate ) );
2497  MGlobal::viewFrame( time );
2498 #else
2499  SetFrame( frameNum );
2500 #endif
2501 
2502  // get the position for this frame
2503  GetCameraFrame( camJoint, align, &model.camera.Alloc() );
2504 
2505  if ( refCam != NULL ) {
2506  status = plug.getValue( v );
2507  newCam = cameraAttribute.fieldName( v, &status ).asChar();
2508  if( MS::kSuccess != status ) {
2509  MayaError( "Error getting camera name on frame %d", GetMayaFrameNum( frameNum ) );
2510  }
2511 
2512  if ( newCam != currentCam ) {
2513  // place a cut at our last frame
2515 
2516  currentCam = newCam;
2517  camJoint = model.FindJoint( currentCam );
2518  if ( !camJoint ) {
2519  MayaError( "Couldn't find camera '%s'", currentCam.c_str() );
2520  }
2521 
2522  // get the position for this frame
2523  GetCameraFrame( camJoint, align, &model.camera.Alloc() );
2524  }
2525  }
2526  }
2527 
2528  common->Printf( "\n" );
2529 }
2530 
2531 /*
2532 ===============
2533 idMayaExport::GetDefaultPose
2534 ===============
2535 */
2537  float start;
2538  MDagPath dagPath;
2539  idMat3 jointaxis;
2540  idVec3 jointpos;
2541  idExportJoint *joint, *parent;
2542  idBounds bnds;
2543  idBounds meshBounds;
2544  idList<jointFrame_t> frame;
2545 
2546  start = TimeForFrame( options.startframe );
2547 
2548  common->Printf( "default pose frame = %d\n", options.startframe );
2549  common->Printf( " default pose time = %f\n", start );
2550 
2551  frame.SetNum( model.joints.Num() );
2552  SetFrame( 0 );
2553 
2554  // convert joints into local coordinates and save in channels
2555  for( joint = model.exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
2556  if ( !joint->dagnode ) {
2557  // custom origin joint
2558  joint->idwm.Identity();
2559  joint->idt.Zero();
2560  frame[ joint->index ].t.Zero();
2561  frame[ joint->index ].q.Set( 0.0f, 0.0f, 0.0f );
2562  continue;
2563  }
2564 
2565  // get the worldspace positions of the joint
2566  GetWorldTransform( joint, jointpos, jointaxis, options.scale );
2567 
2568  // convert to id coordinates
2569  jointaxis = ConvertToIdSpace( jointaxis ) * align;
2570  jointpos = ConvertToIdSpace( jointpos ) * align;
2571 
2572  // save worldspace position of joint for children
2573  joint->idwm = jointaxis;
2574  joint->idt = jointpos;
2575 
2576  parent = joint->exportNode.GetParent();
2577  if ( parent ) {
2578  // convert to local coordinates
2579  jointpos = ( jointpos - parent->idt ) * parent->idwm.Transpose();
2580  jointaxis = jointaxis * parent->idwm.Transpose();
2581  } else if ( joint->name == "origin" ) {
2582  if ( options.clearOrigin ) {
2583  jointpos.Zero();
2584  }
2585  if ( options.clearOriginAxis ) {
2586  jointaxis.Identity();
2587  }
2588  }
2589 
2590  frame[ joint->index ].t = jointpos;
2591  frame[ joint->index ].q = jointaxis.ToQuat().ToCQuat();
2592  }
2593 
2594  // relocate origin to start at 0, 0, 0 for first frame
2595  joint = model.FindJoint( "origin" );
2596  if ( joint ) {
2597  frame[ joint->index ].t.Zero();
2598  }
2599 
2600  // transform the hierarchy
2601  for( joint = model.exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
2602  jointpos = frame[ joint->index ].t;
2603  jointaxis = frame[ joint->index ].q.ToQuat().ToMat3();
2604 
2605  parent = joint->exportNode.GetParent();
2606  if ( parent ) {
2607  joint->idwm = jointaxis * parent->idwm;
2608  joint->idt = parent->idt + jointpos * parent->idwm;
2609  } else {
2610  joint->idwm = jointaxis;
2611  joint->idt = jointpos;
2612  }
2613 
2614  joint->bindmat = joint->idwm;
2615  joint->bindpos = joint->idt;
2616  }
2617 
2618  common->Printf( "\n" );
2619 }
2620 
2621 /*
2622 ===============
2623 idMayaExport::CreateAnimation
2624 ===============
2625 */
2627  int i;
2628  float start, end;
2629  MDagPath dagPath;
2630  idMat3 jointaxis;
2631  idVec3 jointpos;
2632  int frameNum;
2633  idExportJoint *joint, *parent;
2634  idBounds bnds;
2635  idBounds meshBounds;
2636  jointFrame_t *frame;
2637  int cycleStart;
2638  idVec3 totalDelta;
2639  idList<jointFrame_t> copyFrames;
2640 
2641  start = TimeForFrame( options.startframe );
2642  end = TimeForFrame( options.endframe );
2643 
2646 
2647  common->Printf( "start frame = %d\n end frame = %d\n", options.startframe, options.endframe );
2648  common->Printf( " start time = %f\n end time = %f\n total time = %f\n", start, end, end - start );
2649 
2650  if ( start > end ) {
2651  MayaError( "Start frame is greater than end frame." );
2652  }
2653 
2657  for( i = 0; i < model.numFrames; i++ ) {
2658  model.frames[ i ] = &model.jointFrames[ model.joints.Num() * i ];
2659  }
2660 
2661  // *sigh*. cyclestart doesn't work nicely with the anims.
2662  // may just want to not do it in SetTime anymore.
2663  cycleStart = options.cycleStart;
2665 
2666  for( frameNum = 0; frameNum < model.numFrames; frameNum++ ) {
2667  common->Printf( "\rFrame %d/%d...", options.startframe + frameNum, options.endframe );
2668 
2669  frame = model.frames[ frameNum ];
2670  SetFrame( frameNum );
2671 
2672  // convert joints into local coordinates and save in channels
2673  for( joint = model.exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
2674  if ( !joint->dagnode ) {
2675  // custom origin joint
2676  joint->idwm.Identity();
2677  joint->idt.Zero();
2678  frame[ joint->index ].t.Zero();
2679  frame[ joint->index ].q.Set( 0.0f, 0.0f, 0.0f );
2680  continue;
2681  }
2682 
2683  // get the worldspace positions of the joint
2684  GetWorldTransform( joint, jointpos, jointaxis, options.scale );
2685 
2686  // convert to id coordinates
2687  jointaxis = ConvertToIdSpace( jointaxis ) * align;
2688  jointpos = ConvertToIdSpace( jointpos ) * align;
2689 
2690  // save worldspace position of joint for children
2691  joint->idwm = jointaxis;
2692  joint->idt = jointpos;
2693 
2694  parent = joint->exportNode.GetParent();
2695  if ( parent ) {
2696  // convert to local coordinates
2697  jointpos = ( jointpos - parent->idt ) * parent->idwm.Transpose();
2698  jointaxis = jointaxis * parent->idwm.Transpose();
2699  } else if ( joint->name == "origin" ) {
2700  if ( options.clearOrigin ) {
2701  jointpos.Zero();
2702  }
2703  if ( options.clearOriginAxis ) {
2704  jointaxis.Identity();
2705  }
2706  }
2707 
2708  frame[ joint->index ].t = jointpos;
2709  frame[ joint->index ].q = jointaxis.ToQuat().ToCQuat();
2710  }
2711  }
2712 
2713  options.cycleStart = cycleStart;
2714  totalDelta.Zero();
2715 
2716  joint = model.FindJoint( "origin" );
2717  if ( joint ) {
2718  frame = model.frames[ 0 ];
2719  idVec3 origin = frame[ joint->index ].t;
2720 
2721  frame = model.frames[ model.numFrames - 1 ];
2722  totalDelta = frame[ joint->index ].t - origin;
2723  }
2724 
2725  // shift the frames when cycleStart is used
2727  copyFrames = model.jointFrames;
2728  for( i = 0; i < model.numFrames; i++ ) {
2729  bool shiftorigin = false;
2730  frameNum = i + ( options.cycleStart - options.startframe );
2731  if ( frameNum >= model.numFrames ) {
2732  // wrap around, skipping the first frame, since it's a dupe of the last frame
2733  frameNum -= model.numFrames - 1;
2734  shiftorigin = true;
2735  }
2736 
2737  memcpy( &model.jointFrames[ model.joints.Num() * i ], &copyFrames[ model.joints.Num() * frameNum ], model.joints.Num() * sizeof( copyFrames[ 0 ] ) );
2738 
2739  if ( joint && shiftorigin ) {
2740  model.frames[ i ][ joint->index ].t += totalDelta;
2741  }
2742  }
2743  }
2744 
2745  if ( joint ) {
2746  // relocate origin to start at 0, 0, 0 for first frame
2747  frame = model.frames[ 0 ];
2748  idVec3 origin = frame[ joint->index ].t;
2749  for( i = 0; i < model.numFrames; i++ ) {
2750  frame = model.frames[ i ];
2751  frame[ joint->index ].t -= origin;
2752  }
2753  }
2754 
2755  // get the bounds for each frame
2756  for( frameNum = 0; frameNum < model.numFrames; frameNum++ ) {
2757  frame = model.frames[ frameNum ];
2758 
2759  // transform the hierarchy
2760  for( joint = model.exportHead.GetNext(); joint != NULL; joint = joint->exportNode.GetNext() ) {
2761  jointpos = frame[ joint->index ].t;
2762  jointaxis = frame[ joint->index ].q.ToQuat().ToMat3();
2763 
2764  parent = joint->exportNode.GetParent();
2765  if ( parent ) {
2766  joint->idwm = jointaxis * parent->idwm;
2767  joint->idt = parent->idt + jointpos * parent->idwm;
2768  } else {
2769  joint->idwm = jointaxis;
2770  joint->idt = jointpos;
2771  }
2772  }
2773 
2774  // get bounds for this frame
2775  bnds.Clear();
2776  for( i = 0; i < model.meshes.Num(); i++ ) {
2777  if ( model.meshes[ i ]->keep ) {
2778  model.meshes[ i ]->GetBounds( meshBounds );
2779  bnds.AddBounds( meshBounds );
2780  }
2781  }
2782  model.bounds[ frameNum ][ 0 ] = bnds[ 0 ];
2783  model.bounds[ frameNum ][ 1 ] = bnds[ 1 ];
2784  }
2785 
2786  common->Printf( "\n" );
2787 }
2788 
2789 /*
2790 ===============
2791 idMayaExport::ConvertModel
2792 ===============
2793 */
2795  MStatus status;
2796  idMat3 align;
2797 
2798  common->Printf( "Converting %s to %s...\n", options.src.c_str(), options.dest.c_str() );
2799 
2800  // see if the destination file exists
2801  FILE *file = fopen( options.dest, "r" );
2802  if ( file ) {
2803  fclose( file );
2804 
2805  // make sure we can write to the destination
2806  FILE *file = fopen( options.dest, "r+" );
2807  if ( !file ) {
2808  MayaError( "Unable to write to the file '%s'", options.dest.c_str() );
2809  }
2810  fclose( file );
2811  }
2812 
2813  MString filename( options.src );
2814  MFileIO::newFile( true );
2815 
2816  // Load the file into Maya
2817  common->Printf( "Loading file...\n" );
2818  status = MFileIO::open( filename, NULL, true );
2819  if ( !status ) {
2820  MayaError( "Error loading '%s': '%s'\n", filename.asChar(), status.errorString().asChar() );
2821  }
2822 
2823  // force Maya to update the frame. When using references, sometimes
2824  // the model is posed the way it is in the source. Since Maya only
2825  // updates it when the frame time changes to a value other than the
2826  // current, just setting the time to the min time doesn't guarantee
2827  // that the model gets updated.
2828  MGlobal::viewFrame( MAnimControl::maxTime() );
2829  MGlobal::viewFrame( MAnimControl::minTime() );
2830 
2831  if ( options.startframe < 0 ) {
2832  options.startframe = MAnimControl::minTime().as( MTime::kFilm );
2833  }
2834 
2835  if ( options.endframe < 0 ) {
2836  options.endframe = MAnimControl::maxTime().as( MTime::kFilm );
2837  }
2838  if ( options.cycleStart < 0 ) {
2840  } else if ( ( options.cycleStart < options.startframe ) || ( options.cycleStart > options.endframe ) ) {
2841  MayaError( "cycleStart (%d) out of frame range (%d to %d)\n", options.cycleStart, options.startframe, options.endframe );
2842  } else if ( options.cycleStart == options.endframe ) {
2843  // end frame is a duplicate of the first frame in cycles, so just disable cycleStart
2845  }
2846 
2847  // create a list of the transform nodes that will make up our heirarchy
2848  common->Printf( "Creating joints...\n" );
2850  if ( options.type != WRITE_CAMERA ) {
2851  common->Printf( "Creating meshes...\n" );
2853  common->Printf( "Renaming joints...\n" );
2855  common->Printf( "Remapping parents...\n" );
2857  common->Printf( "Pruning joints...\n" );
2859  common->Printf( "Combining meshes...\n" );
2860  CombineMeshes();
2861  }
2862 
2863  common->Printf( "Align model...\n" );
2864  GetAlignment( options.align, align, options.rotate, 0 );
2865 
2866  switch( options.type ) {
2867  case WRITE_MESH :
2868  common->Printf( "Grabbing default pose:\n" );
2869  GetDefaultPose( align );
2870  common->Printf( "Writing file...\n" );
2871  if ( !model.WriteMesh( options.dest, options ) ) {
2872  MayaError( "error writing to '%s'", options.dest.c_str() );
2873  }
2874  break;
2875 
2876  case WRITE_ANIM :
2877  common->Printf( "Creating animation frames:\n" );
2878  CreateAnimation( align );
2879  common->Printf( "Writing file...\n" );
2880  if ( !model.WriteAnim( options.dest, options ) ) {
2881  MayaError( "error writing to '%s'", options.dest.c_str() );
2882  }
2883  break;
2884 
2885  case WRITE_CAMERA :
2886  common->Printf( "Creating camera frames:\n" );
2887  CreateCameraAnim( align );
2888 
2889  common->Printf( "Writing file...\n" );
2890  if ( !model.WriteCamera( options.dest, options ) ) {
2891  MayaError( "error writing to '%s'", options.dest.c_str() );
2892  }
2893  break;
2894  }
2895 
2896  common->Printf( "done\n\n" );
2897 }
2898 
2899 /*
2900 ===============
2901 idMayaExport::ConvertToMD3
2902 ===============
2903 */
2905 #if 0
2906  int i, j;
2907  md3Header_t *pinmodel;
2908  md3Frame_t *frame;
2909  md3Surface_t *surf;
2910  md3Shader_t *shader;
2911  md3Triangle_t *tri;
2912  md3St_t *st;
2913  md3XyzNormal_t *xyz;
2914  md3Tag_t *tag;
2915  int version;
2916  int size;
2917 
2918  //model_t *mod, int lod, void *buffer, const char *mod_name
2919 
2920  pinmodel = (md3Header_t *)buffer;
2921 
2922  version = LittleLong (pinmodel->version);
2923  if (version != MD3_VERSION) {
2924  common->Printf( "R_LoadMD3: %s has wrong version (%i should be %i)\n",
2925  mod_name, version, MD3_VERSION);
2926  return qfalse;
2927  }
2928 
2929  mod->type = MOD_MESH;
2930  size = LittleLong(pinmodel->ofsEnd);
2931  mod->dataSize += size;
2932  mod->md3[lod] = ri.Hunk_Alloc( size );
2933 
2934  memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );
2935 
2936  LL(mod->md3[lod]->ident);
2937  LL(mod->md3[lod]->version);
2938  LL(mod->md3[lod]->numFrames);
2939  LL(mod->md3[lod]->numTags);
2940  LL(mod->md3[lod]->numSurfaces);
2941  LL(mod->md3[lod]->ofsFrames);
2942  LL(mod->md3[lod]->ofsTags);
2943  LL(mod->md3[lod]->ofsSurfaces);
2944  LL(mod->md3[lod]->ofsEnd);
2945 
2946  if ( mod->md3[lod]->numFrames < 1 ) {
2947  common->Printf( "R_LoadMD3: %s has no frames\n", mod_name );
2948  return qfalse;
2949  }
2950 
2951  // swap all the frames
2952  frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
2953  for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
2954  frame->radius = LittleFloat( frame->radius );
2955  for ( j = 0 ; j < 3 ; j++ ) {
2956  frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
2957  frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
2958  frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
2959  }
2960  }
2961 
2962  // swap all the tags
2963  tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
2964  for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
2965  for ( j = 0 ; j < 3 ; j++ ) {
2966  tag->origin[j] = LittleFloat( tag->origin[j] );
2967  tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
2968  tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
2969  tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
2970  }
2971  }
2972 
2973  // swap all the surfaces
2974  surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
2975  for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
2976 
2977  LL(surf->ident);
2978  LL(surf->flags);
2979  LL(surf->numFrames);
2980  LL(surf->numShaders);
2981  LL(surf->numTriangles);
2982  LL(surf->ofsTriangles);
2983  LL(surf->numVerts);
2984  LL(surf->ofsShaders);
2985  LL(surf->ofsSt);
2986  LL(surf->ofsXyzNormals);
2987  LL(surf->ofsEnd);
2988 
2989  if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
2990  ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
2991  mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
2992  }
2993  if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
2994  ri.Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
2995  mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
2996  }
2997 
2998  // change to surface identifier
2999  surf->ident = SF_MD3;
3000 
3001  // lowercase the surface name so skin compares are faster
3002  Q_strlwr( surf->name );
3003 
3004  // strip off a trailing _1 or _2
3005  // this is a crutch for q3data being a mess
3006  j = strlen( surf->name );
3007  if ( j > 2 && surf->name[j-2] == '_' ) {
3008  surf->name[j-2] = 0;
3009  }
3010 
3011  // register the shaders
3012  shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
3013  for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
3014  shader_t *sh;
3015 
3016  sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
3017  if ( sh->defaultShader ) {
3018  shader->shaderIndex = 0;
3019  } else {
3020  shader->shaderIndex = sh->index;
3021  }
3022  }
3023 
3024  // swap all the triangles
3025  tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
3026  for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
3027  LL(tri->indexes[0]);
3028  LL(tri->indexes[1]);
3029  LL(tri->indexes[2]);
3030  }
3031 
3032  // swap all the ST
3033  st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
3034  for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
3035  st->st[0] = LittleFloat( st->st[0] );
3036  st->st[1] = LittleFloat( st->st[1] );
3037  }
3038 
3039  // swap all the XyzNormals
3040  xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
3041  for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
3042  {
3043  xyz->xyz[0] = LittleShort( xyz->xyz[0] );
3044  xyz->xyz[1] = LittleShort( xyz->xyz[1] );
3045  xyz->xyz[2] = LittleShort( xyz->xyz[2] );
3046 
3047  xyz->normal = LittleShort( xyz->normal );
3048  }
3049 
3050 
3051  // find the next surface
3052  surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
3053  }
3054  return true;
3055 #endif
3056 }
3057 
3058 /*
3059 ==============================================================================
3060 
3061 dll setup
3062 
3063 ==============================================================================
3064 */
3065 
3066 /*
3067 ===============
3068 Maya_Shutdown
3069 ===============
3070 */
3071 void Maya_Shutdown( void ) {
3072  if ( initialized ) {
3073  errorMessage.Clear();
3074  initialized = false;
3075 
3076  // This shuts down the entire app somehow, so just ignore it.
3077  //MLibrary::cleanup();
3078  }
3079 }
3080 
3081 /*
3082 ===============
3083 Maya_ConvertModel
3084 ===============
3085 */
3086 const char *Maya_ConvertModel( const char *ospath, const char *commandline ) {
3087 
3088  errorMessage = "Ok";
3089 
3090  try {
3091  idExportOptions options( commandline, ospath );
3092  idMayaExport exportM( options );
3093 
3094  exportM.ConvertModel();
3095  }
3096 
3097  catch( idException &exception ) {
3098  errorMessage = exception.error;
3099  }
3100 
3101  return errorMessage;
3102 }
3103 
3104 /*
3105 ===============
3106 dllEntry
3107 ===============
3108 */
3109 bool dllEntry( int version, idCommon *common, idSys *sys ) {
3110 
3111  if ( !common || !sys ) {
3112  return false;
3113  }
3114 
3115  ::common = common;
3116  ::sys = sys;
3117  ::cvarSystem = NULL;
3118 
3119  idLib::sys = sys;
3123 
3124  idLib::Init();
3125 
3126  if ( version != MD5_VERSION ) {
3127  common->Printf( "Error initializing Maya exporter: DLL version %d different from .exe version %d\n", MD5_VERSION, version );
3128  return false;
3129  }
3130 
3131  if ( !initialized ) {
3132  MStatus status;
3133 
3134  status = MLibrary::initialize( GAME_NAME, true );
3135  if ( !status ) {
3136  common->Printf( "Error calling MLibrary::initialize (%s)\n", status.errorString().asChar() );
3137  return false;
3138  }
3139 
3140  initialized = true;
3141  }
3142 
3143  return true;
3144 }
3145 
3146 // Force type checking on the interface functions to help ensure that they match the ones in the .exe
char name[MAX_Q3PATH]
Definition: exporter.h:305
idStr from
Definition: exporter.h:91
bool RemapParents(idList< idNamePair > &remapjoints)
Definition: maya_main.cpp:1722
#define strcmp
Definition: Str.h:41
bool TokenAvailable(void)
Definition: exporter.h:74
bool AddBounds(const idBounds &a)
Definition: Bounds.h:255
int SetTokens(const char *buffer)
Definition: maya_main.cpp:395
bool Compare(const idVec3 &a) const
Definition: Vector.h:496
idList< idExportJoint > joints
Definition: exporter.h:381
idList< idAnimGroup > groups
Definition: exporter.h:131
const GLbyte * weights
Definition: glext.h:3273
int version
Definition: exporter.h:324
int numTriangles
Definition: exporter.h:294
void ConvertModel(void)
Definition: maya_main.cpp:2794
int Cmp(const char *text) const
Definition: Str.h:652
idMat3 idMat(const MMatrix &matrix)
Definition: maya_main.cpp:332
void GetBindPose(MObject &jointNode, idExportJoint *joint, float scale)
Definition: maya_main.cpp:1475
const exporterShutdown_t ValidateShutdown
Definition: maya_main.cpp:3149
Definition: Quat.h:306
#define DEFAULT_QUAT_EPSILON
Definition: maya_main.cpp:41
idExportJoint * FindJointReal(const char *name)
Definition: maya_main.cpp:933
const char * componentNames[6]
Definition: maya_main.cpp:46
void MayaError(const char *fmt,...)
Definition: maya_main.cpp:59
idList< int > cameraCuts
Definition: exporter.h:384
idStr errorMessage
Definition: maya_main.cpp:37
GLenum GLsizei GLenum format
Definition: glext.h:2846
idExportJoint & operator=(const idExportJoint &other)
Definition: maya_main.cpp:760
const char * Maya_ConvertModel(const char *ospath, const char *commandline)
Definition: maya_main.cpp:3086
const GLdouble * v
Definition: glext.h:2936
short xyz[3]
Definition: exporter.h:318
GLuint GLenum matrix
Definition: glext.h:5179
void SetNum(int newnum, bool resize=true)
Definition: List.h:289
void CreateMesh(float scale)
Definition: maya_main.cpp:2077
idMat3 ToMat3(void) const
Definition: Quat.cpp:70
#define GAME_NAME
Definition: Licensee.h:37
void GetLocalTransform(idExportJoint *joint, idVec3 &pos, idMat3 &mat)
Definition: maya_main.cpp:1541
void ConvertToMD3(void)
Definition: maya_main.cpp:2904
void MakeSiblingAfter(idHierarchy &node)
Definition: Hierarchy.h:157
bool Compare(const idVec2 &a) const
Definition: Vector.h:123
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:4804
#define ANIM_TY
Definition: Anim.h:101
idMat3 Transpose(void) const
Definition: Matrix.h:677
int Length(void) const
Definition: Str.h:702
idStr to
Definition: exporter.h:92
#define ANIM_QY
Definition: Anim.h:104
GLenum GLint GLint y
Definition: glext.h:2849
idList< idAnimGroup * > exportgroups
Definition: exporter.h:130
float z
Definition: Vector.h:320
void StripTrailing(const char c)
Definition: Str.cpp:515
void GetAlignment(idStr &alignName, idMat3 &align, float rotate, int startframe)
Definition: maya_main.cpp:2281
case const int
Definition: Callbacks.cpp:52
int ofsXyzNormals
Definition: exporter.h:299
float scale
Definition: exporter.h:158
bool WriteAnim(const char *filename, idExportOptions &options)
Definition: maya_main.cpp:1074
float jointWeight
Definition: exporter.h:194
#define MD5_VERSION_STRING
Definition: Model.h:41
#define BIT(num)
Definition: Lib.h:92
Definition: Vector.h:316
idList< idBounds > bounds
Definition: exporter.h:386
case const float
Definition: Callbacks.cpp:62
void SetOwner(type *object)
Definition: Hierarchy.h:114
type * Ptr(void)
Definition: List.h:596
void Set(float x, float y, float z)
Definition: Quat.h:346
idExportModel model
Definition: exporter.h:414
void CombineMeshes(void)
Definition: maya_main.cpp:2233
short normal
Definition: exporter.h:319
void Maya_Shutdown(void)
Definition: maya_main.cpp:3071
idMat3 wm
Definition: exporter.h:167
void Clear(void)
Definition: exporter.h:69
int numFrames
Definition: exporter.h:289
void Clear(void)
Definition: Bounds.h:201
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
idMat3 ConvertFromIdSpace(const idMat3 &idmat)
Definition: maya_main.cpp:238
static class idSys * sys
Definition: Lib.h:52
bool dllEntry(int version, idCommon *common, idSys *sys)
Definition: maya_main.cpp:3109
idExportOptions(const char *commandline, const char *ospath)
Definition: maya_main.cpp:490
bool ignoreMeshes
Definition: exporter.h:115
GLdouble s
Definition: glext.h:2935
GLuint src
Definition: glext.h:5390
void ParentTo(idHierarchy &node)
Definition: Hierarchy.h:141
idExportMesh * CopyMesh(MFnSkinCluster &skinCluster, float scale)
Definition: maya_main.cpp:1921
#define SHADER_MAX_VERTEXES
Definition: exporter.h:253
idVec3 offset
Definition: exporter.h:195
bool OSPathToRelativePath(const char *osPath, idStr &qpath, const char *game)
Definition: maya_main.cpp:192
void Identity(void)
Definition: Matrix.h:591
float x
Definition: Vector.h:318
#define ANIM_TX
Definition: Anim.h:100
bool ParentedBy(const idHierarchy &node) const
Definition: Hierarchy.h:124
idStr name
Definition: exporter.h:151
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
idVec3 bindpos
Definition: exporter.h:172
int Cmpn(const char *text, int n) const
Definition: Str.h:657
bool WriteCamera(const char *filename, idExportOptions &options)
Definition: maya_main.cpp:1238
idStr realname
Definition: exporter.h:152
void GetDefaultPose(idMat3 &align)
Definition: maya_main.cpp:2536
GLuint GLuint num
Definition: glext.h:5390
const char * GetObjectType(MObject object)
Definition: maya_main.cpp:2328
int numShaders
Definition: exporter.h:291
const exporterInterface_t ValidateConvert
Definition: maya_main.cpp:3148
int Icmp(const char *text) const
Definition: Str.h:667
void RemoveFromHierarchy(void)
Definition: Hierarchy.h:194
idExportJoint * FindJoint(const char *name)
Definition: maya_main.cpp:947
idStr & BackSlashesToSlashes(void)
Definition: Str.cpp:727
idVec3 bounds[2]
Definition: exporter.h:261
idCVarSystem * cvarSystem
Definition: maya_main.cpp:50
int ofsEnd
Definition: exporter.h:340
idList< cameraFrame_t > camera
Definition: exporter.h:385
idVec3 t
Definition: Camera.h:93
idList< idNamePair > remapjoints
Definition: exporter.h:126
struct version_s version
bool jointInExportGroup(const char *jointname)
Definition: maya_main.cpp:707
int shaderIndex
Definition: exporter.h:306
idList< exportWeight_t > weights
Definition: exporter.h:361
bool ignoreScale
Definition: exporter.h:118
bool AddPoint(const idVec3 &v)
Definition: Bounds.h:226
idVec3 idt
Definition: exporter.h:169
jointFrame_t baseFrame
Definition: exporter.h:177
void UnGetToken(void)
Definition: exporter.h:76
GLuint GLuint GLsizei count
Definition: glext.h:2845
idVec3 origin
Definition: exporter.h:269
idExportOptions & options
Definition: exporter.h:415
static class idFileSystem * fileSystem
Definition: Lib.h:55
void GetTextureForMesh(idExportMesh *mesh, MFnDagNode &dagNode)
Definition: maya_main.cpp:1816
GLuint index
Definition: glext.h:3476
const GLubyte * c
Definition: glext.h:4677
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
void Merge(idExportMesh *mesh)
Definition: maya_main.cpp:840
idStr & StripFileExtension(void)
Definition: Str.cpp:757
#define BASE_GAMEDIR
Definition: Licensee.h:46
exportType_t type
Definition: exporter.h:114
void RenameJoints(idList< idNamePair > &renamejoints, idStr &prefix)
Definition: maya_main.cpp:1693
type & Alloc(void)
Definition: List.h:624
idSys * sys
Definition: maya_main.cpp:48
bool clearOriginAxis
Definition: exporter.h:117
idStr longname
Definition: exporter.h:153
#define vec3_zero
Definition: Vector.h:390
idList< exportTriangle_t > tris
Definition: exporter.h:360
GLuint GLuint end
Definition: glext.h:2845
idList< exportVertex_t > verts
Definition: exporter.h:359
idStr name
Definition: exporter.h:354
idVec3 pos
Definition: exporter.h:199
float radius
Definition: exporter.h:263
#define NULL
Definition: Lib.h:88
idList< exportUV_t > uv
Definition: exporter.h:362
float y
Definition: Vector.h:319
char name[MAX_Q3PATH]
Definition: exporter.h:286
GLuint buffer
Definition: glext.h:3108
bool initialized
Definition: maya_main.cpp:38
int firstComponent
Definition: exporter.h:176
void CapLength(int)
Definition: Str.h:859
const char * NextToken(const char *errorstring=NULL)
Definition: maya_main.cpp:427
idStr name
Definition: exporter.h:97
#define mat3_default
Definition: Matrix.h:413
float GetCameraFov(idExportJoint *joint)
Definition: maya_main.cpp:2352
idList< idNamePair > renamejoints
Definition: exporter.h:125
idMat3 idwm
Definition: exporter.h:170
#define MD3_VERSION
Definition: exporter.h:238
idVec3 t
Definition: exporter.h:166
#define SHADER_MAX_INDEXES
Definition: exporter.h:254
idStrList keepmeshes
Definition: exporter.h:129
idList< idExportMesh * > meshes
Definition: exporter.h:393
type * Find(type const &obj) const
Definition: List.h:782
const char * path
Definition: sws.c:117
idMat3 bindmat
Definition: exporter.h:173
MObject FindShader(MObject &setNode)
Definition: maya_main.cpp:1786
float jointThreshold
Definition: exporter.h:133
void ShareVerts(void)
Definition: maya_main.cpp:801
void DeleteContents(bool clear)
Definition: List.h:207
idStrList keepjoints
Definition: exporter.h:127
void CreateCameraAnim(idMat3 &align)
Definition: maya_main.cpp:2417
void Clear(void)
Definition: Str.h:724
static idCVar * staticVars
Definition: CVarSystem.h:178
const char * Right(int len, idStr &result) const
Definition: Str.h:896
int Find(const char c, int start=0, int end=-1) const
Definition: Str.h:874
bool WriteMesh(const char *filename, idExportOptions &options)
Definition: maya_main.cpp:961
idCQuat q
Definition: Camera.h:92
type * GetNext(void) const
Definition: Hierarchy.h:310
float TimeForFrame(int num) const
Definition: maya_main.cpp:1301
idVec2 texCoords
Definition: exporter.h:200
idCQuat ToCQuat(void) const
Definition: Quat.cpp:122
MFnDagNode * dagnode
Definition: exporter.h:161
virtual void Printf(const char *fmt,...) id_attribute((format(printf
void PruneJoints(idStrList &keepjoints, idStr &prefix)
Definition: maya_main.cpp:1363
void CreateAnimation(idMat3 &align)
Definition: maya_main.cpp:2626
float invscale
Definition: exporter.h:159
void AppendPath(const char *text)
Definition: Str.cpp:830
float st[2]
Definition: exporter.h:314
idMat3 & OrthoNormalizeSelf(void)
Definition: Matrix.h:668
int LittleLong(int l)
Definition: Lib.cpp:281
#define DEFAULT_ANIM_EPSILON
Definition: maya_main.cpp:40
void ProjectVector(const idVec3 &src, idVec3 &dst) const
Definition: Matrix.h:628
idList< jointFrame_t > jointFrames
Definition: exporter.h:387
idHierarchy< idExportJoint > mayaNode
Definition: exporter.h:163
int skipjoints
Definition: exporter.h:391
idVec3 idVec(const MFloatPoint &point)
Definition: maya_main.cpp:314
bool(* exporterDLLEntry_t)(int version, idCommon *common, idSys *sys)
Definition: maya_main.h:41
idExportJoint * exportOrigin
Definition: exporter.h:380
#define MAYA_DEFAULT_CAMERA
Definition: exporter.h:28
short LittleShort(short l)
Definition: Lib.cpp:279
int Append(const type &obj)
Definition: List.h:646
void GetBounds(idBounds &bounds) const
Definition: maya_main.cpp:882
type * GetChild(void) const
Definition: Hierarchy.h:233
int GetMayaFrameNum(int num) const
Definition: maya_main.cpp:1315
idMat3 ConvertToIdSpace(const idMat3 &mat)
Definition: maya_main.cpp:276
Definition: Matrix.h:333
idList< jointFrame_t * > frames
Definition: exporter.h:388
void GetCameraFrame(idExportJoint *camera, idMat3 &align, cameraFrame_t *cam)
Definition: maya_main.cpp:2390
idHierarchy< idExportJoint > exportHead
Definition: exporter.h:383
idStrList joints
Definition: exporter.h:98
type * GetSibling(void) const
Definition: Hierarchy.h:246
static int static int vsnPrintf(char *dest, int size, const char *fmt, va_list argptr)
Definition: Str.cpp:1502
int AddUnique(const type &obj)
Definition: List.h:742
#define ANIM_TZ
Definition: Anim.h:102
void Reset(const char *commandline)
Definition: maya_main.cpp:452
tuple f
Definition: idal.py:89
#define SLOP_TEXCOORD
Definition: maya_main.cpp:44
idHierarchy< idExportJoint > mayaHead
Definition: exporter.h:382
static void Init(void)
Definition: Lib.cpp:57
int indexes[3]
Definition: exporter.h:310
int Num(void) const
Definition: List.h:265
char error[MAX_STRING_CHARS]
Definition: Lib.h:152
#define ANIM_QX
Definition: Anim.h:103
void(* exporterShutdown_t)(void)
Definition: maya_main.h:43
idQuat ToQuat(void) const
Definition: Matrix.cpp:182
void GetWorldTransform(idExportJoint *joint, idVec3 &pos, idMat3 &mat, float scale)
Definition: maya_main.cpp:1576
idMat3 ToMat3(void) const
Definition: Angles.cpp:199
unsigned char byte
Definition: Lib.h:75
type * GetParent(void) const
Definition: Hierarchy.h:220
MFnDagNode * GetParent(MFnDagNode *joint)
Definition: maya_main.cpp:350
idHierarchy< idExportJoint > exportNode
Definition: exporter.h:164
const GLcharARB * name
Definition: glext.h:3629
GLfloat * st
Definition: qgl.h:89
#define RAD2DEG(a)
Definition: Math.h:57
GLsizeiptr size
Definition: glext.h:3112
static class idCVarSystem * cvarSystem
Definition: Lib.h:54
idQuat ToQuat(void) const
Definition: Quat.h:391
Definition: Str.h:116
const exporterDLLEntry_t ValidateEntry
Definition: maya_main.cpp:3147
float xyzPrecision
Definition: exporter.h:122
bool clearOrigin
Definition: exporter.h:116
idVec3 localOrigin
Definition: exporter.h:262
const char * c_str(void) const
Definition: Str.h:487
float LittleFloat(float l)
Definition: Lib.cpp:283
idStr commandLine
Definition: exporter.h:108
idStr shader
Definition: exporter.h:355
void SetFrame(int num)
Definition: maya_main.cpp:1346
float quatPrecision
Definition: exporter.h:123
idGame * game
Definition: Game_local.cpp:65
GLint j
Definition: qgl.h:264
GLuint GLenum GLenum transform
Definition: glext.h:5179
int ofsTriangles
Definition: exporter.h:295
float fov
Definition: Camera.h:94
void CreateJoints(float scale)
Definition: maya_main.cpp:1600
idCommon * common
Definition: maya_main.cpp:49
#define SLOP_VERTEX
Definition: maya_main.cpp:43
int ofsShaders
Definition: exporter.h:297
GLfloat GLfloat p
Definition: glext.h:4674
void FreeDagNodes(void)
Definition: maya_main.cpp:1461
#define MD5_VERSION
Definition: Model.h:45
GLdouble GLdouble z
Definition: glext.h:3067
int export_joints
Definition: exporter.h:392
void Zero(void)
Definition: Vector.h:415
idExportJoint * joint
Definition: exporter.h:193
void Resize(int newsize)
Definition: List.h:360
const char *(* exporterInterface_t)(const char *ospath, const char *commandline)
Definition: maya_main.h:42
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
idStrList tokens
Definition: exporter.h:65
#define LL(x)
Definition: Model_md3.cpp:41
idCQuat q
Definition: exporter.h:44
int currentToken
Definition: exporter.h:64
idVec3 t
Definition: exporter.h:45
idStrList skipmeshes
Definition: exporter.h:128
GLuint start
Definition: glext.h:2845
bool StripLeadingOnce(const char *string)
Definition: Str.cpp:498
idTokenizer tokens
Definition: exporter.h:103
idVec3 axis[3]
Definition: exporter.h:270
static class idCommon * common
Definition: Lib.h:53
idMat3 & TransposeSelf(void)
Definition: Matrix.h:683
#define ANIM_QZ
Definition: Anim.h:105
GLdouble GLdouble t
Definition: glext.h:2943
int numVerts
Definition: exporter.h:292
void Clear(void)
Definition: List.h:184