PageRenderTime 43ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/quake2/qdata_heretic2/qdata.c

https://gitlab.com/illwieckz/netradiant
C | 763 lines | 532 code | 89 blank | 142 comment | 171 complexity | ad934effc1158a7c5f4919c47c2e53d2 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Copyright (C) 1999-2006 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 "qdata.h"
  18. #include "md4.h"
  19. void TK_Init();
  20. qboolean g_compress_pak;
  21. qboolean g_release; // don't grab, copy output data to new tree
  22. qboolean g_pak; // if true, copy to pak instead of release
  23. char g_releasedir[1024]; // c:\quake2\baseq2, etc
  24. qboolean g_archive; // don't grab, copy source data to new tree
  25. qboolean do3ds;
  26. char g_only[256]; // if set, only grab this cd
  27. qboolean g_skipmodel; // set true when a cd is not g_only
  28. int g_forcemodel = MODEL_AUTO;
  29. qboolean g_verbose = false;
  30. qboolean g_allow_newskin = true;
  31. qboolean g_ignoreTriUV = false;
  32. qboolean g_publishOutput = false;
  33. char *ext_3ds = "3ds";
  34. char *ext_tri = "tri";
  35. char *trifileext;
  36. char g_materialFile[256] = "none"; // default for Heretic2
  37. char *g_outputDir;
  38. extern char *g_publishDir;
  39. extern qboolean g_nomkdir;
  40. /*
  41. =======================================================
  42. PAK FILES
  43. =======================================================
  44. */
  45. typedef struct
  46. {
  47. char name[56];
  48. int filepos, filelen;
  49. } packfile_t;
  50. typedef struct
  51. {
  52. char id[4];
  53. int dirofs;
  54. int dirlen;
  55. } packheader_t;
  56. packfile_t pfiles[16384];
  57. FILE *pakfile;
  58. packfile_t *pf;
  59. packheader_t pakheader;
  60. /*
  61. ==============
  62. BeginPak
  63. ==============
  64. */
  65. void BeginPak( char *outname ){
  66. if ( !g_pak ) {
  67. return;
  68. }
  69. pakfile = SafeOpenWrite( outname );
  70. // leave space for header
  71. SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
  72. pf = pfiles;
  73. }
  74. /*
  75. ==============
  76. ReleaseFile
  77. Filename should be gamedir reletive.
  78. Either copies the file to the release dir, or adds it to
  79. the pak file.
  80. ==============
  81. */
  82. void ReleaseFile( char *filename ){
  83. int len;
  84. byte *buf;
  85. char source[1024];
  86. char dest[1024];
  87. if ( !g_release ) {
  88. return;
  89. }
  90. sprintf( source, "%s%s", gamedir, filename );
  91. if ( !g_pak ) { // copy it
  92. sprintf( dest, "%s/%s", g_releasedir, filename );
  93. printf( "copying to %s\n", dest );
  94. QCopyFile( source, dest );
  95. return;
  96. }
  97. // pak it
  98. printf( "paking %s\n", filename );
  99. if ( strlen( filename ) >= sizeof( pf->name ) ) {
  100. Error( "Filename too long for pak: %s", filename );
  101. }
  102. len = LoadFile( source, (void **)&buf );
  103. // segment moved to old.c
  104. strcpy( pf->name, filename );
  105. pf->filepos = LittleLong( ftell( pakfile ) );
  106. pf->filelen = LittleLong( len );
  107. pf++;
  108. SafeWrite( pakfile, buf, len );
  109. free( buf );
  110. }
  111. /*
  112. ==============
  113. FinishPak
  114. ==============
  115. */
  116. void FinishPak( void ){
  117. int dirlen;
  118. int d;
  119. int i;
  120. unsigned checksum;
  121. if ( !g_pak ) {
  122. return;
  123. }
  124. pakheader.id[0] = 'P';
  125. pakheader.id[1] = 'A';
  126. pakheader.id[2] = 'C';
  127. pakheader.id[3] = 'K';
  128. dirlen = (byte *)pf - (byte *)pfiles;
  129. pakheader.dirofs = LittleLong( ftell( pakfile ) );
  130. pakheader.dirlen = LittleLong( dirlen );
  131. checksum = Com_BlockChecksum( (void *)pfiles, dirlen );
  132. SafeWrite( pakfile, pfiles, dirlen );
  133. i = ftell( pakfile );
  134. fseek( pakfile, 0, SEEK_SET );
  135. SafeWrite( pakfile, &pakheader, sizeof( pakheader ) );
  136. fclose( pakfile );
  137. d = pf - pfiles;
  138. printf( "%i files packed in %i bytes\n",d, i );
  139. printf( "checksum: 0x%x\n", checksum );
  140. }
  141. /*
  142. ===============
  143. Cmd_File
  144. This is only used to cause a file to be copied during a release
  145. build (default.cfg, maps, etc)
  146. ===============
  147. */
  148. void Cmd_File( void ){
  149. GetScriptToken( false );
  150. ReleaseFile( token );
  151. }
  152. /*
  153. ===============
  154. PackDirectory_r
  155. ===============
  156. */
  157. #ifdef _WIN32
  158. #include "io.h"
  159. void PackDirectory_r( char *dir ){
  160. struct _finddata_t fileinfo;
  161. int handle;
  162. char dirstring[1024];
  163. char filename[1024];
  164. sprintf( dirstring, "%s%s/*.*", gamedir, dir );
  165. handle = _findfirst( dirstring, &fileinfo );
  166. if ( handle == -1 ) {
  167. return;
  168. }
  169. do
  170. {
  171. sprintf( filename, "%s/%s", dir, fileinfo.name );
  172. if ( fileinfo.attrib & _A_SUBDIR ) { // directory
  173. if ( fileinfo.name[0] != '.' ) { // don't pak . and ..
  174. PackDirectory_r( filename );
  175. }
  176. continue;
  177. }
  178. // copy or pack the file
  179. ReleaseFile( filename );
  180. } while ( _findnext( handle, &fileinfo ) != -1 );
  181. _findclose( handle );
  182. }
  183. #else
  184. #include <sys/types.h>
  185. #ifdef NeXT
  186. #include <sys/dir.h>
  187. #else
  188. #include <dirent.h>
  189. #endif
  190. void PackDirectory_r( char *dir ){
  191. #ifdef NeXT
  192. struct direct **namelist, *ent;
  193. #else
  194. struct dirent **namelist, *ent;
  195. #endif
  196. int count;
  197. struct stat st;
  198. int i;
  199. int len;
  200. char fullname[1024];
  201. char dirstring[1024];
  202. char *name;
  203. sprintf( dirstring, "%s%s", gamedir, dir );
  204. count = scandir( dirstring, &namelist, NULL, NULL );
  205. for ( i = 0 ; i < count ; i++ )
  206. {
  207. ent = namelist[i];
  208. name = ent->d_name;
  209. if ( name[0] == '.' ) {
  210. continue;
  211. }
  212. sprintf( fullname, "%s/%s", dir, name );
  213. sprintf( dirstring, "%s%s/%s", gamedir, dir, name );
  214. if ( stat( dirstring, &st ) == -1 ) {
  215. Error( "fstating %s", pf->name );
  216. }
  217. if ( st.st_mode & S_IFDIR ) { // directory
  218. PackDirectory_r( fullname );
  219. continue;
  220. }
  221. // copy or pack the file
  222. ReleaseFile( fullname );
  223. }
  224. }
  225. #endif
  226. /*
  227. ===============
  228. Cmd_Dir
  229. This is only used to cause a directory to be copied during a
  230. release build (sounds, etc)
  231. ===============
  232. */
  233. void Cmd_Dir( void ){
  234. GetScriptToken( false );
  235. PackDirectory_r( token );
  236. }
  237. //========================================================================
  238. #define MAX_RTEX 16384
  239. int numrtex;
  240. char rtex[MAX_RTEX][64];
  241. void ReleaseTexture( char *name ){
  242. int i;
  243. char path[1024];
  244. for ( i = 0 ; i < numrtex ; i++ )
  245. if ( !Q_strcasecmp( name, rtex[i] ) ) {
  246. return;
  247. }
  248. if ( numrtex == MAX_RTEX ) {
  249. Error( "numrtex == MAX_RTEX" );
  250. }
  251. strcpy( rtex[i], name );
  252. numrtex++;
  253. sprintf( path, "textures/%s.wal", name );
  254. ReleaseFile( path );
  255. }
  256. /*
  257. ===============
  258. Cmd_Maps
  259. Only relevent for release and pak files.
  260. Releases the .bsp files for the maps, and scans all of the files to
  261. build a list of all textures used, which are then released.
  262. ===============
  263. */
  264. void Cmd_Maps( void ){
  265. char map[1024];
  266. int i;
  267. while ( ScriptTokenAvailable() )
  268. {
  269. GetScriptToken( false );
  270. sprintf( map, "maps/%s.bsp", token );
  271. ReleaseFile( map );
  272. if ( !g_release ) {
  273. continue;
  274. }
  275. // get all the texture references
  276. sprintf( map, "%smaps/%s.bsp", gamedir, token );
  277. LoadBSPFileTexinfo( map );
  278. for ( i = 0 ; i < numtexinfo ; i++ )
  279. ReleaseTexture( texinfo[i].texture );
  280. }
  281. }
  282. //==============================================================
  283. /*
  284. ===============
  285. ParseScript
  286. ===============
  287. */
  288. void ParseScript( void ){
  289. while ( 1 )
  290. {
  291. do
  292. { // look for a line starting with a $ command
  293. GetScriptToken( true );
  294. if ( endofscript ) {
  295. return;
  296. }
  297. if ( token[0] == '$' ) {
  298. break;
  299. }
  300. while ( ScriptTokenAvailable() )
  301. GetScriptToken( false );
  302. } while ( 1 );
  303. //
  304. // model commands
  305. //
  306. if ( !strcmp( token, "$modelname" ) ) {
  307. MODELCMD_Modelname( MODEL_MD2 );
  308. }
  309. else if ( !strcmp( token, "$cd" ) ) {
  310. MODELCMD_Cd( MODEL_MD2 );
  311. }
  312. else if ( !strcmp( token, "$origin" ) ) {
  313. MODELCMD_Origin( MODEL_MD2 );
  314. }
  315. else if ( !strcmp( token, "$cluster" ) ) {
  316. MODELCMD_Cluster( MODEL_MD2 );
  317. }
  318. else if ( !strcmp( token, "$base" ) ) {
  319. MODELCMD_Base( MODEL_MD2 );
  320. }
  321. else if ( !strcmp( token, "$scale" ) ) {
  322. MODELCMD_ScaleUp( MODEL_MD2 );
  323. }
  324. else if ( !strcmp( token, "$frame" ) ) {
  325. MODELCMD_Frame( MODEL_MD2 );
  326. }
  327. else if ( !strcmp( token, "$skin" ) ) {
  328. MODELCMD_Skin( MODEL_MD2 );
  329. }
  330. else if ( !strcmp( token, "$skinsize" ) ) {
  331. MODELCMD_Skinsize( MODEL_MD2 );
  332. }
  333. //
  334. // flexible model commands
  335. //
  336. else if ( !strcmp( token, "$fm_modelname" ) ) {
  337. MODELCMD_Modelname( MODEL_FM );
  338. }
  339. else if ( !strcmp( token, "$fm_base" ) ) {
  340. MODELCMD_Base( MODEL_FM );
  341. }
  342. else if ( !strcmp( token, "$fm_basest" ) ) {
  343. MODELCMD_BaseST( MODEL_FM );
  344. }
  345. else if ( !strcmp( token, "$fm_cd" ) ) {
  346. MODELCMD_Cd( MODEL_FM );
  347. }
  348. else if ( !strcmp( token, "$fm_origin" ) ) {
  349. MODELCMD_Origin( MODEL_FM );
  350. }
  351. else if ( !strcmp( token, "$fm_cluster" ) ) {
  352. MODELCMD_Cluster( MODEL_FM );
  353. }
  354. else if ( !strcmp( token, "$fm_skeleton" ) ) {
  355. MODELCMD_Skeleton( MODEL_FM );
  356. }
  357. else if ( !strcmp( token, "$fm_scale" ) ) {
  358. MODELCMD_ScaleUp( MODEL_FM );
  359. }
  360. else if ( !strcmp( token, "$fm_frame" ) ) {
  361. MODELCMD_Frame( MODEL_FM );
  362. }
  363. else if ( !strcmp( token, "$fm_skeletal_frame" ) ) { // left in for compadibility with qdt already using fm_skeletal_frame
  364. MODELCMD_Frame( MODEL_FM );
  365. }
  366. else if ( !strcmp( token, "$fm_skin" ) ) {
  367. MODELCMD_Skin( MODEL_FM );
  368. }
  369. else if ( !strcmp( token, "$fm_skinsize" ) ) {
  370. MODELCMD_Skinsize( MODEL_FM );
  371. }
  372. else if ( !strcmp( token, "$fm_begin_group" ) ) {
  373. MODELCMD_BeginGroup( MODEL_FM );
  374. }
  375. else if ( !strcmp( token, "$fm_end_group" ) ) {
  376. MODELCMD_EndGroup( MODEL_FM );
  377. }
  378. else if ( !strcmp( token, "$fm_referenced" ) ) {
  379. MODELCMD_Referenced( MODEL_FM );
  380. }
  381. else if ( !strcmp( token, "$fm_node_order" ) ) {
  382. MODELCMD_NodeOrder( MODEL_FM );
  383. }
  384. //
  385. // sprite commands
  386. //
  387. else if ( !strcmp( token, "$spritename" ) ) {
  388. Cmd_SpriteName();
  389. }
  390. else if ( !strcmp( token, "$sprdir" ) ) {
  391. Cmd_Sprdir();
  392. }
  393. else if ( !strcmp( token, "$load" ) ) {
  394. Cmd_Load();
  395. }
  396. else if ( !strcmp( token, "$spriteframe" ) ) {
  397. Cmd_SpriteFrame();
  398. }
  399. //
  400. // image commands
  401. //
  402. else if ( !strcmpi( token, "$grab" ) ) {
  403. Cmd_Grab();
  404. }
  405. else if ( !strcmpi( token, "$raw" ) ) {
  406. Cmd_Raw();
  407. }
  408. else if ( !strcmpi( token, "$colormap" ) ) {
  409. Cmd_Colormap();
  410. }
  411. else if ( !strcmpi( token, "$mippal" ) ) {
  412. Cmd_Mippal();
  413. }
  414. else if ( !strcmpi( token, "$mipdir" ) ) {
  415. Cmd_Mipdir();
  416. }
  417. else if ( !strcmpi( token, "$mip" ) ) {
  418. Cmd_Mip();
  419. }
  420. else if ( !strcmp( token, "$environment" ) ) {
  421. Cmd_Environment();
  422. }
  423. //
  424. // pics
  425. //
  426. else if ( !strcmp( token, "$picdir" ) ) {
  427. Cmd_Picdir();
  428. }
  429. else if ( !strcmp( token, "$pic" ) ) {
  430. Cmd_Pic();
  431. }
  432. //
  433. // book
  434. //
  435. else if ( !strcmp( token, "$bookdir" ) ) {
  436. Cmd_Bookdir();
  437. }
  438. else if ( !strcmp( token, "$book" ) ) {
  439. Cmd_Book();
  440. }
  441. //
  442. // tmix
  443. //
  444. else if ( !strcmp( token, "$texturemix" ) ) {
  445. Cmd_TextureMix();
  446. }
  447. //
  448. // video
  449. //
  450. else if ( !strcmp( token, "$video" ) ) {
  451. Cmd_Video();
  452. }
  453. //
  454. // misc
  455. //
  456. else if ( !strcmp( token, "$file" ) ) {
  457. Cmd_File();
  458. }
  459. else if ( !strcmp( token, "$dir" ) ) {
  460. Cmd_Dir();
  461. }
  462. else if ( !strcmp( token, "$maps" ) ) {
  463. Cmd_Maps();
  464. }
  465. else if ( !strcmp( token, "$alphalight" ) ) {
  466. Cmd_Alphalight();
  467. }
  468. else if ( !strcmp( token, "$inverse16table" ) ) {
  469. Cmd_Inverse16Table();
  470. }
  471. else{
  472. Error( "bad command %s\n", token );
  473. }
  474. }
  475. }
  476. //=======================================================
  477. /*
  478. ==============
  479. main
  480. ==============
  481. */
  482. int main( int argc, char **argv ){
  483. int i;
  484. char path[1024];
  485. char *basedir;
  486. double starttime, endtime;
  487. printf( "Qdata Plus : "__TIME__ " "__DATE__ "\n" );
  488. starttime = I_FloatTime();
  489. basedir = NULL;
  490. TK_Init();
  491. ExpandWildcards( &argc, &argv );
  492. for ( i = 1 ; i < argc ; i++ )
  493. {
  494. if ( !strcmp( argv[i], "-archive" ) ) {
  495. // -archive f:/quake2/release/dump_11_30
  496. archive = true;
  497. strcpy( archivedir, argv[i + 1] );
  498. printf( "Archiving source to: %s\n", archivedir );
  499. i++;
  500. }
  501. else if ( !strcmp( argv[i], "-release" ) ) {
  502. g_release = true;
  503. strcpy( g_releasedir, argv[i + 1] );
  504. printf( "Copy output to: %s\n", g_releasedir );
  505. i++;
  506. }
  507. else if ( !strcmp( argv[i], "-base" ) ) {
  508. i++;
  509. basedir = argv[i];
  510. }
  511. else if ( !strcmp( argv[i], "-compress" ) ) {
  512. g_compress_pak = true;
  513. printf( "Compressing pakfile\n" );
  514. }
  515. else if ( !strcmp( argv[i], "-pak" ) ) {
  516. g_release = true;
  517. g_pak = true;
  518. printf( "Building pakfile: %s\n", argv[i + 1] );
  519. BeginPak( argv[i + 1] );
  520. i++;
  521. }
  522. else if ( !strcmp( argv[i], "-only" ) ) {
  523. strcpy( g_only, argv[i + 1] );
  524. printf( "Only grabbing %s\n", g_only );
  525. i++;
  526. }
  527. else if ( !strcmpi( argv[i], "-keypress" ) ) {
  528. g_dokeypress = true;
  529. }
  530. else if ( !strcmp( argv[i], "-3ds" ) ) {
  531. do3ds = true;
  532. printf( "loading .3ds files\n" );
  533. }
  534. else if ( !strcmp( argv[i], "-materialfile" ) ) {
  535. strcpy( g_materialFile, argv[i + 1] );
  536. printf( "Setting material file to %s\n", g_materialFile );
  537. i++;
  538. }
  539. /* else if (!strcmpi(argv[i], "-newgen"))
  540. {
  541. if (i < argc-4)
  542. {
  543. printf("run new triangle grouping routine here\n");
  544. NewGen(argv[i+1],argv[i+2],atoi(argv[i+3]),atoi(argv[i+4]));
  545. }
  546. else
  547. {
  548. printf("qdata -newskin <base.hrc> <skin.pcx> width height\n");
  549. }
  550. return 0;
  551. }
  552. */ else if ( !strcmpi( argv[i], "-genskin" ) ) {
  553. i++;
  554. if ( i < argc - 3 ) {
  555. GenSkin( argv[i],argv[i + 1],atol( argv[i + 2] ),atol( argv[i + 3] ) );
  556. }
  557. else
  558. {
  559. printf( "qdata -genskin <base.hrc> <skin.pcx> <desired width> <desired height>\n" );
  560. }
  561. return 0;
  562. }
  563. else if ( !strcmpi( argv[i], "-noopts" ) ) {
  564. g_no_opimizations = true;
  565. printf( "not performing optimizations\n" );
  566. }
  567. else if ( !strcmpi( argv[i], "-md2" ) ) {
  568. g_forcemodel = MODEL_MD2;
  569. }
  570. else if ( !strcmpi( argv[i], "-fm" ) ) {
  571. g_forcemodel = MODEL_FM;
  572. }
  573. else if ( !strcmpi( argv[i], "-verbose" ) ) {
  574. g_verbose = true;
  575. }
  576. else if ( !strcmpi( argv[i], "-oldskin" ) ) {
  577. g_allow_newskin = false;
  578. }
  579. else if ( !strcmpi( argv[i], "-ignoreUV" ) ) {
  580. g_ignoreTriUV = true;
  581. }
  582. else if ( !strcmpi( argv[i], "-publish" ) ) {
  583. g_publishOutput = true;
  584. }
  585. else if ( !strcmpi( argv[i], "-nomkdir" ) ) {
  586. g_nomkdir = true;
  587. }
  588. else if ( argv[i][0] == '-' ) {
  589. Error( "Unknown option \"%s\"", argv[i] );
  590. }
  591. else{
  592. break;
  593. }
  594. }
  595. if ( i >= argc ) {
  596. Error( "usage: qdata [-archive <directory>]\n"
  597. " [-release <directory>]\n"
  598. " [-base <directory>]\n"
  599. " [-compress]\n"
  600. " [-pak <file>]\n"
  601. " [-only <model>]\n"
  602. " [-keypress]\n"
  603. " [-3ds]\n"
  604. " [-materialfile <file>]\n"
  605. " [-noopts]\n"
  606. " [-md2]\n"
  607. " [-fm]\n"
  608. " [-verbose]\n"
  609. " [-ignoreUV]\n"
  610. " [-oldskin]\n"
  611. " [-publish]\n"
  612. " [-nomkdir]\n"
  613. " file.qdt\n"
  614. "or\n"
  615. " qdata -genskin <base.hrc> <skin.pcx> <desired width> <desired height>" );
  616. }
  617. if ( do3ds ) {
  618. trifileext = ext_3ds;
  619. }
  620. else{
  621. trifileext = ext_tri;
  622. }
  623. for ( ; i < argc ; i++ )
  624. {
  625. printf( "--------------- %s ---------------\n", argv[i] );
  626. // load the script
  627. strcpy( path, argv[i] );
  628. DefaultExtension( path, ".qdt" );
  629. DefaultExtension( g_materialFile, ".mat" );
  630. SetQdirFromPath( path );
  631. printf( "workingdir='%s'\n", gamedir );
  632. if ( basedir ) {
  633. qdir[0] = 0;
  634. g_outputDir = basedir;
  635. }
  636. printf( "outputdir='%s'\n", g_outputDir );
  637. QFile_ReadMaterialTypes( g_materialFile );
  638. LoadScriptFile( ExpandArg( path ) );
  639. //
  640. // parse it
  641. //
  642. ParseScript();
  643. // write out the last model
  644. FinishModel();
  645. FMFinishModel();
  646. FinishSprite();
  647. }
  648. if ( total_textures ) {
  649. printf( "\n" );
  650. printf( "Total textures processed: %d\n",total_textures );
  651. printf( "Average size: %d x %d\n",total_x / total_textures, total_y / total_textures );
  652. }
  653. if ( g_pak ) {
  654. FinishPak();
  655. }
  656. endtime = I_FloatTime();
  657. printf( "Time elapsed: %f\n", endtime - starttime );
  658. if ( g_dokeypress ) {
  659. printf( "Success! ... Hit a key: " );
  660. getchar();
  661. }
  662. return 0;
  663. }