1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-04-22 03:51:58 +02:00

#14 Rats AI; #23 flipmap and water surfaces rework, fix rooms visibility in cutscenes, fix water reflection for additive blended geometry

This commit is contained in:
XProger 2018-03-10 04:19:31 +03:00
parent a89e3f8beb
commit 1c0fde576d
12 changed files with 419 additions and 109 deletions

View File

@ -22,19 +22,42 @@ struct Animation {
Animation() : overrides(NULL) {}
Animation(TR::Level *level, const TR::Model *model) : level(level), model(model), anims(model ? &level->anims[model->animation] : NULL), time(0), delta(0), dir(1.0f),
index(-1), prev(0), next(0), overrides(NULL), overrideMask(0) {
if (anims) setAnim(0);
Animation(TR::Level *level, const TR::Model *model) : level(level), overrides(NULL), overrideMask(0) {
setModel(model);
}
~Animation() {
delete[] overrides;
}
void setModel(const TR::Model *model) {
if (this->model == model)
return;
this->model = model;
anims = model ? &level->anims[model->animation] : NULL;
time = 0;
delta = 0;
dir = 1.0f;
index = -1;
prev = 0;
next = 0;
overrideMask = 0;
if (overrides) {
delete[] overrides;
overrides = NULL;
initOverrides();
}
if (anims) setAnim(0);
}
inline operator TR::Animation* () const { return anims + index; }
void initOverrides() {
ASSERT(model);
ASSERT(!overrides)
overrides = new quat[model->mCount];
overrideMask = 0;
}
@ -79,6 +102,10 @@ struct Animation {
return (TR::AnimFrame*)&level->frameData[anim->frameOffset / 2 + index * frameSize]; // >> 1 (div 2) because frameData is array of shorts
}
void goEnd(bool lerpToNext = true) {
setAnim(index, -(framesCount - 1), lerpToNext);
}
void updateInfo() {
ASSERT(model);
ASSERT(anims);

View File

@ -230,7 +230,7 @@ struct AmbientCache {
enum int32 {
BLANK, WAIT, READY
} status;
vec3 colors[6];
vec3 colors[6]; // TODO: ubyte4[6]
} *items;
int *offsets;
@ -251,7 +251,7 @@ struct AmbientCache {
for (int i = 0; i < level->roomsCount; i++) {
TR::Room &r = level->rooms[i];
offsets[i] = sectors;
sectors += r.xSectors * r.zSectors;
sectors += r.xSectors * r.zSectors * (r.alternateRoom > -1 ? 2 : 1); // x2 for flipped rooms
}
// init cache buffer
items = new Cube[sectors];
@ -270,11 +270,11 @@ struct AmbientCache {
}
void addTask(int room, int sector) {
if (tasksCount >= 32) return;
if (tasksCount >= COUNT(tasks)) return;
Task &task = tasks[tasksCount++];
task.room = room;
task.flip = level->state.flags.flipped;
task.flip = level->state.flags.flipped && level->rooms[room].alternateRoom > -1;
task.sector = sector;
task.cube = &items[offsets[room] + sector];
task.cube->status = Cube::WAIT;
@ -326,20 +326,33 @@ struct AmbientCache {
for (int i = 0; i < tasksCount; i++) {
Task &task = tasks[i];
bool oldFlip = level->state.flags.flipped;
level->state.flags.flipped = task.flip != 0;
renderAmbient(task.room, task.sector, &task.cube->colors[0]);
level->state.flags.flipped = oldFlip;
bool needFlip = task.flip != level->state.flags.flipped;
if (needFlip) game->flipMap();
int sector = task.sector;
if (task.flip) {
TR::Room &r = level->rooms[task.room];
sector -= r.xSectors * r.zSectors;
}
renderAmbient(task.room, sector, &task.cube->colors[0]);
if (needFlip) game->flipMap();
task.cube->status = Cube::READY;
}
tasksCount = 0;
}
Cube* getAmbient(int room, int sector) {
Cube *cube = &items[offsets[room] + sector];
Cube* getAmbient(int roomIndex, int sector) {
TR::Room &r = level->rooms[roomIndex];
if (level->state.flags.flipped && r.alternateRoom > -1)
sector += r.xSectors * r.zSectors;
Cube *cube = &items[offsets[roomIndex] + sector];
if (cube->status == Cube::BLANK)
addTask(room, sector);
addTask(roomIndex, sector);
return cube->status == Cube::READY ? cube : NULL;
}
@ -373,6 +386,8 @@ struct WaterCache {
struct Item {
int from, to, caust;
float timer;
float waterLevel;
bool flip;
bool visible;
bool blank;
vec3 pos, size;
@ -395,8 +410,16 @@ struct WaterCache {
TR::Level *level = game->getLevel();
TR::Room &r = level->rooms[to]; // underwater room
ASSERT(r.flags.water);
int minX = r.xSectors, minZ = r.zSectors, maxX = 0, maxZ = 0, posY = level->rooms[to].waterLevel, caustY = posY;
int minX = r.xSectors, minZ = r.zSectors, maxX = 0, maxZ = 0;
int posY = level->rooms[to].waterLevel;
if (posY == -1)
posY = level->rooms[from].waterLevel;
ASSERT(posY != -1); // underwater room without reaching the surface
int caustY = posY;
for (int z = 0; z < r.zSectors; z++)
for (int x = 0; x < r.xSectors; x++) {
TR::Room::Sector &s = r.sectors[x * r.zSectors + z];
@ -411,8 +434,6 @@ struct WaterCache {
if (floor > caustY) {
caustY = floor;
caust = caustRoom;
if (level->state.flags.flipped && level->rooms[caust].alternateRoom > -1)
caust = level->rooms[caust].alternateRoom;
}
}
}
@ -516,6 +537,20 @@ struct WaterCache {
visible = 0;
}
void flipMap() {
for (int i = 0; i < level->roomsCount && count; i++)
if (level->rooms[i].alternateRoom > -1) {
int j = 0;
while (j < count) {
if (items[j].from == i || items[j].to == i) {
items[j].deinit();
items[j] = items[--count];
} else
j++;
}
}
}
void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) {
if (nextRoom == TR::NO_ROOM) { // setVisible(underwaterRoom) for caustics update
for (int i = 0; i < count; i++)
@ -539,6 +574,9 @@ struct WaterCache {
to = nextRoom;
}
if (level->rooms[to].waterLevel == -1 && level->rooms[from].waterLevel == -1) // not have water surface
return;
for (int i = 0; i < count; i++) {
Item &item = items[i];
if (item.from == from && item.to == to) {
@ -735,6 +773,11 @@ struct WaterCache {
item.init(game);
}
if (!count) {
visible = false;
return;
}
// render mirror reflection
Core::setTarget(reflect, CLEAR_ALL);
Camera *camera = (Camera*)game->getCamera();
@ -754,7 +797,7 @@ struct WaterCache {
vec4 reflectPlane = vec4(n.x, n.y, n.z, -n.dot(p));
bool underwater = level->rooms[camera->getRoomIndex()].flags.water;
//bool underwater = level->camera->pos.y > item.pos.y;
//bool underwater = camera->eye.pos.y > item.pos.y;
camera->reflectPlane = &reflectPlane;
camera->setup(true);

View File

@ -65,43 +65,7 @@ struct Camera : ICamera {
}
virtual int getRoomIndex() const {
return (level->state.flags.flipped && level->rooms[eye.room].alternateRoom > -1) ? level->rooms[eye.room].alternateRoom : eye.room;
}
virtual void checkRoom() {
// level->getSector(eye.room, eye.pos);
// return;
if (mode == MODE_CUTSCENE) {
for (int i = 0; i < level->roomsCount; i++)
if (owner->insideRoom(eye.pos, i)) {
eye.room = i;
break;
}
return;
}
TR::Level::FloorInfo info;
owner->getFloorInfo(getRoomIndex(), eye.pos, info);
if (info.roomNext != TR::NO_ROOM)
eye.room = info.roomNext;
if (eye.pos.y < info.roomCeiling) {
if (info.roomAbove != TR::NO_ROOM)
eye.room = info.roomAbove;
else
if (info.roomCeiling != 0xffff8100)
eye.pos.y = (float)info.roomCeiling;
}
if (eye.pos.y > info.roomFloor) {
if (info.roomBelow != TR::NO_ROOM)
eye.room = info.roomBelow;
else
if (info.roomFloor != 0xffff8100)
eye.pos.y = (float)info.roomFloor;
}
return eye.room;
}
void updateListener() {
@ -387,7 +351,7 @@ struct Camera : ICamera {
} else
updateFirstPerson();
checkRoom();
level->getSector(eye.room, eye.pos);
} else {
Controller *lookAt = NULL;

View File

@ -126,8 +126,6 @@ struct Character : Controller {
if (info.roomAbove != TR::NO_ROOM && pos.y <= info.roomCeiling) {
TR::Room *room = &level->rooms[info.roomAbove];
if (level->state.flags.flipped && room->alternateRoom > -1)
room = &level->rooms[room->alternateRoom];
if (stand == STAND_UNDERWATER && !room->flags.water) {
stand = STAND_ONWATER;

View File

@ -64,6 +64,7 @@ struct IGame {
virtual bool isCutscene() { return false; }
virtual uint16 getRandomBox(uint16 zone, uint16 *zones) { return 0; }
virtual uint16 findPath(int ascend, int descend, bool big, int boxStart, int boxEnd, uint16 *zones, uint16 **boxes) { return 0; }
virtual void flipMap() {}
virtual void setClipParams(float clipSign, float clipHeight) {}
virtual void setWaterParams(float height) {}
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
@ -124,6 +125,7 @@ struct Controller {
TR::Room::Light *targetLight;
vec3 mainLightPos;
vec4 mainLightColor;
bool mainLightFlip;
struct MeshLayer {
uint32 model;
@ -153,9 +155,6 @@ struct Controller {
joints = m ? new Basis[m->mCount] : NULL;
jointsFrame = -1;
if (level->isCutsceneLevel())
fixRoomIndex();
specular = 0.0f;
intensity = e.intensity == -1 ? -1.0f : intensityf(e.intensity);
timer = 0.0f;
@ -186,8 +185,10 @@ struct Controller {
deactivate(true);
}
bool fixRoomIndex() {
bool fixRoomIndex() { // TODO: remove this and fix braid
vec3 p = getPos();
if (insideRoom(p, roomIndex))
return true;
for (int i = 0; i < level->roomsCount; i++)
if (insideRoom(p, i)) {
roomIndex = i;
@ -619,7 +620,7 @@ struct Controller {
pos.z >= min.z && pos.z <= max.z;
}
const TR::Model* getModel() const {
virtual const TR::Model* getModel() {
int index = getEntity().modelIndex;
return index > 0 ? &level->models[index - 1] : NULL;
}
@ -635,10 +636,7 @@ struct Controller {
}
virtual int getRoomIndex() const {
int index = roomIndex;
if (level->state.flags.flipped && level->rooms[index].alternateRoom > -1)
index = level->rooms[index].alternateRoom;
return index;
return roomIndex;
}
virtual vec3 getPos() {
@ -1002,7 +1000,7 @@ struct Controller {
case TR::Effect::ROTATE_180 : angle.y = angle.y + PI; break;
case TR::Effect::FLOOR_SHAKE : game->setEffect(this, TR::Effect::Type(fx)); break;
case TR::Effect::FINISH_LEVEL : game->loadNextLevel(); break;
case TR::Effect::FLIP_MAP : level->state.flags.flipped = !level->state.flags.flipped; break;
case TR::Effect::FLIP_MAP : game->flipMap(); break;
default : cmdEffect(fx); break;
}
} else {
@ -1131,6 +1129,12 @@ struct Controller {
vec3 tpos = vec3(float(targetLight->x), float(targetLight->y), float(targetLight->z));
vec4 tcolor = vec4(vec3(targetLight->color.r, targetLight->color.g, targetLight->color.b) * (1.0f / 255.0f), float(targetLight->radius));
if (mainLightFlip != level->state.flags.flipped) {
if (getRoom().alternateRoom > -1)
lerp = false;
mainLightFlip = level->state.flags.flipped;
}
if (lerp) {
float t = Core::deltaTime * 2.0f;
mainLightPos = mainLightPos.lerp(tpos, t);

View File

@ -481,9 +481,9 @@ namespace Debug {
for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &e = level.entities[i];
Controller *controller = (Controller*)e.controller;
if (!controller || controller->flags.invisible) return;
if (!controller) continue;
sprintf(buf, "%s (%d)", getEntityName(level, e), i);
sprintf(buf, "%s (%d) %s", getEntityName(level, e), i, controller->flags.invisible ? "INVISIBLE" : "");
Debug::Draw::text(controller->getPos() + randf() * 64, controller->flags.active ? vec4(0, 0, 0.8f, 1) : vec4(0.8f, 0, 0, 1), buf);
}

View File

@ -745,9 +745,188 @@ struct Lion : Enemy {
}
};
#define RAT_TURN_SLOW (DEG2RAD * 90)
#define RAT_TURN_FAST (DEG2RAD * 180)
#define RAT_DIST_BITE 341.0f
#define RAT_DIST_ATTACK 1536.0f
#define RAT_WAIT 0.01f
#define RAT_DAMAGE 20
struct Rat : Enemy {
Rat(IGame *game, int entity) : Enemy(game, entity, 6, 341, 375.0f, 0.25f) {
hitSound = TR::SND_HIT_RAT;
enum {
HIT_MASK = 0x300018F,
};
enum {
ANIM_GROUND_DEATH = 8,
ANIM_WATER_DEATH = 2,
};
enum {
STATE_NONE ,
STATE_STOP ,
STATE_ATTACK ,
STATE_RUN ,
STATE_BITE ,
STATE_DEATH ,
STATE_WAIT ,
STATE_WATER_SWIM = 1,
STATE_WATER_ATTACK ,
STATE_WATER_DEATH ,
};
int modelLand, modelWater;
Rat(IGame *game, int entity) : Enemy(game, entity, 5, 204, 200.0f, 0.25f) {
hitSound = TR::SND_HIT_RAT;
jointChest = 1;
jointHead = 2;
modelLand = level->getModelIndex(TR::Entity::ENEMY_RAT_LAND) - 1;
modelWater = level->getModelIndex(TR::Entity::ENEMY_RAT_WATER) - 1;
}
const virtual TR::Model* getModel() {
bool water = getRoom().flags.water;
int modelIndex = water ? modelWater : modelLand;
ASSERT(modelIndex > -1);
const TR::Model *model = &level->models[modelIndex];
if (animation.model != model) {
targetBox = -1;
animation.setModel(model);
stand = water ? STAND_ONWATER : STAND_GROUND;
int16 rIndex = getRoomIndex();
if (water) {
TR::Room::Sector *sector = level->getWaterLevelSector(rIndex, pos);
if (sector) {
pos.y = float(sector->ceiling * 256);
roomIndex = rIndex;
}
} else {
int16 rIndex = getRoomIndex();
TR::Room::Sector *sector = level->getSector(rIndex, pos);
if (sector) {
pos.y = float(sector->floor * 256);
roomIndex = rIndex;
}
}
nextState = STATE_NONE;
state = STATE_NONE;
if (health <= 0.0f) {
getStateDeath();
animation.goEnd(false);
}
updateZone();
}
return animation.model;
}
virtual int getStateGround() {
if (!think(false))
return state;
float angle;
getTargetInfo(0, NULL, NULL, &angle, NULL);
if (nextState == state)
nextState = STATE_NONE;
bool isBite = targetInView && fabsf(target->pos.y - pos.y) < 256.0f;
switch (state) {
case STATE_STOP :
if (nextState != STATE_NONE)
return nextState;
if (isBite && targetDist < RAT_DIST_BITE)
return STATE_BITE;
return STATE_RUN;
case STATE_RUN :
if (targetInView && (collide(target) & HIT_MASK))
return STATE_STOP;
if (isBite && targetDist < RAT_DIST_ATTACK)
return STATE_ATTACK;
if (targetInView && randf() < RAT_WAIT) {
nextState = STATE_WAIT;
return STATE_STOP;
}
break;
case STATE_ATTACK :
case STATE_BITE :
if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
bite(getJoint(jointHead).pos, RAT_DAMAGE);
nextState = state == STATE_ATTACK ? STATE_RUN : STATE_STOP;
}
break;
case STATE_WAIT :
if (mood == MOOD_SLEEP || randf() < RAT_WAIT)
return STATE_STOP;
default : ;
}
return state;
}
virtual int getStateOnwater() {
if (!think(false))
return state;
float angle;
getTargetInfo(0, NULL, NULL, &angle, NULL);
if (nextState == state)
nextState = STATE_NONE;
if (animation.frameIndex % 4 == 0)
game->waterDrop(getJoint(jointHead).pos, 96.0f, 0.02f);
switch (state) {
case STATE_WATER_SWIM :
if (targetInView && (collide(target) & HIT_MASK))
return STATE_WATER_ATTACK;
break;
case STATE_WATER_ATTACK :
if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
game->waterDrop(getJoint(jointHead).pos, 256.0f, 0.2f);
bite(getJoint(jointHead).pos, RAT_DAMAGE);
nextState = STATE_WATER_SWIM;
}
return STATE_NONE;
default : ;
}
return state;
}
virtual void updatePosition() {
float angleY = 0.0f;
if ((stand == STAND_GROUND && state == STATE_RUN) || (stand == STAND_ONWATER && state == STATE_WATER_SWIM))
getTargetInfo(0, NULL, NULL, &angleY, NULL);
turn(angleY, RAT_TURN_FAST);
if (state == STATE_DEATH) {
animation.overrideMask = 0;
return;
}
Enemy::updatePosition();
setOverrides(state != STATE_DEATH, jointChest, jointHead);
lookAt(target);
}
virtual int getStateDeath() {
bool water = getRoom().flags.water;
if ((water && state == STATE_WATER_DEATH) || (!water && state == STATE_DEATH))
return state;
return animation.setAnim(water ? ANIM_WATER_DEATH : ANIM_GROUND_DEATH);
}
};
@ -1547,8 +1726,7 @@ struct Human : Enemy {
game->addMuzzleFlash(this, jointGun, muzzleOffset, -1);
if (targetDist < HUMAN_DIST_SHOT && randf() < ((HUMAN_DIST_SHOT - targetDist) / HUMAN_DIST_SHOT - 0.25f)) {
target->hit(damage, this);
target->addBlood(target->getJoint(rand() % target->getModel()->mCount).pos, vec3(0));
bite(target->getJoint(rand() % target->getModel()->mCount).pos, damage);
game->playSound(target->stand == STAND_UNDERWATER ? TR::SND_HIT_UNDERWATER : TR::SND_HIT, target->pos, Sound::PAN);
return true;
}

View File

@ -2884,7 +2884,7 @@ namespace TR {
cutMatrix.rotateY(16380.0f / float(0x4000) * PI * 0.5f);
break;
case LVL_TR1_CUT_3 :
state.flags.flipped = true;
flipMap();
case LVL_TR1_CUT_4 :
cutMatrix.translate(vec3(float(e.x), float(e.y), float(e.z)));
cutMatrix.rotateY(PI * 0.5f);
@ -3766,6 +3766,18 @@ namespace TR {
return 0;
}
void flipMap() {
for (int i = 0; i < roomsCount; i++)
if (rooms[i].alternateRoom > -1) {
TR::Room &src = rooms[i];
TR::Room &dst = rooms[src.alternateRoom];
swap(src, dst);
swap(src.alternateRoom, dst.alternateRoom);
}
state.flags.flipped = !state.flags.flipped;
}
void floorSkipCommand(FloorData* &fd, int func) {
switch (func) {
case FloorData::PORTAL :
@ -3819,9 +3831,6 @@ namespace TR {
Room::Sector& getSector(int roomIndex, int x, int z, int &dx, int &dz) const {
ASSERT(roomIndex >= 0 && roomIndex < roomsCount);
if (state.flags.flipped && rooms[roomIndex].alternateRoom > -1)
roomIndex = rooms[roomIndex].alternateRoom;
Room &room = rooms[roomIndex];
int sx = x - room.info.x;
@ -3983,6 +3992,34 @@ namespace TR {
return float(ceiling);
}
TR::Room::Sector* getWaterLevelSector(int16 &roomIndex, const vec3 &pos) {
int x = int(pos.x);
int z = int(pos.z);
TR::Room *room = &rooms[roomIndex];
TR::Room::Sector *sector = room->getSector((x - room->info.x) / 1024, (z - room->info.z) / 1024);
if (room->flags.water) { // go up to the air
while (sector->roomAbove != NO_ROOM) {
room = &rooms[sector->roomAbove];
if (!room->flags.water)
break;
roomIndex = sector->roomAbove;
sector = room->getSector((x - room->info.x) / 1024, (z - room->info.z) / 1024);
}
return sector;
} else { // go down to the water
while (sector->roomBelow != NO_ROOM) {
room = &rooms[roomIndex = sector->roomBelow];
sector = room->getSector((x - room->info.x) / 1024, (z - room->info.z) / 1024);
if (room->flags.water)
break;
}
return sector;
}
return NULL;
}
bool isBlocked(int16 &roomIndex, const vec3 &pos) {
Room::Sector *sector = getSector(roomIndex, pos);
return pos.y >= getFloor(sector, pos) || pos.y <= getCeiling(sector, pos);

View File

@ -299,7 +299,7 @@ struct Lara : Character {
delete[] basis;
}
TR::Model* getModel() const {
TR::Model* getModel() {
return &lara->level->models[lara->level->extra.braid];
}
@ -2025,7 +2025,7 @@ struct Lara : Character {
camera->viewIndex = cameraIndex;
if (needFlip) {
level->state.flags.flipped = !level->state.flags.flipped;
game->flipMap();
game->setEffect(this, effect);
}
}
@ -2616,6 +2616,9 @@ struct Lara : Character {
//reset(44, vec3(62976, 1536, 23040), 0);
reset(44, vec3(62976, 1536, 23040), 0);
break;
case TR::LVL_TR2_PLATFORM :
reset(16, vec3(53029, -5120, 77359), 0);
break;
case TR::LVL_TR3_TEMPLE :
reset(204, vec3(40562, 3584, 58694), 0);
break;

View File

@ -315,6 +315,32 @@ struct Level : IGame {
return zoneCache->findPath(ascend, descend, big, boxStart, boxEnd, zones, boxes);
}
void updateBlocks(bool rise) {
for (int i = 0; i < level.entitiesBaseCount; i++) {
Controller *controller = (Controller*)level.entities[i].controller;
switch (level.entities[i].type) {
case TR::Entity::BLOCK_1 :
case TR::Entity::BLOCK_2 :
case TR::Entity::BLOCK_3 :
case TR::Entity::BLOCK_4 :
((Block*)controller)->updateFloor(rise);
break;
case TR::Entity::MOVING_BLOCK :
((MovingBlock*)controller)->updateFloor(rise);
break;
default : ;
}
}
}
virtual void flipMap() {
updateBlocks(false);
if (waterCache) waterCache->flipMap();
mesh->flipMap();
level.flipMap();
updateBlocks(true);
}
virtual void setClipParams(float clipSign, float clipHeight) {
params->clipSign = clipSign;
params->clipHeight = clipHeight;
@ -1520,7 +1546,7 @@ struct Level : IGame {
case 4 : if (effectTimer > 4.1f) { effectIdx++; effect = TR::Effect::NONE; } break;
}
if (idx != effectIdx)
level.state.flags.flipped = !level.state.flags.flipped;
flipMap();
break;
}
case TR::Effect::EARTHQUAKE : {
@ -1742,9 +1768,6 @@ struct Level : IGame {
return;
}
if (level.rooms[to].alternateRoom > -1 && level.state.flags.flipped)
to = level.rooms[to].alternateRoom;
TR::Room &room = level.rooms[to];
if (!room.flags.visible) {
@ -1770,20 +1793,39 @@ struct Level : IGame {
waterCache->reset();
}
for (int i = 0; i < level.roomsCount; i++)
level.rooms[i].flags.visible = false;
int roomsList[256];
int roomsCount = 0;
getVisibleRooms(roomsList, roomsCount, TR::NO_ROOM, roomIndex, vec4(-1.0f, -1.0f, 1.0f, 1.0f), water);
/*
if (level.isCutsceneLevel()) {
if (level.isCutsceneLevel()) { // render all rooms except flipped
for (int i = 0; i < level.roomsCount; i++)
roomsList[i] = i;
roomsCount = level.roomsCount;
level.rooms[i].flags.visible = true;
for (int i = 0; i < level.roomsCount; i++) {
int flipIndex = level.rooms[i].alternateRoom;
if (flipIndex > 0)
level.rooms[flipIndex].flags.visible = false;
}
for (int i = 0; i < level.roomsCount; i++)
if (level.rooms[i].flags.visible) {
roomsList[roomsCount++] = i;
if (Core::pass == Core::passCompose && water && waterCache) {
TR::Room &r = level.rooms[i];
for (int j = 0; j < r.portalsCount; j++) {
int to = r.portals[j].roomIndex;
if (level.rooms[to].flags.visible && (level.rooms[to].flags.water ^ r.flags.water))
waterCache->setVisible(i, to);
}
}
}
} else {
for (int i = 0; i < level.roomsCount; i++)
level.rooms[i].flags.visible = false;
getVisibleRooms(roomsList, roomsCount, TR::NO_ROOM, roomIndex, vec4(-1.0f, -1.0f, 1.0f, 1.0f), water);
}
*/
if (water && waterCache) {
for (int i = 0; i < roomsCount; i++)
waterCache->setVisible(roomsList[i]);
@ -1817,12 +1859,6 @@ struct Level : IGame {
// alpha blending pass
renderRooms(roomsList, roomsCount, 1);
renderEntities(1);
// additive blending pass
vec4 oldFog = Core::fogParams;
Core::fogParams = FOG_BLACK; // don't apply fog for additive
renderRooms(roomsList, roomsCount, 2);
renderEntities(2);
Core::fogParams = oldFog;
Core::setBlending(bmNone);
if (water && waterCache && waterCache->visible) {
@ -1832,8 +1868,18 @@ struct Level : IGame {
setMainLight(player);
waterCache->render();
Core::pass = pass;
setupBinding();
}
// additive blending pass
vec4 oldFog = Core::fogParams;
Core::fogParams = FOG_BLACK; // don't apply fog for additive
renderRooms(roomsList, roomsCount, 2);
renderEntities(2);
Core::fogParams = oldFog;
Core::setBlending(bmNone);
if (showUI) {
Core::Pass pass = Core::pass;
renderUI();
@ -1908,7 +1954,7 @@ struct Level : IGame {
camera->setup(true);
if (Input::down[ikF]) {
level.state.flags.flipped = !level.state.flags.flipped;
flipMap();
Input::down[ikF] = false;
}
@ -2011,18 +2057,19 @@ struct Level : IGame {
// Debug::Level::entities(level);
// Debug::Level::zones(level, lara);
// Debug::Level::blocks(level);
// Debug::Level::path(level, (Enemy*)level.entities[86].controller);
// Debug::Level::path(level, (Enemy*)level.entities[105].controller);
// Debug::Level::debugOverlaps(level, lara->box);
// Debug::Level::debugBoxes(level, lara->dbgBoxes, lara->dbgBoxesCount);
Core::setDepthTest(true);
Core::setBlending(bmNone);
/*
Core::validateRenderState();
static int dbg_ambient = 0;
dbg_ambient = int(params->time * 2) % 4;
shadow->unbind(sShadow);
cube->unbind(sEnvironment);
Core::whiteCube->unbind(sEnvironment);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
@ -2030,7 +2077,7 @@ struct Level : IGame {
glColor3f(1, 1, 1);
for (int j = 0; j < 6; j++) {
glPushMatrix();
glTranslatef(lara->pos.x, lara->pos.y - 1024, lara->pos.z);
glTranslatef(player->pos.x, player->pos.y - 1024, player->pos.z);
switch (j) {
case 0 : glRotatef( 90, 0, 1, 0); break;
case 1 : glRotatef(-90, 0, 1, 0); break;

View File

@ -63,7 +63,7 @@ struct MeshRange {
#define DYN_MESH_QUADS 1024
#define DOUBLE_SIDED 2
#define MAX_ROOM_DYN_FACES 256
#define MAX_ROOM_DYN_FACES 512
struct Mesh {
Index *iBuffer;
@ -800,6 +800,12 @@ struct MeshBuilder {
#endif
}
void flipMap() {
for (int i = 0; i < level->roomsCount; i++)
if (level->rooms[i].alternateRoom > -1)
swap(rooms[i], rooms[level->rooms[i].alternateRoom]);
}
inline short4 rotate(const short4 &v, int dir) {
if (dir == 0) return v;
short4 res = v;

View File

@ -1047,12 +1047,14 @@ struct Lightning : Controller {
if (timer <= 0.0f) {
if (flash) {
level->state.flags.flipped = false;
if (level->state.flags.flipped)
game->flipMap();
flash = false;
armed = true;
timer = (35.0f + randf() * 45.0f) / 30.0f;
} else {
level->state.flags.flipped = true;
if (!level->state.flags.flipped)
game->flipMap();
flash = true;
timer = 20.0f / 30.0f;
@ -1071,7 +1073,8 @@ struct Lightning : Controller {
} else {
timer = 0.0f;
flash = false;
level->state.flags.flipped = false;
if (level->state.flags.flipped)
game->flipMap();
deactivate(true);
}
}
@ -1306,7 +1309,7 @@ struct Cabin : Controller {
if (state == STATE_GROUND) {
flags.invisible = true;
level->state.flipmaps[3].active = TR::ACTIVE;
level->state.flags.flipped = !level->state.flags.flipped;
game->flipMap();
deactivate(true);
}