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