]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3data/q3data.c
set eol-style
[xonotic/netradiant.git] / tools / quake3 / q3data / q3data.c
1 #ifdef _WIN32
2 #include <io.h>
3 #endif
4 #include "q3data.h"
5 #include "md3lib.h"
6
7 #include "vfs.h"
8
9 qboolean        g_verbose;
10 qboolean        g_stripify = qtrue;
11 qboolean        g_release;                      // don't grab, copy output data to new tree
12 char            g_releasedir[1024];     // c:\quake2\baseq2, etc
13 qboolean        g_archive;                      // don't grab, copy source data to new tree
14 char            g_only[256];            // if set, only grab this cd
15 qboolean        g_skipmodel;            // set true when a cd is not g_only
16
17 // bogus externs for some TA hacks (common/ using them against q3map)
18 char *moddir = NULL;
19 // some old defined that was in cmdlib lost during merge
20 char writedir[1024];
21
22 #if defined (__linux__) || defined (__APPLE__)
23 #define strlwr strlower
24 #endif
25
26 /*
27 =======================================================
28
29   PAK FILES
30
31 =======================================================
32 */
33
34 typedef struct
35 {
36         char    name[56];
37         int             filepos, filelen;
38 } packfile_t;
39
40 typedef struct
41 {
42         char    id[4];
43         int             dirofs;
44         int             dirlen;
45 } packheader_t;
46
47 packfile_t              pfiles[16384];
48 FILE                    *pakfile;
49 packfile_t              *pf;
50 packheader_t    pakheader;
51
52 /*
53 ==============
54 ReleaseFile
55
56 Filename should be gamedir reletive.
57 Either copies the file to the release dir, or adds it to
58 the pak file.
59 ==============
60 */
61 void ReleaseFile (char *filename)
62 {
63         char    source[1024];
64         char    dest[1024];
65
66         if (!g_release)
67                 return;
68
69         sprintf (source, "%s%s", gamedir, filename);
70         sprintf (dest, "%s/%s", g_releasedir, filename);
71         printf ("copying to %s\n", dest);
72   QCopyFile (source, dest);
73   return;
74 }
75
76 typedef struct
77 {
78         // shader
79         // opaque
80         // opaque 2
81         // blend 
82         // blend 2
83         char names[5][1024];
84         int      num;
85 } ShaderFiles_t;
86
87 ShaderFiles_t s_shaderFiles;
88
89 void FindShaderFiles( char *filename )
90 {
91         char buffer[1024];
92         char stripped[1024];
93         char linebuffer[1024];
94         int len, i;
95         char *buf;
96         char *diffuseExtensions[] =
97         {
98                 ".TGA",
99                 ".WAL",
100                 ".PCX",
101                 0
102         };
103         char *otherExtensions[] =
104         {
105                 ".specular.TGA",
106                 ".blend.TGA",
107                 ".alpha.TGA",
108                 0
109         };
110
111         s_shaderFiles.num = 0;
112
113         strcpy( stripped, filename );
114         if ( strrchr( stripped, '.' ) )
115                 *strrchr( stripped, '.' ) = 0;
116         strcat( stripped, ".shader" );
117
118         if ( FileExists( stripped ) )
119         {
120                 char *p;
121                 char mapa[512], mapb[512];
122
123                 strcpy( s_shaderFiles.names[s_shaderFiles.num], stripped );
124                 s_shaderFiles.num++;
125
126                 // load and parse
127                 len = LoadFile( stripped, (void **)&buf);
128
129                 p = buf;
130
131                 while ( p - buf < len )
132                 {
133                         i = 0;
134
135                         // skip spaces
136                         while ( *p == ' ' || *p == '\n' || *p == '\t' )
137                                 p++;
138
139                         // grab rest of the line
140                         while ( *p != 0 && *p != '\n' )
141                         {
142                                 linebuffer[i] = *p;
143                                 i++;
144                                 p++;
145                         }
146                         if ( *p == '\n' )
147                                 p++;
148                         linebuffer[i] = 0;
149
150                         strlwr( linebuffer );
151
152                         // see if the line specifies an opaque map or blendmap
153                         if ( strstr( linebuffer, "opaquemap" ) == linebuffer ||
154                                  strstr( linebuffer, "blendmap" ) == linebuffer )
155                         {
156                                 int j;
157
158                                 i = 0;
159
160                                 mapa[0] = mapb[0] = 0;
161
162                                 // skip past the keyword
163                                 while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )
164                                         i++;
165                                 // skip past spaces
166                                 while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] )
167                                         i++;
168
169                                 // grab first map name
170                                 j = 0;
171                                 while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )
172                                 {
173                                         mapa[j] = linebuffer[i];
174                                         j++;
175                                         i++;
176                                 }
177                                 mapa[j] = 0;
178
179                                 // skip past spaces
180                                 while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] )
181                                         i++;
182
183                                 // grab second map name
184                                 j = 0;
185                                 while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )
186                                 {
187                                         mapb[j] = linebuffer[i];
188                                         j++;
189                                         i++;
190                                 }
191                                 mapb[j] = 0;
192
193                                 // store map names
194                                 if ( mapa[0] != 0 && mapa[0] != '-' )
195                                 {
196                                         sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapa );
197                                         s_shaderFiles.num++;
198                                 }
199                                 if ( mapb[0] != 0 && mapb[0] != '-' && mapb[0] != '^' && mapb[0] != '*' )
200                                 {
201                                         sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapb );
202                                         s_shaderFiles.num++;
203                                 }
204                         }
205                 }
206         }
207         else
208         {
209                 if ( strrchr( stripped, '.' ) )
210                         *strrchr( stripped, '.' ) = 0;
211
212                 // look for diffuse maps
213                 for ( i = 0; i < 3; i++ )
214                 {
215                         strcpy( buffer, stripped );
216                         strcat( buffer, diffuseExtensions[i] );
217                         if ( FileExists( buffer ) )
218                         {
219                                 strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer );
220                                 s_shaderFiles.num++;
221                                 break;
222                         }
223                 }
224                 for ( i = 0; i < 3; i++ )
225                 {
226                         strcpy( buffer, stripped );
227                         strcat( buffer, otherExtensions[i] );
228                         if ( FileExists( buffer ) )
229                         {
230                                 strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer );
231                                 s_shaderFiles.num++;
232                         }
233                 }
234         }
235 }
236
237 /*
238 ==============
239 ReleaseShader
240
241 Copies all needed files for a shader to the release directory
242 ==============
243 */
244 void ReleaseShader( char *filename ) 
245 {
246         char fullpath[1024];
247         char dest[1024];
248         char stripped[1024];
249         int i;
250
251         sprintf( fullpath, "%s%s", gamedir, filename );
252
253         FindShaderFiles( fullpath );
254
255         for ( i = 0; i < s_shaderFiles.num; i++ )
256         {
257                 strcpy( stripped, s_shaderFiles.names[i] );
258                 if ( strstr( stripped, gamedir ) )
259                 {
260                         memmove( stripped, stripped+ strlen( gamedir ), strlen( stripped ) );
261                 }
262                 sprintf( dest, "%s/%s", g_releasedir, stripped );
263                 printf ("copying to %s\n", dest );
264                 QCopyFile( s_shaderFiles.names[i], dest );
265   }
266 }
267
268 /*
269 ===============
270 Cmd_File
271
272 This is only used to cause a file to be copied during a release
273 build (default.cfg, maps, etc)
274 ===============
275 */
276 void Cmd_File (void)
277 {
278         GetToken (qfalse);
279         ReleaseFile (token);
280 }
281
282 /*
283 ===============
284 PackDirectory_r
285
286 ===============
287 */
288 #ifdef _WIN32
289 #include "io.h"
290 void PackDirectory_r (char *dir)
291 {
292         struct _finddata_t fileinfo;
293         int             handle;
294         char    dirstring[1024];
295         char    filename[1024];
296
297         sprintf (dirstring, "%s%s/*.*", gamedir, dir);
298
299         handle = _findfirst (dirstring, &fileinfo);
300         if (handle == -1)
301                 return;
302
303         do
304         {
305                 sprintf (filename, "%s/%s", dir, fileinfo.name);
306                 if (fileinfo.attrib & _A_SUBDIR)
307                 {       // directory
308                         if (fileinfo.name[0] != '.')    // don't pak . and ..
309                                 PackDirectory_r (filename);
310                         continue;
311                 }
312                 // copy or pack the file
313                 ReleaseFile (filename);         
314         } while (_findnext( handle, &fileinfo ) != -1);
315
316         _findclose (handle);
317 }
318 #else
319
320 #include <sys/types.h>
321 #ifndef WIN32
322 #include <sys/dir.h>
323 #else
324 #include <sys/dirent.h>
325 #endif
326
327 void PackDirectory_r (char *dir)
328 {
329 #ifdef NeXT
330         struct direct **namelist, *ent;
331 #else
332         struct dirent **namelist, *ent;
333 #endif
334         int             count;
335         struct stat st;
336         int                     i;
337         int                     len;
338         char            fullname[1024];
339         char            dirstring[1024];
340         char            *name;
341         
342         sprintf (dirstring, "%s%s", gamedir, dir);
343         count = scandir(dirstring, &namelist, NULL, NULL);
344         
345         for (i=0 ; i<count ; i++)
346         {
347                 ent = namelist[i];      
348                 name = ent->d_name;
349
350                 if (name[0] == '.')
351                         continue;
352         
353                 sprintf (fullname, "%s/%s", dir, name);
354                 sprintf (dirstring, "%s%s/%s", gamedir, dir, name);
355                 
356                 if (stat (dirstring, &st) == -1)
357                         Error ("fstating %s", pf->name);
358                 if (st.st_mode & S_IFDIR)
359                 {       // directory
360                         PackDirectory_r (fullname);
361                         continue;
362                 }
363
364                 // copy or pack the file
365                 ReleaseFile (fullname);         
366         }
367 }
368 #endif
369
370
371 /*
372 ===============
373 Cmd_Dir
374
375 This is only used to cause a directory to be copied during a
376 release build (sounds, etc)
377 ===============
378 */
379 void Cmd_Dir (void)
380 {
381         GetToken (qfalse);
382         PackDirectory_r (token);        
383 }
384
385 //========================================================================
386
387 #define MAX_RTEX        16384
388 int             numrtex;
389 char    rtex[MAX_RTEX][64];
390
391 void ReleaseTexture (char *name)
392 {
393         int             i;
394         char    path[1024];
395
396         for (i=0 ; i<numrtex ; i++)
397                 if (!Q_stricmp(name, rtex[i]))
398                         return;
399
400         if (numrtex == MAX_RTEX)
401                 Error ("numrtex == MAX_RTEX");
402
403         strcpy (rtex[i], name);
404         numrtex++;
405
406         sprintf (path, "textures/%s.wal", name);
407         ReleaseFile (path);
408 }
409
410 /*
411 ===============
412 Cmd_Maps
413
414 Only relevent for release and pak files.
415 Releases the .bsp files for the maps, and scans all of the files to
416 build a list of all textures used, which are then released.
417 ===============
418 */
419 void Cmd_Maps (void)
420 {
421         char    map[1024];
422
423         while (TokenAvailable ())
424         {
425                 GetToken (qfalse);
426                 sprintf (map, "maps/%s.bsp", token);
427                 ReleaseFile (map);
428
429                 if (!g_release)
430                         continue;
431
432                 // get all the texture references
433                 sprintf (map, "%smaps/%s.bsp", gamedir, token);
434                 LoadBSPFile( map );
435         }
436 }
437
438
439 //==============================================================
440
441 /*
442 ===============
443 ParseScript
444 ===============
445 */
446 void ParseScript (void)
447 {
448         while (1)
449         {
450                 do
451                 {       // look for a line starting with a $ command
452                         GetToken (qtrue);
453                         if (endofscript)
454                                 return;
455                         if (token[0] == '$')
456                                 break;                          
457                         while (TokenAvailable())
458                                 GetToken (qfalse);
459                 } while (1);
460         
461                 //
462                 // model commands
463                 //
464                 if (!strcmp (token, "$modelname"))
465                         Cmd_Modelname ();
466                 else if (!strcmp (token, "$base"))
467                         Cmd_Base ();
468                 else if ( !strcmp( token, "$exit" ) )
469                         break;
470                 else if ( !strcmp( token, "$3dsconvert" ) )
471                         Cmd_3DSConvert();
472                 else if (!strcmp (token, "$spritebase"))
473                         Cmd_SpriteBase ();
474                 else if (!strcmp (token, "$cd"))
475                         Cmd_Cd ();
476                 else if (!strcmp (token, "$origin"))
477                         Cmd_Origin ();
478                 else if (!strcmp (token, "$scale"))
479                         Cmd_ScaleUp ();
480                 else if (!strcmp (token, "$frame"))
481                         Cmd_Frame ();
482                 else if (!strcmp (token, "$skin" ))
483                         Cmd_Skin();
484                 else if (!strcmp (token, "$spriteshader"))
485                         Cmd_SpriteShader();
486                 else if (!strcmp( token, "$aseconvert" ))
487                         Cmd_ASEConvert( qfalse );
488                 else if (!strcmp( token, "$aseanimconvert" ) )
489                         Cmd_ASEConvert( qtrue );
490
491                 //
492                 // image commands
493                 //
494                 else if (!strcmp (token, "$grab"))
495                         Cmd_Grab ();
496                 else if (!strcmp (token, "$raw"))
497                         Cmd_Raw ();
498                 else if (!strcmp (token, "$colormap"))
499                         Cmd_Colormap ();
500                 else if (!strcmp (token, "$environment"))
501                         Cmd_Environment ();
502
503                 //
504                 // video
505                 //
506                 else if (!strcmp (token, "$video"))
507                         Cmd_Video ();
508                 //
509                 // misc
510                 //
511                 else if (!strcmp (token, "$file"))
512                         Cmd_File ();
513                 else if (!strcmp (token, "$dir"))
514                         Cmd_Dir ();
515                 else if (!strcmp (token, "$maps"))
516                         Cmd_Maps ();
517                 else
518                         Error ("bad command %s\n", token);
519         }
520 }
521
522 //=======================================================
523
524 #include "version.h"
525
526 /*
527 ==============
528 main
529 ==============
530 */
531 int main (int argc, char **argv)
532 {
533         static  int             i;              // VC4.2 compiler bug if auto...
534         char    path[1024];
535
536   // using GtkRadiant's versioning next to Id's versioning
537   printf ("Q3Data      - (c) 1999 Id Software Inc.\n");
538   printf ("GtkRadiant  - v" RADIANT_VERSION " " __DATE__ "\n");
539
540         ExpandWildcards (&argc, &argv);
541
542         for (i=1 ; i<argc ; i++)
543         {
544                 if (!strcmp(argv[i], "-archive"))
545                 {
546                         archive = qtrue;
547                         strcpy (archivedir, argv[i+1]);
548                         printf ("Archiving source to: %s\n", archivedir);
549                         i++;
550                 }
551                 else if (!strcmp(argv[i], "-release"))
552                 {
553                         g_release = qtrue;
554                         strcpy (g_releasedir, argv[i+1]);
555                         printf ("Copy output to: %s\n", g_releasedir);
556                         i++;
557                 }
558                 else if ( !strcmp( argv[i], "-nostrips" ) )
559                 {
560                         g_stripify = qfalse;
561                         printf( "Not optimizing for strips\n" );
562                 }
563                 else if ( !strcmp( argv[i], "-writedir" ) )
564                 {
565                         strcpy( writedir, argv[i+1] );
566                         printf( "Write output to: %s\n", writedir );
567                         i++;
568                 }
569                 else if ( !strcmp( argv[i], "-verbose" ) )
570                 {
571                         g_verbose = qtrue;
572                 }
573                 else if ( !strcmp( argv[i], "-dump" ) )
574                 {
575                         printf( "Dumping contents of: '%s'\n", argv[i+1] );
576                         if ( strstr( argv[i+1], ".md3" ) )
577                         {
578                                 MD3_Dump( argv[i+1] );
579                         }
580                         else
581                         {
582                                 Error( "Do not know how to dump the contents of '%s'\n", argv[i+1] );
583                         }
584                         i++;
585                 }
586                 else if ( !strcmp( argv[i], "-3dsconvert" ) )
587                 {
588       // NOTE TTimo this is broken, tried on a sample .3ds
589       // what happens .. it calls the Convert3DStoMD3,
590       // which calls the scriptlib function in non initialized state .. and crashes
591                         printf( "Converting %s.3DS to %s.MD3\n", argv[i+1], argv[i+1] );
592                         SetQdirFromPath( argv[i+1] );
593       vfsInitDirectory( gamedir );
594                         Convert3DStoMD3( argv[i+1] );
595                         i++;
596                 }
597                 else if (!strcmp(argv[i], "-only"))
598                 {
599                         strcpy (g_only, argv[i+1]);
600                         printf ("Only grabbing %s\n", g_only);
601                         i++;
602                 }
603                 else if (!strcmp(argv[i], "-gamedir"))
604                 {
605                         strcpy(gamedir, argv[i+1]);
606                         i++;
607                 }
608                 else if (argv[i][0] == '-')
609                         Error ("Unknown option \"%s\"", argv[i]);
610                 else
611                         break;
612         }
613
614         if (i == argc)
615                 Error ("usage: q3data [-archive <directory>] [-dump <file.md3>] [-release <directory>] [-only <model>] [-3dsconvert <file.3ds>] [-verbose] [file.qdt]");
616
617         for ( ; i<argc ; i++)
618         {
619                 printf ("--------------- %s ---------------\n", argv[i]);
620                 // load the script
621                 strcpy (path, argv[i]);
622                 DefaultExtension (path, ".qdt");
623                 if(!gamedir[0])
624                         SetQdirFromPath (path);
625     // NOTE TTimo
626     // q3data went through a partial conversion to use the vfs
627     // it was never actually tested before 1.1.1
628     // the code is still mostly using direct file access calls
629     vfsInitDirectory( gamedir );
630                 LoadScriptFile (ExpandArg(path), -1);
631                 
632                 //
633                 // parse it
634                 //
635                 ParseScript ();
636
637                 // write out the last model
638                 FinishModel ( TYPE_UNKNOWN );
639         }
640
641         return 0;
642 }
643