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.

LoaderTR2.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*!
  2. * \file src/loader/LoaderTR2.cpp
  3. * \brief TR2 level file loader
  4. *
  5. * \author xythobuz
  6. */
  7. #include <array>
  8. #include <cstdint>
  9. #include <vector>
  10. #include "global.h"
  11. #include "Log.h"
  12. #include "Mesh.h"
  13. #include "TextureManager.h"
  14. #include "utils/pixel.h"
  15. #include "loader/LoaderTR2.h"
  16. LoaderTR2::LoaderTR2() {
  17. }
  18. LoaderTR2::~LoaderTR2() {
  19. }
  20. int LoaderTR2::load(std::string f) {
  21. if (file.open(f.c_str()) != 0) {
  22. return 1; // Could not open file
  23. }
  24. if (file.readU32() != 0x2D) {
  25. return 2; // Not a TR2 level?!
  26. }
  27. loadPaletteTextiles();
  28. file.seek(file.tell() + 4); // Unused value?
  29. loadRooms();
  30. loadFloorData();
  31. loadMeshes();
  32. loadMoveables();
  33. loadStaticMeshes();
  34. loadTextures();
  35. loadSprites();
  36. loadCameras();
  37. loadSoundSources();
  38. loadBoxesOverlapsZones();
  39. loadAnimatedTextures();
  40. loadItems();
  41. file.seek(file.tell() + 8192); // Skip Light map, only for 8bit coloring
  42. loadCinematicFrames();
  43. loadDemoData();
  44. loadSoundMap();
  45. loadSoundDetails();
  46. loadSampleIndices();
  47. return 0; // TODO Not finished with implementation!
  48. }
  49. void LoaderTR2::loadPaletteTextiles() {
  50. file.seek(file.tell() + 768); // Skip 8bit palette, 256 * 3 bytes
  51. // Read the 16bit palette, 256 * 4 bytes, RGBA, A unused
  52. std::array<uint32_t, 256> palette; //!< RGBA, A unused
  53. for (auto& x : palette)
  54. x = file.readU32();
  55. // TODO store palette somewhere
  56. uint32_t numTextiles = file.readU32();
  57. file.seek(file.tell() + (numTextiles * 256 * 256)); // Skip 8bit textiles
  58. // Read the 16bit textiles, numTextiles * 256 * 256 * 2 bytes
  59. for (unsigned int i = 0; i < numTextiles; i++) {
  60. std::array<uint8_t, 256 * 256 * 2> arr;
  61. for (auto& x : arr) {
  62. x = file.readU8();
  63. }
  64. // Convert 16bit textile to 32bit textile
  65. unsigned char* img = argb16to32(&arr[0], 256, 256);
  66. int r = getTextureManager().loadBufferSlot(img, 256, 256, ARGB, 32,
  67. TextureManager::TextureStorage::GAME, i);
  68. assert(r >= 0); //! \fixme properly handle error when texture could not be loaded!
  69. delete [] img;
  70. }
  71. }
  72. void LoaderTR2::loadRooms() {
  73. uint16_t numRooms = file.readU16();
  74. for (unsigned int i = 0; i < numRooms; i++) {
  75. // Room Header
  76. int32_t xOffset = file.read32();
  77. int32_t zOffset = file.read32();
  78. int32_t yBottom = file.read32(); // lowest point == largest y value
  79. int32_t yTop = file.read32(); // highest point == smallest y value
  80. // Number of data words (2 bytes) to follow
  81. uint32_t dataToFollow = file.readU32();
  82. std::vector<struct vertex> vertices;
  83. uint16_t numVertices = file.readU16();
  84. for (unsigned int v = 0; v < numVertices; v++) {
  85. struct vertex v;
  86. // Vertex coordinates, relative to x/zOffset
  87. v.x = file.read16();
  88. v.y = file.read16();
  89. v.z = file.read16();
  90. v.light1 = file.read16();
  91. // Set of flags for special rendering effects
  92. // 0x8000 - Something to do with water surface?
  93. // 0x4000 - Underwater lighting modulation/movement if seen from above
  94. // 0x2000 - Water/Quicksand surface movement
  95. // 0x0010 - Normal?
  96. v.attributes = file.readU16();
  97. v.light2 = file.read16(); // Almost always equal to light1
  98. vertices.push_back(v);
  99. }
  100. Room* room = new Room();
  101. uint16_t numRectangles = file.readU16();
  102. for (unsigned int r = 0; r < numRectangles; r++) {
  103. // Indices into the vertex list read just before
  104. uint16_t vertex1 = file.readU16();
  105. uint16_t vertex2 = file.readU16();
  106. uint16_t vertex3 = file.readU16();
  107. uint16_t vertex4 = file.readU16();
  108. // Index into the object-texture list
  109. uint16_t texture = file.readU16();
  110. room->getMesh().addTexturedRectangle(vertices.at(vertex1), vertices.at(vertex2),
  111. vertices.at(vertex3), vertices.at(vertex4), texture);
  112. }
  113. uint16_t numTriangles = file.readU16();
  114. for (unsigned int t = 0; t < numTriangles; t++) {
  115. // Indices into the room vertex list
  116. uint16_t vertex1 = file.readU16();
  117. uint16_t vertex2 = file.readU16();
  118. uint16_t vertex3 = file.readU16();
  119. // Index into the object-texture list
  120. uint16_t texture = file.readU16();
  121. room->getMesh().addTexturedTriangle(vertices.at(vertex1), vertices.at(vertex2),
  122. vertices.at(vertex3), texture);
  123. }
  124. uint16_t numSprites = file.readU16();
  125. for (unsigned int s = 0; s < numSprites; s++) {
  126. uint16_t vertex = file.readU16(); // Index into vertex list
  127. uint16_t texture = file.readU16(); // Index into object-texture list
  128. room->addSprite(new Sprite(vertices.at(vertex), texture));
  129. }
  130. uint16_t numPortals = file.readU16();
  131. for (unsigned int p = 0; p < numPortals; p++) {
  132. // Which room this portal leads to
  133. uint16_t adjoiningRoom = file.readU16();
  134. // Which way the portal faces
  135. // The normal points away from the adjacent room
  136. // To be seen through, it must point toward the viewpoint
  137. int16_t xNormal = file.read16();
  138. int16_t yNormal = file.read16();
  139. int16_t zNormal = file.read16();
  140. // The corners of this portal
  141. // The right-hand rule applies with respect to the normal
  142. int16_t xCorner1 = file.read16();
  143. int16_t yCorner1 = file.read16();
  144. int16_t zCorner1 = file.read16();
  145. int16_t xCorner2 = file.read16();
  146. int16_t yCorner2 = file.read16();
  147. int16_t zCorner2 = file.read16();
  148. int16_t xCorner3 = file.read16();
  149. int16_t yCorner3 = file.read16();
  150. int16_t zCorner3 = file.read16();
  151. int16_t xCorner4 = file.read16();
  152. int16_t yCorner4 = file.read16();
  153. int16_t zCorner4 = file.read16();
  154. // TODO store portals somewhere
  155. }
  156. uint16_t numZSectors = file.readU16();
  157. uint16_t numXSectors = file.readU16();
  158. for (unsigned int s = 0; s < (numZSectors * numXSectors); s++) {
  159. // Sectors are 1024*1024 world coordinates. Floor and Ceiling are
  160. // signed numbers of 256 units of height.
  161. // Floor/Ceiling value of 0x81 is used to indicate impenetrable
  162. // walls around the sector.
  163. // Floor values are used by the original engine to determine
  164. // what objects can be traversed and how. Relative steps of 1 (256)
  165. // can be walked up, 2..7 must be jumped up, larger than 7 is too high
  166. // If RoomAbove/Below is not none, the Ceiling/Floor is a collisional
  167. // portal to that room
  168. uint16_t indexFloorData = file.readU16();
  169. uint16_t indexBox = file.readU16(); // 0xFFFF if none
  170. uint8_t roomBelow = file.readU8(); // 0xFF if none
  171. int8_t floor = file.read8(); // Absolute height of floor (divided by 256)
  172. uint8_t roomAbove = file.readU8(); // 0xFF if none
  173. int8_t ceiling = file.read8(); // Absolute height of ceiling (/ 256)
  174. // TODO store sectors somewhere
  175. }
  176. int16_t intensity1 = file.read16();
  177. int16_t intensity2 = file.read16();
  178. int16_t lightMode = file.read16();
  179. uint16_t numLights = file.readU16();
  180. for (unsigned int l = 0; l < numLights; l++) {
  181. // Position of light, in world coordinates
  182. int32_t x = file.read32();
  183. int32_t y = file.read32();
  184. int32_t z = file.read32();
  185. uint16_t intensity1 = file.readU16();
  186. uint16_t intensity2 = file.readU16(); // Almost always equal to intensity1
  187. uint32_t fade1 = file.readU32(); // Falloff value?
  188. uint32_t fade2 = file.readU32(); // Falloff value?
  189. // TODO store light somewhere
  190. }
  191. uint16_t numStaticMeshes = file.readU16();
  192. for (unsigned int s = 0; s < numStaticMeshes; s++) {
  193. // Absolute position in world coordinates
  194. int32_t x = file.read32();
  195. int32_t y = file.read32();
  196. int32_t z = file.read32();
  197. // High two bits (0xC000) indicate steps of
  198. // 90 degrees (eg. (rotation >> 14) * 90)
  199. uint16_t rotation = file.readU16();
  200. // Constant lighting, 0xFFFF means use mesh lighting
  201. uint16_t intensity1 = file.readU16();
  202. uint16_t intensity2 = file.readU16();
  203. // Which StaticMesh item to draw
  204. uint16_t objectID = file.readU16();
  205. // TODO store static meshes somewhere
  206. }
  207. int16_t alternateRoom = file.read16();
  208. uint16_t flags = file.readU16();
  209. }
  210. }
  211. void LoaderTR2::loadFloorData() {
  212. uint32_t numFloorData = file.readU32();
  213. for (unsigned int f = 0; f < numFloorData; f++) {
  214. uint16_t unused = file.readU16();
  215. // TODO store floor data somewhere
  216. }
  217. }
  218. void LoaderTR2::loadMeshes() {
  219. // Number of bitu16s of mesh data to follow
  220. // Read all the mesh data into a buffer, because
  221. // only afterward we can read the number of meshes
  222. // in this data block
  223. uint32_t numMeshData = file.readU32();
  224. std::vector<uint16_t> buffer;
  225. for (unsigned int i = 0; i < numMeshData; i++) {
  226. buffer.push_back(file.readU16());
  227. }
  228. uint32_t numMeshPointers = file.readU32();
  229. std::vector<uint32_t> meshPointers;
  230. for (unsigned int i = 0; i < numMeshPointers; i++) {
  231. meshPointers.push_back(file.readU32());
  232. }
  233. // TODO interpret the buffered mesh data
  234. }
  235. void LoaderTR2::loadMoveables() {
  236. uint32_t numAnimations = file.readU32();
  237. for (unsigned int a = 0; a < numAnimations; a++) {
  238. // *Byte* Offset into Frames[] (so divide by 2!)
  239. uint32_t frameOffset = file.readU32();
  240. uint8_t frameRate = file.readU8(); // Engine ticks per frame
  241. // Number of bit16s in Frames[] used by this animation
  242. // Be careful when parsing frames using the FrameSize value
  243. // as the size of each frame, since an animations frame range
  244. // may extend into the next animations frame range, and that
  245. // may have a different FrameSize value.
  246. uint8_t frameSize = file.readU8();
  247. uint16_t stateID = file.readU16();
  248. file.seek(file.tell() + 8); // Skip 8 unknown bytes
  249. uint16_t frameStart = file.readU16(); // First frame in this animation
  250. uint16_t frameEnd = file.readU16(); // Last frame in this animation
  251. uint16_t nextAnimation = file.readU16();
  252. uint16_t nextFrame = file.readU16();
  253. uint16_t numStateChanges = file.readU16();
  254. uint16_t stateChangeOffset = file.readU16(); // Index into StateChanges[]
  255. uint16_t numAnimCommands = file.readU16(); // How many animation commands to use
  256. uint16_t animCommandOffset = file.readU16(); // Index into AnimCommand[]
  257. // TODO store animations somewhere
  258. }
  259. uint32_t numStateChanges = file.readU32();
  260. for (unsigned int s = 0; s < numStateChanges; s++) {
  261. uint16_t stateID = file.readU16();
  262. uint16_t numAnimDispatches = file.readU16();
  263. uint16_t animDispatchOffset = file.readU16(); // Index into AnimDispatches[]
  264. // TODO store state changes somewhere
  265. }
  266. uint32_t numAnimDispatches = file.readU32();
  267. for (unsigned int a = 0; a < numAnimDispatches; a++) {
  268. int16_t low = file.read16(); // Lowest frame that uses this range
  269. int16_t high = file.read16(); // Highest frame (+1?) that uses this range
  270. int16_t nextAnimation = file.read16(); // Animation to go to
  271. int16_t nextFrame = file.read16(); // Frame offset to go to
  272. // TODO store animation dispatches somewhere
  273. }
  274. uint32_t numAnimCommands = file.readU32();
  275. std::vector<int16_t> animCommands;
  276. for (unsigned int a = 0; a < numAnimCommands; a++) {
  277. animCommands.push_back(file.read16());
  278. }
  279. uint32_t numMeshTrees = file.readU32();
  280. for (unsigned int m = 0; m < numMeshTrees; m++) {
  281. // 0x0002 - Put parent mesh on the mesh stack
  282. // 0x0001 - Pop mesh from stack, use as parent mesh
  283. // When both are not set, use previous mesh as parent mesh
  284. // When both are set, do 0x0001 first, then 0x0002, thereby
  285. // reading the stack but not changing it
  286. uint32_t flags = file.readU32();
  287. // Offset of mesh origin from the parent mesh origin
  288. /* Where the hell does this come from?!
  289. int32_t x = file.read32();
  290. int32_t y = file.read32();
  291. int32_t z = file.read32();
  292. */
  293. // TODO store mesh trees somewhere
  294. }
  295. uint32_t numFrames = file.readU32();
  296. std::vector<uint16_t> frames;
  297. for (unsigned int f = 0; f < numFrames; f++) {
  298. frames.push_back(file.readU16());
  299. }
  300. uint32_t numMoveables = file.readU32();
  301. for (unsigned int m = 0; m < numMoveables; m++) {
  302. // Item identifier, matched in Items[]
  303. uint32_t objectID = file.readU32();
  304. uint16_t numMeshes = file.readU16();
  305. uint16_t startingMesh = file.readU16(); // Offset into MeshPointers[]
  306. uint32_t meshTree = file.readU32(); // Offset into MeshTree[]
  307. // *Byte* offset into Frames[] (divide by 2 for Frames[i])
  308. uint32_t frameOffset = file.readU32();
  309. // If animation index is 0xFFFF, the object is stationary or
  310. // animated by the engine (ponytail)
  311. uint16_t animation = file.readU16();
  312. // TODO store moveables somewhere
  313. }
  314. // TODO combine all this into moveables with their animations
  315. }
  316. void LoaderTR2::loadStaticMeshes() {
  317. uint32_t numStaticMeshes = file.readU32();
  318. for (unsigned int s = 0; s < numStaticMeshes; s++) {
  319. uint32_t objectID = file.readU32(); // Matched in Items[]
  320. uint16_t mesh = file.readU16(); // Offset into MeshPointers[]
  321. // tr2_vertex BoundingBox[2][2];
  322. // First index is which one, second index is opposite corners
  323. int16_t x11 = file.read16();
  324. int16_t y11 = file.read16();
  325. int16_t z11 = file.read16();
  326. int16_t x12 = file.read16();
  327. int16_t y12 = file.read16();
  328. int16_t z12 = file.read16();
  329. int16_t x21 = file.read16();
  330. int16_t y21 = file.read16();
  331. int16_t z21 = file.read16();
  332. int16_t x22 = file.read16();
  333. int16_t y22 = file.read16();
  334. int16_t z22 = file.read16();
  335. // Meaning uncertain. Usually 2, and 3 for objects Lara can
  336. // travel through, like TR2s skeletons and underwater plants
  337. uint16_t flags = file.readU16();
  338. // TODO store static meshes somewhere
  339. }
  340. }
  341. void LoaderTR2::loadTextures() {
  342. uint32_t numObjectTextures = file.readU32();
  343. for (unsigned int o = 0; o < numObjectTextures; o++) {
  344. // 0 means that a texture is all-opaque, and that transparency
  345. // information is ignored.
  346. // 1 means that transparency information is used. In 8-bit color,
  347. // index 0 is the transparent color, while in 16-bit color, the
  348. // top bit (0x8000) is the alpha channel (1 = opaque, 0 = transparent)
  349. uint16_t attribute = file.readU16();
  350. // Index into the textile list
  351. uint16_t tile = file.readU16();
  352. // The four corner vertices of the texture
  353. // The Pixel values are the actual coordinates of the vertexs pixel
  354. // The Coordinate values depend on where the other vertices are in
  355. // the object texture. And if the object texture is used to specify
  356. // a triangle, then the fourth vertexs values will all be zero
  357. // Coordinate is 1 if Pixel is the low val, 255 if high val in object texture
  358. uint8_t xCoordinate1 = file.readU8();
  359. uint8_t xPixel1 = file.readU8();
  360. uint8_t yCoordinate1 = file.readU8();
  361. uint8_t yPixel1 = file.readU8();
  362. uint8_t xCoordinate2 = file.readU8();
  363. uint8_t xPixel2 = file.readU8();
  364. uint8_t yCoordinate2 = file.readU8();
  365. uint8_t yPixel2 = file.readU8();
  366. uint8_t xCoordinate3 = file.readU8();
  367. uint8_t xPixel3 = file.readU8();
  368. uint8_t yCoordinate3 = file.readU8();
  369. uint8_t yPixel3 = file.readU8();
  370. uint8_t xCoordinate4 = file.readU8();
  371. uint8_t xPixel4 = file.readU8();
  372. uint8_t yCoordinate4 = file.readU8();
  373. uint8_t yPixel4 = file.readU8();
  374. // TODO store object textures somewhere
  375. }
  376. }
  377. void LoaderTR2::loadSprites() {
  378. uint32_t numSpriteTextures = file.readU32();
  379. for (unsigned int s = 0; s < numSpriteTextures; s++) {
  380. uint16_t tile = file.readU16();
  381. uint8_t x = file.readU8();
  382. uint8_t y = file.readU8();
  383. uint16_t width = file.readU16(); // Actually (width * 256) + 255
  384. uint16_t height = file.readU16(); // Actually (height * 256) + 255
  385. int16_t leftSide = file.read16();
  386. int16_t topSide = file.read16();
  387. int16_t rightSide = file.read16();
  388. int16_t bottomSide = file.read16();
  389. // TODO store sprite textures somewhere
  390. }
  391. uint32_t numSpriteSequences = file.readU32();
  392. for (unsigned int s = 0; s < numSpriteSequences; s++) {
  393. int32_t objectID = file.read32(); // Item identifier, matched in Items[]
  394. int16_t negativeLength = file.read16(); // Negative sprite count
  395. int16_t offset = file.read16(); // Where sequence starts in sprite texture list
  396. // TODO store sprite sequences somewhere
  397. }
  398. }
  399. void LoaderTR2::loadCameras() {
  400. uint32_t numCameras = file.readU32();
  401. for (unsigned int c = 0; c < numCameras; c++) {
  402. int32_t x = file.read32();
  403. int32_t y = file.read32();
  404. int32_t z = file.read32();
  405. int16_t room = file.read16();
  406. file.seek(file.tell() + 2); // Unknown, correlates to Boxes? Zones?
  407. // TODO store cameras somewhere
  408. }
  409. }
  410. void LoaderTR2::loadSoundSources() {
  411. uint32_t numSoundSources = file.readU32();
  412. for (unsigned int s = 0; s < numSoundSources; s++) {
  413. // Absolute world coordinate positions of sound source
  414. int32_t x = file.read32();
  415. int32_t y = file.read32();
  416. int32_t z = file.read32();
  417. // Internal sound index
  418. uint16_t soundID = file.readU16();
  419. // Unknown, 0x40, 0x80 or 0xC0
  420. uint16_t flags = file.readU16();
  421. // TODO store sound sources somewhere
  422. }
  423. }
  424. void LoaderTR2::loadBoxesOverlapsZones() {
  425. uint32_t numBoxes = file.readU32();
  426. for (unsigned int b = 0; b < numBoxes; b++) {
  427. // Sectors (* 1024 units)
  428. uint8_t zMin = file.readU8();
  429. uint8_t zMax = file.readU8();
  430. uint8_t xMin = file.readU8();
  431. uint8_t xMax = file.readU8();
  432. int16_t trueFloor = file.read16(); // Y value (no scaling)
  433. // Index into overlaps[]. The high bit is sometimes set
  434. // this occurs in front of swinging doors and the like
  435. int16_t overlapIndex = file.read16();
  436. // TODO store boxes somewhere
  437. }
  438. uint32_t numOverlaps = file.readU32();
  439. std::vector<uint16_t> overlaps;
  440. for (unsigned int o = 0; o < numOverlaps; o++) {
  441. overlaps.push_back(file.readU16());
  442. }
  443. // TODO store overlaps somewhere
  444. std::vector<int16_t> zones;
  445. for (unsigned int z = 0; z < numBoxes; z++) {
  446. for (unsigned int i = 0; i < 10; i++) {
  447. zones.push_back(file.read16());
  448. }
  449. }
  450. // TODO store zones somewhere
  451. }
  452. void LoaderTR2::loadAnimatedTextures() {
  453. uint32_t numAnimatedTextures = file.readU32();
  454. std::vector<uint16_t> animatedTextures;
  455. for (unsigned int a = 0; a < numAnimatedTextures; a++) {
  456. animatedTextures.push_back(file.readU16());
  457. }
  458. // TODO store animated textures somewhere. Format?
  459. }
  460. void LoaderTR2::loadItems() {
  461. uint32_t numItems = file.readU32();
  462. for (unsigned int i = 0; i < numItems; i++) {
  463. int16_t objectID = file.read16();
  464. int16_t room = file.read16();
  465. // Item position in world coordinates
  466. int32_t x = file.read32();
  467. int32_t y = file.read32();
  468. int32_t z = file.read32();
  469. int16_t angle = file.read16(); // (0xC000 >> 14) * 90deg
  470. int16_t intensity1 = file.read16(); // Constant lighting; -1 means mesh lighting
  471. int16_t intensity2 = file.read16(); // Almost always like intensity1
  472. // 0x0100 - Initially visible
  473. // 0x3E00 - Activation mask, open, can be XORed with related FloorData list fields.
  474. uint16_t flags = file.readU16();
  475. // TODO store items somewhere
  476. }
  477. }
  478. void LoaderTR2::loadCinematicFrames() {
  479. uint16_t numCinematicFrames = file.readU16();
  480. for (unsigned int c = 0; c < numCinematicFrames; c++) {
  481. int16_t rotY = file.read16(); // Y rotation, +-32767 = +-180deg
  482. int16_t rotZ = file.read16(); // Z rotation, like rotY
  483. int16_t rotZ2 = file.read16(); // Like rotZ?
  484. int16_t posZ = file.read16(); // Camera pos relative to what?
  485. int16_t posY = file.read16();
  486. int16_t posX = file.read16();
  487. int16_t unknown = file.read16(); // Changing this can cause runtime error
  488. int16_t rotX = file.read16(); // X rotation, like rotY
  489. // TODO store cinematic frames somewhere
  490. }
  491. }
  492. void LoaderTR2::loadDemoData() {
  493. uint16_t numDemoData = file.readU16();
  494. for (unsigned int d = 0; d < numDemoData; d++)
  495. file.readU8();
  496. // TODO store demo data somewhere, find out meaning
  497. }
  498. void LoaderTR2::loadSoundMap() {
  499. std::array<int16_t, 370> soundMap;
  500. for (auto& x : soundMap) {
  501. x = file.read16();
  502. }
  503. // TODO store sound map somewhere
  504. }
  505. void LoaderTR2::loadSoundDetails() {
  506. uint32_t numSoundDetails = file.readU32();
  507. for (unsigned int s = 0; s < numSoundDetails; s++) {
  508. int16_t sample = file.read16(); // Index into SampleIndices[]
  509. int16_t volume = file.read16();
  510. // sound range? distance at which this sound can be heard?
  511. int16_t unknown1 = file.read16();
  512. // Bits 8-15: priority?
  513. // Bits 2-7: number of samples in this group
  514. // Bits 0-1: channel number?
  515. int16_t unknown2 = file.read16();
  516. // TODO store sound details somewhere
  517. }
  518. }
  519. void LoaderTR2::loadSampleIndices() {
  520. uint32_t numSampleIndices = file.readU32();
  521. std::vector<uint32_t> sampleIndices;
  522. for (unsigned int i = 0; i < numSampleIndices; i++) {
  523. sampleIndices.push_back(file.readU32());
  524. }
  525. // TODO store sample indices somewhere
  526. }