diff --git a/src/cache.h b/src/cache.h index 328af98..ef131fe 100644 --- a/src/cache.h +++ b/src/cache.h @@ -8,6 +8,8 @@ #define NO_CLIP_PLANE 1000000.0f +#define SHADOW_TEX_SIZE 1024 + #define FOG_DIST (18 * 1024) #define WATER_FOG_DIST (8 * 1024) //#define WATER_USE_GRID @@ -130,7 +132,7 @@ struct ShaderCache { typ = typeNames[type]; int animTexRangesCount = game->getMesh()->animTexRangesCount; int animTexOffsetsCount = game->getMesh()->animTexOffsetsCount; - sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST); + sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST, SHADOW_TEX_SIZE); if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR); if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\n"); if (fx & FX_CLIP_PLANE) strcat(def, "#define CLIP_PLANE\n"); diff --git a/src/character.h b/src/character.h index 59220a0..2fb10ed 100644 --- a/src/character.h +++ b/src/character.h @@ -133,6 +133,7 @@ struct Character : Controller { } virtual void update() { + vec3 p = pos; lastInput = input; input = getInput(); stand = getStand(); @@ -140,6 +141,8 @@ struct Character : Controller { Controller::update(); updateVelocity(); updatePosition(); + if (p != pos) + updateLights(); } virtual void cmdJump(const vec3 &vel) { diff --git a/src/controller.h b/src/controller.h index bed3fb1..a796964 100644 --- a/src/controller.h +++ b/src/controller.h @@ -46,6 +46,10 @@ struct Controller { vec3 ambient[6]; float specular; + TR::Room::Light *lights[MAX_LIGHTS]; + vec3 mainLightPos; + float mainLightRadius; + struct MeshLayer { uint32 model; uint32 mask; @@ -71,6 +75,7 @@ struct Controller { frameIndex = -1; specular = 0.0f; ambient[0] = ambient[1] = ambient[2] = ambient[3] = ambient[4] = ambient[5] = vec3(intensityf(getRoom().ambient)); + updateLights(); } virtual ~Controller() { @@ -130,8 +135,6 @@ struct Controller { return false; } - - void updateEntity() { TR::Entity &e = getEntity(); e.x = int(pos.x); @@ -273,7 +276,11 @@ struct Controller { } virtual Box getBoundingBox() { - return animation.getBoundingBox(pos, getEntity().rotation.value / 0x4000); + return getBoundingBoxLocal() * getMatrix(); + } + + virtual Box getBoundingBoxLocal() { + return animation.getBoundingBox(vec3(0, 0, 0), 0); } vec3 trace(int fromRoom, const vec3 &from, const vec3 &to, int &room, bool isCamera) { // TODO: use Bresenham @@ -464,6 +471,85 @@ struct Controller { virtual void update() { updateAnimation(true); } + + struct MaxLight { + TR::Room::Light *light; + float att; + }; + + void checkRoomLights(int roomIndex, int fromRoom, const vec3 &from, MaxLight *maxLights, vec3 &mainDir, float &mainRad, float &attSum, int deep) { + TR::Room &room = level->rooms[roomIndex]; + + for (int i = 0; i < room.lightsCount; i++) { + TR::Room::Light &light = room.lights[i]; + + bool exists = false; + for (int m = 0; m < MAX_LIGHTS; m++) + if (maxLights[m].light == &light) { + exists = true; + break; + } + if (exists) continue; + + vec3 dir = vec3(float(light.x), float(light.y), float(light.z)) - from; + float att = max(0.0f, 1.0f - dir.length2() / float(light.radius) / float(light.radius)) * intensityf(light.intensity); + + for (int m = 0; m < MAX_LIGHTS; m++) { + if (maxLights[m].att < att) { + for (int n = MAX_LIGHTS - 1; n > m; n--) + maxLights[n] = maxLights[n - 1]; + maxLights[m].light = &light; + maxLights[m].att = att; + break; + } + } + + if (att > 0.0f) { + // if (dir.y > 0.0f) + // att *= 1.0f - dir.y / float(light.radius); + att = max(0.0f, att - dir.y / 8192.0f); + attSum += att; + mainDir += dir * att; + mainRad += float(light.radius) * att; + } + } + + if (--deep > 0) + for (int i = 0; i < room.portalsCount; i++) + if (room.portals[i].roomIndex != fromRoom) + checkRoomLights(room.portals[i].roomIndex, roomIndex, from, maxLights, mainDir, mainRad, attSum, deep); + } + + void updateLights() { + if (!getModel()) { + for (int i = 0; i < MAX_LIGHTS; i++) + lights[i] = NULL; + return; + } + + MaxLight maxLights[MAX_LIGHTS]; + + for (int i = 0; i < MAX_LIGHTS; i++) { + maxLights[i].light = NULL; + maxLights[i].att = 0.0f; + } + + vec3 p = getBoundingBox().center(); + vec3 mainDir(0.0f); + float mainRad = 0.0f; + float attSum = 0.0f; + + checkRoomLights(getRoomIndex(), -1, p, maxLights, mainDir, mainRad, attSum, 1); + + if (attSum > 0.0f) { + attSum = 1.0f / attSum; + mainLightPos = mainDir * attSum + p; + mainLightRadius = mainRad * attSum; + } + + for (int i = 0; i < MAX_LIGHTS; i++) + lights[i] = maxLights[i].light; + } /* void renderMesh(MeshBuilder *mesh, uint32 offsetIndex) { return; diff --git a/src/debug.h b/src/debug.h index a5f6e46..3cd8ffc 100644 --- a/src/debug.h +++ b/src/debug.h @@ -350,18 +350,24 @@ namespace Debug { } } - void lights(const TR::Level &level, int room) { + void lights(const TR::Level &level, int room, Controller *lara) { // int roomIndex = level.entities[lara->entity].room; // int lightIndex = getLightIndex(lara->pos, roomIndex); - + lara->updateLights(); glPointSize(8); for (int i = 0; i < level.roomsCount; i++) for (int j = 0; j < level.rooms[i].lightsCount; j++) { TR::Room::Light &l = level.rooms[i].lights[j]; - float a = l.intensity / 8191.0f; + float a = intensityf(l.intensity); vec3 p = vec3(l.x, l.y, l.z); vec4 color = vec4(a, a, a, 1); - if (i == room) color.x = color.z = 0; + + if (&l == lara->lights[0]) color.y = color.z = 0; // r + if (&l == lara->lights[1]) color.x = color.z = 0; // g + if (&l == lara->lights[2]) color.x = color.y = 0; // b + if (&l == lara->lights[3]) color.y = 0; // a + +// if (i == room) color.x = color.z = 0; Debug::Draw::point(p, color); //if (i == roomIndex && j == lightIndex) // color = vec4(0, 1, 0, 1); diff --git a/src/format.h b/src/format.h index 9a7a8e4..53344bc 100644 --- a/src/format.h +++ b/src/format.h @@ -949,7 +949,7 @@ namespace TR { stream.read(light.intensity); stream.read(light.radius); - light.radius *= 2; + // light.radius *= 2; } // meshes stream.read(r.meshesCount); diff --git a/src/lara.h b/src/lara.h index 6640267..6934967 100644 --- a/src/lara.h +++ b/src/lara.h @@ -1808,6 +1808,9 @@ struct Lara : Character { break; } } + + if (state == STATE_DEATH || state == STATE_UNDERWATER_DEATH) + velocity.x = velocity.z = 0.0f; } virtual void updatePosition() { // TODO: sphere / bbox collision diff --git a/src/level.h b/src/level.h index b62b042..5f1f4f8 100644 --- a/src/level.h +++ b/src/level.h @@ -22,7 +22,7 @@ struct Level : IGame { Lara *lara; Camera *camera; - Texture *shadow, *shadowMask; + Texture *shadow; struct Params { float time; @@ -221,8 +221,7 @@ struct Level : IGame { ambientCache = Core::settings.ambient ? new AmbientCache(this) : NULL; waterCache = Core::settings.water ? new WaterCache(this) : NULL; - shadow = Core::settings.shadows ? new Texture(1024, 1024, Texture::SHADOW, false) : NULL; - shadowMask = NULL; + shadow = Core::settings.shadows ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL; initReflections(); @@ -250,7 +249,6 @@ struct Level : IGame { delete shaderCache; delete shadow; - delete shadowMask; delete ambientCache; delete waterCache; @@ -460,48 +458,26 @@ struct Level : IGame { } camera->frustum = camFrustum; // pop camera frustum } + + void setLights(Controller *controller, bool onlyFlashes = false) { + for (int i = 0; i < MAX_LIGHTS; i++) { + TR::Room::Light *light = controller->lights[i]; + if (onlyFlashes && i && light && light->radius > 0.0f) + light = NULL; - int getLightIndex(const vec3 &pos, int &room, float maxAtt = -1.0f, int depth = 0) { - int idx = -1; - - TR::Room &r = level.rooms[room]; - - for (int i = 0; i < r.lightsCount; i++) { - TR::Room::Light &light = r.lights[i]; - if (light.intensity > 0x1FFF) continue; - float att = max(0.0f, 1.0f - (pos - vec3(float(light.x), float(light.y), float(light.z))).length2() / ((float)light.radius * (float)light.radius)); - if (att > maxAtt) { - maxAtt = att; - idx = i; + if (light) { + float c = 1.0f - intensityf(light->intensity); + Core::lightPos[i] = vec3(float(light->x), float(light->y), float(light->z)); + Core::lightColor[i] = vec4(c, c, c, 1.0f / float(light->radius)); + } else { + Core::lightPos[i] = vec3(0); + Core::lightColor[i] = vec4(0, 0, 0, 1); } } - if (depth > 0) - for (int i = 0; i < r.portalsCount; i++) { - int nextRoom = r.portals[i].roomIndex; - int nextLight = getLightIndex(pos, nextRoom, maxAtt, depth - 1); - if (nextLight > -1) { - room = nextRoom; - idx = nextLight; - } - } - - return idx; - } - - void getLight(const vec3 &pos, int roomIndex) { - int room = roomIndex; - int idx = getLightIndex(pos, room); - - if (idx > -1) { - TR::Room::Light &light = level.rooms[room].lights[idx]; - float c = 1.0f - intensityf(level.rooms[room].lights[idx].intensity); - Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z)); - Core::lightColor[0] = vec4(c, c, c, 1.0f / (float)light.radius); - } else { - Core::lightPos[0] = vec3(0); - Core::lightColor[0] = vec4(0, 0, 0, 1); - } + Core::lightPos[0] = lara->mainLightPos; + if (lara->mainLightRadius > 0.0f) + Core::lightColor[0].w = 1.0f / lara->mainLightRadius; } void renderEntity(const TR::Entity &entity) { @@ -543,7 +519,8 @@ struct Level : IGame { } Core::active.shader->setParam(uAmbient, controller->ambient[0], 6); } - getLight(pos, entity.room); + + setLights(controller); } else { // sprite Core::lightPos[0] = vec3(0); Core::lightColor[0] = vec4(0, 0, 0, 1); @@ -610,7 +587,7 @@ struct Level : IGame { void renderRooms(int roomIndex) { PROFILE_MARKER("ROOMS"); - getLight(lara->pos, lara->getRoomIndex()); + setLights(lara, true); #ifdef LEVEL_EDITOR for (int i = 0; i < level.roomsCount; i++) @@ -656,20 +633,43 @@ struct Level : IGame { } - mat4 calcCromMatrix(const mat4 &lightViewProj, const Box *boxes, int count) { - mat4 cameraViewProjInv = (mat4(camera->fov, float(Core::width) / Core::height, 512.0f, 4096.0f) * camera->mViewInv.inverse()).inverse(); + Box bRec, bCast, bCrop, bSplit; +/* + mat4 calcCropMatrix(const mat4 &viewProj, const Box &receivers, const Box &casters) { + mat4 cameraViewProjInv = (camera->getProjMatrix() * camera->mViewInv.inverse()).inverse(); + // camera->mViewInv (mat4(camera->fov, float(Core::width) / Core::height, camera->znear, camera->zfar) * camera->mViewInv.inverse()).inverse(); Box frustumBox = Box(vec3(-1.0f), vec3(1.0f)) * cameraViewProjInv; - Box casterBox(vec3(+INF), vec3(-INF)); + Box caster = casters;// * viewProj; + Box receiver = receivers * viewProj; + Box split = frustumBox * viewProj; - for (int i = 0; i < count; i++) - casterBox += boxes[i] * lightViewProj; + Box crop; + crop.min.x = max(max(caster.min.x, receiver.min.x), split.min.x); + crop.max.x = min(min(caster.max.x, receiver.max.x), split.max.x); + crop.min.y = max(max(caster.min.y, receiver.min.y), split.min.y); + crop.max.y = min(min(caster.max.y, receiver.max.y), split.max.y); + crop.min.z = min(caster.min.z, split.min.z); + crop.max.z = min(receiver.max.z, split.max.z); - casterBox -= frustumBox * lightViewProj; + mat4 m = camera->getProjMatrix(); + Box cc = receivers * m; + cc = cc * m.inverse(); - vec3 scale = vec3(2.0f, 2.0f, 1.0f) / casterBox.size(); - vec3 center = casterBox.center(); - vec3 offset = vec3(center.x, center.y, casterBox.min.z) * scale; + if (!Input::down[ikShift]) { + mat4 m = viewProj.inverse(); + bRec = receivers;// * m; + bCast = casters;// * m; + bCrop = crop * m; + bSplit = split * m; + } + +// casterBox -= frustumBox * viewProj; +// crop.min.z = 0.0f; + + vec3 scale = vec3(2.0f, 2.0f, 1.0f) / crop.size(); + vec3 center = crop.center(); + vec3 offset = vec3(center.x, center.y, crop.min.z) * scale; return mat4(scale.x, 0.0f, 0.0f, 0.0f, 0.0f, scale.y, 0.0f, 0.0f, @@ -679,62 +679,241 @@ struct Level : IGame { bool setupLightCamera() { - vec3 pos = lara->getPos(); - - // omni-spot light shadows - int room = lara->getRoomIndex(); - int idx = getLightIndex(lara->pos, room); - if (idx < 0) return false; + lara->updateLights(); + vec3 pos = lara->getBoundingBox().center(); - TR::Room::Light &light = level.rooms[room].lights[idx]; - vec3 shadowLightPos = vec3(float(light.x), float(light.y), float(light.z)); - Core::mViewInv = mat4(shadowLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0)); + Core::mViewInv = mat4(lara->mainLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0)); Core::mView = Core::mViewInv.inverse(); - Core::mProj = mat4(120.0f, 1.0f, camera->znear, camera->zfar); + Core::mProj = mat4(1.0f, 1.0f, camera->znear, camera->zfar);//lara->mainLightRadius * 2.0f); + + mat4 mLightProj = Core::mProj * Core::mView; + + Box casters = lara->getBoundingBox() * mLightProj; + + float rq = lara->mainLightRadius * lara->mainLightRadius; + for (int i = 0; i < level.entitiesCount; i++) { + TR::Entity &e = level.entities[i]; + Controller *controller = (Controller*)e.controller; + if (controller && TR::castShadow(e.type) && rq > (lara->mainLightPos - controller->pos).length2()) + casters += controller->getBoundingBox() * mLightProj; + } + //casters.expand(vec3(128.0f)); + + Box lightBox = Box(lara->mainLightPos - vec3(lara->mainLightRadius), lara->mainLightPos + vec3(lara->mainLightRadius)); + + Core::mProj = calcCropMatrix(mLightProj, lightBox, casters) * Core::mProj; mat4 bias; bias.identity(); bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; - /* - Box boxes[32]; - int bCount = 0; - - float rq = light.radius * light.radius; - for (int i = 0; i < level.entitiesCount; i++) { - TR::Entity &e = level.entities[i]; - Controller *controller = (Controller*)e.controller; - if (controller && TR::castShadow(e.type) && rq > (shadowLightPos - controller->pos).length2()) - boxes[bCount++] = controller->getBoundingBox(); + + Core::mLightProj = bias * (Core::mProj * Core::mView); + + return true; + } +*/ + +/* // --> XPSM + Box transformPointsBox(const vec3 *points, int count, const mat4 &matrix, float eps) { + Box box(vec3(+INF), vec3(-INF)); + for (int i = 0; i < count; i++) { + vec4 p = matrix * vec4(points[i], 1.0f); + if (p.w > eps) + box += p.xyz / p.w; } - */ - /* - vec3 shadowBox(1024.0f, 0.0f, 1024.0f); - boxes[0] = lara->getBoundingBox(); - boxes[0] += Box(lara->pos - shadowBox, lara->pos + shadowBox); - bCount++; - Core::mProj = calcCromMatrix(Core::mProj * Core::mView, &boxes[0], bCount) * Core::mProj; - */ + return box; + } + + bool setupLightCamera() { + lara->updateLights(); + vec3 pos = lara->getBoundingBox().center(); + + mat4 mViewCamera = camera->mViewInv.inverse(); + + // get shadow casters (bbox corner points) + #define MAX_CASTER_POINTS (32 * 8) + + vec3 cPoints[32 * 8]; + int cPointsCount = 0; + + vec3 rPoints[1 * 8]; + int rPointsCount = 0; + + float rq = lara->mainLightRadius * lara->mainLightRadius; + for (int i = 0; i < level.entitiesCount; i++) { + if (cPointsCount >= MAX_CASTER_POINTS) + break; + + TR::Entity &e = level.entities[i]; + Controller *controller = (Controller*)e.controller; + if (!controller || !TR::castShadow(e.type) || rq < (lara->mainLightPos - controller->pos).length2()) + continue; + + Box box = controller->getBoundingBoxLocal(); + mat4 m = mViewCamera * controller->getMatrix(); + + for (int j = 0; j < 8; j++) + cPoints[cPointsCount++] = m * box[j]; + } + #undef MAX_CASTER_POINTS + + { + mat4 cameraViewProjInv = (camera->getProjMatrix() * mViewCamera).inverse(); + Box box(vec3(-1.0f), vec3(1.0f)); + + for (int i = 0; i < 8; i++) { + vec4 p = cameraViewProjInv * vec4(box[i], 1.0f); + rPoints[rPointsCount++] = mViewCamera * (p.xyz / p.w); + } + } + + mat4 mViewLight = mat4(mViewCamera * pos, mViewCamera * lara->mainLightPos, vec3(0, -1, 0)).inverse(); + + vec2 uP = mViewLight.dir.xy.normal(); + + float minCastersProj = 1.0f; + for (int i = 0; i < cPointsCount; i++) { + vec3 p = mViewLight * cPoints[i]; + minCastersProj = min(minCastersProj, uP.dot(p.xy)); + } + + float minReceiversProj = 1.0f; + for (int i = 0; i < rPointsCount; i++) { + vec3 p = mViewLight * rPoints[i]; + minReceiversProj = min(minReceiversProj, uP.dot(p.xy)); + } + + float eps = 0.85f; + float maxLengthP = (eps - 1.0f) / minCastersProj; //max(minCastersProj, minReceiversProj); + float lengthP = (0.05f * 0.06f) / uP.dot(mViewLight.dir.xy); + + if (maxLengthP > 0.0f && lengthP > maxLengthP) + lengthP = maxLengthP; + + mat4 mLProj(1, 0, 0, uP.x * lengthP, + 0, 1, 0, uP.y * lengthP, + 0, 0, 1, 0, + 0, 0, 0, 1); + + mat4 mLZRot(uP.x, uP.y, 0, 0, + uP.y, -uP.x, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + + mat4 mProjLight = mLZRot * mLProj * mViewLight; + + Box casters = transformPointsBox(cPoints, cPointsCount, mProjLight, eps); + Box receivers = transformPointsBox(rPoints, rPointsCount, mProjLight, eps); + Box focus = casters;//.intersection2D(receivers); + + //focus.min.z = min(casters.min.z, receivers.min.z); + //focus.max.z = max(casters.max.z, receivers.max.z); + + vec3 size = focus.size(); + + if (size.x < EPS || size.y < EPS || size.z < EPS) + return false; + + vec3 u = vec3(1.0f) / size; + + mat4 mUnitCube(u.x, 0, 0, 0, + 0, u.y, 0, 0, + 0, 0, u.z, 0, + -focus.min.x * u.x, -focus.min.y * u.y, -focus.min.z * u.z, 1); + + mat4 mUnitSpace( 2, 0, 0, 0, + 0, 2, 0, 0, + 0, 0, 2, 0, + -1, -1, -1, 1); + + Core::mView = mViewLight * mViewCamera; + Core::mProj = mUnitSpace * mUnitCube * mLZRot * mLProj; + Core::mViewProj = Core::mProj * Core::mView; + + mat4 bias; + bias.identity(); + bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; + + Core::mLightProj = bias * Core::mViewProj; + return true; + } +<-- */ + + mat4 calcCropMatrix(const mat4 &viewProj, const Box &receivers, const Box &casters) { + mat4 cameraViewProjInv = (camera->getProjMatrix() * camera->mViewInv.inverse()).inverse(); + // camera->mViewInv (mat4(camera->fov, float(Core::width) / Core::height, camera->znear, camera->zfar) * camera->mViewInv.inverse()).inverse(); + Box frustumBox = Box(vec3(-1.0f), vec3(1.0f)) * cameraViewProjInv; + + Box caster = casters;// * viewProj; + Box receiver = receivers * viewProj; + Box split = frustumBox * viewProj; + + Box crop; + crop.min.x = max(max(caster.min.x, receiver.min.x), split.min.x); + crop.max.x = min(min(caster.max.x, receiver.max.x), split.max.x); + crop.min.y = max(max(caster.min.y, receiver.min.y), split.min.y); + crop.max.y = min(min(caster.max.y, receiver.max.y), split.max.y); + crop.min.z = min(caster.min.z, split.min.z); + crop.max.z = min(receiver.max.z, split.max.z); + + mat4 m = camera->getProjMatrix(); + Box cc = receivers * m; + cc = cc * m.inverse(); + + if (!Input::down[ikShift]) { + mat4 m = viewProj.inverse(); + bRec = receivers;// * m; + bCast = casters;// * m; + bCrop = crop * m; + bSplit = split * m; + } + +// casterBox -= frustumBox * viewProj; +// crop.min.z = 0.0f; + + vec3 scale = vec3(2.0f, 2.0f, 1.0f) / crop.size(); + vec3 center = crop.center(); + vec3 offset = vec3(center.x, center.y, crop.min.z) * scale; + + return mat4(scale.x, 0.0f, 0.0f, 0.0f, + 0.0f, scale.y, 0.0f, 0.0f, + 0.0f, 0.0f, scale.z, 0.0f, + -offset.x, -offset.y, -offset.z, 1.0f); + } + + bool setupLightCamera() { + lara->updateLights(); + vec3 pos = lara->getBoundingBox().center(); + + Core::mViewInv = mat4(lara->mainLightPos, pos, vec3(0, -1, 0)); + Core::mView = Core::mViewInv.inverse(); + Core::mProj = mat4(120.0f, 1.0f, camera->znear, lara->mainLightRadius); + + mat4 bias; + bias.identity(); + bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; Core::mLightProj = bias * (Core::mProj * Core::mView); return true; } + void renderShadows(int roomIndex) { PROFILE_MARKER("PASS_SHADOW"); Core::eye = 0.0f; Core::pass = Core::passShadow; - if (!setupLightCamera()) return; shadow->unbind(sShadow); bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false; if (colorShadow) Core::setClearColor(vec4(1.0f, 1.0f, 1.0f, 1.0f)); - Core::setTarget(shadow); + Core::setTarget(shadow); + if (!setupLightCamera()) return; Core::clear(true, true); Core::setCulling(cfBack); - renderScene(roomIndex); + renderScene(roomIndex); Core::invalidateTarget(!colorShadow, colorShadow); - Core::setCulling(cfFront); + Core::setCulling(cfFront); if (colorShadow) Core::setClearColor(vec4(0.0f, 0.0f, 0.0f, 0.0f)); } @@ -851,7 +1030,7 @@ struct Level : IGame { // renderModel(level.models[modelIndex], level.entities[4]); */ Debug::begin(); - + /* lara->updateEntity(); // TODO clip angle while rotating int q = int(normalizeAngle(lara->angleExt + PI * 0.25f) / (PI * 0.5f)); @@ -882,7 +1061,7 @@ struct Level : IGame { glColor3f(1, 1, 0); p = lara->pos; glVertex3fv((GLfloat*)&p); p -= vec3(0.0f, LARA_HANG_OFFSET, 0.0f); glVertex3fv((GLfloat*)&p); glEnd(); Core::setDepthTest(true); - /* + */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); @@ -891,8 +1070,8 @@ struct Level : IGame { glLoadIdentity(); glOrtho(0, Core::width, 0, Core::height, 0, 1); - if (waterCache->visible) - waterCache->reflect->bind(sDiffuse); + if (shadow) + shadow->bind(sDiffuse); else atlas->bind(sDiffuse); glEnable(GL_TEXTURE_2D); @@ -921,10 +1100,29 @@ struct Level : IGame { glMatrixMode(GL_MODELVIEW); glPopMatrix(); - + + + Core::setDepthTest(false); + glBegin(GL_LINES); + glColor3f(1, 1, 1); + glVertex3fv((GLfloat*)&lara->pos); + glVertex3fv((GLfloat*)&lara->mainLightPos); + glEnd(); + Core::setDepthTest(true); + + Debug::Draw::sphere(lara->mainLightPos, lara->mainLightRadius, vec4(1, 1, 0, 1)); + + Box bbox = lara->getBoundingBox(); + Debug::Draw::box(bbox.min, bbox.max , vec4(1, 0, 1, 1)); + Debug::Draw::box(bRec.min, bRec.max , vec4(1, 0, 0, 1)); + Debug::Draw::box(bCast.min, bCast.max, vec4(0, 0, 1, 1)); + Debug::Draw::box(bSplit.min, bSplit.max, vec4(0, 1, 1, 1)); + Debug::Draw::box(bCrop.min, bCrop.max, vec4(0, 1, 0, 1)); + + Core::setBlending(bmAlpha); // Debug::Level::rooms(level, lara->pos, lara->getEntity().room); - // Debug::Level::lights(level, lara->getRoomIndex()); + Debug::Level::lights(level, lara->getRoomIndex(), lara); // Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y); // Core::setDepthTest(false); // Debug::Level::portals(level); diff --git a/src/mesh.h b/src/mesh.h index 2df516a..4853691 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -132,8 +132,8 @@ struct Mesh { n.y = (int)o.y;\ n.z = (int)o.z; -float intensityf(int lighting) { - if (lighting < 0) return 1.0f; +float intensityf(uint16 lighting) { + if (lighting > 0x1FFF) return 1.0f; float lum = 1.0f - (lighting >> 5) / 255.0f; //return powf(lum, 2.2f); // gamma to linear space return lum;// * lum; // gamma to "linear" space diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index 379433e..5db007c 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -281,7 +281,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords #endif #else uniform sampler2D sShadow; - #define CMP(a,b) step(b, a) + #define CMP(a,b) step(min(1.0, b), a) #ifdef SHADOW_DEPTH #define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z)); @@ -298,7 +298,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords } #endif - #define SHADOW_TEXEL (2.0 / 1024.0) + #define SHADOW_TEXEL (2.0 / SHADOW_TEX_SIZE) float random(vec3 seed, float freq) { float dt = dot(floor(seed * freq), vec3(53.1215, 21.1352, 9.1322)); @@ -338,14 +338,17 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords } else rShadow /= 4.0; - vec3 lv = vLightVec; - float fade = clamp(dot(lv, lv), 0.0, 1.0); - - return mix(rShadow, 1.0, fade); + return rShadow; } float getShadow() { - return min(dot(vNormal.xyz, vLightVec), vLightProj.w) > 0.0 ? getShadow(vLightProj) : 1.0; + vec3 p = vLightProj.xyz / vLightProj.w; + float fade = smoothstep(0.0, 0.9, p.z);// * (p.z < 1.0 ? 1.0 : 0.0); + float k = max(abs(p.x), abs(p.y)); + fade *= 1.0 - smoothstep(0.5, 1.0, k); + fade *= 1.0 - smoothstep(0.999, 1.0, max(0.0, p.z)); + + return ( fade > 0.0001 && min(dot(vNormal.xyz, vLightVec), vLightProj.w) > 0.0) ? mix(1.0, getShadow(vLightProj), fade) : 1.0; } #endif diff --git a/src/texture.h b/src/texture.h index 0fe6709..4b77c64 100644 --- a/src/texture.h +++ b/src/texture.h @@ -23,6 +23,7 @@ struct Texture { bind(0); GLenum target = cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + bool isShadow = format == SHADOW; if (format == SHADOW && !Core::support.shadowSampler) { format = DEPTH; @@ -57,8 +58,12 @@ struct Texture { glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_S, isShadow ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, isShadow ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE); + if (isShadow) { + float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color); + } glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST); glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? GL_LINEAR : GL_NEAREST); diff --git a/src/utils.h b/src/utils.h index 14fd68a..6075c76 100644 --- a/src/utils.h +++ b/src/utils.h @@ -725,6 +725,17 @@ struct Box { return min; } + Box intersection2D(const Box &b) const { + Box r(vec3(0.0f), vec3(0.0f)); + if (max.x < b.min.x || min.x > b.max.x) return r; + if (max.y < b.min.y || min.y > b.max.y) return r; + r.max.x = ::min(max.x, b.max.x); + r.max.y = ::min(max.y, b.max.y); + r.min.x = ::max(min.x, b.min.x); + r.min.y = ::max(min.y, b.min.y); + return r; + } + Box& operator += (const Box &box) { min.x = ::min(min.x, box.min.x); min.y = ::min(min.y, box.min.y); @@ -772,6 +783,11 @@ struct Box { return max - min; } + void expand(const vec3 &v) { + min -= v; + max += v; + } + void rotate90(int n) { switch (n) { case 0 : break;