mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-14 17:14:29 +02:00
#15 add TR3 PSX format support (with bugs)
This commit is contained in:
368
src/format.h
368
src/format.h
@@ -1101,6 +1101,9 @@ namespace TR {
|
||||
struct { uint16 r:5, g:5, b:5, a:1; };
|
||||
uint16 value;
|
||||
|
||||
Color16() {}
|
||||
Color16(uint16 value) : value(value) {}
|
||||
|
||||
Color32 getBGR() const { return Color32((b << 3) | (b >> 2), (g << 3) | (g >> 2), (r << 3) | (r >> 2), 255); }
|
||||
operator Color24() const { return Color24((r << 3) | (r >> 2), (g << 3) | (g >> 2), (b << 3) | (b >> 2)); }
|
||||
operator Color32() const { return Color32((r << 3) | (r >> 2), (g << 3) | (g >> 2), (b << 3) | (b >> 2), -a); }
|
||||
@@ -1122,6 +1125,7 @@ namespace TR {
|
||||
Tile tile; // tile or palette index
|
||||
uint16 attribute:15, animated:1; // 0 - opaque, 1 - transparent, 2 - blend additive, animated
|
||||
short2 texCoord[4];
|
||||
short2 texCoordAtlas[4];
|
||||
|
||||
short4 getMinMax() const {
|
||||
return short4(
|
||||
@@ -1131,6 +1135,15 @@ namespace TR {
|
||||
max(max(texCoord[0].y, texCoord[1].y), texCoord[2].y)
|
||||
);
|
||||
}
|
||||
|
||||
short4 getMinMaxAtlas() const {
|
||||
return short4(
|
||||
min(min(texCoordAtlas[0].x, texCoordAtlas[1].x), texCoordAtlas[2].x),
|
||||
min(min(texCoordAtlas[0].y, texCoordAtlas[1].y), texCoordAtlas[2].y),
|
||||
max(max(texCoordAtlas[0].x, texCoordAtlas[1].x), texCoordAtlas[2].x),
|
||||
max(max(texCoordAtlas[0].y, texCoordAtlas[1].y), texCoordAtlas[2].y)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct SpriteTexture {
|
||||
@@ -1138,10 +1151,15 @@ namespace TR {
|
||||
uint16 tile;
|
||||
int16 l, t, r, b;
|
||||
short2 texCoord[2];
|
||||
short2 texCoordAtlas[2];
|
||||
|
||||
short4 getMinMax() const {
|
||||
return short4( texCoord[0].x, texCoord[0].y, texCoord[1].x, texCoord[1].y );
|
||||
}
|
||||
|
||||
short4 getMinMaxAtlas() const {
|
||||
return short4( texCoordAtlas[0].x, texCoordAtlas[0].y, texCoordAtlas[1].x, texCoordAtlas[1].y );
|
||||
}
|
||||
};
|
||||
|
||||
// used for access from ::cmp func
|
||||
@@ -1294,8 +1312,8 @@ namespace TR {
|
||||
};
|
||||
uint16 value;
|
||||
} flags;
|
||||
uint16 reverbType;
|
||||
uint8 waterScheme;
|
||||
uint8 reverbType;
|
||||
uint8 filter;
|
||||
uint8 align;
|
||||
int32 waterLevel;
|
||||
@@ -1448,7 +1466,7 @@ namespace TR {
|
||||
int16 radius;
|
||||
union {
|
||||
struct {
|
||||
uint16 transparent:1, reserved:15;
|
||||
uint16 isStatic:1, reserved:15;
|
||||
};
|
||||
uint16 value;
|
||||
} flags;
|
||||
@@ -2252,7 +2270,6 @@ namespace TR {
|
||||
LevelID id;
|
||||
|
||||
int32 tilesCount;
|
||||
Tile32 *tiles;
|
||||
|
||||
uint32 unused;
|
||||
|
||||
@@ -2354,6 +2371,8 @@ namespace TR {
|
||||
uint32 *soundOffsets;
|
||||
uint32 *soundSize;
|
||||
|
||||
Color32 skyColor;
|
||||
|
||||
SaveGame save;
|
||||
SaveGame::CurrentState state;
|
||||
|
||||
@@ -2553,8 +2572,8 @@ namespace TR {
|
||||
stream.setPos(startPos + offsetTexTiles + 8);
|
||||
}
|
||||
|
||||
if (version & VER_PC) {
|
||||
// tiles
|
||||
if (version & VER_PC) {
|
||||
stream.read(tiles8, stream.read(tilesCount));
|
||||
}
|
||||
|
||||
@@ -2562,10 +2581,8 @@ namespace TR {
|
||||
stream.read(tiles16, tilesCount);
|
||||
|
||||
if (version == VER_TR1_PSX) {
|
||||
// tiles
|
||||
stream.read(tiles4, tilesCount = 13);
|
||||
stream.read(cluts, clutsCount = 1024);
|
||||
//stream.seek(0x4000);
|
||||
}
|
||||
|
||||
if (version != VER_TR3_PSX)
|
||||
@@ -2636,10 +2653,11 @@ namespace TR {
|
||||
|
||||
if (version == VER_TR2_PSX || version == VER_TR3_PSX) {
|
||||
stream.read(tiles4, stream.read(tilesCount));
|
||||
stream.read(cluts, stream.read(clutsCount));
|
||||
if (version == VER_TR3_PSX) {
|
||||
stream.seek(clutsCount * sizeof(CLUT));
|
||||
} else
|
||||
stream.read(clutsCount);
|
||||
if (version == VER_TR3_PSX)
|
||||
clutsCount *= 2; // read underwater cluts too
|
||||
stream.read(cluts, clutsCount);
|
||||
if (version != VER_TR3_PSX)
|
||||
stream.seek(4);
|
||||
}
|
||||
|
||||
@@ -2714,7 +2732,6 @@ namespace TR {
|
||||
stream.seek(4);
|
||||
|
||||
if (version == VER_TR3_PSX) {
|
||||
uint32 skyColor;
|
||||
stream.read(skyColor);
|
||||
|
||||
int32 roomTexCount;
|
||||
@@ -2723,17 +2740,16 @@ namespace TR {
|
||||
if (roomTexCount) {
|
||||
ObjectTexture *oldTex = objectTextures;
|
||||
// reallocate textures info to add room textures
|
||||
objectTextures = new ObjectTexture[objectTexturesCount + roomTexCount * 3];
|
||||
objectTextures = new ObjectTexture[objectTexturesCount + roomTexCount];
|
||||
if (oldTex) {
|
||||
memcpy(objectTextures, oldTex, sizeof(ObjectTexture) * objectTexturesCount);
|
||||
delete[] oldTex;
|
||||
}
|
||||
|
||||
// load room textures
|
||||
for (int i = objectTexturesCount; i < objectTexturesCount + roomTexCount * 3; i++) {
|
||||
for (int i = objectTexturesCount; i < objectTexturesCount + roomTexCount; i++) {
|
||||
ObjectTexture &t = objectTextures[i];
|
||||
readObjectTex(stream, t);
|
||||
t.attribute = 0;
|
||||
readObjectTex(stream, t, true);
|
||||
stream.seek(2 * 16); // skip 2 mipmap levels
|
||||
}
|
||||
|
||||
// remap room texture indices
|
||||
@@ -2742,16 +2758,13 @@ namespace TR {
|
||||
for (int j = 0; j < d.fCount; j++) {
|
||||
Face &f = d.faces[j];
|
||||
|
||||
//ASSERT(d.faces[j].flags.texture < roomTexCount);
|
||||
ASSERT(f.flags.texture < roomTexCount);
|
||||
|
||||
if (f.flags.texture < roomTexCount) {
|
||||
f.flags.texture *= 3;
|
||||
f.flags.texture += objectTexturesCount;
|
||||
}
|
||||
f.flags.texture += objectTexturesCount;
|
||||
}
|
||||
}
|
||||
|
||||
objectTexturesCount += roomTexCount * 3;
|
||||
LOG("objTex:%d + roomTex:%d = %d\n", objectTexturesCount, roomTexCount, objectTexturesCount + roomTexCount);
|
||||
objectTexturesCount += roomTexCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2798,6 +2811,19 @@ namespace TR {
|
||||
stream.read(cameraFrames, stream.read(cameraFramesCount));
|
||||
}
|
||||
|
||||
|
||||
// Amiga -> PC color palette for TR1 PC
|
||||
if (version == VER_TR1_PC) {
|
||||
ASSERT(palette);
|
||||
Color24 *c = palette;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
c->r <<= 2;
|
||||
c->g <<= 2;
|
||||
c->b <<= 2;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
initRoomMeshes();
|
||||
initAnimTex();
|
||||
|
||||
@@ -2813,7 +2839,6 @@ namespace TR {
|
||||
}
|
||||
|
||||
~Level() {
|
||||
delete[] tiles;
|
||||
// rooms
|
||||
for (int i = 0; i < roomsCount; i++) {
|
||||
Room &r = rooms[i];
|
||||
@@ -3094,7 +3119,8 @@ namespace TR {
|
||||
stream.read(info);
|
||||
q = 3;
|
||||
}
|
||||
if (!(info ^ 0x03FF)) // info is 0b1111111111
|
||||
uint32 texture = info & 0x03FF;
|
||||
if (texture == 0x03FF) // ending flag
|
||||
break;
|
||||
info >>= 10;
|
||||
stream.seek(4); // skip rectangle indices
|
||||
@@ -3103,10 +3129,8 @@ namespace TR {
|
||||
}
|
||||
}
|
||||
|
||||
if (partsCount != 0)
|
||||
stream.seek(4); // skip unknown shit
|
||||
|
||||
ASSERT(d.size * 2 == stream.pos - startOffset);
|
||||
ASSERT(int(d.size * 2) >= stream.pos - startOffset);
|
||||
stream.setPos(startOffset + d.size * 2);
|
||||
|
||||
d.fCount = d.rCount + d.tCount;
|
||||
d.faces = d.fCount ? new Face[d.fCount] : NULL;
|
||||
@@ -3137,27 +3161,32 @@ namespace TR {
|
||||
Room::Data::Vertex &v = d.vertices[d.vCount++];
|
||||
|
||||
struct {
|
||||
uint32 z:5, y:5, x:5, :1, lighting:8, attributes:8;
|
||||
uint32 z:5, y:5, x:5, color:16, unknown:1;
|
||||
} cv;
|
||||
|
||||
stream.raw(&cv, sizeof(cv));
|
||||
|
||||
//ASSERT(cv.attribute == 0);
|
||||
v.vertex.x = (cv.x << 10);
|
||||
v.vertex.y = (cv.y << 8) + r.info.yTop;
|
||||
v.vertex.z = (cv.z << 10);
|
||||
|
||||
v.attributes = 0;
|
||||
v.color = Color16(cv.color);
|
||||
}
|
||||
|
||||
// read triangles
|
||||
for (uint8 i = 0; i < tCount; i++) {
|
||||
struct {
|
||||
uint32 i0:7, i1:7, i2:7, doubleSided:1, texture:10;
|
||||
uint32 i0:7, i1:7, i2:7, texture:10, unknown:1;
|
||||
} t;
|
||||
|
||||
stream.raw(&t, sizeof(t));
|
||||
|
||||
ASSERT(t.unknown == 0);
|
||||
|
||||
Face &f = d.faces[d.fCount++];
|
||||
f.flags.texture = t.texture;
|
||||
f.flags.doubleSided = t.doubleSided;
|
||||
f.flags.doubleSided = false;
|
||||
f.vCount = 3;
|
||||
f.colored = false;
|
||||
f.vertices[0] = vStart + t.i0;
|
||||
@@ -3178,21 +3207,20 @@ namespace TR {
|
||||
}
|
||||
|
||||
uint32 texture = info & 0x03FF;
|
||||
|
||||
//ASSERT(!(info ^ 0x3FF) == !(texture ^ 0x3FF));
|
||||
|
||||
if (!(info ^ 0x3FF))
|
||||
if (texture == 0x3FF)
|
||||
break;
|
||||
info >>= 10;
|
||||
|
||||
struct {
|
||||
uint32 i0:7, i1:7, i2:7, i3:7, :3, doubleSided:1;
|
||||
uint32 i0:7, i1:7, i2:7, i3:7, unknown:4;
|
||||
} r;
|
||||
stream.raw(&r, sizeof(r));
|
||||
|
||||
ASSERT(r.unknown == 0);
|
||||
|
||||
Face &f = d.faces[d.fCount++];
|
||||
f.flags.texture = texture;
|
||||
f.flags.doubleSided = r.doubleSided;
|
||||
f.flags.doubleSided = false;
|
||||
f.vCount = 4;
|
||||
f.colored = false;
|
||||
f.vertices[0] = vStart + r.i0;
|
||||
@@ -3200,11 +3228,6 @@ namespace TR {
|
||||
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);
|
||||
@@ -3230,7 +3253,7 @@ namespace TR {
|
||||
v.vertex.y = (cv.y << 8) + r.info.yTop;
|
||||
v.vertex.z = (cv.z << 10);
|
||||
lighting = cv.lighting;
|
||||
v.attributes = cv.attributes;
|
||||
v.attributes = 0;//cv.attributes;
|
||||
} else {
|
||||
stream.read(v.vertex.x);
|
||||
stream.read(v.vertex.y);
|
||||
@@ -3339,7 +3362,8 @@ namespace TR {
|
||||
if (partsCount != 0)
|
||||
stream.seek(4); // skip unknown shit
|
||||
|
||||
ASSERT(d.size * 2 == stream.pos - startOffset);
|
||||
ASSERT(int(d.size * 2) >= stream.pos - startOffset);
|
||||
stream.setPos(startOffset + d.size * 2);
|
||||
|
||||
// portals
|
||||
stream.read(r.portals, stream.read(r.portalsCount));
|
||||
@@ -3435,48 +3459,38 @@ namespace TR {
|
||||
if (version & VER_TR3) {
|
||||
Color16 color;
|
||||
stream.read(color.value);
|
||||
m.color = color.getBGR();
|
||||
}
|
||||
|
||||
if (version & VER_TR2)
|
||||
m.color = color;
|
||||
stream.seek(2);
|
||||
} else {
|
||||
if (version & VER_TR2)
|
||||
stream.seek(2);
|
||||
|
||||
uint16 intensity;
|
||||
stream.read(intensity);
|
||||
if ((version & VER_VERSION) < VER_TR3) {
|
||||
int value = clamp((intensity > 0x1FFF) ? 255 : (255 - (intensity >> 5)), 0, 255);
|
||||
m.color.r = m.color.g = m.color.b = value;
|
||||
m.color.a = 0;
|
||||
uint16 intensity;
|
||||
stream.read(intensity);
|
||||
if ((version & VER_VERSION) < VER_TR3) {
|
||||
int value = clamp((intensity > 0x1FFF) ? 255 : (255 - (intensity >> 5)), 0, 255);
|
||||
m.color.r = m.color.g = m.color.b = value;
|
||||
m.color.a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
stream.read(m.meshID);
|
||||
if (version == VER_TR1_PSX)
|
||||
stream.seek(2); // just an align for PSX version
|
||||
stream.seek(2); // skip padding
|
||||
}
|
||||
|
||||
// misc flags
|
||||
stream.read(r.alternateRoom);
|
||||
stream.read(r.flags.value);
|
||||
if (version == VER_TR3_PC) {
|
||||
if (version & VER_TR3) {
|
||||
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)
|
||||
@@ -3489,20 +3503,29 @@ namespace TR {
|
||||
|
||||
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);
|
||||
if (type == Entity::SKY && version == VER_TR3_PSX) {
|
||||
mesh.center.x =
|
||||
mesh.center.y =
|
||||
mesh.center.z =
|
||||
mesh.radius =
|
||||
mesh.tCount = 0;
|
||||
mesh.flags.value = 0x80;
|
||||
stream.read(mesh.vCount);
|
||||
stream.read(mesh.rCount);
|
||||
} else {
|
||||
stream.read(mesh.center);
|
||||
stream.read(mesh.radius);
|
||||
|
||||
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);
|
||||
} else {
|
||||
stream.read(mesh.flags.value);
|
||||
stream.read(mesh.vCount);
|
||||
}
|
||||
}
|
||||
|
||||
switch (version) {
|
||||
@@ -3667,11 +3690,13 @@ namespace TR {
|
||||
stream.read(mesh.vertices[i].normal);
|
||||
}
|
||||
|
||||
ASSERT(stream.pos == fOffset);
|
||||
if (type != Entity::SKY) {
|
||||
ASSERT(stream.pos == fOffset);
|
||||
|
||||
stream.setPos(fOffset);
|
||||
stream.read(mesh.tCount);
|
||||
stream.read(mesh.rCount);
|
||||
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;
|
||||
|
||||
@@ -3682,18 +3707,17 @@ namespace TR {
|
||||
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;
|
||||
uint32 i0:8, i1:8, i2:8, tex:8;
|
||||
} r;
|
||||
stream.raw(&r, sizeof(r));
|
||||
//stream.raw(&indices, sizeof(indices));
|
||||
|
||||
Face &f = mesh.faces[idx++];
|
||||
f.flags.doubleSided = false;
|
||||
f.flags.texture = (info & 0xFF) | (r.tex << 8);
|
||||
f.colored = false;
|
||||
f.vCount = 3;
|
||||
|
||||
f.vertices[0] = r.i0;
|
||||
f.vertices[1] = r.i1;
|
||||
@@ -3709,7 +3733,7 @@ namespace TR {
|
||||
stream.read(info);
|
||||
|
||||
Face &f = mesh.faces[idx++];
|
||||
f.flags.doubleSided = 0;
|
||||
f.flags.doubleSided = false;
|
||||
f.flags.texture = info & 0xFFFF;
|
||||
f.colored = false;
|
||||
f.vCount = 4;
|
||||
@@ -3774,16 +3798,16 @@ namespace TR {
|
||||
}
|
||||
}
|
||||
|
||||
void readObjectTex(Stream &stream, ObjectTexture &t) {
|
||||
void readObjectTex(Stream &stream, ObjectTexture &t, bool isRoom = false) {
|
||||
#define SET_PARAMS(t, d, c) {\
|
||||
t.clut = c;\
|
||||
t.tile = d.tile;\
|
||||
t.attribute = d.attribute;\
|
||||
t.animated = false;\
|
||||
t.texCoord[0] = short2( d.x0, d.y0 );\
|
||||
t.texCoord[1] = short2( d.x1, d.y1 );\
|
||||
t.texCoord[2] = short2( d.x2, d.y2 );\
|
||||
t.texCoord[3] = short2( d.x3, d.y3 );\
|
||||
t.texCoord[0] = t.texCoordAtlas[0] = short2( d.x0, d.y0 );\
|
||||
t.texCoord[1] = t.texCoordAtlas[1] = short2( d.x1, d.y1 );\
|
||||
t.texCoord[2] = t.texCoordAtlas[2] = short2( d.x2, d.y2 );\
|
||||
t.texCoord[3] = t.texCoordAtlas[3] = short2( d.x3, d.y3 );\
|
||||
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);\
|
||||
}
|
||||
|
||||
@@ -3817,6 +3841,18 @@ namespace TR {
|
||||
uint16 attribute;
|
||||
} d;
|
||||
stream.raw(&d, sizeof(d));
|
||||
if (version == VER_TR3_PSX) {
|
||||
if (d.attribute == 0)
|
||||
d.attribute = 0;
|
||||
else if (d.attribute == 2)
|
||||
d.attribute = 2;
|
||||
else if (d.attribute == 0xFFFF)
|
||||
d.attribute = 1;
|
||||
else {
|
||||
//ASSERT(false);
|
||||
d.attribute = 0;
|
||||
}
|
||||
}
|
||||
SET_PARAMS(t, d, d.clut);
|
||||
break;
|
||||
}
|
||||
@@ -3857,8 +3893,8 @@ namespace TR {
|
||||
} d;
|
||||
stream.raw(&d, sizeof(d));
|
||||
SET_PARAMS(t, d, 0);
|
||||
t.texCoord[0] = short2( d.u, d.v );
|
||||
t.texCoord[1] = short2( (uint8)(d.u + (d.w >> 8)), (uint8)(d.v + (d.h >> 8)) );
|
||||
t.texCoord[0] = t.texCoordAtlas[0] = short2( d.u, d.v );
|
||||
t.texCoord[1] = t.texCoordAtlas[1] = short2( (uint8)(d.u + (d.w >> 8)), (uint8)(d.v + (d.h >> 8)) );
|
||||
break;
|
||||
}
|
||||
case VER_TR1_PSX :
|
||||
@@ -3873,8 +3909,8 @@ namespace TR {
|
||||
} d;
|
||||
stream.raw(&d, sizeof(d));
|
||||
SET_PARAMS(t, d, d.clut);
|
||||
t.texCoord[0] = short2( d.u0, d.v0 );
|
||||
t.texCoord[1] = short2( d.u1, d.v1 );
|
||||
t.texCoord[0] = t.texCoordAtlas[0] = short2( d.u0, d.v0 );
|
||||
t.texCoord[1] = t.texCoordAtlas[1] = short2( d.u1, d.v1 );
|
||||
break;
|
||||
}
|
||||
default : ASSERT(false);
|
||||
@@ -3898,12 +3934,16 @@ namespace TR {
|
||||
|
||||
void readAnimTex(Stream &stream) {
|
||||
stream.read(animTexturesData, stream.read(animTexturesDataSize));
|
||||
animTextures = NULL;
|
||||
|
||||
if (!animTexturesDataSize)
|
||||
return;
|
||||
|
||||
uint16 *ptr = animTexturesData;
|
||||
animTexturesCount = *ptr++;
|
||||
if (!animTexturesCount) {
|
||||
animTextures = NULL;
|
||||
if (!animTexturesCount)
|
||||
return;
|
||||
}
|
||||
|
||||
animTextures = new AnimTexture*[animTexturesCount];
|
||||
for (int i = 0; i < animTexturesCount; i++) {
|
||||
animTextures[i] = (AnimTexture*)ptr;
|
||||
@@ -3974,37 +4014,45 @@ namespace TR {
|
||||
}
|
||||
}
|
||||
|
||||
void initTiles() {
|
||||
tiles = new Tile32[tilesCount];
|
||||
void fillObjectTexture(Tile32 *dst, const short4 &uv, int16 tileIndex, int16 clutIndex) {
|
||||
// convert to RGBA
|
||||
switch (version) {
|
||||
case VER_TR1_PC : {
|
||||
ASSERT(tiles8);
|
||||
ASSERT(palette);
|
||||
|
||||
for (int i = 0; i < 256; i++) { // Amiga -> PC color palette
|
||||
Color24 &c = palette[i];
|
||||
c.r <<= 2;
|
||||
c.g <<= 2;
|
||||
c.b <<= 2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tilesCount; i++) {
|
||||
Color32 *ptr = &tiles[i].color[0];
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int x = 0; x < 256; x++) {
|
||||
uint8 index = tiles8[i].index[y * 256 + x];
|
||||
Color24 &p = palette[index];
|
||||
if (index != 0) {
|
||||
ptr[x].r = p.r;
|
||||
ptr[x].g = p.g;
|
||||
ptr[x].b = p.b;
|
||||
ptr[x].a = 255;
|
||||
} else
|
||||
ptr[x].r = ptr[x].g = ptr[x].b = ptr[x].a = 0;
|
||||
}
|
||||
ptr += 256;
|
||||
Color32 *ptr = &dst->color[uv.y * 256];
|
||||
for (int y = uv.y; y < uv.w; y++) {
|
||||
for (int x = uv.x; x < uv.z; x++) {
|
||||
ASSERT(x >= 0 && y >= 0 && x < 256 && y < 256);
|
||||
uint8 index = tiles8[tileIndex].index[y * 256 + x];
|
||||
Color24 &p = palette[index];
|
||||
if (index != 0) {
|
||||
ptr[x].r = p.r;
|
||||
ptr[x].g = p.g;
|
||||
ptr[x].b = p.b;
|
||||
ptr[x].a = 255;
|
||||
} else
|
||||
ptr[x].r = ptr[x].g = ptr[x].b = ptr[x].a = 0;
|
||||
}
|
||||
ptr += 256;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VER_TR2_PC :
|
||||
case VER_TR3_PC : {
|
||||
ASSERT(tiles16);
|
||||
|
||||
Color32 *ptr = &dst->color[uv.y * 256];
|
||||
for (int y = uv.y; y < uv.w; y++) {
|
||||
for (int x = uv.x; x < uv.z; x++) {
|
||||
Color32 c = tiles16[tileIndex].color[y * 256 + x];
|
||||
ptr[x].r = c.b;
|
||||
ptr[x].g = c.g;
|
||||
ptr[x].b = c.r;
|
||||
ptr[x].a = c.a;
|
||||
}
|
||||
ptr += 256;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -4014,63 +4062,17 @@ namespace TR {
|
||||
ASSERT(tiles4);
|
||||
ASSERT(cluts);
|
||||
|
||||
for (int i = 0; i < objectTexturesCount; i++) {
|
||||
ObjectTexture &t = objectTextures[i];
|
||||
CLUT &clut = cluts[t.clut];
|
||||
Tile32 &dst = tiles[t.tile.index];
|
||||
Tile4 &src = tiles4[t.tile.index];
|
||||
CLUT &clut = cluts[clutIndex];
|
||||
Tile4 &src = tiles4[tileIndex];
|
||||
|
||||
int minX = min(min(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x);
|
||||
int maxX = max(max(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x);
|
||||
int minY = min(min(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y);
|
||||
int maxY = max(max(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y);
|
||||
for (int y = uv.y; y < uv.w; y++)
|
||||
for (int x = uv.x; x < uv.z; x++)
|
||||
dst->color[y * 256 + x] = clut.color[(x % 2) ? src.index[(y * 256 + x) / 2].b : src.index[(y * 256 + x) / 2].a];
|
||||
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
dst.color[y * 256 + x] = clut.color[(x % 2) ? src.index[(y * 256 + x) / 2].b : src.index[(y * 256 + x) / 2].a];
|
||||
}
|
||||
|
||||
for (int i = 0; i < spriteTexturesCount; i++) {
|
||||
SpriteTexture &t = spriteTextures[i];
|
||||
CLUT &clut = cluts[t.clut];
|
||||
Tile32 &dst = tiles[t.tile];
|
||||
Tile4 &src = tiles4[t.tile];
|
||||
|
||||
for (int y = t.texCoord[0].y; y <= t.texCoord[1].y; y++)
|
||||
for (int x = t.texCoord[0].x; x <= t.texCoord[1].x; x += 2) {
|
||||
dst.color[y * 256 + x + 0] = clut.color[src.index[(y * 256 + x) / 2].a];
|
||||
dst.color[y * 256 + x + 1] = clut.color[src.index[(y * 256 + x) / 2].b];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case VER_TR2_PC :
|
||||
case VER_TR3_PC : {
|
||||
ASSERT(tiles16);
|
||||
|
||||
for (int i = 0; i < tilesCount; i++) {
|
||||
Color32 *ptr = &tiles[i].color[0];
|
||||
for (int y = 0; y < 256; y++) {
|
||||
for (int x = 0; x < 256; x++) {
|
||||
Color32 c = tiles16[i].color[y * 256 + x];
|
||||
ptr[x].r = c.b;
|
||||
ptr[x].g = c.g;
|
||||
ptr[x].b = c.r;
|
||||
ptr[x].a = c.a;
|
||||
}
|
||||
ptr += 256;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default : ASSERT(false);
|
||||
}
|
||||
|
||||
delete[] tiles8;
|
||||
delete[] tiles16;
|
||||
tiles8 = NULL;
|
||||
tiles16 = NULL;
|
||||
}
|
||||
|
||||
// common methods
|
||||
@@ -4121,7 +4123,7 @@ namespace TR {
|
||||
|
||||
int16 getModelIndex(Entity::Type type) const {
|
||||
//#ifndef _DEBUG
|
||||
if ((type >= Entity::AI_GUARD && type <= Entity::AI_CHECK) || (type >= Entity::GLOW_2 && type <= Entity::ENEMY_BAT_SWARM) || type == Entity::WATERFALL || type == Entity::KILL_ALL_TRIGGERS || type == Entity::VIEW_TARGET || type == Entity::SOUND_DOOR_BELL || type == Entity::SOUND_ALARM_BELL)
|
||||
if ((type >= Entity::AI_GUARD && type <= Entity::AI_CHECK) || (type >= Entity::GLOW_2 && type <= Entity::ENEMY_BAT_SWARM) || type == Entity::WATERFALL || type == Entity::KILL_ALL_TRIGGERS || type == Entity::VIEW_TARGET || type == Entity::SOUND_DOOR_BELL || type == Entity::SOUND_ALARM_BELL || type == Entity::TRIPWIRE)
|
||||
return 0;
|
||||
//#endif
|
||||
|
||||
|
81
src/level.h
81
src/level.h
@@ -915,7 +915,9 @@ struct Level : IGame {
|
||||
}
|
||||
}
|
||||
|
||||
static void fillCallback(int id, int width, int height, int tileX, int tileY, void *userData, void *data) {
|
||||
TR::Tile32 *tileData;
|
||||
|
||||
static void fillCallback(int id, int tileX, int tileY, int atlasWidth, int atlasHeight, Atlas::Tile &tile, void *userData, void *data) {
|
||||
static const uint32 barColor[UI::BAR_MAX][25] = {
|
||||
// flash bar
|
||||
{ 0x00000000, 0xFFA20058, 0xFFFFFFFF, 0xFFA20058, 0x00000000 },
|
||||
@@ -936,27 +938,32 @@ struct Level : IGame {
|
||||
int stride = 256, uvCount;
|
||||
short2 *uv = NULL;
|
||||
|
||||
TR::Level *level = (TR::Level*)userData;
|
||||
Level *owner = (Level*)userData;
|
||||
TR::Level *level = &owner->level;
|
||||
|
||||
TR::Color32 *src, *dst = (TR::Color32*)data;
|
||||
short4 mm;
|
||||
|
||||
|
||||
if (id < level->objectTexturesCount) { // textures
|
||||
TR::ObjectTexture &t = level->objectTextures[id];
|
||||
mm = t.getMinMax();
|
||||
src = level->tiles[t.tile.index].color;
|
||||
uv = t.texCoord;
|
||||
src = owner->tileData->color;
|
||||
uv = t.texCoordAtlas;
|
||||
uvCount = 4;
|
||||
level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut);
|
||||
} else {
|
||||
id -= level->objectTexturesCount;
|
||||
|
||||
if (id < level->spriteTexturesCount) { // sprites
|
||||
TR::SpriteTexture &t = level->spriteTextures[id];
|
||||
mm = t.getMinMax();
|
||||
src = level->tiles[t.tile].color;
|
||||
uv = t.texCoord;
|
||||
src = owner->tileData->color;
|
||||
uv = t.texCoordAtlas;
|
||||
uvCount = 2;
|
||||
level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut);
|
||||
} else { // common (generated) textures
|
||||
id -= level->spriteTexturesCount;
|
||||
|
||||
TR::ObjectTexture *tex;
|
||||
mm.x = mm.y = mm.z = mm.w = 0;
|
||||
stride = 1;
|
||||
@@ -982,7 +989,7 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
memset(tex, 0, sizeof(*tex));
|
||||
uv = tex->texCoord;
|
||||
uv = tex->texCoordAtlas;
|
||||
uv[2].y += mm.w;
|
||||
uv[3].y += mm.w;
|
||||
uv[1].x += mm.z;
|
||||
@@ -995,15 +1002,17 @@ struct Level : IGame {
|
||||
if (data) {
|
||||
int w = mm.z - mm.x + 1;
|
||||
int h = mm.w - mm.y + 1;
|
||||
int dstIndex = tileY * width + tileX;
|
||||
dst += tileY * atlasWidth + tileX;
|
||||
for (int y = -ATLAS_BORDER; y < h + ATLAS_BORDER; y++) {
|
||||
for (int x = -ATLAS_BORDER; x < w + ATLAS_BORDER; x++) {
|
||||
TR::Color32 *p = &src[mm.y * stride + mm.x];
|
||||
ASSERT((x + ATLAS_BORDER + tileX) >= 0 && (x + ATLAS_BORDER + tileX) < atlasWidth);
|
||||
ASSERT((y + ATLAS_BORDER + tileY) >= 0 && (y + ATLAS_BORDER + tileY) < atlasHeight);
|
||||
p += clamp(x, 0, w - 1);
|
||||
p += clamp(y, 0, h - 1) * stride;
|
||||
dst[dstIndex++] = *p;
|
||||
dst[x + ATLAS_BORDER] = *p;
|
||||
}
|
||||
dstIndex += width - ATLAS_BORDER * 2 - w;
|
||||
dst += atlasWidth;
|
||||
}
|
||||
|
||||
cx += tileX + ATLAS_BORDER;
|
||||
@@ -1016,8 +1025,8 @@ struct Level : IGame {
|
||||
uv[i].x += cx;
|
||||
uv[i].y += cy;
|
||||
|
||||
uv[i].x = int32(uv[i].x) * 32767 / width;
|
||||
uv[i].y = int32(uv[i].y) * 32767 / height;
|
||||
uv[i].x = int32(uv[i].x) * 32767 / atlasWidth;
|
||||
uv[i].y = int32(uv[i].y) * 32767 / atlasHeight;
|
||||
}
|
||||
|
||||
// apply ref for instanced tile
|
||||
@@ -1025,11 +1034,11 @@ struct Level : IGame {
|
||||
|
||||
int ref = tileX;
|
||||
if (ref < level->objectTexturesCount) { // textures
|
||||
mm = level->objectTextures[ref].getMinMax();
|
||||
mm = level->objectTextures[ref].getMinMaxAtlas();
|
||||
} else {
|
||||
ref -= level->objectTexturesCount;
|
||||
if (ref < level->spriteTexturesCount) // sprites
|
||||
mm = level->spriteTextures[ref].getMinMax();
|
||||
mm = level->spriteTextures[ref].getMinMaxAtlas();
|
||||
else
|
||||
ASSERT(false); // only object textures and sprites may be instanced
|
||||
}
|
||||
@@ -1084,49 +1093,49 @@ struct Level : IGame {
|
||||
#error atlas packing is not allowed for this platform
|
||||
#endif
|
||||
|
||||
level.initTiles();
|
||||
|
||||
//dumpGlyphs();
|
||||
|
||||
int texIdx = (level.version & TR::VER_PSX) ? 256 : 0; // skip palette color for PSX version
|
||||
int texIdx = 0;
|
||||
|
||||
// repack texture tiles
|
||||
Atlas *tiles = new Atlas(level.objectTexturesCount + level.spriteTexturesCount + UI::BAR_MAX, &level, fillCallback);
|
||||
Atlas *tiles = new Atlas(level.objectTexturesCount + level.spriteTexturesCount + UI::BAR_MAX, this, fillCallback);
|
||||
// add textures
|
||||
for (int i = texIdx; i < level.objectTexturesCount; i++) {
|
||||
TR::ObjectTexture &t = level.objectTextures[i];
|
||||
int16 tx = (t.tile.index % 4) * 256;
|
||||
int16 ty = (t.tile.index / 4) * 256;
|
||||
|
||||
short4 uv;
|
||||
uv.x = tx + min(min(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x);
|
||||
uv.y = ty + min(min(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y);
|
||||
uv.z = tx + max(max(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x) + 1;
|
||||
uv.w = ty + max(max(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y) + 1;
|
||||
uv.x = min(min(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x);
|
||||
uv.y = min(min(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y);
|
||||
uv.z = max(max(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x) + 1;
|
||||
uv.w = max(max(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y) + 1;
|
||||
|
||||
tiles->add(uv, texIdx++);
|
||||
tiles->add(texIdx++, uv, t.tile.index, t.clut);
|
||||
}
|
||||
// add sprites
|
||||
for (int i = 0; i < level.spriteTexturesCount; i++) {
|
||||
TR::SpriteTexture &t = level.spriteTextures[i];
|
||||
int16 tx = (t.tile % 4) * 256;
|
||||
int16 ty = (t.tile / 4) * 256;
|
||||
|
||||
short4 uv;
|
||||
uv.x = tx + t.texCoord[0].x;
|
||||
uv.y = ty + t.texCoord[0].y;
|
||||
uv.z = tx + t.texCoord[1].x + 1;
|
||||
uv.w = ty + t.texCoord[1].y + 1;
|
||||
uv.x = t.texCoord[0].x;
|
||||
uv.y = t.texCoord[0].y;
|
||||
uv.z = t.texCoord[1].x + 1;
|
||||
uv.w = t.texCoord[1].y + 1;
|
||||
|
||||
tiles->add(uv, texIdx++);
|
||||
tiles->add(texIdx++, uv, t.tile, t.clut);
|
||||
}
|
||||
// add common textures
|
||||
const short2 bar[UI::BAR_MAX] = { short2(0, 4), short2(0, 4), short2(0, 4), short2(4, 4), short2(0, 0) };
|
||||
for (int i = 0; i < UI::BAR_MAX; i++)
|
||||
tiles->add(short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y), texIdx++);
|
||||
tiles->add(texIdx++, short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y));
|
||||
|
||||
// get result texture
|
||||
tileData = new TR::Tile32();
|
||||
|
||||
atlas = tiles->pack();
|
||||
|
||||
delete[] tileData;
|
||||
tileData = NULL;
|
||||
|
||||
atlas->setFilterQuality(Core::settings.detail.filter);
|
||||
|
||||
delete tiles;
|
||||
@@ -1134,8 +1143,6 @@ struct Level : IGame {
|
||||
LOG("atlas: %d x %d\n", atlas->width, atlas->height);
|
||||
PROFILE_LABEL(TEXTURE, atlas->ID, "atlas");
|
||||
|
||||
delete[] level.tiles;
|
||||
level.tiles = NULL;
|
||||
#else
|
||||
#ifdef _PSP
|
||||
atlas = new Texture(level.tiles4, level.tilesCount, level.cluts, level.clutsCount);
|
||||
@@ -1260,7 +1267,7 @@ struct Level : IGame {
|
||||
Core::setBlending(bmNone);
|
||||
Core::setDepthTest(false);
|
||||
setShader(Core::pass, Shader::FLASH, false, false);
|
||||
Core::active.shader->setParam(uMaterial, vec4(0.5f, 0.0f, 0.0f, 0.0f));
|
||||
Core::active.shader->setParam(uMaterial, vec4(1.0f / 1.8f, 0.0f, 0.0f, 0.0f));
|
||||
// anim.getJoints(Basis(quat(0, 0, 0, 1), vec3(0)), 0, false));//Basis(anim.getJointRot(0), vec3(0)));
|
||||
Core::setBasis(&b, 1);
|
||||
|
||||
|
18
src/mesh.h
18
src/mesh.h
@@ -625,7 +625,7 @@ struct MeshBuilder {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
Vertex &v0 = vertices[vCount + i * 2 + 0];
|
||||
v0.normal = short4( 0, -1, 0, 32767 );
|
||||
v0.texCoord = short4( whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 );
|
||||
v0.texCoord = short4( whiteTile.texCoordAtlas[0].x, whiteTile.texCoordAtlas[0].y, 32767, 32767 );
|
||||
v0.color = v0.light = ubyte4( 0, 0, 0, 0 );
|
||||
|
||||
if (i == 8) {
|
||||
@@ -702,7 +702,7 @@ struct MeshBuilder {
|
||||
pos.rotate(cs);
|
||||
v.coord = short4( short(pos.x), short(pos.y), 0, 0 );
|
||||
v.normal = short4( 0, 0, 0, 32767 );
|
||||
v.texCoord = short4( whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 );
|
||||
v.texCoord = short4( whiteTile.texCoordAtlas[0].x, whiteTile.texCoordAtlas[0].y, 32767, 32767 );
|
||||
v.color = ubyte4( 255, 255, 255, 255 );
|
||||
v.light = ubyte4( 255, 255, 255, 255 );
|
||||
|
||||
@@ -995,7 +995,7 @@ struct MeshBuilder {
|
||||
int count = triangle ? 3 : 4;
|
||||
for (int i = 0; i < count; i++) {
|
||||
Vertex &v = vertices[vCount + i];
|
||||
v.texCoord = short4( tex->texCoord[i].x, tex->texCoord[i].y, 32767, 32767 );
|
||||
v.texCoord = short4( tex->texCoordAtlas[i].x, tex->texCoordAtlas[i].y, 32767, 32767 );
|
||||
}
|
||||
|
||||
if (((level->version & TR::VER_PSX)) && !triangle) // TODO: swap vertices instead of rectangle indices and vertices.texCoords (WRONG lighting in TR2!)
|
||||
@@ -1142,10 +1142,10 @@ struct MeshBuilder {
|
||||
quad[0].light = quad[1].light = ubyte4( tColor.r, tColor.g, tColor.b, tColor.a );
|
||||
quad[2].light = quad[3].light = ubyte4( bColor.r, bColor.g, bColor.b, bColor.a );
|
||||
|
||||
quad[0].texCoord = short4( sprite.texCoord[0].x, sprite.texCoord[0].y, sprite.l, -sprite.t );
|
||||
quad[1].texCoord = short4( sprite.texCoord[1].x, sprite.texCoord[0].y, sprite.r, -sprite.t );
|
||||
quad[2].texCoord = short4( sprite.texCoord[1].x, sprite.texCoord[1].y, sprite.r, -sprite.b );
|
||||
quad[3].texCoord = short4( sprite.texCoord[0].x, sprite.texCoord[1].y, sprite.l, -sprite.b );
|
||||
quad[0].texCoord = short4( sprite.texCoordAtlas[0].x, sprite.texCoordAtlas[0].y, sprite.l, -sprite.t );
|
||||
quad[1].texCoord = short4( sprite.texCoordAtlas[1].x, sprite.texCoordAtlas[0].y, sprite.r, -sprite.t );
|
||||
quad[2].texCoord = short4( sprite.texCoordAtlas[1].x, sprite.texCoordAtlas[1].y, sprite.r, -sprite.b );
|
||||
quad[3].texCoord = short4( sprite.texCoordAtlas[0].x, sprite.texCoordAtlas[1].y, sprite.l, -sprite.b );
|
||||
|
||||
vCount += 4;
|
||||
}
|
||||
@@ -1171,7 +1171,7 @@ struct MeshBuilder {
|
||||
else
|
||||
v.light = *((ubyte4*)&color);
|
||||
|
||||
short2 uv = tile.texCoord[i];
|
||||
short2 uv = tile.texCoordAtlas[i];
|
||||
|
||||
v.texCoord = short4( uv.x, uv.y, 32767, 32767 );
|
||||
}
|
||||
@@ -1180,7 +1180,7 @@ struct MeshBuilder {
|
||||
}
|
||||
|
||||
void addFrame(Index *indices, Vertex *vertices, int &iCount, int &vCount, const vec2 &pos, const vec2 &size, uint32 color1, uint32 color2) {
|
||||
short4 uv = short4( whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 );
|
||||
short4 uv = short4( whiteTile.texCoordAtlas[0].x, whiteTile.texCoordAtlas[0].y, 32767, 32767 );
|
||||
|
||||
int16 minX = int16(pos.x);
|
||||
int16 minY = int16(pos.y);
|
||||
|
@@ -834,14 +834,21 @@ struct Texture {
|
||||
#define ATLAS_BORDER 8
|
||||
|
||||
struct Atlas {
|
||||
typedef void (Callback)(int id, int width, int height, int x, int y, void *userData, void *data);
|
||||
struct Tile {
|
||||
int32 id;
|
||||
int16 tile;
|
||||
int16 clut;
|
||||
short4 uv;
|
||||
} *tiles;
|
||||
|
||||
typedef void (Callback)(int id, int tileX, int tileY, int atalsWidth, int atlasHeight, Tile &tile, void *userData, void *data);
|
||||
|
||||
struct Node {
|
||||
Node *child[2];
|
||||
short4 rect;
|
||||
int id;
|
||||
int tileIndex;
|
||||
|
||||
Node(short l, short t, short r, short b) : rect(l, t, r, b), id(-1) {
|
||||
Node(short l, short t, short r, short b) : rect(l, t, r, b), tileIndex(-1) {
|
||||
child[0] = child[1] = NULL;
|
||||
}
|
||||
|
||||
@@ -850,15 +857,15 @@ struct Atlas {
|
||||
delete child[1];
|
||||
}
|
||||
|
||||
Node* insert(const short4 &tile, int id) {
|
||||
Node* insert(const short4 &tile, int tileIndex) {
|
||||
ASSERT(tile.x != 0x7FFF);
|
||||
|
||||
if (child[0] != NULL && child[1] != NULL) {
|
||||
Node *node = child[0]->insert(tile, id);
|
||||
Node *node = child[0]->insert(tile, tileIndex);
|
||||
if (node != NULL) return node;
|
||||
return child[1]->insert(tile, id);
|
||||
return child[1]->insert(tile, tileIndex);
|
||||
} else {
|
||||
if (this->id != -1)
|
||||
if (this->tileIndex != -1)
|
||||
return NULL;
|
||||
|
||||
int16 w = rect.z - rect.x;
|
||||
@@ -870,7 +877,7 @@ struct Atlas {
|
||||
return NULL;
|
||||
|
||||
if (w == tx && h == ty) {
|
||||
this->id = id;
|
||||
this->tileIndex = tileIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -885,16 +892,11 @@ struct Atlas {
|
||||
child[1] = new Node(rect.x, rect.y + ty, rect.z, rect.w);
|
||||
}
|
||||
|
||||
return child[0]->insert(tile, id);
|
||||
return child[0]->insert(tile, tileIndex);
|
||||
}
|
||||
}
|
||||
} *root;
|
||||
|
||||
struct Tile {
|
||||
int id;
|
||||
short4 uv;
|
||||
} *tiles;
|
||||
|
||||
int tilesCount;
|
||||
int size;
|
||||
int width, height;
|
||||
@@ -910,17 +912,19 @@ struct Atlas {
|
||||
delete[] tiles;
|
||||
}
|
||||
|
||||
void add(short4 uv, int id) {
|
||||
void add(int32 id, short4 uv, int16 tile = 0, int16 clut = 0) {
|
||||
for (int i = 0; i < tilesCount; i++)
|
||||
if (tiles[i].uv == uv) {
|
||||
if (tiles[i].uv == uv && tiles[i].tile == tile && tiles[i].clut == clut) {
|
||||
uv.x = 0x7FFF;
|
||||
uv.y = tiles[i].id;
|
||||
uv.z = uv.w = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
tiles[tilesCount].id = id;
|
||||
tiles[tilesCount].uv = uv;
|
||||
|
||||
tiles[tilesCount].id = id;
|
||||
tiles[tilesCount].tile = tile;
|
||||
tiles[tilesCount].clut = clut;
|
||||
tiles[tilesCount].uv = uv;
|
||||
tilesCount++;
|
||||
|
||||
if (uv.x != 0x7FFF)
|
||||
@@ -930,7 +934,7 @@ struct Atlas {
|
||||
bool insertAll(int *indices) {
|
||||
for (int i = 0; i < tilesCount; i++) {
|
||||
int idx = indices[i];
|
||||
if (tiles[idx].uv.x != 0x7FFF && !root->insert(tiles[idx].uv, tiles[idx].id))
|
||||
if (tiles[idx].uv.x != 0x7FFF && !root->insert(tiles[idx].uv, idx))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -965,7 +969,7 @@ struct Atlas {
|
||||
// pack
|
||||
while (1) {
|
||||
delete root;
|
||||
root = new Node(0, 0, width, height);
|
||||
root = new Node(0, 0, width - 1, height - 1);
|
||||
|
||||
if (insertAll(indices))
|
||||
break;
|
||||
@@ -994,17 +998,17 @@ struct Atlas {
|
||||
void fill(Node *node, void *data) {
|
||||
if (!node) return;
|
||||
|
||||
if (node->id == -1) {
|
||||
if (node->tileIndex == -1) {
|
||||
fill(node->child[0], data);
|
||||
fill(node->child[1], data);
|
||||
} else
|
||||
callback(node->id, width, height, node->rect.x, node->rect.y, userData, data);
|
||||
callback(tiles[node->tileIndex].id, node->rect.x, node->rect.y, width, height, tiles[node->tileIndex], userData, data);
|
||||
}
|
||||
|
||||
void fillInstances() {
|
||||
for (int i = 0; i < tilesCount; i++)
|
||||
if (tiles[i].uv.x == 0x7FFF)
|
||||
callback(tiles[i].id, width, height, tiles[i].uv.y, 0, userData, NULL);
|
||||
callback(tiles[i].id, tiles[i].uv.y, 0, width, height, tiles[i], userData, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -1099,7 +1099,7 @@ struct Lightning : Controller {
|
||||
void setVertex(Vertex &v, const vec3 &coord, int16 joint, int idx) {
|
||||
v.coord = toCoord(coord, joint);
|
||||
v.normal = short4( 0, -1, 0, 0 );
|
||||
v.texCoord = short4( barTile[0].texCoord[idx].x, barTile[0].texCoord[idx].y, 32767, 32767 );
|
||||
v.texCoord = short4( barTile[0].texCoordAtlas[idx].x, barTile[0].texCoordAtlas[idx].y, 32767, 32767 );
|
||||
v.color = ubyte4( 255, 255, 255, 255 );
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user