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 */
BeginPak(char * outname)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 */
ReleaseFile(char * filename)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 */
FinishPak(void)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 */
Cmd_File(void)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"
PackDirectory_r(char * dir)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/dirent.h>
252
PackDirectory_r(char * dir)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 */
Cmd_Dir(void)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
ReleaseTexture(char * name)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 */
Cmd_Maps(void)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 */
ParseScript(void)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 */
main(int argc,char ** argv)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
554