]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata/qdata.c
Merge branch 'fix-minizip' into 'master'
[xonotic/netradiant.git] / tools / quake2 / qdata / qdata.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 #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 #ifdef _WIN32
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 #include <sys/dir.h>
249
250 void PackDirectory_r( char *dir ){
251 #ifdef NeXT
252         struct direct **namelist, *ent;
253 #else
254         struct dirent **namelist, *ent;
255 #endif
256         int count;
257         struct stat st;
258         int i;
259         int len;
260         char fullname[1024];
261         char dirstring[1024];
262         char        *name;
263
264         sprintf( dirstring, "%s%s", gamedir, dir );
265         count = scandir( dirstring, &namelist, NULL, NULL );
266
267         for ( i = 0 ; i < count ; i++ )
268         {
269                 ent = namelist[i];
270                 name = ent->d_name;
271
272                 if ( name[0] == '.' ) {
273                         continue;
274                 }
275
276                 sprintf( fullname, "%s/%s", dir, name );
277                 sprintf( dirstring, "%s%s/%s", gamedir, dir, name );
278
279                 if ( stat( dirstring, &st ) == -1 ) {
280                         Error( "fstating %s", pf->name );
281                 }
282                 if ( st.st_mode & S_IFDIR ) { // directory
283                         PackDirectory_r( fullname );
284                         continue;
285                 }
286
287                 // copy or pack the file
288                 ReleaseFile( fullname );
289         }
290 }
291 #endif
292
293
294 /*
295    ===============
296    Cmd_Dir
297
298    This is only used to cause a directory to be copied during a
299    release build (sounds, etc)
300    ===============
301  */
302 void Cmd_Dir( void ){
303         GetToken( false );
304         PackDirectory_r( token );
305 }
306
307 //========================================================================
308
309 #define MAX_RTEX    16384
310 int numrtex;
311 char rtex[MAX_RTEX][64];
312
313 void ReleaseTexture( char *name ){
314         int i;
315         char path[1024];
316
317         for ( i = 0 ; i < numrtex ; i++ )
318                 if ( !Q_strncasecmp( name, rtex[i], strlen( name ) ) ) {
319                         return;
320                 }
321
322         if ( numrtex == MAX_RTEX ) {
323                 Error( "numrtex == MAX_RTEX" );
324         }
325
326         strcpy( rtex[i], name );
327         numrtex++;
328
329         sprintf( path, "textures/%s.wal", name );
330         ReleaseFile( path );
331 }
332
333 /*
334    ===============
335    Cmd_Maps
336
337    Only relevent for release and pak files.
338    Releases the .bsp files for the maps, and scans all of the files to
339    build a list of all textures used, which are then released.
340    ===============
341  */
342 void Cmd_Maps( void ){
343         char map[1024];
344         int i;
345
346         while ( TokenAvailable() )
347         {
348                 GetToken( false );
349                 sprintf( map, "maps/%s.bsp", token );
350                 ReleaseFile( map );
351
352                 if ( !g_release ) {
353                         continue;
354                 }
355
356                 // get all the texture references
357                 sprintf( map, "%smaps/%s.bsp", gamedir, token );
358                 LoadBSPFileTexinfo( map );
359                 for ( i = 0 ; i < numtexinfo ; i++ )
360                         ReleaseTexture( texinfo[i].texture );
361         }
362 }
363
364
365 //==============================================================
366
367 /*
368    ===============
369    ParseScript
370    ===============
371  */
372 void ParseScript( void ){
373         while ( 1 )
374         {
375                 do
376                 {   // look for a line starting with a $ command
377                         GetToken( true );
378                         if ( endofscript ) {
379                                 return;
380                         }
381                         if ( token[0] == '$' ) {
382                                 break;
383                         }
384                         while ( TokenAvailable() )
385                                 GetToken( false );
386                 } while ( 1 );
387
388                 //
389                 // model commands
390                 //
391                 if ( !strcmp( token, "$modelname" ) ) {
392                         Cmd_Modelname();
393                 }
394                 else if ( !strcmp( token, "$base" ) ) {
395                         Cmd_Base();
396                 }
397                 else if ( !strcmp( token, "$cd" ) ) {
398                         Cmd_Cd();
399                 }
400                 else if ( !strcmp( token, "$origin" ) ) {
401                         Cmd_Origin();
402                 }
403                 else if ( !strcmp( token, "$scale" ) ) {
404                         Cmd_ScaleUp();
405                 }
406                 else if ( !strcmp( token, "$frame" ) ) {
407                         Cmd_Frame();
408                 }
409                 else if ( !strcmp( token, "$skin" ) ) {
410                         Cmd_Skin();
411                 }
412                 else if ( !strcmp( token, "$skinsize" ) ) {
413                         Cmd_Skinsize();
414                 }
415                 //
416                 // sprite commands
417                 //
418                 else if ( !strcmp( token, "$spritename" ) ) {
419                         Cmd_SpriteName();
420                 }
421                 else if ( !strcmp( token, "$load" ) ) {
422                         Cmd_Load();
423                 }
424                 else if ( !strcmp( token, "$spriteframe" ) ) {
425                         Cmd_SpriteFrame();
426                 }
427                 //
428                 // image commands
429                 //
430                 else if ( !strcmp( token, "$grab" ) ) {
431                         Cmd_Grab();
432                 }
433                 else if ( !strcmp( token, "$raw" ) ) {
434                         Cmd_Raw();
435                 }
436                 else if ( !strcmp( token, "$colormap" ) ) {
437                         Cmd_Colormap();
438                 }
439                 else if ( !strcmp( token, "$mippal" ) ) {
440                         Cmd_Mippal();
441                 }
442                 else if ( !strcmp( token, "$mipdir" ) ) {
443                         Cmd_Mipdir();
444                 }
445                 else if ( !strcmp( token, "$mip" ) ) {
446                         Cmd_Mip();
447                 }
448                 else if ( !strcmp( token, "$environment" ) ) {
449                         Cmd_Environment();
450                 }
451                 //
452                 // video
453                 //
454                 else if ( !strcmp( token, "$video" ) ) {
455                         Cmd_Video();
456                 }
457                 //
458                 // misc
459                 //
460                 else if ( !strcmp( token, "$file" ) ) {
461                         Cmd_File();
462                 }
463                 else if ( !strcmp( token, "$dir" ) ) {
464                         Cmd_Dir();
465                 }
466                 else if ( !strcmp( token, "$maps" ) ) {
467                         Cmd_Maps();
468                 }
469                 else if ( !strcmp( token, "$alphalight" ) ) {
470                         Cmd_Alphalight();
471                 }
472                 else if ( !strcmp( token, "$inverse16table" ) ) {
473                         Cmd_Inverse16Table();
474                 }
475                 else{
476                         Error( "bad command %s\n", token );
477                 }
478         }
479 }
480
481 //=======================================================
482
483 /*
484    ==============
485    main
486    ==============
487  */
488 int main( int argc, char **argv ){
489         static int i;           // VC4.2 compiler bug if auto...
490         char path[1024];
491
492         ExpandWildcards( &argc, &argv );
493
494         InitPaths( &argc, argv );
495
496         for ( i = 1 ; i < argc ; i++ )
497         {
498                 if ( !strcmp( argv[i], "-archive" ) ) {
499                         // -archive f:/quake2/release/dump_11_30
500                         archive = true;
501                         strcpy( archivedir, argv[i + 1] );
502                         printf( "Archiving source to: %s\n", archivedir );
503                         i++;
504                 }
505                 else if ( !strcmp( argv[i], "-release" ) ) {
506                         g_release = true;
507                         strcpy( g_releasedir, argv[i + 1] );
508                         printf( "Copy output to: %s\n", g_releasedir );
509                         i++;
510                 }
511                 else if ( !strcmp( argv[i], "-compress" ) ) {
512                         g_compress_pak = true;
513                         printf( "Compressing pakfile\n" );
514                 }
515                 else if ( !strcmp( argv[i], "-pak" ) ) {
516                         g_release = true;
517                         g_pak = true;
518                         printf( "Building pakfile: %s\n", argv[i + 1] );
519                         BeginPak( argv[i + 1] );
520                         i++;
521                 }
522                 else if ( !strcmp( argv[i], "-only" ) ) {
523                         strcpy( g_only, argv[i + 1] );
524                         printf( "Only grabbing %s\n", g_only );
525                         i++;
526                 }
527                 else if ( !strcmp( argv[i], "-3ds" ) ) {
528                         do3ds = true;
529                         printf( "loading .3ds files\n" );
530                 }
531                 else if ( argv[i][0] == '-' ) {
532                         Error( "Unknown option \"%s\"", argv[i] );
533                 }
534                 else{
535                         break;
536                 }
537         }
538
539         if ( i >= argc ) {
540                 Error( "usage: %s [-archive <directory>] [-release <directory>] [-only <model>] [-3ds] file.qgr", argv[ 0 ] );
541         }
542
543         if ( do3ds ) {
544                 trifileext = ext_3ds;
545         }
546         else{
547                 trifileext = ext_tri;
548         }
549
550         for ( ; i < argc ; i++ )
551         {
552                 printf( "--------------- %s ---------------\n", argv[i] );
553                 // load the script
554                 strcpy( path, argv[i] );
555                 DefaultExtension( path, ".qdt" );
556                 SetQdirFromPath( path );
557                 LoadScriptFile( ExpandArg( path ) );
558
559                 //
560                 // parse it
561                 //
562                 ParseScript();
563
564                 // write out the last model
565                 FinishModel();
566                 FinishSprite();
567         }
568
569         if ( g_pak ) {
570                 FinishPak();
571         }
572
573         return 0;
574 }