]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3data/q3data.c
05ff92208cb4400a7c50fc0d8021e4fdfb02125f
[xonotic/netradiant.git] / tools / quake3 / q3data / q3data.c
1 #ifdef _WIN32\r
2 #include <io.h>\r
3 #endif\r
4 #include "q3data.h"\r
5 #include "md3lib.h"\r
6 \r
7 #include "vfs.h"\r
8 \r
9 qboolean        g_verbose;\r
10 qboolean        g_stripify = qtrue;\r
11 qboolean        g_release;                      // don't grab, copy output data to new tree\r
12 char            g_releasedir[1024];     // c:\quake2\baseq2, etc\r
13 qboolean        g_archive;                      // don't grab, copy source data to new tree\r
14 char            g_only[256];            // if set, only grab this cd\r
15 qboolean        g_skipmodel;            // set true when a cd is not g_only\r
16 \r
17 // bogus externs for some TA hacks (common/ using them against q3map)\r
18 char *moddir = NULL;\r
19 // some old defined that was in cmdlib lost during merge\r
20 char writedir[1024];\r
21 \r
22 #if defined (__linux__) || defined (__APPLE__)\r
23 #define strlwr strlower\r
24 #endif\r
25 \r
26 /*\r
27 =======================================================\r
28 \r
29   PAK FILES\r
30 \r
31 =======================================================\r
32 */\r
33 \r
34 typedef struct\r
35 {\r
36         char    name[56];\r
37         int             filepos, filelen;\r
38 } packfile_t;\r
39 \r
40 typedef struct\r
41 {\r
42         char    id[4];\r
43         int             dirofs;\r
44         int             dirlen;\r
45 } packheader_t;\r
46 \r
47 packfile_t              pfiles[16384];\r
48 FILE                    *pakfile;\r
49 packfile_t              *pf;\r
50 packheader_t    pakheader;\r
51 \r
52 /*\r
53 ==============\r
54 ReleaseFile\r
55 \r
56 Filename should be gamedir reletive.\r
57 Either copies the file to the release dir, or adds it to\r
58 the pak file.\r
59 ==============\r
60 */\r
61 void ReleaseFile (char *filename)\r
62 {\r
63         char    source[1024];\r
64         char    dest[1024];\r
65 \r
66         if (!g_release)\r
67                 return;\r
68 \r
69         sprintf (source, "%s%s", gamedir, filename);\r
70         sprintf (dest, "%s/%s", g_releasedir, filename);\r
71         printf ("copying to %s\n", dest);\r
72   QCopyFile (source, dest);\r
73   return;\r
74 }\r
75 \r
76 typedef struct\r
77 {\r
78         // shader\r
79         // opaque\r
80         // opaque 2\r
81         // blend \r
82         // blend 2\r
83         char names[5][1024];\r
84         int      num;\r
85 } ShaderFiles_t;\r
86 \r
87 ShaderFiles_t s_shaderFiles;\r
88 \r
89 void FindShaderFiles( char *filename )\r
90 {\r
91         char buffer[1024];\r
92         char stripped[1024];\r
93         char linebuffer[1024];\r
94         int len, i;\r
95         char *buf;\r
96         char *diffuseExtensions[] =\r
97         {\r
98                 ".TGA",\r
99                 ".WAL",\r
100                 ".PCX",\r
101                 0\r
102         };\r
103         char *otherExtensions[] =\r
104         {\r
105                 ".specular.TGA",\r
106                 ".blend.TGA",\r
107                 ".alpha.TGA",\r
108                 0\r
109         };\r
110 \r
111         s_shaderFiles.num = 0;\r
112 \r
113         strcpy( stripped, filename );\r
114         if ( strrchr( stripped, '.' ) )\r
115                 *strrchr( stripped, '.' ) = 0;\r
116         strcat( stripped, ".shader" );\r
117 \r
118         if ( FileExists( stripped ) )\r
119         {\r
120                 char *p;\r
121                 char mapa[512], mapb[512];\r
122 \r
123                 strcpy( s_shaderFiles.names[s_shaderFiles.num], stripped );\r
124                 s_shaderFiles.num++;\r
125 \r
126                 // load and parse\r
127                 len = LoadFile( stripped, (void **)&buf);\r
128 \r
129                 p = buf;\r
130 \r
131                 while ( p - buf < len )\r
132                 {\r
133                         i = 0;\r
134 \r
135                         // skip spaces\r
136                         while ( *p == ' ' || *p == '\n' || *p == '\t' )\r
137                                 p++;\r
138 \r
139                         // grab rest of the line\r
140                         while ( *p != 0 && *p != '\n' )\r
141                         {\r
142                                 linebuffer[i] = *p;\r
143                                 i++;\r
144                                 p++;\r
145                         }\r
146                         if ( *p == '\n' )\r
147                                 p++;\r
148                         linebuffer[i] = 0;\r
149 \r
150                         strlwr( linebuffer );\r
151 \r
152                         // see if the line specifies an opaque map or blendmap\r
153                         if ( strstr( linebuffer, "opaquemap" ) == linebuffer ||\r
154                                  strstr( linebuffer, "blendmap" ) == linebuffer )\r
155                         {\r
156                                 int j;\r
157 \r
158                                 i = 0;\r
159 \r
160                                 mapa[0] = mapb[0] = 0;\r
161 \r
162                                 // skip past the keyword\r
163                                 while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )\r
164                                         i++;\r
165                                 // skip past spaces\r
166                                 while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] )\r
167                                         i++;\r
168 \r
169                                 // grab first map name\r
170                                 j = 0;\r
171                                 while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )\r
172                                 {\r
173                                         mapa[j] = linebuffer[i];\r
174                                         j++;\r
175                                         i++;\r
176                                 }\r
177                                 mapa[j] = 0;\r
178 \r
179                                 // skip past spaces\r
180                                 while ( ( linebuffer[i] == ' ' || linebuffer[i] == '\t' ) && linebuffer[i] )\r
181                                         i++;\r
182 \r
183                                 // grab second map name\r
184                                 j = 0;\r
185                                 while ( linebuffer[i] != ' ' && linebuffer[i] != '\t' && linebuffer[i] )\r
186                                 {\r
187                                         mapb[j] = linebuffer[i];\r
188                                         j++;\r
189                                         i++;\r
190                                 }\r
191                                 mapb[j] = 0;\r
192 \r
193                                 // store map names\r
194                                 if ( mapa[0] != 0 && mapa[0] != '-' )\r
195                                 {\r
196                                         sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapa );\r
197                                         s_shaderFiles.num++;\r
198                                 }\r
199                                 if ( mapb[0] != 0 && mapb[0] != '-' && mapb[0] != '^' && mapb[0] != '*' )\r
200                                 {\r
201                                         sprintf( s_shaderFiles.names[s_shaderFiles.num], "%s%s", gamedir, mapb );\r
202                                         s_shaderFiles.num++;\r
203                                 }\r
204                         }\r
205                 }\r
206         }\r
207         else\r
208         {\r
209                 if ( strrchr( stripped, '.' ) )\r
210                         *strrchr( stripped, '.' ) = 0;\r
211 \r
212                 // look for diffuse maps\r
213                 for ( i = 0; i < 3; i++ )\r
214                 {\r
215                         strcpy( buffer, stripped );\r
216                         strcat( buffer, diffuseExtensions[i] );\r
217                         if ( FileExists( buffer ) )\r
218                         {\r
219                                 strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer );\r
220                                 s_shaderFiles.num++;\r
221                                 break;\r
222                         }\r
223                 }\r
224                 for ( i = 0; i < 3; i++ )\r
225                 {\r
226                         strcpy( buffer, stripped );\r
227                         strcat( buffer, otherExtensions[i] );\r
228                         if ( FileExists( buffer ) )\r
229                         {\r
230                                 strcpy( s_shaderFiles.names[s_shaderFiles.num], buffer );\r
231                                 s_shaderFiles.num++;\r
232                         }\r
233                 }\r
234         }\r
235 }\r
236 \r
237 /*\r
238 ==============\r
239 ReleaseShader\r
240 \r
241 Copies all needed files for a shader to the release directory\r
242 ==============\r
243 */\r
244 void ReleaseShader( char *filename ) \r
245 {\r
246         char fullpath[1024];\r
247         char dest[1024];\r
248         char stripped[1024];\r
249         int i;\r
250 \r
251         sprintf( fullpath, "%s%s", gamedir, filename );\r
252 \r
253         FindShaderFiles( fullpath );\r
254 \r
255         for ( i = 0; i < s_shaderFiles.num; i++ )\r
256         {\r
257                 strcpy( stripped, s_shaderFiles.names[i] );\r
258                 if ( strstr( stripped, gamedir ) )\r
259                 {\r
260                         memmove( stripped, stripped+ strlen( gamedir ), strlen( stripped ) );\r
261                 }\r
262                 sprintf( dest, "%s/%s", g_releasedir, stripped );\r
263                 printf ("copying to %s\n", dest );\r
264                 QCopyFile( s_shaderFiles.names[i], dest );\r
265   }\r
266 }\r
267 \r
268 /*\r
269 ===============\r
270 Cmd_File\r
271 \r
272 This is only used to cause a file to be copied during a release\r
273 build (default.cfg, maps, etc)\r
274 ===============\r
275 */\r
276 void Cmd_File (void)\r
277 {\r
278         GetToken (qfalse);\r
279         ReleaseFile (token);\r
280 }\r
281 \r
282 /*\r
283 ===============\r
284 PackDirectory_r\r
285 \r
286 ===============\r
287 */\r
288 #ifdef _WIN32\r
289 #include "io.h"\r
290 void PackDirectory_r (char *dir)\r
291 {\r
292         struct _finddata_t fileinfo;\r
293         int             handle;\r
294         char    dirstring[1024];\r
295         char    filename[1024];\r
296 \r
297         sprintf (dirstring, "%s%s/*.*", gamedir, dir);\r
298 \r
299         handle = _findfirst (dirstring, &fileinfo);\r
300         if (handle == -1)\r
301                 return;\r
302 \r
303         do\r
304         {\r
305                 sprintf (filename, "%s/%s", dir, fileinfo.name);\r
306                 if (fileinfo.attrib & _A_SUBDIR)\r
307                 {       // directory\r
308                         if (fileinfo.name[0] != '.')    // don't pak . and ..\r
309                                 PackDirectory_r (filename);\r
310                         continue;\r
311                 }\r
312                 // copy or pack the file\r
313                 ReleaseFile (filename);         \r
314         } while (_findnext( handle, &fileinfo ) != -1);\r
315 \r
316         _findclose (handle);\r
317 }\r
318 #else\r
319 \r
320 #include <sys/types.h>\r
321 #ifndef WIN32\r
322 #include <sys/dir.h>\r
323 #else\r
324 #include <sys/dirent.h>\r
325 #endif\r
326 \r
327 void PackDirectory_r (char *dir)\r
328 {\r
329 #ifdef NeXT\r
330         struct direct **namelist, *ent;\r
331 #else\r
332         struct dirent **namelist, *ent;\r
333 #endif\r
334         int             count;\r
335         struct stat st;\r
336         int                     i;\r
337         int                     len;\r
338         char            fullname[1024];\r
339         char            dirstring[1024];\r
340         char            *name;\r
341         \r
342         sprintf (dirstring, "%s%s", gamedir, dir);\r
343         count = scandir(dirstring, &namelist, NULL, NULL);\r
344         \r
345         for (i=0 ; i<count ; i++)\r
346         {\r
347                 ent = namelist[i];      \r
348                 name = ent->d_name;\r
349 \r
350                 if (name[0] == '.')\r
351                         continue;\r
352         \r
353                 sprintf (fullname, "%s/%s", dir, name);\r
354                 sprintf (dirstring, "%s%s/%s", gamedir, dir, name);\r
355                 \r
356                 if (stat (dirstring, &st) == -1)\r
357                         Error ("fstating %s", pf->name);\r
358                 if (st.st_mode & S_IFDIR)\r
359                 {       // directory\r
360                         PackDirectory_r (fullname);\r
361                         continue;\r
362                 }\r
363 \r
364                 // copy or pack the file\r
365                 ReleaseFile (fullname);         \r
366         }\r
367 }\r
368 #endif\r
369 \r
370 \r
371 /*\r
372 ===============\r
373 Cmd_Dir\r
374 \r
375 This is only used to cause a directory to be copied during a\r
376 release build (sounds, etc)\r
377 ===============\r
378 */\r
379 void Cmd_Dir (void)\r
380 {\r
381         GetToken (qfalse);\r
382         PackDirectory_r (token);        \r
383 }\r
384 \r
385 //========================================================================\r
386 \r
387 #define MAX_RTEX        16384\r
388 int             numrtex;\r
389 char    rtex[MAX_RTEX][64];\r
390 \r
391 void ReleaseTexture (char *name)\r
392 {\r
393         int             i;\r
394         char    path[1024];\r
395 \r
396         for (i=0 ; i<numrtex ; i++)\r
397                 if (!Q_stricmp(name, rtex[i]))\r
398                         return;\r
399 \r
400         if (numrtex == MAX_RTEX)\r
401                 Error ("numrtex == MAX_RTEX");\r
402 \r
403         strcpy (rtex[i], name);\r
404         numrtex++;\r
405 \r
406         sprintf (path, "textures/%s.wal", name);\r
407         ReleaseFile (path);\r
408 }\r
409 \r
410 /*\r
411 ===============\r
412 Cmd_Maps\r
413 \r
414 Only relevent for release and pak files.\r
415 Releases the .bsp files for the maps, and scans all of the files to\r
416 build a list of all textures used, which are then released.\r
417 ===============\r
418 */\r
419 void Cmd_Maps (void)\r
420 {\r
421         char    map[1024];\r
422 \r
423         while (TokenAvailable ())\r
424         {\r
425                 GetToken (qfalse);\r
426                 sprintf (map, "maps/%s.bsp", token);\r
427                 ReleaseFile (map);\r
428 \r
429                 if (!g_release)\r
430                         continue;\r
431 \r
432                 // get all the texture references\r
433                 sprintf (map, "%smaps/%s.bsp", gamedir, token);\r
434                 LoadBSPFile( map );\r
435         }\r
436 }\r
437 \r
438 \r
439 //==============================================================\r
440 \r
441 /*\r
442 ===============\r
443 ParseScript\r
444 ===============\r
445 */\r
446 void ParseScript (void)\r
447 {\r
448         while (1)\r
449         {\r
450                 do\r
451                 {       // look for a line starting with a $ command\r
452                         GetToken (qtrue);\r
453                         if (endofscript)\r
454                                 return;\r
455                         if (token[0] == '$')\r
456                                 break;                          \r
457                         while (TokenAvailable())\r
458                                 GetToken (qfalse);\r
459                 } while (1);\r
460         \r
461                 //\r
462                 // model commands\r
463                 //\r
464                 if (!strcmp (token, "$modelname"))\r
465                         Cmd_Modelname ();\r
466                 else if (!strcmp (token, "$base"))\r
467                         Cmd_Base ();\r
468                 else if ( !strcmp( token, "$exit" ) )\r
469                         break;\r
470                 else if ( !strcmp( token, "$3dsconvert" ) )\r
471                         Cmd_3DSConvert();\r
472                 else if (!strcmp (token, "$spritebase"))\r
473                         Cmd_SpriteBase ();\r
474                 else if (!strcmp (token, "$cd"))\r
475                         Cmd_Cd ();\r
476                 else if (!strcmp (token, "$origin"))\r
477                         Cmd_Origin ();\r
478                 else if (!strcmp (token, "$scale"))\r
479                         Cmd_ScaleUp ();\r
480                 else if (!strcmp (token, "$frame"))\r
481                         Cmd_Frame ();\r
482                 else if (!strcmp (token, "$skin" ))\r
483                         Cmd_Skin();\r
484                 else if (!strcmp (token, "$spriteshader"))\r
485                         Cmd_SpriteShader();\r
486                 else if (!strcmp( token, "$aseconvert" ))\r
487                         Cmd_ASEConvert( qfalse );\r
488                 else if (!strcmp( token, "$aseanimconvert" ) )\r
489                         Cmd_ASEConvert( qtrue );\r
490 \r
491                 //\r
492                 // image commands\r
493                 //\r
494                 else if (!strcmp (token, "$grab"))\r
495                         Cmd_Grab ();\r
496                 else if (!strcmp (token, "$raw"))\r
497                         Cmd_Raw ();\r
498                 else if (!strcmp (token, "$colormap"))\r
499                         Cmd_Colormap ();\r
500                 else if (!strcmp (token, "$environment"))\r
501                         Cmd_Environment ();\r
502 \r
503                 //\r
504                 // video\r
505                 //\r
506                 else if (!strcmp (token, "$video"))\r
507                         Cmd_Video ();\r
508                 //\r
509                 // misc\r
510                 //\r
511                 else if (!strcmp (token, "$file"))\r
512                         Cmd_File ();\r
513                 else if (!strcmp (token, "$dir"))\r
514                         Cmd_Dir ();\r
515                 else if (!strcmp (token, "$maps"))\r
516                         Cmd_Maps ();\r
517                 else\r
518                         Error ("bad command %s\n", token);\r
519         }\r
520 }\r
521 \r
522 //=======================================================\r
523 \r
524 #include "version.h"\r
525 \r
526 /*\r
527 ==============\r
528 main\r
529 ==============\r
530 */\r
531 int main (int argc, char **argv)\r
532 {\r
533         static  int             i;              // VC4.2 compiler bug if auto...\r
534         char    path[1024];\r
535 \r
536   // using GtkRadiant's versioning next to Id's versioning\r
537   printf ("Q3Data      - (c) 1999 Id Software Inc.\n");\r
538   printf ("GtkRadiant  - v" RADIANT_VERSION " " __DATE__ "\n");\r
539 \r
540         ExpandWildcards (&argc, &argv);\r
541 \r
542         for (i=1 ; i<argc ; i++)\r
543         {\r
544                 if (!strcmp(argv[i], "-archive"))\r
545                 {\r
546                         archive = qtrue;\r
547                         strcpy (archivedir, argv[i+1]);\r
548                         printf ("Archiving source to: %s\n", archivedir);\r
549                         i++;\r
550                 }\r
551                 else if (!strcmp(argv[i], "-release"))\r
552                 {\r
553                         g_release = qtrue;\r
554                         strcpy (g_releasedir, argv[i+1]);\r
555                         printf ("Copy output to: %s\n", g_releasedir);\r
556                         i++;\r
557                 }\r
558                 else if ( !strcmp( argv[i], "-nostrips" ) )\r
559                 {\r
560                         g_stripify = qfalse;\r
561                         printf( "Not optimizing for strips\n" );\r
562                 }\r
563                 else if ( !strcmp( argv[i], "-writedir" ) )\r
564                 {\r
565                         strcpy( writedir, argv[i+1] );\r
566                         printf( "Write output to: %s\n", writedir );\r
567                         i++;\r
568                 }\r
569                 else if ( !strcmp( argv[i], "-verbose" ) )\r
570                 {\r
571                         g_verbose = qtrue;\r
572                 }\r
573                 else if ( !strcmp( argv[i], "-dump" ) )\r
574                 {\r
575                         printf( "Dumping contents of: '%s'\n", argv[i+1] );\r
576                         if ( strstr( argv[i+1], ".md3" ) )\r
577                         {\r
578                                 MD3_Dump( argv[i+1] );\r
579                         }\r
580                         else\r
581                         {\r
582                                 Error( "Do not know how to dump the contents of '%s'\n", argv[i+1] );\r
583                         }\r
584                         i++;\r
585                 }\r
586                 else if ( !strcmp( argv[i], "-3dsconvert" ) )\r
587                 {\r
588       // NOTE TTimo this is broken, tried on a sample .3ds\r
589       // what happens .. it calls the Convert3DStoMD3,\r
590       // which calls the scriptlib function in non initialized state .. and crashes\r
591                         printf( "Converting %s.3DS to %s.MD3\n", argv[i+1], argv[i+1] );\r
592                         SetQdirFromPath( argv[i+1] );\r
593       vfsInitDirectory( gamedir );\r
594                         Convert3DStoMD3( argv[i+1] );\r
595                         i++;\r
596                 }\r
597                 else if (!strcmp(argv[i], "-only"))\r
598                 {\r
599                         strcpy (g_only, argv[i+1]);\r
600                         printf ("Only grabbing %s\n", g_only);\r
601                         i++;\r
602                 }\r
603                 else if (!strcmp(argv[i], "-gamedir"))\r
604                 {\r
605                         strcpy(gamedir, argv[i+1]);\r
606                         i++;\r
607                 }\r
608                 else if (argv[i][0] == '-')\r
609                         Error ("Unknown option \"%s\"", argv[i]);\r
610                 else\r
611                         break;\r
612         }\r
613 \r
614         if (i == argc)\r
615                 Error ("usage: q3data [-archive <directory>] [-dump <file.md3>] [-release <directory>] [-only <model>] [-3dsconvert <file.3ds>] [-verbose] [file.qdt]");\r
616 \r
617         for ( ; i<argc ; i++)\r
618         {\r
619                 printf ("--------------- %s ---------------\n", argv[i]);\r
620                 // load the script\r
621                 strcpy (path, argv[i]);\r
622                 DefaultExtension (path, ".qdt");\r
623                 if(!gamedir[0])\r
624                         SetQdirFromPath (path);\r
625     // NOTE TTimo\r
626     // q3data went through a partial conversion to use the vfs\r
627     // it was never actually tested before 1.1.1\r
628     // the code is still mostly using direct file access calls\r
629     vfsInitDirectory( gamedir );\r
630                 LoadScriptFile (ExpandArg(path), -1);\r
631                 \r
632                 //\r
633                 // parse it\r
634                 //\r
635                 ParseScript ();\r
636 \r
637                 // write out the last model\r
638                 FinishModel ( TYPE_UNKNOWN );\r
639         }\r
640 \r
641         return 0;\r
642 }\r
643 \r