1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-15 09:34:18 +02:00

#23 dynamic lighting for stone artifacts and crystals

This commit is contained in:
XProger
2017-11-28 10:42:50 +03:00
parent 6c652a1f09
commit c270527d40
7 changed files with 130 additions and 50 deletions

View File

@@ -600,7 +600,7 @@ struct Controller {
return level->entities[entity];
}
const TR::Room& getRoom() const {
TR::Room& getRoom() {
int index = getRoomIndex();
ASSERT(index >= 0 && index < level->roomsCount);
return level->rooms[index];

View File

@@ -277,12 +277,12 @@ namespace Debug {
rc[i] = vec3( x + offsets[i][0], info.roomCeiling + 4, z + offsets[i][1] );
f[i] = vec3( x + offsets[i][0], info.floor - 4, z + offsets[i][1] );
c[i] = vec3( x + offsets[i][0], info.ceiling + 4, z + offsets[i][1] );
if (info.roomBelow == 0xFF) rf[i].y = f[i].y;
if (info.roomAbove == 0xFF) rc[i].y = c[i].y;
if (info.roomBelow == TR::NO_ROOM) rf[i].y = f[i].y;
if (info.roomAbove == TR::NO_ROOM) rc[i].y = c[i].y;
}
if (info.roomNext != 0xFF) {
glColor4f(0.0f, 0.0f, 1.0f, 0.1f);
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glVertex3fv((GLfloat*)&f[3]);
glVertex3fv((GLfloat*)&f[2]);

View File

@@ -1461,6 +1461,14 @@ namespace TR {
uint8 align;
uint32 waterLevel;
struct DynLight {
int32 id;
vec4 pos;
vec4 color;
} dynLights[2];
int32 dynLightsCount;
struct Portal {
uint16 roomIndex;
Vertex normal;
@@ -1506,6 +1514,36 @@ namespace TR {
vec3 getOffset() const {
return vec3(float(info.x), 0.0f, float(info.z));
}
void addDynLight(int32 id, const vec4 &pos, const vec4 &color) {
DynLight *light = NULL;
for (int i = 0; i < dynLightsCount; i++)
if (dynLights[i].id == id) {
light = &dynLights[i];
break;
}
// 1 is additional second light, can be overridden
if (!light) {
if (dynLightsCount < 2) {
light = &dynLights[dynLightsCount];
dynLightsCount = min(2, dynLightsCount + 1);
} else
light = &dynLights[1];
}
light->id = id;
light->pos = pos;
light->color = color;
}
void removeDynLight(int32 id) {
for (int i = 0; i < dynLightsCount; i++)
if (dynLights[i].id == id) {
if (i == 0) dynLights[0] = dynLights[1];
dynLightsCount--;
break;
}
}
};
union FloorData {
@@ -3505,6 +3543,8 @@ namespace TR {
stream.read(r.reverbType);
stream.read(r.filter); // unused
}
r.dynLightsCount = 0;
}

View File

@@ -2572,6 +2572,7 @@ struct Lara : Character {
for (int i = 0; i < pickupListCount; i++) {
if (pickupList[i]->getEntity().type == TR::Entity::SCION_PICKUP_HOLDER)
continue;
pickupList[i]->deactivate();
pickupList[i]->flags.invisible = true;
game->invAdd(pickupList[i]->getEntity().type, 1);
}

View File

@@ -323,6 +323,14 @@ struct Level : IGame {
TR::Room &room = level.rooms[roomIndex];
if (room.dynLightsCount) {
Core::lightPos[3] = room.dynLights[0].pos;
Core::lightColor[3] = room.dynLights[0].color;
} else {
Core::lightPos[3] = vec4(0);
Core::lightColor[3] = vec4(0, 0, 0, 1);
}
if (room.flags.water)
setWaterParams(float(room.info.yTop));
else
@@ -794,6 +802,12 @@ struct Level : IGame {
case TR::Entity::ENEMY_MONK_1 :
case TR::Entity::ENEMY_MONK_2 : return new Enemy(this, index, 100, 10, 0.0f, 0.0f);
case TR::Entity::CRYSTAL_PICKUP : return new CrystalPickup(this, index);
case TR::Entity::STONE_ITEM_1 :
case TR::Entity::STONE_ITEM_2 :
case TR::Entity::STONE_ITEM_3 :
case TR::Entity::STONE_ITEM_4 : return new StoneItem(this, index);
default : return (level.entities[index].modelIndex > 0) ? new Controller(this, index) : new Sprite(this, index, 0);
}
}
@@ -1105,8 +1119,6 @@ struct Level : IGame {
if (Core::pass == Core::passShadow)
return;
bool hasGeom = false, hasSprite = false;
Basis basis;
basis.identity();
@@ -1138,11 +1150,8 @@ struct Level : IGame {
setRoomParams(roomIndex, Shader::ROOM, 1.0f, intensityf(level.rooms[roomIndex].ambient), 0.0f, 1.0f, transp == 1);
Shader *sh = Core::active.shader;
if (!hasGeom) {
hasGeom = true;
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
}
basis.pos = level.rooms[roomIndex].getOffset();
sh->setParam(uBasis, basis);
@@ -1170,10 +1179,9 @@ struct Level : IGame {
setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true);
Shader *sh = Core::active.shader;
if (!hasSprite) {
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
}
basis.pos = level.rooms[roomIndex].getOffset();
sh->setParam(uBasis, basis);
@@ -1241,36 +1249,6 @@ struct Level : IGame {
controller->render(camera->frustum, mesh, type, room.flags.water);
}
void updateLighting() {
// update crystal lighting (TODO: make it per-room instead of global)
int index = -1;
float minDist = 1000000000.f;
for (int i = 0; i < level.entitiesBaseCount; i++) {
TR::Entity &e = level.entities[i];
if (e.type == TR::Entity::CRYSTAL) {
Crystal *crystal = (Crystal*)e.controller;
if (crystal->flags.state != TR::Entity::asActive && !level.rooms[crystal->getRoomIndex()].flags.visible)
continue;
if (camera->frustum->isVisible(crystal->lightPos, CRYSTAL_LIGHT_RADIUS + 1024.0f)) { // 1024.0f because of vertex lighting
float d = (lara->pos - crystal->pos).length();
if (d < minDist) {
index = i;
minDist = d;
}
};
}
}
if (index > -1) {
Crystal *crystal = (Crystal*)level.entities[index].controller;
Core::lightPos[3] = crystal->lightPos;
Core::lightColor[3] = CRYSTAL_LIGHT_COLOR;
} else
Core::lightColor[3] = Core::lightColor[3] = vec4(0, 0, 0, 1);
}
void update() {
if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK)) {
if (camera->timer > 0.0f)
@@ -1309,8 +1287,6 @@ struct Level : IGame {
camera->update();
updateLighting();
if (waterCache)
waterCache->update();
@@ -1730,6 +1706,7 @@ struct Level : IGame {
// Debug::Draw::box(bbox.min, bbox.max, vec4(1, 0, 1, 1));
// Core::setBlending(bmAlpha);
// Core::setDepthTest(false);
// Core::validateRenderState();
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex(), lara);
@@ -1744,6 +1721,7 @@ struct Level : IGame {
// Debug::Level::path(level, (Enemy*)level.entities[86].controller);
// Debug::Level::debugOverlaps(level, lara->box);
// Debug::Level::debugBoxes(level, lara->dbgBoxes, lara->dbgBoxesCount);
// Core::setDepthTest(true);
// Core::setBlending(bmNone);
/*

View File

@@ -363,7 +363,14 @@ struct MeshBuilder {
if (range.iCount && model.type == TR::Entity::SKY && ((level.version & TR::VER_TR3)))
range.iCount -= 16 * 3;
}
// TR::Entity::fixOpaque(model.type, opaque);
//int transp = TR::Entity::fixTransp(model.type);
if (model.type == TR::Entity::SKY) {
models[i].geometry[0].iCount = iCount - models[i].geometry[0].iStart;
models[i].geometry[1].iCount = 0;
models[i].geometry[2].iCount = 0;
}
}
ASSERT(vCount - vStartModel <= 0xFFFF);

View File

@@ -678,7 +678,6 @@ struct Drawbridge : Controller {
struct Crystal : Controller {
Texture *environment;
vec3 lightPos;
Crystal(IGame *game, int entity) : Controller(game, entity) {
environment = new Texture(64, 64, Texture::RGBA, true, NULL, true, true);
@@ -689,9 +688,15 @@ struct Crystal : Controller {
delete environment;
}
virtual void deactivate(bool removeFromList = false) {
Controller::deactivate(removeFromList);
getRoom().removeDynLight(entity);
}
virtual void update() {
updateAnimation(false);
lightPos = animation.getJoints(getMatrix(), 0, false).pos - vec3(0, 256, 0);
vec3 lightPos = animation.getJoints(getMatrix(), 0, false).pos - vec3(0, 256, 0);
getRoom().addDynLight(entity, vec4(lightPos, 0.0f), CRYSTAL_LIGHT_COLOR);
}
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
@@ -701,6 +706,27 @@ struct Crystal : Controller {
}
};
#define CRYSTAL_PICKUP_LIGHT_COLOR vec4(0.1f, 0.5f, 0.1f, 1.0f / CRYSTAL_LIGHT_RADIUS)
struct CrystalPickup : Controller {
CrystalPickup(IGame *game, int entity) : Controller(game, entity) {
activate();
}
virtual void deactivate(bool removeFromList = false) {
Controller::deactivate(removeFromList);
getRoom().removeDynLight(entity);
}
virtual void update() {
updateAnimation(false);
vec3 lightPos = animation.getJoints(getMatrix(), 0, false).pos;
getRoom().addDynLight(entity, vec4(lightPos, 0.0f), CRYSTAL_PICKUP_LIGHT_COLOR);
}
};
#define BLADE_DAMAGE 100
#define BLADE_RANGE 1024
@@ -1404,4 +1430,32 @@ struct Explosion : Sprite {
};
#define STONE_ITEM_LIGHT_RADIUS 2048.0f
struct StoneItem : Controller {
float phase;
StoneItem(IGame *game, int entity) : Controller(game, entity), phase(0) {
activate();
}
virtual void deactivate(bool removeFromList = false) {
Controller::deactivate(removeFromList);
getRoom().removeDynLight(entity);
}
virtual void update() {
updateAnimation(false);
angle.y += Core::deltaTime * 2.0f;
phase += Core::deltaTime;
float s = 0.3f + (sinf(phase * PI2) * 0.5f + 0.5f) * 0.7f;
vec4 lightColor(0.1f * s, 1.0f * s, 1.0f * s, 1.0f / STONE_ITEM_LIGHT_RADIUS);
vec3 lightPos = animation.getJoints(getMatrix(), 0, false).pos;
getRoom().addDynLight(entity, vec4(lightPos, 0.0f), lightColor);
}
};
#endif