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

#15 RT management rework; #23 per-object shadows (sm atlas)

This commit is contained in:
XProger
2018-04-15 02:20:09 +03:00
parent 81c91d8b8f
commit 67d89d1e1d
9 changed files with 226 additions and 118 deletions

View File

@@ -8,8 +8,6 @@
#define NO_CLIP_PLANE 1000000.0f
#define SHADOW_TEX_SIZE 1024
#define WATER_FOG_DIST (6 * 1024)
//#define WATER_USE_GRID
#define UNDERWATER_COLOR "#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9)\n"
@@ -144,7 +142,7 @@ struct ShaderCache {
src = SHADER;
typ = typeNames[type];
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_CONTACTS %d\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_CONTACTS, WATER_FOG_DIST, SHADOW_TEX_SIZE);
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_CONTACTS %d\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEXEL vec3(1.0 / %d.0, 1.0 / %d.0, 0.0)\n#define SHADOW_OBJ_MAX %d\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_CONTACTS, WATER_FOG_DIST, SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, SHADOW_OBJ_MAX);
#ifdef MERGE_SPRITES
if (type == Shader::SPRITE)
strcat(def, "#define ALIGN_SPRITES 1\n");
@@ -211,7 +209,7 @@ struct ShaderCache {
shader->bind();
// TODO: bindable uniform block
shader->setParam(uViewProj, Core::mViewProj);
shader->setParam(uLightProj, Core::mLightProj);
shader->setParam(uLightProj, Core::mLightProj[0], SHADOW_OBJ_MAX);
shader->setParam(uViewPos, Core::viewPos);
shader->setParam(uParam, Core::params);
shader->setParam(uFogParams, Core::fogParams);
@@ -306,7 +304,7 @@ struct AmbientCache {
for (int j = 0; j < 6; j++) {
Texture *src = textures[j * 4 + i - 1];
Texture *dst = textures[j * 4 + i];
Core::setTarget(dst, CLEAR_ALL);
Core::setRenderTarget(dst, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR);
src->bind(sDiffuse);
game->getMesh()->renderQuad();
}
@@ -314,7 +312,7 @@ struct AmbientCache {
// get result color from 1x1 textures
for (int j = 0; j < 6; j++) {
Core::setTarget(textures[j * 4 + 3]);
Core::setRenderTarget(textures[j * 4 + 3], RT_STORE_COLOR);
colors[j] = Core::copyPixel(0, 0).xyz();
}
@@ -462,25 +460,24 @@ struct WaterCache {
m[(x - minX) + w * (z - minZ)] = hasWater ? 0xF800 : 0;
}
mask = new Texture(w, h, Texture::RGB16, Texture::NEAREST, m);
delete[] m;
size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size
pos = vec3(r.info.x + minX * 1024 + size.x, float(posY), r.info.z + minZ * 1024 + size.z);
data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF);
data[1] = new Texture(w * 64, h * 64, Texture::RGBA_HALF);
int *mf = new int[4 * w * 64 * h * 64];
memset(mf, 0, sizeof(int) * 4 * w * 64 * h * 64);
data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF, 0, mf);
data[1] = new Texture(w * 64, h * 64, Texture::RGBA_HALF);
delete[] mf;
caustics = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, Texture::RGBA) : NULL;
#ifdef BLUR_CAUSTICS
caustics_tmp = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, Texture::RGBA) : NULL;
#endif
mask = new Texture(w, h, Texture::RGB16, Texture::NEAREST, m);
delete[] m;
blank = false;
// texture may be initialized with trash, so...
Core::setTarget(data[0], CLEAR_ALL);
Core::validateRenderState(); // immediate clear
Core::invalidateTarget(false, true);
}
void deinit() {
@@ -631,15 +628,15 @@ struct WaterCache {
Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, -drop.strength));
item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1], CLEAR_ALL);
Core::setRenderTarget(item.data[1], RT_STORE_COLOR);
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
game->getMesh()->renderQuad();
Core::invalidateTarget(false, true);
swap(item.data[0], item.data[1]);
}
}
void step(Item &item) {
item.timer = SIMULATE_TIMESTEP;
if (item.timer < SIMULATE_TIMESTEP) return;
game->setShader(Core::passWater, Shader::WATER_STEP);
@@ -649,10 +646,9 @@ struct WaterCache {
while (item.timer >= SIMULATE_TIMESTEP) {
// water step
item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1], CLEAR_ALL);
Core::setRenderTarget(item.data[1], RT_STORE_COLOR);
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
game->getMesh()->renderQuad();
Core::invalidateTarget(false, true);
swap(item.data[0], item.data[1]);
item.timer -= SIMULATE_TIMESTEP;
}
@@ -669,9 +665,8 @@ struct WaterCache {
Core::whiteTex->bind(sReflect);
item.data[0]->bind(sNormal);
Core::setTarget(item.caustics, CLEAR_ALL);
Core::setRenderTarget(item.caustics, RT_STORE_COLOR);
game->getMesh()->renderPlane();
Core::invalidateTarget(false, true);
#ifdef BLUR_CAUSTICS
// v blur
Core::setTarget(item.caustics_tmp, CLEAR_ALL);
@@ -735,10 +730,6 @@ struct WaterCache {
if (!refract || w != refract->origWidth || h != refract->origHeight) {
delete refract;
refract = new Texture(w, h, Texture::RGBA, false);
Core::setTarget(refract, CLEAR_ALL);
Core::validateRenderState(); // immediate clear
Core::invalidateTarget(false, true);
Core::setTarget(NULL);
}
Core::copyTarget(refract, 0, 0, int(Core::viewportDef.x), int(Core::viewportDef.y), w, h); // copy framebuffer into refraction texture
}
@@ -774,8 +765,7 @@ struct WaterCache {
}
// render mirror reflection
Core::setTarget(reflect, CLEAR_ALL);
Core::validateRenderState();
Core::setRenderTarget(reflect, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR);
Camera *camera = (Camera*)game->getCamera();
game->setupBinding();
@@ -829,7 +819,6 @@ struct WaterCache {
game->renderView(TR::NO_ROOM, false, false, roomsCount, roomsList);
}
Core::invalidateTarget(false, true);
game->setClipParams(1.0f, NO_CLIP_PLANE);
camera->reflectPlane = NULL;

View File

@@ -266,8 +266,7 @@ struct Character : Controller {
void addSparks(uint32 mask) {
Sphere spheres[MAX_SPHERES];
int count;
getSpheres(spheres, count);
int count = getSpheres(spheres);
for (int i = 0; i < count; i++)
if (mask & (1 << i)) {
vec3 sprPos = spheres[i].center + (vec3(randf(), randf(), randf()) * 2.0f - 1.0f) * spheres[i].radius;

View File

@@ -699,21 +699,43 @@ struct Controller {
return animation.getBoundingBox(vec3(0, 0, 0), oriented ? getEntity().rotation.value / 0x4000 : 0);
}
void getSpheres(Sphere *spheres, int &count) {
int getSpheres(Sphere *spheres) {
const TR::Model *m = getModel();
ASSERT(m->mCount <= MAX_SPHERES);
updateJoints();
count = 0;
int count = 0;
for (int i = 0; i < m->mCount; i++) {
TR::Mesh &aMesh = level->meshes[level->meshOffsets[m->mStart + i]];
if (aMesh.radius <= 0) continue;
vec3 center = joints[i] * aMesh.center;
spheres[count++] = Sphere(center, aMesh.radius);
}
return count;
}
Box getSpheresBox(bool local = false) {
Sphere spheres[MAX_SPHERES];
int count = getSpheres(spheres);
if (count) {
if (local) {
mat4 m = getMatrix().inverseOrtho();
for (int i = 0; i < count; i++)
spheres[i].center = m * spheres[i].center;
}
Box box(spheres[0].center - vec3(spheres[0].radius), spheres[0].center + vec3(spheres[0].radius));
for (int i = 1; i < count; i++)
box += Box(spheres[i].center - vec3(spheres[i].radius), spheres[i].center + vec3(spheres[i].radius));
return box;
} else
return local ? getBoundingBoxLocal() : getBoundingBox();
}
int collide(Controller *controller, bool checkBoxes = true) {
const TR::Model *a = getModel();
const TR::Model *b = controller->getModel();
@@ -728,10 +750,9 @@ struct Controller {
Sphere aSpheres[MAX_SPHERES];
Sphere bSpheres[MAX_SPHERES];
int aCount, bCount;
getSpheres(aSpheres, aCount);
controller->getSpheres(bSpheres, bCount);
int aCount = getSpheres(aSpheres);
int bCount = controller->getSpheres(bSpheres);
int mask = 0;
for (int i = 0; i < aCount; i++)
@@ -1114,7 +1135,7 @@ struct Controller {
if ((light.color.r | light.color.g | light.color.b) == 0) continue;
vec3 dir = vec3(float(light.x), float(light.y), float(light.z)) - center;
float att = max(0.0f, 1.0f - dir.length2() / float(light.radius) / float(light.radius)) * ((light.color.r + light.color.g + light.color.b) / (3.0f * 255.0f));
float att = max(0.0f, 1.0f - dir.length2() / SQR(light.radius)) * ((light.color.r + light.color.g + light.color.b) / (3.0f * 255.0f));
if (att > maxAtt) {
maxAtt = att;

View File

@@ -5,6 +5,10 @@
#define USE_INFLATE
#endif
#ifdef _DEBUG
#define PROFILE
#endif
#include <stdio.h>
#define OS_FILEIO_CACHE
@@ -182,6 +186,13 @@
#include "utils.h"
#define SHADOW_OBJ_COLS 4
#define SHADOW_OBJ_ROWS 2
#define SHADOW_TEX_TILE 128
#define SHADOW_TEX_WIDTH (SHADOW_OBJ_COLS * SHADOW_TEX_TILE)
#define SHADOW_TEX_HEIGHT (SHADOW_OBJ_ROWS * SHADOW_TEX_TILE)
#define SHADOW_OBJ_MAX (SHADOW_OBJ_COLS * SHADOW_OBJ_ROWS)
extern void* osMutexInit ();
extern void osMutexFree (void *obj);
extern void osMutexLock (void *obj);
@@ -276,6 +287,16 @@ struct KeySet {
KeySet(InputKey key, JoyKey joy) : key(key), joy(joy) {}
};
enum RenderTargetOp {
RT_CLEAR_COLOR = 0x0001,
RT_LOAD_COLOR = 0x0002,
RT_STORE_COLOR = 0x0004,
RT_CLEAR_DEPTH = 0x0008,
RT_LOAD_DEPTH = 0x0010,
RT_STORE_DEPTH = 0x0020,
};
namespace Core {
float deltaTime;
int lastTime;
@@ -616,7 +637,8 @@ enum BlendMode { bmNone, bmAlpha, bmAdd, bmMult, bmPremult };
namespace Core {
float eye;
vec4 viewport, viewportDef;
mat4 mModel, mView, mProj, mViewProj, mViewInv, mLightProj;
mat4 mModel, mView, mProj, mViewProj, mViewInv;
mat4 mLightProj[SHADOW_OBJ_MAX];
Basis basis;
vec3 viewPos;
vec4 lightPos[MAX_LIGHTS];
@@ -651,9 +673,10 @@ namespace Core {
Shader *shader;
Texture *textures[8];
Texture *target;
uint32 targetFace;
uint32 targetOp;
vec4 viewport;
vec4 material;
uint32 targetFace;
#ifdef _PSP
Index *iBuffer;
VertexGPU *vBuffer;
@@ -670,8 +693,8 @@ namespace Core {
struct ReqTarget {
Texture *texture;
uint8 clear;
uint8 face;
uint32 op;
uint32 face;
} reqTarget;
struct Stats {
@@ -1191,8 +1214,19 @@ namespace Core {
if (!mask) return;
if (mask & RS_TARGET) {
#ifdef MOBILE
if (support.discardFrame) {
int count = 0;
GLenum discard[2];
if (!(active.targetOp & RT_STORE_COLOR)) discard[count++] = active.target ? GL_COLOR_ATTACHMENT0 : GL_COLOR_EXT;
if (!(active.targetOp & RT_STORE_DEPTH)) discard[count++] = active.target ? GL_DEPTH_ATTACHMENT : GL_DEPTH_EXT;
if (count)
glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, discard);
}
#endif
Texture *target = reqTarget.texture;
uint8 face = reqTarget.face;
uint32 face = reqTarget.face;
if (target != active.target || face != active.targetFace) {
#ifdef _PSP
@@ -1221,6 +1255,7 @@ namespace Core {
#endif
active.target = target;
active.targetOp = reqTarget.op;
active.targetFace = face;
}
}
@@ -1334,16 +1369,16 @@ namespace Core {
}
#endif
if (mask & RS_TARGET) {
if (reqTarget.clear) {
int clear = 0;
#ifdef _PSP
sceGuClear(((reqTarget.clear & CLEAR_COLOR) ? GU_COLOR_BUFFER_BIT : 0) |
((reqTarget.clear & CLEAR_DEPTH) ? GU_DEPTH_BUFFER_BIT : 0) |
GU_FAST_CLEAR_BIT);
if (reqTarget.op & RT_CLEAR_COLOR) clear |= GU_COLOR_BUFFER_BIT;
if (reqTarget.op & RT_CLEAR_DEPTH) clear |= GU_DEPTH_BUFFER_BIT;
if (clear) sceGuClear(clear | GU_FAST_CLEAR_BIT);
#else
glClear(((reqTarget.clear & CLEAR_COLOR) ? GL_COLOR_BUFFER_BIT : 0) |
((reqTarget.clear & CLEAR_DEPTH) ? GL_DEPTH_BUFFER_BIT : 0));
if (reqTarget.op & RT_CLEAR_COLOR) clear |= GL_COLOR_BUFFER_BIT;
if (reqTarget.op & RT_CLEAR_DEPTH) clear |= GL_DEPTH_BUFFER_BIT;
if (clear) glClear(clear);
#endif
}
renderState &= ~RS_TARGET;
}
@@ -1367,6 +1402,10 @@ namespace Core {
renderState |= RS_VIEWPORT;
}
void setViewport(const vec4 &vp) {
setViewport(int(vp.x), int(vp.y), int(vp.z), int(vp.w));
}
void setCulling(CullFace mode) {
renderState &= ~RS_CULL;
switch (mode) {
@@ -1415,19 +1454,7 @@ namespace Core {
renderState &= ~RS_DEPTH_TEST;
}
void invalidateTarget(bool color, bool depth) {
#ifdef MOBILE
if (support.discardFrame && (color || depth)) {
int count = 0;
GLenum discard[2];
if (color) discard[count++] = active.target ? GL_COLOR_ATTACHMENT0 : GL_COLOR_EXT;
if (depth) discard[count++] = active.target ? GL_DEPTH_ATTACHMENT : GL_DEPTH_EXT;
glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, discard);
}
#endif
}
void setTarget(Texture *target, uint8 clear = 0, uint8 face = 0) {
void setRenderTarget(Texture *target, int op, int face = 0) {
if (!target)
target = defaultTarget;
@@ -1440,7 +1467,7 @@ namespace Core {
setViewport(0, 0, target->width, target->height);
reqTarget.texture = target;
reqTarget.clear = clear;
reqTarget.op = op;
reqTarget.face = face;
renderState |= RS_TARGET;
}

View File

@@ -617,8 +617,7 @@ namespace Debug {
Debug::Draw::box(matrix, box.min, box.max, bboxIntersect ? vec4(1, 0, 0, 1): vec4(1));
Sphere spheres[MAX_SPHERES];
int count;
controller->getSpheres(spheres, count);
int count = controller->getSpheres(spheres);
for (int joint = 0; joint < count; joint++) {
Sphere &sphere = spheres[joint];

View File

@@ -1121,21 +1121,21 @@ struct Inventory {
//
#else
// vertical blur
Core::setTarget(background[1], CLEAR_COLOR);
Core::setRenderTarget(background[1], RT_STORE_COLOR);
game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false);
Core::active.shader->setParam(uParam, vec4(0, 1, 1.0f / INVENTORY_BG_SIZE, 0));;
background[0]->bind(sDiffuse);
game->getMesh()->renderQuad();
// horizontal blur
Core::setTarget(background[0], CLEAR_COLOR);
Core::setRenderTarget(background[0], RT_STORE_COLOR);
game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false);
Core::active.shader->setParam(uParam, vec4(1, 0, 1.0f / INVENTORY_BG_SIZE, 0));;
background[1]->bind(sDiffuse);
game->getMesh()->renderQuad();
// grayscale
Core::setTarget(background[1], CLEAR_COLOR);
Core::setRenderTarget(background[1], RT_STORE_COLOR);
game->setShader(Core::passFilter, Shader::FILTER_GRAYSCALE, false, false);
Core::active.shader->setParam(uParam, vec4(1, 0, 0, 0));
background[0]->bind(sDiffuse);
@@ -1144,8 +1144,6 @@ struct Inventory {
swap(background[0], background[1]);
#endif
Core::setTarget(NULL, CLEAR_ALL); // TODO: ???
Core::setDepthTest(true);
}
@@ -1389,7 +1387,6 @@ struct Inventory {
}
void renderGameBG() {
Core::setTarget(NULL, CLEAR_DEPTH);
#ifdef _PSP
return;
#endif
@@ -1492,7 +1489,8 @@ struct Inventory {
// items
game->setupBinding();
Core::mLightProj.identity();
for (int i = 0; i < SHADOW_OBJ_MAX; i++)
Core::mLightProj[i].identity();
setupCamera(aspect);

View File

@@ -1376,8 +1376,7 @@ struct Lara : Character {
t *= v.length();
v = v.normal();
Sphere spheres[MAX_SPHERES];
int count;
target->getSpheres(spheres, count);
int count = target->getSpheres(spheres);
for (int i = 0; i < count; i++) {
float st;
if (spheres[i].intersect(from, v, st)) {

View File

@@ -261,7 +261,7 @@ struct Level : IGame {
if (rebuildShadows) {
delete shadow;
shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL;
shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, Texture::SHADOW, false) : NULL;
}
if (rebuildWater) {
@@ -422,9 +422,8 @@ struct Level : IGame {
setupCubeCamera(pos, i);
Core::pass = pass;
Texture *target = (targets[0]->opt & Texture::CUBEMAP) ? targets[0] : targets[i * stride];
Core::setTarget(target, CLEAR_ALL, i);
Core::setRenderTarget(target, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR, i);
renderView(roomIndex, false, false);
Core::invalidateTarget(false, true);
}
Core::pass = tmpPass;
}
@@ -678,7 +677,7 @@ struct Level : IGame {
zoneCache = new ZoneCache(this);
ambientCache = Core::settings.detail.lighting > Core::Settings::MEDIUM ? new AmbientCache(this) : NULL;
waterCache = Core::settings.detail.water > Core::Settings::LOW ? new WaterCache(this) : NULL;
shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL;
shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, Texture::SHADOW, false) : NULL;
initReflections();
@@ -714,9 +713,6 @@ struct Level : IGame {
}
*/
Core::setTarget(NULL);
Core::validateRenderState();
Core::resetTime();
}
@@ -1278,11 +1274,10 @@ struct Level : IGame {
if (Core::settings.detail.shadows > Core::Settings::MEDIUM) {
Sphere spheres[MAX_CONTACTS];
int spheresCount;
player->getSpheres(spheres, spheresCount);
int count = player->getSpheres(spheres);
for (int i = 0; i < MAX_CONTACTS; i++)
if (i < spheresCount)
if (i < count)
Core::contacts[i] = vec4(spheres[i].center, PI * spheres[i].radius * spheres[i].radius * 0.25f);
else
Core::contacts[i] = vec4(0.0f);
@@ -1874,10 +1869,7 @@ struct Level : IGame {
}
if (water) {
//bool clear = Core::settings.detail.stereo == Core::Settings::STEREO_VR;
//clear |= Core::settings.detail.stereo == Core::Settings::STEREO_OFF && players[1] == NULL;
bool clear = true;
Core::setTarget(NULL, clear ? CLEAR_ALL : 0); // render to back buffer
Core::setRenderTarget(NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); // render to back buffer
setupBinding();
}
@@ -1935,25 +1927,112 @@ struct Level : IGame {
camera->setup(false);
}
void setupLightCamera() {
vec3 pos = player->getBoundingBox().center();
void renderEntityShadow(int index, Controller *controller, Controller *player) {
Box box = controller->getSpheresBox(true);
mat4 m = controller->getMatrix();
vec3 pos = m * box.center();
Core::mViewInv = mat4(player->mainLightPos, pos, vec3(0, -1, 0));
Core::mView = Core::mViewInv.inverseOrtho();
Core::mProj = mat4(90.0f, 1.0f, camera->znear, player->mainLightColor.w * 1.5f);
Core::mProj = mat4(90.0f, 1.0f, 1.0f, 2.0f);
mat4 mLightProj = Core::mProj * Core::mView * m;
Box crop = box * (mLightProj);
crop.min.z = max(0.0f, crop.min.z);
float sx = 2.0f / (crop.max.x - crop.min.x);
float sy = 2.0f / (crop.max.y - crop.min.y);
float sz = 2.0f / (crop.max.z - crop.min.z);
float ox = -0.5f * (crop.max.x + crop.min.x) * sx;
float oy = -0.5f * (crop.max.y + crop.min.y) * sy;
float oz = -0.5f * (crop.max.z + crop.min.z) * sz;
Core::mProj = mat4(sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
ox, oy, oz, 1) * Core::mProj;
Core::setViewProj(Core::mView, Core::mProj);
mat4 bias;
bias.identity();
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
bias.e00 = bias.e11 = bias.e22 = 0.5f;
bias.e03 = bias.e13 = bias.e23 = 0.5f;
Core::mLightProj[index] = bias * (Core::mProj * Core::mView);
Core::setBlending(bmNone);
Core::mLightProj = bias * (Core::mProj * Core::mView);
mesh->transparent = 0;
if (mesh->models[controller->getEntity().modelIndex - 1].geometry[mesh->transparent].count) {
setShader(Core::pass, Shader::ENTITY, false, false);
controller->render(NULL, mesh, Shader::ENTITY, false);
}
mesh->transparent = 1;
if (mesh->models[controller->getEntity().modelIndex - 1].geometry[mesh->transparent].count) {
setShader(Core::pass, Shader::ENTITY, false, true);
controller->render(NULL, mesh, Shader::ENTITY, false);
}
mesh->transparent = 0;
}
camera->frustum->pos = Core::viewPos;
camera->frustum->calcPlanes(Core::mViewProj);
struct NearObj {
int player;
int index;
float dist;
NearObj() {}
NearObj(int player, int index, float dist) : player(player), index(index), dist(dist) {}
};
int getNearObjects(NearObj *nearObj, int maxCount) {
int count = 0;
nearObj[count++] = NearObj(0, players[0]->entity, 0.0f);
if (players[1])
nearObj[count++] = NearObj(1, players[1]->entity, 0.0f);
int base = count;
for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &e = level.entities[i];
Controller *controller = (Controller*)e.controller;
if (controller && controller->isActive() && e.isEnemy() && e.castShadow() && controller != players[0] && controller != players[1]) {
int pIndex = 0;
float dist = (players[0]->pos - controller->pos).length2();
if (players[1]) {
float dist2 = (players[1]->pos - controller->pos).length2();
if (dist2 < dist) {
dist = dist2;
pIndex = 1;
}
}
// get index to insert
int index = base;
while (index < count) {
if (dist < nearObj[index].dist)
break;
index++;
}
// insertion
if (index < maxCount) {
if (count < maxCount)
count++;
for (int j = count - 1; j > index; j--)
nearObj[j] = nearObj[j - 1];
nearObj[index] = NearObj(pIndex, controller->entity, dist);
}
}
}
return count;
}
void renderShadows(int roomIndex) {
PROFILE_MARKER("PASS_SHADOW");
// get near objects
NearObj nearObj[SHADOW_OBJ_MAX];
int nearCount = getNearObjects(nearObj, SHADOW_OBJ_MAX);
// render to shadow map
float oldEye = Core::eye;
Core::eye = 0.0f;
@@ -1962,14 +2041,19 @@ struct Level : IGame {
bool colorShadow = shadow->format == Texture::RGBA ? true : false;
if (colorShadow)
Core::setClearColor(vec4(1.0f));
Core::setTarget(shadow, CLEAR_ALL);
setupLightCamera();
Core::setRenderTarget(shadow, RT_CLEAR_DEPTH | (colorShadow ? (RT_CLEAR_COLOR | RT_STORE_COLOR) : RT_STORE_DEPTH));
Core::validateRenderState();
Core::setCulling(cfBack);
setup();
renderView(roomIndex, false, false);
for (int i = 0; i < nearCount; i++) {
Core::setViewport((i % SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, (i / SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, SHADOW_TEX_TILE, SHADOW_TEX_TILE);
renderEntityShadow(i, (Controller*)level.entities[nearObj[i].index].controller, players[nearObj[i].player]);
}
for (int i = nearCount; i < SHADOW_OBJ_MAX; i++)
Core::mLightProj[i].identity();
Core::invalidateTarget(!colorShadow, colorShadow);
Core::setCulling(cfFront);
if (colorShadow)
Core::setClearColor(vec4(0.0f));
@@ -2032,8 +2116,8 @@ struct Level : IGame {
glLoadIdentity();
glOrtho(0, Core::width, 0, Core::height, 0, 1);
if (waterCache && waterCache->count && waterCache->items[0].caustics)
waterCache->items[0].caustics->bind(sDiffuse);
if (shadow)
shadow->bind(sDiffuse);
else
atlas->bind(sDiffuse);
glEnable(GL_TEXTURE_2D);
@@ -2043,8 +2127,8 @@ struct Level : IGame {
Core::validateRenderState();
glColor3f(10, 10, 10);
int w = Core::active.textures[sDiffuse]->width / 2;
int h = Core::active.textures[sDiffuse]->height / 2;
float w = float(Core::active.textures[sDiffuse]->width);
float h = float(Core::active.textures[sDiffuse]->height);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(w, 0);
@@ -2060,7 +2144,7 @@ struct Level : IGame {
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
*/
/*
Core::setDepthTest(false);
glBegin(GL_LINES);
@@ -2079,7 +2163,7 @@ struct Level : IGame {
Core::setDepthTest(false);
Core::validateRenderState();
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex(), lara);
// Debug::Level::lights(level, player->getRoomIndex(), player);
// Debug::Level::sectors(this, lara->getRoomIndex(), (int)lara->pos.y);
// Core::setDepthTest(false);
// Debug::Level::portals(level);
@@ -2222,16 +2306,11 @@ struct Level : IGame {
}
void renderPrepare() {
Core::invalidateTarget(true, true);
if (ambientCache)
ambientCache->processQueue();
if (shadow)
renderShadows(player->getRoomIndex());
Core::setTarget(NULL, CLEAR_ALL);
Core::validateRenderState();
}
void renderGame(bool showUI) {
@@ -2267,9 +2346,6 @@ struct Level : IGame {
params->clipSign = 1.0f;
params->waterHeight = params->clipHeight;
if (shadow && view == 1)
renderShadows(player->getRoomIndex());
if (shadow) shadow->bind(sShadow);
Core::pass = Core::passCompose;
/*
@@ -2401,8 +2477,8 @@ struct Level : IGame {
UI::end();
}
void renderInventory(bool clear) {
Core::setTarget(NULL, clear ? CLEAR_ALL : 0);
void renderInventory() {
Core::setRenderTarget(NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR);
if (!(level.isTitle() || inventory.titleTimer > 0.0f))
inventory.renderBackground();
@@ -2425,7 +2501,7 @@ struct Level : IGame {
lastTitle = title;
if (isEnded) {
Core::setTarget(NULL, CLEAR_ALL);
Core::setRenderTarget(NULL, RT_CLEAR_COLOR);
UI::begin();
UI::updateAspect(float(Core::width) / float(Core::height));
UI::textOut(vec2(0, 480 - 16), STR_LOADING, UI::aCenter, UI::width);
@@ -2444,7 +2520,7 @@ struct Level : IGame {
}
}
renderInventory(title);
renderInventory();
}
};

View File

@@ -66,7 +66,7 @@ JNI_METHOD(void, nativeInit)(JNIEnv* env, jobject obj, jstring contentDir, jstri
env->ReleaseStringUTFChars(cacheDir, str);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&Core::defaultFBO);
Game::init("level/1/LEVEL2.PSX");
Game::init();
}
JNI_METHOD(void, nativeFree)(JNIEnv* env) {