Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

LoaderTR2.cpp 46KB

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