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