mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-16 18:14:05 +02:00
#15 TR3 PSX format loader (WIP)
This commit is contained in:
477
src/format.h
477
src/format.h
@@ -2265,6 +2265,9 @@ namespace TR {
|
||||
int16 meshesCount;
|
||||
Mesh meshes[MAX_MESHES];
|
||||
|
||||
int32 meshDataCount;
|
||||
uint16 *meshData;
|
||||
|
||||
int32 meshOffsetsCount;
|
||||
uint32 *meshOffsets;
|
||||
|
||||
@@ -2459,12 +2462,13 @@ namespace TR {
|
||||
#define MAGIC_TR3_PC1 0xFF080038
|
||||
#define MAGIC_TR3_PC2 0xFF180038
|
||||
#define MAGIC_TR3_PC3 0xFF180034
|
||||
#define MAGIC_TR3_PSX 0xFFFFFFC8
|
||||
|
||||
id = TR::getLevelID(stream.size, version, isDemoLevel);
|
||||
|
||||
if (version == VER_UNKNOWN || version == VER_TR1_PSX) {
|
||||
stream.read(magic);
|
||||
if (magic != MAGIC_TR1_PC && magic != MAGIC_TR2_PC && magic != MAGIC_TR3_PC1 && magic != MAGIC_TR3_PC2 && magic != MAGIC_TR3_PC3) {
|
||||
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);
|
||||
}
|
||||
@@ -2476,6 +2480,7 @@ namespace TR {
|
||||
case MAGIC_TR3_PC1 :
|
||||
case MAGIC_TR3_PC2 :
|
||||
case MAGIC_TR3_PC3 : version = VER_TR3_PC; break;
|
||||
case MAGIC_TR3_PSX : version = VER_TR3_PSX; break;
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
@@ -2499,6 +2504,25 @@ namespace TR {
|
||||
stream.read(soundData, soundDataSize);
|
||||
}
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
stream.read(soundOffsets, stream.read(soundOffsetsCount));
|
||||
stream.read(soundDataSize);
|
||||
stream.read(soundData, soundDataSize);
|
||||
}
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
// skip code modules
|
||||
int size;
|
||||
for (int i = 0; i < 13; i++) {
|
||||
stream.read(size);
|
||||
if (size) {
|
||||
stream.seek(size);
|
||||
stream.read(size);
|
||||
stream.seek(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (version == VER_TR2_PC || version == VER_TR3_PC) {
|
||||
stream.read(palette, 256);
|
||||
stream.read(palette32, 256);
|
||||
@@ -2543,18 +2567,36 @@ namespace TR {
|
||||
stream.read(cluts, clutsCount = 1024);
|
||||
//stream.seek(0x4000);
|
||||
}
|
||||
|
||||
if (version != VER_TR3_PSX)
|
||||
stream.read(unused);
|
||||
|
||||
// rooms
|
||||
rooms = stream.read(roomsCount) ? new Room[roomsCount] : NULL;
|
||||
for (int i = 0; i < roomsCount; i++)
|
||||
readRoom(stream, rooms[i]);
|
||||
readRoom(stream, i);
|
||||
|
||||
// floors
|
||||
stream.read(floors, stream.read(floorsCount));
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
// outside room offsets
|
||||
stream.seek(27 * 27 * 2);
|
||||
// outside rooms table
|
||||
int size;
|
||||
stream.read(size);
|
||||
stream.seek(size);
|
||||
// room mesh bbox
|
||||
stream.read(size);
|
||||
stream.seek(8 * size);
|
||||
}
|
||||
|
||||
// meshes
|
||||
readMeshes(stream);
|
||||
meshesCount = 0;
|
||||
stream.read(meshData, stream.read(meshDataCount));
|
||||
stream.read(meshOffsets, stream.read(meshOffsetsCount));
|
||||
// animations
|
||||
|
||||
stream.read(anims, stream.read(animsCount));
|
||||
stream.read(states, stream.read(statesCount));
|
||||
stream.read(ranges, stream.read(rangesCount));
|
||||
@@ -2576,18 +2618,33 @@ namespace TR {
|
||||
if (version & VER_PSX)
|
||||
stream.seek(2);
|
||||
m.type = Entity::remap(version, m.type);
|
||||
|
||||
for (int j = 0; j < m.mCount; j++)
|
||||
initMesh(m.mStart + j, m.type);
|
||||
}
|
||||
stream.read(staticMeshes, stream.read(staticMeshesCount));
|
||||
|
||||
if (version == VER_TR2_PSX) {
|
||||
for (int i = 0; i < staticMeshesCount; i++)
|
||||
initMesh(staticMeshes[i].mesh);
|
||||
|
||||
remapMeshOffsetsToIndices();
|
||||
|
||||
delete[] meshData;
|
||||
meshData = NULL;
|
||||
|
||||
LOG("meshes: %d\n", meshesCount);
|
||||
|
||||
if (version == VER_TR2_PSX || version == VER_TR3_PSX) {
|
||||
stream.read(tiles4, stream.read(tilesCount));
|
||||
stream.read(cluts, stream.read(clutsCount));
|
||||
//stream.read(palette32, stream.read(paletteSize));
|
||||
if (version == VER_TR3_PSX) {
|
||||
stream.seek(clutsCount * sizeof(CLUT));
|
||||
} else
|
||||
stream.seek(4);
|
||||
}
|
||||
|
||||
// textures & UV
|
||||
if (version & (VER_TR1 | VER_TR2))
|
||||
if (version != VER_TR3_PC)
|
||||
readObjectTex(stream);
|
||||
readSpriteTex(stream);
|
||||
// palette for demo levels
|
||||
@@ -2636,7 +2693,7 @@ namespace TR {
|
||||
// animated textures
|
||||
readAnimTex(stream);
|
||||
|
||||
if (version & VER_TR3)
|
||||
if (version == VER_TR3_PC)
|
||||
readObjectTex(stream);
|
||||
|
||||
// entities (enemies, items, lara etc.)
|
||||
@@ -2656,6 +2713,48 @@ namespace TR {
|
||||
if (version == VER_TR2_PSX)
|
||||
stream.seek(4);
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
uint32 skyColor;
|
||||
stream.read(skyColor);
|
||||
|
||||
int32 roomTexCount;
|
||||
stream.read(roomTexCount);
|
||||
|
||||
if (roomTexCount) {
|
||||
ObjectTexture *oldTex = objectTextures;
|
||||
// reallocate textures info to add room textures
|
||||
objectTextures = new ObjectTexture[objectTexturesCount + roomTexCount * 3];
|
||||
if (oldTex) {
|
||||
memcpy(objectTextures, oldTex, sizeof(ObjectTexture) * objectTexturesCount);
|
||||
delete[] oldTex;
|
||||
}
|
||||
|
||||
// load room textures
|
||||
for (int i = objectTexturesCount; i < objectTexturesCount + roomTexCount * 3; i++) {
|
||||
ObjectTexture &t = objectTextures[i];
|
||||
readObjectTex(stream, t);
|
||||
t.attribute = 0;
|
||||
}
|
||||
|
||||
// remap room texture indices
|
||||
for (int i = 0; i < roomsCount; i++) {
|
||||
Room::Data &d = rooms[i].data;
|
||||
for (int j = 0; j < d.fCount; j++) {
|
||||
Face &f = d.faces[j];
|
||||
|
||||
//ASSERT(d.faces[j].flags.texture < roomTexCount);
|
||||
|
||||
if (f.flags.texture < roomTexCount) {
|
||||
f.flags.texture *= 3;
|
||||
f.flags.texture += objectTexturesCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objectTexturesCount += roomTexCount * 3;
|
||||
}
|
||||
}
|
||||
|
||||
// sounds
|
||||
stream.read(soundsMap, (version & VER_TR1) ? 256 : 370);
|
||||
soundsInfo = stream.read(soundsInfoCount) ? new SoundInfo[soundsInfoCount] : NULL;
|
||||
@@ -2694,6 +2793,7 @@ namespace TR {
|
||||
|
||||
// cinematic frames for cameras (PSX)
|
||||
if (version & VER_PSX) {
|
||||
if (version != VER_TR3_PSX)
|
||||
stream.seek(4);
|
||||
stream.read(cameraFrames, stream.read(cameraFramesCount));
|
||||
}
|
||||
@@ -2958,7 +3058,8 @@ namespace TR {
|
||||
#endif
|
||||
}
|
||||
|
||||
void readRoom(Stream &stream, Room &r) {
|
||||
void readRoom(Stream &stream, int roomIndex) {
|
||||
Room &r = rooms[roomIndex];
|
||||
Room::Data &d = r.data;
|
||||
// room info
|
||||
stream.read(r.info);
|
||||
@@ -2966,24 +3067,170 @@ namespace TR {
|
||||
stream.read(d.size);
|
||||
int startOffset = stream.pos;
|
||||
if (version == VER_TR1_PSX) stream.seek(2);
|
||||
|
||||
// only for TR3 PSX
|
||||
int32 partsCount;
|
||||
int32 parts[16];
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
d.vCount = d.tCount = d.rCount = d.fCount = 0;
|
||||
// pre-calculate number of vertices, triangles and rectangles for TR3 PSX format
|
||||
stream.read(partsCount);
|
||||
stream.raw(parts, sizeof(parts));
|
||||
|
||||
for (int pIndex = 0; pIndex < partsCount; pIndex++) {
|
||||
stream.setPos(startOffset + parts[pIndex] + 6);
|
||||
|
||||
uint8 tmpV, tmpT;
|
||||
d.vCount += stream.read(tmpV);
|
||||
d.tCount += stream.read(tmpT);
|
||||
|
||||
stream.seek(tmpV * 4 + tmpT * 4); // skip vertices and triangles
|
||||
|
||||
int q = 0;
|
||||
while (1) {
|
||||
uint32 info;
|
||||
if (!q) {
|
||||
stream.read(info);
|
||||
q = 3;
|
||||
}
|
||||
if (!(info ^ 0x03FF)) // info is 0b1111111111
|
||||
break;
|
||||
info >>= 10;
|
||||
stream.seek(4); // skip rectangle indices
|
||||
d.rCount++;
|
||||
q--;
|
||||
}
|
||||
}
|
||||
|
||||
if (partsCount != 0)
|
||||
stream.seek(4); // skip unknown shit
|
||||
|
||||
ASSERT(d.size * 2 == stream.pos - startOffset);
|
||||
|
||||
d.fCount = d.rCount + d.tCount;
|
||||
d.faces = d.fCount ? new Face[d.fCount] : NULL;
|
||||
d.vertices = d.vCount ? new Room::Data::Vertex[d.vCount] : NULL;
|
||||
|
||||
d.vCount = d.fCount = 0;
|
||||
} else
|
||||
d.vertices = stream.read(d.vCount) ? new Room::Data::Vertex[d.vCount] : NULL;
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
for (int pIndex = 0; pIndex < partsCount; pIndex++) {
|
||||
stream.setPos(startOffset + parts[pIndex] + 4);
|
||||
|
||||
uint8 rIndex, rFlags;
|
||||
stream.read(rIndex); // room index
|
||||
stream.read(rFlags); // room flags
|
||||
|
||||
ASSERT(rIndex == roomIndex);
|
||||
r.flags.value = rFlags;
|
||||
|
||||
uint8 vCount, tCount;
|
||||
stream.read(vCount);
|
||||
stream.read(tCount);
|
||||
|
||||
int32 vStart = d.vCount;
|
||||
// read vertices
|
||||
for (uint8 i = 0; i < vCount; i++) {
|
||||
Room::Data::Vertex &v = d.vertices[d.vCount++];
|
||||
|
||||
struct {
|
||||
uint32 z:5, y:5, x:5, :1, lighting:8, attributes:8;
|
||||
} cv;
|
||||
|
||||
stream.raw(&cv, sizeof(cv));
|
||||
|
||||
v.vertex.x = (cv.x << 10);
|
||||
v.vertex.y = (cv.y << 8) + r.info.yTop;
|
||||
v.vertex.z = (cv.z << 10);
|
||||
}
|
||||
|
||||
// read triangles
|
||||
for (uint8 i = 0; i < tCount; i++) {
|
||||
struct {
|
||||
uint32 i0:7, i1:7, i2:7, doubleSided:1, texture:10;
|
||||
} t;
|
||||
|
||||
stream.raw(&t, sizeof(t));
|
||||
|
||||
Face &f = d.faces[d.fCount++];
|
||||
f.flags.texture = t.texture;
|
||||
f.flags.doubleSided = t.doubleSided;
|
||||
f.vCount = 3;
|
||||
f.colored = false;
|
||||
f.vertices[0] = vStart + t.i0;
|
||||
f.vertices[1] = vStart + t.i1;
|
||||
f.vertices[2] = vStart + t.i2;
|
||||
f.vertices[3] = 0;
|
||||
ASSERT(f.vertices[0] < d.vCount);
|
||||
ASSERT(f.vertices[1] < d.vCount);
|
||||
ASSERT(f.vertices[2] < d.vCount);
|
||||
}
|
||||
// read rectangles
|
||||
int q = 0;
|
||||
while (1) {
|
||||
uint32 info;
|
||||
if (!q) {
|
||||
stream.read(info);
|
||||
q = 3;
|
||||
}
|
||||
|
||||
uint32 texture = info & 0x03FF;
|
||||
|
||||
//ASSERT(!(info ^ 0x3FF) == !(texture ^ 0x3FF));
|
||||
|
||||
if (!(info ^ 0x3FF))
|
||||
break;
|
||||
info >>= 10;
|
||||
|
||||
struct {
|
||||
uint32 i0:7, i1:7, i2:7, i3:7, :3, doubleSided:1;
|
||||
} r;
|
||||
stream.raw(&r, sizeof(r));
|
||||
|
||||
Face &f = d.faces[d.fCount++];
|
||||
f.flags.texture = texture;
|
||||
f.flags.doubleSided = r.doubleSided;
|
||||
f.vCount = 4;
|
||||
f.colored = false;
|
||||
f.vertices[0] = vStart + r.i0;
|
||||
f.vertices[1] = vStart + r.i1;
|
||||
f.vertices[2] = vStart + r.i2;
|
||||
f.vertices[3] = vStart + r.i3;
|
||||
|
||||
if (texture == 1023) {
|
||||
f.flags.texture = 0;
|
||||
f.vertices[0] = f.vertices[1] = f.vertices[2] = f.vertices[3] = 0;
|
||||
}
|
||||
|
||||
ASSERT(f.vertices[0] < d.vCount);
|
||||
ASSERT(f.vertices[1] < d.vCount);
|
||||
ASSERT(f.vertices[2] < d.vCount);
|
||||
ASSERT(f.vertices[3] < d.vCount);
|
||||
|
||||
q--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < d.vCount; i++) {
|
||||
Room::Data::Vertex &v = d.vertices[i];
|
||||
|
||||
uint16 lighting;
|
||||
|
||||
if (version == VER_TR2_PSX) {
|
||||
union Compressed {
|
||||
struct { uint32 lighting:8, attributes:8, z:5, y:5, x:5, w:1; };
|
||||
uint32 value;
|
||||
} comp;
|
||||
stream.read(comp.value);
|
||||
v.vertex.x = (comp.x << 10);
|
||||
v.vertex.y = (comp.y << 8) + r.info.yTop;
|
||||
v.vertex.z = (comp.z << 10);
|
||||
lighting = comp.lighting;
|
||||
v.attributes = comp.attributes;
|
||||
ASSERT(comp.w == 0);
|
||||
struct {
|
||||
uint32 lighting:8, attributes:8, z:5, y:5, x:5, :1;
|
||||
} cv;
|
||||
|
||||
stream.raw(&cv, sizeof(cv));
|
||||
|
||||
v.vertex.x = (cv.x << 10);
|
||||
v.vertex.y = (cv.y << 8) + r.info.yTop;
|
||||
v.vertex.z = (cv.z << 10);
|
||||
lighting = cv.lighting;
|
||||
v.attributes = cv.attributes;
|
||||
} else {
|
||||
stream.read(v.vertex.x);
|
||||
stream.read(v.vertex.y);
|
||||
@@ -3035,6 +3282,7 @@ namespace TR {
|
||||
int16 tmpCount;
|
||||
stream.read(tmpCount);
|
||||
ASSERT(tmpCount == d.rCount);
|
||||
|
||||
if (version == VER_TR2_PSX) {
|
||||
for (int i = 0; i < d.rCount; i++)
|
||||
stream.raw(&d.faces[i].flags.value, sizeof(uint16));
|
||||
@@ -3052,13 +3300,9 @@ namespace TR {
|
||||
} else
|
||||
for (int i = 0; i < d.rCount; i++) readFace(stream, d.faces[idx++], false, false);
|
||||
|
||||
if (version & VER_PSX) { // swap indices (quad strip -> quad list) only for PSX version
|
||||
for (int j = 0; j < d.rCount; j++)
|
||||
swap(d.faces[j].vertices[2], d.faces[j].vertices[3]);
|
||||
}
|
||||
|
||||
stream.read(tmpCount);
|
||||
ASSERT(tmpCount == d.tCount);
|
||||
|
||||
if (version == VER_TR2_PSX) {
|
||||
stream.seek(2);
|
||||
for (int i = 0; i < d.tCount; i++) {
|
||||
@@ -3076,18 +3320,31 @@ namespace TR {
|
||||
for (int i = 0; i < d.tCount; i++)
|
||||
readFace(stream, d.faces[idx++], false, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (version & VER_PSX) { // swap indices (quad strip -> quad list) only for PSX version
|
||||
for (int j = 0; j < d.fCount; j++)
|
||||
if (d.faces[j].vCount == 4)
|
||||
swap(d.faces[j].vertices[2], d.faces[j].vertices[3]);
|
||||
}
|
||||
|
||||
// room sprites
|
||||
if (version == VER_TR2_PSX) { // there is no room sprites
|
||||
if (version == VER_TR2_PSX || version == VER_TR3_PSX) { // there is no room sprites
|
||||
d.sprites = NULL;
|
||||
d.sCount = 0;
|
||||
} else
|
||||
stream.read(d.sprites, stream.read(d.sCount));
|
||||
|
||||
if (version == VER_TR3_PSX)
|
||||
if (partsCount != 0)
|
||||
stream.seek(4); // skip unknown shit
|
||||
|
||||
ASSERT(d.size * 2 == stream.pos - startOffset);
|
||||
|
||||
// portals
|
||||
stream.read(r.portals, stream.read(r.portalsCount));
|
||||
|
||||
if (version == VER_TR2_PSX) {
|
||||
if (version == VER_TR2_PSX || version == VER_TR3_PSX) {
|
||||
for (int i = 0; i < r.portalsCount; i++) {
|
||||
r.portals[i].vertices[0].y += r.info.yTop;
|
||||
r.portals[i].vertices[1].y += r.info.yTop;
|
||||
@@ -3122,11 +3379,15 @@ namespace TR {
|
||||
}
|
||||
// ambient light luminance
|
||||
stream.read(r.ambient);
|
||||
|
||||
if (version != VER_TR3_PSX) {
|
||||
if (version & (VER_TR2 | VER_TR3))
|
||||
stream.read(r.ambient2);
|
||||
|
||||
if (version & VER_TR2)
|
||||
stream.read(r.lightMode);
|
||||
} else
|
||||
stream.read(r.ambient2);
|
||||
|
||||
// lights
|
||||
r.lights = stream.read(r.lightsCount) ? new Room::Light[r.lightsCount] : NULL;
|
||||
@@ -3138,7 +3399,7 @@ namespace TR {
|
||||
|
||||
uint16 intensity;
|
||||
|
||||
if (version == VER_TR3_PC)
|
||||
if (version & VER_TR3)
|
||||
stream.read(light.color);
|
||||
|
||||
stream.read(intensity);
|
||||
@@ -3196,30 +3457,53 @@ namespace TR {
|
||||
// misc flags
|
||||
stream.read(r.alternateRoom);
|
||||
stream.read(r.flags.value);
|
||||
if (version & VER_TR3) {
|
||||
if (version == VER_TR3_PC) {
|
||||
stream.read(r.waterScheme);
|
||||
stream.read(r.reverbType);
|
||||
stream.read(r.filter); // unused
|
||||
}
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
//stream.seek(1);
|
||||
stream.read(r.waterScheme);
|
||||
stream.read(r.reverbType);
|
||||
stream.seek(1);
|
||||
}
|
||||
|
||||
r.dynLightsCount = 0;
|
||||
}
|
||||
|
||||
void initMesh(int mIndex, Entity::Type type = Entity::LARA) {
|
||||
if (type == Entity::SKY)
|
||||
return;
|
||||
|
||||
int offset = meshOffsets[mIndex];
|
||||
for (int i = 0; i < meshesCount; i++)
|
||||
if (meshes[i].offset == offset)
|
||||
return;
|
||||
|
||||
Stream stream(NULL, &meshData[offset / 2], 1024 * 1024);
|
||||
|
||||
void readMeshes(Stream &stream) {
|
||||
uint32 meshDataSize;
|
||||
stream.read(meshDataSize);
|
||||
int32 start = stream.pos;
|
||||
int32 end = stream.pos + meshDataSize * 2;
|
||||
meshesCount = 0;
|
||||
while (stream.pos < end) {
|
||||
Mesh &mesh = meshes[meshesCount++];
|
||||
mesh.offset = stream.pos - start;
|
||||
mesh.offset = offset;
|
||||
|
||||
uint32 fOffset;
|
||||
|
||||
stream.read(mesh.center);
|
||||
stream.read(mesh.radius);
|
||||
|
||||
//ASSERT(mesh.radius >= 0);
|
||||
if (version == VER_TR3_PSX) {
|
||||
uint8 tmp;
|
||||
uint16 tmpOffset;
|
||||
mesh.vCount = stream.read(tmp);
|
||||
mesh.flags.value = stream.read(tmp);
|
||||
fOffset = stream.pos + stream.read(tmpOffset);
|
||||
//LOG("offset:%d\n", offset - stream.pos);
|
||||
} else {
|
||||
stream.read(mesh.flags.value);
|
||||
stream.read(mesh.vCount);
|
||||
}
|
||||
|
||||
switch (version) {
|
||||
case VER_TR1_PC :
|
||||
@@ -3322,7 +3606,7 @@ namespace TR {
|
||||
}
|
||||
}
|
||||
|
||||
if (version == VER_TR2_PSX && nCount > 0) { // TODO probably for unused meshes only but need to check
|
||||
if ((version & VER_TR2) && nCount > 0) { // TODO probably for unused meshes only but need to check
|
||||
uint16 crCount = 0, ctCount = 0;
|
||||
stream.read(crCount);
|
||||
stream.seek((FACE4_SIZE + 2) * crCount);
|
||||
@@ -3362,6 +3646,89 @@ namespace TR {
|
||||
|
||||
break;
|
||||
}
|
||||
case VER_TR3_PSX : {
|
||||
if (!mesh.vCount) {
|
||||
mesh.vertices = NULL;
|
||||
mesh.faces = NULL;
|
||||
mesh.tCount = mesh.rCount = mesh.fCount = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
mesh.vertices = new Mesh::Vertex[mesh.vCount];
|
||||
|
||||
for (int i = 0; i < mesh.vCount; i++)
|
||||
stream.read(mesh.vertices[i].coord);
|
||||
|
||||
if (mesh.flags.value & 0x80) { // static mesh without normals
|
||||
for (int i = 0; i < mesh.vCount; i++)
|
||||
mesh.vertices[i].normal = short4( 0, 0, 0, 0 );
|
||||
} else {
|
||||
for (int i = 0; i < mesh.vCount; i++)
|
||||
stream.read(mesh.vertices[i].normal);
|
||||
}
|
||||
|
||||
ASSERT(stream.pos == fOffset);
|
||||
|
||||
stream.setPos(fOffset);
|
||||
stream.read(mesh.tCount);
|
||||
stream.read(mesh.rCount);
|
||||
mesh.fCount = mesh.rCount + mesh.tCount;
|
||||
mesh.faces = mesh.fCount ? new Face[mesh.fCount] : NULL;
|
||||
|
||||
// read triangles
|
||||
int idx = 0;
|
||||
uint32 info;
|
||||
|
||||
for (int i = 0; i < mesh.tCount; i++) {
|
||||
if (!(i % 4))
|
||||
stream.read(info);
|
||||
|
||||
Face &f = mesh.faces[idx++];
|
||||
f.flags.doubleSided = 0;
|
||||
f.flags.texture = info & 0xFF;
|
||||
f.colored = false;
|
||||
f.vCount = 3;
|
||||
|
||||
struct {
|
||||
uint32 i0:8, i1:8, i2:8, :8;
|
||||
} r;
|
||||
stream.raw(&r, sizeof(r));
|
||||
//stream.raw(&indices, sizeof(indices));
|
||||
|
||||
f.vertices[0] = r.i0;
|
||||
f.vertices[1] = r.i1;
|
||||
f.vertices[2] = r.i2;
|
||||
f.vertices[3] = 0;
|
||||
|
||||
info >>= 8;
|
||||
}
|
||||
|
||||
// read rectangles
|
||||
for (int i = 0; i < mesh.rCount; i++) {
|
||||
if (!(i % 2))
|
||||
stream.read(info);
|
||||
|
||||
Face &f = mesh.faces[idx++];
|
||||
f.flags.doubleSided = 0;
|
||||
f.flags.texture = info & 0xFFFF;
|
||||
f.colored = false;
|
||||
f.vCount = 4;
|
||||
|
||||
struct {
|
||||
uint32 i0:8, i1:8, i2:8, i3:8;
|
||||
} r;
|
||||
stream.raw(&r, sizeof(r));
|
||||
|
||||
f.vertices[0] = r.i0;
|
||||
f.vertices[1] = r.i1;
|
||||
f.vertices[2] = r.i3;
|
||||
f.vertices[3] = r.i2;
|
||||
|
||||
info >>= 16;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default : ASSERT(false);
|
||||
}
|
||||
|
||||
@@ -3393,20 +3760,11 @@ namespace TR {
|
||||
}
|
||||
|
||||
#undef RECALC_ZERO_NORMALS
|
||||
|
||||
int32 align = (stream.pos - start - mesh.offset) % 4;
|
||||
if (align) stream.seek(4 - align);
|
||||
}
|
||||
ASSERT(stream.pos - start == meshDataSize * 2);
|
||||
|
||||
stream.read(meshOffsets, stream.read(meshOffsetsCount));
|
||||
|
||||
// remap offsets to mesh index
|
||||
void remapMeshOffsetsToIndices() {
|
||||
for (int i = 0; i < meshOffsetsCount; i++) {
|
||||
int index = -1;
|
||||
// if (!meshOffsets[i] && i)
|
||||
// index = -1;
|
||||
// else
|
||||
for (int j = 0; j < meshesCount; j++)
|
||||
if (meshes[j].offset == meshOffsets[i]) {
|
||||
index = j;
|
||||
@@ -3416,7 +3774,7 @@ namespace TR {
|
||||
}
|
||||
}
|
||||
|
||||
void readObjectTex(Stream &stream) {
|
||||
void readObjectTex(Stream &stream, ObjectTexture &t) {
|
||||
#define SET_PARAMS(t, d, c) {\
|
||||
t.clut = c;\
|
||||
t.tile = d.tile;\
|
||||
@@ -3429,9 +3787,6 @@ namespace TR {
|
||||
ASSERT(d.x0 < 256 && d.x1 < 256 && d.x2 < 256 && d.x3 < 256 && d.y0 < 256 && d.y1 < 256 && d.y2 < 256 && d.y3 < 256);\
|
||||
}
|
||||
|
||||
objectTextures = stream.read(objectTexturesCount) ? new ObjectTexture[objectTexturesCount] : NULL;
|
||||
for (int i = 0; i < objectTexturesCount; i++) {
|
||||
ObjectTexture &t = objectTextures[i];
|
||||
switch (version) {
|
||||
case VER_TR1_PC :
|
||||
case VER_TR2_PC :
|
||||
@@ -3449,7 +3804,8 @@ namespace TR {
|
||||
break;
|
||||
}
|
||||
case VER_TR1_PSX :
|
||||
case VER_TR2_PSX : {
|
||||
case VER_TR2_PSX :
|
||||
case VER_TR3_PSX : {
|
||||
struct {
|
||||
uint8 x0, y0;
|
||||
uint16 clut;
|
||||
@@ -3466,11 +3822,16 @@ namespace TR {
|
||||
}
|
||||
default : ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
#undef SET_PARAMS
|
||||
}
|
||||
|
||||
void readObjectTex(Stream &stream) {
|
||||
objectTextures = stream.read(objectTexturesCount) ? new ObjectTexture[objectTexturesCount] : NULL;
|
||||
for (int i = 0; i < objectTexturesCount; i++)
|
||||
readObjectTex(stream, objectTextures[i]);
|
||||
}
|
||||
|
||||
void readSpriteTex(Stream &stream) {
|
||||
#define SET_PARAMS(t, d, c) {\
|
||||
t.clut = c;\
|
||||
@@ -3501,7 +3862,8 @@ namespace TR {
|
||||
break;
|
||||
}
|
||||
case VER_TR1_PSX :
|
||||
case VER_TR2_PSX : {
|
||||
case VER_TR2_PSX :
|
||||
case VER_TR3_PSX : {
|
||||
struct {
|
||||
int16 l, t, r, b;
|
||||
uint16 clut;
|
||||
@@ -3647,7 +4009,8 @@ namespace TR {
|
||||
break;
|
||||
}
|
||||
case VER_TR1_PSX :
|
||||
case VER_TR2_PSX : {
|
||||
case VER_TR2_PSX :
|
||||
case VER_TR3_PSX : {
|
||||
ASSERT(tiles4);
|
||||
ASSERT(cluts);
|
||||
|
||||
@@ -3717,7 +4080,8 @@ namespace TR {
|
||||
case VER_TR2_PC :
|
||||
case VER_TR3_PC : return palette32[(texture >> 8) & 0xFF];
|
||||
case VER_TR1_PSX :
|
||||
case VER_TR2_PSX : {
|
||||
case VER_TR2_PSX :
|
||||
case VER_TR3_PSX : {
|
||||
ASSERT((texture & 0x7FFF) < 256);
|
||||
ObjectTexture &t = objectTextures[texture & 0x7FFF];
|
||||
int idx = (t.texCoord[0].y * 256 + t.texCoord[0].x) / 2;
|
||||
@@ -3741,6 +4105,7 @@ namespace TR {
|
||||
case VER_TR3_PC : size = FOURCC(data + 4) + 8; break; // read size from wave header
|
||||
case VER_TR1_PSX :
|
||||
case VER_TR2_PSX : size = soundSize[index]; break;
|
||||
case VER_TR3_PSX : return NULL; // TR3_TODO
|
||||
default : ASSERT(false);
|
||||
}
|
||||
return new Stream(NULL, data, size);
|
||||
|
@@ -443,7 +443,7 @@ struct MeshBuilder {
|
||||
TR::Model &model = level.models[i];
|
||||
for (int j = 0; j < model.mCount; j++) {
|
||||
int index = level.meshOffsets[model.mStart + j];
|
||||
if (!index && model.mStart + j > 0)
|
||||
if (index == -1)
|
||||
continue;
|
||||
TR::Mesh &mesh = level.meshes[index];
|
||||
iCount += (mesh.rCount * 6 + mesh.tCount * 3) * DOUBLE_SIDED;
|
||||
@@ -562,13 +562,14 @@ struct MeshBuilder {
|
||||
#endif
|
||||
|
||||
int index = level.meshOffsets[model.mStart + j];
|
||||
if (index || model.mStart + j <= 0) {
|
||||
if (index == -1)
|
||||
continue;
|
||||
|
||||
TR::Mesh &mesh = level.meshes[index];
|
||||
#ifndef MERGE_MODELS
|
||||
geom.getNextRange(vStartModel, iCount, 0xFFFF, 0xFFFF);
|
||||
#endif
|
||||
buildMesh(geom, blendMask, mesh, level, indices, vertices, iCount, vCount, vStartModel, j, 0, 0, 0, 0, COLOR_WHITE);
|
||||
}
|
||||
|
||||
#ifndef MERGE_MODELS
|
||||
geom.finish(iCount);
|
||||
|
Reference in New Issue
Block a user