Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TombRaider.cpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: t; c-basic-offset: 3 -*- */
  2. /*================================================================
  3. *
  4. * Project : OpenRaider
  5. * Author : Mongoose
  6. * Website : http://www.westga.edu/~stu7440/
  7. * Email : stu7440@westga.edu
  8. * Object : OpenRaider
  9. * License : No use w/o permission (C) 2001 Mongoose
  10. * Comments: Loads TR 1, 2, 3, and 4 maps, meshes, and textures
  11. *
  12. * This file was generated using Mongoose's C++
  13. * template generator script. <stu7440@westga.edu>
  14. *
  15. *-- History ------------------------------------------------
  16. *
  17. * 2003.05.13:
  18. * Mongoose - New API, maintance cost was becoming so high
  19. * it was needed to sort out methods in groups
  20. * like my newer source code -- of course some
  21. * methods were altered or removed ( clean up )
  22. *
  23. * 2001.06.19:
  24. * Mongoose - New texture API for the new TR4/TR5 bump map
  25. * support, also purged textile exposure
  26. *
  27. * 2001.05.21:
  28. * Mongoose - Added to project OpenRaider, more documentation
  29. * than Freyja version I wrote ( 3d modeler )
  30. *
  31. *
  32. * 2000-05-13:
  33. * Mongoose - Added gcc and VC++ pragmas for packing
  34. *
  35. * id style typedefs for structs
  36. *
  37. * Heavy clean up and ported to C++
  38. *
  39. * I saved yuri's notes as best I could and
  40. * reformatted and corected as needed
  41. *
  42. * Mongoose - Created, based on:
  43. * tr_view's tr2io.c by Yuri Zhivago, PhD,
  44. * TR Rosetta Stone ( TombRaider pak format specs )
  45. ================================================================*/
  46. #include <stdlib.h>
  47. #include <stdio.h>
  48. #include <math.h>
  49. #include <string.h>
  50. #include <stdarg.h>
  51. #include <TombRaider.h>
  52. #ifdef __TEST_TR5_DUMP_TGA
  53. #include <TGA.h>
  54. #endif
  55. #ifdef DEBUG_MEMORY
  56. #include <memory_test.h>
  57. #endif
  58. void dump_textures(TombRaider *tr, char *mapname)
  59. {
  60. #ifdef __TEST_TR5_DUMP_TGA
  61. int i;
  62. unsigned char *image;
  63. unsigned char *bumpmap;
  64. char buffer[128];
  65. FILE *f;
  66. if (!tr || !mapname)
  67. return;
  68. // Dump textures
  69. printf("\n\t[Texture dumping for '%s']\n", mapname);
  70. for (i = 0; i < tr->NumTextures(); i++)
  71. {
  72. tr->Texture(i, &image, &bumpmap);
  73. if (image)
  74. {
  75. snprintf(buffer, 128, "%s-%03i-texture.tga", mapname, i);
  76. f = fopen(buffer, "wb");
  77. if (f)
  78. {
  79. if (!mtk_image__tga_save(f, image, 256, 256, 4))
  80. printf("\tWrote texture %s\n", buffer);
  81. fclose(f);
  82. }
  83. snprintf(buffer, 128, "%s.lst", mapname);
  84. f = fopen(buffer, "a");
  85. if (f)
  86. {
  87. fprintf(f, "%s-%03i-texture.tga;\n", mapname, i);
  88. fclose(f);
  89. }
  90. delete [] image;
  91. }
  92. if (bumpmap)
  93. {
  94. snprintf(buffer, 64, "%s-%03i-bumpmap.tga", mapname, i);
  95. f = fopen(buffer, "wb");
  96. if (f)
  97. {
  98. if (!mtk_image__tga_save(f, bumpmap, 256, 256, 4))
  99. printf("\tWrote texture %s\n", buffer);
  100. fclose(f);
  101. }
  102. delete [] bumpmap;
  103. }
  104. }
  105. for (i = 0; i < tr->NumSpecialTextures(); i++)
  106. {
  107. image = tr->SpecialTexTile(i);
  108. snprintf(buffer, 128, "%s-%03i-special.tga", mapname, i);
  109. f = fopen(buffer, "wb");
  110. if (f)
  111. {
  112. if (!mtk_image__tga_save(f, image, 256, 256, 4))
  113. printf("\tWrote texture %s\n", buffer);
  114. fclose(f);
  115. }
  116. else
  117. {
  118. printf("\tFailed to write texture %s\n", buffer);
  119. }
  120. delete [] image;
  121. }
  122. #else
  123. printf("Texture dumping not in this build\n");
  124. #endif
  125. }
  126. void dump_mesh(TombRaider *tr, char *mapname, int index)
  127. {
  128. tr2_object_texture_t *object_texture = NULL;
  129. tr2_mesh_t *meshes = NULL;
  130. unsigned int v, check;
  131. int i, triangles, rectangles, t_index;
  132. char buffer[128];
  133. float rgba[4];
  134. float s, t;
  135. char id[8];
  136. FILE *f;
  137. if (!mapname || !tr)
  138. {
  139. return;
  140. }
  141. snprintf(buffer, 128, "%s-%03i.mesh", mapname, index);
  142. object_texture = tr->ObjectTextures();
  143. meshes = tr->Mesh();
  144. f = fopen(buffer, "wb");
  145. if (!f)
  146. {
  147. perror("Failed to write mesh :");
  148. return;
  149. }
  150. // Setup header id and check points
  151. strncpy(id, "TRMESH", 7);
  152. id[7] = 0;
  153. check = 0xcdcdcdcd;
  154. fwrite(id, 8, 1, f);
  155. fwrite(&meshes[index].num_vertices, 2, 1, f);
  156. fwrite(&meshes[index].num_textured_triangles, 2, 1, f);
  157. fwrite(&meshes[index].num_textured_rectangles, 2, 1, f);
  158. fwrite(&meshes[index].num_coloured_triangles, 2, 1, f);
  159. fwrite(&meshes[index].num_coloured_rectangles, 2, 1, f);
  160. fwrite(&meshes[index].collision_size, 4, 1, f);
  161. // Textured triangles ////////////////////////
  162. fwrite(&check, 4, 1, f);
  163. triangles = meshes[index].num_textured_triangles;
  164. for (i = 0; triangles > 0 && i < triangles; i++)
  165. {
  166. t_index = meshes[index].textured_triangles[i].texture;
  167. // Store texture info
  168. fwrite(&object_texture[t_index].tile, 2, 1, f);
  169. fwrite(&object_texture[t_index].transparency_flags, 2, 1, f);
  170. // Store vertices
  171. v = meshes[index].textured_triangles[i].vertices[0];
  172. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  173. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  174. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  175. v = meshes[index].textured_triangles[i].vertices[1];
  176. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  177. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  178. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  179. v = meshes[index].textured_triangles[i].vertices[2];
  180. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  181. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  182. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  183. // Store texels
  184. s = tr->adjustTexel(object_texture[t_index].vertices[0].xpixel,
  185. object_texture[t_index].vertices[0].xcoordinate);
  186. t = tr->adjustTexel(object_texture[t_index].vertices[0].ypixel,
  187. object_texture[t_index].vertices[0].ycoordinate);
  188. fwrite(&s, 4, 1, f);
  189. fwrite(&t, 4, 1, f);
  190. s = tr->adjustTexel(object_texture[t_index].vertices[1].xpixel,
  191. object_texture[t_index].vertices[1].xcoordinate);
  192. t = tr->adjustTexel(object_texture[t_index].vertices[1].ypixel,
  193. object_texture[t_index].vertices[1].ycoordinate);
  194. fwrite(&s, 4, 1, f);
  195. fwrite(&t, 4, 1, f);
  196. s = tr->adjustTexel(object_texture[t_index].vertices[2].xpixel,
  197. object_texture[t_index].vertices[2].xcoordinate);
  198. t = tr->adjustTexel(object_texture[t_index].vertices[2].ypixel,
  199. object_texture[t_index].vertices[2].ycoordinate);
  200. fwrite(&s, 4, 1, f);
  201. fwrite(&t, 4, 1, f);
  202. }
  203. fwrite(&check, 4, 1, f);
  204. // Textured rectangles ////////////////////////
  205. fwrite(&check, 4, 1, f);
  206. rectangles = meshes[index].num_textured_rectangles;
  207. for (i = 0; rectangles > 0 && i < rectangles; i++)
  208. {
  209. t_index = meshes[index].textured_rectangles[i].texture;
  210. // Store texture info
  211. fwrite(&object_texture[t_index].tile, 2, 1, f);
  212. fwrite(&object_texture[t_index].transparency_flags, 2, 1, f);
  213. // Store vertices
  214. v = meshes[index].textured_rectangles[i].vertices[0];
  215. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  216. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  217. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  218. v = meshes[index].textured_rectangles[i].vertices[1];
  219. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  220. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  221. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  222. v = meshes[index].textured_rectangles[i].vertices[2];
  223. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  224. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  225. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  226. v = meshes[index].textured_rectangles[i].vertices[3];
  227. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  228. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  229. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  230. // Store texels
  231. s = tr->adjustTexel(object_texture[t_index].vertices[0].xpixel,
  232. object_texture[t_index].vertices[0].xcoordinate);
  233. t = tr->adjustTexel(object_texture[t_index].vertices[0].ypixel,
  234. object_texture[t_index].vertices[0].ycoordinate);
  235. fwrite(&s, 4, 1, f);
  236. fwrite(&t, 4, 1, f);
  237. s = tr->adjustTexel(object_texture[t_index].vertices[1].xpixel,
  238. object_texture[t_index].vertices[1].xcoordinate);
  239. t = tr->adjustTexel(object_texture[t_index].vertices[1].ypixel,
  240. object_texture[t_index].vertices[1].ycoordinate);
  241. fwrite(&s, 4, 1, f);
  242. fwrite(&t, 4, 1, f);
  243. s = tr->adjustTexel(object_texture[t_index].vertices[2].xpixel,
  244. object_texture[t_index].vertices[2].xcoordinate);
  245. t = tr->adjustTexel(object_texture[t_index].vertices[2].ypixel,
  246. object_texture[t_index].vertices[2].ycoordinate);
  247. fwrite(&s, 4, 1, f);
  248. fwrite(&t, 4, 1, f);
  249. s = tr->adjustTexel(object_texture[t_index].vertices[3].xpixel,
  250. object_texture[t_index].vertices[3].xcoordinate);
  251. t = tr->adjustTexel(object_texture[t_index].vertices[3].ypixel,
  252. object_texture[t_index].vertices[3].ycoordinate);
  253. fwrite(&s, 4, 1, f);
  254. fwrite(&t, 4, 1, f);
  255. }
  256. fwrite(&check, 4, 1, f);
  257. // Coloured triangles ////////////////////////
  258. fwrite(&check, 4, 1, f);
  259. triangles = meshes[index].num_coloured_triangles;
  260. for (i = 0; triangles > 0 && i < triangles; i++)
  261. {
  262. // Store vertices
  263. v = meshes[index].coloured_triangles[i].vertices[0];
  264. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  265. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  266. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  267. v = meshes[index].coloured_triangles[i].vertices[1];
  268. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  269. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  270. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  271. v = meshes[index].coloured_triangles[i].vertices[2];
  272. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  273. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  274. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  275. // Store color
  276. switch (tr->Engine())
  277. {
  278. case TR_VERSION_1:
  279. tr->getColor(meshes[index].coloured_triangles[i].texture
  280. & 0xff, rgba);
  281. break;
  282. default:
  283. tr->getColor((meshes[index].coloured_triangles[i].texture>>8)
  284. & 0xff, rgba);
  285. }
  286. s = rgba[0];
  287. t = rgba[1];
  288. fwrite(&s, 4, 1, f);
  289. fwrite(&t, 4, 1, f);
  290. s = rgba[2];
  291. t = rgba[3];
  292. fwrite(&s, 4, 1, f);
  293. fwrite(&t, 4, 1, f);
  294. }
  295. fwrite(&check, 4, 1, f);
  296. // Coloured rectangles ////////////////////////
  297. fwrite(&check, 4, 1, f);
  298. rectangles = meshes[index].num_coloured_rectangles;
  299. for (i = 0; rectangles > 0 && i < rectangles; i++)
  300. {
  301. // Store vertices
  302. v = meshes[index].coloured_rectangles[i].vertices[0];
  303. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  304. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  305. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  306. v = meshes[index].coloured_rectangles[i].vertices[1];
  307. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  308. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  309. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  310. v = meshes[index].coloured_rectangles[i].vertices[2];
  311. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  312. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  313. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  314. v = meshes[index].coloured_rectangles[i].vertices[3];
  315. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  316. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  317. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  318. // Store color
  319. switch (tr->Engine())
  320. {
  321. case TR_VERSION_1:
  322. tr->getColor(meshes[index].coloured_rectangles[i].texture
  323. & 0xff, rgba);
  324. break;
  325. default:
  326. tr->getColor((meshes[index].coloured_rectangles[i].texture>>8)
  327. & 0xff, rgba);
  328. }
  329. s = rgba[0];
  330. t = rgba[1];
  331. fwrite(&s, 4, 1, f);
  332. fwrite(&t, 4, 1, f);
  333. s = rgba[2];
  334. t = rgba[3];
  335. fwrite(&s, 4, 1, f);
  336. fwrite(&t, 4, 1, f);
  337. }
  338. fwrite(&check, 4, 1, f);
  339. fclose(f);
  340. printf(".");
  341. fflush(stdout);
  342. }
  343. void dump_lara_stuff(char *mapname, TombRaider &tr)
  344. {
  345. unsigned int i, j, k, n;
  346. tr2_moveable_t *moveable = tr.Moveable();
  347. unsigned int numMoveables = tr.NumMoveables();
  348. char filename[64];
  349. unsigned char *riff;
  350. unsigned int riffSz, total = 0;
  351. FILE *f;
  352. snprintf(filename, 63, "%s-lara.nfo", mapname);
  353. f = fopen(filename, "w");
  354. if (!f)
  355. {
  356. perror("Failed to write lara.nfo: ");
  357. return;
  358. }
  359. for (i = 0; i < numMoveables; ++i)
  360. {
  361. j = n = 0;
  362. if (moveable[i].object_id == 0)
  363. {
  364. j = moveable[i].starting_mesh;
  365. n = moveable[i].num_meshes + j;
  366. fprintf(f, "Lara (%i)\n", i);
  367. }
  368. else if (moveable[i].object_id == 30)
  369. {
  370. j = moveable[i].starting_mesh;
  371. n = moveable[i].num_meshes + j;
  372. fprintf(f, "Lara ponytail\n");
  373. }
  374. else if (tr.Engine() == TR_VERSION_4)
  375. {
  376. switch (moveable[i].object_id)
  377. {
  378. case 8: // Joints, ( interconnecting skin/ploys )
  379. case 9:
  380. fprintf(f, "TR4 lara joints (%i)\n", i);
  381. j = moveable[i].starting_mesh;
  382. n = moveable[i].num_meshes + j;
  383. }
  384. }
  385. for (k = j; j < n; ++j)
  386. {
  387. fprintf(f, "\tMesh[%i] = %i\n", (j - k), j);
  388. }
  389. }
  390. fclose(f);
  391. printf("\nDumping %i audio samples: ", tr.getSoundSamplesCount());
  392. for (i = 0, j = 0; i < tr.getSoundSamplesCount(); ++i)
  393. {
  394. tr.getSoundSample(i, &riffSz, &riff);
  395. total += riffSz;
  396. snprintf(filename, 63, "%s-%03i.wav", mapname, j++);
  397. f = fopen(filename, "wb");
  398. if (!f)
  399. {
  400. perror("Failed to write riff.wav: ");
  401. continue;
  402. }
  403. fwrite(riff, 1, riffSz, f);
  404. fclose(f);
  405. delete [] riff;
  406. printf(".");
  407. fflush(stdout);
  408. }
  409. printf("\n");
  410. if (total)
  411. {
  412. printf("Dumped %ibytes (%.2f MB) of audio samples\n",
  413. total, (float)total/1024000.0);
  414. }
  415. }
  416. void percent_callback(int p)
  417. {
  418. printf("Level %i%% loaded\n", p);
  419. }
  420. int test_main(int argc, char *argv[])
  421. {
  422. TombRaider tr;
  423. char mapname[128];
  424. int len, i, j;
  425. printf("[TombRaider class test]\n");
  426. tr.setDebug(true);
  427. if (argc > 2)
  428. {
  429. // Strip for mapname //////////////////////////////
  430. len = strlen(argv[2]);
  431. for (i = len, j = 0; i > 0; i--, j++)
  432. if (argv[2][i] == '/' || argv[2][i] == '\\')
  433. break;
  434. j--;
  435. memset(mapname, 0, 128);
  436. for (i = 0; i < len - j && i < 30; i++)
  437. mapname[i] = argv[2][i + len - j];
  438. ////////////////////////////////////////////////////
  439. if (strncmp(argv[1], "load", 4) == 0)
  440. {
  441. if (!tr.Load(argv[2], percent_callback))
  442. {
  443. printf("\nmain: Load reports success.\n");
  444. }
  445. }
  446. else if (strncmp(argv[1], "dump", 4) == 0)
  447. {
  448. if (!tr.Load(argv[2], percent_callback))
  449. {
  450. printf("\nmain: Load reports success.\n");
  451. dump_textures(&tr, mapname);
  452. printf("Mesh dumping: ");
  453. for (i = 0; i < tr.getMeshCount(); i++)
  454. {
  455. dump_mesh(&tr, mapname, i);
  456. }
  457. if (argc > 3)
  458. {
  459. printf("\nLoading external sound SFX.\n");
  460. tr.loadSFX(argv[3]);
  461. }
  462. dump_lara_stuff(mapname, tr);
  463. printf("\n");
  464. }
  465. else
  466. {
  467. printf("\nmain: Load failed.\n");
  468. }
  469. }
  470. else
  471. printf("\n\n%s [ load | dump ] filename [sound.sfx]\n", argv[0]);
  472. }
  473. else
  474. {
  475. printf("\n\n%s [ load | dump ] filename [sound.sfx]\n", argv[0]);
  476. }
  477. return 0;
  478. }
  479. int main(int argc, char *argv[])
  480. {
  481. test_main(argc, argv);
  482. #ifdef DEBUG_MEMORY
  483. dump_memory_report();
  484. #endif
  485. return 0;
  486. }