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