1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-16 01:54:38 +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]; return level->entities[entity];
} }
const TR::Room& getRoom() const { TR::Room& getRoom() {
int index = getRoomIndex(); int index = getRoomIndex();
ASSERT(index >= 0 && index < level->roomsCount); ASSERT(index >= 0 && index < level->roomsCount);
return level->rooms[index]; 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] ); 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] ); 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] ); 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.roomBelow == TR::NO_ROOM) rf[i].y = f[i].y;
if (info.roomAbove == 0xFF) rc[i].y = c[i].y; if (info.roomAbove == TR::NO_ROOM) rc[i].y = c[i].y;
} }
if (info.roomNext != 0xFF) { 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); glBegin(GL_QUADS);
glVertex3fv((GLfloat*)&f[3]); glVertex3fv((GLfloat*)&f[3]);
glVertex3fv((GLfloat*)&f[2]); glVertex3fv((GLfloat*)&f[2]);

View File

@@ -1461,6 +1461,14 @@ namespace TR {
uint8 align; uint8 align;
uint32 waterLevel; uint32 waterLevel;
struct DynLight {
int32 id;
vec4 pos;
vec4 color;
} dynLights[2];
int32 dynLightsCount;
struct Portal { struct Portal {
uint16 roomIndex; uint16 roomIndex;
Vertex normal; Vertex normal;
@@ -1506,6 +1514,36 @@ namespace TR {
vec3 getOffset() const { vec3 getOffset() const {
return vec3(float(info.x), 0.0f, float(info.z)); 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 { union FloorData {
@@ -3505,6 +3543,8 @@ namespace TR {
stream.read(r.reverbType); stream.read(r.reverbType);
stream.read(r.filter); // unused stream.read(r.filter); // unused
} }
r.dynLightsCount = 0;
} }

View File

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

View File

@@ -323,6 +323,14 @@ struct Level : IGame {
TR::Room &room = level.rooms[roomIndex]; 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) if (room.flags.water)
setWaterParams(float(room.info.yTop)); setWaterParams(float(room.info.yTop));
else else
@@ -794,6 +802,12 @@ struct Level : IGame {
case TR::Entity::ENEMY_MONK_1 : 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::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); 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) if (Core::pass == Core::passShadow)
return; return;
bool hasGeom = false, hasSprite = false;
Basis basis; Basis basis;
basis.identity(); 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); setRoomParams(roomIndex, Shader::ROOM, 1.0f, intensityf(level.rooms[roomIndex].ambient), 0.0f, 1.0f, transp == 1);
Shader *sh = Core::active.shader; Shader *sh = Core::active.shader;
if (!hasGeom) { sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
hasGeom = true; sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
}
basis.pos = level.rooms[roomIndex].getOffset(); basis.pos = level.rooms[roomIndex].getOffset();
sh->setParam(uBasis, basis); sh->setParam(uBasis, basis);
@@ -1170,10 +1179,9 @@ struct Level : IGame {
setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true); setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true);
Shader *sh = Core::active.shader; Shader *sh = Core::active.shader;
if (!hasSprite) {
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS); sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS); sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
}
basis.pos = level.rooms[roomIndex].getOffset(); basis.pos = level.rooms[roomIndex].getOffset();
sh->setParam(uBasis, basis); sh->setParam(uBasis, basis);
@@ -1241,36 +1249,6 @@ struct Level : IGame {
controller->render(camera->frustum, mesh, type, room.flags.water); 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() { void update() {
if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK)) { if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK)) {
if (camera->timer > 0.0f) if (camera->timer > 0.0f)
@@ -1309,8 +1287,6 @@ struct Level : IGame {
camera->update(); camera->update();
updateLighting();
if (waterCache) if (waterCache)
waterCache->update(); waterCache->update();
@@ -1730,6 +1706,7 @@ struct Level : IGame {
// Debug::Draw::box(bbox.min, bbox.max, vec4(1, 0, 1, 1)); // Debug::Draw::box(bbox.min, bbox.max, vec4(1, 0, 1, 1));
// Core::setBlending(bmAlpha); // Core::setBlending(bmAlpha);
// Core::setDepthTest(false);
// Core::validateRenderState(); // Core::validateRenderState();
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room); // Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex(), lara); // 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::path(level, (Enemy*)level.entities[86].controller);
// Debug::Level::debugOverlaps(level, lara->box); // Debug::Level::debugOverlaps(level, lara->box);
// Debug::Level::debugBoxes(level, lara->dbgBoxes, lara->dbgBoxesCount); // Debug::Level::debugBoxes(level, lara->dbgBoxes, lara->dbgBoxesCount);
// Core::setDepthTest(true);
// Core::setBlending(bmNone); // Core::setBlending(bmNone);
/* /*

View File

@@ -363,7 +363,14 @@ struct MeshBuilder {
if (range.iCount && model.type == TR::Entity::SKY && ((level.version & TR::VER_TR3))) if (range.iCount && model.type == TR::Entity::SKY && ((level.version & TR::VER_TR3)))
range.iCount -= 16 * 3; 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); ASSERT(vCount - vStartModel <= 0xFFFF);

View File

@@ -678,7 +678,6 @@ struct Drawbridge : Controller {
struct Crystal : Controller { struct Crystal : Controller {
Texture *environment; Texture *environment;
vec3 lightPos;
Crystal(IGame *game, int entity) : Controller(game, entity) { Crystal(IGame *game, int entity) : Controller(game, entity) {
environment = new Texture(64, 64, Texture::RGBA, true, NULL, true, true); environment = new Texture(64, 64, Texture::RGBA, true, NULL, true, true);
@@ -689,9 +688,15 @@ struct Crystal : Controller {
delete environment; delete environment;
} }
virtual void deactivate(bool removeFromList = false) {
Controller::deactivate(removeFromList);
getRoom().removeDynLight(entity);
}
virtual void update() { virtual void update() {
updateAnimation(false); 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) { 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_DAMAGE 100
#define BLADE_RANGE 1024 #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 #endif