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