OpenRaider  0.1.4-dev
Open Source Tomb Raider Game Engine implementation
LoaderTR1.cpp
Go to the documentation of this file.
1 
8 #include "global.h"
9 #include "Game.h"
10 #include "Log.h"
11 #include "SoundManager.h"
12 #include "World.h"
13 #include "utils/strings.h"
14 #include "loader/LoaderTR1.h"
15 
16 int LoaderTR1::load(std::string f) {
17  if (file.open(f) != 0) {
18  return 1; // Could not open file
19  }
20 
21  uint32_t version = file.readU32();
22  if (version != 0x20) {
23  return 2; // Not a TR1 level?!
24  }
25 
26  bool unfinishedBusiness = stringEndsWith(f, ".tub");
27  if (unfinishedBusiness)
28  Log::get(LOG_INFO) << "LoaderTR1: Detected Unfinished Business level!" << Log::endl;
29 
30  loadTextures();
31 
32  file.seek(file.tell() + 4); // Unused value?
33 
34  loadRooms();
35  loadFloorData();
36  loadMeshes();
37  loadMoveables();
39  loadTextiles();
40  loadSprites();
41 
42  if (unfinishedBusiness)
43  loadPalette();
44 
45  loadCameras();
49  loadItems();
50 
51  file.seek(file.tell() + 8192); // TODO light map!
52 
53  if (!unfinishedBusiness)
54  loadPalette();
55 
57  loadDemoData();
58  loadSoundMap();
61 
62  return 0;
63 }
64 
66  // Read the 8bit palette, 256 * 3 bytes, RGB
67  for (int i = 0; i < 256; i++) {
68  uint8_t r = file.readU8();
69  uint8_t g = file.readU8();
70  uint8_t b = file.readU8();
71 
72  // Color values range from 0 to 63, so multiply by 4
73  static const uint8_t lightFactor = 4;
74  r *= lightFactor;
75  g *= lightFactor;
76  b *= lightFactor;
77 
78  glm::vec4 c(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
80  }
81 }
82 
84  uint32_t numTextures = file.readU32();
85  for (unsigned int i = 0; i < numTextures; i++) {
86  std::array<uint8_t, 256 * 256> arr;
87  for (auto& x : arr) {
88  x = file.readU8(); // Palette index
89  }
90 
91  TextureManager::addIndexedTexture(&arr[0], 256, 256);
92  }
93 
94  if (numTextures > 0)
95  Log::get(LOG_INFO) << "LoaderTR1: Found " << numTextures << " Textures!" << Log::endl;
96  else
97  Log::get(LOG_INFO) << "LoaderTR1: No Textures in this level?!" << Log::endl;
98 }
99 
101  int16_t intensity = file.read16();
102 
103  uint16_t numLights = file.readU16();
104  for (unsigned int l = 0; l < numLights; l++) {
105  // Position of light, in world coordinates
106  int32_t x = file.read32();
107  int32_t y = file.read32();
108  int32_t z = file.read32();
109 
110  uint16_t intensity1 = file.readU16();
111  uint32_t fade = file.readU32(); // Falloff value?
112 
113  // TODO store light somewhere
114  }
115 }
116 
117 void LoaderTR1::loadRoomStaticMeshes(std::vector<StaticModel*>& staticModels) {
118  uint16_t numStaticMeshes = file.readU16();
119  for (unsigned int s = 0; s < numStaticMeshes; s++) {
120  // Absolute position in world coordinates
121  int32_t x = file.read32();
122  int32_t y = file.read32();
123  int32_t z = file.read32();
124 
125  // High two bits (0xC000) indicate steps of
126  // 90 degrees (eg. (rotation >> 14) * 90)
127  uint16_t rotation = file.readU16();
128 
129  // Constant lighting, 0xFFFF means use mesh lighting
131  uint16_t intensity1 = file.readU16();
132 
133  // Which StaticMesh item to draw
134  uint16_t objectID = file.readU16();
135 
136  staticModels.push_back(new StaticModel(glm::vec3(x, y, z),
137  glm::radians((rotation >> 14) * 90.0f),
138  objectID));
139  }
140 }
141 
143  vert.x = file.read16();
144  vert.y = file.read16();
145  vert.z = file.read16();
146  vert.light1 = file.read16();
147  vert.attributes = 0;
148  vert.light2 = vert.light1;
149 }
150 
152  uint32_t numItems = file.readU32();
153  for (unsigned int i = 0; i < numItems; i++) {
154  int16_t objectID = file.read16();
155  int16_t room = file.read16();
156 
157  // Item position in world coordinates
158  int32_t x = file.read32();
159  int32_t y = file.read32();
160  int32_t z = file.read32();
161 
162  uint16_t angle = file.readU16(); // (0xC000 >> 14) * 90deg
163  int16_t intensity = file.read16(); // Constant lighting; -1 means mesh lighting
164 
165  // 0x0100 - Initially visible
166  // 0x3E00 - Activation mask, open, can be XORed with related FloorData list fields.
167  uint16_t flags = file.readU16();
168 
169  glm::vec3 pos(
170  static_cast<float>(x),
171  static_cast<float>(y),
172  static_cast<float>(z)
173  );
174 
175  glm::vec3 rot(
176  0.0f,
177  glm::radians(((angle >> 14) & 0x03) * 90.0f),
178  0.0f
179  );
180 
181  Entity* e = new Entity(objectID, room, pos, rot);
182  getWorld().addEntity(e);
183 
184  if (objectID == 0) {
185  Game::setLara(getWorld().sizeEntity() - 1);
186  }
187  }
188 
189  if (numItems > 0)
190  Log::get(LOG_INFO) << "LoaderTR1: Found " << numItems << " Items!" << Log::endl;
191  else
192  Log::get(LOG_INFO) << "LoaderTR1: No Items in this level?!" << Log::endl;
193 }
194 
196  uint32_t numBoxes = file.readU32();
197  for (unsigned int b = 0; b < numBoxes; b++) {
198  // Sectors (not scaled!)
199  int32_t zMin = file.read32();
200  int32_t zMax = file.read32();
201  int32_t xMin = file.read32();
202  int32_t xMax = file.read32();
203 
204  int16_t trueFloor = file.read16(); // Y value (no scaling)
205 
206  // Index into overlaps[]. The high bit is sometimes set
207  // this occurs in front of swinging doors and the like
208  uint16_t overlapIndex = file.readU16();
209 
210  // TODO store boxes somewhere
211  }
212 
213  uint32_t numOverlaps = file.readU32();
214  std::vector<std::vector<uint16_t>> overlaps;
215  overlaps.emplace_back();
216  unsigned int list = 0;
217  for (unsigned int o = 0; o < numOverlaps; o++) {
218  // Apparently used by NPCs to decide where to go next.
219  // List of neighboring boxes for each box.
220  // Each entry is a uint16, 0x8000 set marks end of list.
221  uint16_t e = file.readU16();
222  overlaps.at(list).push_back(e);
223  if (e & 0x8000) {
224  overlaps.emplace_back();
225  list++;
226  }
227  }
228 
229  // TODO store overlaps somewhere
230 
231  for (unsigned int z = 0; z < numBoxes; z++) {
232  // Normal room state
233  int16_t ground1 = file.read16();
234  int16_t ground2 = file.read16();
235  int16_t fly = file.read16();
236 
237  // Alternate room state
238  int16_t ground1alt = file.read16();
239  int16_t ground2alt = file.read16();
240  int16_t flyAlt = file.read16();
241 
242  // TODO store zones somewhere
243  }
244 
245  if ((numBoxes > 0) || (numOverlaps > 0))
246  Log::get(LOG_INFO) << "LoaderTR1: Found NPC NavigationHints (" << numBoxes
247  << ", " << numOverlaps << ", " << list << "), unimplemented!" << Log::endl;
248  else
249  Log::get(LOG_INFO) << "LoaderTR1: No NPC NavigationHints in this level?!" << Log::endl;
250 }
251 
253  for (int i = 0; i < 256; i++) {
255  }
256 }
257 
259  uint32_t soundSampleSize = file.readU32();
260  std::vector<uint8_t> buffer;
261  for (int i = 0; i < soundSampleSize; i++) {
262  buffer.push_back(file.readU8());
263  }
264 
265  uint32_t numSampleIndices = file.readU32();
266  for (unsigned int i = 0; i < numSampleIndices; i++) {
268  uint32_t sampleOffset = file.readU32();
269  assertLessThan(sampleOffset, soundSampleSize);
270  char* tmpPtr = reinterpret_cast<char*>(&buffer[sampleOffset]);
271  BinaryMemory sample(tmpPtr, soundSampleSize - sampleOffset);
272  int ret = loadSoundFiles(sample, 1);
273  assertEqual(ret, 1);
274  }
275 
276  if (numSampleIndices > 0)
277  Log::get(LOG_INFO) << "LoaderTR1: Found " << numSampleIndices << " SoundSamples" << Log::endl;
278  else
279  Log::get(LOG_INFO) << "LoaderTR1: No SoundSamples in this level?!" << Log::endl;
280 }
281 
282 int LoaderTR1::getPaletteIndex(uint16_t index) {
283  return index;
284 }
285 
286 void LoaderTR1::loadAngleSet(BoneFrame* bf, BinaryReader& frame, uint16_t numMeshes,
287  uint16_t startingMesh, uint32_t meshTree,
288  uint32_t numMeshTrees, std::vector<int32_t> meshTrees) {
296  uint16_t numValues = frame.readU16();
297 
298  for (int i = 0; i < numValues; i++) {
299  int mesh = startingMesh + i;
300  glm::vec3 offset(0.0f, 0.0f, 0.0f);
301  float rotation[3] = { 0.0f, 0.0f, 0.0f };
302  char flag = (i == 0) ? 2 : 0;
303 
304  // Nonprimary tag - positioned relative to first tag
305  if (i != 0) {
306  char* tmp = reinterpret_cast<char*>(&meshTrees[0]) + meshTree; // TODO (meshTree * 4)?
307  tmp += (i - 1) * 16; // TODO ?
308  BinaryMemory tree(tmp, (numMeshTrees * 4) - meshTree - ((i - 1) * 16));
309 
310  flag = (char)tree.readU32();
311  offset.x = tree.read32();
312  offset.y = tree.read32();
313  offset.z = tree.read32();
314 
315  uint16_t b = frame.readU16();
316  uint16_t a = frame.readU16();
317  rotation[0] = (a & 0x3FF0) >> 4;
318  rotation[1] = ((a & 0x000F) << 6) | ((b & 0xFC00) >> 10);
319  rotation[2] = b & 0x03FF;
320  for (int i = 0; i < 3; i++)
321  rotation[i] = rotation[i] * 360.0f / 1024.0f;
322  }
323 
324  glm::vec3 rot(rotation[0], rotation[1], rotation[2]);
325  BoneTag* bt = new BoneTag(mesh, offset, rot, flag);
326  bf->add(bt);
327  }
328 }
329 
virtual void loadTextures()
Definition: LoaderTR1.cpp:83
String handling utilities.
virtual void loadAnimatedTextures()
Definition: LoaderTR2.cpp:155
BinaryFile file
Definition: Loader.h:34
virtual uint8_t readU8()
Definition: binary.cpp:14
virtual int load(std::string f)
Definition: LoaderTR1.cpp:16
virtual void loadAngleSet(BoneFrame *bf, BinaryReader &frame, uint16_t numMeshes, uint16_t startingMesh, uint32_t meshTree, uint32_t numMeshTrees, std::vector< int32_t > meshTrees)
Definition: LoaderTR1.cpp:286
void add(BoneTag *t)
virtual void loadSoundSources()
Definition: LoaderTR2.cpp:1084
World Model.
virtual void loadRoomStaticMeshes(std::vector< StaticModel * > &staticModels)
Definition: LoaderTR1.cpp:117
TR1 level file loader.
virtual long long tell()
Definition: binary.cpp:123
Sound Source Manager.
virtual int loadSoundFiles(BinaryReader &sfx, unsigned int count=0)
Definition: LoaderTR2.cpp:1173
World & getWorld()
Definition: main.cpp:32
Included everywhere.
virtual void loadCinematicFrames()
Definition: LoaderTR2.cpp:1226
virtual void seek(long long pos=0)
Definition: binary.cpp:128
static LogLevel & get(int level)
Definition: Log.cpp:14
virtual void loadTextiles()
Definition: LoaderTR2.cpp:108
virtual void loadMeshes()
Definition: LoaderTR2.cpp:527
virtual int16_t read16()
Definition: binary.cpp:77
virtual void loadStaticMeshes()
Definition: LoaderTR2.cpp:648
Global Logging Utility.
bool stringEndsWith(std::string s, std::string suffix, bool casesensitive=false)
Definition: strings.cpp:32
static void addIndexedTexture(unsigned char *image, unsigned int width, unsigned int height)
unsigned int attributes
Definition: RoomMesh.h:25
Definition: Entity.h:11
virtual void loadSoundMap()
Definition: LoaderTR1.cpp:252
virtual void loadSoundSamples()
Definition: LoaderTR1.cpp:258
#define LOG_INFO
Definition: Log.h:21
static void addSampleIndex(int index)
virtual void loadPalette()
Definition: LoaderTR1.cpp:65
virtual void loadSprites()
Definition: LoaderTR2.cpp:480
virtual void loadCameras()
Definition: LoaderTR2.cpp:1209
virtual uint16_t readU16()
Definition: binary.cpp:21
static void addSoundMapEntry(int id)
static const char endl
Definition: Log.h:35
virtual void loadBoxesOverlapsZones()
Definition: LoaderTR1.cpp:195
virtual void loadMoveables()
Definition: LoaderTR2.cpp:785
virtual void loadSoundDetails()
Definition: LoaderTR2.cpp:1113
#define assertEqual(x, y)
Definition: global.h:130
virtual void loadRooms()
Definition: LoaderTR2.cpp:289
virtual int getPaletteIndex(uint16_t index)
Definition: LoaderTR1.cpp:282
virtual uint32_t readU32()
Definition: binary.cpp:27
static void setLara(long lara)
Definition: Game.cpp:121
virtual void loadDemoData()
Definition: LoaderTR2.cpp:1246
virtual int32_t read32()
Definition: binary.cpp:85
virtual void loadRoomVertex(RoomVertexTR2 &vert)
Definition: LoaderTR1.cpp:142
static void setPalette(int index, glm::vec4 color)
void addEntity(Entity *entity)
Definition: World.cpp:64
#define assertLessThan(x, y)
Definition: global.h:146
virtual void loadFloorData()
Definition: LoaderTR2.cpp:465
virtual void loadItems()
Definition: LoaderTR1.cpp:151
virtual void loadRoomLights()
Definition: LoaderTR1.cpp:100
Gameplay Handler.
int open(std::string f="")
Definition: binary.cpp:112