diff --git a/src/format.h b/src/format.h index 038acf8..25a351c 100644 --- a/src/format.h +++ b/src/format.h @@ -1123,11 +1123,6 @@ namespace TR { operator short3() const { return *((short3*)this); } }; - union Tile { - struct { uint16 index:14, undefined:1, triangle:1; }; - uint16 value; - }; - enum TextureType { TEX_TYPE_ROOM, TEX_TYPE_ITEM, @@ -1138,11 +1133,13 @@ namespace TR { struct ObjectTexture { TextureType type; uint16 index; - uint16 clut; - Tile tile; - uint16 attribute:15, animated:1; // 0 - opaque, 1 - transparent, 2 - blend additive, animated - short2 texCoord[4]; - short2 texCoordAtlas[4]; + uint16 clut; + uint16 tile; + uint32 attribute:15, animated:1; // 0 - opaque, 1 - transparent, 2 - blend additive, animated, triangle + short2 texCoord[4]; + short2 texCoordAtlas[4]; + + uint16 i1, i2, i3, i4, i5; short4 getMinMax() const { return short4( @@ -1193,7 +1190,7 @@ namespace TR { short3 normal; uint16 vertices[4]; - uint8 water:1, colored:1, vCount:6; + uint8 water:1, colored:1, flip:1, vCount:5; static int cmp(const Face &a, const Face &b) { int aIndex = a.flags.texture; @@ -1209,9 +1206,9 @@ namespace TR { ObjectTexture &ta = gObjectTextures[aIndex]; ObjectTexture &tb = gObjectTextures[bIndex]; - if (ta.tile.index < tb.tile.index) + if (ta.tile < tb.tile) return -1; - if (ta.tile.index > tb.tile.index) + if (ta.tile > tb.tile) return 1; #ifdef SPLIT_BY_CLUT @@ -1234,7 +1231,7 @@ namespace TR { #define FACE3_SIZE (FACE4_SIZE - sizeof(uint16)) struct ColorIndex4 { - uint8 a:4, b:4; + uint8 a:4, b:4; }; struct Tile4 { @@ -3004,18 +3001,14 @@ namespace TR { uint8 data[3]; }; - struct SPAL { - uint8 data[2]; - }; - uint32 tsubCount = 0; uint8 *tsub = NULL; uint32 tpalCount = 0; TPAL *tpal = NULL; - uint32 spalCount = 0; - SPAL *spal = NULL; + int32 spalCount = 0; + uint16 *spal = NULL; Room *room = NULL; @@ -3025,7 +3018,7 @@ namespace TR { char buf[9]; memcpy(buf, &chunkType, 8); buf[8] = 0; - LOG("chunk: \"%s\"\n", buf); + LOG("chunk: \"%s\"\n", buf); } switch (chunkType) { @@ -3041,30 +3034,68 @@ namespace TR { for (int i = 0; i < roomTexturesCount; i++) readObjectTex(stream, roomTextures[i], TEX_TYPE_ROOM); break; - case CHUNK("ROOMTQTR") : + case CHUNK("ROOMTQTR") : { ASSERTV(stream.readBE32() == 0x00000001); roomTexturesDataSize = stream.readBE32(); roomTexturesData = roomTexturesDataSize ? new uint8[roomTexturesDataSize] : NULL; stream.raw(roomTexturesData, roomTexturesDataSize); +/* + int32 count = stream.readBE32(); + stream.seek(count); + */ break; + } case CHUNK("ROOMTSUB") : ASSERTV(stream.readBE32() == 0x00000001); + /* + roomTexturesDataSize = stream.readBE32(); + roomTexturesData = roomTexturesDataSize ? new uint8[roomTexturesDataSize] : NULL; + stream.raw(roomTexturesData, roomTexturesDataSize); + */ + tsubCount = stream.readBE32(); tsub = new uint8[tsubCount]; stream.raw(tsub, sizeof(uint8) * tsubCount); + break; - case CHUNK("ROOMTPAL") : + case CHUNK("ROOMTPAL") : { ASSERTV(stream.readBE32() == 0x00000003); 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") : + } + case CHUNK("ROOMSPAL") : { ASSERTV(stream.readLE32() == 0x02000000); spalCount = stream.readBE32(); - spal = new SPAL[spalCount]; - stream.raw(spal, sizeof(SPAL) * spalCount); + 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") : ASSERTV(stream.readBE32() == 0x00000044); roomsCount = stream.readBE32(); @@ -3164,6 +3195,10 @@ namespace TR { f.vertices[3] = 0; ASSERT(f.vertices[0] < data.vCount && f.vertices[1] < data.vCount && f.vertices[2] < data.vCount); f.flags.value = stream.readBE16(); + if (type == TYPE_T_INVISIBLE) { + fIndex--; + continue; + } data.tCount++; break; case TYPE_R_INVISIBLE : @@ -3176,19 +3211,28 @@ namespace TR { f.vertices[3] = (stream.readBE16() >> 4); ASSERT(f.vertices[0] < data.vCount && f.vertices[1] < data.vCount && f.vertices[2] < data.vCount && f.vertices[3] < data.vCount); f.flags.value = stream.readBE16(); + if (type == TYPE_R_INVISIBLE) { + fIndex--; + continue; + } data.rCount++; break; default : LOG("! unknown face type: %d\n", type); ASSERT(false); } - if (type == TYPE_R_INVISIBLE || type == TYPE_T_INVISIBLE) - f.flags.value = 0; + //if (type == TYPE_R_TRANSP) + // f.flags.value = 0; //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) { + roomTextures[f.flags.texture].attribute = 1; + } } } data.fCount = fIndex; @@ -3380,7 +3424,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] = first + j; + animTex.textures[j] = last - j; } break; } @@ -3572,7 +3616,7 @@ namespace TR { objectTexturesCount = stream.readBE32(); objectTextures = objectTexturesCount ? new ObjectTexture[objectTexturesCount] : NULL; for (int i = 0; i < objectTexturesCount; i++) - readObjectTex(stream, objectTextures[i]); + readObjectTex(stream, objectTextures[i], TEX_TYPE_OBJECT); break; case CHUNK("OTEXTDAT") : { ASSERTV(stream.readBE32() == 0x00000001); @@ -3960,6 +4004,7 @@ namespace TR { #endif f.water = false; + f.flip = false; } void readRoom(Stream &stream, int roomIndex) { @@ -4199,6 +4244,7 @@ namespace TR { f.vertices[3] >>= 2; f.colored = false; f.water = false; + f.flip = false; } } else for (int i = 0; i < d.rCount; i++) readFace(stream, d.faces[idx++], false, false); @@ -4218,6 +4264,8 @@ namespace TR { f.vertices[2] >>= 2; f.vertices[3] = 0; f.colored = false; + f.water = false; + f.flip = false; } } else { for (int i = 0; i < d.tCount; i++) @@ -4420,7 +4468,7 @@ namespace TR { mesh.radius = swap16(mesh.radius); mesh.flags.value = swap16(mesh.flags.value); mesh.vCount = swap16(mesh.vCount); - } + } } switch (version) { @@ -4454,15 +4502,16 @@ namespace TR { mesh.tCount = mesh.rCount = 0; enum { - TYPE_T_UNKNOWN1 = 2, - TYPE_T_COLOR = 4, - TYPE_T_PALETTE = 8, - TYPE_T_UNKNOWN2 = 16, - TYPE_R_UNKNOWN1 = 17, - TYPE_R_COLOR = 5, - TYPE_R_TEX = 9, - TYPE_R_TRANSP = 49, - TYPE_R_UNKNOWN2 = 57, + TYPE_T_TEX = 2, + TYPE_T_COLOR = 4, + TYPE_T_PALETTE = 8, + TYPE_T_UNKNOWN2 = 16, + + TYPE_R_COLOR = 5, + TYPE_R_TEX = 9, + TYPE_R_TRANSP = 17, + TYPE_R_FLIP_TEX = 49, + TYPE_R_FLIP_TRANSP = 57, }; int divisor = 16; @@ -4479,7 +4528,7 @@ namespace TR { ASSERT(fIndex < mesh.fCount); Face &f = mesh.faces[fIndex++]; switch (type) { - case TYPE_T_UNKNOWN1 : + case TYPE_T_TEX : case TYPE_T_COLOR : case TYPE_T_PALETTE : case TYPE_T_UNKNOWN2 : @@ -4491,12 +4540,13 @@ namespace TR { f.flags.value = stream.readBE16(); ASSERT(f.vertices[0] < mesh.vCount && f.vertices[1] < mesh.vCount && f.vertices[2] < mesh.vCount); mesh.tCount++; + f.colored = true; break; - case TYPE_R_COLOR : - case TYPE_R_TEX : - case TYPE_R_TRANSP : - case TYPE_R_UNKNOWN1 : - case TYPE_R_UNKNOWN2 : + case TYPE_R_COLOR : + case TYPE_R_TEX : + case TYPE_R_TRANSP : + case TYPE_R_FLIP_TEX : + case TYPE_R_FLIP_TRANSP : f.vCount = 4; f.vertices[0] = (stream.readBE16() >> 5); f.vertices[1] = (stream.readBE16() >> 5); @@ -4512,7 +4562,9 @@ namespace TR { } if (type == TYPE_T_COLOR || type == TYPE_R_COLOR || type == TYPE_T_PALETTE || type == TYPE_T_UNKNOWN2) { if (type == TYPE_T_PALETTE) - f.flags.value = 0; + f.flags.value = 0xFFFF; // TODO + if (type == TYPE_T_UNKNOWN2) + f.flags.value = 0xFF80; // TODO f.colored = true; } else { ASSERT(f.flags.value % 16 == 0); @@ -4520,6 +4572,11 @@ namespace TR { f.flags.value /= divisor; f.colored = false; } + + if (type == TYPE_R_TRANSP || type == TYPE_R_FLIP_TRANSP) + objectTextures[f.flags.texture].attribute = 1; + + f.flip = (type == TYPE_R_FLIP_TEX || type == TYPE_R_FLIP_TRANSP); f.water = false; } } @@ -4813,7 +4870,8 @@ namespace TR { case VER_TR1_SAT : { struct { uint16 attribute; - Tile tile; + uint16 tile; + uint8 triangle; uint16 clut; uint8 w, h; uint8 x0, y0; @@ -4828,27 +4886,37 @@ namespace TR { if (type == TEX_TYPE_ITEM) index = stream.readBE16(); - d.tile.value = stream.readBE16(); // offset to 4-bit indices + 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.value; // offset to color palette - d.w = stream.read(); + d.clut = stream.readBE16() + d.tile; // offset to color palette + d.w = stream.read() << 3; d.h = stream.read(); uint16 i5 = stream.readBE16(); - //LOG("%d %d %d %d %d\n", i1, i2, i3, i4, i5); + //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_ITEM) stream.seek(2); d.x0 = d.y0 = d.x3 = d.y1 = 0; - d.x1 = d.x2 = max(0, (d.w << 3) - 1); + d.x1 = d.x2 = max(0, d.w - 1); d.y2 = d.y3 = max(0, d.h - 1); 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; @@ -4858,7 +4926,7 @@ namespace TR { case VER_TR3_PC : { struct { uint16 attribute; - Tile tile; + uint16 tile:14, :2; uint8 xh0, x0, yh0, y0; uint8 xh1, x1, yh1, y1; uint8 xh2, x2, yh2, y2; @@ -4875,9 +4943,9 @@ namespace TR { uint8 x0, y0; uint16 clut; uint8 x1, y1; - Tile tile; + uint16 tile:14, :2; uint8 x2, y2; - uint16 unknown; + uint16 unknown2; uint8 x3, y3; uint16 attribute; } d; @@ -4919,7 +4987,7 @@ namespace TR { t.b = d.b;\ } - switch (version) { + switch (version) { case VER_TR1_SAT : { struct { uint16 tile; @@ -4941,39 +5009,39 @@ namespace TR { t.texCoord[1] = t.texCoordAtlas[1] = short2( ((int16)d.w << 3) - 1, ((int16)d.h) - 1 ); break; } - case VER_TR1_PC : - case VER_TR2_PC : - case VER_TR3_PC : { - struct { - uint16 tile; - uint8 u, v; - uint16 w, h; - int16 l, t, r, b; - } d; - stream.raw(&d, sizeof(d)); - SET_PARAMS(t, d, 0); - 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 : - case VER_TR2_PSX : - case VER_TR3_PSX : { - struct { - int16 l, t, r, b; - uint16 clut; - uint16 tile; - uint8 u0, v0; - uint8 u1, v1; - } d; - stream.raw(&d, sizeof(d)); - SET_PARAMS(t, d, d.clut); - 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); + case VER_TR1_PC : + case VER_TR2_PC : + case VER_TR3_PC : { + struct { + uint16 tile; + uint8 u, v; + uint16 w, h; + int16 l, t, r, b; + } d; + stream.raw(&d, sizeof(d)); + SET_PARAMS(t, d, 0); + 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 : + case VER_TR2_PSX : + case VER_TR3_PSX : { + struct { + int16 l, t, r, b; + uint16 clut; + uint16 tile; + uint8 u0, v0; + uint8 u1, v1; + } d; + stream.raw(&d, sizeof(d)); + SET_PARAMS(t, d, d.clut); + 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); + } #undef SET_PARAMS } @@ -5095,18 +5163,10 @@ namespace TR { } } - void fillObjectTexture(Tile32 *dst, const short4 &uv, int16 tileIndex, int16 clutIndex, TextureType type) { + void fillObjectTexture(Tile32 *dst, const short4 &uv, int16 tileIndex, int32 clutIndex, TextureType type) { // convert to RGBA switch (version) { case VER_TR1_SAT : { - /* - if (type == TEX_TYPE_ROOM) { - for (int y = uv.y; y < uv.w; y++) - for (int x = uv.x; x < uv.z; x++) - dst->color[y * 256 + x] = Color32(255, 0, 255, 255); - return; - } - */ uint32 iOffset = uint32(uint16(tileIndex)) << 3; uint32 cOffset = uint32(uint16(clutIndex)) << 3; @@ -5123,14 +5183,37 @@ namespace TR { ColorIndex4 *indices = (ColorIndex4*) (data + iOffset); CLUT *clut = (CLUT*) (data + cOffset); + 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++) + for (int x = 0; x < h; x++) + dst->color[y * 256 + x] = Color32(255, 0, 255, 255); + return; + } + */ + for (int y = 0; y < h; y++) + for (int x = 0; x < w; x++) { + ColorIndex4 *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; + } - for (int y = uv.y; y < uv.w; y++) - for (int x = uv.x; x < uv.z; x++) { - ColorIndex4 *index = indices + ((y - uv.y) * w + (x - uv.x)) / 2; - Color16 &c = clut->color[(x % 2) ? index->a : index->b]; 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; + } + */ } + break; } case VER_TR1_PC : { @@ -5205,7 +5288,7 @@ namespace TR { ObjectTexture &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.index]; + Tile4 &tile = tiles4[t.tile]; CLUT &clut = cluts[t.clut]; return clut.color[part ? tile.index[idx].b : tile.index[idx].a]; } @@ -5278,7 +5361,7 @@ namespace TR { void floorSkipCommand(FloorData* &fd, int func) { switch (func) { - case FloorData::PORTAL : + case FloorData::PORTAL : case FloorData::FLOOR : case FloorData::CEILING : fd++; diff --git a/src/gameflow.h b/src/gameflow.h index a723158..b33a87d 100644 --- a/src/gameflow.h +++ b/src/gameflow.h @@ -936,6 +936,7 @@ namespace TR { } } else { switch (version) { + case VER_TR1_SAT : case VER_TR1_PC : case VER_TR1_PSX : sprintf(title, "audio/1/track_%02d.ogg", track); diff --git a/src/level.h b/src/level.h index 6e5988a..a36d299 100644 --- a/src/level.h +++ b/src/level.h @@ -1145,7 +1145,8 @@ struct Level : IGame { src = owner->tileData->color; uv = t.texCoordAtlas; uvCount = 4; - level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut, t.type); + if (data) + level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut, t.type); } else { id -= level->objectTexturesCount; @@ -1155,7 +1156,8 @@ struct Level : IGame { src = owner->tileData->color; uv = t.texCoordAtlas; uvCount = 2; - level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut, TR::TextureType::TEX_TYPE_SPRITE); + if (data) + level->fillObjectTexture(owner->tileData, tile.uv, tile.tile, tile.clut, TR::TextureType::TEX_TYPE_SPRITE); } else { // common (generated) textures id -= level->spriteTexturesCount; @@ -1302,7 +1304,7 @@ 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++, uv, t.tile.index, t.clut); + tiles->add(texIdx++, t.type, uv, t.tile, t.clut); } // add sprites for (int i = 0; i < level.spriteTexturesCount; i++) { @@ -1314,12 +1316,12 @@ struct Level : IGame { uv.z = t.texCoord[1].x + 1; uv.w = t.texCoord[1].y + 1; - tiles->add(texIdx++, uv, t.tile, t.clut); + tiles->add(texIdx++, TR::TEX_TYPE_SPRITE, 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(texIdx++, short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y)); + tiles->add(texIdx++, TR::TEX_TYPE_SPRITE, short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y)); // get result texture tileData = new TR::Tile32(); diff --git a/src/mesh.h b/src/mesh.h index 0106d1d..37d8be0 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -17,6 +17,8 @@ TR::ObjectTexture &whiteTile = barTile[4]; // BAR_WHITE #define WATER_VOLUME_HEIGHT (768 * 2) #define WATER_VOLUME_OFFSET 4 +const TR::Color32 COLOR_WHITE( 255, 255, 255, 255 ); + struct Mesh : GAPI::Mesh { int aIndex; @@ -365,8 +367,6 @@ struct MeshBuilder { int vStartModel = vCount; aCount++; - TR::Color32 COLOR_WHITE(255, 255, 255, 255); - for (int i = 0; i < level.modelsCount; i++) { TR::Model &model = level.models[i]; @@ -487,7 +487,7 @@ struct MeshBuilder { quad.iStart = iCount; quad.iCount = 2 * 3; - addQuad(indices, iCount, vCount, vStartCommon, vertices, &whiteTile, false); + addQuad(indices, iCount, vCount, vStartCommon, vertices, &whiteTile, false, false); vertices[vCount + 0].coord = short4( -32767, 32767, 0, 1 ); vertices[vCount + 1].coord = short4( 32767, 32767, 1, 1 ); vertices[vCount + 2].coord = short4( 32767, -32767, 1, 0 ); @@ -926,8 +926,8 @@ struct MeshBuilder { continue; } - if (!geom.validForTile(t.tile.index, t.clut)) - geom.getNextRange(vStart, iCount, t.tile.index, t.clut); + if (!geom.validForTile(t.tile, t.clut)) + geom.getNextRange(vStart, iCount, t.tile, t.clut); ADD_ROOM_FACE(indices, iCount, vCount, vStart, vertices, f, t); } @@ -959,7 +959,6 @@ struct MeshBuilder { } bool buildMesh(Geometry &geom, int blendMask, const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir, const TR::Color32 &light) { - TR::Color24 COLOR_WHITE( 255, 255, 255 ); bool isOpaque = true; for (int j = 0; j < mesh.fCount; j++) { @@ -973,8 +972,8 @@ struct MeshBuilder { if (!(blendMask & getBlendMask(t.attribute))) continue; - if (!geom.validForTile(t.tile.index, t.clut)) - geom.getNextRange(vStart, iCount, t.tile.index, t.clut); + if (!geom.validForTile(t.tile, t.clut)) + geom.getNextRange(vStart, iCount, t.tile, t.clut); TR::Color32 c = f.colored ? level.getColor(f.flags.value) : COLOR_WHITE; @@ -1001,7 +1000,7 @@ struct MeshBuilder { return isOpaque; } - void addTexCoord(Vertex *vertices, int vCount, TR::ObjectTexture *tex, bool triangle) { + void addTexCoord(Vertex *vertices, int vCount, TR::ObjectTexture *tex, bool triangle, bool flip) { int count = triangle ? 3 : 4; for (int i = 0; i < count; i++) { Vertex &v = vertices[vCount + i]; @@ -1010,9 +1009,14 @@ struct MeshBuilder { if (((level->version & TR::VER_PSX)) && !triangle) // TODO: swap vertices instead of rectangle indices and vertices.texCoords (WRONG lighting in TR2!) swap(vertices[vCount + 2].texCoord, vertices[vCount + 3].texCoord); + + if (flip) { + swap(vertices[vCount + 0].texCoord, vertices[vCount + 1].texCoord); + swap(vertices[vCount + 2].texCoord, vertices[vCount + 3].texCoord); + } } - void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex, bool doubleSided) { + void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex, bool doubleSided, bool flip) { int vIndex = vCount - vStart; indices[iCount + 0] = vIndex + 0; @@ -1028,10 +1032,10 @@ struct MeshBuilder { iCount += 3; } - if (tex) addTexCoord(vertices, vCount, tex, true); + 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) { + void addQuad(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex, bool doubleSided, bool flip) { int vIndex = vCount - vStart; indices[iCount + 0] = vIndex + 0; @@ -1056,12 +1060,12 @@ struct MeshBuilder { iCount += 6; } - if (tex) addTexCoord(vertices, vCount, tex, false); + 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, + void addQuad(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, TR::ObjectTexture *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); + addQuad(indices, iCount, vCount, vStart, vertices, tex, doubleSided, flip); vec3 a = c0 - c1; vec3 b = c3 - c2; @@ -1099,9 +1103,9 @@ 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) { if (f.vCount == 4) - addQuad(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, a, b, c, d); + addQuad(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, f.flip, a, b, c, d); else - addTriangle(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided); + addTriangle(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, f.flip); } @@ -1114,7 +1118,7 @@ struct MeshBuilder { } 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) { - addQuad(indices, iCount, vCount, vStart, NULL, NULL, false); + addQuad(indices, iCount, vCount, vStart, NULL, NULL, false, false); Vertex *quad = &vertices[vCount]; @@ -1161,7 +1165,7 @@ struct MeshBuilder { } 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) { - addQuad(indices, iCount, vCount, 0, vertices, NULL, false); + addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); int16 minX = int16(pos.x); int16 minY = int16(pos.y); @@ -1214,8 +1218,8 @@ struct MeshBuilder { v.texCoord = uv; } - addQuad(indices, iCount, vCount, 0, vertices, NULL, false); vCount += 4; - addQuad(indices, iCount, vCount, 0, vertices, NULL, false); vCount += 4; + addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4; + addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4; vertices[vCount + 0].coord = short4( minX, int16(maxY - 1), 0, 0 ); vertices[vCount + 1].coord = short4( maxX, int16(maxY - 1), 0, 0 ); @@ -1234,8 +1238,8 @@ struct MeshBuilder { v.texCoord = uv; } - addQuad(indices, iCount, vCount, 0, vertices, NULL, false); vCount += 4; - addQuad(indices, iCount, vCount, 0, vertices, NULL, false); vCount += 4; + addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4; + addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4; } void renderBuffer(Index *indices, int iCount, Vertex *vertices, int vCount) { diff --git a/src/texture.h b/src/texture.h index eac96fe..27d3e40 100644 --- a/src/texture.h +++ b/src/texture.h @@ -683,9 +683,10 @@ struct Texture : GAPI::Texture { struct Atlas { struct Tile { - int32 id; - int16 tile; - int16 clut; + uint16 id; + uint16 type; + uint16 tile; + uint16 clut; short4 uv; } *tiles; @@ -760,9 +761,9 @@ struct Atlas { delete[] tiles; } - void add(int32 id, short4 uv, int16 tile = 0, int16 clut = 0) { + void add(uint16 id, uint16 type, short4 uv, uint16 tile = 0, uint16 clut = 0) { for (int i = 0; i < tilesCount; i++) - if (tiles[i].uv == uv && tiles[i].tile == tile && tiles[i].clut == clut) { + if (tiles[i].uv == uv && tiles[i].type == type && tiles[i].tile == tile && tiles[i].clut == clut) { uv.x = 0x7FFF; uv.y = tiles[i].id; uv.z = uv.w = 0; @@ -770,6 +771,7 @@ struct Atlas { } tiles[tilesCount].id = id; + tiles[tilesCount].type = type; tiles[tilesCount].tile = tile; tiles[tilesCount].clut = clut; tiles[tilesCount].uv = uv; diff --git a/src/ui.h b/src/ui.h index ca55051..9a13db8 100644 --- a/src/ui.h +++ b/src/ui.h @@ -413,6 +413,9 @@ namespace UI { int frame = charRemap(c); + if (frame >= level->spriteSequences[seq].sCount) + continue; + if (buffer.iCount == MAX_CHARS * 6) flush(); @@ -468,6 +471,9 @@ namespace UI { if (buffer.iCount == MAX_CHARS * 6) flush(); + if (specChar >= level->spriteSequences[seq].sCount) + return; + TR::SpriteTexture &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + specChar]; #ifdef SPLIT_BY_TILE