Open Source Tomb Raider Engine
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

LoaderTR2.cpp 38KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  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 "Game.h"
  12. #include "Log.h"
  13. #include "Mesh.h"
  14. #include "Room.h"
  15. #include "SoundManager.h"
  16. #include "TextureManager.h"
  17. #include "World.h"
  18. #include "math/Vec3.h"
  19. #include "system/Sound.h"
  20. #include "utils/pixel.h"
  21. #include "loader/LoaderTR2.h"
  22. LoaderTR2::LoaderTR2() {
  23. }
  24. LoaderTR2::~LoaderTR2() {
  25. }
  26. int LoaderTR2::load(std::string f) {
  27. if (file.open(f) != 0) {
  28. return 1; // Could not open file
  29. }
  30. if (file.readU32() != 0x2D) {
  31. return 2; // Not a TR2 level?!
  32. }
  33. loadPaletteTextiles();
  34. file.seek(file.tell() + 4); // Unused value?
  35. loadRooms();
  36. loadFloorData();
  37. loadMeshes();
  38. loadMoveables();
  39. loadStaticMeshes();
  40. loadTextures();
  41. loadSprites();
  42. loadCameras();
  43. loadSoundSources();
  44. loadBoxesOverlapsZones();
  45. loadAnimatedTextures();
  46. loadItems();
  47. file.seek(file.tell() + 8192); // Skip Light map, only for 8bit coloring
  48. loadCinematicFrames();
  49. loadDemoData();
  50. loadSoundMap();
  51. loadSoundDetails();
  52. loadSampleIndices();
  53. loadExternalSoundFile(f);
  54. return 0; // TODO Not finished with implementation!
  55. }
  56. // ---- Textures ----
  57. void LoaderTR2::loadPaletteTextiles() {
  58. file.seek(file.tell() + 768); // Skip 8bit palette, 256 * 3 bytes
  59. // Read the 16bit palette, 256 * 4 bytes, RGBA, A unused
  60. std::array<uint32_t, 256> palette; //!< RGBA, A unused
  61. for (auto& x : palette)
  62. x = file.readU32();
  63. // TODO store palette somewhere?
  64. uint32_t numTextiles = file.readU32();
  65. file.seek(file.tell() + (numTextiles * 256 * 256)); // Skip 8bit textiles
  66. // Read the 16bit textiles, numTextiles * 256 * 256 * 2 bytes
  67. for (unsigned int i = 0; i < numTextiles; i++) {
  68. std::array<uint8_t, 256 * 256 * 2> arr;
  69. for (auto& x : arr) {
  70. x = file.readU8();
  71. }
  72. // Convert 16bit textile to 32bit textile
  73. unsigned char* img = argb16to32(&arr[0], 256, 256);
  74. int r = getTextureManager().loadBufferSlot(img, 256, 256, ARGB, 32,
  75. TextureManager::TextureStorage::GAME, i);
  76. assert(r >= 0); //! \fixme properly handle error when texture could not be loaded!
  77. delete [] img;
  78. }
  79. if (numTextiles > 0)
  80. getLog() << "LoaderTR2: Found " << numTextiles << " Textures!" << Log::endl;
  81. else
  82. getLog() << "LoaderTR2: No Textures in this level?!" << Log::endl;
  83. }
  84. void LoaderTR2::loadTextures() {
  85. uint32_t numObjectTextures = file.readU32();
  86. for (unsigned int o = 0; o < numObjectTextures; o++) {
  87. // 0 means that a texture is all-opaque, and that transparency
  88. // information is ignored.
  89. // 1 means that transparency information is used. In 8-bit color,
  90. // index 0 is the transparent color, while in 16-bit color, the
  91. // top bit (0x8000) is the alpha channel (1 = opaque, 0 = transparent)
  92. uint16_t attribute = file.readU16();
  93. // Index into the textile list
  94. uint16_t tile = file.readU16();
  95. TextureTile* t = new TextureTile(attribute, tile);
  96. // The four corner vertices of the texture
  97. // The Pixel values are the actual coordinates of the vertexs pixel
  98. // The Coordinate values depend on where the other vertices are in
  99. // the object texture. And if the object texture is used to specify
  100. // a triangle, then the fourth vertexs values will all be zero
  101. // Coordinate is 1 if Pixel is the low val, 255 if high val in object texture
  102. for (int i = 0; i < 4; i++) {
  103. uint8_t xCoordinate = file.readU8();
  104. uint8_t xPixel = file.readU8();
  105. uint8_t yCoordinate = file.readU8();
  106. uint8_t yPixel = file.readU8();
  107. assert((xCoordinate == 1) || (xCoordinate == 255) || (xCoordinate == 0));
  108. assert((yCoordinate == 1) || (yCoordinate == 255) || (yCoordinate == 0));
  109. t->add(new TextureTileVertex(xCoordinate, xPixel, yCoordinate, yPixel));
  110. }
  111. getTextureManager().addTile(t);
  112. }
  113. if (numObjectTextures > 0)
  114. getLog() << "LoaderTR2: Found " << numObjectTextures << " Textiles!" << Log::endl;
  115. else
  116. getLog() << "LoaderTR2: No Textiles in this level?!" << Log::endl;
  117. }
  118. void LoaderTR2::loadAnimatedTextures() {
  119. uint32_t numWords = file.readU32() - 1;
  120. uint16_t numAnimatedTextures = file.readU16();
  121. std::vector<uint16_t> animatedTextures;
  122. for (unsigned int a = 0; a < numWords; a++) {
  123. animatedTextures.push_back(file.readU16());
  124. }
  125. int pos = 0;
  126. for (unsigned int a = 0; a < numAnimatedTextures; a++) {
  127. int count = animatedTextures.at(pos) + 1;
  128. if ((pos + count) >= numWords) {
  129. getLog() << "LoaderTR2: Invalid AnimatedTextures ("
  130. << pos + count << " >= " << numWords << ")!" << Log::endl;
  131. return;
  132. }
  133. for (int i = 0; i < count; i++) {
  134. getTextureManager().addAnimatedTile(a, animatedTextures.at(pos + i + 1));
  135. }
  136. pos += count + 1;
  137. }
  138. if ((numAnimatedTextures > 0) || (numWords > 0))
  139. getLog() << "LoaderTR2: Found " << numAnimatedTextures << " Animated Textures!" << Log::endl;
  140. if (pos != numWords)
  141. getLog() << "LoaderTR2: Extra bytes at end of AnimatedTextures?!" << Log::endl;
  142. }
  143. // ---- Rooms ----
  144. void LoaderTR2::loadRooms() {
  145. uint16_t numRooms = file.readU16();
  146. for (unsigned int i = 0; i < numRooms; i++) {
  147. // Room Header
  148. int32_t xOffset = file.read32();
  149. int32_t zOffset = file.read32();
  150. int32_t yBottom = file.read32(); // lowest point == largest y value
  151. int32_t yTop = file.read32(); // highest point == smallest y value
  152. // Number of data words (2 bytes) to follow
  153. uint32_t dataToFollow = file.readU32();
  154. uint16_t numVertices = file.readU16();
  155. std::vector<Vec3> vertices;
  156. for (unsigned int v = 0; v < numVertices; v++) {
  157. // Vertex coordinates, relative to x/zOffset
  158. int16_t x = file.read16();
  159. int16_t y = file.read16();
  160. int16_t z = file.read16();
  161. int16_t light1 = file.read16();
  162. // Set of flags for special rendering effects
  163. // 0x8000 - Something to do with water surface?
  164. // 0x4000 - Underwater lighting modulation/movement if seen from above
  165. // 0x2000 - Water/Quicksand surface movement
  166. // 0x0010 - Normal?
  167. uint16_t attributes = file.readU16();
  168. int16_t light2 = file.read16(); // Almost always equal to light1
  169. vertices.emplace_back(x, y, z);
  170. }
  171. Room* room = new Room();
  172. uint16_t numRectangles = file.readU16();
  173. for (unsigned int r = 0; r < numRectangles; r++) {
  174. // Indices into the vertex list read just before
  175. uint16_t vertex1 = file.readU16();
  176. uint16_t vertex2 = file.readU16();
  177. uint16_t vertex3 = file.readU16();
  178. uint16_t vertex4 = file.readU16();
  179. // Index into the object-texture list
  180. uint16_t texture = file.readU16();
  181. room->getMesh().addTexturedRectangle(vertices.at(vertex1), vertices.at(vertex2),
  182. vertices.at(vertex3), vertices.at(vertex4),
  183. texture);
  184. }
  185. uint16_t numTriangles = file.readU16();
  186. for (unsigned int t = 0; t < numTriangles; t++) {
  187. // Indices into the room vertex list
  188. uint16_t vertex1 = file.readU16();
  189. uint16_t vertex2 = file.readU16();
  190. uint16_t vertex3 = file.readU16();
  191. // Index into the object-texture list
  192. uint16_t texture = file.readU16();
  193. room->getMesh().addTexturedTriangle(vertices.at(vertex1), vertices.at(vertex2),
  194. vertices.at(vertex3), texture);
  195. }
  196. uint16_t numSprites = file.readU16();
  197. for (unsigned int s = 0; s < numSprites; s++) {
  198. uint16_t vertex = file.readU16(); // Index into vertex list
  199. uint16_t sprite = file.readU16(); // Index into sprite list
  200. // TODO store sprites somewhere
  201. }
  202. uint16_t numPortals = file.readU16();
  203. for (unsigned int p = 0; p < numPortals; p++) {
  204. // Which room this portal leads to
  205. uint16_t adjoiningRoom = file.readU16();
  206. // Which way the portal faces
  207. // The normal points away from the adjacent room
  208. // To be seen through, it must point toward the viewpoint
  209. int16_t xNormal = file.read16();
  210. int16_t yNormal = file.read16();
  211. int16_t zNormal = file.read16();
  212. // The corners of this portal
  213. // The right-hand rule applies with respect to the normal
  214. int16_t xCorner1 = file.read16();
  215. int16_t yCorner1 = file.read16();
  216. int16_t zCorner1 = file.read16();
  217. int16_t xCorner2 = file.read16();
  218. int16_t yCorner2 = file.read16();
  219. int16_t zCorner2 = file.read16();
  220. int16_t xCorner3 = file.read16();
  221. int16_t yCorner3 = file.read16();
  222. int16_t zCorner3 = file.read16();
  223. int16_t xCorner4 = file.read16();
  224. int16_t yCorner4 = file.read16();
  225. int16_t zCorner4 = file.read16();
  226. // TODO store portals somewhere
  227. }
  228. uint16_t numZSectors = file.readU16();
  229. uint16_t numXSectors = file.readU16();
  230. for (unsigned int s = 0; s < (numZSectors * numXSectors); s++) {
  231. // Sectors are 1024*1024 world coordinates. Floor and Ceiling are
  232. // signed numbers of 256 units of height.
  233. // Floor/Ceiling value of 0x81 is used to indicate impenetrable
  234. // walls around the sector.
  235. // Floor values are used by the original engine to determine
  236. // what objects can be traversed and how. Relative steps of 1 (256)
  237. // can be walked up, 2..7 must be jumped up, larger than 7 is too high
  238. // If RoomAbove/Below is not none, the Ceiling/Floor is a collisional
  239. // portal to that room
  240. uint16_t indexFloorData = file.readU16();
  241. uint16_t indexBox = file.readU16(); // 0xFFFF if none
  242. uint8_t roomBelow = file.readU8(); // 0xFF if none
  243. int8_t floor = file.read8(); // Absolute height of floor (divided by 256)
  244. uint8_t roomAbove = file.readU8(); // 0xFF if none
  245. int8_t ceiling = file.read8(); // Absolute height of ceiling (/ 256)
  246. // TODO store sectors somewhere
  247. }
  248. int16_t intensity1 = file.read16();
  249. int16_t intensity2 = file.read16();
  250. int16_t lightMode = file.read16();
  251. uint16_t numLights = file.readU16();
  252. for (unsigned int l = 0; l < numLights; l++) {
  253. // Position of light, in world coordinates
  254. int32_t x = file.read32();
  255. int32_t y = file.read32();
  256. int32_t z = file.read32();
  257. uint16_t intensity1 = file.readU16();
  258. uint16_t intensity2 = file.readU16(); // Almost always equal to intensity1
  259. uint32_t fade1 = file.readU32(); // Falloff value?
  260. uint32_t fade2 = file.readU32(); // Falloff value?
  261. // TODO store light somewhere
  262. }
  263. uint16_t numStaticMeshes = file.readU16();
  264. for (unsigned int s = 0; s < numStaticMeshes; s++) {
  265. // Absolute position in world coordinates
  266. int32_t x = file.read32();
  267. int32_t y = file.read32();
  268. int32_t z = file.read32();
  269. // High two bits (0xC000) indicate steps of
  270. // 90 degrees (eg. (rotation >> 14) * 90)
  271. uint16_t rotation = file.readU16();
  272. // Constant lighting, 0xFFFF means use mesh lighting
  273. uint16_t intensity1 = file.readU16();
  274. uint16_t intensity2 = file.readU16();
  275. // Which StaticMesh item to draw
  276. uint16_t objectID = file.readU16();
  277. // TODO store static meshes somewhere
  278. }
  279. int16_t alternateRoom = file.read16();
  280. uint16_t flags = file.readU16();
  281. getWorld().addRoom(room);
  282. }
  283. if (numRooms > 0)
  284. getLog() << "LoaderTR2: Found " << numRooms << " Rooms!" << Log::endl;
  285. else
  286. getLog() << "LoaderTR2: No Rooms in this Level?!" << Log::endl;
  287. }
  288. void LoaderTR2::loadFloorData() {
  289. uint32_t numFloorData = file.readU32();
  290. for (unsigned int f = 0; f < numFloorData; f++) {
  291. uint16_t unused = file.readU16();
  292. // TODO store floor data somewhere
  293. }
  294. if (numFloorData > 0)
  295. getLog() << "LoaderTR2: Found " << numFloorData << " words FloorData, unimplemented!" << Log::endl;
  296. }
  297. void LoaderTR2::loadSprites() {
  298. uint32_t numSpriteTextures = file.readU32();
  299. std::vector<Sprite> sprites;
  300. for (unsigned int s = 0; s < numSpriteTextures; s++) {
  301. uint16_t tile = file.readU16();
  302. uint8_t x = file.readU8();
  303. uint8_t y = file.readU8();
  304. uint16_t width = file.readU16(); // Actually (width * 256) + 255
  305. uint16_t height = file.readU16(); // Actually (height * 256) + 255
  306. // Required for what?
  307. int16_t leftSide = file.read16();
  308. int16_t topSide = file.read16();
  309. int16_t rightSide = file.read16();
  310. int16_t bottomSide = file.read16();
  311. sprites.emplace_back(tile, x, y, width, height);
  312. }
  313. uint32_t numSpriteSequences = file.readU32();
  314. for (unsigned int s = 0; s < numSpriteSequences; s++) {
  315. int32_t objectID = file.read32(); // Item identifier, matched in Items[]
  316. int16_t negativeLength = file.read16(); // Negative sprite count
  317. int16_t offset = file.read16(); // Where sequence starts in sprite texture list
  318. assert(negativeLength < 0);
  319. assert(offset >= 0);
  320. assert((offset + (negativeLength * -1)) <= numSpriteTextures);
  321. SpriteSequence* ss = new SpriteSequence(objectID);
  322. for (int i = 0; i < (negativeLength * -1); i++) {
  323. ss->add(sprites.at(offset + i));
  324. }
  325. getWorld().addSprite(ss);
  326. }
  327. if ((numSpriteTextures > 0) || (numSpriteSequences > 0))
  328. getLog() << "LoaderTR2: Found " << numSpriteTextures << " Sprites in " << numSpriteSequences <<
  329. " Sequences!" << Log::endl;
  330. else
  331. getLog() << "LoaderTR2: No Sprites in this level?!" << Log::endl;
  332. }
  333. // ---- Meshes ----
  334. void LoaderTR2::loadMeshes() {
  335. // Number of bitu16s of mesh data to follow
  336. // Read all the mesh data into a buffer, because
  337. // only afterward we can read the number of meshes
  338. // in this data block
  339. uint32_t numMeshData = file.readU32();
  340. std::vector<uint16_t> buffer;
  341. for (unsigned int i = 0; i < numMeshData; i++) {
  342. buffer.push_back(file.readU16());
  343. }
  344. uint32_t numMeshPointers = file.readU32();
  345. if ((numMeshData == 0) || (numMeshPointers == 0)) {
  346. getLog() << "LoaderTR2: No mesh data found!" << Log::endl;
  347. return;
  348. }
  349. for (unsigned int i = 0; i < numMeshPointers; i++) {
  350. uint32_t meshPointer = file.readU32();
  351. char* tmpPtr = reinterpret_cast<char*>(&buffer[meshPointer / 2]);
  352. BinaryMemory mem(tmpPtr, (numMeshData * 2) - meshPointer);
  353. int16_t mx = mem.read16();
  354. int16_t my = mem.read16();
  355. int16_t mz = mem.read16();
  356. int32_t collisionSize = mem.read32();
  357. // TODO store mesh collision info somewhere
  358. uint16_t numVertices = mem.readU16();
  359. std::vector<Vec3> vertices;
  360. for (int v = 0; v < numVertices; v++) {
  361. int16_t x = mem.read16();
  362. int16_t y = mem.read16();
  363. int16_t z = mem.read16();
  364. vertices.emplace_back(x, y, z);
  365. }
  366. int16_t numNormals = mem.read16();
  367. if (numNormals > 0) {
  368. // External vertex lighting is used, with the lighting calculated
  369. // from the rooms ambient and point-source lighting values. The
  370. // latter appears to use a simple Lambert law for directionality:
  371. // intensity is proportional to
  372. // max((normal direction).(direction to source), 0)
  373. for (int n = 0; n < numNormals; n++) {
  374. int16_t x = mem.read16();
  375. int16_t y = mem.read16();
  376. int16_t z = mem.read16();
  377. // TODO store normals somewhere
  378. }
  379. } else if (numNormals < 0) {
  380. // Internal vertex lighting is used,
  381. // using the data included with the mesh
  382. for (int l = 0; l < (numNormals * -1); l++) {
  383. int16_t light = mem.read16();
  384. // TODO store lights somewhere
  385. }
  386. }
  387. Mesh* mesh = new Mesh();
  388. int16_t numTexturedRectangles = mem.read16();
  389. for (int r = 0; r < numTexturedRectangles; r++) {
  390. uint16_t vertex1 = mem.readU16();
  391. uint16_t vertex2 = mem.readU16();
  392. uint16_t vertex3 = mem.readU16();
  393. uint16_t vertex4 = mem.readU16();
  394. uint16_t texture = mem.readU16();
  395. mesh->addTexturedRectangle(vertices.at(vertex1), vertices.at(vertex2),
  396. vertices.at(vertex3), vertices.at(vertex4),
  397. texture);
  398. }
  399. int16_t numTexturedTriangles = mem.read16();
  400. for (int t = 0; t < numTexturedTriangles; t++) {
  401. uint16_t vertex1 = mem.readU16();
  402. uint16_t vertex2 = mem.readU16();
  403. uint16_t vertex3 = mem.readU16();
  404. uint16_t texture = mem.readU16();
  405. mesh->addTexturedTriangle(vertices.at(vertex1), vertices.at(vertex2),
  406. vertices.at(vertex3), texture);
  407. }
  408. int16_t numColoredRectangles = mem.read16();
  409. for (int r = 0; r < numColoredRectangles; r++) {
  410. uint16_t vertex1 = mem.readU16();
  411. uint16_t vertex2 = mem.readU16();
  412. uint16_t vertex3 = mem.readU16();
  413. uint16_t vertex4 = mem.readU16();
  414. uint16_t texture = mem.readU16();
  415. // TODO color?
  416. mesh->addColoredRectangle(vertices.at(vertex1), vertices.at(vertex2),
  417. vertices.at(vertex3), vertices.at(vertex4),
  418. texture);
  419. }
  420. int16_t numColoredTriangles = mem.read16();
  421. for (int t = 0; t < numColoredTriangles; t++) {
  422. uint16_t vertex1 = mem.readU16();
  423. uint16_t vertex2 = mem.readU16();
  424. uint16_t vertex3 = mem.readU16();
  425. uint16_t texture = mem.readU16();
  426. // TODO color?
  427. mesh->addColoredTriangle(vertices.at(vertex1), vertices.at(vertex2),
  428. vertices.at(vertex3), texture);
  429. }
  430. getWorld().addMesh(mesh);
  431. }
  432. if (numMeshPointers > 0)
  433. getLog() << "LoaderTR2: Found " << numMeshPointers << " Meshes, unimplemented!" << Log::endl;
  434. }
  435. void LoaderTR2::loadStaticMeshes() {
  436. uint32_t numStaticMeshes = file.readU32();
  437. for (unsigned int s = 0; s < numStaticMeshes; s++) {
  438. uint32_t objectID = file.readU32(); // Matched in Items[]
  439. uint16_t mesh = file.readU16(); // Offset into MeshPointers[]
  440. // tr2_vertex BoundingBox[2][2];
  441. // First index is which one, second index is opposite corners
  442. int16_t x11 = file.read16();
  443. int16_t y11 = file.read16();
  444. int16_t z11 = file.read16();
  445. int16_t x12 = file.read16();
  446. int16_t y12 = file.read16();
  447. int16_t z12 = file.read16();
  448. int16_t x21 = file.read16();
  449. int16_t y21 = file.read16();
  450. int16_t z21 = file.read16();
  451. int16_t x22 = file.read16();
  452. int16_t y22 = file.read16();
  453. int16_t z22 = file.read16();
  454. // Meaning uncertain. Usually 2, and 3 for objects Lara can
  455. // travel through, like TR2s skeletons and underwater plants
  456. uint16_t flags = file.readU16();
  457. getWorld().addStaticMesh(new StaticMesh(objectID, mesh));
  458. }
  459. if (numStaticMeshes > 0)
  460. getLog() << "LoaderTR2: Found " << numStaticMeshes << " StaticMeshes, unimplemented!" << Log::endl;
  461. else
  462. getLog() << "LoaderTR2: No StaticMeshes in this level?!" << Log::endl;
  463. }
  464. // ---- Moveables ----
  465. struct Animation_t {
  466. uint32_t frameOffset;
  467. uint8_t frameRate, frameSize;
  468. uint16_t stateID, frameStart, frameEnd, nextAnimation;
  469. uint16_t nextFrame, numStateChanges, stateChangeOffset;
  470. uint16_t numAnimCommands, animCommandOffset;
  471. Animation_t(uint32_t fo, uint8_t fr, uint8_t fs, uint16_t si,
  472. uint16_t fst, uint16_t fe, uint16_t na, uint16_t nf,
  473. uint16_t ns, uint16_t so, uint16_t nac, uint16_t ao)
  474. : frameOffset(fo), frameRate(fr), frameSize(fs),
  475. stateID(si), frameStart(fst), frameEnd(fe), nextAnimation(na),
  476. nextFrame(nf), numStateChanges(ns), stateChangeOffset(so),
  477. numAnimCommands(nac), animCommandOffset(ao) { }
  478. };
  479. struct StateChange_t {
  480. uint16_t stateID, numAnimDispatches, animDispatchOffset;
  481. StateChange_t(uint16_t s, uint16_t n, uint16_t a)
  482. : stateID(s), numAnimDispatches(n), animDispatchOffset(a) { }
  483. };
  484. struct AnimDispatch_t {
  485. int16_t low, high, nextAnimation, nextFrame;
  486. AnimDispatch_t(int16_t l, int16_t h, int16_t na, int16_t nf)
  487. : low(l), high(h), nextAnimation(na), nextFrame(nf) { }
  488. };
  489. void LoaderTR2::loadMoveables() {
  490. uint32_t numAnimations = file.readU32();
  491. std::vector<Animation_t> animations;
  492. for (unsigned int a = 0; a < numAnimations; a++) {
  493. // *Byte* Offset into Frames[] (so divide by 2!)
  494. uint32_t frameOffset = file.readU32();
  495. uint8_t frameRate = file.readU8(); // Engine ticks per frame
  496. // Number of bit16s in Frames[] used by this animation
  497. // Be careful when parsing frames using the FrameSize value
  498. // as the size of each frame, since an animations frame range
  499. // may extend into the next animations frame range, and that
  500. // may have a different FrameSize value.
  501. uint8_t frameSize = file.readU8();
  502. uint16_t stateID = file.readU16();
  503. file.seek(file.tell() + 8); // Skip 8 unknown bytes
  504. uint16_t frameStart = file.readU16(); // First frame in this animation
  505. uint16_t frameEnd = file.readU16(); // Last frame in this animation
  506. uint16_t nextAnimation = file.readU16();
  507. uint16_t nextFrame = file.readU16();
  508. uint16_t numStateChanges = file.readU16();
  509. uint16_t stateChangeOffset = file.readU16(); // Index into StateChanges[]
  510. uint16_t numAnimCommands = file.readU16(); // How many animation commands to use
  511. uint16_t animCommandOffset = file.readU16(); // Index into AnimCommand[]
  512. animations.emplace_back(frameOffset, frameRate, frameSize,
  513. stateID, frameStart, frameEnd, nextAnimation, nextFrame, numStateChanges,
  514. stateChangeOffset, numAnimCommands, animCommandOffset);
  515. }
  516. if (numAnimations > 0)
  517. getLog() << "LoaderTR2: Found " << numAnimations << " Animations!" << Log::endl;
  518. else
  519. getLog() << "LoaderTR2: No Animations in this level?!" << Log::endl;
  520. uint32_t numStateChanges = file.readU32();
  521. std::vector<StateChange_t> stateChanges;
  522. for (unsigned int s = 0; s < numStateChanges; s++) {
  523. uint16_t stateID = file.readU16();
  524. uint16_t numAnimDispatches = file.readU16(); // Number of ranges (always 1..5?)
  525. uint16_t animDispatchOffset = file.readU16(); // Index into AnimDispatches[]
  526. stateChanges.emplace_back(stateID, numAnimDispatches, animDispatchOffset);
  527. }
  528. if (numStateChanges > 0)
  529. getLog() << "LoaderTR2: Found " << numStateChanges << " StateChanges!" << Log::endl;
  530. else
  531. getLog() << "LoaderTR2: No StateChanges in this level?!" << Log::endl;
  532. uint32_t numAnimDispatches = file.readU32();
  533. std::vector<AnimDispatch_t> animDispatches;
  534. for (unsigned int a = 0; a < numAnimDispatches; a++) {
  535. int16_t low = file.read16(); // Lowest frame that uses this range
  536. int16_t high = file.read16(); // Highest frame (+1?) that uses this range
  537. int16_t nextAnimation = file.read16(); // Animation to go to
  538. int16_t nextFrame = file.read16(); // Frame offset to go to
  539. animDispatches.emplace_back(low, high, nextAnimation, nextFrame);
  540. }
  541. if (numAnimDispatches > 0)
  542. getLog() << "LoaderTR2: Found " << numAnimDispatches << " AnimationDispatches!" << Log::endl;
  543. else
  544. getLog() << "LoaderTR2: No AnimationDispatches in this level?!" << Log::endl;
  545. uint32_t numAnimCommands = file.readU32();
  546. std::vector<int16_t> animCommands;
  547. for (unsigned int a = 0; a < numAnimCommands; a++) {
  548. // A list of Opcodes with zero or more operands each,
  549. // some referring to the whole animation (jump/grab points),
  550. // some to specific frames (sound, bubbles, ...).
  551. animCommands.push_back(file.read16());
  552. }
  553. if (numAnimCommands > 0)
  554. getLog() << "LoaderTR2: Found " << numAnimCommands << " AnimationCommands!" << Log::endl;
  555. else
  556. getLog() << "LoaderTR2: No AnimationCommands in this level?!" << Log::endl;
  557. // This is really one uint32_t flags, followed by
  558. // three int32_t x, y, z. However, we're given the number
  559. // of 32bits, as well as byte indices later, so we store
  560. // it as a single list of int32_t.
  561. uint32_t numMeshTrees = file.readU32();
  562. std::vector<int32_t> meshTrees;
  563. for (unsigned int m = 0; m < numMeshTrees; m++) {
  564. // 0x0002 - Put parent mesh on the mesh stack
  565. // 0x0001 - Pop mesh from stack, use as parent mesh
  566. // When both are not set, use previous mesh as parent mesh
  567. // When both are set, do 0x0001 first, then 0x0002, thereby
  568. // reading the stack but not changing it
  569. //uint32_t flags = file.readU32();
  570. // Offset of mesh origin from the parent mesh origin
  571. //int32_t x = file.read32();
  572. //int32_t y = file.read32();
  573. //int32_t z = file.read32();
  574. meshTrees.push_back(file.read32());
  575. }
  576. if (numMeshTrees > 0)
  577. getLog() << "LoaderTR2: Found " << numMeshTrees << " MeshTrees!" << Log::endl;
  578. else
  579. getLog() << "LoaderTR2: No MeshTrees in this level?!" << Log::endl;
  580. uint32_t numFrames = file.readU32();
  581. std::vector<uint16_t> frames;
  582. for (unsigned int f = 0; f < numFrames; f++) {
  583. // int16 bb1x, bb1y, bb1z
  584. // int16 bb2x, bb2y, bb2z
  585. // int16 offsetX, offsetY, offsetZ
  586. // What follows next is a list of angles with numMeshes (from Moveable) entries.
  587. // If the top bit (0x8000) of the first uint16 is set, a single X angle follows,
  588. // if the second bit (0x4000) is set, a Y angle follows, both are a Z angle.
  589. // If none is set, it's a three-axis rotation. The next 10 bits (0x3FF0) are
  590. // the X rotation, the next 10 (0x000F 0xFC00) are Y, the next (0x03FF) are
  591. // the Z rotation. The scaling is always 0x100->90deg.
  592. // Rotation order: Y, X, Z!
  593. frames.push_back(file.readU16());
  594. }
  595. if (numFrames > 0)
  596. getLog() << "LoaderTR2: Found " << numFrames << " Frames!" << Log::endl;
  597. else
  598. getLog() << "LoaderTR2: No Frames in this level?!" << Log::endl;
  599. uint32_t numMoveables = file.readU32();
  600. for (unsigned int m = 0; m < numMoveables; m++) {
  601. // Item identifier, matched in Items[]
  602. uint32_t objectID = file.readU32();
  603. uint16_t numMeshes = file.readU16();
  604. uint16_t startingMesh = file.readU16(); // Offset into MeshPointers[]
  605. uint32_t meshTree = file.readU32(); // Offset into MeshTree[]
  606. // *Byte* offset into Frames[] (divide by 2 for Frames[i])
  607. uint32_t frameOffset = file.readU32(); // Only needed if no animation
  608. // If animation index is 0xFFFF, the object is stationary or
  609. // animated by the engine (ponytail)
  610. uint16_t animation = file.readU16();
  611. // TODO load all animations, not only the first frame!
  612. //if (animation == 0xFFFF) {
  613. // Just add the frame indicated in frameOffset, nothing else
  614. char* tmp = reinterpret_cast<char*>(&frames[0]) + frameOffset;
  615. BinaryMemory frame(tmp + 12, (numFrames * 2) - frameOffset - 12); // skip two BBs
  616. float pos[3];
  617. pos[0] = frame.read16();
  618. pos[1] = frame.read16();
  619. pos[2] = frame.read16();
  620. BoneFrame* bf = new BoneFrame(pos);
  621. for (int i = 0; i < numMeshes; i++) {
  622. int mesh = startingMesh + i;
  623. float offset[3] = { 0.0f, 0.0f, 0.0f };
  624. float rotation[3] = { 0.0f, 0.0f, 0.0f };
  625. char flag = (i == 0) ? 2 : 0;
  626. // Nonprimary tag - positioned relative to first tag
  627. if (i != 0) {
  628. tmp = reinterpret_cast<char*>(&meshTrees[0]) + meshTree; // TODO (meshTree * 4)?
  629. tmp += (i - 1) * 16; // TODO ?
  630. BinaryMemory tree(tmp, (numMeshTrees * 4) - meshTree - ((i - 1) * 16));
  631. flag = (char)tree.readU32();
  632. offset[0] = tree.read32();
  633. offset[1] = tree.read32();
  634. offset[2] = tree.read32();
  635. uint16_t a = frame.readU16();
  636. if (a & 0xC000) {
  637. // Single angle
  638. int index = 0;
  639. if ((a & 0x8000) && (a & 0x4000))
  640. index = 2;
  641. else if (a & 0x4000)
  642. index = 1;
  643. rotation[index] = ((float)(a & 0x03FF)) * 360.0f / 1024.0f;
  644. } else {
  645. // Three angles
  646. uint16_t b = frame.readU16();
  647. rotation[0] = (a & 0x3FF0) >> 4;
  648. rotation[1] = ((a & 0x000F) << 6) | ((b & 0xFC00) >> 10);
  649. rotation[2] = b & 0x03FF;
  650. for (int i = 0; i < 3; i++)
  651. rotation[i] = rotation[i] * 360.0f / 1024.0f;
  652. }
  653. }
  654. BoneTag* bt = new BoneTag(mesh, offset, rotation, flag);
  655. bf->add(bt);
  656. }
  657. AnimationFrame* af = new AnimationFrame(0);
  658. af->add(bf);
  659. SkeletalModel* sm = new SkeletalModel(objectID);
  660. sm->add(af);
  661. getWorld().addSkeletalModel(sm);
  662. //} else {
  663. // Add the whole animation hierarchy
  664. //}
  665. }
  666. if (numMoveables > 0)
  667. getLog() << "LoaderTR2: Found " << numMoveables << " Moveables!" << Log::endl;
  668. else
  669. getLog() << "LoaderTR2: No Moveables in this level?!" << Log::endl;
  670. }
  671. void LoaderTR2::loadItems() {
  672. uint32_t numItems = file.readU32();
  673. for (unsigned int i = 0; i < numItems; i++) {
  674. int16_t objectID = file.read16();
  675. int16_t room = file.read16();
  676. // Item position in world coordinates
  677. int32_t x = file.read32();
  678. int32_t y = file.read32();
  679. int32_t z = file.read32();
  680. int16_t angle = file.read16(); // (0xC000 >> 14) * 90deg
  681. int16_t intensity1 = file.read16(); // Constant lighting; -1 means mesh lighting
  682. int16_t intensity2 = file.read16(); // Almost always like intensity1
  683. // 0x0100 - Initially visible
  684. // 0x3E00 - Activation mask, open, can be XORed with related FloorData list fields.
  685. uint16_t flags = file.readU16();
  686. // TODO for now we're only creating Entities for each Moveable Item
  687. for (int m = 0; m < getWorld().sizeSkeletalModel(); m++) {
  688. if (getWorld().getSkeletalModel(m).getId() == objectID) {
  689. float pos[3] = {
  690. static_cast<float>(x),
  691. static_cast<float>(y),
  692. static_cast<float>(z)
  693. };
  694. float rot[3] = {
  695. 0.0f,
  696. OR_DEG_TO_RAD(((angle >> 14) & 0x03) * 90.0f),
  697. 0.0f
  698. };
  699. Entity* e = new Entity(pos, rot, objectID, room, m);
  700. getWorld().addEntity(e);
  701. if (objectID == 0) {
  702. getGame().setLara(getWorld().sizeEntity() - 1);
  703. }
  704. }
  705. }
  706. }
  707. if (numItems > 0)
  708. getLog() << "LoaderTR2: Found " << numItems << " Items, unimplemented!" << Log::endl;
  709. else
  710. getLog() << "LoaderTR2: No Items in this level?!" << Log::endl;
  711. }
  712. void LoaderTR2::loadBoxesOverlapsZones() {
  713. uint32_t numBoxes = file.readU32();
  714. for (unsigned int b = 0; b < numBoxes; b++) {
  715. // Sectors (* 1024 units)
  716. uint8_t zMin = file.readU8();
  717. uint8_t zMax = file.readU8();
  718. uint8_t xMin = file.readU8();
  719. uint8_t xMax = file.readU8();
  720. int16_t trueFloor = file.read16(); // Y value (no scaling)
  721. // Index into overlaps[]. The high bit is sometimes set
  722. // this occurs in front of swinging doors and the like
  723. int16_t overlapIndex = file.read16();
  724. // TODO store boxes somewhere
  725. }
  726. uint32_t numOverlaps = file.readU32();
  727. std::vector<uint16_t> overlaps;
  728. for (unsigned int o = 0; o < numOverlaps; o++) {
  729. overlaps.push_back(file.readU16());
  730. }
  731. // TODO store overlaps somewhere
  732. std::vector<int16_t> zones;
  733. for (unsigned int z = 0; z < numBoxes; z++) {
  734. for (unsigned int i = 0; i < 10; i++) {
  735. zones.push_back(file.read16());
  736. }
  737. }
  738. // TODO store zones somewhere
  739. if ((numBoxes > 0) || (numOverlaps > 0))
  740. getLog() << "LoaderTR2: Found NPC NavigationHints, unimplemented!" << Log::endl;
  741. }
  742. // ---- Sound ----
  743. void LoaderTR2::loadSoundSources() {
  744. uint32_t numSoundSources = file.readU32();
  745. for (unsigned int s = 0; s < numSoundSources; s++) {
  746. // Absolute world coordinate positions of sound source
  747. int32_t x = file.read32();
  748. int32_t y = file.read32();
  749. int32_t z = file.read32();
  750. // Internal sound index
  751. uint16_t soundID = file.readU16();
  752. // Unknown, 0x40, 0x80 or 0xC0
  753. uint16_t flags = file.readU16();
  754. SoundManager::addSoundSource(x, y, z, soundID, flags);
  755. }
  756. if (numSoundSources > 0)
  757. getLog() << "LoaderTR2: Found " << numSoundSources << " SoundSources" << Log::endl;
  758. }
  759. void LoaderTR2::loadSoundMap() {
  760. for (int i = 0; i < 370; i++) {
  761. SoundManager::addSoundMapEntry(file.read16());
  762. }
  763. }
  764. void LoaderTR2::loadSoundDetails() {
  765. uint32_t numSoundDetails = file.readU32();
  766. for (unsigned int s = 0; s < numSoundDetails; s++) {
  767. uint16_t sample = file.readU16(); // Index into SampleIndices[]
  768. uint16_t volume = file.readU16();
  769. // sound range? distance at which this sound can be heard?
  770. uint16_t unknown1 = file.readU16();
  771. // Bits 8-15: priority?
  772. // Bits 2-7: number of samples in this group
  773. // Bits 0-1: channel number?
  774. uint16_t unknown2 = file.readU16();
  775. SoundManager::addSoundDetail(sample, ((float)volume) / 32767.0f);
  776. }
  777. if (numSoundDetails > 0)
  778. getLog() << "LoaderTR2: Found " << numSoundDetails << " SoundDetails" << Log::endl;
  779. }
  780. void LoaderTR2::loadSampleIndices() {
  781. uint32_t numSampleIndices = file.readU32();
  782. for (unsigned int i = 0; i < numSampleIndices; i++) {
  783. SoundManager::addSampleIndex(file.readU32());
  784. }
  785. if (numSampleIndices > 0)
  786. getLog() << "LoaderTR2: Found " << numSampleIndices << " SampleIndices" << Log::endl;
  787. }
  788. void LoaderTR2::loadExternalSoundFile(std::string f) {
  789. size_t dir = f.find_last_of("/\\");
  790. if (dir != std::string::npos) {
  791. f.replace(dir + 1, std::string::npos, "MAIN.SFX");
  792. } else {
  793. f = "MAIN.SFX";
  794. }
  795. BinaryFile sfx;
  796. if (sfx.open(f) != 0) {
  797. getLog() << "LoaderTR2: Can't open \"" << f << "\"!" << Log::endl;
  798. return;
  799. }
  800. int riffCount = 0;
  801. while (!sfx.eof()) {
  802. char test[5];
  803. test[4] = '\0';
  804. for (int i = 0; i < 4; i++)
  805. test[i] = sfx.read8();
  806. if (std::string("RIFF") != std::string(test)) {
  807. getLog() << "LoaderTR2: External SFX invalid! (" << riffCount
  808. << ", \"" << test << "\" != \"RIFF\")" << Log::endl;
  809. return;
  810. }
  811. // riffSize is (fileLength - 8)
  812. uint32_t riffSize = sfx.readU32();
  813. unsigned char buff[riffSize + 8];
  814. sfx.seek(sfx.tell() - 8);
  815. for (int i = 0; i < (riffSize + 8); i++)
  816. buff[i] = sfx.readU8();
  817. unsigned long src;
  818. int ret = Sound::loadBuffer(buff, riffSize + 8);
  819. assert(ret >= 0);
  820. riffCount++;
  821. }
  822. if (riffCount > 0)
  823. getLog() << "LoaderTR2: Found " << riffCount << " SoundSamples in SFX" << Log::endl;
  824. }
  825. // ---- Stuff ----
  826. void LoaderTR2::loadCameras() {
  827. uint32_t numCameras = file.readU32();
  828. for (unsigned int c = 0; c < numCameras; c++) {
  829. int32_t x = file.read32();
  830. int32_t y = file.read32();
  831. int32_t z = file.read32();
  832. int16_t room = file.read16();
  833. file.seek(file.tell() + 2); // Unknown, correlates to Boxes? Zones?
  834. // TODO store cameras somewhere
  835. }
  836. if (numCameras > 0)
  837. getLog() << "LoaderTR2: Found " << numCameras << " Cameras, unimplemented!" << Log::endl;
  838. }
  839. void LoaderTR2::loadCinematicFrames() {
  840. uint16_t numCinematicFrames = file.readU16();
  841. for (unsigned int c = 0; c < numCinematicFrames; c++) {
  842. int16_t rotY = file.read16(); // Y rotation, +-32767 = +-180deg
  843. int16_t rotZ = file.read16(); // Z rotation, like rotY
  844. int16_t rotZ2 = file.read16(); // Like rotZ?
  845. int16_t posZ = file.read16(); // Camera pos relative to what?
  846. int16_t posY = file.read16();
  847. int16_t posX = file.read16();
  848. int16_t unknown = file.read16(); // Changing this can cause runtime error
  849. int16_t rotX = file.read16(); // X rotation, like rotY
  850. // TODO store cinematic frames somewhere
  851. }
  852. if (numCinematicFrames > 0)
  853. getLog() << "LoaderTR2: Found " << numCinematicFrames
  854. << " CinematicFrames, unimplemented!" << Log::endl;
  855. }
  856. void LoaderTR2::loadDemoData() {
  857. uint16_t numDemoData = file.readU16();
  858. for (unsigned int d = 0; d < numDemoData; d++)
  859. file.readU8();
  860. // TODO store demo data somewhere, find out meaning
  861. if (numDemoData > 0)
  862. getLog() << "LoaderTR2: Found " << numDemoData << " bytes DemoData, unimplemented!" <<
  863. Log::endl;
  864. }