2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
23 #include "globaldefs.h"
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
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;
42 char *ext_3ds = "3ds";
43 char *ext_tri = "tri";
46 char g_materialFile[256] = "none"; // default for Heretic2
48 extern char *g_publishDir;
50 extern qboolean g_nomkdir;
53 =======================================================
57 =======================================================
73 packfile_t pfiles[16384];
76 packheader_t pakheader;
85 void BeginPak( char *outname ){
90 pakfile = SafeOpenWrite( outname );
92 // leave space for header
93 SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
103 Filename should be gamedir reletive.
104 Either copies the file to the release dir, or adds it to
108 void ReleaseFile( char *filename ){
118 sprintf( source, "%s%s", gamedir, filename );
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 );
128 printf( "paking %s\n", filename );
129 if ( strlen( filename ) >= sizeof( pf->name ) ) {
130 Error( "Filename too long for pak: %s", filename );
133 len = LoadFile( source, (void **)&buf );
135 // segment moved to old.c
137 strcpy( pf->name, filename );
138 pf->filepos = LittleLong( ftell( pakfile ) );
139 pf->filelen = LittleLong( len );
142 SafeWrite( pakfile, buf, len );
153 void FinishPak( void ){
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 );
171 checksum = Com_BlockChecksum( (void *)pfiles, dirlen );
173 SafeWrite( pakfile, pfiles, dirlen );
175 i = ftell( pakfile );
177 fseek( pakfile, 0, SEEK_SET );
178 SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
182 printf( "%i files packed in %i bytes\n",d, i );
183 printf( "checksum: 0x%x\n", checksum );
191 This is only used to cause a file to be copied during a release
192 build (default.cfg, maps, etc)
195 void Cmd_File( void ){
196 GetScriptToken( false );
197 ReleaseFile( token );
208 void PackDirectory_r( char *dir ){
209 struct _finddata_t fileinfo;
211 char dirstring[1024];
214 sprintf( dirstring, "%s%s/*.*", gamedir, dir );
216 handle = _findfirst( dirstring, &fileinfo );
217 if ( handle == -1 ) {
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 );
230 // copy or pack the file
231 ReleaseFile( filename );
232 } while ( _findnext( handle, &fileinfo ) != -1 );
234 _findclose( handle );
238 #include <sys/types.h>
245 void PackDirectory_r( char *dir ){
247 struct direct **namelist, *ent;
249 struct dirent **namelist, *ent;
256 char dirstring[1024];
259 sprintf( dirstring, "%s%s", gamedir, dir );
260 count = scandir( dirstring, &namelist, NULL, NULL );
262 for ( i = 0 ; i < count ; i++ )
267 if ( name[0] == '.' ) {
271 sprintf( fullname, "%s/%s", dir, name );
272 sprintf( dirstring, "%s%s/%s", gamedir, dir, name );
274 if ( stat( dirstring, &st ) == -1 ) {
275 Error( "fstating %s", pf->name );
277 if ( st.st_mode & S_IFDIR ) { // directory
278 PackDirectory_r( fullname );
282 // copy or pack the file
283 ReleaseFile( fullname );
293 This is only used to cause a directory to be copied during a
294 release build (sounds, etc)
297 void Cmd_Dir( void ){
298 GetScriptToken( false );
299 PackDirectory_r( token );
302 //========================================================================
304 #define MAX_RTEX 16384
306 char rtex[MAX_RTEX][64];
308 void ReleaseTexture( char *name ){
312 for ( i = 0 ; i < numrtex ; i++ )
313 if ( !Q_strcasecmp( name, rtex[i] ) ) {
317 if ( numrtex == MAX_RTEX ) {
318 Error( "numrtex == MAX_RTEX" );
321 strcpy( rtex[i], name );
324 sprintf( path, "textures/%s.wal", name );
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.
337 void Cmd_Maps( void ){
341 while ( ScriptTokenAvailable() )
343 GetScriptToken( false );
344 sprintf( map, "maps/%s.bsp", token );
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 );
360 //==============================================================
367 void ParseScript( void ){
371 { // look for a line starting with a $ command
372 GetScriptToken( true );
376 if ( token[0] == '$' ) {
379 while ( ScriptTokenAvailable() )
380 GetScriptToken( false );
386 if ( !strcmp( token, "$modelname" ) ) {
387 MODELCMD_Modelname( MODEL_MD2 );
389 else if ( !strcmp( token, "$cd" ) ) {
390 MODELCMD_Cd( MODEL_MD2 );
392 else if ( !strcmp( token, "$origin" ) ) {
393 MODELCMD_Origin( MODEL_MD2 );
395 else if ( !strcmp( token, "$cluster" ) ) {
396 MODELCMD_Cluster( MODEL_MD2 );
398 else if ( !strcmp( token, "$base" ) ) {
399 MODELCMD_Base( MODEL_MD2 );
401 else if ( !strcmp( token, "$scale" ) ) {
402 MODELCMD_ScaleUp( MODEL_MD2 );
404 else if ( !strcmp( token, "$frame" ) ) {
405 MODELCMD_Frame( MODEL_MD2 );
407 else if ( !strcmp( token, "$skin" ) ) {
408 MODELCMD_Skin( MODEL_MD2 );
410 else if ( !strcmp( token, "$skinsize" ) ) {
411 MODELCMD_Skinsize( MODEL_MD2 );
414 // flexible model commands
416 else if ( !strcmp( token, "$fm_modelname" ) ) {
417 MODELCMD_Modelname( MODEL_FM );
419 else if ( !strcmp( token, "$fm_base" ) ) {
420 MODELCMD_Base( MODEL_FM );
422 else if ( !strcmp( token, "$fm_basest" ) ) {
423 MODELCMD_BaseST( MODEL_FM );
425 else if ( !strcmp( token, "$fm_cd" ) ) {
426 MODELCMD_Cd( MODEL_FM );
428 else if ( !strcmp( token, "$fm_origin" ) ) {
429 MODELCMD_Origin( MODEL_FM );
431 else if ( !strcmp( token, "$fm_cluster" ) ) {
432 MODELCMD_Cluster( MODEL_FM );
434 else if ( !strcmp( token, "$fm_skeleton" ) ) {
435 MODELCMD_Skeleton( MODEL_FM );
437 else if ( !strcmp( token, "$fm_scale" ) ) {
438 MODELCMD_ScaleUp( MODEL_FM );
440 else if ( !strcmp( token, "$fm_frame" ) ) {
441 MODELCMD_Frame( MODEL_FM );
443 else if ( !strcmp( token, "$fm_skeletal_frame" ) ) { // left in for compadibility with qdt already using fm_skeletal_frame
444 MODELCMD_Frame( MODEL_FM );
446 else if ( !strcmp( token, "$fm_skin" ) ) {
447 MODELCMD_Skin( MODEL_FM );
449 else if ( !strcmp( token, "$fm_skinsize" ) ) {
450 MODELCMD_Skinsize( MODEL_FM );
452 else if ( !strcmp( token, "$fm_begin_group" ) ) {
453 MODELCMD_BeginGroup( MODEL_FM );
455 else if ( !strcmp( token, "$fm_end_group" ) ) {
456 MODELCMD_EndGroup( MODEL_FM );
458 else if ( !strcmp( token, "$fm_referenced" ) ) {
459 MODELCMD_Referenced( MODEL_FM );
461 else if ( !strcmp( token, "$fm_node_order" ) ) {
462 MODELCMD_NodeOrder( MODEL_FM );
468 else if ( !strcmp( token, "$spritename" ) ) {
471 else if ( !strcmp( token, "$sprdir" ) ) {
474 else if ( !strcmp( token, "$load" ) ) {
477 else if ( !strcmp( token, "$spriteframe" ) ) {
483 else if ( !strcmpi( token, "$grab" ) ) {
486 else if ( !strcmpi( token, "$raw" ) ) {
489 else if ( !strcmpi( token, "$colormap" ) ) {
492 else if ( !strcmpi( token, "$mippal" ) ) {
495 else if ( !strcmpi( token, "$mipdir" ) ) {
498 else if ( !strcmpi( token, "$mip" ) ) {
501 else if ( !strcmp( token, "$environment" ) ) {
507 else if ( !strcmp( token, "$picdir" ) ) {
510 else if ( !strcmp( token, "$pic" ) ) {
516 else if ( !strcmp( token, "$bookdir" ) ) {
519 else if ( !strcmp( token, "$book" ) ) {
525 else if ( !strcmp( token, "$texturemix" ) ) {
531 else if ( !strcmp( token, "$video" ) ) {
537 else if ( !strcmp( token, "$file" ) ) {
540 else if ( !strcmp( token, "$dir" ) ) {
543 else if ( !strcmp( token, "$maps" ) ) {
546 else if ( !strcmp( token, "$alphalight" ) ) {
549 else if ( !strcmp( token, "$inverse16table" ) ) {
550 Cmd_Inverse16Table();
553 Error( "bad command %s\n", token );
558 //=======================================================
565 int main( int argc, char **argv ){
569 double starttime, endtime;
571 printf( "Qdata Plus : "__TIME__ " "__DATE__ "\n" );
573 starttime = I_FloatTime();
577 ExpandWildcards( &argc, &argv );
579 for ( i = 1 ; i < argc ; i++ )
581 if ( !strcmp( argv[i], "-archive" ) ) {
582 // -archive f:/quake2/release/dump_11_30
584 strcpy( archivedir, argv[i + 1] );
585 printf( "Archiving source to: %s\n", archivedir );
588 else if ( !strcmp( argv[i], "-release" ) ) {
590 strcpy( g_releasedir, argv[i + 1] );
591 printf( "Copy output to: %s\n", g_releasedir );
594 else if ( !strcmp( argv[i], "-base" ) ) {
598 else if ( !strcmp( argv[i], "-compress" ) ) {
599 g_compress_pak = true;
600 printf( "Compressing pakfile\n" );
602 else if ( !strcmp( argv[i], "-pak" ) ) {
605 printf( "Building pakfile: %s\n", argv[i + 1] );
606 BeginPak( argv[i + 1] );
609 else if ( !strcmp( argv[i], "-only" ) ) {
610 strcpy( g_only, argv[i + 1] );
611 printf( "Only grabbing %s\n", g_only );
614 else if ( !strcmpi( argv[i], "-keypress" ) ) {
617 else if ( !strcmp( argv[i], "-3ds" ) ) {
619 printf( "loading .3ds files\n" );
621 else if ( !strcmp( argv[i], "-materialfile" ) ) {
622 strcpy( g_materialFile, argv[i + 1] );
623 printf( "Setting material file to %s\n", g_materialFile );
626 /* else if (!strcmpi(argv[i], "-newgen"))
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]));
635 printf("h2data -newskin <base.hrc> <skin.pcx> width height\n");
639 */ else if ( !strcmpi( argv[i], "-genskin" ) ) {
641 if ( i < argc - 3 ) {
642 GenSkin( argv[i],argv[i + 1],atol( argv[i + 2] ),atol( argv[i + 3] ) );
646 printf( "h2data -genskin <base.hrc> <skin.pcx> <desired width> <desired height>\n" );
651 else if ( !strcmpi( argv[i], "-noopts" ) ) {
652 g_no_opimizations = true;
653 printf( "not performing optimizations\n" );
655 else if ( !strcmpi( argv[i], "-md2" ) ) {
656 g_forcemodel = MODEL_MD2;
658 else if ( !strcmpi( argv[i], "-fm" ) ) {
659 g_forcemodel = MODEL_FM;
661 else if ( !strcmpi( argv[i], "-verbose" ) ) {
664 else if ( !strcmpi( argv[i], "-oldskin" ) ) {
665 g_allow_newskin = false;
667 else if ( !strcmpi( argv[i], "-ignoreUV" ) ) {
668 g_ignoreTriUV = true;
670 else if ( !strcmpi( argv[i], "-publish" ) ) {
671 g_publishOutput = true;
673 else if ( !strcmpi( argv[i], "-nomkdir" ) ) {
676 else if ( argv[i][0] == '-' ) {
677 Error( "Unknown option \"%s\"", argv[i] );
685 Error( "usage: h2data [-archive <directory>]\n"
686 " [-release <directory>]\n"
687 " [-base <directory>]\n"
693 " [-materialfile <file>]\n"
704 " h2data -genskin <base.hrc> <skin.pcx> <desired width> <desired height>" );
708 trifileext = ext_3ds;
711 trifileext = ext_tri;
714 for ( ; i < argc ; i++ )
716 printf( "--------------- %s ---------------\n", argv[i] );
718 strcpy( path, argv[i] );
719 DefaultExtension( path, ".qdt" );
720 DefaultExtension( g_materialFile, ".mat" );
721 SetQdirFromPath( path );
723 printf( "workingdir='%s'\n", gamedir );
726 g_outputDir = basedir;
729 printf( "outputdir='%s'\n", g_outputDir );
731 QFile_ReadMaterialTypes( g_materialFile );
732 LoadScriptFile( ExpandArg( path ) );
739 // write out the last model
745 if ( total_textures ) {
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 );
755 endtime = I_FloatTime();
756 printf( "Time elapsed: %f\n", endtime - starttime );
758 if ( g_dokeypress ) {
759 printf( "Success! ... Hit a key: " );