diff --git a/src/cache.h b/src/cache.h index 6989dc3..419c0bf 100644 --- a/src/cache.h +++ b/src/cache.h @@ -155,8 +155,6 @@ struct ShaderCache { if (pass == Core::passCompose) { if (fx & FX_CLIP_PLANE) strcat(def, "#define CLIP_PLANE\n"); - if (type == Shader::ROOM) - strcat(def, "#define OPT_ANIMTEX\n"); if (Core::settings.detail.lighting > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM)) strcat(def, "#define OPT_LIGHTING\n"); if (Core::settings.detail.lighting > Core::Settings::MEDIUM && (type == Shader::ENTITY)) @@ -216,9 +214,6 @@ struct ShaderCache { shader->setParam(uLightProj, Core::mLightProj); shader->setParam(uViewPos, Core::viewPos); shader->setParam(uParam, Core::params); - MeshBuilder *mesh = game->getMesh(); - shader->setParam(uAnimTexRanges, mesh->animTexRanges[0], min(mesh->animTexRangesCount, MAX_ANIM_TEX_RANGES)); - shader->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], min(mesh->animTexOffsetsCount, MAX_ANIM_TEX_OFFSETS)); #endif } diff --git a/src/camera.h b/src/camera.h index 2ae2965..607aefd 100644 --- a/src/camera.h +++ b/src/camera.h @@ -406,8 +406,8 @@ struct Camera : ICamera { continue; } - int sx = (int(p.x) - room.info.x) / 1024; - int sz = (int(p.z) - room.info.z) / 1024; + int sx = clamp((int(p.x) - room.info.x) / 1024, 0, room.xSectors - 1); + int sz = clamp((int(p.z) - room.info.z) / 1024, 0, room.zSectors - 1); int boxIndex = room.sectors[sz + sx * room.zSectors].boxIndex; diff --git a/src/core.h b/src/core.h index 4e589fc..ed3970a 100644 --- a/src/core.h +++ b/src/core.h @@ -505,35 +505,20 @@ enum RenderState { typedef uint16 Index; struct Vertex { - short4 coord; // xyz - position, w - joint index (for entities only) - short4 normal; // xyz - vertex normal, w - unused - short4 texCoord; // xy - texture coordinates, zw - trapezoid warping - ubyte4 param; // xy - anim tex range and frame index, zw - unused - ubyte4 color; // for non-textured geometry - ubyte4 light; // xyz - color, w - use premultiplied alpha + short4 coord; // xyz - position, w - joint index (for entities only) + short4 normal; // xyz - vertex normal, w - unused + short4 texCoord; // xy - texture coordinates, zw - trapezoid warping + ubyte4 color; // for non-textured geometry + ubyte4 light; // xyz - color, w - use premultiplied alpha }; -#ifdef FFP - #ifdef _PSP - struct VertexGPU { - short2 texCoord; - ubyte4 color; - short3 normal; - short3 coord; - }; - #else -/* - struct VertexGPU { - short2 texCoord; - ubyte4 color; - short3 normal; - uint16 _alignN; - short3 coord; - uint16 _alignC; - }; -*/ - typedef Vertex VertexGPU; - #endif +#ifdef _PSP + struct VertexGPU { + short2 texCoord; + ubyte4 color; + short3 normal; + short3 coord; + }; #else typedef Vertex VertexGPU; #endif @@ -976,6 +961,7 @@ namespace Core { sceGuDisable(GU_LIGHT3); sceGuAmbientColor(0xFFFFFFFF); sceGuColor(0xFFFFFFFF); + sceGuClearColor(0xffff00ff); freeEDRAM(); #else @@ -996,6 +982,8 @@ namespace Core { glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef(1.0f / 32767.0f, 1.0f / 32767.0f, 1.0f / 32767.0f); + + glClearColor(1, 0, 1, 1); #endif #endif diff --git a/src/format.h b/src/format.h index 47cbd93..493754b 100644 --- a/src/format.h +++ b/src/format.h @@ -1115,7 +1115,7 @@ namespace TR { struct ObjectTexture { uint16 clut; Tile tile; // tile or palette index - uint16 attribute:15, repeat:1; // 0 - opaque, 1 - transparent, 2 - blend additive, + uint16 attribute:15, animated:1; // 0 - opaque, 1 - transparent, 2 - blend additive, animated short2 texCoord[4]; short4 getMinMax() const { @@ -1152,6 +1152,7 @@ namespace TR { } flags; uint8 colored; // !!! not existing in file uint8 vCount; // !!! not existing in file + short3 normal; // !!! not existing in file uint16 vertices[4]; static int cmp(const Face &a, const Face &b) { @@ -1189,7 +1190,7 @@ namespace TR { } }; - #define FACE4_SIZE (sizeof(Face) - sizeof(uint8) - sizeof(uint8)) + #define FACE4_SIZE (sizeof(uint16) + sizeof(uint16) * 4) // flags + vertices[4] #define FACE3_SIZE (FACE4_SIZE - sizeof(uint16)) struct Tile4 { @@ -2307,6 +2308,8 @@ namespace TR { int32 animTexturesDataSize; uint16 *animTexturesData; + int16 animTexturesCount; + AnimTexture **animTextures; int32 entitiesBaseCount; int32 entitiesCount; @@ -2622,45 +2625,15 @@ namespace TR { } stream.read(zones[i].fly, boxesCount); } + // animated textures - stream.read(animTexturesData, stream.read(animTexturesDataSize)); + readAnimTex(stream); + if (version & VER_TR3) readObjectTex(stream); + // entities (enemies, items, lara etc.) - entitiesCount = stream.read(entitiesBaseCount) + MAX_RESERVED_ENTITIES; - entities = new Entity[entitiesCount]; - for (int i = 0; i < entitiesBaseCount; i++) { - Entity &e = entities[i]; - uint16 type; - e.type = Entity::Type(stream.read(type)); - stream.read(e.room); - stream.read(e.x); - stream.read(e.y); - stream.read(e.z); - stream.read(e.rotation); - stream.read(e.intensity); - if (version & (VER_TR2 | VER_TR3)) - stream.read(e.intensity2); - stream.read(e.flags.value); - - 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++) { - TR::Entity &e = entities[i]; - if ((((version & VER_TR1)) && e.isActor()) || - (((version & (VER_TR2 | VER_TR3))) && e.isLara())) { - cutEntity = i; - break; - } - } - } + readEntities(stream); if (version & VER_PC) { stream.seek(32 * 256); @@ -2719,6 +2692,7 @@ namespace TR { } initRoomMeshes(); + initAnimTex(); memset(&state, 0, sizeof(state)); @@ -2770,6 +2744,7 @@ namespace TR { delete[] zones[i].fly; } delete[] animTexturesData; + delete[] animTextures; delete[] entities; delete[] palette; delete[] palette32; @@ -3423,6 +3398,7 @@ namespace TR { t.clut = c;\ t.tile = d.tile;\ t.attribute = d.attribute;\ + t.animated = false;\ t.texCoord[0] = short2( d.x0, d.y0 );\ t.texCoord[1] = short2( d.x1, d.y1 );\ t.texCoord[2] = short2( d.x2, d.y2 );\ @@ -3535,6 +3511,59 @@ namespace TR { } } + void readAnimTex(Stream &stream) { + stream.read(animTexturesData, stream.read(animTexturesDataSize)); + uint16 *ptr = animTexturesData; + animTexturesCount = *ptr++; + if (!animTexturesCount) { + animTextures = NULL; + return; + } + animTextures = new AnimTexture*[animTexturesCount]; + for (int i = 0; i < animTexturesCount; i++) { + animTextures[i] = (AnimTexture*)ptr; + animTextures[i]->count++; // count + 1 + ptr += 1 + animTextures[i]->count; // skip count and texture indices + } + } + + void readEntities(Stream &stream) { + entitiesCount = stream.read(entitiesBaseCount) + MAX_RESERVED_ENTITIES; + entities = new Entity[entitiesCount]; + for (int i = 0; i < entitiesBaseCount; i++) { + Entity &e = entities[i]; + uint16 type; + e.type = Entity::Type(stream.read(type)); + stream.read(e.room); + stream.read(e.x); + stream.read(e.y); + stream.read(e.z); + stream.read(e.rotation); + stream.read(e.intensity); + if (version & (VER_TR2 | VER_TR3)) + stream.read(e.intensity2); + stream.read(e.flags.value); + + 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++) { + TR::Entity &e = entities[i]; + if ((((version & VER_TR1)) && e.isActor()) || + (((version & (VER_TR2 | VER_TR3))) && e.isLara())) { + cutEntity = i; + break; + } + } + } + } + void initRoomMeshes() { for (int i = 0; i < roomsCount; i++) { Room &room = rooms[i]; @@ -3543,6 +3572,22 @@ namespace TR { } } + void initAnimTex() { + for (int i = 0; i < animTexturesCount; i++) + for (int j = 0; j < animTextures[i]->count; j++) + objectTextures[animTextures[i]->textures[j]].animated = true; + } + + void shiftAnimTex() { + for (int i = 0; i < animTexturesCount; i++) { + AnimTexture *at = animTextures[i]; + ObjectTexture tmp = objectTextures[at->textures[0]]; + for (int j = 0; j < at->count - 1; j++) + objectTextures[at->textures[j]] = objectTextures[at->textures[j + 1]]; + objectTextures[at->textures[at->count - 1]] = tmp; + } + } + void initTiles() { tiles = new Tile32[tilesCount]; // convert to RGBA diff --git a/src/level.h b/src/level.h index 883a3a8..284abf1 100644 --- a/src/level.h +++ b/src/level.h @@ -15,6 +15,8 @@ #include "debug.h" #endif +#define ANIM_TEX_TIMESTEP (10.0f / 30.0f) + extern ShaderCache *shaderCache; extern void loadAsync(Stream *stream, void *userData); @@ -52,6 +54,7 @@ struct Level : IGame { float effectTimer; int effectIdx; float cutsceneWaitTimer; + float animTexTimer; Texture *cube360; @@ -587,7 +590,7 @@ struct Level : IGame { } //============================== - Level(Stream &stream) : level(stream), inventory(this), isEnded(false), cutsceneWaitTimer(0.0f) { + Level(Stream &stream) : level(stream), inventory(this), isEnded(false), cutsceneWaitTimer(0.0f), animTexTimer(0.0f) { #ifdef _PSP Core::freeEDRAM(); #endif @@ -1272,7 +1275,7 @@ struct Level : IGame { int roomIndex = roomsList[i]; MeshBuilder::RoomRange &range = mesh->rooms[roomIndex]; - if (!range.geometry[transp].count) { + if (!range.geometry[transp].count && !range.dynamic[transp].count) { i += dir; continue; } @@ -1437,6 +1440,12 @@ struct Level : IGame { sndChanged = NULL; } else { params->time += Core::deltaTime; + animTexTimer += Core::deltaTime; + + if (animTexTimer > ANIM_TEX_TIMESTEP) { + level.shiftAnimTex(); + animTexTimer -= ANIM_TEX_TIMESTEP; + } updateEffect(); diff --git a/src/mesh.h b/src/mesh.h index 14c3d4f..2ccd7a4 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -39,7 +39,6 @@ struct MeshRange { glEnableVertexAttribArray(aCoord); glEnableVertexAttribArray(aNormal); glEnableVertexAttribArray(aTexCoord); - glEnableVertexAttribArray(aParam); glEnableVertexAttribArray(aColor); glEnableVertexAttribArray(aLight); @@ -47,7 +46,6 @@ struct MeshRange { glVertexAttribPointer(aCoord, 4, GL_SHORT, false, sizeof(*v), &v->coord); glVertexAttribPointer(aNormal, 4, GL_SHORT, true, sizeof(*v), &v->normal); glVertexAttribPointer(aTexCoord, 4, GL_SHORT, true, sizeof(*v), &v->texCoord); - glVertexAttribPointer(aParam, 4, GL_UNSIGNED_BYTE, false, sizeof(*v), &v->param); glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, true, sizeof(*v), &v->color); glVertexAttribPointer(aLight, 4, GL_UNSIGNED_BYTE, true, sizeof(*v), &v->light); } @@ -63,7 +61,9 @@ struct MeshRange { #define PLANE_DETAIL 48 #define CIRCLE_SEGS 16 -#define DYN_MESH_QUADS 1024 +#define DYN_MESH_QUADS 1024 +#define DOUBLE_SIDED 2 +#define MAX_ROOM_DYN_FACES 256 struct Mesh { #ifdef _PSP @@ -211,20 +211,36 @@ struct Mesh { vec3 o(mVertices[f.vertices[0]]);\ vec3 a = o - mVertices[f.vertices[1]];\ vec3 b = o - mVertices[f.vertices[2]];\ - o = b.cross(a).normal() * 16300.0f;\ + o = b.cross(a).normal() * 32767.0f;\ n.x = (int)o.x;\ n.y = (int)o.y;\ n.z = (int)o.z;\ }\ -#define CHECK_ROOM_NORMAL(n) \ +#define CHECK_ROOM_NORMAL(f) \ vec3 o(d.vertices[f.vertices[0]].vertex);\ vec3 a = o - d.vertices[f.vertices[1]].vertex;\ vec3 b = o - d.vertices[f.vertices[2]].vertex;\ - o = b.cross(a).normal() * 16300.0f;\ - n.x = (int)o.x;\ - n.y = (int)o.y;\ - n.z = (int)o.z; + o = b.cross(a).normal() * 32767.0f;\ + f.normal.x = (int)o.x;\ + f.normal.y = (int)o.y;\ + f.normal.z = (int)o.z; + +#define ADD_ROOM_FACE(indices, iCount, vCount, vStart, vertices, f, t) \ + addFace(indices, iCount, vCount, vStart, vertices, f, &t,\ + d.vertices[f.vertices[0]].vertex,\ + d.vertices[f.vertices[1]].vertex,\ + d.vertices[f.vertices[2]].vertex,\ + d.vertices[f.vertices[3]].vertex);\ + for (int k = 0; k < f.vCount; k++) {\ + TR::Room::Data::Vertex &v = d.vertices[f.vertices[k]];\ + vertices[vCount].coord = short4( v.vertex.x, v.vertex.y, v.vertex.z, 0 );\ + vertices[vCount].normal = short4( f.normal.x, f.normal.y, f.normal.z, 0 );\ + vertices[vCount].color = ubyte4( 255, 255, 255, 255 );\ + vertices[vCount].light = ubyte4( v.color.r, v.color.g, v.color.b, 255 );\ + vCount++;\ + } + float intensityf(uint16 lighting) { if (lighting > 0x1FFF) return 1.0f; @@ -299,8 +315,14 @@ struct MeshBuilder { } }; + struct Dynamic { + uint16 count; + uint16 *faces; + }; + struct RoomRange { Geometry geometry[3]; // opaque, double-side alpha, additive + Dynamic dynamic[3]; // lists of dynamic polygons (with animated textures) like lava, waterfalls etc. MeshRange sprites; int split; } *rooms; @@ -320,12 +342,6 @@ struct MeshBuilder { MeshRange quad, circle; MeshRange plane; - vec2 *animTexRanges; - vec2 *animTexOffsets; - - int animTexRangesCount; - int animTexOffsetsCount; - int transparent; enum { @@ -342,8 +358,6 @@ struct MeshBuilder { dynMesh->initRange(dynRange); #endif - initAnimTextures(level); - // allocate room geometry ranges rooms = new RoomRange[level.roomsCount]; @@ -372,8 +386,8 @@ struct MeshBuilder { int vStartCount = vCount; - iCount += 2 * (d.rCount * 6 + d.tCount * 3); - vCount += d.rCount * 4 + d.tCount * 3; + iCount += (d.rCount * 6 + d.tCount * 3) * DOUBLE_SIDED; + vCount += (d.rCount * 4 + d.tCount * 3); if (Core::settings.detail.water > Core::Settings::LOW) roomRemoveWaterSurfaces(r, iCount, vCount); @@ -384,8 +398,8 @@ struct MeshBuilder { if (!level.meshOffsets[s->mesh]) continue; TR::Mesh &mesh = level.meshes[level.meshOffsets[s->mesh]]; - iCount += 2 * (mesh.rCount * 6 + mesh.tCount * 3); - vCount += mesh.rCount * 4 + mesh.tCount * 3; + iCount += (mesh.rCount * 6 + mesh.tCount * 3) * DOUBLE_SIDED; + vCount += (mesh.rCount * 4 + mesh.tCount * 3); } #ifdef MERGE_SPRITES @@ -409,8 +423,8 @@ struct MeshBuilder { if (!index && model.mStart + j > 0) continue; TR::Mesh &mesh = level.meshes[index]; - iCount += 2 * (mesh.rCount * 6 + mesh.tCount * 3); - vCount += mesh.rCount * 4 + mesh.tCount * 3; + iCount += (mesh.rCount * 6 + mesh.tCount * 3) * DOUBLE_SIDED; + vCount += (mesh.rCount * 4 + mesh.tCount * 3); } } @@ -429,7 +443,7 @@ struct MeshBuilder { vCount += 8 * 2 + 1; // quad (post effect filter) - iCount += 2 * 3; + iCount += 6; vCount += 4; // circle @@ -438,8 +452,8 @@ struct MeshBuilder { // detailed plane #ifdef GENERATE_WATER_PLANE - iCount += PLANE_DETAIL * 2 * PLANE_DETAIL * 2 * (2 * 3); - vCount += (PLANE_DETAIL * 2 + 1) * (PLANE_DETAIL * 2 + 1); + iCount += SQR(PLANE_DETAIL * 2) * 6; + vCount += SQR(PLANE_DETAIL * 2 + 1); #endif // make meshes buffer (single vertex buffer object for all geometry & sprites on level) @@ -468,7 +482,7 @@ struct MeshBuilder { Geometry &geom = range.geometry[transp]; // rooms geometry - buildRoom(geom, blendMask, room, level, indices, vertices, iCount, vCount, vStartRoom); + buildRoom(geom, range.dynamic[transp], blendMask, room, level, indices, vertices, iCount, vCount, vStartRoom); // static meshes for (int j = 0; j < room.meshesCount; j++) { @@ -588,7 +602,7 @@ struct MeshBuilder { Vertex &v0 = vertices[vCount + i * 2 + 0]; v0.normal = short4( 0, -1, 0, 32767 ); v0.texCoord = short4( whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 ); - v0.param = v0.color = v0.light = ubyte4( 0, 0, 0, 0 ); + v0.color = v0.light = ubyte4( 0, 0, 0, 0 ); if (i == 8) { v0.coord = short4( 0, 0, 0, 0 ); @@ -607,7 +621,6 @@ struct MeshBuilder { Vertex &v1 = vertices[vCount + i * 2 + 1]; v1 = v0; v1.coord = short4( c1, 0, s1, 0 ); - v0.param = ubyte4( 0, 0, 0, 0 ); v1.color = v1.light = ubyte4( 255, 255, 255, 0 ); int idx = iCount + i * 3 * 3; @@ -641,20 +654,13 @@ struct MeshBuilder { vertices[vCount + 3].texCoord = short4( 0, 0, 0, 0 ); vertices[vCount + 2].texCoord = short4( 32767, 0, 0, 0 ); vertices[vCount + 1].texCoord = short4( 32767, 32767, 0, 0 ); - vertices[vCount + 0].texCoord = short4( 0, 0, 0, 0 ); - vertices[vCount + 3].light = - vertices[vCount + 2].light = - vertices[vCount + 1].light = - vertices[vCount + 0].light = vertices[vCount + 3].color = ubyte4(255, 255, 255, 255); - + vertices[vCount + 0].texCoord = short4( 0, 32767, 0, 0 ); for (int i = 0; i < 4; i++) { Vertex &v = vertices[vCount + i]; - v.normal = short4( 0, 0, 0, 32767 ); - v.texCoord = short4( whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 ); - v.param = ubyte4( 0, 0, 0, 0 ); - v.color = ubyte4( 255, 255, 255, 255 ); - v.light = ubyte4( 255, 255, 255, 255 ); + v.normal = short4( 0, 0, 0, 0 ); + v.color = ubyte4( 255, 255, 255, 255 ); + v.light = ubyte4( 255, 255, 255, 255 ); } vCount += 4; @@ -673,7 +679,6 @@ struct MeshBuilder { v.coord = short4( short(pos.x), short(pos.y), 0, 0 ); v.normal = short4( 0, 0, 0, 32767 ); v.texCoord = short4( whiteTile.texCoord[0].x, whiteTile.texCoord[0].y, 32767, 32767 ); - v.param = ubyte4( 0, 0, 0, 0 ); v.color = ubyte4( 255, 255, 255, 255 ); v.light = ubyte4( 255, 255, 255, 255 ); @@ -769,8 +774,10 @@ struct MeshBuilder { } ~MeshBuilder() { - delete[] animTexRanges; - delete[] animTexOffsets; + for (int i = 0; i < level->roomsCount; i++) + for (int j = 0; j < COUNT(rooms[i].dynamic); j++) + delete[] rooms[i].dynamic[j].faces; + delete[] rooms; delete[] models; delete[] sequences; @@ -857,46 +864,57 @@ struct MeshBuilder { return 1 << texAttribute; } - void buildRoom(Geometry &geom, int blendMask, const TR::Room &room, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) { + void buildRoom(Geometry &geom, Dynamic &dyn, int blendMask, const TR::Room &room, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) { const TR::Room::Data &d = room.data; + dyn.count = 0; + dyn.faces = NULL; + for (int j = 0; j < d.fCount; j++) { TR::Face &f = d.faces[j]; TR::ObjectTexture &t = level.objectTextures[f.flags.texture]; if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes) + CHECK_ROOM_NORMAL(f); + if (!(blendMask & getBlendMask(t.attribute))) continue; + if (t.animated) { + ASSERT(dyn.count < 0xFFFF); + dyn.count++; + continue; + } + if (!geom.validForTile(t.tile.index, t.clut)) geom.getNextRange(vStart, iCount, t.tile.index, t.clut); - addFace(indices, iCount, vCount, vStart, vertices, f, &t, - d.vertices[f.vertices[0]].vertex, - d.vertices[f.vertices[1]].vertex, - d.vertices[f.vertices[2]].vertex, - d.vertices[f.vertices[3]].vertex); + ADD_ROOM_FACE(indices, iCount, vCount, vStart, vertices, f, t); + } - TR::Vertex n; - CHECK_ROOM_NORMAL(n); + // if room has non-static polygons, fill the list of dynamic faces + if (dyn.count) { - for (int k = 0; k < f.vCount; k++) { - TR::Room::Data::Vertex &v = d.vertices[f.vertices[k]]; - vertices[vCount].coord = short4( v.vertex.x, v.vertex.y, v.vertex.z, 0 ); - vertices[vCount].normal = short4( n.x, n.y, n.z, int16(t.attribute == 2 ? 0 : 32767) ); - vertices[vCount].color = ubyte4( 255, 255, 255, 255 ); - TR::Color32 c = v.color; - /* - #ifdef FFP - if (room.flags.water) { - vertices[vCount].light = ubyte4( int(c.r * 0.6f), int(c.g * 0.9), int(c.b * 0.9), 255 ); // apply underwater color - } else - vertices[vCount].light = ubyte4( c.r, c.g, c.b, 255 ); - #endif - */ - vertices[vCount].light = ubyte4( c.r, c.g, c.b, 255 ); - vCount++; + if (dyn.count > MAX_ROOM_DYN_FACES) { + LOG("! %d > MAX_ROOM_DYN_FACES\n", int(dyn.count)); + dyn.count = MAX_ROOM_DYN_FACES; + ASSERT(false); + } + + 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]; + + if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes) + + if (!(blendMask & getBlendMask(t.attribute))) + continue; + + if (t.animated) + dyn.faces[dyn.count++] = j; } } } @@ -942,76 +960,11 @@ struct MeshBuilder { return isOpaque; } - vec2 getTexCoord(const TR::ObjectTexture &tex) { - return vec2(tex.texCoord[0].x / 32767.0f, tex.texCoord[0].y / 32767.0f); - } - - void initAnimTextures(TR::Level &level) { - ASSERT(level.animTexturesDataSize); - - uint16 *ptr = &level.animTexturesData[0]; - animTexRangesCount = *ptr++ + 1; - animTexRanges = new vec2[animTexRangesCount]; - animTexRanges[0] = vec2(0.0f, 1.0f); - animTexOffsetsCount = 1; - for (int i = 1; i < animTexRangesCount; i++) { - TR::AnimTexture *animTex = (TR::AnimTexture*)ptr; - - int start = animTexOffsetsCount; - animTexOffsetsCount += animTex->count + 1; - animTexRanges[i] = vec2((float)start, (float)(animTexOffsetsCount - start)); - - ptr += (sizeof(animTex->count) + sizeof(animTex->textures[0]) * (animTex->count + 1)) / sizeof(uint16); - } - animTexOffsets = new vec2[animTexOffsetsCount]; - animTexOffsets[0] = vec2(0.0f); - animTexOffsetsCount = 1; - - ptr = &level.animTexturesData[1]; - for (int i = 1; i < animTexRangesCount; i++) { - TR::AnimTexture *animTex = (TR::AnimTexture*)ptr; - - vec2 first = getTexCoord(level.objectTextures[animTex->textures[0]]); - animTexOffsets[animTexOffsetsCount++] = vec2(0.0f); // first - first for first frame %) - - for (int j = 1; j <= animTex->count; j++) - animTexOffsets[animTexOffsetsCount++] = getTexCoord(level.objectTextures[animTex->textures[j]]) - first; - - ptr += (sizeof(animTex->count) + sizeof(animTex->textures[0]) * (animTex->count + 1)) / sizeof(uint16); - } - } - - TR::ObjectTexture* getAnimTexture(TR::ObjectTexture *tex, uint8 &range, uint8 &frame) { - range = frame = 0; - if (!level->animTexturesDataSize) - return tex; - - uint16 *ptr = &level->animTexturesData[1]; - for (int i = 1; i < animTexRangesCount; i++) { - TR::AnimTexture *animTex = (TR::AnimTexture*)ptr; - - for (int j = 0; j <= animTex->count; j++) - if (tex == &level->objectTextures[animTex->textures[j]]) { - range = i; - frame = j; - return &level->objectTextures[animTex->textures[0]]; - } - - ptr += (sizeof(animTex->count) + sizeof(animTex->textures[0]) * (animTex->count + 1)) / sizeof(uint16); - } - - return tex; - } - void addTexCoord(Vertex *vertices, int vCount, TR::ObjectTexture *tex, bool triangle) { - uint8 range, frame; - tex = getAnimTexture(tex, range, frame); - int count = triangle ? 3 : 4; for (int i = 0; i < count; i++) { Vertex &v = vertices[vCount + i]; v.texCoord = short4( tex->texCoord[i].x, tex->texCoord[i].y, 32767, 32767 ); - v.param = ubyte4( range, frame, 0, 0 ); } if (((level->version & TR::VER_PSX)) && !triangle) // TODO: swap vertices instead of rectangle indices and vertices.texCoords (WRONG lighting in TR2!) @@ -1157,7 +1110,6 @@ struct MeshBuilder { quad[2].color = quad[3].color = ubyte4( 255, 255, 255, 255 ); quad[0].light = quad[1].light = ubyte4( tColor.r, tColor.g, tColor.b, tColor.a ); quad[2].light = quad[3].light = ubyte4( bColor.r, bColor.g, bColor.b, bColor.a ); - quad[0].param = quad[1].param = quad[2].param = quad[3].param = ubyte4( 0, 0, 0, 0 ); quad[0].texCoord = short4( sprite.texCoord[0].x, sprite.texCoord[0].y, sprite.l, -sprite.t ); quad[1].texCoord = short4( sprite.texCoord[1].x, sprite.texCoord[0].y, sprite.r, -sprite.t ); @@ -1191,7 +1143,6 @@ struct MeshBuilder { short2 uv = tile.texCoord[i]; v.texCoord = short4( uv.x, uv.y, 32767, 32767 ); - v.param = ubyte4( 0, 0, 0, 0 ); } vCount += 4; @@ -1251,6 +1202,9 @@ struct MeshBuilder { } void renderBuffer(Index *indices, int iCount, Vertex *vertices, int vCount) { + if (!iCount) return; + ASSERT(vCount > 0); + #ifdef _PSP MeshRange dynRange; Mesh cmdBufMesh(iCount, vCount); @@ -1275,6 +1229,51 @@ struct MeshBuilder { mesh->render(range); } + + Dynamic &dyn = rooms[roomIndex].dynamic[transparent]; + if (dyn.count) { + #ifdef SPLIT_BY_TILE + uint16 tile = 0xFFFF, clut = 0xFFFF; + #endif + int iCount = 0, vCount = 0, vStart = 0; + Index indices[MAX_ROOM_DYN_FACES * 6 * DOUBLE_SIDED]; + Vertex vertices[MAX_ROOM_DYN_FACES * 4]; + + 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]; + + #ifdef SPLIT_BY_TILE + if (iCount) { + if (tile != t.tile.index + #ifdef SPLIT_BY_CLUT + || clut != t.clut + #endif + ) { + atlas->bind(tile, clut); + renderBuffer(indices, iCount, vertices, vCount); + tile = t.tile.index; + clut = t.clut; + iCount = 0; + vCount = 0; + } + } else { + tile = t.tile.index; + clut = t.clut; + } + #endif + + ADD_ROOM_FACE(indices, iCount, vCount, vStart, vertices, f, t); + } + + if (iCount) { + #ifdef SPLIT_BY_TILE + atlas->bind(tile, clut); + #endif + renderBuffer(indices, iCount, vertices, vCount); + } + } } void renderRoomSprites(int roomIndex) { diff --git a/src/shader.h b/src/shader.h index c4d5db4..eaf2acb 100644 --- a/src/shader.h +++ b/src/shader.h @@ -7,7 +7,6 @@ E( aCoord ) \ E( aNormal ) \ E( aTexCoord ) \ - E( aParam ) \ E( aColor ) \ E( aLight ) @@ -84,7 +83,7 @@ struct Shader { } ID = glCreateProgram(); - + if (!(Core::support.shaderBinary && linkBinary(fileName))) // try to load cached shader if (linkSource(source, defines) && Core::support.shaderBinary) { // compile shader from source and dump it into cache #ifndef __EMSCRIPTEN__ @@ -202,51 +201,32 @@ struct Shader { return false; } - inline bool checkParam(UniformType uType, const void *value, int size) { - return true; - /* - if (size > sizeof(vec4) * 4) return true; - if (memcmp(¶ms[uType], value, size) != 0) { - memcpy(¶ms[uType], value, size); - return true; - } - return false; - */ - } - void setParam(UniformType uType, const int &value, int count = 1) { - if (uID[uType] != -1) - glUniform1iv(uID[uType], count, (GLint*)&value); + if (uID[uType] != -1) glUniform1iv(uID[uType], count, (GLint*)&value); } void setParam(UniformType uType, const float &value, int count = 1) { - if (uID[uType] != -1 && checkParam(uType, &value, sizeof(value) * count)) - glUniform1fv(uID[uType], count, (GLfloat*)&value); + if (uID[uType] != -1) glUniform1fv(uID[uType], count, (GLfloat*)&value); } void setParam(UniformType uType, const vec2 &value, int count = 1) { - if (uID[uType] != -1 && checkParam(uType, &value, sizeof(value) * count)) - glUniform2fv(uID[uType], count, (GLfloat*)&value); + if (uID[uType] != -1) glUniform2fv(uID[uType], count, (GLfloat*)&value); } void setParam(UniformType uType, const vec3 &value, int count = 1) { - if (uID[uType] != -1 && checkParam(uType, &value, sizeof(value) * count)) - glUniform3fv(uID[uType], count, (GLfloat*)&value); + if (uID[uType] != -1) glUniform3fv(uID[uType], count, (GLfloat*)&value); } void setParam(UniformType uType, const vec4 &value, int count = 1) { - if (uID[uType] != -1 && checkParam(uType, &value, sizeof(value) * count)) - glUniform4fv(uID[uType], count, (GLfloat*)&value); + if (uID[uType] != -1) glUniform4fv(uID[uType], count, (GLfloat*)&value); } void setParam(UniformType uType, const mat4 &value, int count = 1) { - if (uID[uType] != -1 && checkParam(uType, &value, sizeof(value) * count)) - glUniformMatrix4fv(uID[uType], count, false, (GLfloat*)&value); + if (uID[uType] != -1) glUniformMatrix4fv(uID[uType], count, false, (GLfloat*)&value); } void setParam(UniformType uType, const Basis &value, int count = 1) { - if (uID[uType] != -1 && checkParam(uType, &value, sizeof(value) * count)) - glUniform4fv(uID[uType], count * 2, (GLfloat*)&value); + if (uID[uType] != -1) glUniform4fv(uID[uType], count * 2, (GLfloat*)&value); } #endif }; diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index 73fafb1..f03a2a0 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -63,15 +63,9 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha sqr.z * mix(uAmbient[5], uAmbient[4], pos.z); } #endif - - #ifdef OPT_ANIMTEX - uniform vec2 uAnimTexRanges[MAX_RANGES]; - uniform vec2 uAnimTexOffsets[MAX_OFFSETS]; - #endif attribute vec4 aCoord; attribute vec4 aTexCoord; - attribute vec4 aParam; attribute vec4 aNormal; #ifndef PASS_SHADOW @@ -230,13 +224,6 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha void _uv(vec3 coord) { vTexCoord = aTexCoord; #if defined(PASS_COMPOSE) && !defined(TYPE_SPRITE) - #ifdef OPT_ANIMTEX - // animated texture coordinates - vec2 range = uAnimTexRanges[int(aParam.x)]; // x - start index, y - count - float frame = fract((aParam.y + uParam.x * 4.0 - range.x) / range.y) * range.y; - vec2 offset = uAnimTexOffsets[int(range.x + frame)]; // texCoord offset from first frame - vTexCoord.xy += offset; - #endif vTexCoord.xy *= vTexCoord.zw; #endif diff --git a/src/texture.h b/src/texture.h index c80612e..a515eaa 100644 --- a/src/texture.h +++ b/src/texture.h @@ -126,7 +126,8 @@ struct Texture { this->format = format; #ifdef _PSP - memory = NULL;//new uint8[width * height * 2]; + memory = new uint8[width * height * 4]; + memcpy(memory, data, width * height * 4); #else glGenTextures(1, &ID); bind(0); @@ -262,11 +263,19 @@ struct Texture { void bind(int sampler) { #ifdef _PSP - if (this && !sampler && memory) + if (this && !sampler && memory) { + int swizzle = GU_FALSE; + #ifdef TEX_SWIZZLE + swizzle = GU_TRUE; + #endif + + sceGuTexMode(GU_PSM_8888, 0, 0, GU_FALSE); sceGuTexImage(0, width, height, width, memory); + sceGuTexMode(GU_PSM_T4, 0, 0, swizzle); + } #else #ifdef SPLIT_BY_TILE - if (sampler || !ID) return; + if (!this || sampler || !ID) return; #endif if (Core::active.textures[sampler] != this) { diff --git a/src/trigger.h b/src/trigger.h index d9e2321..9936161 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -1031,7 +1031,6 @@ struct Lightning : Controller { v.coord = toCoord(coord, joint); v.normal = short4( 0, -1, 0, 0 ); v.texCoord = short4( barTile[0].texCoord[idx].x, barTile[0].texCoord[idx].y, 32767, 32767 ); - v.param = ubyte4( 0, 0, 0, 0 ); v.color = ubyte4( 255, 255, 255, 255 ); }