]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata/qdata.c
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / tools / quake2 / qdata / qdata.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 "qdata.h"
23 #include "inout.h"
24 #include "md4.h"
25
26 qboolean g_compress_pak;
27 qboolean g_release;             // don't grab, copy output data to new tree
28 qboolean g_pak;                 // if true, copy to pak instead of release
29 char g_releasedir[1024];        // c:\quake2\baseq2, etc
30 qboolean g_archive;             // don't grab, copy source data to new tree
31 qboolean do3ds;
32 char g_only[256];               // if set, only grab this cd
33 qboolean g_skipmodel;           // set true when a cd is not g_only
34
35 char        *ext_3ds = "3ds";
36 char        *ext_tri = "tri";
37 char        *trifileext;
38
39 char game[64] = "quake2";
40
41 void InitPaths( int *argc, char **argv );
42
43 /*
44    =======================================================
45
46    PAK FILES
47
48    =======================================================
49  */
50
51 typedef struct
52 {
53         char name[56];
54         int filepos, filelen;
55 } packfile_t;
56
57 typedef struct
58 {
59         char id[4];
60         int dirofs;
61         int dirlen;
62 } packheader_t;
63
64 packfile_t pfiles[16384];
65 FILE            *pakfile;
66 packfile_t      *pf;
67 packheader_t pakheader;
68
69
70
71 /*
72    ==============
73    BeginPak
74    ==============
75  */
76 void BeginPak( char *outname ){
77         if ( !g_pak ) {
78                 return;
79         }
80
81         pakfile = SafeOpenWrite( outname );
82
83         // leave space for header
84         SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
85
86         pf = pfiles;
87 }
88
89
90 /*
91    ==============
92    ReleaseFile
93
94    Filename should be gamedir reletive.
95    Either copies the file to the release dir, or adds it to
96    the pak file.
97    ==============
98  */
99 void ReleaseFile( char *filename ){
100         int len;
101         byte    *buf;
102         char source[1024];
103         char dest[1024];
104
105         if ( !g_release ) {
106                 return;
107         }
108
109         sprintf( source, "%s%s", gamedir, filename );
110
111         if ( !g_pak ) { // copy it
112                 sprintf( dest, "%s/%s", g_releasedir, filename );
113                 printf( "copying to %s\n", dest );
114                 QCopyFile( source, dest );
115                 return;
116         }
117
118         // pak it
119         printf( "paking %s\n", filename );
120         if ( strlen( filename ) >= sizeof( pf->name ) ) {
121                 Error( "Filename too long for pak: %s", filename );
122         }
123
124         len = LoadFile( source, (void **)&buf );
125
126         if ( g_compress_pak && len < 4096 * 1024 ) {
127                 cblock_t in, out;
128                 cblock_t Huffman( cblock_t in );
129
130                 in.count = len;
131                 in.data = buf;
132
133                 out = Huffman( in );
134
135                 if ( out.count < in.count ) {
136                         printf( "   compressed from %i to %i\n", in.count, out.count );
137                         free( in.data );
138                         buf = out.data;
139                         len = out.count;
140                 }
141                 else{
142                         free( out.data );
143                 }
144         }
145
146         strcpy( pf->name, filename );
147         pf->filepos = LittleLong( ftell( pakfile ) );
148         pf->filelen = LittleLong( len );
149         pf++;
150
151         SafeWrite( pakfile, buf, len );
152
153         free( buf );
154 }
155
156
157 /*
158    ==============
159    FinishPak
160    ==============
161  */
162 void FinishPak( void ){
163         int dirlen;
164         int d;
165         int i;
166         unsigned checksum;
167
168         if ( !g_pak ) {
169                 return;
170         }
171
172         pakheader.id[0] = 'P';
173         pakheader.id[1] = 'A';
174         pakheader.id[2] = 'C';
175         pakheader.id[3] = 'K';
176         dirlen = (byte *)pf - (byte *)pfiles;
177         pakheader.dirofs = LittleLong( ftell( pakfile ) );
178         pakheader.dirlen = LittleLong( dirlen );
179
180         checksum = Com_BlockChecksum( (void *)pfiles, dirlen );
181
182         SafeWrite( pakfile, pfiles, dirlen );
183
184         i = ftell( pakfile );
185
186         fseek( pakfile, 0, SEEK_SET );
187         SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
188         fclose( pakfile );
189
190         d = pf - pfiles;
191         printf( "%i files packed in %i bytes\n",d, i );
192         printf( "checksum: 0x%x\n", checksum );
193 }
194
195
196 /*
197    ===============
198    Cmd_File
199
200    This is only used to cause a file to be copied during a release
201    build (default.cfg, maps, etc)
202    ===============
203  */
204 void Cmd_File( void ){
205         GetToken( false );
206         ReleaseFile( token );
207 }
208
209 /*
210    ===============
211    PackDirectory_r
212
213    ===============
214  */
215 #if GDEF_OS_WINDOWS
216 #include "io.h"
217 void PackDirectory_r( char *dir ){
218         struct _finddata_t fileinfo;
219         int handle;
220         char dirstring[1024];
221         char filename[1024];
222
223         sprintf( dirstring, "%s%s/*.*", gamedir, dir );
224
225         handle = _findfirst( dirstring, &fileinfo );
226         if ( handle == -1 ) {
227                 return;
228         }
229
230         do
231         {
232                 sprintf( filename, "%s/%s", dir, fileinfo.name );
233                 if ( fileinfo.attrib & _A_SUBDIR ) { // directory
234                         if ( fileinfo.name[0] != '.' ) {  // don't pak . and ..
235                                 PackDirectory_r( filename );
236                         }
237                         continue;
238                 }
239                 // copy or pack the file
240                 ReleaseFile( filename );
241         } while ( _findnext( handle, &fileinfo ) != -1 );
242
243         _findclose( handle );
244 }
245 #else
246
247 #include <sys/types.h>
248
249 #include <dirent.h>
250
251 void PackDirectory_r( char *dir ){
252 #ifdef NeXT
253         struct direct **namelist, *ent;
254 #else
255         struct dirent **namelist, *ent;
256 #endif
257         int count;
258         struct stat st;
259         int i;
260         int len;
261         char fullname[1024];
262         char dirstring[1024];
263         char        *name;
264
265         sprintf( dirstring, "%s%s", gamedir, dir );
266         count = scandir( dirstring, &namelist, NULL, NULL );
267
268         for ( i = 0 ; i < count ; i++ )
269         {
270                 ent = namelist[i];
271                 name = ent->d_name;
272
273                 if ( name[0] == '.' ) {
274                         continue;
275                 }
276
277                 sprintf( fullname, "%s/%s", dir, name );
278                 sprintf( dirstring, "%s%s/%s", gamedir, dir, name );
279
280                 if ( stat( dirstring, &st ) == -1 ) {
281                         Error( "fstating %s", pf->name );
282                 }
283                 if ( st.st_mode & S_IFDIR ) { // directory
284                         PackDirectory_r( fullname );
285                         continue;
286                 }
287
288                 // copy or pack the file
289                 ReleaseFile( fullname );
290         }
291 }
292 #endif
293
294
295 /*
296    ===============
297    Cmd_Dir
298
299    This is only used to cause a directory to be copied during a
300    release build (sounds, etc)
301    ===============
302  */
303 void Cmd_Dir( void ){
304         GetToken( false );
305         PackDirectory_r( token );
306 }
307
308 //========================================================================
309
310 #define MAX_RTEX    16384
311 int numrtex;
312 char rtex[MAX_RTEX][64];
313
314 void ReleaseTexture( char *name ){
315         int i;
316         char path[1024];
317
318         for ( i = 0 ; i < numrtex ; i++ )
319                 if ( !Q_strncasecmp( name, rtex[i], strlen( name ) ) ) {
320                         return;
321                 }
322
323         if ( numrtex == MAX_RTEX ) {
324                 Error( "numrtex == MAX_RTEX" );
325         }
326
327         strcpy( rtex[i], name );
328         numrtex++;
329
330         sprintf( path, "textures/%s.wal", name );
331         ReleaseFile( path );
332 }
333
334 /*
335    ===============
336    Cmd_Maps
337
338    Only relevent for release and pak files.
339    Releases the .bsp files for the maps, and scans all of the files to
340    build a list of all textures used, which are then released.
341    ===============
342  */
343 void Cmd_Maps( void ){
344         char map[1024];
345         int i;
346
347         while ( TokenAvailable() )
348         {
349                 GetToken( false );
350                 sprintf( map, "maps/%s.bsp", token );
351                 ReleaseFile( map );
352
353                 if ( !g_release ) {
354                         continue;
355                 }
356
357                 // get all the texture references
358                 sprintf( map, "%smaps/%s.bsp", gamedir, token );
359                 LoadBSPFileTexinfo( map );
360                 for ( i = 0 ; i < numtexinfo ; i++ )
361                         ReleaseTexture( texinfo[i].texture );
362         }
363 }
364
365
366 //==============================================================
367
368 /*
369    ===============
370    ParseScript
371    ===============
372  */
373 void ParseScript( void ){
374         while ( 1 )
375         {
376                 do
377                 {   // look for a line starting with a $ command
378                         GetToken( true );
379                         if ( endofscript ) {
380                                 return;
381                         }
382                         if ( token[0] == '$' ) {
383                                 break;
384                         }
385                         while ( TokenAvailable() )
386                                 GetToken( false );
387                 } while ( 1 );
388
389                 //
390                 // model commands
391                 //
392                 if ( !strcmp( token, "$modelname" ) ) {
393                         Cmd_Modelname();
394                 }
395                 else if ( !strcmp( token, "$base" ) ) {
396                         Cmd_Base();
397                 }
398                 else if ( !strcmp( token, "$cd" ) ) {
399                         Cmd_Cd();
400                 }
401                 else if ( !strcmp( token, "$origin" ) ) {
402                         Cmd_Origin();
403                 }
404                 else if ( !strcmp( token, "$scale" ) ) {
405                         Cmd_ScaleUp();
406                 }
407                 else if ( !strcmp( token, "$frame" ) ) {
408                         Cmd_Frame();
409                 }
410                 else if ( !strcmp( token, "$skin" ) ) {
411                         Cmd_Skin();
412                 }
413                 else if ( !strcmp( token, "$skinsize" ) ) {
414                         Cmd_Skinsize();
415                 }
416                 //
417                 // sprite commands
418                 //
419                 else if ( !strcmp( token, "$spritename" ) ) {
420                         Cmd_SpriteName();
421                 }
422                 else if ( !strcmp( token, "$load" ) ) {
423                         Cmd_Load();
424                 }
425                 else if ( !strcmp( token, "$spriteframe" ) ) {
426                         Cmd_SpriteFrame();
427                 }
428                 //
429                 // image commands
430                 //
431                 else if ( !strcmp( token, "$grab" ) ) {
432                         Cmd_Grab();
433                 }
434                 else if ( !strcmp( token, "$raw" ) ) {
435                         Cmd_Raw();
436                 }
437                 else if ( !strcmp( token, "$colormap" ) ) {
438                         Cmd_Colormap();
439                 }
440                 else if ( !strcmp( token, "$mippal" ) ) {
441                         Cmd_Mippal();
442                 }
443                 else if ( !strcmp( token, "$mipdir" ) ) {
444                         Cmd_Mipdir();
445                 }
446                 else if ( !strcmp( token, "$mip" ) ) {
447                         Cmd_Mip();
448                 }
449                 else if ( !strcmp( token, "$environment" ) ) {
450                         Cmd_Environment();
451                 }
452                 //
453                 // video
454                 //
455                 else if ( !strcmp( token, "$video" ) ) {
456                         Cmd_Video();
457                 }
458                 //
459                 // misc
460                 //
461                 else if ( !strcmp( token, "$file" ) ) {
462                         Cmd_File();
463                 }
464                 else if ( !strcmp( token, "$dir" ) ) {
465                         Cmd_Dir();
466                 }
467                 else if ( !strcmp( token, "$maps" ) ) {
468                         Cmd_Maps();
469                 }
470                 else if ( !strcmp( token, "$alphalight" ) ) {
471                         Cmd_Alphalight();
472                 }
473                 else if ( !strcmp( token, "$inverse16table" ) ) {
474                         Cmd_Inverse16Table();
475                 }
476                 else{
477                         Error( "bad command %s\n", token );
478                 }
479         }
480 }
481
482 //=======================================================
483
484 /*
485    ==============
486    main
487    ==============
488  */
489 int main( int argc, char **argv ){
490         static int i;           // VC4.2 compiler bug if auto...
491         char path[1024];
492
493         ExpandWildcards( &argc, &argv );
494
495         InitPaths( &argc, argv );
496
497         for ( i = 1 ; i < argc ; i++ )
498         {
499                 if ( !strcmp( argv[i], "-archive" ) ) {
500                         // -archive f:/quake2/release/dump_11_30
501                         archive = true;
502                         strcpy( archivedir, argv[i + 1] );
503                         printf( "Archiving source to: %s\n", archivedir );
504                         i++;
505                 }
506                 else if ( !strcmp( argv[i], "-release" ) ) {
507                         g_release = true;
508                         strcpy( g_releasedir, argv[i + 1] );
509                         printf( "Copy output to: %s\n", g_releasedir );
510                         i++;
511                 }
512                 else if ( !strcmp( argv[i], "-compress" ) ) {
513                         g_compress_pak = true;
514                         printf( "Compressing pakfile\n" );
515                 }
516                 else if ( !strcmp( argv[i], "-pak" ) ) {
517                         g_release = true;
518                         g_pak = true;
519                         printf( "Building pakfile: %s\n", argv[i + 1] );
520                         BeginPak( argv[i + 1] );
521                         i++;
522                 }
523                 else if ( !strcmp( argv[i], "-only" ) ) {
524                         strcpy( g_only, argv[i + 1] );
525                         printf( "Only grabbing %s\n", g_only );
526                         i++;
527                 }
528                 else if ( !strcmp( argv[i], "-3ds" ) ) {
529                         do3ds = true;
530                         printf( "loading .3ds files\n" );
531                 }
532                 else if ( argv[i][0] == '-' ) {
533                         Error( "Unknown option \"%s\"", argv[i] );
534                 }
535                 else{
536                         break;
537                 }
538         }
539
540         if ( i >= argc ) {
541                 Error( "usage: %s [-archive <directory>] [-release <directory>] [-only <model>] [-3ds] file.qgr", argv[ 0 ] );
542         }
543
544         if ( do3ds ) {
545                 trifileext = ext_3ds;
546         }
547         else{
548                 trifileext = ext_tri;
549         }
550
551         for ( ; i < argc ; i++ )
552         {
553                 printf( "--------------- %s ---------------\n", argv[i] );
554                 // load the script
555                 strcpy( path, argv[i] );
556                 DefaultExtension( path, ".qdt" );
557                 SetQdirFromPath( path );
558                 LoadScriptFile( ExpandArg( path ) );
559
560                 //
561                 // parse it
562                 //
563                 ParseScript();
564
565                 // write out the last model
566                 FinishModel();
567                 FinishSprite();
568         }
569
570         if ( g_pak ) {
571                 FinishPak();
572         }
573
574         return 0;
575 }