]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/d3xp/anim/Anim_Import.cpp
hello world
[icculus/iodoom3.git] / neo / d3xp / anim / Anim_Import.cpp
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 "../Game_local.h"
33 #include "../../MayaImport/maya_main.h"
34
35 /***********************************************************************
36
37         Maya conversion functions
38
39 ***********************************************************************/
40
41 static idStr                            Maya_Error;
42
43 static exporterInterface_t      Maya_ConvertModel = NULL;
44 static exporterShutdown_t       Maya_Shutdown = NULL;
45 static int                                      importDLL = 0;
46
47 bool idModelExport::initialized = false;
48
49 /*
50 ====================
51 idModelExport::idModelExport
52 ====================
53 */
54 idModelExport::idModelExport() {
55         Reset();
56 }
57
58 /*
59 ====================
60 idModelExport::Shutdown
61 ====================
62 */
63 void idModelExport::Shutdown( void ) {
64         if ( Maya_Shutdown ) {
65                 Maya_Shutdown();
66         }
67
68         if ( importDLL ) {
69                 sys->DLL_Unload( importDLL );
70         }
71
72         importDLL = 0;
73         Maya_Shutdown = NULL;
74         Maya_ConvertModel = NULL;
75         Maya_Error.Clear();
76         initialized = false;
77 }
78
79 /*
80 =====================
81 idModelExport::CheckMayaInstall
82
83 Determines if Maya is installed on the user's machine
84 =====================
85 */
86 bool idModelExport::CheckMayaInstall( void ) {
87 #ifndef _WIN32
88         return false;
89 #elif 0
90         HKEY    hKey;
91         long    lres, lType;
92
93         lres = RegOpenKey( HKEY_LOCAL_MACHINE, "SOFTWARE\\Alias|Wavefront\\Maya\\4.5\\Setup\\InstallPath", &hKey );
94
95         if ( lres != ERROR_SUCCESS ) {
96                 return false;
97         }
98
99         lres = RegQueryValueEx( hKey, "MAYA_INSTALL_LOCATION", NULL, (unsigned long*)&lType, (unsigned char*)NULL, (unsigned long*)NULL );
100
101         RegCloseKey( hKey );
102
103         if ( lres != ERROR_SUCCESS ) {
104                 return false;
105         }
106         return true;
107 #else
108         HKEY    hKey;
109         long    lres;
110
111         // only check the non-version specific key so that we only have to update the maya dll when new versions are released
112         lres = RegOpenKey( HKEY_LOCAL_MACHINE, "SOFTWARE\\Alias|Wavefront\\Maya", &hKey );
113         RegCloseKey( hKey );
114
115         if ( lres != ERROR_SUCCESS ) {
116                 return false;
117         }
118         return true;
119 #endif
120 }
121
122 /*
123 =====================
124 idModelExport::LoadMayaDll
125
126 Checks to see if we can load the Maya export dll
127 =====================
128 */
129 void idModelExport::LoadMayaDll( void ) {
130         exporterDLLEntry_t      dllEntry;
131         char                            dllPath[ MAX_OSPATH ];
132
133         fileSystem->FindDLL( "MayaImport", dllPath, false );
134         if ( !dllPath[ 0 ] ) {
135                 return;
136         }
137         importDLL = sys->DLL_Load( dllPath );
138         if ( !importDLL ) {
139                 return;
140         }
141
142         // look up the dll interface functions
143         dllEntry = ( exporterDLLEntry_t )sys->DLL_GetProcAddress( importDLL, "dllEntry" ); 
144         Maya_ConvertModel = ( exporterInterface_t )sys->DLL_GetProcAddress( importDLL, "Maya_ConvertModel" );
145         Maya_Shutdown = ( exporterShutdown_t )sys->DLL_GetProcAddress( importDLL, "Maya_Shutdown" );
146         if ( !Maya_ConvertModel || !dllEntry || !Maya_Shutdown ) {
147                 Maya_ConvertModel = NULL;
148                 Maya_Shutdown = NULL;
149                 sys->DLL_Unload( importDLL );
150                 importDLL = 0;
151                 gameLocal.Error( "Invalid interface on export DLL." );
152                 return;
153         }
154
155         // initialize the DLL
156         if ( !dllEntry( MD5_VERSION, common, sys ) ) {
157                 // init failed
158                 Maya_ConvertModel = NULL;
159                 Maya_Shutdown = NULL;
160                 sys->DLL_Unload( importDLL );
161                 importDLL = 0;
162                 gameLocal.Error( "Export DLL init failed." );
163                 return;
164         }
165 }
166
167 /*
168 =====================
169 idModelExport::ConvertMayaToMD5
170
171 Checks if a Maya model should be converted to an MD5, and converts if if the time/date or 
172 version number has changed.
173 =====================
174 */
175 bool idModelExport::ConvertMayaToMD5( void ) {
176         ID_TIME_T               sourceTime;
177         ID_TIME_T               destTime;
178         int                     version;
179         idToken         cmdLine;
180         idStr           path;
181
182         // check if our DLL got loaded
183         if ( initialized && !Maya_ConvertModel ) {
184                 Maya_Error = "MayaImport dll not loaded.";
185                 return false;
186         }
187
188         // if idAnimManager::forceExport is set then we always reexport Maya models
189         if ( idAnimManager::forceExport ) {
190                 force = true;
191         }
192
193         // get the source file's time
194         if ( fileSystem->ReadFile( src, NULL, &sourceTime ) < 0 ) {
195                 // source file doesn't exist
196                 return true;
197         }
198
199         // get the destination file's time
200         if ( !force && ( fileSystem->ReadFile( dest, NULL, &destTime ) >= 0 ) ) {
201                 idParser parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
202
203                 parser.LoadFile( dest );
204
205                 // read the file version
206                 if ( parser.CheckTokenString( MD5_VERSION_STRING ) ) {
207                         version = parser.ParseInt();
208
209                         // check the command line
210                         if ( parser.CheckTokenString( "commandline" ) ) {
211                                 parser.ReadToken( &cmdLine );
212
213                                 // check the file time, scale, and version
214                                 if ( ( destTime >= sourceTime ) && ( version == MD5_VERSION ) && ( cmdLine == commandLine ) ) {
215                                         // don't convert it
216                                         return true;
217                                 }
218                         }
219                 }
220         }
221
222         // if this is the first time we've been run, check if Maya is installed and load our DLL
223         if ( !initialized ) {
224                 initialized = true;
225
226                 if ( !CheckMayaInstall() ) {
227                         Maya_Error = "Maya not installed in registry.";
228                         return false;
229                 }
230
231                 LoadMayaDll();
232
233                 // check if our DLL got loaded
234                 if ( !Maya_ConvertModel ) {
235                         Maya_Error = "Could not load MayaImport dll.";
236                         return false;
237                 }
238         }
239
240         // we need to make sure we have a full path, so convert the filename to an OS path
241         // _D3XP :: we work out of the cdpath, at least until we get Alienbrain
242         src = fileSystem->RelativePathToOSPath( src, "fs_cdpath" );
243         dest = fileSystem->RelativePathToOSPath( dest, "fs_cdpath" );
244
245         dest.ExtractFilePath( path );
246         if ( path.Length() ) {
247                 fileSystem->CreateOSPath( path );
248         }
249
250         // get the os path in case it needs to create one
251         path = fileSystem->RelativePathToOSPath( "", "fs_cdpath" /* _D3XP */ );
252
253         common->SetRefreshOnPrint( true );
254         Maya_Error = Maya_ConvertModel( path, commandLine );
255         common->SetRefreshOnPrint( false );
256         if ( Maya_Error != "Ok" ) {
257                 return false;
258         }
259         
260         // conversion succeded
261         return true;
262 }
263
264 /*
265 ====================
266 idModelExport::Reset
267 ====================
268 */
269 void idModelExport::Reset( void ) {
270         force           = false;
271         commandLine = "";
272         src                     = "";
273         dest            = "";
274 }
275
276 /*
277 ====================
278 idModelExport::ExportModel
279 ====================
280 */
281 bool idModelExport::ExportModel( const char *model ) {
282         const char *game = cvarSystem->GetCVarString( "fs_game" );
283         if ( strlen(game) == 0 ) {
284                 game = BASE_GAMEDIR;
285         }
286
287         Reset();
288         src  = model;
289         dest = model;
290         dest.SetFileExtension( MD5_MESH_EXT );
291
292         sprintf( commandLine, "mesh %s -dest %s -game %s", src.c_str(), dest.c_str(), game );
293         if ( !ConvertMayaToMD5() ) {
294                 gameLocal.Printf( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() );
295                 return false;
296         }
297
298         return true;
299 }
300
301 /*
302 ====================
303 idModelExport::ExportAnim
304 ====================
305 */
306 bool idModelExport::ExportAnim( const char *anim ) {
307         const char *game = cvarSystem->GetCVarString( "fs_game" );
308         if ( strlen(game) == 0 ) {
309                 game = BASE_GAMEDIR;
310         }
311
312         Reset();
313         src  = anim;
314         dest = anim;
315         dest.SetFileExtension( MD5_ANIM_EXT );
316
317         sprintf( commandLine, "anim %s -dest %s -game %s", src.c_str(), dest.c_str(), game );
318         if ( !ConvertMayaToMD5() ) {
319                 gameLocal.Printf( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() );
320                 return false;
321         }
322
323         return true;
324 }
325
326 /*
327 ====================
328 idModelExport::ParseOptions
329 ====================
330 */
331 bool idModelExport::ParseOptions( idLexer &lex ) {
332         idToken token;
333         idStr   destdir;
334         idStr   sourcedir;
335
336         if ( !lex.ReadToken( &token ) ) {
337                 lex.Error( "Expected filename" );
338                 return false;
339         }
340
341         src = token;
342         dest = token;
343
344         while( lex.ReadToken( &token ) ) {
345                 if ( token == "-" ) {
346                         if ( !lex.ReadToken( &token ) ) {
347                                 lex.Error( "Expecting option" );
348                                 return false;
349                         }
350                         if ( token == "sourcedir" ) {
351                                 if ( !lex.ReadToken( &token ) ) {
352                                         lex.Error( "Missing pathname after -sourcedir" );
353                                         return false;
354                                 }
355                                 sourcedir = token;
356                         } else if ( token == "destdir" ) {
357                                 if ( !lex.ReadToken( &token ) ) {
358                                         lex.Error( "Missing pathname after -destdir" );
359                                         return false;
360                                 }
361                                 destdir = token;
362                         } else if ( token == "dest" ) {
363                                 if ( !lex.ReadToken( &token ) ) {
364                                         lex.Error( "Missing filename after -dest" );
365                                         return false;
366                                 }
367                                 dest = token;
368                         } else {
369                                 commandLine += va( " -%s", token.c_str() );
370                         }
371                 } else {
372                         commandLine += va( " %s", token.c_str() );
373                 }
374         }
375
376         if ( sourcedir.Length() ) {
377                 src.StripPath();
378                 sourcedir.BackSlashesToSlashes();
379                 sprintf( src, "%s/%s", sourcedir.c_str(), src.c_str() );
380         }
381
382         if ( destdir.Length() ) {
383                 dest.StripPath();
384                 destdir.BackSlashesToSlashes();
385                 sprintf( dest, "%s/%s", destdir.c_str(), dest.c_str() );
386         }
387
388         return true;
389 }
390
391 /*
392 ====================
393 idModelExport::ParseExportSection
394 ====================
395 */
396 int idModelExport::ParseExportSection( idParser &parser ) {
397         idToken command;
398         idToken token;
399         idStr   defaultCommands;
400         idLexer lex;
401         idStr   temp;
402         idStr   parms;
403         int             count;
404
405         const char *game = cvarSystem->GetCVarString( "fs_game" );
406
407         if ( strlen(game) == 0 ) {
408                 game = BASE_GAMEDIR;
409         }
410
411         // only export sections that match our export mask
412         if ( g_exportMask.GetString()[ 0 ] ) {
413                 if ( parser.CheckTokenString( "{" ) ) {
414                         parser.SkipBracedSection( false );
415                         return 0;
416                 }
417
418         parser.ReadToken( &token );
419                 if ( token.Icmp( g_exportMask.GetString() ) ) {
420                         parser.SkipBracedSection();
421                         return 0;
422                 }
423                 parser.ExpectTokenString( "{" );
424         } else if ( !parser.CheckTokenString( "{" ) ) {
425                 // skip the export mask
426                 parser.ReadToken( &token );
427                 parser.ExpectTokenString( "{" );
428         }
429
430         count = 0;
431
432         lex.SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
433
434         while( 1 ) {
435
436                 if ( !parser.ReadToken( &command ) ) {
437                         parser.Error( "Unexpoected end-of-file" );
438                         break;
439                 }
440
441                 if ( command == "}" ) {
442                         break;
443                 }
444
445                 if ( command == "options" ) {
446                         parser.ParseRestOfLine( defaultCommands );
447                 } else if ( command == "addoptions" ) {
448                         parser.ParseRestOfLine( temp );
449                         defaultCommands += " ";
450                         defaultCommands += temp;
451                 } else if ( ( command == "mesh" ) || ( command == "anim" ) || ( command == "camera" ) ) {
452                         if ( !parser.ReadToken( &token ) ) {
453                                 parser.Error( "Expected filename" );
454                         }
455
456                         temp = token;
457                         parser.ParseRestOfLine( parms );
458
459                         if ( defaultCommands.Length() ) {
460                                 sprintf( temp, "%s %s", temp.c_str(), defaultCommands.c_str() );
461                         }
462
463                         if ( parms.Length() ) {
464                                 sprintf( temp, "%s %s", temp.c_str(), parms.c_str() );
465                         }
466
467                         lex.LoadMemory( temp, temp.Length(), parser.GetFileName() );
468
469                         Reset();
470                         if ( ParseOptions( lex ) ) {
471                                 const char *game = cvarSystem->GetCVarString( "fs_game" );
472                                 if ( strlen(game) == 0 ) {
473                                         game = BASE_GAMEDIR;
474                                 }
475
476                                 if ( command == "mesh" ) {
477                                         dest.SetFileExtension( MD5_MESH_EXT );
478                                 } else if ( command == "anim" ) {
479                                         dest.SetFileExtension( MD5_ANIM_EXT );
480                                 } else if ( command == "camera" ) {
481                                         dest.SetFileExtension( MD5_CAMERA_EXT );
482                                 } else {
483                                         dest.SetFileExtension( command );
484                                 }
485                                 idStr back = commandLine;
486                                 sprintf( commandLine, "%s %s -dest %s -game %s%s", command.c_str(), src.c_str(), dest.c_str(), game, commandLine.c_str() );
487                                 if ( ConvertMayaToMD5() ) {
488                                         count++;
489                                 } else {
490                                         parser.Warning( "Failed to export '%s' : %s", src.c_str(), Maya_Error.c_str() );
491                                 }
492                         }
493                         lex.FreeSource();
494                 } else {
495                         parser.Error( "Unknown token: %s", command.c_str() );
496                         parser.SkipBracedSection( false );
497                         break;
498                 }
499         }
500
501         return count;
502 }
503
504 /*
505 ================
506 idModelExport::ExportDefFile
507 ================
508 */
509 int idModelExport::ExportDefFile( const char *filename ) {
510         idParser        parser( LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
511         idToken         token;
512         int                     count;
513
514         count = 0;
515
516         if ( !parser.LoadFile( filename ) ) {
517                 gameLocal.Printf( "Could not load '%s'\n", filename );
518                 return 0;
519         }
520
521         while( parser.ReadToken( &token ) ) {
522                 if ( token == "export" ) {
523                         count += ParseExportSection( parser );
524                 } else {
525                         parser.ReadToken( &token );
526                         parser.SkipBracedSection();
527                 }
528         }
529
530         return count;
531 }
532
533 /*
534 ================
535 idModelExport::ExportModels
536 ================
537 */
538 int idModelExport::ExportModels( const char *pathname, const char *extension ) {
539         int     count;
540
541         count = 0;
542
543         idFileList *files;
544         int                     i;
545
546         if ( !CheckMayaInstall() ) {
547                 // if Maya isn't installed, don't bother checking if we have anims to export
548                 return 0;
549         }
550
551         gameLocal.Printf( "--------- Exporting models --------\n" );
552         if ( !g_exportMask.GetString()[ 0 ] ) {
553                 gameLocal.Printf( "  Export mask: '%s'\n", g_exportMask.GetString() );
554         }
555
556         count = 0;
557
558         files = fileSystem->ListFiles( pathname, extension );
559         for( i = 0; i < files->GetNumFiles(); i++ ) {
560                 count += ExportDefFile( va( "%s/%s", pathname, files->GetFile( i ) ) );
561         }
562         fileSystem->FreeFileList( files );
563
564         gameLocal.Printf( "...%d models exported.\n", count );
565         gameLocal.Printf( "-----------------------------------\n" );
566
567         return count;
568 }