]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/qdata.c
Centralise compile checks
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / 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 "globaldefs.h"
24 #include "md4.h"
25
26 void TK_Init();
27
28 qboolean g_compress_pak;
29 qboolean g_release;             // don't grab, copy output data to new tree
30 qboolean g_pak;                 // if true, copy to pak instead of release
31 char g_releasedir[1024];        // c:\quake2\baseq2, etc
32 qboolean g_archive;             // don't grab, copy source data to new tree
33 qboolean do3ds;
34 char g_only[256];               // if set, only grab this cd
35 qboolean g_skipmodel;           // set true when a cd is not g_only
36 int g_forcemodel = MODEL_AUTO;
37 qboolean g_verbose = false;
38 qboolean g_allow_newskin = true;
39 qboolean g_ignoreTriUV = false;
40 qboolean g_publishOutput = false;
41
42 char        *ext_3ds = "3ds";
43 char        *ext_tri = "tri";
44 char        *trifileext;
45
46 char g_materialFile[256] = "none";          // default for Heretic2
47 char        *g_outputDir;
48 extern char *g_publishDir;
49
50 extern qboolean g_nomkdir;
51
52 /*
53    =======================================================
54
55    PAK FILES
56
57    =======================================================
58  */
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 /*
81    ==============
82    BeginPak
83    ==============
84  */
85 void BeginPak( char *outname ){
86         if ( !g_pak ) {
87                 return;
88         }
89
90         pakfile = SafeOpenWrite( outname );
91
92         // leave space for header
93         SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
94
95         pf = pfiles;
96 }
97
98
99 /*
100    ==============
101    ReleaseFile
102
103    Filename should be gamedir reletive.
104    Either copies the file to the release dir, or adds it to
105    the pak file.
106    ==============
107  */
108 void ReleaseFile( char *filename ){
109         int len;
110         byte    *buf;
111         char source[1024];
112         char dest[1024];
113
114         if ( !g_release ) {
115                 return;
116         }
117
118         sprintf( source, "%s%s", gamedir, filename );
119
120         if ( !g_pak ) { // copy it
121                 sprintf( dest, "%s/%s", g_releasedir, filename );
122                 printf( "copying to %s\n", dest );
123                 QCopyFile( source, dest );
124                 return;
125         }
126
127         // pak it
128         printf( "paking %s\n", filename );
129         if ( strlen( filename ) >= sizeof( pf->name ) ) {
130                 Error( "Filename too long for pak: %s", filename );
131         }
132
133         len = LoadFile( source, (void **)&buf );
134
135         // segment moved to old.c
136
137         strcpy( pf->name, filename );
138         pf->filepos = LittleLong( ftell( pakfile ) );
139         pf->filelen = LittleLong( len );
140         pf++;
141
142         SafeWrite( pakfile, buf, len );
143
144         free( buf );
145 }
146
147
148 /*
149    ==============
150    FinishPak
151    ==============
152  */
153 void FinishPak( void ){
154         int dirlen;
155         int d;
156         int i;
157         unsigned checksum;
158
159         if ( !g_pak ) {
160                 return;
161         }
162
163         pakheader.id[0] = 'P';
164         pakheader.id[1] = 'A';
165         pakheader.id[2] = 'C';
166         pakheader.id[3] = 'K';
167         dirlen = (byte *)pf - (byte *)pfiles;
168         pakheader.dirofs = LittleLong( ftell( pakfile ) );
169         pakheader.dirlen = LittleLong( dirlen );
170
171         checksum = Com_BlockChecksum( (void *)pfiles, dirlen );
172
173         SafeWrite( pakfile, pfiles, dirlen );
174
175         i = ftell( pakfile );
176
177         fseek( pakfile, 0, SEEK_SET );
178         SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
179         fclose( pakfile );
180
181         d = pf - pfiles;
182         printf( "%i files packed in %i bytes\n",d, i );
183         printf( "checksum: 0x%x\n", checksum );
184 }
185
186
187 /*
188    ===============
189    Cmd_File
190
191    This is only used to cause a file to be copied during a release
192    build (default.cfg, maps, etc)
193    ===============
194  */
195 void Cmd_File( void ){
196         GetScriptToken( false );
197         ReleaseFile( token );
198 }
199
200 /*
201    ===============
202    PackDirectory_r
203
204    ===============
205  */
206 #if GDEF_OS_WINDOWS
207 #include "io.h"
208 void PackDirectory_r( char *dir ){
209         struct _finddata_t fileinfo;
210         int handle;
211         char dirstring[1024];
212         char filename[1024];
213
214         sprintf( dirstring, "%s%s/*.*", gamedir, dir );
215
216         handle = _findfirst( dirstring, &fileinfo );
217         if ( handle == -1 ) {
218                 return;
219         }
220
221         do
222         {
223                 sprintf( filename, "%s/%s", dir, fileinfo.name );
224                 if ( fileinfo.attrib & _A_SUBDIR ) { // directory
225                         if ( fileinfo.name[0] != '.' ) {  // don't pak . and ..
226                                 PackDirectory_r( filename );
227                         }
228                         continue;
229                 }
230                 // copy or pack the file
231                 ReleaseFile( filename );
232         } while ( _findnext( handle, &fileinfo ) != -1 );
233
234         _findclose( handle );
235 }
236 #else
237
238 #include <sys/types.h>
239 #ifdef NeXT
240 #include <sys/dir.h>
241 #else
242 #include <dirent.h>
243 #endif
244
245 void PackDirectory_r( char *dir ){
246 #ifdef NeXT
247         struct direct **namelist, *ent;
248 #else
249         struct dirent **namelist, *ent;
250 #endif
251         int count;
252         struct stat st;
253         int i;
254         int len;
255         char fullname[1024];
256         char dirstring[1024];
257         char        *name;
258
259         sprintf( dirstring, "%s%s", gamedir, dir );
260         count = scandir( dirstring, &namelist, NULL, NULL );
261
262         for ( i = 0 ; i < count ; i++ )
263         {
264                 ent = namelist[i];
265                 name = ent->d_name;
266
267                 if ( name[0] == '.' ) {
268                         continue;
269                 }
270
271                 sprintf( fullname, "%s/%s", dir, name );
272                 sprintf( dirstring, "%s%s/%s", gamedir, dir, name );
273
274                 if ( stat( dirstring, &st ) == -1 ) {
275                         Error( "fstating %s", pf->name );
276                 }
277                 if ( st.st_mode & S_IFDIR ) { // directory
278                         PackDirectory_r( fullname );
279                         continue;
280                 }
281
282                 // copy or pack the file
283                 ReleaseFile( fullname );
284         }
285 }
286 #endif
287
288
289 /*
290    ===============
291    Cmd_Dir
292
293    This is only used to cause a directory to be copied during a
294    release build (sounds, etc)
295    ===============
296  */
297 void Cmd_Dir( void ){
298         GetScriptToken( false );
299         PackDirectory_r( token );
300 }
301
302 //========================================================================
303
304 #define MAX_RTEX    16384
305 int numrtex;
306 char rtex[MAX_RTEX][64];
307
308 void ReleaseTexture( char *name ){
309         int i;
310         char path[1024];
311
312         for ( i = 0 ; i < numrtex ; i++ )
313                 if ( !Q_strcasecmp( name, rtex[i] ) ) {
314                         return;
315                 }
316
317         if ( numrtex == MAX_RTEX ) {
318                 Error( "numrtex == MAX_RTEX" );
319         }
320
321         strcpy( rtex[i], name );
322         numrtex++;
323
324         sprintf( path, "textures/%s.wal", name );
325         ReleaseFile( path );
326 }
327
328 /*
329    ===============
330    Cmd_Maps
331
332    Only relevent for release and pak files.
333    Releases the .bsp files for the maps, and scans all of the files to
334    build a list of all textures used, which are then released.
335    ===============
336  */
337 void Cmd_Maps( void ){
338         char map[1024];
339         int i;
340
341         while ( ScriptTokenAvailable() )
342         {
343                 GetScriptToken( false );
344                 sprintf( map, "maps/%s.bsp", token );
345                 ReleaseFile( map );
346
347                 if ( !g_release ) {
348                         continue;
349                 }
350
351                 // get all the texture references
352                 sprintf( map, "%smaps/%s.bsp", gamedir, token );
353                 LoadBSPFileTexinfo( map );
354                 for ( i = 0 ; i < numtexinfo ; i++ )
355                         ReleaseTexture( texinfo[i].texture );
356         }
357 }
358
359
360 //==============================================================
361
362 /*
363    ===============
364    ParseScript
365    ===============
366  */
367 void ParseScript( void ){
368         while ( 1 )
369         {
370                 do
371                 {   // look for a line starting with a $ command
372                         GetScriptToken( true );
373                         if ( endofscript ) {
374                                 return;
375                         }
376                         if ( token[0] == '$' ) {
377                                 break;
378                         }
379                         while ( ScriptTokenAvailable() )
380                                 GetScriptToken( false );
381                 } while ( 1 );
382
383                 //
384                 // model commands
385                 //
386                 if ( !strcmp( token, "$modelname" ) ) {
387                         MODELCMD_Modelname( MODEL_MD2 );
388                 }
389                 else if ( !strcmp( token, "$cd" ) ) {
390                         MODELCMD_Cd( MODEL_MD2 );
391                 }
392                 else if ( !strcmp( token, "$origin" ) ) {
393                         MODELCMD_Origin( MODEL_MD2 );
394                 }
395                 else if ( !strcmp( token, "$cluster" ) ) {
396                         MODELCMD_Cluster( MODEL_MD2 );
397                 }
398                 else if ( !strcmp( token, "$base" ) ) {
399                         MODELCMD_Base( MODEL_MD2 );
400                 }
401                 else if ( !strcmp( token, "$scale" ) ) {
402                         MODELCMD_ScaleUp( MODEL_MD2 );
403                 }
404                 else if ( !strcmp( token, "$frame" ) ) {
405                         MODELCMD_Frame( MODEL_MD2 );
406                 }
407                 else if ( !strcmp( token, "$skin" ) ) {
408                         MODELCMD_Skin( MODEL_MD2 );
409                 }
410                 else if ( !strcmp( token, "$skinsize" ) ) {
411                         MODELCMD_Skinsize( MODEL_MD2 );
412                 }
413                 //
414                 // flexible model commands
415                 //
416                 else if ( !strcmp( token, "$fm_modelname" ) ) {
417                         MODELCMD_Modelname( MODEL_FM );
418                 }
419                 else if ( !strcmp( token, "$fm_base" ) ) {
420                         MODELCMD_Base( MODEL_FM );
421                 }
422                 else if ( !strcmp( token, "$fm_basest" ) ) {
423                         MODELCMD_BaseST( MODEL_FM );
424                 }
425                 else if ( !strcmp( token, "$fm_cd" ) ) {
426                         MODELCMD_Cd( MODEL_FM );
427                 }
428                 else if ( !strcmp( token, "$fm_origin" ) ) {
429                         MODELCMD_Origin( MODEL_FM );
430                 }
431                 else if ( !strcmp( token, "$fm_cluster" ) ) {
432                         MODELCMD_Cluster( MODEL_FM );
433                 }
434                 else if ( !strcmp( token, "$fm_skeleton" ) ) {
435                         MODELCMD_Skeleton( MODEL_FM );
436                 }
437                 else if ( !strcmp( token, "$fm_scale" ) ) {
438                         MODELCMD_ScaleUp( MODEL_FM );
439                 }
440                 else if ( !strcmp( token, "$fm_frame" ) ) {
441                         MODELCMD_Frame( MODEL_FM );
442                 }
443                 else if ( !strcmp( token, "$fm_skeletal_frame" ) ) { // left in for compadibility with qdt already using fm_skeletal_frame
444                         MODELCMD_Frame( MODEL_FM );
445                 }
446                 else if ( !strcmp( token, "$fm_skin" ) ) {
447                         MODELCMD_Skin( MODEL_FM );
448                 }
449                 else if ( !strcmp( token, "$fm_skinsize" ) ) {
450                         MODELCMD_Skinsize( MODEL_FM );
451                 }
452                 else if ( !strcmp( token, "$fm_begin_group" ) ) {
453                         MODELCMD_BeginGroup( MODEL_FM );
454                 }
455                 else if ( !strcmp( token, "$fm_end_group" ) ) {
456                         MODELCMD_EndGroup( MODEL_FM );
457                 }
458                 else if ( !strcmp( token, "$fm_referenced" ) ) {
459                         MODELCMD_Referenced( MODEL_FM );
460                 }
461                 else if ( !strcmp( token, "$fm_node_order" ) ) {
462                         MODELCMD_NodeOrder( MODEL_FM );
463                 }
464
465                 //
466                 // sprite commands
467                 //
468                 else if ( !strcmp( token, "$spritename" ) ) {
469                         Cmd_SpriteName();
470                 }
471                 else if ( !strcmp( token, "$sprdir" ) ) {
472                         Cmd_Sprdir();
473                 }
474                 else if ( !strcmp( token, "$load" ) ) {
475                         Cmd_Load();
476                 }
477                 else if ( !strcmp( token, "$spriteframe" ) ) {
478                         Cmd_SpriteFrame();
479                 }
480                 //
481                 // image commands
482                 //
483                 else if ( !strcmpi( token, "$grab" ) ) {
484                         Cmd_Grab();
485                 }
486                 else if ( !strcmpi( token, "$raw" ) ) {
487                         Cmd_Raw();
488                 }
489                 else if ( !strcmpi( token, "$colormap" ) ) {
490                         Cmd_Colormap();
491                 }
492                 else if ( !strcmpi( token, "$mippal" ) ) {
493                         Cmd_Mippal();
494                 }
495                 else if ( !strcmpi( token, "$mipdir" ) ) {
496                         Cmd_Mipdir();
497                 }
498                 else if ( !strcmpi( token, "$mip" ) ) {
499                         Cmd_Mip();
500                 }
501                 else if ( !strcmp( token, "$environment" ) ) {
502                         Cmd_Environment();
503                 }
504                 //
505                 // pics
506                 //
507                 else if ( !strcmp( token, "$picdir" ) ) {
508                         Cmd_Picdir();
509                 }
510                 else if ( !strcmp( token, "$pic" ) ) {
511                         Cmd_Pic();
512                 }
513                 //
514                 // book
515                 //
516                 else if ( !strcmp( token, "$bookdir" ) ) {
517                         Cmd_Bookdir();
518                 }
519                 else if ( !strcmp( token, "$book" ) ) {
520                         Cmd_Book();
521                 }
522                 //
523                 // tmix
524                 //
525                 else if ( !strcmp( token, "$texturemix" ) ) {
526                         Cmd_TextureMix();
527                 }
528                 //
529                 // video
530                 //
531                 else if ( !strcmp( token, "$video" ) ) {
532                         Cmd_Video();
533                 }
534                 //
535                 // misc
536                 //
537                 else if ( !strcmp( token, "$file" ) ) {
538                         Cmd_File();
539                 }
540                 else if ( !strcmp( token, "$dir" ) ) {
541                         Cmd_Dir();
542                 }
543                 else if ( !strcmp( token, "$maps" ) ) {
544                         Cmd_Maps();
545                 }
546                 else if ( !strcmp( token, "$alphalight" ) ) {
547                         Cmd_Alphalight();
548                 }
549                 else if ( !strcmp( token, "$inverse16table" ) ) {
550                         Cmd_Inverse16Table();
551                 }
552                 else{
553                         Error( "bad command %s\n", token );
554                 }
555         }
556 }
557
558 //=======================================================
559
560 /*
561    ==============
562    main
563    ==============
564  */
565 int main( int argc, char **argv ){
566         int i;
567         char path[1024];
568         char        *basedir;
569         double starttime, endtime;
570
571         printf( "Qdata Plus : "__TIME__ " "__DATE__ "\n" );
572
573         starttime = I_FloatTime();
574         basedir = NULL;
575
576         TK_Init();
577         ExpandWildcards( &argc, &argv );
578
579         for ( i = 1 ; i < argc ; i++ )
580         {
581                 if ( !strcmp( argv[i], "-archive" ) ) {
582                         // -archive f:/quake2/release/dump_11_30
583                         archive = true;
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 = true;
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], "-base" ) ) {
595                         i++;
596                         basedir = argv[i];
597                 }
598                 else if ( !strcmp( argv[i], "-compress" ) ) {
599                         g_compress_pak = true;
600                         printf( "Compressing pakfile\n" );
601                 }
602                 else if ( !strcmp( argv[i], "-pak" ) ) {
603                         g_release = true;
604                         g_pak = true;
605                         printf( "Building pakfile: %s\n", argv[i + 1] );
606                         BeginPak( argv[i + 1] );
607                         i++;
608                 }
609                 else if ( !strcmp( argv[i], "-only" ) ) {
610                         strcpy( g_only, argv[i + 1] );
611                         printf( "Only grabbing %s\n", g_only );
612                         i++;
613                 }
614                 else if ( !strcmpi( argv[i], "-keypress" ) ) {
615                         g_dokeypress = true;
616                 }
617                 else if ( !strcmp( argv[i], "-3ds" ) ) {
618                         do3ds = true;
619                         printf( "loading .3ds files\n" );
620                 }
621                 else if ( !strcmp( argv[i], "-materialfile" ) ) {
622                         strcpy( g_materialFile, argv[i + 1] );
623                         printf( "Setting material file to %s\n", g_materialFile );
624                         i++;
625                 }
626 /*              else if (!strcmpi(argv[i], "-newgen"))
627         {
628             if (i < argc-4)
629             {
630                 printf("run new triangle grouping routine here\n");
631                 NewGen(argv[i+1],argv[i+2],atoi(argv[i+3]),atoi(argv[i+4]));
632             }
633             else
634             {
635                 printf("qdata -newskin <base.hrc> <skin.pcx> width height\n");
636             }
637             return 0;
638         }
639  */     else if ( !strcmpi( argv[i], "-genskin" ) ) {
640                         i++;
641                         if ( i < argc - 3 ) {
642                                 GenSkin( argv[i],argv[i + 1],atol( argv[i + 2] ),atol( argv[i + 3] ) );
643                         }
644                         else
645                         {
646                                 printf( "qdata -genskin <base.hrc> <skin.pcx> <desired width> <desired height>\n" );
647                         }
648                         return 0;
649
650                 }
651                 else if ( !strcmpi( argv[i], "-noopts" ) ) {
652                         g_no_opimizations = true;
653                         printf( "not performing optimizations\n" );
654                 }
655                 else if ( !strcmpi( argv[i], "-md2" ) ) {
656                         g_forcemodel = MODEL_MD2;
657                 }
658                 else if ( !strcmpi( argv[i], "-fm" ) ) {
659                         g_forcemodel = MODEL_FM;
660                 }
661                 else if ( !strcmpi( argv[i], "-verbose" ) ) {
662                         g_verbose = true;
663                 }
664                 else if ( !strcmpi( argv[i], "-oldskin" ) ) {
665                         g_allow_newskin = false;
666                 }
667                 else if ( !strcmpi( argv[i], "-ignoreUV" ) ) {
668                         g_ignoreTriUV = true;
669                 }
670                 else if ( !strcmpi( argv[i], "-publish" ) ) {
671                         g_publishOutput = true;
672                 }
673                 else if ( !strcmpi( argv[i], "-nomkdir" ) ) {
674                         g_nomkdir = true;
675                 }
676                 else if ( argv[i][0] == '-' ) {
677                         Error( "Unknown option \"%s\"", argv[i] );
678                 }
679                 else{
680                         break;
681                 }
682         }
683
684         if ( i >= argc ) {
685                 Error( "usage: qdata [-archive <directory>]\n"
686                            "             [-release <directory>]\n"
687                            "             [-base <directory>]\n"
688                            "             [-compress]\n"
689                            "             [-pak <file>]\n"
690                            "             [-only <model>]\n"
691                            "             [-keypress]\n"
692                            "             [-3ds]\n"
693                            "             [-materialfile <file>]\n"
694                            "             [-noopts]\n"
695                            "             [-md2]\n"
696                            "             [-fm]\n"
697                            "             [-verbose]\n"
698                            "             [-ignoreUV]\n"
699                            "             [-oldskin]\n"
700                            "             [-publish]\n"
701                            "             [-nomkdir]\n"
702                            "             file.qdt\n"
703                            "or\n"
704                            "       qdata -genskin <base.hrc> <skin.pcx> <desired width> <desired height>" );
705         }
706
707         if ( do3ds ) {
708                 trifileext = ext_3ds;
709         }
710         else{
711                 trifileext = ext_tri;
712         }
713
714         for ( ; i < argc ; i++ )
715         {
716                 printf( "--------------- %s ---------------\n", argv[i] );
717                 // load the script
718                 strcpy( path, argv[i] );
719                 DefaultExtension( path, ".qdt" );
720                 DefaultExtension( g_materialFile, ".mat" );
721                 SetQdirFromPath( path );
722
723                 printf( "workingdir='%s'\n", gamedir );
724                 if ( basedir ) {
725                         qdir[0] = 0;
726                         g_outputDir = basedir;
727                 }
728
729                 printf( "outputdir='%s'\n", g_outputDir );
730
731                 QFile_ReadMaterialTypes( g_materialFile );
732                 LoadScriptFile( ExpandArg( path ) );
733
734                 //
735                 // parse it
736                 //
737                 ParseScript();
738
739                 // write out the last model
740                 FinishModel();
741                 FMFinishModel();
742                 FinishSprite();
743         }
744
745         if ( total_textures ) {
746                 printf( "\n" );
747                 printf( "Total textures processed: %d\n",total_textures );
748                 printf( "Average size: %d x %d\n",total_x / total_textures, total_y / total_textures );
749         }
750
751         if ( g_pak ) {
752                 FinishPak();
753         }
754
755         endtime = I_FloatTime();
756         printf( "Time elapsed:  %f\n", endtime - starttime );
757
758         if ( g_dokeypress ) {
759                 printf( "Success! ... Hit a key: " );
760                 getchar();
761         }
762
763         return 0;
764 }