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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  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 (!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 (!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 (!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. case TR_VERSION_UNKNOWN:
  283. case TR_VERSION_2:
  284. case TR_VERSION_3:
  285. case TR_VERSION_4:
  286. case TR_VERSION_5:
  287. tr->getColor((meshes[index].coloured_triangles[i].texture>>8)
  288. & 0xff, rgba);
  289. break;
  290. }
  291. s = rgba[0];
  292. t = rgba[1];
  293. fwrite(&s, 4, 1, f);
  294. fwrite(&t, 4, 1, f);
  295. s = rgba[2];
  296. t = rgba[3];
  297. fwrite(&s, 4, 1, f);
  298. fwrite(&t, 4, 1, f);
  299. }
  300. fwrite(&check, 4, 1, f);
  301. // Coloured rectangles ////////////////////////
  302. fwrite(&check, 4, 1, f);
  303. rectangles = meshes[index].num_coloured_rectangles;
  304. for (i = 0; rectangles > 0 && i < rectangles; i++)
  305. {
  306. // Store vertices
  307. v = meshes[index].coloured_rectangles[i].vertices[0];
  308. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  309. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  310. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  311. v = meshes[index].coloured_rectangles[i].vertices[1];
  312. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  313. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  314. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  315. v = meshes[index].coloured_rectangles[i].vertices[2];
  316. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  317. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  318. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  319. v = meshes[index].coloured_rectangles[i].vertices[3];
  320. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  321. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  322. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  323. // Store color
  324. switch (tr->Engine())
  325. {
  326. case TR_VERSION_1:
  327. tr->getColor(meshes[index].coloured_rectangles[i].texture
  328. & 0xff, rgba);
  329. break;
  330. case TR_VERSION_UNKNOWN:
  331. case TR_VERSION_2:
  332. case TR_VERSION_3:
  333. case TR_VERSION_4:
  334. case TR_VERSION_5:
  335. tr->getColor((meshes[index].coloured_rectangles[i].texture>>8)
  336. & 0xff, rgba);
  337. break;
  338. }
  339. s = rgba[0];
  340. t = rgba[1];
  341. fwrite(&s, 4, 1, f);
  342. fwrite(&t, 4, 1, f);
  343. s = rgba[2];
  344. t = rgba[3];
  345. fwrite(&s, 4, 1, f);
  346. fwrite(&t, 4, 1, f);
  347. }
  348. fwrite(&check, 4, 1, f);
  349. fclose(f);
  350. printf(".");
  351. fflush(stdout);
  352. }
  353. void dump_lara_stuff(char *mapname, TombRaider &tr)
  354. {
  355. unsigned int i, j, k, n;
  356. tr2_moveable_t *moveable = tr.Moveable();
  357. unsigned int numMoveables = tr.NumMoveables();
  358. char filename[64];
  359. unsigned char *riff;
  360. unsigned int riffSz, total = 0;
  361. FILE *f;
  362. snprintf(filename, 63, "%s-lara.nfo", mapname);
  363. f = fopen(filename, "w");
  364. if (!f)
  365. {
  366. perror("Failed to write lara.nfo: ");
  367. return;
  368. }
  369. for (i = 0; i < numMoveables; ++i)
  370. {
  371. j = n = 0;
  372. if (moveable[i].object_id == 0)
  373. {
  374. j = moveable[i].starting_mesh;
  375. n = moveable[i].num_meshes + j;
  376. fprintf(f, "Lara (%u)\n", i);
  377. }
  378. else if (moveable[i].object_id == 30)
  379. {
  380. j = moveable[i].starting_mesh;
  381. n = moveable[i].num_meshes + j;
  382. fprintf(f, "Lara ponytail\n");
  383. }
  384. else if (tr.Engine() == TR_VERSION_4)
  385. {
  386. switch (moveable[i].object_id)
  387. {
  388. case 8: // Joints, ( interconnecting skin/ploys )
  389. case 9:
  390. fprintf(f, "TR4 lara joints (%u)\n", i);
  391. j = moveable[i].starting_mesh;
  392. n = moveable[i].num_meshes + j;
  393. }
  394. }
  395. for (k = j; j < n; ++j)
  396. {
  397. fprintf(f, "\tMesh[%i] = %u\n", (j - k), j);
  398. }
  399. }
  400. fclose(f);
  401. printf("\nDumping %u audio samples: ", tr.getSoundSamplesCount());
  402. for (i = 0, j = 0; i < tr.getSoundSamplesCount(); ++i)
  403. {
  404. tr.getSoundSample(i, &riffSz, &riff);
  405. total += riffSz;
  406. snprintf(filename, 63, "%s-%03i.wav", mapname, j++);
  407. f = fopen(filename, "wb");
  408. if (!f)
  409. {
  410. perror("Failed to write riff.wav: ");
  411. continue;
  412. }
  413. fwrite(riff, 1, riffSz, f);
  414. fclose(f);
  415. delete [] riff;
  416. printf(".");
  417. fflush(stdout);
  418. }
  419. printf("\n");
  420. if (total)
  421. {
  422. printf("Dumped %ubytes (%.2f MB) of audio samples\n",
  423. total, (float)total/1024000.0);
  424. }
  425. }
  426. void percent_callback(int p)
  427. {
  428. printf("Level %i%% loaded\n", p);
  429. }
  430. int test_main(int argc, char *argv[])
  431. {
  432. TombRaider tr;
  433. char mapname[128];
  434. int len, i, j;
  435. printf("[TombRaider class test]\n");
  436. tr.setDebug(true);
  437. if (argc > 2)
  438. {
  439. // Strip for mapname //////////////////////////////
  440. len = strlen(argv[2]);
  441. for (i = len, j = 0; i > 0; i--, j++)
  442. if (argv[2][i] == '/' || argv[2][i] == '\\')
  443. break;
  444. j--;
  445. memset(mapname, 0, 128);
  446. for (i = 0; i < len - j && i < 30; i++)
  447. mapname[i] = argv[2][i + len - j];
  448. ////////////////////////////////////////////////////
  449. if (strncmp(argv[1], "load", 4) == 0)
  450. {
  451. if (!tr.Load(argv[2], percent_callback))
  452. {
  453. printf("\nmain: Load reports success.\n");
  454. }
  455. }
  456. else if (strncmp(argv[1], "dump", 4) == 0)
  457. {
  458. if (!tr.Load(argv[2], percent_callback))
  459. {
  460. printf("\nmain: Load reports success.\n");
  461. dump_textures(&tr, mapname);
  462. printf("Mesh dumping: ");
  463. for (i = 0; i < tr.getMeshCount(); i++)
  464. {
  465. dump_mesh(&tr, mapname, i);
  466. }
  467. if (argc > 3)
  468. {
  469. printf("\nLoading external sound SFX.\n");
  470. tr.loadSFX(argv[3]);
  471. }
  472. dump_lara_stuff(mapname, tr);
  473. printf("\n");
  474. }
  475. else
  476. {
  477. printf("\nmain: Load failed.\n");
  478. }
  479. }
  480. else
  481. printf("\n\n%s [ load | dump ] filename [sound.sfx]\n", argv[0]);
  482. }
  483. else
  484. {
  485. printf("\n\n%s [ load | dump ] filename [sound.sfx]\n", argv[0]);
  486. }
  487. return 0;
  488. }
  489. int main(int argc, char *argv[])
  490. {
  491. test_main(argc, argv);
  492. #ifdef DEBUG_MEMORY
  493. dump_memory_report();
  494. #endif
  495. return 0;
  496. }