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