From b6c64401fdac4c06f282aa085ca676f0c95f3f16 Mon Sep 17 00:00:00 2001 From: XProger Date: Sat, 10 Nov 2018 06:15:34 +0300 Subject: [PATCH] #138 fix lights, pre-multiplied alpha for transparent geometry, fix hi-res textures --- src/format.h | 467 +++++++++++++++++++++--------------------------- src/inventory.h | 5 +- src/level.h | 32 ++-- src/mesh.h | 34 ++-- src/texture.h | 22 +-- src/ui.h | 6 +- 6 files changed, 248 insertions(+), 318 deletions(-) diff --git a/src/format.h b/src/format.h index 25a351c..a008b87 100644 --- a/src/format.h +++ b/src/format.h @@ -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]; diff --git a/src/inventory.h b/src/inventory.h index f6da4bb..0950793 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -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); } diff --git a/src/level.h b/src/level.h index a36d299..9dd14cf 100644 --- a/src/level.h +++ b/src/level.h @@ -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 diff --git a/src/mesh.h b/src/mesh.h index 37d8be0..5873a9f 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -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) { diff --git a/src/texture.h b/src/texture.h index 27d3e40..f99d1d2 100644 --- a/src/texture.h +++ b/src/texture.h @@ -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; diff --git a/src/ui.h b/src/ui.h index 9a13db8..3bcc790 100644 --- a/src/ui.h +++ b/src/ui.h @@ -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