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 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*!
  2. * \file test/TombRaider.cpp
  3. * \brief Loads maps, meshes, textures...
  4. *
  5. * \author Mongoose
  6. */
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <math.h>
  10. #include <string.h>
  11. #include <stdarg.h>
  12. #include <TombRaider.h>
  13. #ifdef __TEST_TR5_DUMP_TGA
  14. #include <utils/tga.h>
  15. #endif
  16. #ifdef DEBUG_MEMORY
  17. #include <memory_test.h>
  18. #endif
  19. void dump_textures(TombRaider *tr, char *mapname)
  20. {
  21. #ifdef __TEST_TR5_DUMP_TGA
  22. int i;
  23. unsigned char *image;
  24. unsigned char *bumpmap;
  25. char buffer[128];
  26. FILE *f;
  27. if (!tr || !mapname)
  28. return;
  29. // Dump textures
  30. printf("\n\t[Texture dumping for '%s']\n", mapname);
  31. for (i = 0; i < tr->NumTextures(); i++)
  32. {
  33. tr->Texture(i, &image, &bumpmap);
  34. if (image)
  35. {
  36. snprintf(buffer, 128, "%s-%03i-texture.tga", mapname, i);
  37. f = fopen(buffer, "wb");
  38. if (f)
  39. {
  40. if (!tga_save(f, image, 256, 256, 4))
  41. printf("\tWrote texture %s\n", buffer);
  42. fclose(f);
  43. }
  44. snprintf(buffer, 128, "%s.lst", mapname);
  45. f = fopen(buffer, "a");
  46. if (f)
  47. {
  48. fprintf(f, "%s-%03i-texture.tga;\n", mapname, i);
  49. fclose(f);
  50. }
  51. delete [] image;
  52. }
  53. if (bumpmap)
  54. {
  55. snprintf(buffer, 64, "%s-%03i-bumpmap.tga", mapname, i);
  56. f = fopen(buffer, "wb");
  57. if (f)
  58. {
  59. if (!tga_save(f, bumpmap, 256, 256, 4))
  60. printf("\tWrote texture %s\n", buffer);
  61. fclose(f);
  62. }
  63. delete [] bumpmap;
  64. }
  65. }
  66. for (i = 0; i < tr->NumSpecialTextures(); i++)
  67. {
  68. image = tr->SpecialTexTile(i);
  69. snprintf(buffer, 128, "%s-%03i-special.tga", mapname, i);
  70. f = fopen(buffer, "wb");
  71. if (f)
  72. {
  73. if (!tga_save(f, image, 256, 256, 4))
  74. printf("\tWrote texture %s\n", buffer);
  75. fclose(f);
  76. }
  77. else
  78. {
  79. printf("\tFailed to write texture %s\n", buffer);
  80. }
  81. delete [] image;
  82. }
  83. #else
  84. printf("Texture dumping not in this build\n");
  85. #endif
  86. }
  87. void dump_mesh(TombRaider *tr, char *mapname, int index)
  88. {
  89. tr2_object_texture_t *object_texture = NULL;
  90. tr2_mesh_t *meshes = NULL;
  91. unsigned int v, check;
  92. int i, triangles, rectangles, t_index;
  93. char buffer[128];
  94. float rgba[4];
  95. float s, t;
  96. char id[8];
  97. FILE *f;
  98. if (!mapname || !tr)
  99. {
  100. return;
  101. }
  102. snprintf(buffer, 128, "%s-%03i.mesh", mapname, index);
  103. object_texture = tr->ObjectTextures();
  104. meshes = tr->Mesh();
  105. f = fopen(buffer, "wb");
  106. if (!f)
  107. {
  108. perror("Failed to write mesh :");
  109. return;
  110. }
  111. // Setup header id and check points
  112. strncpy(id, "TRMESH", 7);
  113. id[7] = 0;
  114. check = 0xcdcdcdcd;
  115. fwrite(id, 8, 1, f);
  116. fwrite(&meshes[index].num_vertices, 2, 1, f);
  117. fwrite(&meshes[index].num_textured_triangles, 2, 1, f);
  118. fwrite(&meshes[index].num_textured_rectangles, 2, 1, f);
  119. fwrite(&meshes[index].num_coloured_triangles, 2, 1, f);
  120. fwrite(&meshes[index].num_coloured_rectangles, 2, 1, f);
  121. fwrite(&meshes[index].collision_size, 4, 1, f);
  122. // Textured triangles ////////////////////////
  123. fwrite(&check, 4, 1, f);
  124. triangles = meshes[index].num_textured_triangles;
  125. for (i = 0; triangles > 0 && i < triangles; i++)
  126. {
  127. t_index = meshes[index].textured_triangles[i].texture;
  128. // Store texture info
  129. fwrite(&object_texture[t_index].tile, 2, 1, f);
  130. fwrite(&object_texture[t_index].transparency_flags, 2, 1, f);
  131. // Store vertices
  132. v = meshes[index].textured_triangles[i].vertices[0];
  133. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  134. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  135. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  136. v = meshes[index].textured_triangles[i].vertices[1];
  137. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  138. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  139. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  140. v = meshes[index].textured_triangles[i].vertices[2];
  141. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  142. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  143. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  144. // Store texels
  145. s = tr->adjustTexel(object_texture[t_index].vertices[0].xpixel,
  146. object_texture[t_index].vertices[0].xcoordinate);
  147. t = tr->adjustTexel(object_texture[t_index].vertices[0].ypixel,
  148. object_texture[t_index].vertices[0].ycoordinate);
  149. fwrite(&s, 4, 1, f);
  150. fwrite(&t, 4, 1, f);
  151. s = tr->adjustTexel(object_texture[t_index].vertices[1].xpixel,
  152. object_texture[t_index].vertices[1].xcoordinate);
  153. t = tr->adjustTexel(object_texture[t_index].vertices[1].ypixel,
  154. object_texture[t_index].vertices[1].ycoordinate);
  155. fwrite(&s, 4, 1, f);
  156. fwrite(&t, 4, 1, f);
  157. s = tr->adjustTexel(object_texture[t_index].vertices[2].xpixel,
  158. object_texture[t_index].vertices[2].xcoordinate);
  159. t = tr->adjustTexel(object_texture[t_index].vertices[2].ypixel,
  160. object_texture[t_index].vertices[2].ycoordinate);
  161. fwrite(&s, 4, 1, f);
  162. fwrite(&t, 4, 1, f);
  163. }
  164. fwrite(&check, 4, 1, f);
  165. // Textured rectangles ////////////////////////
  166. fwrite(&check, 4, 1, f);
  167. rectangles = meshes[index].num_textured_rectangles;
  168. for (i = 0; rectangles > 0 && i < rectangles; i++)
  169. {
  170. t_index = meshes[index].textured_rectangles[i].texture;
  171. // Store texture info
  172. fwrite(&object_texture[t_index].tile, 2, 1, f);
  173. fwrite(&object_texture[t_index].transparency_flags, 2, 1, f);
  174. // Store vertices
  175. v = meshes[index].textured_rectangles[i].vertices[0];
  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_rectangles[i].vertices[1];
  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. v = meshes[index].textured_rectangles[i].vertices[2];
  184. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  185. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  186. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  187. v = meshes[index].textured_rectangles[i].vertices[3];
  188. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  189. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  190. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  191. // Store texels
  192. s = tr->adjustTexel(object_texture[t_index].vertices[0].xpixel,
  193. object_texture[t_index].vertices[0].xcoordinate);
  194. t = tr->adjustTexel(object_texture[t_index].vertices[0].ypixel,
  195. object_texture[t_index].vertices[0].ycoordinate);
  196. fwrite(&s, 4, 1, f);
  197. fwrite(&t, 4, 1, f);
  198. s = tr->adjustTexel(object_texture[t_index].vertices[1].xpixel,
  199. object_texture[t_index].vertices[1].xcoordinate);
  200. t = tr->adjustTexel(object_texture[t_index].vertices[1].ypixel,
  201. object_texture[t_index].vertices[1].ycoordinate);
  202. fwrite(&s, 4, 1, f);
  203. fwrite(&t, 4, 1, f);
  204. s = tr->adjustTexel(object_texture[t_index].vertices[2].xpixel,
  205. object_texture[t_index].vertices[2].xcoordinate);
  206. t = tr->adjustTexel(object_texture[t_index].vertices[2].ypixel,
  207. object_texture[t_index].vertices[2].ycoordinate);
  208. fwrite(&s, 4, 1, f);
  209. fwrite(&t, 4, 1, f);
  210. s = tr->adjustTexel(object_texture[t_index].vertices[3].xpixel,
  211. object_texture[t_index].vertices[3].xcoordinate);
  212. t = tr->adjustTexel(object_texture[t_index].vertices[3].ypixel,
  213. object_texture[t_index].vertices[3].ycoordinate);
  214. fwrite(&s, 4, 1, f);
  215. fwrite(&t, 4, 1, f);
  216. }
  217. fwrite(&check, 4, 1, f);
  218. // Coloured triangles ////////////////////////
  219. fwrite(&check, 4, 1, f);
  220. triangles = meshes[index].num_coloured_triangles;
  221. for (i = 0; triangles > 0 && i < triangles; i++)
  222. {
  223. // Store vertices
  224. v = meshes[index].coloured_triangles[i].vertices[0];
  225. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  226. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  227. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  228. v = meshes[index].coloured_triangles[i].vertices[1];
  229. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  230. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  231. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  232. v = meshes[index].coloured_triangles[i].vertices[2];
  233. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  234. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  235. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  236. // Store color
  237. switch (tr->Engine())
  238. {
  239. case TR_VERSION_1:
  240. tr->getColor(meshes[index].coloured_triangles[i].texture
  241. & 0xff, rgba);
  242. break;
  243. case TR_VERSION_UNKNOWN:
  244. case TR_VERSION_2:
  245. case TR_VERSION_3:
  246. case TR_VERSION_4:
  247. case TR_VERSION_5:
  248. tr->getColor((meshes[index].coloured_triangles[i].texture>>8)
  249. & 0xff, rgba);
  250. break;
  251. }
  252. s = rgba[0];
  253. t = rgba[1];
  254. fwrite(&s, 4, 1, f);
  255. fwrite(&t, 4, 1, f);
  256. s = rgba[2];
  257. t = rgba[3];
  258. fwrite(&s, 4, 1, f);
  259. fwrite(&t, 4, 1, f);
  260. }
  261. fwrite(&check, 4, 1, f);
  262. // Coloured rectangles ////////////////////////
  263. fwrite(&check, 4, 1, f);
  264. rectangles = meshes[index].num_coloured_rectangles;
  265. for (i = 0; rectangles > 0 && i < rectangles; i++)
  266. {
  267. // Store vertices
  268. v = meshes[index].coloured_rectangles[i].vertices[0];
  269. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  270. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  271. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  272. v = meshes[index].coloured_rectangles[i].vertices[1];
  273. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  274. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  275. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  276. v = meshes[index].coloured_rectangles[i].vertices[2];
  277. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  278. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  279. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  280. v = meshes[index].coloured_rectangles[i].vertices[3];
  281. fwrite(&meshes[index].vertices[v].x, 2, 1, f);
  282. fwrite(&meshes[index].vertices[v].y, 2, 1, f);
  283. fwrite(&meshes[index].vertices[v].z, 2, 1, f);
  284. // Store color
  285. switch (tr->Engine())
  286. {
  287. case TR_VERSION_1:
  288. tr->getColor(meshes[index].coloured_rectangles[i].texture
  289. & 0xff, rgba);
  290. break;
  291. case TR_VERSION_UNKNOWN:
  292. case TR_VERSION_2:
  293. case TR_VERSION_3:
  294. case TR_VERSION_4:
  295. case TR_VERSION_5:
  296. tr->getColor((meshes[index].coloured_rectangles[i].texture>>8)
  297. & 0xff, rgba);
  298. break;
  299. }
  300. s = rgba[0];
  301. t = rgba[1];
  302. fwrite(&s, 4, 1, f);
  303. fwrite(&t, 4, 1, f);
  304. s = rgba[2];
  305. t = rgba[3];
  306. fwrite(&s, 4, 1, f);
  307. fwrite(&t, 4, 1, f);
  308. }
  309. fwrite(&check, 4, 1, f);
  310. fclose(f);
  311. printf(".");
  312. fflush(stdout);
  313. }
  314. void dump_lara_stuff(char *mapname, TombRaider &tr)
  315. {
  316. unsigned int i, j, k, n;
  317. tr2_moveable_t *moveable = tr.Moveable();
  318. unsigned int numMoveables = tr.NumMoveables();
  319. char filename[64];
  320. unsigned char *riff;
  321. unsigned int riffSz, total = 0;
  322. FILE *f;
  323. snprintf(filename, 63, "%s-lara.nfo", mapname);
  324. f = fopen(filename, "w");
  325. if (!f)
  326. {
  327. perror("Failed to write lara.nfo: ");
  328. return;
  329. }
  330. for (i = 0; i < numMoveables; ++i)
  331. {
  332. j = n = 0;
  333. if (moveable[i].object_id == 0)
  334. {
  335. j = moveable[i].starting_mesh;
  336. n = moveable[i].num_meshes + j;
  337. fprintf(f, "Lara (%u)\n", i);
  338. }
  339. else if (moveable[i].object_id == 30)
  340. {
  341. j = moveable[i].starting_mesh;
  342. n = moveable[i].num_meshes + j;
  343. fprintf(f, "Lara ponytail\n");
  344. }
  345. else if (tr.Engine() == TR_VERSION_4)
  346. {
  347. switch (moveable[i].object_id)
  348. {
  349. case 8: // Joints, ( interconnecting skin/ploys )
  350. case 9:
  351. fprintf(f, "TR4 lara joints (%u)\n", i);
  352. j = moveable[i].starting_mesh;
  353. n = moveable[i].num_meshes + j;
  354. }
  355. }
  356. for (k = j; j < n; ++j)
  357. {
  358. fprintf(f, "\tMesh[%i] = %u\n", (j - k), j);
  359. }
  360. }
  361. fclose(f);
  362. printf("\nDumping %u audio samples: ", tr.getSoundSamplesCount());
  363. for (i = 0, j = 0; i < tr.getSoundSamplesCount(); ++i)
  364. {
  365. tr.getSoundSample(i, &riffSz, &riff);
  366. total += riffSz;
  367. snprintf(filename, 63, "%s-%03i.wav", mapname, j++);
  368. f = fopen(filename, "wb");
  369. if (!f)
  370. {
  371. perror("Failed to write riff.wav: ");
  372. continue;
  373. }
  374. fwrite(riff, 1, riffSz, f);
  375. fclose(f);
  376. delete [] riff;
  377. printf(".");
  378. fflush(stdout);
  379. }
  380. printf("\n");
  381. if (total)
  382. {
  383. printf("Dumped %ubytes (%.2f MB) of audio samples\n",
  384. total, (float)total/1024000.0);
  385. }
  386. }
  387. void percent_callback(int p)
  388. {
  389. printf("Level %i%% loaded\n", p);
  390. }
  391. int test_main(int argc, char *argv[])
  392. {
  393. TombRaider tr;
  394. char mapname[128];
  395. int len, i, j;
  396. printf("[TombRaider class test]\n");
  397. tr.setDebug(true);
  398. if (argc > 2)
  399. {
  400. // Strip for mapname //////////////////////////////
  401. len = strlen(argv[2]);
  402. for (i = len, j = 0; i > 0; i--, j++)
  403. if (argv[2][i] == '/' || argv[2][i] == '\\')
  404. break;
  405. j--;
  406. memset(mapname, 0, 128);
  407. for (i = 0; i < len - j && i < 30; i++)
  408. mapname[i] = argv[2][i + len - j];
  409. ////////////////////////////////////////////////////
  410. if (strncmp(argv[1], "load", 4) == 0)
  411. {
  412. if (!tr.Load(argv[2], percent_callback))
  413. {
  414. printf("\nmain: Load reports success.\n");
  415. }
  416. }
  417. else if (strncmp(argv[1], "dump", 4) == 0)
  418. {
  419. if (!tr.Load(argv[2], percent_callback))
  420. {
  421. printf("\nmain: Load reports success.\n");
  422. dump_textures(&tr, mapname);
  423. printf("Mesh dumping: ");
  424. for (i = 0; i < tr.getMeshCount(); i++)
  425. {
  426. dump_mesh(&tr, mapname, i);
  427. }
  428. if (argc > 3)
  429. {
  430. printf("\nLoading external sound SFX.\n");
  431. tr.loadSFX(argv[3]);
  432. }
  433. dump_lara_stuff(mapname, tr);
  434. printf("\n");
  435. }
  436. else
  437. {
  438. printf("\nmain: Load failed.\n");
  439. }
  440. }
  441. else
  442. printf("\n\n%s [ load | dump ] filename [sound.sfx]\n", argv[0]);
  443. }
  444. else
  445. {
  446. printf("\n\n%s [ load | dump ] filename [sound.sfx]\n", argv[0]);
  447. }
  448. return 0;
  449. }
  450. int main(int argc, char *argv[])
  451. {
  452. test_main(argc, argv);
  453. #ifdef DEBUG_MEMORY
  454. dump_memory_report();
  455. #endif
  456. return 0;
  457. }