initial
[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
25 qboolean        g_compress_pak;
26 qboolean        g_release;                      // don't grab, copy output data to new tree
27 qboolean        g_pak;                          // if true, copy to pak instead of release
28 char            g_releasedir[1024];     // c:\quake2\baseq2, etc
29 qboolean        g_archive;                      // don't grab, copy source data to new tree
30 qboolean        do3ds;
31 char            g_only[256];            // if set, only grab this cd
32 qboolean        g_skipmodel;            // set true when a cd is not g_only
33
34 char            *ext_3ds = "3ds";
35 char            *ext_tri= "tri";
36 char            *trifileext;
37
38 char            game[64] = "quake2";
39
40 void InitPaths( int *argc, char **argv );
41
42 /*
43 =======================================================
44
45   PAK FILES
46
47 =======================================================
48 */
49
50 unsigned Com_BlockChecksum (void *buffer, int length);
51
52 typedef struct
53 {
54         char    name[56];
55         int             filepos, filelen;
56 } packfile_t;
57
58 typedef struct
59 {
60         char    id[4];
61         int             dirofs;
62         int             dirlen;
63 } packheader_t;
64
65 packfile_t              pfiles[16384];
66 FILE                    *pakfile;
67 packfile_t              *pf;
68 packheader_t    pakheader;
69
70
71
72 /*
73 ==============
74 BeginPak
75 ==============
76 */
77 void BeginPak (char *outname)
78 {
79         if (!g_pak)
80                 return;
81
82         pakfile = SafeOpenWrite (outname);
83
84         // leave space for header
85         SafeWrite (pakfile, &pakheader, sizeof(pakheader));
86         
87         pf = pfiles;
88 }
89
90
91 /*
92 ==============
93 ReleaseFile
94
95 Filename should be gamedir reletive.
96 Either copies the file to the release dir, or adds it to
97 the pak file.
98 ==============
99 */
100 void ReleaseFile (char *filename)
101 {
102         int             len;
103         byte    *buf;
104         char    source[1024];
105         char    dest[1024];
106
107         if (!g_release)
108                 return;
109
110         sprintf (source, "%s%s", gamedir, filename);
111
112         if (!g_pak)
113         {       // copy it
114                 sprintf (dest, "%s/%s", g_releasedir, filename);
115                 printf ("copying to %s\n", dest);
116                 QCopyFile (source, dest);
117                 return;
118         }
119
120         // pak it
121         printf ("paking %s\n", filename);
122         if (strlen(filename) >= sizeof(pf->name))
123                 Error ("Filename too long for pak: %s", filename);
124
125         len = LoadFile (source, (void **)&buf);
126
127         if (g_compress_pak && len < 4096*1024 )
128         {
129                 cblock_t        in, out;
130                 cblock_t Huffman (cblock_t in);
131
132                 in.count = len;
133                 in.data = buf;
134
135                 out = Huffman (in);
136
137                 if (out.count < in.count)
138                 {
139                         printf ("   compressed from %i to %i\n", in.count, out.count);
140                         free (in.data);
141                         buf = out.data;
142                         len = out.count;
143                 }
144                 else
145                         free (out.data);
146         }
147
148         strcpy (pf->name, filename);
149         pf->filepos = LittleLong(ftell(pakfile));
150         pf->filelen = LittleLong(len);
151         pf++;
152
153         SafeWrite (pakfile, buf, len);
154
155         free (buf);
156 }
157
158
159 /*
160 ==============
161 FinishPak
162 ==============
163 */
164 void FinishPak (void)
165 {
166         int             dirlen;
167         int             d;
168         int             i;
169         unsigned        checksum;
170
171         if (!g_pak)
172                 return;
173
174         pakheader.id[0] = 'P';
175         pakheader.id[1] = 'A';
176         pakheader.id[2] = 'C';
177         pakheader.id[3] = 'K';
178         dirlen = (byte *)pf - (byte *)pfiles;
179         pakheader.dirofs = LittleLong(ftell(pakfile));
180         pakheader.dirlen = LittleLong(dirlen);
181         
182         checksum = Com_BlockChecksum ( (void *)pfiles, dirlen );
183
184         SafeWrite (pakfile, pfiles, dirlen);
185
186         i = ftell (pakfile);
187          
188         fseek (pakfile, 0, SEEK_SET);
189         SafeWrite (pakfile, &pakheader, sizeof(pakheader));
190         fclose (pakfile);       
191         
192         d = pf - pfiles;
193         printf ("%i files packed in %i bytes\n",d, i);
194         printf ("checksum: 0x%x\n", checksum);
195 }
196
197
198 /*
199 ===============
200 Cmd_File
201
202 This is only used to cause a file to be copied during a release
203 build (default.cfg, maps, etc)
204 ===============
205 */
206 void Cmd_File (void)
207 {
208         GetToken (false);
209         ReleaseFile (token);
210 }
211
212 /*
213 ===============
214 PackDirectory_r
215
216 ===============
217 */
218 #ifdef _WIN32
219 #include "io.h"
220 void PackDirectory_r (char *dir)
221 {
222         struct _finddata_t fileinfo;
223         int             handle;
224         char    dirstring[1024];
225         char    filename[1024];
226
227         sprintf (dirstring, "%s%s/*.*", gamedir, dir);
228
229         handle = _findfirst (dirstring, &fileinfo);
230         if (handle == -1)
231                 return;
232
233         do
234         {
235                 sprintf (filename, "%s/%s", dir, fileinfo.name);
236                 if (fileinfo.attrib & _A_SUBDIR)
237                 {       // directory
238                         if (fileinfo.name[0] != '.')    // don't pak . and ..
239                                 PackDirectory_r (filename);
240                         continue;
241                 }
242                 // copy or pack the file
243                 ReleaseFile (filename);         
244         } while (_findnext( handle, &fileinfo ) != -1);
245
246         _findclose (handle);
247 }
248 #else
249
250 #include <sys/types.h>
251 #include <sys/dir.h>
252
253 void PackDirectory_r (char *dir)
254 {
255 #ifdef NeXT
256         struct direct **namelist, *ent;
257 #else
258         struct dirent **namelist, *ent;
259 #endif
260         int             count;
261         struct stat st;
262         int                     i;
263         int                     len;
264         char            fullname[1024];
265         char            dirstring[1024];
266         char            *name;
267         
268         sprintf (dirstring, "%s%s", gamedir, dir);
269         count = scandir(dirstring, &namelist, NULL, NULL);
270         
271         for (i=0 ; i<count ; i++)
272         {
273                 ent = namelist[i];      
274                 name = ent->d_name;
275
276                 if (name[0] == '.')
277                         continue;
278         
279                 sprintf (fullname, "%s/%s", dir, name);
280                 sprintf (dirstring, "%s%s/%s", gamedir, dir, name);
281                 
282                 if (stat (dirstring, &st) == -1)
283                         Error ("fstating %s", pf->name);
284                 if (st.st_mode & S_IFDIR)
285                 {       // directory
286                         PackDirectory_r (fullname);
287                         continue;
288                 }
289
290                 // copy or pack the file
291                 ReleaseFile (fullname);         
292         }
293 }
294 #endif
295
296
297 /*
298 ===============
299 Cmd_Dir
300
301 This is only used to cause a directory to be copied during a
302 release build (sounds, etc)
303 ===============
304 */
305 void Cmd_Dir (void)
306 {
307         GetToken (false);
308         PackDirectory_r (token);        
309 }
310
311 //========================================================================
312
313 #define MAX_RTEX        16384
314 int             numrtex;
315 char    rtex[MAX_RTEX][64];
316
317 void ReleaseTexture (char *name)
318 {
319         int             i;
320         char    path[1024];
321
322         for (i=0 ; i<numrtex ; i++)
323                 if (!Q_strncasecmp(name, rtex[i], strlen(name)))
324                         return;
325
326         if (numrtex == MAX_RTEX)
327                 Error ("numrtex == MAX_RTEX");
328
329         strcpy (rtex[i], name);
330         numrtex++;
331
332         sprintf (path, "textures/%s.wal", name);
333         ReleaseFile (path);
334 }
335
336 /*
337 ===============
338 Cmd_Maps
339
340 Only relevent for release and pak files.
341 Releases the .bsp files for the maps, and scans all of the files to
342 build a list of all textures used, which are then released.
343 ===============
344 */
345 void Cmd_Maps (void)
346 {
347         char    map[1024];
348         int             i;
349
350         while (TokenAvailable ())
351         {
352                 GetToken (false);
353                 sprintf (map, "maps/%s.bsp", token);
354                 ReleaseFile (map);
355
356                 if (!g_release)
357                         continue;
358
359                 // get all the texture references
360                 sprintf (map, "%smaps/%s.bsp", gamedir, token);
361                 LoadBSPFileTexinfo (map);
362                 for (i=0 ; i<numtexinfo ; i++)
363                         ReleaseTexture (texinfo[i].texture);
364         }
365 }
366
367
368 //==============================================================
369
370 /*
371 ===============
372 ParseScript
373 ===============
374 */
375 void ParseScript (void)
376 {
377         while (1)
378         {
379                 do
380                 {       // look for a line starting with a $ command
381                         GetToken (true);
382                         if (endofscript)
383                                 return;
384                         if (token[0] == '$')
385                                 break;                          
386                         while (TokenAvailable())
387                                 GetToken (false);
388                 } while (1);
389         
390                 //
391                 // model commands
392                 //
393                 if (!strcmp (token, "$modelname"))
394                         Cmd_Modelname ();
395                 else if (!strcmp (token, "$base"))
396                         Cmd_Base ();
397                 else if (!strcmp (token, "$cd"))
398                         Cmd_Cd ();
399                 else if (!strcmp (token, "$origin"))
400                         Cmd_Origin ();
401                 else if (!strcmp (token, "$scale"))
402                         Cmd_ScaleUp ();
403                 else if (!strcmp (token, "$frame"))
404                         Cmd_Frame ();
405                 else if (!strcmp (token, "$skin"))
406                         Cmd_Skin ();
407                 else if (!strcmp (token, "$skinsize"))
408                         Cmd_Skinsize ();
409                 //
410                 // sprite commands
411                 //
412                 else if (!strcmp (token, "$spritename"))
413                         Cmd_SpriteName ();
414                 else if (!strcmp (token, "$load"))
415                         Cmd_Load ();
416                 else if (!strcmp (token, "$spriteframe"))
417                         Cmd_SpriteFrame ();
418                 //
419                 // image commands
420                 //
421                 else if (!strcmp (token, "$grab"))
422                         Cmd_Grab ();
423                 else if (!strcmp (token, "$raw"))
424                         Cmd_Raw ();
425                 else if (!strcmp (token, "$colormap"))
426                         Cmd_Colormap ();
427                 else if (!strcmp (token, "$mippal"))
428                         Cmd_Mippal ();
429                 else if (!strcmp (token, "$mipdir"))
430                         Cmd_Mipdir ();
431                 else if (!strcmp (token, "$mip"))
432                         Cmd_Mip ();
433                 else if (!strcmp (token, "$environment"))
434                         Cmd_Environment ();
435                 //
436                 // video
437                 //
438                 else if (!strcmp (token, "$video"))
439                         Cmd_Video ();
440                 //
441                 // misc
442                 //
443                 else if (!strcmp (token, "$file"))
444                         Cmd_File ();
445                 else if (!strcmp (token, "$dir"))
446                         Cmd_Dir ();
447                 else if (!strcmp (token, "$maps"))
448                         Cmd_Maps ();
449                 else if (!strcmp (token, "$alphalight"))
450                         Cmd_Alphalight ();
451                 else if (!strcmp (token, "$inverse16table" ))
452                         Cmd_Inverse16Table();
453                 else
454                         Error ("bad command %s\n", token);
455         }
456 }
457
458 //=======================================================
459
460 /*
461 ==============
462 main
463 ==============
464 */
465 int main (int argc, char **argv)
466 {
467         static  int             i;              // VC4.2 compiler bug if auto...
468         char    path[1024];
469
470         ExpandWildcards (&argc, &argv);
471
472   InitPaths( &argc, argv );
473
474         for (i=1 ; i<argc ; i++)
475         {
476                 if (!strcmp(argv[i], "-archive"))
477                 {
478                         // -archive f:/quake2/release/dump_11_30
479                         archive = true;
480                         strcpy (archivedir, argv[i+1]);
481                         printf ("Archiving source to: %s\n", archivedir);
482                         i++;
483                 }
484                 else if (!strcmp(argv[i], "-release"))
485                 {
486                         g_release = true;
487                         strcpy (g_releasedir, argv[i+1]);
488                         printf ("Copy output to: %s\n", g_releasedir);
489                         i++;
490                 }
491                 else if (!strcmp(argv[i], "-compress"))
492                 {
493                         g_compress_pak = true;
494                         printf ("Compressing pakfile\n");
495                 }
496                 else if (!strcmp(argv[i], "-pak"))
497                 {
498                         g_release = true;
499                         g_pak = true;
500                         printf ("Building pakfile: %s\n", argv[i+1]);
501                         BeginPak (argv[i+1]);
502                         i++;
503                 }
504                 else if (!strcmp(argv[i], "-only"))
505                 {
506                         strcpy (g_only, argv[i+1]);
507                         printf ("Only grabbing %s\n", g_only);
508                         i++;
509                 }
510                 else if (!strcmp(argv[i], "-3ds"))
511                 {
512                         do3ds = true;
513                         printf ("loading .3ds files\n");
514                 }
515                 else if (argv[i][0] == '-')
516                         Error ("Unknown option \"%s\"", argv[i]);
517                 else
518                         break;
519         }
520
521         if (i >= argc)
522                 Error ("usage: %s [-archive <directory>] [-release <directory>] [-only <model>] [-3ds] file.qgr", argv[ 0 ] );
523
524         if (do3ds)
525                 trifileext = ext_3ds;
526         else
527                 trifileext = ext_tri;
528
529         for ( ; i<argc ; i++)
530         {
531                 printf ("--------------- %s ---------------\n", argv[i]);
532                 // load the script
533                 strcpy (path, argv[i]);
534                 DefaultExtension (path, ".qdt");
535                 SetQdirFromPath (path);
536                 LoadScriptFile (ExpandArg(path));
537                 
538                 //
539                 // parse it
540                 //
541                 ParseScript ();
542
543                 // write out the last model
544                 FinishModel ();
545                 FinishSprite ();
546         }
547
548         if (g_pak)
549                 FinishPak ();
550
551         return 0;
552 }
553