mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-14 09:04:31 +02:00
#138 fix triangular textures
This commit is contained in:
232
src/format.h
232
src/format.h
@@ -110,7 +110,7 @@
|
|||||||
E( AMMO_SHOTGUN ) \
|
E( AMMO_SHOTGUN ) \
|
||||||
E( AMMO_MAGNUMS ) \
|
E( AMMO_MAGNUMS ) \
|
||||||
E( AMMO_UZIS ) \
|
E( AMMO_UZIS ) \
|
||||||
E( AMMO_EXPLOSIVE ) \
|
E( EXPLOSIVE ) \
|
||||||
E( MEDIKIT_SMALL ) \
|
E( MEDIKIT_SMALL ) \
|
||||||
E( MEDIKIT_BIG ) \
|
E( MEDIKIT_BIG ) \
|
||||||
E( INV_DETAIL ) \
|
E( INV_DETAIL ) \
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
E( INV_AMMO_SHOTGUN ) \
|
E( INV_AMMO_SHOTGUN ) \
|
||||||
E( INV_AMMO_MAGNUMS ) \
|
E( INV_AMMO_MAGNUMS ) \
|
||||||
E( INV_AMMO_UZIS ) \
|
E( INV_AMMO_UZIS ) \
|
||||||
E( INV_AMMO_EXPLOSIVE ) \
|
E( INV_EXPLOSIVE ) \
|
||||||
E( INV_MEDIKIT_SMALL ) \
|
E( INV_MEDIKIT_SMALL ) \
|
||||||
E( INV_MEDIKIT_BIG ) \
|
E( INV_MEDIKIT_BIG ) \
|
||||||
E( PUZZLE_1 ) \
|
E( PUZZLE_1 ) \
|
||||||
@@ -1181,7 +1181,7 @@ namespace TR {
|
|||||||
|
|
||||||
short3 normal;
|
short3 normal;
|
||||||
uint16 vertices[4];
|
uint16 vertices[4];
|
||||||
uint8 water:1, colored:1, flip:1, vCount:5;
|
uint8 triangle:1, colored:1, water:1, flip:5;
|
||||||
|
|
||||||
static int cmp(const Face &a, const Face &b) {
|
static int cmp(const Face &a, const Face &b) {
|
||||||
int aIndex = a.flags.texture;
|
int aIndex = a.flags.texture;
|
||||||
@@ -1849,7 +1849,7 @@ namespace TR {
|
|||||||
|| type == INV_AMMO_SHOTGUN
|
|| type == INV_AMMO_SHOTGUN
|
||||||
|| type == INV_AMMO_MAGNUMS
|
|| type == INV_AMMO_MAGNUMS
|
||||||
|| type == INV_AMMO_UZIS
|
|| type == INV_AMMO_UZIS
|
||||||
|| type == INV_AMMO_EXPLOSIVE
|
|| type == INV_EXPLOSIVE
|
||||||
|| type == INV_MEDIKIT_SMALL
|
|| type == INV_MEDIKIT_SMALL
|
||||||
|| type == INV_MEDIKIT_BIG
|
|| type == INV_MEDIKIT_BIG
|
||||||
|| type == INV_PUZZLE_1
|
|| type == INV_PUZZLE_1
|
||||||
@@ -2279,6 +2279,7 @@ namespace TR {
|
|||||||
int32 staticMeshesCount;
|
int32 staticMeshesCount;
|
||||||
StaticMesh *staticMeshes;
|
StaticMesh *staticMeshes;
|
||||||
|
|
||||||
|
int32 objectTexturesBaseCount;
|
||||||
int32 objectTexturesCount;
|
int32 objectTexturesCount;
|
||||||
TextureInfo *objectTextures;
|
TextureInfo *objectTextures;
|
||||||
|
|
||||||
@@ -2294,6 +2295,7 @@ namespace TR {
|
|||||||
int32 itemTexturesCount;
|
int32 itemTexturesCount;
|
||||||
TextureInfo *itemTextures;
|
TextureInfo *itemTextures;
|
||||||
|
|
||||||
|
int32 itemTexturesBaseCount;
|
||||||
int32 itemTexturesDataSize;
|
int32 itemTexturesDataSize;
|
||||||
uint8 *itemTexturesData;
|
uint8 *itemTexturesData;
|
||||||
|
|
||||||
@@ -2472,6 +2474,7 @@ namespace TR {
|
|||||||
int16 sound;
|
int16 sound;
|
||||||
int16 controls;
|
int16 controls;
|
||||||
int16 gamma;
|
int16 gamma;
|
||||||
|
int16 explosive;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int16 items[MAX_WEAPONS];
|
int16 items[MAX_WEAPONS];
|
||||||
@@ -2612,8 +2615,7 @@ namespace TR {
|
|||||||
|
|
||||||
if (version == VER_UNKNOWN) {
|
if (version == VER_UNKNOWN) {
|
||||||
LOG("unsupported level format\n");
|
LOG("unsupported level format\n");
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
memset(this, 0, sizeof(*this));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2982,12 +2984,14 @@ namespace TR {
|
|||||||
|
|
||||||
while (stream.pos < stream.size) {
|
while (stream.pos < stream.size) {
|
||||||
uint64 chunkType = stream.read64();
|
uint64 chunkType = stream.read64();
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
char buf[9];
|
char buf[9];
|
||||||
memcpy(buf, &chunkType, 8);
|
memcpy(buf, &chunkType, 8);
|
||||||
buf[8] = 0;
|
buf[8] = 0;
|
||||||
LOG("chunk: \"%s\"\n", buf);
|
LOG("chunk: \"%s\"\n", buf);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
switch (chunkType) {
|
switch (chunkType) {
|
||||||
// SAT
|
// SAT
|
||||||
@@ -3117,7 +3121,7 @@ namespace TR {
|
|||||||
for (int j = 0; j < typesCount; j++) {
|
for (int j = 0; j < typesCount; j++) {
|
||||||
uint16 type = stream.readBE16();
|
uint16 type = stream.readBE16();
|
||||||
uint16 count = stream.readBE16();
|
uint16 count = stream.readBE16();
|
||||||
LOG(" type:%d count:%d\n", (int)type, (int)count);
|
//LOG(" type:%d count:%d\n", (int)type, (int)count);
|
||||||
for (int k = 0; k < count; k++) {
|
for (int k = 0; k < count; k++) {
|
||||||
ASSERT(fIndex < data.fCount);
|
ASSERT(fIndex < data.fCount);
|
||||||
|
|
||||||
@@ -3133,7 +3137,7 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
case TYPE_T_INVISIBLE :
|
case TYPE_T_INVISIBLE :
|
||||||
case TYPE_T_SOLID :
|
case TYPE_T_SOLID :
|
||||||
f.vCount = 3;
|
f.triangle = true;
|
||||||
f.vertices[0] = (stream.readBE16() >> 4);
|
f.vertices[0] = (stream.readBE16() >> 4);
|
||||||
f.vertices[1] = (stream.readBE16() >> 4);
|
f.vertices[1] = (stream.readBE16() >> 4);
|
||||||
f.vertices[2] = (stream.readBE16() >> 4);
|
f.vertices[2] = (stream.readBE16() >> 4);
|
||||||
@@ -3149,7 +3153,7 @@ namespace TR {
|
|||||||
case TYPE_R_INVISIBLE :
|
case TYPE_R_INVISIBLE :
|
||||||
case TYPE_R_TRANSP :
|
case TYPE_R_TRANSP :
|
||||||
case TYPE_R_SOLID :
|
case TYPE_R_SOLID :
|
||||||
f.vCount = 4;
|
f.triangle = false;
|
||||||
f.vertices[0] = (stream.readBE16() >> 4);
|
f.vertices[0] = (stream.readBE16() >> 4);
|
||||||
f.vertices[1] = (stream.readBE16() >> 4);
|
f.vertices[1] = (stream.readBE16() >> 4);
|
||||||
f.vertices[2] = (stream.readBE16() >> 4);
|
f.vertices[2] = (stream.readBE16() >> 4);
|
||||||
@@ -3539,9 +3543,11 @@ namespace TR {
|
|||||||
ASSERTV(stream.readBE32() == 0x00000010);
|
ASSERTV(stream.readBE32() == 0x00000010);
|
||||||
ASSERT(objectTextures == NULL);
|
ASSERT(objectTextures == NULL);
|
||||||
objectTexturesCount = stream.readBE32();
|
objectTexturesCount = stream.readBE32();
|
||||||
objectTextures = objectTexturesCount ? new TextureInfo[objectTexturesCount] : NULL;
|
objectTextures = objectTexturesCount ? new TextureInfo[objectTexturesCount * 5] : NULL;
|
||||||
for (int i = 0; i < objectTexturesCount; i++)
|
for (int i = 0; i < objectTexturesCount; i++)
|
||||||
readObjectTex(stream, objectTextures[i], TEX_TYPE_OBJECT);
|
readObjectTex(stream, objectTextures[i], TEX_TYPE_OBJECT);
|
||||||
|
objectTexturesBaseCount = objectTexturesCount;
|
||||||
|
expandObjectTex(objectTextures, objectTexturesCount);
|
||||||
break;
|
break;
|
||||||
case CHUNK("OTEXTDAT") : {
|
case CHUNK("OTEXTDAT") : {
|
||||||
ASSERTV(stream.readBE32() == 0x00000001);
|
ASSERTV(stream.readBE32() == 0x00000001);
|
||||||
@@ -3553,9 +3559,11 @@ namespace TR {
|
|||||||
case CHUNK("ITEXTINF") : {
|
case CHUNK("ITEXTINF") : {
|
||||||
ASSERTV(stream.readBE32() == 0x00000014);
|
ASSERTV(stream.readBE32() == 0x00000014);
|
||||||
itemTexturesCount = stream.readBE32();
|
itemTexturesCount = stream.readBE32();
|
||||||
itemTextures = itemTexturesCount ? new TextureInfo[itemTexturesCount] : NULL;
|
itemTextures = itemTexturesCount ? new TextureInfo[itemTexturesCount * 5] : NULL;
|
||||||
for (int i = 0; i < itemTexturesCount; i++)
|
for (int i = 0; i < itemTexturesCount; i++)
|
||||||
readObjectTex(stream, itemTextures[i], TEX_TYPE_ITEM);
|
readObjectTex(stream, itemTextures[i], TEX_TYPE_ITEM);
|
||||||
|
itemTexturesBaseCount = itemTexturesCount;
|
||||||
|
expandObjectTex(itemTextures, itemTexturesCount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CHUNK("ITEXTDAT") : {
|
case CHUNK("ITEXTDAT") : {
|
||||||
@@ -3665,6 +3673,16 @@ namespace TR {
|
|||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void expandObjectTex(TextureInfo *textures, int32 &count) {
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
int idx = count * (1 + j) + i;
|
||||||
|
textures[idx] = textures[i];
|
||||||
|
textures[idx].tile = textures[idx].sub[j];
|
||||||
|
}
|
||||||
|
count *= 5;
|
||||||
|
}
|
||||||
|
|
||||||
int getItemTexureByIndex(uint16 index) {
|
int getItemTexureByIndex(uint16 index) {
|
||||||
for (int i = 0; i < itemTexturesCount; i++)
|
for (int i = 0; i < itemTexturesCount; i++)
|
||||||
if (itemTextures[i].index == index)
|
if (itemTextures[i].index == index)
|
||||||
@@ -3754,8 +3772,7 @@ namespace TR {
|
|||||||
Mesh &mesh = meshes[meshOffsets[j]];
|
Mesh &mesh = meshes[meshOffsets[j]];
|
||||||
for (int k = 0; k < mesh.fCount; k++)
|
for (int k = 0; k < mesh.fCount; k++)
|
||||||
if (!mesh.faces[k].colored) {
|
if (!mesh.faces[k].colored) {
|
||||||
ASSERT(mesh.faces[k].flags.texture < itemTexturesCount);
|
mesh.faces[k].flags.texture += objectTexturesCount;
|
||||||
mesh.faces[k].flags.texture = getItemTexureByIndex(mesh.faces[k].flags.texture) + objectTexturesCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3764,6 +3781,13 @@ namespace TR {
|
|||||||
appendObjectTex(itemTextures, itemTexturesCount);
|
appendObjectTex(itemTextures, itemTexturesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version == VER_TR1_SAT) {
|
||||||
|
for (int i = 0; i < objectTexturesCount; i++) {
|
||||||
|
if (objectTextures[i].tile == 1)
|
||||||
|
objectTextures[i].tile = 0xFFFF; // mark as unused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initRoomMeshes();
|
initRoomMeshes();
|
||||||
initAnimTex();
|
initAnimTex();
|
||||||
initExtra();
|
initExtra();
|
||||||
@@ -3832,6 +3856,7 @@ namespace TR {
|
|||||||
case Entity::INV_SOUND : extra.inv.sound = i; break;
|
case Entity::INV_SOUND : extra.inv.sound = i; break;
|
||||||
case Entity::INV_CONTROLS : extra.inv.controls = i; break;
|
case Entity::INV_CONTROLS : extra.inv.controls = i; break;
|
||||||
case Entity::INV_GAMMA : extra.inv.gamma = i; break;
|
case Entity::INV_GAMMA : extra.inv.gamma = i; break;
|
||||||
|
case Entity::INV_EXPLOSIVE : extra.inv.explosive = i; break;
|
||||||
|
|
||||||
case Entity::LARA_PISTOLS :
|
case Entity::LARA_PISTOLS :
|
||||||
case Entity::LARA_SHOTGUN :
|
case Entity::LARA_SHOTGUN :
|
||||||
@@ -3943,9 +3968,9 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void readFace(Stream &stream, Face &f, bool colored, bool triangle) {
|
void readFace(Stream &stream, Face &f, bool colored, bool triangle) {
|
||||||
f.vCount = triangle ? 3 : 4;
|
f.triangle = triangle;
|
||||||
|
|
||||||
for (int i = 0; i < f.vCount; i++)
|
for (int i = 0; i < (triangle ? 3 : 4); i++)
|
||||||
stream.read(f.vertices[i]);
|
stream.read(f.vertices[i]);
|
||||||
|
|
||||||
if (triangle)
|
if (triangle)
|
||||||
@@ -4067,7 +4092,7 @@ namespace TR {
|
|||||||
Face &f = d.faces[d.fCount++];
|
Face &f = d.faces[d.fCount++];
|
||||||
f.flags.texture = t.texture;
|
f.flags.texture = t.texture;
|
||||||
f.flags.doubleSided = false;
|
f.flags.doubleSided = false;
|
||||||
f.vCount = 3;
|
f.triangle = true;
|
||||||
f.colored = false;
|
f.colored = false;
|
||||||
f.flip = false;
|
f.flip = false;
|
||||||
f.vertices[0] = vStart + t.i0;
|
f.vertices[0] = vStart + t.i0;
|
||||||
@@ -4102,7 +4127,7 @@ namespace TR {
|
|||||||
Face &f = d.faces[d.fCount++];
|
Face &f = d.faces[d.fCount++];
|
||||||
f.flags.texture = texture;
|
f.flags.texture = texture;
|
||||||
f.flags.doubleSided = false;
|
f.flags.doubleSided = false;
|
||||||
f.vCount = 4;
|
f.triangle = false;
|
||||||
f.colored = false;
|
f.colored = false;
|
||||||
f.flip = false;
|
f.flip = false;
|
||||||
f.vertices[0] = vStart + r.i0;
|
f.vertices[0] = vStart + r.i0;
|
||||||
@@ -4194,15 +4219,15 @@ namespace TR {
|
|||||||
if ((stream.pos - startOffset) % 4) stream.seek(2);
|
if ((stream.pos - startOffset) % 4) stream.seek(2);
|
||||||
for (int i = 0; i < d.rCount; i++) {
|
for (int i = 0; i < d.rCount; i++) {
|
||||||
Face &f = d.faces[i];
|
Face &f = d.faces[i];
|
||||||
f.vCount = 4;
|
|
||||||
stream.raw(f.vertices, sizeof(uint16) * 4);
|
stream.raw(f.vertices, sizeof(uint16) * 4);
|
||||||
f.vertices[0] >>= 2;
|
f.vertices[0] >>= 2;
|
||||||
f.vertices[1] >>= 2;
|
f.vertices[1] >>= 2;
|
||||||
f.vertices[2] >>= 2;
|
f.vertices[2] >>= 2;
|
||||||
f.vertices[3] >>= 2;
|
f.vertices[3] >>= 2;
|
||||||
f.colored = false;
|
f.triangle = false;
|
||||||
f.water = false;
|
f.colored = false;
|
||||||
f.flip = false;
|
f.water = false;
|
||||||
|
f.flip = false;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
for (int i = 0; i < d.rCount; i++) readFace(stream, d.faces[idx++], false, false);
|
for (int i = 0; i < d.rCount; i++) readFace(stream, d.faces[idx++], false, false);
|
||||||
@@ -4214,16 +4239,16 @@ namespace TR {
|
|||||||
stream.seek(2);
|
stream.seek(2);
|
||||||
for (int i = 0; i < d.tCount; i++) {
|
for (int i = 0; i < d.tCount; i++) {
|
||||||
Face &f = d.faces[d.rCount + i];
|
Face &f = d.faces[d.rCount + i];
|
||||||
f.vCount = 3;
|
|
||||||
stream.raw(&f.flags.value, sizeof(uint16));
|
stream.raw(&f.flags.value, sizeof(uint16));
|
||||||
stream.raw(f.vertices, sizeof(uint16) * 3);
|
stream.raw(f.vertices, sizeof(uint16) * 3);
|
||||||
f.vertices[0] >>= 2;
|
f.vertices[0] >>= 2;
|
||||||
f.vertices[1] >>= 2;
|
f.vertices[1] >>= 2;
|
||||||
f.vertices[2] >>= 2;
|
f.vertices[2] >>= 2;
|
||||||
f.vertices[3] = 0;
|
f.vertices[3] = 0;
|
||||||
f.colored = false;
|
f.triangle = true;
|
||||||
f.water = false;
|
f.colored = false;
|
||||||
f.flip = false;
|
f.water = false;
|
||||||
|
f.flip = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < d.tCount; i++)
|
for (int i = 0; i < d.tCount; i++)
|
||||||
@@ -4233,7 +4258,7 @@ namespace TR {
|
|||||||
|
|
||||||
if (version & VER_PSX) { // swap indices (quad strip -> quad list) only for PSX version
|
if (version & VER_PSX) { // swap indices (quad strip -> quad list) only for PSX version
|
||||||
for (int j = 0; j < d.fCount; j++)
|
for (int j = 0; j < d.fCount; j++)
|
||||||
if (d.faces[j].vCount == 4)
|
if (!d.faces[j].triangle)
|
||||||
swap(d.faces[j].vertices[2], d.faces[j].vertices[3]);
|
swap(d.faces[j].vertices[2], d.faces[j].vertices[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4460,26 +4485,29 @@ namespace TR {
|
|||||||
mesh.tCount = mesh.rCount = 0;
|
mesh.tCount = mesh.rCount = 0;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TYPE_T_TEX = 2,
|
TYPE_T_TEX_UNK = 2,
|
||||||
TYPE_T_COLOR = 4,
|
TYPE_T_COLOR = 4,
|
||||||
TYPE_T_UNKNOWN1 = 8,
|
TYPE_T_TEX = 8,
|
||||||
TYPE_T_UNKNOWN2 = 16,
|
TYPE_T_TEX_TRANSP = 16,
|
||||||
TYPE_R_COLOR = 5,
|
TYPE_R_COLOR = 5,
|
||||||
TYPE_R_TEX = 9,
|
TYPE_R_TEX = 9,
|
||||||
TYPE_R_TRANSP = 17,
|
TYPE_R_TRANSP = 17,
|
||||||
TYPE_R_FLIP_TEX = 49,
|
TYPE_R_FLIP_TEX = 49,
|
||||||
TYPE_R_FLIP_TRANSP = 57,
|
TYPE_R_FLIP_TRANSP = 57,
|
||||||
};
|
};
|
||||||
|
|
||||||
TextureInfo *textures;
|
TextureInfo *textures;
|
||||||
int texturesCount;
|
int texturesCount;
|
||||||
|
int texturesBaseCount;
|
||||||
|
|
||||||
if (Entity::isInventoryItem(type)) {
|
if (itemTexturesCount && Entity::isInventoryItem(type)) {
|
||||||
textures = itemTextures;
|
textures = itemTextures;
|
||||||
texturesCount = itemTexturesCount;
|
texturesCount = itemTexturesCount;
|
||||||
|
texturesBaseCount = itemTexturesBaseCount;
|
||||||
} else {
|
} else {
|
||||||
textures = objectTextures;
|
textures = objectTextures;
|
||||||
texturesCount = objectTexturesCount;
|
texturesCount = objectTexturesCount;
|
||||||
|
texturesBaseCount = objectTexturesBaseCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fIndex = 0;
|
int fIndex = 0;
|
||||||
@@ -4487,16 +4515,18 @@ namespace TR {
|
|||||||
for (int j = 0; j < typesCount; j++) {
|
for (int j = 0; j < typesCount; j++) {
|
||||||
uint16 type = stream.readBE16();
|
uint16 type = stream.readBE16();
|
||||||
uint16 count = stream.readBE16();
|
uint16 count = stream.readBE16();
|
||||||
|
|
||||||
for (int k = 0; k < count; k++) {
|
for (int k = 0; k < count; k++) {
|
||||||
ASSERT(fIndex < mesh.fCount);
|
ASSERT(fIndex < mesh.fCount);
|
||||||
Face &f = mesh.faces[fIndex++];
|
Face &f = mesh.faces[fIndex++];
|
||||||
|
f.water = false;
|
||||||
|
f.colored = false;
|
||||||
|
f.flip = 0;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_T_COLOR : f.colored = true;
|
case TYPE_T_COLOR : f.colored = true;
|
||||||
case TYPE_T_TEX :
|
case TYPE_T_TEX_UNK :
|
||||||
case TYPE_T_UNKNOWN1 :
|
case TYPE_T_TEX :
|
||||||
case TYPE_T_UNKNOWN2 :
|
case TYPE_T_TEX_TRANSP :
|
||||||
f.vCount = 3;
|
f.triangle = true;
|
||||||
f.vertices[0] = (stream.readBE16() >> 5);
|
f.vertices[0] = (stream.readBE16() >> 5);
|
||||||
f.vertices[1] = (stream.readBE16() >> 5);
|
f.vertices[1] = (stream.readBE16() >> 5);
|
||||||
f.vertices[2] = (stream.readBE16() >> 5);
|
f.vertices[2] = (stream.readBE16() >> 5);
|
||||||
@@ -4504,13 +4534,49 @@ namespace TR {
|
|||||||
f.flags.value = stream.readBE16();
|
f.flags.value = stream.readBE16();
|
||||||
ASSERT(f.vertices[0] < mesh.vCount && f.vertices[1] < mesh.vCount && f.vertices[2] < mesh.vCount);
|
ASSERT(f.vertices[0] < mesh.vCount && f.vertices[1] < mesh.vCount && f.vertices[2] < mesh.vCount);
|
||||||
mesh.tCount++;
|
mesh.tCount++;
|
||||||
|
|
||||||
|
if (!f.colored) {
|
||||||
|
union {
|
||||||
|
struct { uint16 texture:12, flip:4; };
|
||||||
|
uint16 value;
|
||||||
|
} tri;
|
||||||
|
|
||||||
|
tri.value = f.flags.value;
|
||||||
|
f.flags.value = tri.texture;
|
||||||
|
f.flip = tri.flip;
|
||||||
|
|
||||||
|
if (textures == itemTextures)
|
||||||
|
f.flags.value = getItemTexureByIndex(f.flags.value);
|
||||||
|
|
||||||
|
f.flags.value += texturesBaseCount;
|
||||||
|
|
||||||
|
if (f.flip != 0 && f.flip != 2 && f.flip != 4 && f.flip != 6 && f.flip != 8 && f.flip != 10 && f.flip != 12 && f.flip != 14) {
|
||||||
|
// TODO puma flip 14 bug
|
||||||
|
ASSERT(false);
|
||||||
|
f.colored = true;
|
||||||
|
f.flags.value = 0x00FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.flip == 6 || f.flip == 12) { // 3 bit
|
||||||
|
f.flags.value += texturesBaseCount + texturesBaseCount + texturesBaseCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.flip == 4 || f.flip == 14) {
|
||||||
|
f.flags.value += texturesBaseCount + texturesBaseCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.flip == 2 || f.flip == 8) {
|
||||||
|
f.flags.value += texturesBaseCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case TYPE_R_COLOR : f.colored = true;
|
case TYPE_R_COLOR : f.colored = true;
|
||||||
|
case TYPE_R_FLIP_TEX :
|
||||||
|
case TYPE_R_FLIP_TRANSP : f.flip = 1;
|
||||||
case TYPE_R_TEX :
|
case TYPE_R_TEX :
|
||||||
case TYPE_R_TRANSP :
|
case TYPE_R_TRANSP :
|
||||||
case TYPE_R_FLIP_TEX :
|
f.triangle = false;
|
||||||
case TYPE_R_FLIP_TRANSP :
|
|
||||||
f.vCount = 4;
|
|
||||||
f.vertices[0] = (stream.readBE16() >> 5);
|
f.vertices[0] = (stream.readBE16() >> 5);
|
||||||
f.vertices[1] = (stream.readBE16() >> 5);
|
f.vertices[1] = (stream.readBE16() >> 5);
|
||||||
f.vertices[2] = (stream.readBE16() >> 5);
|
f.vertices[2] = (stream.readBE16() >> 5);
|
||||||
@@ -4518,32 +4584,28 @@ namespace TR {
|
|||||||
f.flags.value = stream.readBE16();
|
f.flags.value = stream.readBE16();
|
||||||
ASSERT(f.vertices[0] < mesh.vCount && f.vertices[1] < mesh.vCount && f.vertices[2] < mesh.vCount && f.vertices[3] < mesh.vCount);
|
ASSERT(f.vertices[0] < mesh.vCount && f.vertices[1] < mesh.vCount && f.vertices[2] < mesh.vCount && f.vertices[3] < mesh.vCount);
|
||||||
mesh.rCount++;
|
mesh.rCount++;
|
||||||
|
|
||||||
|
f.flip = (type == TYPE_R_FLIP_TEX || type == TYPE_R_FLIP_TRANSP);
|
||||||
|
|
||||||
|
if (!f.colored) {
|
||||||
|
ASSERT(f.flags.value % 16 == 0);
|
||||||
|
f.flags.value /= 16;
|
||||||
|
|
||||||
|
if (textures == itemTextures)
|
||||||
|
f.flags.value = getItemTexureByIndex(f.flags.value);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
LOG("! unknown face type: %d\n", type);
|
LOG("! unknown face type: %d\n", type);
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
ASSERT(f.colored || f.flags.value < texturesCount);
|
||||||
if (type == TYPE_T_UNKNOWN1 || type == TYPE_T_UNKNOWN2) {
|
|
||||||
if (type == TYPE_T_UNKNOWN1)
|
|
||||||
f.flags.value = 0xFFFF;
|
|
||||||
if (type == TYPE_T_UNKNOWN2)
|
|
||||||
f.flags.value = 0xFF80;
|
|
||||||
f.colored = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!f.colored) {
|
if (type == TYPE_R_TRANSP || type == TYPE_R_FLIP_TRANSP || type == TYPE_T_TEX_TRANSP)
|
||||||
ASSERT(f.flags.value % 16 == 0);
|
|
||||||
ASSERT(f.flags.value / 16 < texturesCount);
|
|
||||||
f.flags.value /= 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == TYPE_R_TRANSP || type == TYPE_R_FLIP_TRANSP)
|
|
||||||
textures[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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT(fIndex == mesh.fCount);
|
ASSERT(fIndex == mesh.fCount);
|
||||||
@@ -4736,9 +4798,9 @@ namespace TR {
|
|||||||
Face &f = mesh.faces[idx++];
|
Face &f = mesh.faces[idx++];
|
||||||
f.flags.doubleSided = false;
|
f.flags.doubleSided = false;
|
||||||
f.flags.texture = (info & 0xFF) | (r.tex << 8);
|
f.flags.texture = (info & 0xFF) | (r.tex << 8);
|
||||||
f.colored = false;
|
f.triangle = true;
|
||||||
f.flip = false;
|
f.colored = false;
|
||||||
f.vCount = 3;
|
f.flip = false;
|
||||||
|
|
||||||
f.vertices[0] = r.i0;
|
f.vertices[0] = r.i0;
|
||||||
f.vertices[1] = r.i1;
|
f.vertices[1] = r.i1;
|
||||||
@@ -4756,9 +4818,9 @@ namespace TR {
|
|||||||
Face &f = mesh.faces[idx++];
|
Face &f = mesh.faces[idx++];
|
||||||
f.flags.doubleSided = false;
|
f.flags.doubleSided = false;
|
||||||
f.flags.texture = info & 0xFFFF;
|
f.flags.texture = info & 0xFFFF;
|
||||||
f.colored = false;
|
f.triangle = false;
|
||||||
f.flip = false;
|
f.colored = false;
|
||||||
f.vCount = 4;
|
f.flip = false;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint32 i0:8, i1:8, i2:8, i3:8;
|
uint32 i0:8, i1:8, i2:8, i3:8;
|
||||||
@@ -4780,7 +4842,7 @@ namespace TR {
|
|||||||
|
|
||||||
#define RECALC_ZERO_NORMALS(mesh, face)\
|
#define RECALC_ZERO_NORMALS(mesh, face)\
|
||||||
int fn = -1;\
|
int fn = -1;\
|
||||||
for (int j = 0; j < face.vCount; j++) {\
|
for (int j = 0; j < (face.triangle ? 3 : 4); j++) {\
|
||||||
Mesh::Vertex &v = mesh.vertices[face.vertices[j]];\
|
Mesh::Vertex &v = mesh.vertices[face.vertices[j]];\
|
||||||
short4 &n = v.normal;\
|
short4 &n = v.normal;\
|
||||||
if (!(n.x | n.y | n.z)) {\
|
if (!(n.x | n.y | n.z)) {\
|
||||||
@@ -4857,7 +4919,7 @@ namespace TR {
|
|||||||
t.sub[1] = stream.readBE16();
|
t.sub[1] = stream.readBE16();
|
||||||
t.sub[2] = stream.readBE16();
|
t.sub[2] = stream.readBE16();
|
||||||
t.sub[3] = stream.readBE16();
|
t.sub[3] = stream.readBE16();
|
||||||
d.clut = stream.readBE16() + d.tile; // offset to color palette
|
d.clut = stream.readBE16(); // offset to color palette
|
||||||
d.w = stream.read() * 8;
|
d.w = stream.read() * 8;
|
||||||
d.h = stream.read();
|
d.h = stream.read();
|
||||||
t.i5 = stream.readBE16();
|
t.i5 = stream.readBE16();
|
||||||
@@ -4867,10 +4929,9 @@ namespace TR {
|
|||||||
d.h *= 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);
|
uint16 bi = 0;
|
||||||
|
|
||||||
if (type == TEX_TYPE_ITEM)
|
if (type == TEX_TYPE_ITEM)
|
||||||
stream.seek(2);
|
ASSERTV(stream.readBE16() == t.i5);
|
||||||
|
|
||||||
d.x0 = d.y0 = d.x3 = d.y1 = 0;
|
d.x0 = d.y0 = d.x3 = d.y1 = 0;
|
||||||
d.x1 = d.x2 = max(0, d.w - 1);
|
d.x1 = d.x2 = max(0, d.w - 1);
|
||||||
@@ -4878,6 +4939,10 @@ namespace TR {
|
|||||||
|
|
||||||
SET_PARAMS(t, d, d.clut);
|
SET_PARAMS(t, d, d.clut);
|
||||||
|
|
||||||
|
//if (type == TEX_TYPE_ITEM) {
|
||||||
|
// LOG("%d %d | %d %d %d %d | %d %d %dx%d | %d\n", t.index, t.tile, t.sub[0], t.sub[1], t.sub[2], t.sub[3], t.clut, t.i5, d.w, d.h, bi);
|
||||||
|
//}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VER_TR1_PC :
|
case VER_TR1_PC :
|
||||||
@@ -4958,7 +5023,7 @@ namespace TR {
|
|||||||
int16 l, t, r, b;
|
int16 l, t, r, b;
|
||||||
} d;
|
} d;
|
||||||
d.tile = stream.readBE16(); // offset to 4-bit indices
|
d.tile = stream.readBE16(); // offset to 4-bit indices
|
||||||
d.clut = stream.readBE16(); // offset to 16-bit color table (16 colors)
|
d.clut = stream.readBE16() - d.tile; // offset to 16-bit color table (16 colors)
|
||||||
d.w = stream.read(); // texture width div 8
|
d.w = stream.read(); // texture width div 8
|
||||||
d.h = stream.read(); // texture height
|
d.h = stream.read(); // texture height
|
||||||
d.l = stream.readBE16();
|
d.l = stream.readBE16();
|
||||||
@@ -5111,7 +5176,7 @@ namespace TR {
|
|||||||
switch (version) {
|
switch (version) {
|
||||||
case VER_TR1_SAT : {
|
case VER_TR1_SAT : {
|
||||||
uint32 iOffset = uint32(uint16(t->tile)) << 3;
|
uint32 iOffset = uint32(uint16(t->tile)) << 3;
|
||||||
uint32 cOffset = uint32(uint16(t->clut)) << 3;
|
uint32 cOffset = uint32(uint16(t->clut + t->tile)) << 3;
|
||||||
|
|
||||||
uint8 *data = NULL;
|
uint8 *data = NULL;
|
||||||
switch (t->type) {
|
switch (t->type) {
|
||||||
@@ -5131,10 +5196,13 @@ namespace TR {
|
|||||||
ASSERT(w <= 256 && h <= 256);
|
ASSERT(w <= 256 && h <= 256);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (type == TEX_TYPE_OBJECT && w == 80 && h == 56) {
|
if (t->type == TEX_TYPE_OBJECT) {
|
||||||
for (int y = 0; y < h; y++)
|
for (int y = 0; y < h; y++)
|
||||||
for (int x = 0; x < h; x++)
|
for (int x = 0; x < h; x++) {
|
||||||
dst->color[y * 256 + x] = Color32(255, 0, 255, 255);
|
ColorIndex4 *index = indices + (y * w + x) / 2;
|
||||||
|
uint8 p = uint8((x % 2) ? index->a : index->b) << 4;
|
||||||
|
dst->color[y * 256 + x] = Color32(p, p, p, 255);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
72
src/mesh.h
72
src/mesh.h
@@ -54,7 +54,7 @@ struct Mesh : GAPI::Mesh {
|
|||||||
d.vertices[f.vertices[1]].vertex,\
|
d.vertices[f.vertices[1]].vertex,\
|
||||||
d.vertices[f.vertices[2]].vertex,\
|
d.vertices[f.vertices[2]].vertex,\
|
||||||
d.vertices[f.vertices[3]].vertex);\
|
d.vertices[f.vertices[3]].vertex);\
|
||||||
for (int k = 0; k < f.vCount; k++) {\
|
for (int k = 0; k < (f.triangle ? 3 : 4); k++) {\
|
||||||
TR::Room::Data::Vertex &v = d.vertices[f.vertices[k]];\
|
TR::Room::Data::Vertex &v = d.vertices[f.vertices[k]];\
|
||||||
Vertex &rv = vertices[vCount++];\
|
Vertex &rv = vertices[vCount++];\
|
||||||
rv.coord = short4( v.vertex.x, v.vertex.y, v.vertex.z, 0 );\
|
rv.coord = short4( v.vertex.x, v.vertex.y, v.vertex.z, 0 );\
|
||||||
@@ -721,22 +721,22 @@ struct MeshBuilder {
|
|||||||
f.water = true;
|
f.water = true;
|
||||||
|
|
||||||
room.waterLevel = a.y;
|
room.waterLevel = a.y;
|
||||||
if (f.vCount == 4) {
|
if (f.triangle) {
|
||||||
iCount -= 6;
|
|
||||||
vCount -= 4;
|
|
||||||
} else {
|
|
||||||
iCount -= 3;
|
iCount -= 3;
|
||||||
vCount -= 3;
|
vCount -= 3;
|
||||||
|
} else {
|
||||||
|
iCount -= 6;
|
||||||
|
vCount -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// preserve indices & vertices for water volume
|
// preserve indices & vertices for water volume
|
||||||
if (room.flags.water && Core::settings.detail.water > Core::Settings::MEDIUM) {
|
if (room.flags.water && Core::settings.detail.water > Core::Settings::MEDIUM) {
|
||||||
// water volume caps
|
// water volume caps
|
||||||
iCount += (f.vCount == 4 ? 6 : 3) * 2;
|
iCount += (f.triangle ? 3 : 6) * 2;
|
||||||
vCount += f.vCount * 2;
|
vCount += (f.triangle ? 3 : 4) * 2;
|
||||||
// water volume bounds (reserved)
|
// water volume bounds (reserved)
|
||||||
iCount += 6 * f.vCount;
|
iCount += (f.triangle ? 3 : 4) * 6;
|
||||||
vCount += 4 * f.vCount;
|
vCount += (f.triangle ? 3 : 4) * 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -781,7 +781,7 @@ struct MeshBuilder {
|
|||||||
idx[1] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[1]].vertex);
|
idx[1] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[1]].vertex);
|
||||||
idx[2] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[2]].vertex);
|
idx[2] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[2]].vertex);
|
||||||
|
|
||||||
if (f.vCount > 3) {
|
if (!f.triangle) {
|
||||||
idx[3] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[3]].vertex);
|
idx[3] = addUniqueVertex(wVertices, room.data.vertices[f.vertices[3]].vertex);
|
||||||
|
|
||||||
wIndices.push(idx[0]);
|
wIndices.push(idx[0]);
|
||||||
@@ -983,7 +983,7 @@ struct MeshBuilder {
|
|||||||
mesh.vertices[f.vertices[2]].coord,
|
mesh.vertices[f.vertices[2]].coord,
|
||||||
mesh.vertices[f.vertices[3]].coord);
|
mesh.vertices[f.vertices[3]].coord);
|
||||||
|
|
||||||
for (int k = 0; k < f.vCount; k++) {
|
for (int k = 0; k < (f.triangle ? 3 : 4); k++) {
|
||||||
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
|
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
|
||||||
|
|
||||||
vertices[vCount].coord = transform(v.coord, joint, x, y, z, dir);
|
vertices[vCount].coord = transform(v.coord, joint, x, y, z, dir);
|
||||||
@@ -1000,7 +1000,7 @@ struct MeshBuilder {
|
|||||||
return isOpaque;
|
return isOpaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTexCoord(Vertex *vertices, int vCount, TR::TextureInfo *tex, bool triangle, bool flip) {
|
void addTexCoord(Vertex *vertices, int vCount, TR::TextureInfo *tex, bool triangle, uint8 flip) {
|
||||||
int count = triangle ? 3 : 4;
|
int count = triangle ? 3 : 4;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
Vertex &v = vertices[vCount + i];
|
Vertex &v = vertices[vCount + i];
|
||||||
@@ -1010,13 +1010,43 @@ struct MeshBuilder {
|
|||||||
if (((level->version & TR::VER_PSX)) && !triangle) // TODO: swap vertices instead of rectangle indices and vertices.texCoords (WRONG lighting in TR2!)
|
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);
|
swap(vertices[vCount + 2].texCoord, vertices[vCount + 3].texCoord);
|
||||||
|
|
||||||
if (flip) {
|
if ((level->version & TR::VER_SAT)) {
|
||||||
swap(vertices[vCount + 0].texCoord, vertices[vCount + 1].texCoord);
|
if (triangle) {
|
||||||
swap(vertices[vCount + 2].texCoord, vertices[vCount + 3].texCoord);
|
/* transform Saturn's triangle texCoords by flip code
|
||||||
|
|\
|
||||||
|
flip 2, 6, 8, 12 - |_\
|
||||||
|
_
|
||||||
|
flip 0, 4, 10, 14 - | /
|
||||||
|
|/
|
||||||
|
*/
|
||||||
|
if (flip == 2 || flip == 6 || flip == 8 || flip == 12)
|
||||||
|
vertices[vCount + 1].texCoord = vertices[vCount + 2].texCoord;
|
||||||
|
|
||||||
|
vertices[vCount + 2].texCoord.x = vertices[vCount + 0].texCoord.x;
|
||||||
|
|
||||||
|
if (flip == 10 || flip == 14) // flip diagonal
|
||||||
|
swap(vertices[vCount + 1].texCoord, vertices[vCount + 2].texCoord);
|
||||||
|
|
||||||
|
if (flip == 2 || flip == 6) { // rotate
|
||||||
|
swap(vertices[vCount + 0].texCoord, vertices[vCount + 2].texCoord);
|
||||||
|
swap(vertices[vCount + 2].texCoord, vertices[vCount + 1].texCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flip == 12) // flip vertical
|
||||||
|
swap(vertices[vCount + 0].texCoord, vertices[vCount + 2].texCoord);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (flip) { // flip horizontal
|
||||||
|
swap(vertices[vCount + 0].texCoord, vertices[vCount + 1].texCoord);
|
||||||
|
swap(vertices[vCount + 3].texCoord, vertices[vCount + 2].texCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, bool flip) {
|
void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, uint8 flip) {
|
||||||
int vIndex = vCount - vStart;
|
int vIndex = vCount - vStart;
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
indices[iCount + 0] = vIndex + 0;
|
||||||
@@ -1035,7 +1065,7 @@ struct MeshBuilder {
|
|||||||
if (tex) addTexCoord(vertices, vCount, tex, true, flip);
|
if (tex) addTexCoord(vertices, vCount, tex, true, flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addQuad(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, bool flip) {
|
void addQuad(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, uint8 flip) {
|
||||||
int vIndex = vCount - vStart;
|
int vIndex = vCount - vStart;
|
||||||
|
|
||||||
indices[iCount + 0] = vIndex + 0;
|
indices[iCount + 0] = vIndex + 0;
|
||||||
@@ -1063,7 +1093,7 @@ struct MeshBuilder {
|
|||||||
if (tex) addTexCoord(vertices, vCount, tex, false, flip);
|
if (tex) addTexCoord(vertices, vCount, tex, false, flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addQuad(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, bool flip,
|
void addQuad(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, TR::TextureInfo *tex, bool doubleSided, uint8 flip,
|
||||||
const short3 &c0, const short3 &c1, const short3 &c2, const short3 &c3) {
|
const short3 &c0, const short3 &c1, const short3 &c2, const short3 &c3) {
|
||||||
addQuad(indices, iCount, vCount, vStart, vertices, tex, doubleSided, flip);
|
addQuad(indices, iCount, vCount, vStart, vertices, tex, doubleSided, flip);
|
||||||
|
|
||||||
@@ -1102,10 +1132,10 @@ struct MeshBuilder {
|
|||||||
|
|
||||||
|
|
||||||
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) {
|
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)
|
if (f.triangle)
|
||||||
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, f.flip);
|
addTriangle(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, f.flip);
|
||||||
|
else
|
||||||
|
addQuad(indices, iCount, vCount, vStart, vertices, tex, f.flags.doubleSided, f.flip, a, b, c, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user