PageRenderTime 1342ms CodeModel.GetById 22ms RepoModel.GetById 5ms app.codeStats 0ms

/tools/quake3/q3data/q3data.c

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