|
@@ -17,6 +17,7 @@
|
17
|
17
|
#include "SoundManager.h"
|
18
|
18
|
#include "TextureManager.h"
|
19
|
19
|
#include "World.h"
|
|
20
|
+#include "math/Matrix.h"
|
20
|
21
|
#include "math/Vec3.h"
|
21
|
22
|
#include "system/Sound.h"
|
22
|
23
|
#include "utils/pixel.h"
|
|
@@ -172,6 +173,8 @@ void LoaderTR2::loadAnimatedTextures() {
|
172
|
173
|
|
173
|
174
|
if ((numAnimatedTextures > 0) || (numWords > 0))
|
174
|
175
|
getLog() << "LoaderTR2: Found " << numAnimatedTextures << " Animated Textures!" << Log::endl;
|
|
176
|
+ else
|
|
177
|
+ getLog() << "LoaderTR2: No Animated Textures in this level?!" << Log::endl;
|
175
|
178
|
|
176
|
179
|
if (pos != numWords)
|
177
|
180
|
getLog() << "LoaderTR2: Extra bytes at end of AnimatedTextures?!" << Log::endl;
|
|
@@ -181,7 +184,6 @@ void LoaderTR2::loadAnimatedTextures() {
|
181
|
184
|
|
182
|
185
|
void LoaderTR2::loadRooms() {
|
183
|
186
|
uint16_t numRooms = file.readU16();
|
184
|
|
-
|
185
|
187
|
for (unsigned int i = 0; i < numRooms; i++) {
|
186
|
188
|
// Room Header
|
187
|
189
|
int32_t xOffset = file.read32();
|
|
@@ -194,6 +196,10 @@ void LoaderTR2::loadRooms() {
|
194
|
196
|
|
195
|
197
|
uint16_t numVertices = file.readU16();
|
196
|
198
|
std::vector<Vec3> vertices;
|
|
199
|
+ float bbox[2][3] = {
|
|
200
|
+ { 0.0f, 0.0f, 0.0f },
|
|
201
|
+ { 0.0f, 0.0f, 0.0f }
|
|
202
|
+ };
|
197
|
203
|
for (unsigned int v = 0; v < numVertices; v++) {
|
198
|
204
|
// Vertex coordinates, relative to x/zOffset
|
199
|
205
|
int16_t x = file.read16();
|
|
@@ -212,9 +218,43 @@ void LoaderTR2::loadRooms() {
|
212
|
218
|
int16_t light2 = file.read16(); // Almost always equal to light1
|
213
|
219
|
|
214
|
220
|
vertices.emplace_back(x, y, z);
|
|
221
|
+
|
|
222
|
+ if (v == 0) {
|
|
223
|
+ for (int i = 0; i < 2; i++) {
|
|
224
|
+ bbox[i][0] = x;
|
|
225
|
+ bbox[i][1] = y;
|
|
226
|
+ bbox[i][2] = z;
|
|
227
|
+ }
|
|
228
|
+ } else {
|
|
229
|
+ if (x < bbox[0][0])
|
|
230
|
+ bbox[0][0] = x;
|
|
231
|
+ if (x > bbox[1][0])
|
|
232
|
+ bbox[1][0] = x;
|
|
233
|
+
|
|
234
|
+ if (y < bbox[0][1])
|
|
235
|
+ bbox[0][1] = y;
|
|
236
|
+ if (y > bbox[1][1])
|
|
237
|
+ bbox[1][1] = y;
|
|
238
|
+
|
|
239
|
+ if (z < bbox[0][2])
|
|
240
|
+ bbox[0][2] = z;
|
|
241
|
+ if (z > bbox[1][2])
|
|
242
|
+ bbox[1][2] = z;
|
|
243
|
+ }
|
215
|
244
|
}
|
216
|
245
|
|
217
|
|
- Room* room = new Room();
|
|
246
|
+ float pos[3] {
|
|
247
|
+ static_cast<float>(xOffset),
|
|
248
|
+ 0.0f,
|
|
249
|
+ static_cast<float>(zOffset)
|
|
250
|
+ };
|
|
251
|
+ Room* room = new Room(pos);
|
|
252
|
+
|
|
253
|
+ bbox[0][0] += pos[0];
|
|
254
|
+ bbox[1][0] += pos[0];
|
|
255
|
+ bbox[0][2] += pos[2];
|
|
256
|
+ bbox[1][2] += pos[2];
|
|
257
|
+ room->getBoundingBox().setBoundingBox(bbox[0], bbox[1]);
|
218
|
258
|
|
219
|
259
|
uint16_t numRectangles = file.readU16();
|
220
|
260
|
for (unsigned int r = 0; r < numRectangles; r++) {
|
|
@@ -254,6 +294,11 @@ void LoaderTR2::loadRooms() {
|
254
|
294
|
// TODO store sprites somewhere
|
255
|
295
|
}
|
256
|
296
|
|
|
297
|
+ Matrix transform;
|
|
298
|
+ transform.setIdentity();
|
|
299
|
+ transform.translate(pos);
|
|
300
|
+ room->addAdjacentRoom(i); // Always set room itself as first
|
|
301
|
+
|
257
|
302
|
uint16_t numPortals = file.readU16();
|
258
|
303
|
for (unsigned int p = 0; p < numPortals; p++) {
|
259
|
304
|
// Which room this portal leads to
|
|
@@ -281,11 +326,46 @@ void LoaderTR2::loadRooms() {
|
281
|
326
|
int16_t yCorner4 = file.read16();
|
282
|
327
|
int16_t zCorner4 = file.read16();
|
283
|
328
|
|
284
|
|
- // TODO store portals somewhere
|
|
329
|
+ float vertices[4][3] = {
|
|
330
|
+ {
|
|
331
|
+ static_cast<float>(xCorner1),
|
|
332
|
+ static_cast<float>(yCorner1),
|
|
333
|
+ static_cast<float>(zCorner1)
|
|
334
|
+ }, {
|
|
335
|
+ static_cast<float>(xCorner2),
|
|
336
|
+ static_cast<float>(yCorner2),
|
|
337
|
+ static_cast<float>(zCorner2)
|
|
338
|
+ }, {
|
|
339
|
+ static_cast<float>(xCorner3),
|
|
340
|
+ static_cast<float>(yCorner3),
|
|
341
|
+ static_cast<float>(zCorner3)
|
|
342
|
+ }, {
|
|
343
|
+ static_cast<float>(xCorner4),
|
|
344
|
+ static_cast<float>(yCorner4),
|
|
345
|
+ static_cast<float>(zCorner4)
|
|
346
|
+ }
|
|
347
|
+ };
|
|
348
|
+
|
|
349
|
+ // Portals have relative coordinates
|
|
350
|
+ transform.multiply3v(vertices[0], vertices[0]);
|
|
351
|
+ transform.multiply3v(vertices[1], vertices[1]);
|
|
352
|
+ transform.multiply3v(vertices[2], vertices[2]);
|
|
353
|
+ transform.multiply3v(vertices[3], vertices[3]);
|
|
354
|
+
|
|
355
|
+ float normals[3] = {
|
|
356
|
+ static_cast<float>(xNormal),
|
|
357
|
+ static_cast<float>(yNormal),
|
|
358
|
+ static_cast<float>(zNormal)
|
|
359
|
+ };
|
|
360
|
+
|
|
361
|
+ room->addPortal(new Portal(vertices, normals, adjoiningRoom));
|
|
362
|
+ room->addAdjacentRoom(adjoiningRoom);
|
285
|
363
|
}
|
286
|
364
|
|
287
|
365
|
uint16_t numZSectors = file.readU16();
|
288
|
366
|
uint16_t numXSectors = file.readU16();
|
|
367
|
+ room->setNumXSectors(numXSectors);
|
|
368
|
+ room->setNumZSectors(numZSectors);
|
289
|
369
|
for (unsigned int s = 0; s < (numZSectors * numXSectors); s++) {
|
290
|
370
|
// Sectors are 1024*1024 world coordinates. Floor and Ceiling are
|
291
|
371
|
// signed numbers of 256 units of height.
|
|
@@ -303,7 +383,12 @@ void LoaderTR2::loadRooms() {
|
303
|
383
|
uint8_t roomAbove = file.readU8(); // 0xFF if none
|
304
|
384
|
int8_t ceiling = file.read8(); // Absolute height of ceiling (/ 256)
|
305
|
385
|
|
306
|
|
- // TODO store sectors somewhere
|
|
386
|
+ bool wall = false;
|
|
387
|
+ if ((((uint8_t)floor) == 0x81) || (((uint8_t)ceiling) == 0x81)) {
|
|
388
|
+ wall = true;
|
|
389
|
+ }
|
|
390
|
+
|
|
391
|
+ room->addSector(new Sector(floor * 256.0f, ceiling * 256.0f, wall));
|
307
|
392
|
}
|
308
|
393
|
|
309
|
394
|
int16_t intensity1 = file.read16();
|
|
@@ -347,11 +432,22 @@ void LoaderTR2::loadRooms() {
|
347
|
432
|
// TODO store static meshes somewhere
|
348
|
433
|
}
|
349
|
434
|
|
350
|
|
- int16_t alternateRoom = file.read16();
|
|
435
|
+ int16_t alternateRoom = file.read16(); // TODO
|
351
|
436
|
|
352
|
437
|
uint16_t flags = file.readU16();
|
|
438
|
+ int roomFlags = 0;
|
|
439
|
+ if (flags & 0x0001) {
|
|
440
|
+ roomFlags |= RoomFlagUnderWater;
|
|
441
|
+ }
|
|
442
|
+ room->setFlags(room->getFlags() | roomFlags);
|
353
|
443
|
|
354
|
444
|
getWorld().addRoom(room);
|
|
445
|
+
|
|
446
|
+ if ((numPortals == 0) || (numVertices == 0)
|
|
447
|
+ || ((numRectangles == 0) && (numTriangles == 0)))
|
|
448
|
+ getLog() << "LoaderTR2: Room " << i << " seems invalid: " << numPortals << "p "
|
|
449
|
+ << numRectangles << "r " << numTriangles << "t " << numVertices
|
|
450
|
+ << "v" << Log::endl;
|
355
|
451
|
}
|
356
|
452
|
|
357
|
453
|
if (numRooms > 0)
|
|
@@ -370,6 +466,8 @@ void LoaderTR2::loadFloorData() {
|
370
|
466
|
|
371
|
467
|
if (numFloorData > 0)
|
372
|
468
|
getLog() << "LoaderTR2: Found " << numFloorData << " words FloorData, unimplemented!" << Log::endl;
|
|
469
|
+ else
|
|
470
|
+ getLog() << "LoaderTR2: No FloorData in this level?!" << Log::endl;
|
373
|
471
|
}
|
374
|
472
|
|
375
|
473
|
void LoaderTR2::loadSprites() {
|
|
@@ -430,14 +528,15 @@ void LoaderTR2::loadMeshes() {
|
430
|
528
|
|
431
|
529
|
uint32_t numMeshPointers = file.readU32();
|
432
|
530
|
|
433
|
|
- if ((numMeshData == 0) || (numMeshPointers == 0)) {
|
434
|
|
- getLog() << "LoaderTR2: No mesh data found!" << Log::endl;
|
435
|
|
- return;
|
436
|
|
- }
|
437
|
|
-
|
438
|
531
|
for (unsigned int i = 0; i < numMeshPointers; i++) {
|
439
|
532
|
uint32_t meshPointer = file.readU32();
|
440
|
533
|
|
|
534
|
+ if (numMeshData < (meshPointer / 2)) {
|
|
535
|
+ getLog() << "LoaderTR2: Invalid Mesh: "
|
|
536
|
+ << (meshPointer / 2) << " > " << numMeshData << Log::endl;
|
|
537
|
+ continue;
|
|
538
|
+ }
|
|
539
|
+
|
441
|
540
|
char* tmpPtr = reinterpret_cast<char*>(&buffer[meshPointer / 2]);
|
442
|
541
|
BinaryMemory mem(tmpPtr, (numMeshData * 2) - meshPointer);
|
443
|
542
|
|
|
@@ -536,7 +635,9 @@ void LoaderTR2::loadMeshes() {
|
536
|
635
|
}
|
537
|
636
|
|
538
|
637
|
if (numMeshPointers > 0)
|
539
|
|
- getLog() << "LoaderTR2: Found " << numMeshPointers << " Meshes, unimplemented!" << Log::endl;
|
|
638
|
+ getLog() << "LoaderTR2: Found " << numMeshPointers << " Meshes!" << Log::endl;
|
|
639
|
+ else
|
|
640
|
+ getLog() << "LoaderTR2: No Meshes in this level?!" << Log::endl;
|
540
|
641
|
}
|
541
|
642
|
|
542
|
643
|
void LoaderTR2::loadStaticMeshes() {
|
|
@@ -571,7 +672,7 @@ void LoaderTR2::loadStaticMeshes() {
|
571
|
672
|
}
|
572
|
673
|
|
573
|
674
|
if (numStaticMeshes > 0)
|
574
|
|
- getLog() << "LoaderTR2: Found " << numStaticMeshes << " StaticMeshes, unimplemented!" << Log::endl;
|
|
675
|
+ getLog() << "LoaderTR2: Found " << numStaticMeshes << " StaticMeshes!" << Log::endl;
|
575
|
676
|
else
|
576
|
677
|
getLog() << "LoaderTR2: No StaticMeshes in this level?!" << Log::endl;
|
577
|
678
|
}
|
|
@@ -834,7 +935,7 @@ void LoaderTR2::loadItems() {
|
834
|
935
|
int32_t y = file.read32();
|
835
|
936
|
int32_t z = file.read32();
|
836
|
937
|
|
837
|
|
- int16_t angle = file.read16(); // (0xC000 >> 14) * 90deg
|
|
938
|
+ uint16_t angle = file.readU16(); // (0xC000 >> 14) * 90deg
|
838
|
939
|
int16_t intensity1 = file.read16(); // Constant lighting; -1 means mesh lighting
|
839
|
940
|
int16_t intensity2 = file.read16(); // Almost always like intensity1
|
840
|
941
|
|
|
@@ -868,7 +969,7 @@ void LoaderTR2::loadItems() {
|
868
|
969
|
}
|
869
|
970
|
|
870
|
971
|
if (numItems > 0)
|
871
|
|
- getLog() << "LoaderTR2: Found " << numItems << " Items, unimplemented!" << Log::endl;
|
|
972
|
+ getLog() << "LoaderTR2: Found " << numItems << " Items!" << Log::endl;
|
872
|
973
|
else
|
873
|
974
|
getLog() << "LoaderTR2: No Items in this level?!" << Log::endl;
|
874
|
975
|
}
|
|
@@ -886,30 +987,52 @@ void LoaderTR2::loadBoxesOverlapsZones() {
|
886
|
987
|
|
887
|
988
|
// Index into overlaps[]. The high bit is sometimes set
|
888
|
989
|
// this occurs in front of swinging doors and the like
|
889
|
|
- int16_t overlapIndex = file.read16();
|
|
990
|
+ uint16_t overlapIndex = file.readU16();
|
890
|
991
|
|
891
|
992
|
// TODO store boxes somewhere
|
892
|
993
|
}
|
893
|
994
|
|
894
|
995
|
uint32_t numOverlaps = file.readU32();
|
895
|
|
- std::vector<uint16_t> overlaps;
|
|
996
|
+ std::vector<std::vector<uint16_t>> overlaps;
|
|
997
|
+ overlaps.emplace_back();
|
|
998
|
+ unsigned int list = 0;
|
896
|
999
|
for (unsigned int o = 0; o < numOverlaps; o++) {
|
897
|
|
- overlaps.push_back(file.readU16());
|
|
1000
|
+ // Apparently used by NPCs to decide where to go next.
|
|
1001
|
+ // List of neighboring boxes for each box.
|
|
1002
|
+ // Each entry is a uint16, 0x8000 set marks end of list.
|
|
1003
|
+ uint16_t e = file.readU16();
|
|
1004
|
+ overlaps.at(list).push_back(e);
|
|
1005
|
+ if (e & 0x8000) {
|
|
1006
|
+ overlaps.emplace_back();
|
|
1007
|
+ list++;
|
|
1008
|
+ }
|
898
|
1009
|
}
|
899
|
1010
|
|
900
|
1011
|
// TODO store overlaps somewhere
|
901
|
1012
|
|
902
|
|
- std::vector<int16_t> zones;
|
903
|
1013
|
for (unsigned int z = 0; z < numBoxes; z++) {
|
904
|
|
- for (unsigned int i = 0; i < 10; i++) {
|
905
|
|
- zones.push_back(file.read16());
|
906
|
|
- }
|
|
1014
|
+ // Normal room state
|
|
1015
|
+ int16_t ground1 = file.read16();
|
|
1016
|
+ int16_t ground2 = file.read16();
|
|
1017
|
+ int16_t ground3 = file.read16();
|
|
1018
|
+ int16_t ground4 = file.read16();
|
|
1019
|
+ int16_t fly = file.read16();
|
|
1020
|
+
|
|
1021
|
+ // Alternate room state
|
|
1022
|
+ int16_t ground1alt = file.read16();
|
|
1023
|
+ int16_t ground2alt = file.read16();
|
|
1024
|
+ int16_t ground3alt = file.read16();
|
|
1025
|
+ int16_t ground4alt = file.read16();
|
|
1026
|
+ int16_t flyAlt = file.read16();
|
|
1027
|
+
|
|
1028
|
+ // TODO store zones somewhere
|
907
|
1029
|
}
|
908
|
1030
|
|
909
|
|
- // TODO store zones somewhere
|
910
|
|
-
|
911
|
1031
|
if ((numBoxes > 0) || (numOverlaps > 0))
|
912
|
|
- getLog() << "LoaderTR2: Found NPC NavigationHints, unimplemented!" << Log::endl;
|
|
1032
|
+ getLog() << "LoaderTR2: Found NPC NavigationHints (" << numBoxes
|
|
1033
|
+ << ", " << numOverlaps << ", " << list << "), unimplemented!" << Log::endl;
|
|
1034
|
+ else
|
|
1035
|
+ getLog() << "LoaderTR2: No NPC NavigationHints in this level?!" << Log::endl;
|
913
|
1036
|
}
|
914
|
1037
|
|
915
|
1038
|
// ---- Sound ----
|
|
@@ -933,6 +1056,8 @@ void LoaderTR2::loadSoundSources() {
|
933
|
1056
|
|
934
|
1057
|
if (numSoundSources > 0)
|
935
|
1058
|
getLog() << "LoaderTR2: Found " << numSoundSources << " SoundSources" << Log::endl;
|
|
1059
|
+ else
|
|
1060
|
+ getLog() << "LoaderTR2: No SoundSources in this level?!" << Log::endl;
|
936
|
1061
|
}
|
937
|
1062
|
|
938
|
1063
|
void LoaderTR2::loadSoundMap() {
|
|
@@ -960,6 +1085,8 @@ void LoaderTR2::loadSoundDetails() {
|
960
|
1085
|
|
961
|
1086
|
if (numSoundDetails > 0)
|
962
|
1087
|
getLog() << "LoaderTR2: Found " << numSoundDetails << " SoundDetails" << Log::endl;
|
|
1088
|
+ else
|
|
1089
|
+ getLog() << "LoaderTR2: No SoundDetails in this level?!" << Log::endl;
|
963
|
1090
|
}
|
964
|
1091
|
|
965
|
1092
|
void LoaderTR2::loadSampleIndices() {
|
|
@@ -970,6 +1097,8 @@ void LoaderTR2::loadSampleIndices() {
|
970
|
1097
|
|
971
|
1098
|
if (numSampleIndices > 0)
|
972
|
1099
|
getLog() << "LoaderTR2: Found " << numSampleIndices << " SampleIndices" << Log::endl;
|
|
1100
|
+ else
|
|
1101
|
+ getLog() << "LoaderTR2: No SampleIndices in this level?!" << Log::endl;
|
973
|
1102
|
}
|
974
|
1103
|
|
975
|
1104
|
void LoaderTR2::loadExternalSoundFile(std::string f) {
|
|
@@ -1016,6 +1145,8 @@ void LoaderTR2::loadExternalSoundFile(std::string f) {
|
1016
|
1145
|
|
1017
|
1146
|
if (riffCount > 0)
|
1018
|
1147
|
getLog() << "LoaderTR2: Found " << riffCount << " SoundSamples in SFX" << Log::endl;
|
|
1148
|
+ else
|
|
1149
|
+ getLog() << "LoaderTR2: No SoundSamples in SFX?!" << Log::endl;
|
1019
|
1150
|
}
|
1020
|
1151
|
|
1021
|
1152
|
// ---- Stuff ----
|