1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-13 08:34:32 +02:00

#138 Sega Saturn levels loader WIP

This commit is contained in:
XProger
2018-10-31 00:45:51 +03:00
parent 8f6f2a2a76
commit 8577bfeb1d
2 changed files with 764 additions and 19 deletions

View File

@@ -1123,8 +1123,9 @@ namespace TR {
operator short3() const { return *((short3*)this); }
};
struct Tile {
uint16 index:14, undefined:1, triangle:1;
union Tile {
struct { uint16 index:14, undefined:1, triangle:1; };
uint16 value;
};
struct ObjectTexture {
@@ -1452,8 +1453,9 @@ namespace TR {
};
};
struct Overlap {
uint16 boxIndex:15, end:1;
union Overlap {
struct { uint16 boxIndex:15, end:1; };
uint16 value;
};
struct Flags {
@@ -2273,7 +2275,6 @@ namespace TR {
int32 entitiesCount;
Entity *entities;
int32 paletteSize;
Color24 *palette;
Color32 *palette32;
@@ -2445,23 +2446,19 @@ namespace TR {
} inv;
} extra;
Level(Stream &stream) : version(VER_UNKNOWN), soundData(NULL), soundOffsets(NULL), soundSize(NULL) {
int startPos = stream.pos;
Level(Stream &stream) {
memset(this, 0, sizeof(*this));
version = VER_UNKNOWN;
cutEntity = -1;
tiles4 = NULL;
tiles8 = NULL;
tiles16 = NULL;
palette = NULL;
palette32 = NULL;
int startPos = stream.pos;
int soundOffset = 0;
uint32 magic;
#define MAGIC_TR1_PC 0x00000020
#define MAGIC_TR1_PSX 0x56414270
#define MAGIC_TR1_SAT 0x4D4F4F52
#define MAGIC_TR2_PC 0x0000002D
#define MAGIC_TR3_PC1 0xFF080038
#define MAGIC_TR3_PC2 0xFF180038
@@ -2472,6 +2469,40 @@ namespace TR {
if (version == VER_UNKNOWN || version == VER_TR1_PSX) {
stream.read(magic);
if (magic == MAGIC_TR1_SAT) {
version = VER_TR1_SEGA;
stream.seek(-4);
// get file name without extension
int len = strlen(stream.name);
char *name = new char[len + 1];
memcpy(name, stream.name, len);
for (int i = len - 1; i >= 0; i--) {
if (name[i] == '/' || name[i] == '\\')
break;
if (name[i] == '.') {
len = i;
break;
}
}
name[len] = 0;
LOG("load Sega Saturn level: %s\n", name);
readSAT(stream);
strcat(name, ".SAD");
readSAT(Stream(name));
name[len] = '\0';
strcat(name, ".SPR");
readSAT(Stream(name));
name[len] = '\0';
strcat(name, ".SND");
readSAT(Stream(name));
return;
}
if (magic != MAGIC_TR1_PC && magic != MAGIC_TR2_PC && magic != MAGIC_TR3_PC1 && magic != MAGIC_TR3_PC2 && magic != MAGIC_TR3_PC3 && magic != MAGIC_TR3_PSX) {
soundOffset = magic;
stream.read(magic);
@@ -2907,6 +2938,626 @@ namespace TR {
delete[] soundSize;
}
#define CHUNK(str) ((uint64)((const char*)(str))[0] | ((uint64)((const char*)(str))[1] << 8) | ((uint64)((const char*)(str))[2] << 16) | ((uint64)((const char*)(str))[3] << 24) | \
((uint64)((const char*)(str))[4] << 32) | ((uint64)((const char*)(str))[5] << 40) | ((uint64)((const char*)(str))[6] << 48) | ((uint64)((const char*)(str))[7] << 56))
void readSAT(Stream &stream) {
struct TINF {
uint8 data[16];
};
struct TPAL {
uint8 data[3];
};
struct SPAL {
uint8 data[2];
};
uint32 tinfCount = 0;
TINF *tinf = NULL;
uint32 tqtrCount = 0;
uint8 *tqtr = NULL;
uint32 tsubCount = 0;
uint8 *tsub = NULL;
uint32 tpalCount = 0;
TPAL *tpal = NULL;
uint32 spalCount = 0;
SPAL *spal = NULL;
Room *room = NULL;
while (stream.pos < stream.size) {
uint64 chunkType = stream.read64();
{
char buf[9];
memcpy(buf, &chunkType, 8);
buf[8] = 0;
LOG("chunk: \"%s\"\n", buf);
}
switch (chunkType) {
// SAT
case CHUNK("ROOMFILE") :
ASSERT(stream.readBE32() == 0x00000000);
ASSERT(stream.readBE32() == 0x00000020);
break;
case CHUNK("ROOMTINF") :
ASSERT(stream.readBE32() == 0x00000010);
tinfCount = stream.readBE32();
tinf = new TINF[tinfCount];
stream.raw(tinf, sizeof(TINF) * tinfCount);
break;
case CHUNK("ROOMTQTR") :
ASSERT(stream.readBE32() == 0x00000001);
tqtrCount = stream.readBE32();
tqtr = new uint8[tqtrCount];
stream.raw(tqtr, sizeof(uint8) * tqtrCount);
break;
case CHUNK("ROOMTSUB") :
ASSERT(stream.readBE32() == 0x00000001);
tsubCount = stream.readBE32();
tsub = new uint8[tsubCount];
stream.raw(tsub, sizeof(uint8) * tsubCount);
break;
case CHUNK("ROOMTPAL") :
ASSERT(stream.readBE32() == 0x00000003);
tpalCount = stream.readBE32();
tpal = new TPAL[tpalCount];
stream.raw(tpal, sizeof(TPAL) * tpalCount);
break;
case CHUNK("ROOMSPAL") :
ASSERT(stream.readLE32() == 0x02000000);
spalCount = stream.readBE32();
spal = new SPAL[spalCount];
stream.raw(spal, sizeof(SPAL) * spalCount);
break;
case CHUNK("ROOMDATA") :
ASSERT(stream.readBE32() == 0x00000044);
roomsCount = stream.readBE32();
rooms = new Room[roomsCount];
memset(rooms, 0, sizeof(Room) * roomsCount);
break;
case CHUNK("ROOMNUMB") :
ASSERT(stream.readBE32() == 0x00000000);
room = &rooms[stream.readBE32()];
break;
case CHUNK("MESHPOS ") :
room->info.x = stream.readBE32();
room->info.z = stream.readBE32();
room->info.yBottom = stream.readBE32();
room->info.yTop = stream.readBE32();
break;
case CHUNK("MESHSIZE") : {
uint32 flag = stream.readBE32();
if (flag == 0x00000014) {
uint32 count = stream.readBE32();
stream.seek(20 * count); // unknown
break;
}
ASSERT(flag == 0x00000002);
Room::Data &data = room->data;
data.size = stream.readBE32();
data.vCount = stream.readBE16();
data.vertices = new Room::Data::Vertex[data.vCount];
for (int j = 0; j < data.vCount; j++) {
Room::Data::Vertex &v = data.vertices[j];
v.vertex.x = stream.readBE16();
v.vertex.y = stream.readBE16();
v.vertex.z = stream.readBE16();
v.color = Color16(stream.readBE16());
v.attributes = 0;
}
data.fCount = stream.readBE16();
data.faces = new Face[data.fCount];
enum {
TYPE_R_TRANSP = 33,
TYPE_T_INVISIBLE = 34,
TYPE_R_INVISIBLE = 35,
TYPE_T_SOLID = 36,
TYPE_R_SOLID = 37,
TYPE_SPRITE = 39,
};
int fIndex = 0;
data.sCount = 0;
uint16 typesCount = stream.readBE16();
for (int j = 0; j < typesCount; j++) {
uint16 type = stream.readBE16();
uint16 count = stream.readBE16();
LOG(" type:%d count:%d\n", (int)type, (int)count);
for (int k = 0; k < count; k++) {
ASSERT(fIndex < data.fCount);
Face &f = data.faces[fIndex++];
switch (type) {
case TYPE_SPRITE :
stream.readBE16(); // sprite vertex
stream.readBE16(); // sprite texture
break;
case TYPE_T_INVISIBLE :
case TYPE_T_SOLID :
f.vCount = 3;
f.vertices[0] = stream.readBE16();
f.vertices[1] = stream.readBE16();
f.vertices[2] = stream.readBE16();
f.flags.value = stream.readBE16();
break;
case TYPE_R_TRANSP :
case TYPE_R_INVISIBLE :
case TYPE_R_SOLID :
f.vCount = 4;
f.vertices[0] = stream.readBE16();
f.vertices[1] = stream.readBE16();
f.vertices[2] = stream.readBE16();
f.vertices[3] = stream.readBE16();
f.flags.value = stream.readBE16();
break;
default :
LOG("! unknown face type: %d\n", type);
ASSERT(false);
}
}
}
break;
}
case CHUNK("DOORDATA") : {
ASSERT(room && room->sectors == NULL);
stream.seek(4); // unknown
room->portalsCount = stream.readBE32();
room->portals = new Room::Portal[room->portalsCount];
for (int j = 0; j < room->portalsCount; j++) {
Room::Portal &p = room->portals[j];
p.roomIndex = stream.readBE16();
p.normal.x = stream.readBE16();
p.normal.y = stream.readBE16();
p.normal.z = stream.readBE16();
for (int k = 0; k < 4; k++) {
p.vertices[k].x = stream.readBE16();
p.vertices[k].y = stream.readBE16();
p.vertices[k].z = stream.readBE16();
}
}
break;
}
case CHUNK("FLOORDAT") :
room->zSectors = stream.readBE32();
room->xSectors = stream.readBE32();
break;
case CHUNK("FLOORSIZ") : {
ASSERT(stream.readBE32() == 0x00000008);
ASSERT(room && room->sectors == NULL);
int32 count = stream.readBE32();
ASSERT(count == room->xSectors * room->zSectors);
room->sectors = count ? new Room::Sector[count] : NULL;
for (int i = 0; i < count; i++) {
Room::Sector &s = room->sectors[i];
s.material = 0;
s.floorIndex = stream.readBE16();
s.boxIndex = stream.readBE16();
stream.read(s.roomBelow);
stream.read(s.floor);
stream.read(s.roomAbove);
stream.read(s.ceiling);
}
break;
}
case CHUNK("FLORDATA") :
ASSERT(stream.readBE32() == 0x00000002);
ASSERT(floors == NULL);
floorsCount = stream.readBE32();
floors = new FloorData[floorsCount];
stream.raw(floors, sizeof(FloorData) * floorsCount);
break;
case CHUNK("LIGHTAMB") :
room->ambient = stream.readBE32();
room->ambient2 = stream.readBE32();
break;
case CHUNK("RM_FLIP ") : {
ASSERT(stream.readBE32() == 0x00000002);
uint32 value = stream.readBE32();
room->alternateRoom = value == 0xFFFFFFFF ? -1 : value;
break;
}
case CHUNK("RM_FLAGS") : {
ASSERT(stream.readBE32() == 0x00000002);
uint32 value = stream.readBE32();
room->flags.water = (value & 0x01) != 0;
break;
}
case CHUNK("LIGHTSIZ") : {
ASSERT(stream.readBE32() == 0x00000014);
ASSERT(room && room->lights == NULL);
room->lightsCount = stream.readBE32();
room->lights = room->lightsCount ? new Room::Light[room->lightsCount] : NULL;
for (int i = 0; i < room->lightsCount; i++) {
Room::Light &light = room->lights[i];
light.x = stream.readBE32();
light.y = stream.readBE32();
light.z = stream.readBE32();
int32 intensity = stream.readBE32();
int value = clamp((intensity > 0x1FFF) ? 0 : (intensity >> 5), 0, 255);
light.color.r = light.color.g = light.color.b = value;
light.color.a = 0;
light.radius = stream.readBE32() * 2;
}
break;
}
case CHUNK("CAMERAS ") :
ASSERT(stream.readBE32() == 0x00000010);
ASSERT(cameras == NULL);
camerasCount = stream.readBE32();
cameras = camerasCount ? new Camera[camerasCount] : NULL;
for (int i = 0; i < camerasCount; i++) {
Camera &cam = cameras[i];
cam.x = stream.readBE32();
cam.y = stream.readBE32();
cam.z = stream.readBE32();
cam.room = stream.readBE16();
cam.flags.boxIndex = stream.readBE16();
}
break;
case CHUNK("SOUNDFX ") : {
uint32 flag = stream.readBE32();
if (flag == 0x00000000) { // SND
ASSERT(stream.readBE32() == 0x00000000);
break;
}
ASSERT(flag == 0x00000010); // SAT
ASSERT(soundSources == NULL);
soundSourcesCount = stream.readBE32();
soundSources = soundSourcesCount ? new SoundSource[soundSourcesCount] : NULL;
for (int i = 0; i < soundSourcesCount; i++) {
SoundSource &s = soundSources[i];
s.x = stream.readBE32();
s.y = stream.readBE32();
s.z = stream.readBE32();
s.id = stream.readBE16();
s.flags = stream.readBE16();
}
break;
}
case CHUNK("BOXES ") :
ASSERT(stream.readBE32() == 0x00000014);
ASSERT(boxes == NULL);
boxesCount = stream.readBE32();
boxes = boxesCount ? new Box[boxesCount] : NULL;
for (int i = 0; i < boxesCount; i++) {
Box &b = boxes[i];
b.minZ = stream.readBE32();
b.maxZ = stream.readBE32();
b.minX = stream.readBE32();
b.maxX = stream.readBE32();
b.floor = stream.readBE16();
b.overlap.value = stream.readBE16();
}
break;
case CHUNK("OVERLAPS") :
ASSERT(stream.readBE32() == 0x00000002);
ASSERT(overlaps == NULL);
overlapsCount = stream.readBE32();
overlaps = overlapsCount ? new Overlap[overlapsCount] : NULL;
for (int i = 0; i < overlapsCount; i++)
overlaps[i].value = stream.readBE16();
break;
case CHUNK("GND_ZONE") :
case CHUNK("GND_ZON2") :
case CHUNK("FLY_ZONE") : {
ASSERT(stream.readBE32() == 0x00000002);
uint16 **ptr;
switch (chunkType) {
case CHUNK("GND_ZONE") : ptr = zones[0].ground1 ? &zones[1].ground1 : &zones[0].ground1; break;
case CHUNK("GND_ZON2") : ptr = zones[0].ground2 ? &zones[1].ground2 : &zones[0].ground2; break;
case CHUNK("FLY_ZONE") : ptr = zones[0].fly ? &zones[1].fly : &zones[0].fly; break;
default : ptr = NULL;
}
ASSERT(ptr != NULL);
ASSERT(*ptr == NULL);
int32 count = stream.readBE32();
*ptr = count ? new uint16[count] : NULL;
for (int i = 0; i < count; i++)
(*ptr)[i] = stream.readBE16();
break;
}
case CHUNK("ARANGES ") : {
ASSERT(stream.readBE32() == 0x00000008);
int32 count = stream.readBE32();
stream.seek(count * 8); // unknown
break;
}
case CHUNK("ITEMDATA") : {
ASSERT(stream.readBE32() == 0x00000014);
int32 count = stream.readBE32();
stream.seek(count * 24); // unknown
break;
}
case CHUNK("ROOMEND ") :
ASSERT(stream.readBE32() == 0x00000000);
ASSERT(stream.readBE32() == 0x00000000);
LOG("tinfCount = %d\n", tinfCount);
LOG("tqtrCount = %d\n", tqtrCount);
LOG("tsubCount = %d\n", tsubCount);
LOG("tpalCount = %d\n", tpalCount);
LOG("spalCount = %d\n", spalCount);
tilesCount = 16;
tiles8 = new Tile8[tilesCount];
palette = new Color24[256];
break;
// SAD
case CHUNK("OBJFILE ") :
ASSERT(stream.readBE32() == 0x00000000);
ASSERT(stream.readBE32() == 0x00000020);
break;
case CHUNK("ANIMS ") :
ASSERT(stream.readBE32() == 0x00000022);
ASSERT(anims == NULL);
animsCount = stream.readBE32();
anims = animsCount ? new Animation[animsCount] : NULL;
for (int i = 0; i < animsCount; i++) {
Animation &anim = anims[i];
anim.frameOffset = stream.readBE32();
anim.frameRate = stream.read();
anim.frameSize = stream.read();
anim.state = stream.readBE16();
anim.speed.L = stream.readBE16();
anim.speed.H = stream.readBE16();
anim.accel.L = stream.readBE16();
anim.accel.H = stream.readBE16();
anim.frameStart = stream.readBE16();
anim.frameEnd = stream.readBE16();
anim.nextAnimation = stream.readBE16();
anim.nextFrame = stream.readBE16();
anim.scCount = stream.readBE16();
anim.scOffset = stream.readBE16();
anim.acCount = stream.readBE16();
anim.animCommand = stream.readBE16();
}
break;
case CHUNK("CHANGES ") :
ASSERT(stream.readBE32() == 0x00000008);
ASSERT(states == NULL);
statesCount = stream.readBE32();
states = statesCount ? new AnimState[statesCount] : NULL;
for (int i = 0; i < statesCount; i++) {
AnimState &state = states[i];
state.state = stream.readBE16();
state.rangesCount = stream.readBE16();
state.rangesOffset = stream.readBE16();
ASSERT(stream.readBE16() == state.rangesOffset); // dummy
}
break;
case CHUNK("RANGES \0") :
ASSERT(stream.readBE32() == 0x00000008);
ASSERT(ranges == NULL);
rangesCount = stream.readBE32();
ranges = rangesCount ? new AnimRange[rangesCount] : NULL;
for (int i = 0; i < rangesCount; i++) {
AnimRange &range = ranges[i];
range.low = stream.readBE16();
range.high = stream.readBE16();
range.nextAnimation = stream.readBE16();
range.nextFrame = stream.readBE16();
}
break;
case CHUNK("COMMANDS") :
ASSERT(stream.readBE32() == 0x00000002);
ASSERT(commands == NULL);
commandsCount = stream.readBE32();
commands = commandsCount ? new int16[commandsCount] : NULL;
for (int i = 0; i < commandsCount; i++)
commands[i] = stream.readBE16();
break;
case CHUNK("ANIBONES") :
ASSERT(stream.readBE32() == 0x00000004);
ASSERT(nodesData == NULL);
nodesDataSize = stream.readBE32();
nodesData = nodesDataSize ? new uint32[nodesDataSize] : NULL;
for (int i = 0; i < nodesDataSize; i++)
nodesData[i] = stream.readBE32();
break;
case CHUNK("ANIMOBJ ") :
ASSERT(stream.readBE32() == 0x00000038);
ASSERT(models == NULL);
modelsCount = stream.readBE32();
models = modelsCount ? new Model[modelsCount] : NULL;
for (int i = 0; i < modelsCount; i++) {
Model &model = models[i];
ASSERT(stream.readBE16() == 0x0000);
model.index = i;
model.type = Entity::Type(stream.readBE16());
model.mCount = stream.readBE16();
model.mStart = stream.readBE16();
model.node = stream.readBE32();
model.frame = stream.readBE32();
model.animation = stream.readBE16();
ASSERT(stream.readBE16() == model.animation);
}
break;
case CHUNK("STATOBJ ") :
ASSERT(stream.readBE32() == 0x00000020);
ASSERT(staticMeshes == NULL);
staticMeshesCount = stream.readBE32();
staticMeshes = staticMeshesCount ? new StaticMesh[staticMeshesCount] : NULL;
for (int i = 0; i < staticMeshesCount; i++) {
StaticMesh &mesh = staticMeshes[i];
mesh.id = stream.readBE32();
mesh.mesh = stream.readBE16();
mesh.vbox.minX = stream.readBE16();
mesh.vbox.maxX = stream.readBE16();
mesh.vbox.minY = stream.readBE16();
mesh.vbox.maxY = stream.readBE16();
mesh.vbox.minZ = stream.readBE16();
mesh.vbox.maxZ = stream.readBE16();
mesh.cbox.minX = stream.readBE16();
mesh.cbox.maxX = stream.readBE16();
mesh.cbox.minY = stream.readBE16();
mesh.cbox.maxY = stream.readBE16();
mesh.cbox.minZ = stream.readBE16();
mesh.cbox.maxZ = stream.readBE16();
mesh.flags = stream.readBE16();
}
break;
case CHUNK("FRAMES ") :
ASSERT(stream.readBE32() == 0x00000002);
ASSERT(frameData == NULL);
frameDataSize = stream.readBE32();
frameData = frameDataSize ? new uint16[frameDataSize] : NULL;
for (int i = 0; i < frameDataSize; i++)
frameData[i] = stream.readBE16();
break;
case CHUNK("MESHPTRS") :
ASSERT(stream.readBE32() == 0x00000004);
ASSERT(meshOffsets == NULL);
meshOffsetsCount = stream.readBE32();
meshOffsets = meshOffsetsCount ? new int32[meshOffsetsCount] : NULL;
for (int i = 0; i < meshOffsetsCount; i++)
meshOffsets[i] = stream.readBE32();
break;
case CHUNK("MESHDATA") :
ASSERT(stream.readBE32() == 0x00000002);
ASSERT(meshData == NULL);
meshDataCount = stream.readBE32();
meshData = meshDataCount ? new uint16[meshDataCount] : NULL;
stream.raw(meshData, sizeof(uint16) * meshDataCount); // load raw for initMesh call
break;
case CHUNK("OTEXTINF") :
ASSERT(stream.readBE32() == 0x00000010);
ASSERT(objectTextures == NULL);
objectTexturesCount = stream.readBE32();
objectTextures = objectTexturesCount ? new ObjectTexture[objectTexturesCount] : NULL;
for (int i = 0; i < objectTexturesCount; i++)
readObjectTex(stream, objectTextures[i]);
break;
case CHUNK("OTEXTDAT") : {
ASSERT(stream.readBE32() == 0x00000001);
int count = stream.readBE32();
stream.seek(count); // TODO
break;
}
case CHUNK("ITEXTINF") : {
ASSERT(stream.readBE32() == 0x00000014);
int count = stream.readBE32();
stream.seek(count * 20); // TODO
break;
}
case CHUNK("ITEXTDAT") : {
ASSERT(stream.readBE32() == 0x00000001);
int count = stream.readBE32();
stream.seek(count); // TODO
break;
}
case CHUNK("OBJEND ") :
ASSERT(stream.readBE32() == 0x00000000);
ASSERT(stream.readBE32() == 0x00000000);
for (int i = 0; i < modelsCount; i++) {
Model &model = models[i];
model.type = Entity::remap(version, model.type);
for (int j = 0; j < model.mCount; j++)
initMesh(model.mStart + j, model.type);
}
for (int i = 0; i < staticMeshesCount; i++)
initMesh(staticMeshes[i].mesh);
remapMeshOffsetsToIndices();
delete[] meshData;
meshData = NULL;
break;
// SPR
case CHUNK("SPRFILE ") :
ASSERT(stream.readBE32() == 0x00000000);
ASSERT(stream.readBE32() == 0x00000020);
break;
case CHUNK("SPRITINF") : {
ASSERT(stream.readBE32() == 0x00000010);
int count = stream.readBE32();
stream.seek(count * 16); // TODO
break;
}
case CHUNK("SPRITDAT") : {
ASSERT(stream.readBE32() == 0x00000001);
int count = stream.readBE32();
stream.seek(count); // TODO
break;
}
case CHUNK("OBJECTS ") : {
ASSERT(stream.readBE32() == 0x00000000);
int count = stream.readBE32();
stream.seek(count * 8); // TODO
break;
}
case CHUNK("SPRITEND") :
ASSERT(stream.readBE32() == 0x00000000);
ASSERT(stream.readBE32() == 0x00000000);
break;
// SND
case CHUNK("SAMPLUT ") : {
ASSERT(stream.readBE32() == 0x00000002);
int count = stream.readBE32();
soundsMap = new int16[count];
for (int i = 0; i < count; i++)
soundsMap[i] = stream.readBE16();
break;
}
case CHUNK("SAMPINFS") : {
ASSERT(stream.readBE32() == 0x00000008);
int count = stream.readBE32();
stream.seek(count * 8); // TODO
break;
}
case CHUNK("SAMPLE ") : {
int index = stream.readBE32();
int count = stream.readBE32();
stream.seek(count); // TODO
break;
}
case CHUNK("ENDFILE\0") :
ASSERT(stream.readBE32() == 0x00000000);
ASSERT(stream.readBE32() == 0x00000000);
break;
default : {
char buf[9];
memcpy(buf, &chunkType, 8);
buf[8] = 0;
LOG("! unknown chunk type: \"%s\"\n", buf);
ASSERT(false);
break;
}
}
}
delete[] spal;
delete[] tpal;
delete[] tsub;
delete[] tqtr;
delete[] tinf;
}
void readSamples(Stream &stream) {
stream.read(soundData, soundDataSize = stream.size);
@@ -3555,9 +4206,52 @@ namespace TR {
stream.read(mesh.flags.value);
stream.read(mesh.vCount);
}
if (version == VER_TR1_SEGA) {
mesh.center.x = swap16(mesh.center.x);
mesh.center.y = swap16(mesh.center.y);
mesh.center.z = swap16(mesh.center.z);
mesh.radius = swap16(mesh.radius);
mesh.flags.value = swap16(mesh.flags.value);
mesh.vCount = swap16(mesh.vCount);
}
}
switch (version) {
case VER_TR1_SEGA : {
mesh.vertices = new Mesh::Vertex[mesh.vCount];
for (int i = 0; i < mesh.vCount; i++) {
short4 &c = mesh.vertices[i].coord;
c.x = stream.readBE16();
c.y = stream.readBE16();
c.z = stream.readBE16();
}
int16 nCount = stream.readBE16();
ASSERT(mesh.vCount == abs(nCount));
for (int i = 0; i < mesh.vCount; i++) {
short4 &c = mesh.vertices[i].coord;
short4 &n = mesh.vertices[i].normal;
if (nCount > 0) { // normal
n.x = stream.readBE16();
n.y = stream.readBE16();
n.z = stream.readBE16();
n.w = 1;
c.w = 0x1FFF;
} else { // intensity
c.w = stream.readBE16();
n = short4( 0, 0, 0, 0 );
}
}
mesh.fCount = stream.readBE16();
mesh.faces = new Face[mesh.fCount];
mesh.fCount = 0;
// TODO read faces
//ASSERT(false);
break;
}
case VER_TR1_PC :
case VER_TR2_PC :
case VER_TR3_PC : {
@@ -3840,6 +4534,21 @@ namespace TR {
}
switch (version) {
case VER_TR1_SEGA : {
struct {
uint16 attribute;
Tile tile;
uint8 xh0, x0, yh0, y0;
uint8 xh1, x1, yh1, y1;
uint8 xh2, x2, yh2, y2;
uint8 xh3, x3, yh3, y3;
} d;
d.attribute = 0;
d.tile.value = 0;
stream.raw(&d.xh0, 16);
SET_PARAMS(t, d, 0);
break;
}
case VER_TR1_PC :
case VER_TR2_PC :
case VER_TR3_PC : {
@@ -4064,6 +4773,10 @@ namespace TR {
void fillObjectTexture(Tile32 *dst, const short4 &uv, int16 tileIndex, int16 clutIndex) {
// convert to RGBA
switch (version) {
case VER_TR1_SEGA : {
// TODO
break;
}
case VER_TR1_PC : {
ASSERT(tiles8);
ASSERT(palette);

View File

@@ -72,12 +72,14 @@
#define SQR(x) ((x)*(x))
#define randf() ((float)rand()/RAND_MAX)
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
typedef signed long long int64;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
#define FOURCC(str) uint32(((uint8*)(str))[0] | (((uint8*)(str))[1] << 8) | (((uint8*)(str))[2] << 16) | (((uint8*)(str))[3] << 24) )
@@ -1335,6 +1337,36 @@ struct Stream {
a = NULL;
return a;
}
inline uint8 read() {
uint8 x;
return read(x);
}
inline uint16 readLE16() {
uint16 x;
return read(x);
}
inline uint32 readLE32() {
uint32 x;
return read(x);
}
inline uint16 readBE16() {
uint16 x;
return swap16(read(x));
}
inline uint32 readBE32() {
uint32 x;
return swap32(read(x));
}
inline uint64 read64() {
uint64 x;
return read(x);
}
};