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