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

#138 fix lights, pre-multiplied alpha for transparent geometry, fix hi-res textures

This commit is contained in:
XProger
2018-11-10 06:15:34 +03:00
parent eef6fe100c
commit b6c64401fd
6 changed files with 248 additions and 318 deletions

View File

@@ -1130,7 +1130,7 @@ namespace TR {
TEX_TYPE_SPRITE,
};
struct ObjectTexture {
struct TextureInfo {
TextureType type;
uint16 index;
uint16 clut;
@@ -1138,10 +1138,14 @@ namespace TR {
uint32 attribute:15, animated:1; // 0 - opaque, 1 - transparent, 2 - blend additive, animated, triangle
short2 texCoord[4];
short2 texCoordAtlas[4];
int16 l, t, r, b;
uint16 i1, i2, i3, i4, i5;
uint16 sub[4], i5;
short4 getMinMax() const {
if (type == TEX_TYPE_SPRITE)
return short4( texCoord[0].x, texCoord[0].y, texCoord[1].x, texCoord[1].y );
return short4(
min(min(texCoord[0].x, texCoord[1].x), texCoord[2].x),
min(min(texCoord[0].y, texCoord[1].y), texCoord[2].y),
@@ -1151,6 +1155,9 @@ namespace TR {
}
short4 getMinMaxAtlas() const {
if (type == TEX_TYPE_SPRITE)
return short4( texCoordAtlas[0].x, texCoordAtlas[0].y, texCoordAtlas[1].x, texCoordAtlas[1].y );
return short4(
min(min(texCoordAtlas[0].x, texCoordAtlas[1].x), texCoordAtlas[2].x),
min(min(texCoordAtlas[0].y, texCoordAtlas[1].y), texCoordAtlas[2].y),
@@ -1160,25 +1167,9 @@ namespace TR {
}
};
struct SpriteTexture {
uint16 clut;
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
static ObjectTexture *gObjectTextures = NULL;
static SpriteTexture *gSpriteTextures = NULL;
static TextureInfo *gObjectTextures = NULL;
static TextureInfo *gSpriteTextures = NULL;
static int gObjectTexturesCount;
static int gSpriteTexturesCount;
@@ -1203,8 +1194,8 @@ namespace TR {
ASSERT(aIndex < gObjectTexturesCount);
ASSERT(bIndex < gObjectTexturesCount);
ObjectTexture &ta = gObjectTextures[aIndex];
ObjectTexture &tb = gObjectTextures[bIndex];
TextureInfo &ta = gObjectTextures[aIndex];
TextureInfo &tb = gObjectTextures[bIndex];
if (ta.tile < tb.tile)
return -1;
@@ -1287,8 +1278,8 @@ namespace TR {
ASSERT(a.texture < gSpriteTexturesCount);
ASSERT(b.texture < gSpriteTexturesCount);
SpriteTexture &ta = gSpriteTextures[a.texture];
SpriteTexture &tb = gSpriteTextures[b.texture];
TextureInfo &ta = gSpriteTextures[a.texture];
TextureInfo &tb = gSpriteTextures[b.texture];
if (ta.tile < tb.tile)
return -1;
@@ -2289,25 +2280,25 @@ namespace TR {
StaticMesh *staticMeshes;
int32 objectTexturesCount;
ObjectTexture *objectTextures;
TextureInfo *objectTextures;
int32 objectTexturesDataSize;
uint8 *objectTexturesData;
int32 roomTexturesCount;
ObjectTexture *roomTextures;
TextureInfo *roomTextures;
int32 roomTexturesDataSize;
uint8 *roomTexturesData;
int32 itemTexturesCount;
ObjectTexture *itemTextures;
TextureInfo *itemTextures;
int32 itemTexturesDataSize;
uint8 *itemTexturesData;
int32 spriteTexturesCount;
SpriteTexture *spriteTextures;
TextureInfo *spriteTextures;
int32 spriteSequencesCount;
SpriteSequence *spriteSequences;
@@ -2505,6 +2496,19 @@ namespace TR {
} inv;
} extra;
struct TPAL {
uint8 data[3];
};
uint32 tpalCount;
TPAL *tpal;
int32 spalCount;
uint16 *spal;
uint32 tsubCount;
uint8 *tsub;
Level(Stream &stream) {
memset(this, 0, sizeof(*this));
version = VER_UNKNOWN;
@@ -2725,23 +2729,9 @@ namespace TR {
stream.read(m.animation);
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));
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(clutsCount);
@@ -2829,43 +2819,16 @@ namespace TR {
if (version == VER_TR3_PSX) {
stream.read(skyColor);
int32 roomTexCount;
stream.read(roomTexCount);
roomTexturesCount = stream.readLE32();
if (roomTexturesCount) {
roomTextures = new TextureInfo[roomTexturesCount];
if (roomTexCount) {
ObjectTexture *oldTex = objectTextures;
// reallocate textures info to add room textures
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; i++) {
ObjectTexture &t = objectTextures[i];
readObjectTex(stream, t, TEX_TYPE_ROOM);
for (int i = 0; i < roomTexturesCount; i++) {
readObjectTex(stream, roomTextures[i], TEX_TYPE_ROOM);
stream.seek(2 * 16); // skip 2 mipmap levels
}
// 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(f.flags.texture < roomTexCount);
f.flags.texture += objectTexturesCount;
}
}
// remap animated textures
for (int i = 0; i < animTexturesCount; i++)
for (int j = 0; j < animTextures[i].count; j++)
animTextures[i].textures[j] += objectTexturesCount;
LOG("objTex:%d + roomTex:%d = %d\n", objectTexturesCount, roomTexCount, objectTexturesCount + roomTexCount);
objectTexturesCount += roomTexCount;
}
}
@@ -2915,19 +2878,6 @@ 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++;
}
}
prepare();
}
@@ -2991,25 +2941,16 @@ namespace TR {
delete[] soundData;
delete[] soundOffsets;
delete[] soundSize;
delete[] spal;
delete[] tpal;
delete[] tsub;
}
#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 TPAL {
uint8 data[3];
};
uint32 tsubCount = 0;
uint8 *tsub = NULL;
uint32 tpalCount = 0;
TPAL *tpal = NULL;
int32 spalCount = 0;
uint16 *spal = NULL;
Room *room = NULL;
while (stream.pos < stream.size) {
@@ -3030,7 +2971,7 @@ namespace TR {
case CHUNK("ROOMTINF") :
ASSERTV(stream.readBE32() == 0x00000010);
roomTexturesCount = stream.readBE32();
roomTextures = roomTexturesCount ? new ObjectTexture[roomTexturesCount] : NULL;
roomTextures = roomTexturesCount ? new TextureInfo[roomTexturesCount] : NULL;
for (int i = 0; i < roomTexturesCount; i++)
readObjectTex(stream, roomTextures[i], TEX_TYPE_ROOM);
break;
@@ -3063,17 +3004,6 @@ namespace TR {
tpalCount = stream.readBE32();
tpal = new TPAL[tpalCount];
stream.raw(tpal, sizeof(TPAL) * tpalCount);
uint8 *data = new uint8[roomTexturesDataSize];
for (int i = 0; i < roomTexturesDataSize; i++) {
TPAL *p = tpal + roomTexturesData[i];
data[i] = uint8((int(p->data[0]) + int(p->data[1]) + int(p->data[2])) / 3);
}
FILE *f = fopen("room_data.dmp", "wb");
fwrite(data, 1, roomTexturesDataSize, f);
fclose(f);
delete[] data;
break;
}
case CHUNK("ROOMSPAL") : {
@@ -3082,18 +3012,6 @@ namespace TR {
spal = new uint16[spalCount];
for (int i = 0; i < spalCount; i++)
spal[i] = stream.readBE16();
uint8 *data = new uint8[roomTexturesDataSize];
for (int i = 0; i < roomTexturesDataSize; i++) {
Color32 c = Color16(spal[roomTexturesData[i]]);
data[i] = uint8((int(c.r) + int(c.g) + int(c.b)) / 3);
}
FILE *f = fopen("room_data_16.dmp", "wb");
fwrite(data, 1, roomTexturesDataSize, f);
fclose(f);
delete[] data;
break;
}
case CHUNK("ROOMDATA") :
@@ -3221,18 +3139,15 @@ namespace TR {
LOG("! unknown face type: %d\n", type);
ASSERT(false);
}
//if (type == TYPE_R_TRANSP)
// f.flags.value = 0;
//ASSERT(f.flags.value % 16 == 0);
//ASSERT(f.flags.value / 16 < roomTexturesCount);
ASSERT(f.flags.value % 16 == 0);
ASSERT(f.flags.value / 16 < roomTexturesCount);
f.flags.value /= 16;
f.water = false;
f.colored = false;
f.flip = false;
if (type == TYPE_R_TRANSP) {
if (type == TYPE_R_TRANSP)
roomTextures[f.flags.texture].attribute = 1;
}
}
}
data.fCount = fIndex;
@@ -3323,8 +3238,10 @@ namespace TR {
light.x = stream.readBE32();
light.y = stream.readBE32();
light.z = stream.readBE32();
int32 intensity = stream.readBE32();
int16 intensity = stream.readBE16();
int16 intensity2 = stream.readBE16();
ASSERT(intensity == intensity2);
int value = clamp((intensity > 0x1FFF) ? 0 : (intensity >> 5), 0, 255);
light.color.r = light.color.g = light.color.b = value;
light.color.a = 0;
@@ -3424,7 +3341,7 @@ namespace TR {
animTex.count = last - first + 1;
animTex.textures = new uint16[animTex.count];
for (int j = 0; j < animTex.count; j++)
animTex.textures[j] = last - j;
animTex.textures[j] = first + j;
}
break;
}
@@ -3444,25 +3361,7 @@ namespace TR {
e.intensity = stream.readBE16();
e.intensity2 = stream.readBE16();
e.flags.value = stream.readBE16();
e.flags.smooth = true;
e.type = Entity::remap(version, e.type);
e.modelIndex = getModelIndex(e.type);
}
for (int i = 0; i < entitiesCount; i++)
entities[i].controller = NULL;
if (isCutsceneLevel()) {
for (int i = 0; i < entitiesBaseCount; i++) {
Entity &e = entities[i];
if (e.isActor()) {
cutEntity = i;
break;
}
}
}
break;
}
case CHUNK("ROOMEND ") :
@@ -3608,13 +3507,13 @@ namespace TR {
ASSERT(meshData == NULL);
meshDataSize = stream.readBE32();
meshData = meshDataSize ? new uint16[meshDataSize] : NULL;
stream.raw(meshData, sizeof(uint16) * meshDataSize); // load raw for initMesh call
stream.raw(meshData, sizeof(uint16) * meshDataSize);
break;
case CHUNK("OTEXTINF") :
ASSERTV(stream.readBE32() == 0x00000010);
ASSERT(objectTextures == NULL);
objectTexturesCount = stream.readBE32();
objectTextures = objectTexturesCount ? new ObjectTexture[objectTexturesCount] : NULL;
objectTextures = objectTexturesCount ? new TextureInfo[objectTexturesCount] : NULL;
for (int i = 0; i < objectTexturesCount; i++)
readObjectTex(stream, objectTextures[i], TEX_TYPE_OBJECT);
break;
@@ -3628,7 +3527,7 @@ namespace TR {
case CHUNK("ITEXTINF") : {
ASSERTV(stream.readBE32() == 0x00000014);
itemTexturesCount = stream.readBE32();
itemTextures = itemTexturesCount ? new ObjectTexture[itemTexturesCount] : NULL;
itemTextures = itemTexturesCount ? new TextureInfo[itemTexturesCount] : NULL;
for (int i = 0; i < itemTexturesCount; i++)
readObjectTex(stream, itemTextures[i], TEX_TYPE_ITEM);
break;
@@ -3643,23 +3542,6 @@ namespace TR {
case CHUNK("OBJEND ") :
ASSERTV(stream.readBE32() == 0x00000000);
ASSERTV(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 ") :
@@ -3669,7 +3551,7 @@ namespace TR {
case CHUNK("SPRITINF") : {
ASSERTV(stream.readBE32() == 0x00000010);
spriteTexturesCount = stream.readBE32();
spriteTextures = spriteTexturesCount ? new SpriteTexture[spriteTexturesCount] : NULL;
spriteTextures = spriteTexturesCount ? new TextureInfo[spriteTexturesCount] : NULL;
for (int i = 0; i < spriteTexturesCount; i++)
readSpriteTex(stream, spriteTextures[i]);
break;
@@ -3735,16 +3617,12 @@ namespace TR {
}
}
}
delete[] spal;
delete[] tpal;
delete[] tsub;
}
void appendObjectTex(ObjectTexture *&objTex, int32 &count) {
ObjectTexture *newObjectTextures = new ObjectTexture[objectTexturesCount + count];
memcpy(newObjectTextures, objectTextures, sizeof(ObjectTexture) * objectTexturesCount);
memcpy(newObjectTextures + objectTexturesCount, objTex, sizeof(ObjectTexture) * count);
void appendObjectTex(TextureInfo *&objTex, int32 &count) {
TextureInfo *newObjectTextures = new TextureInfo[objectTexturesCount + count];
memcpy(newObjectTextures, objectTextures, sizeof(TextureInfo) * objectTexturesCount);
memcpy(newObjectTextures + objectTexturesCount, objTex, sizeof(TextureInfo) * count);
delete[] objectTextures;
objectTextures = newObjectTextures;
objectTexturesCount += count;
@@ -3763,6 +3641,62 @@ namespace TR {
}
void prepare() {
if (version == VER_TR1_PC) {
// Amiga -> PC color palette for TR1 PC
ASSERT(palette);
Color24 *c = palette;
for (int i = 0; i < 256; i++) {
c->r <<= 2;
c->g <<= 2;
c->b <<= 2;
c++;
}
}
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;
LOG("meshes: %d\n", meshesCount);
for (int i = 0; i < entitiesBaseCount; i++) {
Entity &e = entities[i];
e.type = Entity::remap(version, e.type);
e.controller = NULL;
e.modelIndex = getModelIndex(e.type);
// turn off interpolation for some entities
e.flags.smooth = !((id == LVL_TR2_CUT_1 && (e.type == Entity::CUT_6 || e.type == Entity::CUT_8 || e.type == Entity::CUT_9))
|| e.type == Entity::SWITCH_BUTTON);
}
for (int i = entitiesBaseCount; i < entitiesCount; i++)
entities[i].controller = NULL;
if (isCutsceneLevel()) {
for (int i = 0; i < entitiesBaseCount; i++) {
Entity &e = entities[i];
if ((((version & VER_TR1)) && e.isActor()) ||
(((version & (VER_TR2 | VER_TR3))) && e.isLara())) {
cutEntity = i;
break;
}
}
}
if (roomTextures) {
// remap texture indices for room faces
for (int i = 0; i < roomsCount; i++) {
@@ -3941,17 +3875,6 @@ namespace TR {
cutMatrix.rotateY(e.rotation);
}
}
// turn off interpolation for some entities
for (int i = 0; i < entitiesBaseCount; i++) {
Entity &e = entities[i];
if ((id == LVL_TR2_CUT_1 && (e.type == Entity::CUT_6 || e.type == Entity::CUT_8 || e.type == Entity::CUT_9)) ||
e.type == Entity::SWITCH_BUTTON) {
e.flags.smooth = false;
}
}
}
LevelID getTitleId() const {
@@ -4113,6 +4036,7 @@ namespace TR {
f.flags.doubleSided = false;
f.vCount = 3;
f.colored = false;
f.flip = false;
f.vertices[0] = vStart + t.i0;
f.vertices[1] = vStart + t.i1;
f.vertices[2] = vStart + t.i2;
@@ -4147,6 +4071,7 @@ namespace TR {
f.flags.doubleSided = false;
f.vCount = 4;
f.colored = false;
f.flip = false;
f.vertices[0] = vStart + r.i0;
f.vertices[1] = vStart + r.i1;
f.vertices[2] = vStart + r.i2;
@@ -4423,7 +4348,7 @@ namespace TR {
r.dynLightsCount = 0;
}
void initMesh(int mIndex, Entity::Type type = Entity::LARA) {
void initMesh(int mIndex, Entity::Type type = Entity::NONE) {
int offset = meshOffsets[mIndex];
for (int i = 0; i < meshesCount; i++)
if (meshes[i].offset == offset)
@@ -4514,6 +4439,18 @@ namespace TR {
TYPE_R_FLIP_TRANSP = 57,
};
TextureInfo *textures;
int texturesCount;
if (Entity::isInventoryItem(type)) {
textures = itemTextures;
texturesCount = itemTexturesCount;
} else {
textures = objectTextures;
texturesCount = objectTexturesCount;
}
int divisor = 16;
//if (Entity::isInventoryItem(type))
// divisor = 20;
@@ -4530,6 +4467,7 @@ namespace TR {
switch (type) {
case TYPE_T_TEX :
case TYPE_T_COLOR :
case TYPE_T_PALETTE :
case TYPE_T_UNKNOWN2 :
f.vCount = 3;
@@ -4568,13 +4506,13 @@ namespace TR {
f.colored = true;
} else {
ASSERT(f.flags.value % 16 == 0);
ASSERT(f.flags.value / 16 < objectTexturesCount);
ASSERT(f.flags.value / 16 < texturesCount);
f.flags.value /= divisor;
f.colored = false;
}
if (type == TYPE_R_TRANSP || type == TYPE_R_FLIP_TRANSP)
objectTextures[f.flags.texture].attribute = 1;
textures[f.flags.texture].attribute = 1;
f.flip = (type == TYPE_R_FLIP_TEX || type == TYPE_R_FLIP_TRANSP);
f.water = false;
@@ -4771,6 +4709,7 @@ namespace TR {
f.flags.doubleSided = false;
f.flags.texture = (info & 0xFF) | (r.tex << 8);
f.colored = false;
f.flip = false;
f.vCount = 3;
f.vertices[0] = r.i0;
@@ -4790,6 +4729,7 @@ namespace TR {
f.flags.doubleSided = false;
f.flags.texture = info & 0xFFFF;
f.colored = false;
f.flip = false;
f.vCount = 4;
struct {
@@ -4852,7 +4792,7 @@ namespace TR {
}
}
void readObjectTex(Stream &stream, ObjectTexture &t, TextureType type = TEX_TYPE_OBJECT) {
void readObjectTex(Stream &stream, TextureInfo &t, TextureType type = TEX_TYPE_OBJECT) {
#define SET_PARAMS(t, d, c) {\
t.clut = c;\
t.tile = d.tile;\
@@ -4871,7 +4811,6 @@ namespace TR {
struct {
uint16 attribute;
uint16 tile;
uint8 triangle;
uint16 clut;
uint8 w, h;
uint8 x0, y0;
@@ -4880,26 +4819,27 @@ namespace TR {
uint8 x3, y3;
} d;
d.attribute = 0;
int16 index = 0;
t.index = 0;
if (type == TEX_TYPE_ITEM)
index = stream.readBE16();
t.index = stream.readBE16();
d.triangle = false;
d.tile = stream.readBE16(); // offset to 4-bit indices
uint16 i1 = stream.readBE16();
uint16 i2 = stream.readBE16();
uint16 i3 = stream.readBE16();
uint16 i4 = stream.readBE16();
d.clut = stream.readBE16() + d.tile; // offset to color palette
d.w = stream.read() << 3;
d.h = stream.read();
uint16 i5 = stream.readBE16();
d.attribute = 0;
d.tile = stream.readBE16(); // offset to 4-bit indices
t.sub[0] = stream.readBE16();
t.sub[1] = stream.readBE16();
t.sub[2] = stream.readBE16();
t.sub[3] = stream.readBE16();
d.clut = stream.readBE16() + d.tile; // offset to color palette
d.w = stream.read() * 8;
d.h = stream.read();
t.i5 = stream.readBE16();
//if (type == TEX_TYPE_OBJECT && d.w == 80 && d.h == 56) {
// LOG("%d %d %d %d %d\n", i1, i2, i3, i4, i5);
//}
if (type == TEX_TYPE_ROOM) { // for room tiles we will use fullres TSUB textures instead of mips TQTR
d.w *= 2;
d.h *= 2;
}
//LOG("%d %d %d %d %d\n", t.sub[0], t.sub[1], t.sub[2], t.sub[3], t.i5);
if (type == TEX_TYPE_ITEM)
stream.seek(2);
@@ -4910,15 +4850,6 @@ namespace TR {
SET_PARAMS(t, d, d.clut);
t.i1 = i1;
t.i2 = i2;
t.i3 = i3;
t.i4 = i4;
t.i5 = i5;
t.index = index;
break;
}
case VER_TR1_PC :
@@ -4972,12 +4903,12 @@ namespace TR {
}
void readObjectTex(Stream &stream) {
objectTextures = stream.read(objectTexturesCount) ? new ObjectTexture[objectTexturesCount] : NULL;
objectTextures = stream.read(objectTexturesCount) ? new TextureInfo[objectTexturesCount] : NULL;
for (int i = 0; i < objectTexturesCount; i++)
readObjectTex(stream, objectTextures[i]);
}
void readSpriteTex(Stream &stream, SpriteTexture &t) {
void readSpriteTex(Stream &stream, TextureInfo &t) {
#define SET_PARAMS(t, d, c) {\
t.clut = c;\
t.tile = d.tile;\
@@ -4987,6 +4918,9 @@ namespace TR {
t.b = d.b;\
}
t.type = TEX_TYPE_SPRITE;
t.attribute = 1;
switch (version) {
case VER_TR1_SAT : {
struct {
@@ -5047,7 +4981,7 @@ namespace TR {
}
void readSpriteTex(Stream &stream) {
spriteTextures = stream.read(spriteTexturesCount) ? new SpriteTexture[spriteTexturesCount] : NULL;
spriteTextures = stream.read(spriteTexturesCount) ? new TextureInfo[spriteTexturesCount] : NULL;
for (int i = 0; i < spriteTexturesCount; i++)
readSpriteTex(stream, spriteTextures[i]);
@@ -5117,25 +5051,6 @@ namespace TR {
if (version & (VER_TR2 | VER_TR3))
stream.read(e.intensity2);
stream.read(e.flags.value);
e.flags.smooth = true;
e.type = Entity::remap(version, e.type);
e.controller = NULL;
e.modelIndex = getModelIndex(e.type);
}
for (int i = entitiesBaseCount; i < entitiesCount; i++)
entities[i].controller = NULL;
if (isCutsceneLevel()) {
for (int i = 0; i < entitiesBaseCount; i++) {
Entity &e = entities[i];
if ((((version & VER_TR1)) && e.isActor()) ||
(((version & (VER_TR2 | VER_TR3))) && e.isLara())) {
cutEntity = i;
break;
}
}
}
}
@@ -5156,22 +5071,22 @@ namespace TR {
void shiftAnimTex() {
for (int i = 0; i < animTexturesCount; i++) {
AnimTexture &animTex = animTextures[i];
ObjectTexture tmp = objectTextures[animTex.textures[0]];
TextureInfo tmp = objectTextures[animTex.textures[0]];
for (int j = 0; j < animTex.count - 1; j++)
objectTextures[animTex.textures[j]] = objectTextures[animTex.textures[j + 1]];
objectTextures[animTex.textures[animTex.count - 1]] = tmp;
}
}
void fillObjectTexture(Tile32 *dst, const short4 &uv, int16 tileIndex, int32 clutIndex, TextureType type) {
void fillObjectTexture(Tile32 *dst, const short4 &uv, TextureInfo *t) {
// convert to RGBA
switch (version) {
case VER_TR1_SAT : {
uint32 iOffset = uint32(uint16(tileIndex)) << 3;
uint32 cOffset = uint32(uint16(clutIndex)) << 3;
uint32 iOffset = uint32(uint16(t->tile)) << 3;
uint32 cOffset = uint32(uint16(t->clut)) << 3;
uint8 *data = NULL;
switch (type) {
switch (t->type) {
case TEX_TYPE_ROOM : data = roomTexturesData; break;
case TEX_TYPE_ITEM : data = itemTexturesData; break;
case TEX_TYPE_OBJECT : data = objectTexturesData; break;
@@ -5186,6 +5101,7 @@ namespace TR {
int h = uv.w - uv.y;
int w = uv.z - uv.x;
ASSERT(w <= 256 && h <= 256);
/*
if (type == TEX_TYPE_OBJECT && w == 80 && h == 56) {
for (int y = 0; y < h; y++)
@@ -5196,22 +5112,28 @@ namespace TR {
*/
for (int y = 0; y < h; y++)
for (int x = 0; x < w; x++) {
ColorIndex4 *index = indices + (y * w + x) / 2;
ColorIndex4 *index;
if (t->type == TEX_TYPE_ROOM) {
int iw = w / 2;
int ih = h / 2;
int ix = x % iw;
int iy = y % ih;
int offset = uint32(uint16(t->sub[y >= ih ? (x >= iw ? 2 : 3) : (x >= iw ? 1 : 0)])) << 3;
offset += (iy * iw + ix) / 2;
index = (ColorIndex4*) (tsub + offset);
} else
index = indices + (y * w + x) / 2;
int idx = (x % 2) ? index->a : index->b;
Color16 &c = clut->color[idx];
if (idx == 0 && (c.value == 0x1BF4 || c.value == 0x0080)) {
dst->color[y * 256 + x].a = 0;// = Color32(255, 0, 0, 0);
continue;
}
dst->color[y * 256 + x] = Color16(swap16(c.value));
/*
if (dst->color[y * 256 + x].a != 255) {
dst->color[y * 256 + x] = Color32(0, 255, 0, 255);
continue;
}
*/
if (t->attribute == 1 && idx == 0)
dst->color[y * 256 + x] = Color32(255, 0, 0, 0);
else
dst->color[y * 256 + x] = Color16(swap16(c.value));
}
break;
@@ -5224,7 +5146,7 @@ namespace TR {
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];
uint8 index = tiles8[t->tile].index[y * 256 + x];
Color24 &p = palette[index];
if (index != 0) {
ptr[x].r = p.r;
@@ -5245,7 +5167,7 @@ namespace TR {
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];
Color32 c = tiles16[t->tile].color[y * 256 + x];
ptr[x].r = c.b;
ptr[x].g = c.g;
ptr[x].b = c.r;
@@ -5261,8 +5183,8 @@ namespace TR {
ASSERT(tiles4);
ASSERT(cluts);
CLUT &clut = cluts[clutIndex];
Tile4 &src = tiles4[tileIndex];
CLUT &clut = cluts[t->clut];
Tile4 &src = tiles4[t->tile];
for (int y = uv.y; y < uv.w; y++)
for (int x = uv.x; x < uv.z; x++)
@@ -5272,6 +5194,15 @@ namespace TR {
}
default : ASSERT(false);
}
// pre-multiple alpha
for (int y = uv.y; y < uv.w; y++)
for (int x = uv.x; x < uv.z; x++) {
Color32 &c = dst->color[y * 256 + x];
c.r = uint8((uint16(c.r) * c.a) / 255);
c.g = uint8((uint16(c.g) * c.a) / 255);
c.b = uint8((uint16(c.b) * c.a) / 255);
}
}
// common methods
@@ -5285,7 +5216,7 @@ namespace TR {
case VER_TR2_PSX :
case VER_TR3_PSX : {
ASSERT((texture & 0x7FFF) < 256);
ObjectTexture &t = objectTextures[texture & 0x7FFF];
TextureInfo &t = objectTextures[texture & 0x7FFF];
int idx = (t.texCoord[0].y * 256 + t.texCoord[0].x) / 2;
int part = t.texCoord[0].x % 2;
Tile4 &tile = tiles4[t.tile];

View File

@@ -508,9 +508,10 @@ struct Inventory {
Core::setBasis(joints, m.mCount);
Core::setBlendMode(bmAlpha);
Core::setBlendMode(bmNone);
mesh->transparent = 0;
mesh->renderModel(desc.model);
Core::setBlendMode(bmPremult);
mesh->transparent = 1;
mesh->renderModel(desc.model);
Core::setBlendMode(bmAdd);
@@ -1655,7 +1656,7 @@ struct Inventory {
renderTitleBG(1.0f, sy, alpha);
}
Core::setBlendMode(bmAlpha);
Core::setBlendMode(bmPremult);
Core::setDepthTest(true);
}

View File

@@ -1140,28 +1140,28 @@ struct Level : IGame {
short4 mm;
if (id < level->objectTexturesCount) { // textures
TR::ObjectTexture &t = level->objectTextures[id];
TR::TextureInfo &t = level->objectTextures[id];
mm = t.getMinMax();
src = owner->tileData->color;
uv = t.texCoordAtlas;
uvCount = 4;
if (data)
level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut, t.type);
level->fillObjectTexture(owner->tileData, tile.uv, tile.tex);
} else {
id -= level->objectTexturesCount;
if (id < level->spriteTexturesCount) { // sprites
TR::SpriteTexture &t = level->spriteTextures[id];
TR::TextureInfo &t = level->spriteTextures[id];
mm = t.getMinMax();
src = owner->tileData->color;
uv = t.texCoordAtlas;
uvCount = 2;
if (data)
level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut, TR::TextureType::TEX_TYPE_SPRITE);
level->fillObjectTexture(owner->tileData, tile.uv, tile.tex);
} else { // common (generated) textures
id -= level->spriteTexturesCount;
TR::ObjectTexture *tex;
TR::TextureInfo *tex;
mm.x = mm.y = mm.z = mm.w = 0;
stride = 1;
uvCount = 4;
@@ -1296,7 +1296,7 @@ struct Level : IGame {
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];
TR::TextureInfo &t = level.objectTextures[i];
short4 uv;
uv.x = min(min(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x);
@@ -1304,11 +1304,11 @@ struct Level : IGame {
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(texIdx++, t.type, uv, t.tile, t.clut);
tiles->add(texIdx++, uv, &t);
}
// add sprites
for (int i = 0; i < level.spriteTexturesCount; i++) {
TR::SpriteTexture &t = level.spriteTextures[i];
TR::TextureInfo &t = level.spriteTextures[i];
short4 uv;
uv.x = t.texCoord[0].x;
@@ -1316,12 +1316,14 @@ struct Level : IGame {
uv.z = t.texCoord[1].x + 1;
uv.w = t.texCoord[1].y + 1;
tiles->add(texIdx++, TR::TEX_TYPE_SPRITE, uv, t.tile, t.clut);
tiles->add(texIdx++, uv, &t);
}
// 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(texIdx++, TR::TEX_TYPE_SPRITE, short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y));
for (int i = 0; i < UI::BAR_MAX; i++) {
barTile[i].type = TR::TEX_TYPE_SPRITE;
tiles->add(texIdx++, short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y), &barTile[i]);
}
// get result texture
tileData = new TR::Tile32();
@@ -1548,8 +1550,8 @@ struct Level : IGame {
Core::mModel.identity();
switch (transp) {
case 0 : Core::setBlendMode(bmNone); break;
case 1 : Core::setBlendMode(bmAlpha); break;
case 0 : Core::setBlendMode(bmNone); break;
case 1 : Core::setBlendMode(bmPremult); break;
case 2 : Core::setBlendMode(bmAdd); Core::setDepthWrite(false); break;
}
@@ -1592,7 +1594,7 @@ struct Level : IGame {
Core::setDepthWrite(true);
if (transp == 1) {
Core::setBlendMode(bmAlpha);
Core::setBlendMode(bmPremult);
#ifdef MERGE_SPRITES
basis.rot = Core::mViewInv.getRot();
@@ -2001,7 +2003,7 @@ struct Level : IGame {
}
if (transp == 1) {
Core::setBlendMode(bmAlpha);
Core::setBlendMode(bmPremult);
renderEntitiesTransp(transp);
#ifdef FFP

View File

@@ -4,8 +4,8 @@
#include "core.h"
#include "format.h"
TR::ObjectTexture barTile[5 /* UI::BAR_MAX */];
TR::ObjectTexture &whiteTile = barTile[4]; // BAR_WHITE
TR::TextureInfo barTile[5 /* UI::BAR_MAX */];
TR::TextureInfo &whiteTile = barTile[4]; // BAR_WHITE
#define PLANE_DETAIL 48
#define CIRCLE_SEGS 16
@@ -352,7 +352,7 @@ struct MeshBuilder {
for (int j = 0; j < d.sCount; j++) {
TR::Room::Data::Sprite &f = d.sprites[j];
TR::Room::Data::Vertex &v = d.vertices[f.vertex];
TR::SpriteTexture &sprite = level.spriteTextures[f.texture];
TR::TextureInfo &sprite = level.spriteTextures[f.texture];
addSprite(indices, vertices, iCount, vCount, vStartRoom, v.vertex.x, v.vertex.y, v.vertex.z, sprite, v.color, v.color);
}
@@ -425,7 +425,7 @@ struct MeshBuilder {
range.vStart = vStartSprite;
range.iStart = iCount;
for (int j = 0; j < level.spriteSequences[i].sCount; j++) {
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart + j];
TR::TextureInfo &sprite = level.spriteTextures[level.spriteSequences[i].sStart + j];
addSprite(indices, vertices, iCount, vCount, vStartSprite, 0, 0, 0, sprite, TR::Color32(255, 255, 255, 255), TR::Color32(255, 255, 255, 255));
}
range.iCount = iCount - range.iStart;
@@ -911,7 +911,7 @@ struct MeshBuilder {
TR::Face &f = d.faces[j];
ASSERT(!f.colored);
ASSERT(f.flags.texture < level.objectTexturesCount);
TR::ObjectTexture &t = level.objectTextures[f.flags.texture];
TR::TextureInfo &t = level.objectTextures[f.flags.texture];
if (f.water) continue;
@@ -944,8 +944,8 @@ struct MeshBuilder {
dyn.faces = new uint16[dyn.count];
dyn.count = 0;
for (int j = 0; j < d.fCount; j++) {
TR::Face &f = d.faces[j];
TR::ObjectTexture &t = level.objectTextures[f.flags.texture];
TR::Face &f = d.faces[j];
TR::TextureInfo &t = level.objectTextures[f.flags.texture];
if (f.water) continue;
@@ -964,7 +964,7 @@ struct MeshBuilder {
for (int j = 0; j < mesh.fCount; j++) {
TR::Face &f = mesh.faces[j];
ASSERT(f.colored || f.flags.texture < level.objectTexturesCount);
TR::ObjectTexture &t = f.colored ? whiteTile : level.objectTextures[f.flags.texture];
TR::TextureInfo &t = f.colored ? whiteTile : level.objectTextures[f.flags.texture];
if (t.attribute != 0)
isOpaque = false;
@@ -1000,7 +1000,7 @@ struct MeshBuilder {
return isOpaque;
}
void addTexCoord(Vertex *vertices, int vCount, TR::ObjectTexture *tex, bool triangle, bool flip) {
void addTexCoord(Vertex *vertices, int vCount, TR::TextureInfo *tex, bool triangle, bool flip) {
int count = triangle ? 3 : 4;
for (int i = 0; i < count; i++) {
Vertex &v = vertices[vCount + i];
@@ -1016,7 +1016,7 @@ struct MeshBuilder {
}
}
void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex, bool doubleSided, bool flip) {
void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, bool flip) {
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
@@ -1035,7 +1035,7 @@ struct MeshBuilder {
if (tex) addTexCoord(vertices, vCount, tex, true, flip);
}
void addQuad(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex, bool doubleSided, bool flip) {
void addQuad(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, bool flip) {
int vIndex = vCount - vStart;
indices[iCount + 0] = vIndex + 0;
@@ -1063,7 +1063,7 @@ struct MeshBuilder {
if (tex) addTexCoord(vertices, vCount, tex, false, flip);
}
void addQuad(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex, bool doubleSided, bool flip,
void addQuad(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, bool flip,
const short3 &c0, const short3 &c1, const short3 &c2, const short3 &c3) {
addQuad(indices, iCount, vCount, vStart, vertices, tex, doubleSided, flip);
@@ -1101,7 +1101,7 @@ struct MeshBuilder {
}
void addFace(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, const TR::Face &f, TR::ObjectTexture *tex, const short3 &a, const short3 &b, const short3 &c, const short3 &d) {
void addFace(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, const TR::Face &f, TR::TextureInfo *tex, const short3 &a, const short3 &b, const short3 &c, const short3 &d) {
if (f.vCount == 4)
addQuad(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, f.flip, a, b, c, d);
else
@@ -1117,7 +1117,7 @@ struct MeshBuilder {
return short4(int16(coord.x), int16(coord.y), int16(coord.z), 0);
}
void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, const TR::SpriteTexture &sprite, const TR::Color32 &tColor, const TR::Color32 &bColor, bool expand = false) {
void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, const TR::TextureInfo &sprite, const TR::Color32 &tColor, const TR::Color32 &bColor, bool expand = false) {
addQuad(indices, iCount, vCount, vStart, NULL, NULL, false, false);
Vertex *quad = &vertices[vCount];
@@ -1164,7 +1164,7 @@ struct MeshBuilder {
vCount += 4;
}
void addBar(Index *indices, Vertex *vertices, int &iCount, int &vCount, const TR::ObjectTexture &tile, const vec2 &pos, const vec2 &size, uint32 color, uint32 color2 = 0) {
void addBar(Index *indices, Vertex *vertices, int &iCount, int &vCount, const TR::TextureInfo &tile, const vec2 &pos, const vec2 &size, uint32 color, uint32 color2 = 0) {
addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false);
int16 minX = int16(pos.x);
@@ -1277,8 +1277,8 @@ struct MeshBuilder {
const TR::Room::Data &d = level->rooms[roomIndex].data;
for (int i = 0; i < dyn.count; i++) {
TR::Face &f = d.faces[dyn.faces[i]];
TR::ObjectTexture &t = level->objectTextures[f.flags.texture];
TR::Face &f = d.faces[dyn.faces[i]];
TR::TextureInfo &t = level->objectTextures[f.flags.texture];
#ifdef SPLIT_BY_TILE
if (iCount) {

View File

@@ -683,11 +683,9 @@ struct Texture : GAPI::Texture {
struct Atlas {
struct Tile {
uint16 id;
uint16 type;
uint16 tile;
uint16 clut;
short4 uv;
uint16 id;
TR::TextureInfo *tex;
short4 uv;
} *tiles;
typedef void (Callback)(int id, int tileX, int tileY, int atalsWidth, int atlasHeight, Tile &tile, void *userData, void *data);
@@ -761,20 +759,18 @@ struct Atlas {
delete[] tiles;
}
void add(uint16 id, uint16 type, short4 uv, uint16 tile = 0, uint16 clut = 0) {
void add(uint16 id, short4 uv, TR::TextureInfo *tex) {
for (int i = 0; i < tilesCount; i++)
if (tiles[i].uv == uv && tiles[i].type == type && tiles[i].tile == tile && tiles[i].clut == clut) {
if (tiles[i].uv == uv && tiles[i].tex->type == tex->type && tiles[i].tex->tile == tex->tile && tiles[i].tex->clut == tex->clut) {
uv.x = 0x7FFF;
uv.y = tiles[i].id;
uv.z = uv.w = 0;
break;
}
tiles[tilesCount].id = id;
tiles[tilesCount].type = type;
tiles[tilesCount].tile = tile;
tiles[tilesCount].clut = clut;
tiles[tilesCount].uv = uv;
tiles[tilesCount].id = id;
tiles[tilesCount].tex = tex;
tiles[tilesCount].uv = uv;
tilesCount++;
if (uv.x != 0x7FFF)
@@ -839,7 +835,7 @@ struct Atlas {
Texture *atlas = new Texture(width, height, FMT_RGBA, OPT_MIPMAPS, data);
//Texture::SaveBMP("atlas", (char*)data, width, height);
Texture::SaveBMP("atlas", (char*)data, width, height);
delete[] data;
return atlas;

View File

@@ -330,7 +330,7 @@ namespace UI {
void begin() {
Core::setDepthTest(false);
Core::setBlendMode(bmAlpha);
Core::setBlendMode(bmPremult);
Core::setCullMode(cmNone);
game->setupBinding();
@@ -419,7 +419,7 @@ namespace UI {
if (buffer.iCount == MAX_CHARS * 6)
flush();
TR::SpriteTexture &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + frame];
TR::TextureInfo &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + frame];
TR::Color32 tColor, bColor;
if (isShadow) {
@@ -474,7 +474,7 @@ namespace UI {
if (specChar >= level->spriteSequences[seq].sCount)
return;
TR::SpriteTexture &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + specChar];
TR::TextureInfo &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + specChar];
#ifdef SPLIT_BY_TILE
if (sprite.tile != curTile