1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-01-17 21:09:00 +01:00

#23 ambient cache, shadow attenuation, merge model into one mesh, merge room and static mesh into one mesh (reduce count of DIPs by ~x10 times)

This commit is contained in:
XProger 2016-12-25 16:06:52 +03:00
parent 2cd339138b
commit 916700fc0f
12 changed files with 553 additions and 360 deletions

Binary file not shown.

View File

@ -34,6 +34,7 @@ struct Animation {
inline operator TR::Animation* () const { return anims + index; }
void initOverrides() {
ASSERT(model);
overrides = new quat[model->mCount];
overrideMask = 0;
}
@ -48,6 +49,7 @@ struct Animation {
}
int setAnim(int animIndex, int animFrame = 0, bool lerpToNext = true) {
ASSERT(model);
TR::Animation *anim = anims + animIndex;
isEnded = isPrepareToNext = false;
offset = jump = vec3(0.0f);
@ -127,6 +129,7 @@ struct Animation {
}
bool setState(int state) {
ASSERT(model);
TR::Animation *anim = anims + index;
if (state == anim->state)
@ -198,6 +201,7 @@ struct Animation {
}
mat4 getJoints(mat4 matrix, int joint, bool postRot = false, mat4 *joints = NULL) {
ASSERT(model);
vec3 offset = isPrepareToNext ? this->offset : vec3(0.0f);
matrix.translate(((vec3)frameA->pos).lerp(offset + frameB->pos, delta));
@ -239,6 +243,8 @@ struct Animation {
}
Box getBoundingBox(const vec3 &pos, int dir) {
if (!model)
return Box(pos, pos);
vec3 min = frameA->box.min().lerp(frameB->box.min(), delta);
vec3 max = frameA->box.max().lerp(frameB->box.max(), delta);
Box box(min, max);

View File

@ -10,6 +10,8 @@
#define NO_OVERLAP 0x7FFFFFFF
#define SPRITE_FPS 10.0f
#define MAX_LAYERS 4
struct Controller {
TR::Level *level;
int entity;
@ -20,12 +22,16 @@ struct Controller {
vec3 pos;
vec3 angle;
int *meshes;
int mCount;
mat4 *joints;
int frameIndex;
vec3 ambient[6];
struct MeshLayer {
uint32 model;
uint32 mask;
} *layers;
struct ActionCommand {
int emitter;
TR::Action action;
@ -37,7 +43,7 @@ struct Controller {
ActionCommand(int emitter, TR::Action action, int value, float timer, ActionCommand *next = NULL) : emitter(emitter), action(action), value(value), timer(timer), next(next) {}
} *actionCommand;
Controller(TR::Level *level, int entity) : level(level), entity(entity), animation(level, getModel()), state(animation.state), meshes(NULL), mCount(0), actionCommand(NULL) {
Controller(TR::Level *level, int entity) : level(level), entity(entity), animation(level, getModel()), state(animation.state), layers(NULL), actionCommand(NULL) {
TR::Entity &e = getEntity();
pos = vec3((float)e.x, (float)e.y, (float)e.z);
angle = vec3(0.0f, e.rotation, 0.0f);
@ -47,26 +53,28 @@ struct Controller {
}
virtual ~Controller() {
delete[] meshes;
delete[] joints;
delete[] layers;
}
void initMeshOverrides() {
TR::Model *model = getModel();
mCount = model->mCount;
meshes = mCount ? new int[mCount] : NULL;
for (int i = 0; i < mCount; i++)
meshes[i] = model->mStart + i;
layers = new MeshLayer[MAX_LAYERS];
memset(layers, 0, sizeof(MeshLayer) * MAX_LAYERS);
layers[0].model = getEntity().modelIndex - 1;
layers[0].mask = 0xFFFFFFFF;
}
void meshSwap(TR::Model *model, int mask = 0xFFFFFFFF) {
if (!meshes) initMeshOverrides();
void meshSwap(int layer, uint32 model, uint32 mask = 0xFFFFFFFF) {
if (!layers) initMeshOverrides();
for (int i = 0; i < model->mCount; i++) {
int index = model->mStart + i;
if (((1 << i) & mask) && level->meshOffsets[index])
meshes[i] = index;
TR::Model &m = level->models[model];
for (int i = 0; i < m.mCount; i++) {
if (((1 << i) & mask) && !level->meshOffsets[m.mStart + i] && m.mStart + i > 0)
mask &= ~(1 << i);
}
layers[layer].model = model;
layers[layer].mask = mask;
}
bool aim(int target, int joint, const vec4 &angleRange, quat &rot, quat *rotAbs = NULL) {
@ -401,13 +409,14 @@ struct Controller {
virtual void update() {
updateAnimation(true);
}
/*
void renderMesh(MeshBuilder *mesh, uint32 offsetIndex) {
return;
MeshBuilder::MeshInfo *mInfo = mesh->meshMap[offsetIndex];
if (!mInfo) return; // invisible mesh (offsetIndex > 0 && level.meshOffsets[offsetIndex] == 0) camera target entity etc.
mesh->renderMesh(mInfo);
}
*/
mat4 getMatrix() {
mat4 matrix;
matrix.identity();
@ -450,14 +459,28 @@ struct Controller {
if (Core::frameIndex != frameIndex)
animation.getJoints(matrix, -1, true, joints);
Core::active.shader->setParam(uModel, joints[0], model->mCount);
if (layers) {
int mask = 0;
for (int i = 0; i < model->mCount; i++)
renderMesh(mesh, meshes ? meshes[i] : (model->mStart + i));
for (int i = MAX_LAYERS - 1; i >= 0; i--) {
int vmask = layers[i].mask & ~mask;
if (!vmask) continue;
mask |= layers[i].mask;
// set meshes visibility
for (int j = 0; j < model->mCount; j++)
joints[j].e33 = (vmask & (1 << j)) ? 1.0f : -1.0f;
// render
Core::active.shader->setParam(uModel, joints[0], model->mCount);
mesh->renderModel(layers[i].model);
}
} else {
Core::active.shader->setParam(uModel, joints[0], model->mCount);
mesh->renderModel(entity.modelIndex - 1);
}
frameIndex = Core::frameIndex;
/* // blob shadow
/* // blob shadow // TODO: fake AO
if (TR::castShadow(entity.type)) {
TR::Level::FloorInfo info;
level->getFloorInfo(entity.room, entity.x, entity.y, entity.z, info);

View File

@ -102,8 +102,8 @@
#endif
#endif
#define MAX_LIGHTS 3
#define MAX_SHADOW_DIST 4096
#define MAX_LIGHTS 3
#define MAX_RENDER_BUFFERS 11
struct Shader;
struct Texture;
@ -142,11 +142,13 @@ namespace Core {
enum Pass { passCompose, passShadow, passAmbient, passFilter } pass;
GLuint RT, RB;
GLuint FBO;
GLuint renderBuffers[2][MAX_RENDER_BUFFERS];
struct {
Shader *shader;
Texture *testures[8];
GLuint VAO;
} active;
struct {
@ -243,10 +245,15 @@ namespace Core {
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
LOG("\n");
glGenFramebuffers(1, &RT);
glGenRenderbuffers(1, &RB);
glBindRenderbuffer(GL_RENDERBUFFER, RB);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 128, 128);
glGenFramebuffers(1, &FBO);
glGenRenderbuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
for (int j = 0; j < 2; j++)
for (int i = 0; i < MAX_RENDER_BUFFERS; i++) {
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffers[j][i]);
glRenderbufferStorage(GL_RENDERBUFFER, j ? GL_RGB565 : GL_DEPTH_COMPONENT16, 1 << i, 1 << i);
}
glBindRenderbuffer(GL_RENDERBUFFER, 0);
Sound::init();
@ -258,7 +265,8 @@ namespace Core {
}
void free() {
// glDeleteFrameBuffers(1, &RT);
// glDeleteRenderBuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
// glDeleteFrameBuffers(1, &FBO);
Sound::free();
}
@ -321,16 +329,19 @@ namespace Core {
if (target->cube)
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
glBindFramebuffer(GL_FRAMEBUFFER, RT);
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, texTarget, target->dummy ? target->dummy->ID : 0, 0);
if (!target->depth)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, RB);
int i = target->width, dummyBuffer = 0;
while (i > 1) {
dummyBuffer++;
i >>= 1;
}
bool mask = !target->depth;
glColorMask(mask, mask, mask, mask);
// GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
// glDrawBuffers(target->depth ? 0 : 1, buffers);
ASSERT(target->width == (1 << dummyBuffer) )
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glFramebufferTexture2D (GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
glFramebufferRenderbuffer (GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffers[target->depth][dummyBuffer]);
if (target->depth)
glColorMask(false, false, false, false);
}
void resetStates() {

View File

@ -280,9 +280,6 @@ namespace TR {
int16 intensity;
uint16 meshID;
uint16 align; // PSX
struct { // ! not exists in file !
uint16 unused:15, rendered:1;
} flags;
} *meshes;
};
@ -817,8 +814,8 @@ namespace TR {
void *cameraController;
struct {
Model *muzzleFlash;
Model *puzzleSet;
uint16 muzzleFlash;
uint16 puzzleSet;
} extra;
Level(const char *name, bool demo) {
@ -932,7 +929,7 @@ namespace TR {
stream.read(r.meshesCount);
r.meshes = r.meshesCount ? new Room::Mesh[r.meshesCount] : NULL;
for (int i = 0; i < r.meshesCount; i++)
stream.raw(&r.meshes[i], sizeof(r.meshes[i]) - (version == VER_TR1_PC ? sizeof(r.meshes[i].align) : 0) - sizeof(r.meshes[i].flags));
stream.raw(&r.meshes[i], sizeof(r.meshes[i]) - (version == VER_TR1_PC ? sizeof(r.meshes[i].align) : 0));
// misc flags
stream.read(r.alternateRoom);
stream.read(r.flags);
@ -1019,8 +1016,8 @@ namespace TR {
memset(&extra, 0, sizeof(extra));
for (int i = 0; i < modelsCount; i++)
switch (models[i].type) {
case Entity::MUZZLE_FLASH : extra.muzzleFlash = &models[i]; break;
case Entity::HOLE_PUZZLE_SET : extra.puzzleSet = &models[i]; break;
case Entity::MUZZLE_FLASH : extra.muzzleFlash = i; break;
case Entity::HOLE_PUZZLE_SET : extra.puzzleSet = i; break;
default : ;
}
}
@ -1229,6 +1226,20 @@ namespace TR {
ASSERT(stream.pos - start == meshDataSize * 2);
stream.read(meshOffsets, stream.read(meshOffsetsCount));
// remap offsets to mesh index
for (int i = 0; i < meshOffsetsCount; i++) {
int index = -1;
// if (!meshOffsets[i] && i)
// index = -1;
// else
for (int j = 0; j < meshesCount; j++)
if (meshes[j].offset == meshOffsets[i]) {
index = j;
break;
}
meshOffsets[i] = index;
}
}
void readObjectTex(Stream &stream) {
@ -1403,7 +1414,7 @@ namespace TR {
}
// common methods
Color24 getColor(int texture) {
Color24 getColor(int texture) const {
switch (version) {
case VER_TR1_PC : return palette[texture & 0xFF];
case VER_TR1_PSX : {

View File

@ -31,7 +31,7 @@
#define DESCENT_SPEED 2048.0f
#define MUZZLE_FLASH_TIME 0.1f
#define FLASH_LIGHT_COLOR vec4(0.8f, 0.7f, 0.3f, 2048 * 2048)
#define FLASH_LIGHT_COLOR vec4(0.8f, 0.7f, 0.3f, 3584 * 3584)
#define TARGET_MAX_DIST (8.0f * 1024.0f)
struct Lara : Character {
@ -217,7 +217,7 @@ struct Lara : Character {
weapons[Weapon::UZIS ].ammo = 9000;
wpnSet(Weapon::PISTOLS);
} else
meshSwap(&level->models[TR::MODEL_LARA_SPEC], BODY_UPPER | BODY_LOWER);
meshSwap(1, TR::MODEL_LARA_SPEC, BODY_UPPER | BODY_LOWER);
#ifdef _DEBUG
/*
// gym
@ -366,22 +366,25 @@ struct Lara : Character {
if (wpnState == Weapon::IS_HIDDEN && wState == Weapon::IS_ARMED) playSound(TR::SND_UNHOLSTER, pos, Sound::Flags::PAN);
if (wpnState == Weapon::IS_ARMED && wState == Weapon::IS_HIDDEN) playSound(TR::SND_HOLSTER, pos, Sound::Flags::PAN);
int resetMask = BODY_HEAD | BODY_UPPER | BODY_LOWER;
if (wpnCurrent == Weapon::SHOTGUN)
resetMask &= ~(BODY_LEG_L1 | BODY_LEG_R1);
// swap layers
// 0 - body (full)
// 1 - legs (hands, legs)
// 2 - shotgun (hands, chest)
// 3 - angry (head)
// swap weapon parts
if (wpnCurrent != Weapon::SHOTGUN) {
meshSwap(1, wpnCurrent, mask);
// have a shotgun in inventory place it on the back if another weapon is in use
meshSwap(2, Weapon::SHOTGUN, (weapons[Weapon::SHOTGUN].ammo != -1) ? BODY_CHEST : 0);
} else {
meshSwap(2, wpnCurrent, mask);
}
// restore original meshes first
meshSwap(&level->models[Weapon::EMPTY], resetMask);
// replace some parts
meshSwap(&level->models[wpnCurrent], mask);
// have a shotgun in inventory place it on the back if another weapon is in use
if (wpnCurrent != Weapon::SHOTGUN && weapons[Weapon::SHOTGUN].ammo != -1)
meshSwap(&level->models[Weapon::SHOTGUN], BODY_CHEST);
// mesh swap to angry Lara's head while firing (from uzis model)
if (wState == Weapon::IS_FIRING)
meshSwap(&level->models[Weapon::UZIS], BODY_HEAD);
wpnState = wState;
meshSwap(3, Weapon::UZIS, (wState == Weapon::IS_FIRING) ? BODY_HEAD : 0);
wpnState = wState;
}
bool emptyHands() {
@ -1119,7 +1122,7 @@ struct Lara : Character {
vec3 p = pos + getDir() * 128.0f;
TR::Level::FloorInfo info;
// TODO: use brain
info.roomAbove = getRoomIndex();
level->getFloorInfo(info.roomAbove, (int)pos.x, (int)pos.y, (int)pos.z, info);
if (info.roomAbove == 0xFF)
@ -1129,7 +1132,7 @@ struct Lara : Character {
level->getFloorInfo(info.roomAbove, (int)p.x, (int)p.y, (int)p.z, info);
} while (info.ceiling > p.y - LARA_HANG_OFFSET && info.roomAbove != 0xFF);
if (abs(int(info.floor - (p.y - LARA_HANG_OFFSET))) < 16) {
if (abs(int(info.floor - (p.y - LARA_HANG_OFFSET))) < 32) {
alignToWall();
pos = pos - getDir() * 96.0f; // TODO: collision wall offset
pos.y = info.floor + LARA_HANG_OFFSET;
@ -1425,7 +1428,7 @@ struct Lara : Character {
case STATE_USE_PUZZLE : {
TR::Entity &item = level->entities[lastPickUp];
if (animation.isFrameActive(PUZZLE_FRAME))
((Controller*)item.controller)->meshSwap(level->extra.puzzleSet);
((Controller*)item.controller)->meshSwap(0, level->extra.puzzleSet);
break;
}
}
@ -1762,7 +1765,7 @@ struct Lara : Character {
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
Core::active.shader->setParam(uModel, m);
renderMesh(mesh, level->extra.muzzleFlash->mStart);
mesh->renderModel(level->extra.muzzleFlash);
}
virtual void render(Frustum *frustum, MeshBuilder *mesh) {

View File

@ -30,17 +30,151 @@ struct Level {
TR::Level level;
Shader *shaders[shMAX];
Texture *atlas;
Texture *atlas, *cube;
MeshBuilder *mesh;
Lara *lara;
Camera *camera;
Texture *shadow;
Texture *ambient[6 * 4]; // 64, 16, 4, 1
float time;
vec3 cube[6];
struct AmbientCache {
Level *level;
struct Cube {
enum int32 {
BLANK, WAIT, READY
} status;
vec3 colors[6];
} *items;
int *offsets;
struct Task {
int room;
int sector;
Cube *cube;
} tasks[32];
int tasksCount;
Texture *textures[6 * 4]; // 64, 16, 4, 1
AmbientCache(Level *level) : level(level), tasksCount(0) {
items = NULL;
offsets = new int[level->level.roomsCount];
int sectors = 0;
for (int i = 0; i < level->level.roomsCount; i++) {
TR::Room &r = level->level.rooms[i];
offsets[i] = sectors;
sectors += r.xSectors * r.zSectors;
}
// init cache buffer
items = new Cube[sectors];
memset(items, 0, sizeof(Cube) * sectors);
// init downsample textures
for (int j = 0; j < 6; j++)
for (int i = 0; i < 4; i++)
textures[j * 4 + i] = new Texture(64 >> (i << 1), 64 >> (i << 1), false, false);
}
~AmbientCache() {
delete[] items;
delete[] offsets;
for (int i = 0; i < 6 * 4; i++)
delete textures[i];
}
void addTask(int room, int sector) {
if (tasksCount >= 32) return;
Task &task = tasks[tasksCount++];
task.room = room;
task.sector = sector;
task.cube = &items[offsets[room] + sector];
task.cube->status = Cube::WAIT;
}
void renderAmbient(int room, int sector, vec3 *colors) {
PROFILE_MARKER("PASS_AMBIENT");
TR::Room &r = level->level.rooms[room];
TR::Room::Sector &s = r.sectors[sector];
vec3 pos = vec3(float((sector / r.zSectors) * 1024 + 512 + r.info.x),
float(max((s.floor - 2) * 256, (s.floor + s.ceiling) * 256 / 2)),
float((sector % r.zSectors) * 1024 + 512 + r.info.z));
// first pass - render environment from position (room geometry & static meshes)
level->renderEnvironment(room, pos, textures, 4);
// second pass - downsample it
glDisable(GL_DEPTH_TEST);
// glDisable(GL_CULL_FACE);
level->setPassShader(Core::passFilter);
Core::active.shader->setParam(uType, Shader::DOWNSAMPLE);
for (int i = 1; i < 4; i++) {
int size = 64 >> (i << 1);
Core::active.shader->setParam(uTime, float(size << 2));
Core::setViewport(0, 0, size, size);
for (int j = 0; j < 6; j++) {
Texture *src = textures[j * 4 + i - 1];
Texture *dst = textures[j * 4 + i];
Core::setTarget(dst);
src->bind(sDiffuse);
level->mesh->renderQuad();
}
}
// get result color from 1x1 textures
for (int j = 0; j < 6; j++) {
Core::setTarget(textures[j * 4 + 3]);
TR::Color32 color;
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color);
colors[j] = vec3(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f);
}
Core::setTarget(NULL);
glEnable(GL_DEPTH_TEST);
// glEnable(GL_CULL_FACE);
}
void precessQueue() {
for (int i = 0; i < tasksCount; i++) {
Task &task = tasks[i];
renderAmbient(task.room, task.sector, &task.cube->colors[0]);
task.cube->status = Cube::READY;
}
tasksCount = 0;
}
Cube* getAmbient(int room, int sector) {
Cube *cube = &items[offsets[room] + sector];
if (cube->status == Cube::BLANK)
addTask(room, sector);
return cube->status == Cube::READY ? cube : NULL;
}
void getAmbient(int room, const vec3 &pos, Cube &value) {
TR::Room &r = level->level.rooms[room];
int sx = (int(pos.x) - r.info.x) / 1024;
int sz = (int(pos.z) - r.info.z) / 1024;
int sector = sx * r.zSectors + sz;
Cube *a = getAmbient(room, sector);
if (a) {
value = *a;
} else {
value.status = Cube::BLANK;
value.colors[0] = value.colors[1] = value.colors[2] =
value.colors[3] = value.colors[4] = value.colors[5] = vec3(intensityf(r.ambient));
}
}
} *ambientCache;
Level(const char *name, bool demo, bool home) : level(name, demo), lara(NULL), time(0.0f) {
#ifdef _DEBUG
@ -49,11 +183,8 @@ struct Level {
mesh = new MeshBuilder(level);
shadow = new Texture(1024, 1024, true, false);
for (int j = 0; j < 6; j++)
for (int i = 0; i < 4; i++)
ambient[j * 4 + i] = new Texture(64 >> (i << 1), 64 >> (i << 1), false, false);
initAtlas();
initTextures();
initShaders();
initOverrides();
@ -156,6 +287,8 @@ struct Level {
level.cameraController = camera;
initReflections();
ambientCache = new AmbientCache(this);
}
~Level() {
@ -169,16 +302,16 @@ struct Level {
delete shaders[i];
delete shadow;
for (int i = 0; i < 6 * 4; i++)
delete ambient[i];
delete ambientCache;
delete atlas;
delete cube;
delete mesh;
delete camera;
}
void initAtlas() {
void initTextures() {
if (!level.tilesCount) {
atlas = NULL;
return;
@ -212,6 +345,9 @@ struct Level {
atlas = new Texture(1024, 1024, false, false, data);
PROFILE_LABEL(TEXTURE, atlas->ID, "atlas");
uint32 whitePix = 0xFFFFFFFF;
cube = new Texture(1, 1, false, true, &whitePix);
delete[] data;
delete[] level.tiles;
level.tiles = NULL;
@ -232,7 +368,7 @@ struct Level {
else
strcat(ext, "#define SHADOW_COLOR\n");
sprintf(def, "%s#define PASS_COMPOSE\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define MAX_SHADOW_DIST %d.0\n", ext, MAX_LIGHTS, mesh->animTexRangesCount, mesh->animTexOffsetsCount, MAX_SHADOW_DIST);
sprintf(def, "%s#define PASS_COMPOSE\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n", ext, MAX_LIGHTS, mesh->animTexRangesCount, mesh->animTexOffsetsCount);
shaders[shCompose] = new Shader(SHADER, def);
sprintf(def, "%s#define PASS_SHADOW\n", ext);
shaders[shShadow] = new Shader(SHADER, def);
@ -280,7 +416,7 @@ struct Level {
}
void initReflections() {
Core::resetStates();
Core::resetStates();
for (int i = 0; i < level.entitiesBaseCount; i++) {
TR::Entity &e = level.entities[i];
if (e.type == TR::Entity::CRYSTAL) {
@ -375,68 +511,34 @@ struct Level {
TR::Room &room = level.rooms[roomIndex];
vec3 offset = vec3(float(room.info.x), 0.0f, float(room.info.z));
setRoomParams(room, intensityf(room.ambient));
Shader *sh = Core::active.shader;
Core::lightColor[0] = vec4(0, 0, 0, 1);
sh->setParam(uType, Shader::ROOM);
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
// room static meshes
if (Core::pass != Core::passShadow)
for (int i = 0; i < room.meshesCount; i++) {
TR::Room::Mesh &rMesh = room.meshes[i];
if (rMesh.flags.rendered) continue; // skip if already rendered
TR::StaticMesh *sMesh = level.getMeshByID(rMesh.meshID);
ASSERT(sMesh != NULL);
if (!mesh->meshMap[sMesh->mesh]) continue;
// check visibility
Box box;
vec3 offset = vec3((float)rMesh.x, (float)rMesh.y, (float)rMesh.z);
sMesh->getBox(false, rMesh.rotation, box);
if (!camera->frustum->isVisible(offset + box.min, offset + box.max))
continue;
rMesh.flags.rendered = true;
//Core::color.w = intensityf(rMesh.intensity);//intensityf(rMesh.intensity == -1 ? room.ambient : rMesh.intensity);
//sh->setParam(uColor, Core::color);
// render static mesh
mat4 mTemp = Core::mModel;
Core::mModel.translate(offset);
Core::mModel.rotateY(rMesh.rotation);
sh->setParam(uModel, Core::mModel);
mesh->renderMesh(mesh->meshMap[sMesh->mesh]);
Core::mModel = mTemp;
}
// room geometry & sprites
if (!room.flags.rendered) { // skip if already rendered
mat4 mTemp = Core::mModel;
if (!room.flags.rendered) { // skip if already rendered
room.flags.rendered = true;
Core::mModel.translate(offset);
if (Core::pass != Core::passShadow) {
setRoomParams(room, intensityf(room.ambient));
Shader *sh = Core::active.shader;
sh->setParam(uModel, Core::mModel);
sh->setParam(uType, Shader::ROOM);
// render room geometry
if (Core::pass == Core::passCompose || Core::pass == Core::passAmbient) {
mat4 mTemp = Core::mModel;
Core::mModel.translate(offset);
sh->setParam(uModel, Core::mModel);
// render room geometry
mesh->renderRoomGeometry(roomIndex);
}
// render room sprites
if (mesh->hasRoomSprites(roomIndex) && Core::pass != Core::passShadow) {
Core::color.w = 1.0;
sh->setParam(uType, Shader::SPRITE);
sh->setParam(uColor, Core::color);
mesh->renderRoomSprites(roomIndex);
}
// render room sprites
if (mesh->hasRoomSprites(roomIndex)) {
Core::color.w = 1.0;
sh->setParam(uType, Shader::SPRITE);
sh->setParam(uColor, Core::color);
mesh->renderRoomSprites(roomIndex);
}
Core::mModel = mTemp;
Core::mModel = mTemp;
}
}
#ifdef LEVEL_EDITOR
@ -523,9 +625,19 @@ struct Level {
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
setRoomParams(room, intensityf(lum));
Controller *controller = (Controller*)entity.controller;
if (entity.modelIndex > 0) { // model
getLight(((Controller*)entity.controller)->pos, entity.room);
vec3 pos = controller->pos;
AmbientCache::Cube cube;
if (Core::frameIndex != controller->frameIndex) {
ambientCache->getAmbient(entity.room, pos, cube);
if (cube.status == AmbientCache::Cube::READY)
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
}
getLight(pos, entity.room);
Core::active.shader->setParam(uType, Shader::ENTITY);
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
}
if (entity.modelIndex < 0) { // sprite
@ -537,7 +649,7 @@ struct Level {
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
((Controller*)entity.controller)->render(camera->frustum, mesh);
controller->render(camera->frustum, mesh);
}
void update() {
@ -558,7 +670,8 @@ struct Level {
camera->setup(Core::pass == Core::passCompose);
atlas->bind(0);
atlas->bind(sDiffuse);
cube->bind(sEnvironment); // dummy texture binding to prevent "there is no texture bound to the unit 2" warnings
if (!Core::support.VAO)
mesh->bind();
@ -571,21 +684,14 @@ struct Level {
sh->setParam(uViewInv, Core::mViewInv);
sh->setParam(uViewPos, Core::viewPos);
sh->setParam(uTime, time);
sh->setParam(uLightTarget, lara->pos);
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
sh->setParam(uAmbient, cube[0], 6);
Core::mModel.identity();
// clear visible flags for rooms & static meshes
for (int i = 0; i < level.roomsCount; i++) {
TR::Room &room = level.rooms[i];
room.flags.rendered = false; // clear visible flag for room geometry & sprites
for (int j = 0; j < room.meshesCount; j++)
room.meshes[j].flags.rendered = false; // clear visible flag for room static meshes
}
// clear visibility flag for rooms
for (int i = 0; i < level.roomsCount; i++)
level.rooms[i].flags.rendered = false;
if (Core::pass != Core::passAmbient)
for (int i = 0; i < level.entitiesCount; i++)
@ -594,6 +700,11 @@ struct Level {
void renderRooms(int roomIndex) {
PROFILE_MARKER("ROOMS");
getLight(lara->pos, lara->getRoomIndex());
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
#ifdef LEVEL_EDITOR
for (int i = 0; i < level.roomsCount; i++)
renderRoom(i);
@ -683,46 +794,6 @@ struct Level {
}
}
void renderAmbient(int roomIndex, const vec3 &pos, vec3 *cube) {
PROFILE_MARKER("PASS_AMBIENT");
renderEnvironment(roomIndex, pos, ambient, 4);
// second pass - downsample
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
setPassShader(Core::passFilter);
Core::active.shader->setParam(uType, Shader::DOWNSAMPLE);
for (int i = 1; i < 4; i++) {
int size = 64 >> (i << 1);
Core::active.shader->setParam(uTime, float(size << 2));
Core::setViewport(0, 0, size, size);
for (int j = 0; j < 6; j++) {
Texture *src = ambient[j * 4 + i - 1];
Texture *dst = ambient[j * 4 + i];
Core::setTarget(dst);
src->bind(sDiffuse);
mesh->renderQuad();
}
}
// get result color from 1x1 textures
for (int j = 0; j < 6; j++) {
Core::setTarget(ambient[j * 4 + 3]);
TR::Color32 color;
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color);
cube[j] = vec3(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f);
}
Core::setTarget(NULL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
void renderShadows(int roomIndex) {
PROFILE_MARKER("PASS_SHADOW");
if (!setupLightCamera()) return;
@ -751,8 +822,9 @@ struct Level {
void render() {
Core::resetStates();
renderAmbient(lara->getRoomIndex(), lara->pos - vec3(0, 512, 0), cube);
ambientCache->precessQueue();
//renderEnvironment(lara->getRoomIndex(), lara->pos - vec3(0, , ambientCache->textures, 4);
renderShadows(lara->getRoomIndex());
renderCompose(camera->getRoomIndex());
@ -783,14 +855,17 @@ struct Level {
Debug::begin();
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex());
Debug::Level::lights(level, lara->getRoomIndex());
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Debug::Level::portals(level);
// Debug::Level::meshes(level);
// Debug::Level::entities(level);
static int dbg_ambient = 0;
dbg_ambient = int(time * 2) % 4;
shadow->unbind(sShadow);
cube->unbind(sEnvironment);
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
@ -807,8 +882,8 @@ struct Level {
case 5 : glRotatef(180, 0, 1, 0); break;
}
glTranslatef(0, 0, 256);
shadow->unbind(sShadow);
ambient[j * 4 + dbg_ambient]->bind(sDiffuse);
ambientCache->textures[j * 4 + dbg_ambient]->bind(sDiffuse);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex3f(-256, 256, 0);
glTexCoord2f(1, 0); glVertex3f( 256, 256, 0);
@ -819,7 +894,50 @@ struct Level {
}
glEnable(GL_CULL_FACE);
glDisable(GL_TEXTURE_2D);
glLineWidth(4);
glBegin(GL_LINES);
float S = 64.0f;
for (int i = 0; i < level.roomsCount; i++) {
TR::Room &r = level.rooms[i];
for (int j = 0; j < r.xSectors * r.zSectors; j++) {
TR::Room::Sector &s = r.sectors[j];
vec3 p = vec3(float((j / r.zSectors) * 1024 + 512 + r.info.x),
float(max((s.floor - 2) * 256, (s.floor + s.ceiling) * 256 / 2)),
float((j % r.zSectors) * 1024 + 512 + r.info.z));
AmbientCache::Cube &cube = ambientCache->items[ambientCache->offsets[i] + j];
if (cube.status == AmbientCache::Cube::READY) {
glColor3fv((GLfloat*)&cube.colors[0]);
glVertex3f(p.x + 0, p.y + 0, p.z + 0);
glVertex3f(p.x + S, p.y + 0, p.z + 0);
glColor3fv((GLfloat*)&cube.colors[1]);
glVertex3f(p.x + 0, p.y + 0, p.z + 0);
glVertex3f(p.x - S, p.y + 0, p.z + 0);
glColor3fv((GLfloat*)&cube.colors[2]);
glVertex3f(p.x + 0, p.y + 0, p.z + 0);
glVertex3f(p.x + 0, p.y + S, p.z + 0);
glColor3fv((GLfloat*)&cube.colors[3]);
glVertex3f(p.x + 0, p.y + 0, p.z + 0);
glVertex3f(p.x + 0, p.y - S, p.z + 0);
glColor3fv((GLfloat*)&cube.colors[4]);
glVertex3f(p.x + 0, p.y + 0, p.z + 0);
glVertex3f(p.x + 0, p.y + 0, p.z + S);
glColor3fv((GLfloat*)&cube.colors[5]);
glVertex3f(p.x + 0, p.y + 0, p.z + 0);
glVertex3f(p.x + 0, p.y + 0, p.z - S);
}
}
}
glEnd();
glLineWidth(1);
/*
shaders[shGUI]->bind();
Core::mViewProj = mat4(0, (float)Core::width, (float)Core::height, 0, 0, 1);
@ -828,12 +946,12 @@ struct Level {
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
//
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
*/
// Debug::Level::info(level, lara->getEntity(), lara->animation);
Debug::Level::info(level, lara->getEntity(), lara->animation);
Debug::end();
#endif
}

View File

@ -30,9 +30,11 @@ struct MeshRange {
}
void bind(GLuint *VAO) const {
if (aIndex > -1)
glBindVertexArray(VAO[aIndex]);
else
if (aIndex > -1) {
if (Core::active.VAO != VAO[aIndex]) {
glBindVertexArray(Core::active.VAO = VAO[aIndex]);
}
} else
setup();
}
};
@ -126,28 +128,20 @@ uint8 intensity(int lighting) {
}
struct MeshBuilder {
// rooms
Mesh *mesh;
// level
struct RoomRange {
MeshRange geometry;
MeshRange sprites;
} *roomRanges;
// objects meshes
struct MeshInfo : MeshRange {
int offset;
TR::Vertex center;
TR::Collider collider;
} *meshInfo;
MeshInfo **meshMap; // meshInfo by meshOffsetIndex
MeshRange *spriteSequences;
MeshRange sprites;
MeshRange **meshes;
} *rooms;
MeshRange *models;
MeshRange *sequences;
// procedured
MeshRange shadowBlob;
MeshRange bar;
MeshRange quad;
// indexed mesh
Mesh *mesh;
vec2 *animTexRanges;
vec2 *animTexOffsets;
@ -155,67 +149,82 @@ struct MeshBuilder {
int animTexOffsetsCount;
TR::Level *level;
TR::ObjectTexture whiteTile;
MeshBuilder(TR::Level &level) : level(&level) {
initAnimTextures(level);
// create dummy white object textures for non-textured (colored) geometry
TR::ObjectTexture whiteTileQuad;
whiteTileQuad.attribute = 0;
whiteTileQuad.tile.index = 15;
whiteTileQuad.tile.triangle = 0;
whiteTileQuad.texCoord[0] =
whiteTileQuad.texCoord[1] =
whiteTileQuad.texCoord[2] =
whiteTileQuad.texCoord[3] = { 253, 253 };
TR::ObjectTexture whiteTileTri = whiteTileQuad;
whiteTileTri.tile.triangle = 1;
// create dummy white object textures for non-textured (colored) geometry
whiteTile.attribute = 0;
whiteTile.tile.index = 15;
whiteTile.tile.triangle = 0;
whiteTile.texCoord[0] =
whiteTile.texCoord[1] =
whiteTile.texCoord[2] =
whiteTile.texCoord[3] = { 253, 253 };
// allocate room geometry ranges
roomRanges = new RoomRange[level.roomsCount];
rooms = new RoomRange[level.roomsCount];
int iCount = 0, vCount = 0, aCount = 0;
// get size of mesh for rooms (geometry & sprites)
for (int i = 0; i < level.roomsCount; i++) {
TR::Room::Data &d = level.rooms[i].data;
RoomRange &r = roomRanges[i];
TR::Room &r = level.rooms[i];
TR::Room::Data &d = r.data;
r.geometry.vStart = vCount;
r.geometry.iStart = iCount;
RoomRange &range = rooms[i];
range.geometry.vStart = vCount;
range.geometry.iStart = iCount;
iCount += d.rCount * 6 + d.tCount * 3;
vCount += d.rCount * 4 + d.tCount * 3;
r.geometry.iCount = iCount - r.geometry.iStart;
r.sprites.vStart = vCount;
r.sprites.iStart = iCount;
for (int j = 0; j < r.meshesCount; j++) {
TR::Room::Mesh &m = r.meshes[j];
TR::StaticMesh *s = level.getMeshByID(m.meshID);
if (!level.meshOffsets[s->mesh]) continue;
TR::Mesh &mesh = level.meshes[level.meshOffsets[s->mesh]];
iCount += mesh.rCount * 6 + mesh.tCount * 3;
vCount += mesh.rCount * 4 + mesh.tCount * 3;
}
range.geometry.iCount = iCount - range.geometry.iStart;
ASSERT(vCount - range.geometry.vStart < 0xFFFF);
range.sprites.vStart = vCount;
range.sprites.iStart = iCount;
iCount += d.sCount * 6;
vCount += d.sCount * 4;
r.sprites.iCount = iCount - r.sprites.iStart;
if (r.sprites.iCount)
range.sprites.iCount = iCount - range.sprites.iStart;
if (range.sprites.iCount)
aCount++;
ASSERT(vCount - range.sprites.vStart < 0xFFFF);
}
aCount += level.roomsCount;
// get objects mesh info
for (int i = 0; i < level.meshesCount; i++) {
TR::Mesh &mesh = level.meshes[i];
iCount += mesh.rCount * 6 + mesh.tCount * 3;
vCount += mesh.rCount * 4 + mesh.tCount * 3;
// get models info
models = new MeshRange[level.modelsCount];
for (int i = 0; i < level.modelsCount; i++) {
TR::Model &model = level.models[i];
for (int j = 0; j < model.mCount; j++) {
int index = level.meshOffsets[model.mStart + j];
if (!index && model.mCount == 1) continue;
aCount++;
TR::Mesh &mesh = level.meshes[index];
iCount += mesh.rCount * 6 + mesh.tCount * 3;
vCount += mesh.rCount * 4 + mesh.tCount * 3;
}
}
aCount += level.meshesCount;
meshInfo = new MeshInfo[level.meshesCount];
meshMap = new MeshInfo*[level.meshOffsetsCount];
memset(meshMap, 0, sizeof(meshMap[0]) * level.meshOffsetsCount);
// get size of mesh for sprite sequences
spriteSequences = new MeshRange[level.spriteSequencesCount];
sequences = new MeshRange[level.spriteSequencesCount];
for (int i = 0; i < level.spriteSequencesCount; i++) {
// TODO: sequences not only first frame
spriteSequences[i].vStart = vCount;
spriteSequences[i].iStart = iCount;
spriteSequences[i].iCount = level.spriteSequences[i].sCount * 6;
sequences[i].vStart = vCount;
sequences[i].iStart = iCount;
sequences[i].iCount = level.spriteSequences[i].sCount * 6;
iCount += level.spriteSequences[i].sCount * 6;
vCount += level.spriteSequences[i].sCount * 4;
}
@ -252,7 +261,8 @@ struct MeshBuilder {
// build rooms
for (int i = 0; i < level.roomsCount; i++) {
TR::Room::Data &d = level.rooms[i].data;
TR::Room &r = level.rooms[i];
TR::Room::Data &d = r.data;
// rooms geometry
int vStart = vCount;
@ -292,6 +302,20 @@ struct MeshBuilder {
}
}
// static meshes
for (int j = 0; j < r.meshesCount; j++) {
TR::Room::Mesh &m = r.meshes[j];
TR::StaticMesh *s = level.getMeshByID(m.meshID);
if (!level.meshOffsets[s->mesh]) continue;
TR::Mesh &mesh = level.meshes[level.meshOffsets[s->mesh]];
int x = m.x - r.info.x;
int y = m.y;
int z = m.z - r.info.z;
int d = m.rotation.value / 0x4000;
buildMesh(mesh, level, indices, vertices, iCount, vCount, vStart, 0, x, y, z, d);
}
// rooms sprites
vStart = vCount;
for (int j = 0; j < d.sCount; j++) {
@ -303,83 +327,30 @@ struct MeshBuilder {
}
}
// build objects geometry
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
for (int i = 0; i < level.meshesCount; i++) {
TR::Mesh &mesh = level.meshes[i];
MeshInfo &info = meshInfo[i];
info.offset = mesh.offset;
info.vStart = vCount;
info.iStart = iCount;
info.center = mesh.center;
info.collider = mesh.collider;
if (!info.offset)
meshMap[0] = &info;
else
for (int j = 0; j < level.meshOffsetsCount; j++)
if (info.offset == level.meshOffsets[j])
meshMap[j] = &info;
int16 joint = 0;
for (int j = 0; j < level.modelsCount; j++) {
TR::Model &m = level.models[j];
for (int k = m.mStart; k < m.mStart + m.mCount; k++) {
if (mesh.offset == level.meshOffsets[k]) {
joint = k - m.mStart;
break;
}
}
}
// build models geometry
for (int i = 0; i < level.modelsCount; i++) {
TR::Model &model = level.models[i];
MeshRange &range = models[i];
int vStart = vCount;
for (int j = 0; j < mesh.rCount; j++) {
TR::Rectangle &f = mesh.rectangles[j];
bool textured = !(f.texture & 0x8000);
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTileQuad;
TR::Color24 c = textured ? COLOR_WHITE : level.getColor(f.texture);
range.vStart = vStart;
range.iStart = iCount;
addQuad(indices, iCount, vCount, vStart, vertices, &t);
for (int j = 0; j < model.mCount; j++) {
int index = level.meshOffsets[model.mStart + j];
if (!index && model.mCount == 1) continue;
for (int k = 0; k < 4; k++) {
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
vertices[vCount].coord = { v.coord.x, v.coord.y, v.coord.z, joint };
vertices[vCount].normal = v.normal;
vertices[vCount].color = { c.r, c.g, c.b, intensity(v.coord.w) };
vCount++;
}
TR::Mesh &mesh = level.meshes[index];
buildMesh(mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
}
for (int j = 0; j < mesh.tCount; j++) {
TR::Triangle &f = mesh.triangles[j];
bool textured = !(f.texture & 0x8000);
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTileQuad;
TR::Color24 c = textured ? COLOR_WHITE : level.getColor(f.texture);
addTriangle(indices, iCount, vCount, vStart, vertices, &t);
for (int k = 0; k < 3; k++) {
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
vertices[vCount].coord = { v.coord.x, v.coord.y, v.coord.z, joint };
vertices[vCount].normal = v.normal;
vertices[vCount].color = { c.r, c.g, c.b, intensity(v.coord.w) };
vCount++;
}
}
info.iCount = iCount - info.iStart;
range.iCount = iCount - range.iStart;
}
// build sprite sequences
for (int i = 0; i < level.spriteSequencesCount; i++)
for (int j = 0; j < level.spriteSequences[i].sCount; j++) {
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart + j];
addSprite(indices, vertices, iCount, vCount, spriteSequences[i].vStart, 0, 0, 0, sprite, 255);
addSprite(indices, vertices, iCount, vCount, sequences[i].vStart, 0, 0, 0, sprite, 255);
}
// build shadow spot
@ -403,7 +374,7 @@ struct MeshBuilder {
iCount += shadowBlob.iCount;
// white bar
addQuad(indices, iCount, vCount, bar.vStart, vertices, &whiteTileQuad);
addQuad(indices, iCount, vCount, bar.vStart, vertices, &whiteTile);
vertices[vCount + 0].coord = { 0, 0, 0, 0 };
vertices[vCount + 1].coord = { 1, 0, 0, 0 };
vertices[vCount + 2].coord = { 1, 1, 0, 0 };
@ -418,11 +389,11 @@ struct MeshBuilder {
vCount += 4;
// quad
addQuad(indices, iCount, vCount, quad.vStart, vertices, &whiteTileQuad);
vertices[vCount + 0].coord = { -1, -1, 0, 0 };
vertices[vCount + 1].coord = { 1, -1, 1, 0 };
vertices[vCount + 2].coord = { 1, 1, 1, 1 };
vertices[vCount + 3].coord = { -1, 1, 0, 1 };
addQuad(indices, iCount, vCount, quad.vStart, vertices, &whiteTile);
vertices[vCount + 3].coord = { -1, -1, 0, 0 };
vertices[vCount + 2].coord = { 1, -1, 1, 0 };
vertices[vCount + 1].coord = { 1, 1, 1, 1 };
vertices[vCount + 0].coord = { -1, 1, 0, 1 };
for (int i = 0; i < 4; i++) {
Vertex &v = vertices[vCount + i];
@ -442,16 +413,16 @@ struct MeshBuilder {
// initialize Vertex Arrays
for (int i = 0; i < level.roomsCount; i++) {
RoomRange &r = roomRanges[i];
RoomRange &r = rooms[i];
mesh->initRange(r.geometry);
if (r.sprites.iCount)
mesh->initRange(r.sprites);
}
for (int i = 0; i < level.spriteSequencesCount; i++)
mesh->initRange(spriteSequences[i]);
for (int i = 0; i < level.meshesCount; i++)
mesh->initRange(meshInfo[i]);
mesh->initRange(sequences[i]);
for (int i = 0; i < level.modelsCount; i++)
mesh->initRange(models[i]);
mesh->initRange(shadowBlob);
mesh->initRange(bar);
mesh->initRange(quad);
@ -460,13 +431,77 @@ struct MeshBuilder {
~MeshBuilder() {
delete[] animTexRanges;
delete[] animTexOffsets;
delete[] roomRanges;
delete[] meshInfo;
delete[] meshMap;
delete[] spriteSequences;
delete[] rooms;
delete[] models;
delete[] sequences;
delete mesh;
}
inline short4 rotate(const short4 &v, int dir) {
if (dir == 0) return v;
short4 res = v;
switch (dir) {
case 1 : res.x = v.z, res.z = -v.x; break;
case 2 : res.x = -v.x, res.z = -v.z; break;
case 3 : res.x = -v.z, res.z = v.x; break;
default : ASSERT(false);
}
return res;
}
inline short4 transform(const short4 &v, int joint, int x, int y, int z, int dir) {
short4 res = rotate(v, dir);
res.x += x;
res.y += y;
res.z += z;
res.w = joint;
return res;
}
void buildMesh(const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) {
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
for (int j = 0; j < mesh.rCount; j++) {
TR::Rectangle &f = mesh.rectangles[j];
bool textured = !(f.texture & 0x8000);
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile;
TR::Color24 c = textured ? COLOR_WHITE : level.getColor(f.texture);
addQuad(indices, iCount, vCount, vStart, vertices, &t);
for (int k = 0; k < 4; k++) {
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
vertices[vCount].coord = transform(v.coord, joint, x, y, z, dir);
vertices[vCount].normal = rotate(v.normal, dir);
vertices[vCount].color = { c.r, c.g, c.b, intensity(v.coord.w) };
vCount++;
}
}
for (int j = 0; j < mesh.tCount; j++) {
TR::Triangle &f = mesh.triangles[j];
bool textured = !(f.texture & 0x8000);
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile;
TR::Color24 c = textured ? COLOR_WHITE : level.getColor(f.texture);
addTriangle(indices, iCount, vCount, vStart, vertices, &t);
for (int k = 0; k < 3; k++) {
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
vertices[vCount].coord = transform(v.coord, joint, x, y, z, dir);
vertices[vCount].normal = rotate(v.normal, dir);
vertices[vCount].color = { c.r, c.g, c.b, intensity(v.coord.w) };
vCount++;
}
}
}
vec2 getTexCoord(const TR::ObjectTexture &tex) {
int tile = tex.tile.index;
int tx = (tile % 4) * 256;
@ -611,27 +646,23 @@ struct MeshBuilder {
}
void renderRoomGeometry(int roomIndex) {
mesh->render(roomRanges[roomIndex].geometry);
mesh->render(rooms[roomIndex].geometry);
}
void renderRoomSprites(int roomIndex) {
mesh->render(roomRanges[roomIndex].sprites);
mesh->render(rooms[roomIndex].sprites);
}
bool hasRoomSprites(int roomIndex) {
return roomRanges[roomIndex].sprites.iCount > 0;
return rooms[roomIndex].sprites.iCount > 0;
}
void renderMesh(MeshInfo *meshInfo) {
mesh->render(*meshInfo);
}
void renderMesh(int meshIndex) {
renderMesh(&meshInfo[meshIndex]);
void renderModel(int modelIndex) {
mesh->render(models[modelIndex]);
}
void renderSprite(int sequenceIndex, int frame) {
MeshRange range = spriteSequences[sequenceIndex];
MeshRange range = sequences[sequenceIndex];
range.iCount = 6;
range.iStart += frame * 6;
mesh->render(range);

View File

@ -7,7 +7,6 @@ varying vec2 vTexCoord;
varying vec4 vNormal;
varying vec3 vViewVec;
varying vec4 vLightProj;
varying float vLightTargetDist;
#endif
varying vec4 vColor;
#endif
@ -32,7 +31,6 @@ uniform int uType;
#ifndef PASS_AMBIENT
uniform mat4 uViewInv;
uniform mat4 uLightProj;
uniform vec3 uLightTarget;
#endif
#ifdef PASS_COMPOSE
@ -88,11 +86,7 @@ uniform int uType;
vColor.xyz *= abs(sin(sum / 512.0 + uTime)) * 1.5 + 0.5; // color dodge
}
vViewVec = uViewPos - coord.xyz;
vec2 dist = (uLightTarget - coord.xyz).xz;
vLightTargetDist = dot(dist, dist) / (MAX_SHADOW_DIST * MAX_SHADOW_DIST);
vViewVec = uViewPos - coord.xyz;
vLightProj = uLightProj * coord;
vCoord = coord.xyz;
@ -185,7 +179,9 @@ uniform int uType;
rShadow += SHADOW(p + vec3(poissonDisk[i] * 1.5, 0.0) * (1.0 / 1024.0));
rShadow /= 16.0;
float fade = min(1.0, vLightTargetDist);
vec3 lv = uLightPos[0].xyz - vCoord.xyz;
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
return mix(rShadow, 1.0, fade);
}

View File

@ -5,11 +5,11 @@
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
enum SamplerType { sDiffuse, sShadow, sEnvironment, sMAX };
enum UniformType { uType, uCaustics, uTime, uViewProj, uViewInv, uModel, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uLightTarget, uAnimTexRanges, uAnimTexOffsets, uMAX };
enum UniformType { uType, uCaustics, uTime, uViewProj, uViewInv, uModel, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uMAX };
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
const char *SamplerName[sMAX] = { "sDiffuse", "sShadow", "sEnvironment" };
const char *UniformName[uMAX] = { "uType", "uCaustics", "uTime", "uViewProj", "uViewInv", "uModel", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uLightTarget", "uAnimTexRanges", "uAnimTexOffsets" };
const char *UniformName[uMAX] = { "uType", "uCaustics", "uTime", "uViewProj", "uViewInv", "uModel", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets" };
struct Shader {
GLuint ID;

View File

@ -8,9 +8,8 @@ struct Texture {
int width, height;
bool depth;
bool cube;
Texture *dummy;
Texture(int width, int height, bool depth, bool cube, void *data = NULL) : width(width), height(height), cube(cube), dummy(NULL) {
Texture(int width, int height, bool depth, bool cube, void *data = NULL) : width(width), height(height), cube(cube) {
glGenTextures(1, &ID);
bind(0);
@ -39,13 +38,9 @@ struct Texture {
glTexImage2D(cube ? (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i) : GL_TEXTURE_2D, 0, format, width, height, 0, format, depth ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, data);
if (!cube) break;
}
if (depth)
dummy = new Texture(width, height, false, false, NULL); // some drivers can't render to texture without color target, create dummy color target for fix it
}
virtual ~Texture() {
delete dummy;
glDeleteTextures(1, &ID);
}

View File

@ -292,7 +292,7 @@ struct Crystal : Controller {
Texture *environment;
Crystal(TR::Level *level, int entity) : Controller(level, entity) {
environment = new Texture(128, 128, false, true);
environment = new Texture(64, 64, false, true);
}
virtual ~Crystal() {
@ -305,7 +305,6 @@ struct Crystal : Controller {
sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge
environment->bind(sEnvironment);
Controller::render(frustum, mesh);
environment->unbind(sEnvironment);
sh->setParam(uType, Shader::ENTITY);
}
};