mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-10 15:14:28 +02: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:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@@ -34,6 +34,7 @@ struct Animation {
|
|||||||
inline operator TR::Animation* () const { return anims + index; }
|
inline operator TR::Animation* () const { return anims + index; }
|
||||||
|
|
||||||
void initOverrides() {
|
void initOverrides() {
|
||||||
|
ASSERT(model);
|
||||||
overrides = new quat[model->mCount];
|
overrides = new quat[model->mCount];
|
||||||
overrideMask = 0;
|
overrideMask = 0;
|
||||||
}
|
}
|
||||||
@@ -48,6 +49,7 @@ struct Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int setAnim(int animIndex, int animFrame = 0, bool lerpToNext = true) {
|
int setAnim(int animIndex, int animFrame = 0, bool lerpToNext = true) {
|
||||||
|
ASSERT(model);
|
||||||
TR::Animation *anim = anims + animIndex;
|
TR::Animation *anim = anims + animIndex;
|
||||||
isEnded = isPrepareToNext = false;
|
isEnded = isPrepareToNext = false;
|
||||||
offset = jump = vec3(0.0f);
|
offset = jump = vec3(0.0f);
|
||||||
@@ -127,6 +129,7 @@ struct Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool setState(int state) {
|
bool setState(int state) {
|
||||||
|
ASSERT(model);
|
||||||
TR::Animation *anim = anims + index;
|
TR::Animation *anim = anims + index;
|
||||||
|
|
||||||
if (state == anim->state)
|
if (state == anim->state)
|
||||||
@@ -198,6 +201,7 @@ struct Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mat4 getJoints(mat4 matrix, int joint, bool postRot = false, mat4 *joints = NULL) {
|
mat4 getJoints(mat4 matrix, int joint, bool postRot = false, mat4 *joints = NULL) {
|
||||||
|
ASSERT(model);
|
||||||
vec3 offset = isPrepareToNext ? this->offset : vec3(0.0f);
|
vec3 offset = isPrepareToNext ? this->offset : vec3(0.0f);
|
||||||
matrix.translate(((vec3)frameA->pos).lerp(offset + frameB->pos, delta));
|
matrix.translate(((vec3)frameA->pos).lerp(offset + frameB->pos, delta));
|
||||||
|
|
||||||
@@ -239,6 +243,8 @@ struct Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Box getBoundingBox(const vec3 &pos, int dir) {
|
Box getBoundingBox(const vec3 &pos, int dir) {
|
||||||
|
if (!model)
|
||||||
|
return Box(pos, pos);
|
||||||
vec3 min = frameA->box.min().lerp(frameB->box.min(), delta);
|
vec3 min = frameA->box.min().lerp(frameB->box.min(), delta);
|
||||||
vec3 max = frameA->box.max().lerp(frameB->box.max(), delta);
|
vec3 max = frameA->box.max().lerp(frameB->box.max(), delta);
|
||||||
Box box(min, max);
|
Box box(min, max);
|
||||||
|
@@ -10,6 +10,8 @@
|
|||||||
#define NO_OVERLAP 0x7FFFFFFF
|
#define NO_OVERLAP 0x7FFFFFFF
|
||||||
#define SPRITE_FPS 10.0f
|
#define SPRITE_FPS 10.0f
|
||||||
|
|
||||||
|
#define MAX_LAYERS 4
|
||||||
|
|
||||||
struct Controller {
|
struct Controller {
|
||||||
TR::Level *level;
|
TR::Level *level;
|
||||||
int entity;
|
int entity;
|
||||||
@@ -20,12 +22,16 @@ struct Controller {
|
|||||||
vec3 pos;
|
vec3 pos;
|
||||||
vec3 angle;
|
vec3 angle;
|
||||||
|
|
||||||
int *meshes;
|
|
||||||
int mCount;
|
|
||||||
|
|
||||||
mat4 *joints;
|
mat4 *joints;
|
||||||
int frameIndex;
|
int frameIndex;
|
||||||
|
|
||||||
|
vec3 ambient[6];
|
||||||
|
|
||||||
|
struct MeshLayer {
|
||||||
|
uint32 model;
|
||||||
|
uint32 mask;
|
||||||
|
} *layers;
|
||||||
|
|
||||||
struct ActionCommand {
|
struct ActionCommand {
|
||||||
int emitter;
|
int emitter;
|
||||||
TR::Action action;
|
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(int emitter, TR::Action action, int value, float timer, ActionCommand *next = NULL) : emitter(emitter), action(action), value(value), timer(timer), next(next) {}
|
||||||
} *actionCommand;
|
} *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();
|
TR::Entity &e = getEntity();
|
||||||
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
||||||
angle = vec3(0.0f, e.rotation, 0.0f);
|
angle = vec3(0.0f, e.rotation, 0.0f);
|
||||||
@@ -47,26 +53,28 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Controller() {
|
virtual ~Controller() {
|
||||||
delete[] meshes;
|
|
||||||
delete[] joints;
|
delete[] joints;
|
||||||
|
delete[] layers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initMeshOverrides() {
|
void initMeshOverrides() {
|
||||||
TR::Model *model = getModel();
|
layers = new MeshLayer[MAX_LAYERS];
|
||||||
mCount = model->mCount;
|
memset(layers, 0, sizeof(MeshLayer) * MAX_LAYERS);
|
||||||
meshes = mCount ? new int[mCount] : NULL;
|
layers[0].model = getEntity().modelIndex - 1;
|
||||||
for (int i = 0; i < mCount; i++)
|
layers[0].mask = 0xFFFFFFFF;
|
||||||
meshes[i] = model->mStart + i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void meshSwap(TR::Model *model, int mask = 0xFFFFFFFF) {
|
void meshSwap(int layer, uint32 model, uint32 mask = 0xFFFFFFFF) {
|
||||||
if (!meshes) initMeshOverrides();
|
if (!layers) initMeshOverrides();
|
||||||
|
|
||||||
for (int i = 0; i < model->mCount; i++) {
|
TR::Model &m = level->models[model];
|
||||||
int index = model->mStart + i;
|
for (int i = 0; i < m.mCount; i++) {
|
||||||
if (((1 << i) & mask) && level->meshOffsets[index])
|
if (((1 << i) & mask) && !level->meshOffsets[m.mStart + i] && m.mStart + i > 0)
|
||||||
meshes[i] = index;
|
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) {
|
bool aim(int target, int joint, const vec4 &angleRange, quat &rot, quat *rotAbs = NULL) {
|
||||||
@@ -401,13 +409,14 @@ struct Controller {
|
|||||||
virtual void update() {
|
virtual void update() {
|
||||||
updateAnimation(true);
|
updateAnimation(true);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
void renderMesh(MeshBuilder *mesh, uint32 offsetIndex) {
|
void renderMesh(MeshBuilder *mesh, uint32 offsetIndex) {
|
||||||
|
return;
|
||||||
MeshBuilder::MeshInfo *mInfo = mesh->meshMap[offsetIndex];
|
MeshBuilder::MeshInfo *mInfo = mesh->meshMap[offsetIndex];
|
||||||
if (!mInfo) return; // invisible mesh (offsetIndex > 0 && level.meshOffsets[offsetIndex] == 0) camera target entity etc.
|
if (!mInfo) return; // invisible mesh (offsetIndex > 0 && level.meshOffsets[offsetIndex] == 0) camera target entity etc.
|
||||||
mesh->renderMesh(mInfo);
|
mesh->renderMesh(mInfo);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
mat4 getMatrix() {
|
mat4 getMatrix() {
|
||||||
mat4 matrix;
|
mat4 matrix;
|
||||||
matrix.identity();
|
matrix.identity();
|
||||||
@@ -450,14 +459,28 @@ struct Controller {
|
|||||||
if (Core::frameIndex != frameIndex)
|
if (Core::frameIndex != frameIndex)
|
||||||
animation.getJoints(matrix, -1, true, joints);
|
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++)
|
for (int i = MAX_LAYERS - 1; i >= 0; i--) {
|
||||||
renderMesh(mesh, meshes ? meshes[i] : (model->mStart + 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;
|
frameIndex = Core::frameIndex;
|
||||||
|
|
||||||
/* // blob shadow
|
/* // blob shadow // TODO: fake AO
|
||||||
if (TR::castShadow(entity.type)) {
|
if (TR::castShadow(entity.type)) {
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
level->getFloorInfo(entity.room, entity.x, entity.y, entity.z, info);
|
level->getFloorInfo(entity.room, entity.x, entity.y, entity.z, info);
|
||||||
|
45
src/core.h
45
src/core.h
@@ -102,8 +102,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_LIGHTS 3
|
#define MAX_LIGHTS 3
|
||||||
#define MAX_SHADOW_DIST 4096
|
#define MAX_RENDER_BUFFERS 11
|
||||||
|
|
||||||
struct Shader;
|
struct Shader;
|
||||||
struct Texture;
|
struct Texture;
|
||||||
@@ -142,11 +142,13 @@ namespace Core {
|
|||||||
|
|
||||||
enum Pass { passCompose, passShadow, passAmbient, passFilter } pass;
|
enum Pass { passCompose, passShadow, passAmbient, passFilter } pass;
|
||||||
|
|
||||||
GLuint RT, RB;
|
GLuint FBO;
|
||||||
|
GLuint renderBuffers[2][MAX_RENDER_BUFFERS];
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Shader *shader;
|
Shader *shader;
|
||||||
Texture *testures[8];
|
Texture *testures[8];
|
||||||
|
GLuint VAO;
|
||||||
} active;
|
} active;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -243,10 +245,15 @@ namespace Core {
|
|||||||
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
||||||
LOG("\n");
|
LOG("\n");
|
||||||
|
|
||||||
glGenFramebuffers(1, &RT);
|
glGenFramebuffers(1, &FBO);
|
||||||
glGenRenderbuffers(1, &RB);
|
|
||||||
glBindRenderbuffer(GL_RENDERBUFFER, RB);
|
glGenRenderbuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
|
||||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 128, 128);
|
|
||||||
|
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);
|
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||||
|
|
||||||
Sound::init();
|
Sound::init();
|
||||||
@@ -258,7 +265,8 @@ namespace Core {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void free() {
|
void free() {
|
||||||
// glDeleteFrameBuffers(1, &RT);
|
// glDeleteRenderBuffers(MAX_RENDER_BUFFERS * 2, &renderBuffers[0][0]);
|
||||||
|
// glDeleteFrameBuffers(1, &FBO);
|
||||||
Sound::free();
|
Sound::free();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,16 +329,19 @@ namespace Core {
|
|||||||
if (target->cube)
|
if (target->cube)
|
||||||
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, RT);
|
int i = target->width, dummyBuffer = 0;
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
|
while (i > 1) {
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, texTarget, target->dummy ? target->dummy->ID : 0, 0);
|
dummyBuffer++;
|
||||||
if (!target->depth)
|
i >>= 1;
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, RB);
|
}
|
||||||
|
|
||||||
bool mask = !target->depth;
|
ASSERT(target->width == (1 << dummyBuffer) )
|
||||||
glColorMask(mask, mask, mask, mask);
|
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
|
||||||
// GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
|
glFramebufferTexture2D (GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
|
||||||
// glDrawBuffers(target->depth ? 0 : 1, buffers);
|
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() {
|
void resetStates() {
|
||||||
|
29
src/format.h
29
src/format.h
@@ -280,9 +280,6 @@ namespace TR {
|
|||||||
int16 intensity;
|
int16 intensity;
|
||||||
uint16 meshID;
|
uint16 meshID;
|
||||||
uint16 align; // PSX
|
uint16 align; // PSX
|
||||||
struct { // ! not exists in file !
|
|
||||||
uint16 unused:15, rendered:1;
|
|
||||||
} flags;
|
|
||||||
} *meshes;
|
} *meshes;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -817,8 +814,8 @@ namespace TR {
|
|||||||
void *cameraController;
|
void *cameraController;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Model *muzzleFlash;
|
uint16 muzzleFlash;
|
||||||
Model *puzzleSet;
|
uint16 puzzleSet;
|
||||||
} extra;
|
} extra;
|
||||||
|
|
||||||
Level(const char *name, bool demo) {
|
Level(const char *name, bool demo) {
|
||||||
@@ -932,7 +929,7 @@ namespace TR {
|
|||||||
stream.read(r.meshesCount);
|
stream.read(r.meshesCount);
|
||||||
r.meshes = r.meshesCount ? new Room::Mesh[r.meshesCount] : NULL;
|
r.meshes = r.meshesCount ? new Room::Mesh[r.meshesCount] : NULL;
|
||||||
for (int i = 0; i < r.meshesCount; i++)
|
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
|
// misc flags
|
||||||
stream.read(r.alternateRoom);
|
stream.read(r.alternateRoom);
|
||||||
stream.read(r.flags);
|
stream.read(r.flags);
|
||||||
@@ -1019,8 +1016,8 @@ namespace TR {
|
|||||||
memset(&extra, 0, sizeof(extra));
|
memset(&extra, 0, sizeof(extra));
|
||||||
for (int i = 0; i < modelsCount; i++)
|
for (int i = 0; i < modelsCount; i++)
|
||||||
switch (models[i].type) {
|
switch (models[i].type) {
|
||||||
case Entity::MUZZLE_FLASH : extra.muzzleFlash = &models[i]; break;
|
case Entity::MUZZLE_FLASH : extra.muzzleFlash = i; break;
|
||||||
case Entity::HOLE_PUZZLE_SET : extra.puzzleSet = &models[i]; break;
|
case Entity::HOLE_PUZZLE_SET : extra.puzzleSet = i; break;
|
||||||
default : ;
|
default : ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1229,6 +1226,20 @@ namespace TR {
|
|||||||
ASSERT(stream.pos - start == meshDataSize * 2);
|
ASSERT(stream.pos - start == meshDataSize * 2);
|
||||||
|
|
||||||
stream.read(meshOffsets, stream.read(meshOffsetsCount));
|
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) {
|
void readObjectTex(Stream &stream) {
|
||||||
@@ -1403,7 +1414,7 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// common methods
|
// common methods
|
||||||
Color24 getColor(int texture) {
|
Color24 getColor(int texture) const {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case VER_TR1_PC : return palette[texture & 0xFF];
|
case VER_TR1_PC : return palette[texture & 0xFF];
|
||||||
case VER_TR1_PSX : {
|
case VER_TR1_PSX : {
|
||||||
|
43
src/lara.h
43
src/lara.h
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#define DESCENT_SPEED 2048.0f
|
#define DESCENT_SPEED 2048.0f
|
||||||
#define MUZZLE_FLASH_TIME 0.1f
|
#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)
|
#define TARGET_MAX_DIST (8.0f * 1024.0f)
|
||||||
|
|
||||||
struct Lara : Character {
|
struct Lara : Character {
|
||||||
@@ -217,7 +217,7 @@ struct Lara : Character {
|
|||||||
weapons[Weapon::UZIS ].ammo = 9000;
|
weapons[Weapon::UZIS ].ammo = 9000;
|
||||||
wpnSet(Weapon::PISTOLS);
|
wpnSet(Weapon::PISTOLS);
|
||||||
} else
|
} else
|
||||||
meshSwap(&level->models[TR::MODEL_LARA_SPEC], BODY_UPPER | BODY_LOWER);
|
meshSwap(1, TR::MODEL_LARA_SPEC, BODY_UPPER | BODY_LOWER);
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
/*
|
/*
|
||||||
// gym
|
// 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_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);
|
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;
|
// swap layers
|
||||||
if (wpnCurrent == Weapon::SHOTGUN)
|
// 0 - body (full)
|
||||||
resetMask &= ~(BODY_LEG_L1 | BODY_LEG_R1);
|
// 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)
|
// mesh swap to angry Lara's head while firing (from uzis model)
|
||||||
if (wState == Weapon::IS_FIRING)
|
meshSwap(3, Weapon::UZIS, (wState == Weapon::IS_FIRING) ? BODY_HEAD : 0);
|
||||||
meshSwap(&level->models[Weapon::UZIS], BODY_HEAD);
|
|
||||||
|
wpnState = wState;
|
||||||
wpnState = wState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emptyHands() {
|
bool emptyHands() {
|
||||||
@@ -1119,7 +1122,7 @@ struct Lara : Character {
|
|||||||
|
|
||||||
vec3 p = pos + getDir() * 128.0f;
|
vec3 p = pos + getDir() * 128.0f;
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
|
// TODO: use brain
|
||||||
info.roomAbove = getRoomIndex();
|
info.roomAbove = getRoomIndex();
|
||||||
level->getFloorInfo(info.roomAbove, (int)pos.x, (int)pos.y, (int)pos.z, info);
|
level->getFloorInfo(info.roomAbove, (int)pos.x, (int)pos.y, (int)pos.z, info);
|
||||||
if (info.roomAbove == 0xFF)
|
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);
|
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);
|
} 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();
|
alignToWall();
|
||||||
pos = pos - getDir() * 96.0f; // TODO: collision wall offset
|
pos = pos - getDir() * 96.0f; // TODO: collision wall offset
|
||||||
pos.y = info.floor + LARA_HANG_OFFSET;
|
pos.y = info.floor + LARA_HANG_OFFSET;
|
||||||
@@ -1425,7 +1428,7 @@ struct Lara : Character {
|
|||||||
case STATE_USE_PUZZLE : {
|
case STATE_USE_PUZZLE : {
|
||||||
TR::Entity &item = level->entities[lastPickUp];
|
TR::Entity &item = level->entities[lastPickUp];
|
||||||
if (animation.isFrameActive(PUZZLE_FRAME))
|
if (animation.isFrameActive(PUZZLE_FRAME))
|
||||||
((Controller*)item.controller)->meshSwap(level->extra.puzzleSet);
|
((Controller*)item.controller)->meshSwap(0, level->extra.puzzleSet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1762,7 +1765,7 @@ struct Lara : Character {
|
|||||||
|
|
||||||
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
|
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
|
||||||
Core::active.shader->setParam(uModel, m);
|
Core::active.shader->setParam(uModel, m);
|
||||||
renderMesh(mesh, level->extra.muzzleFlash->mStart);
|
mesh->renderModel(level->extra.muzzleFlash);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
|
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
|
||||||
|
372
src/level.h
372
src/level.h
@@ -30,17 +30,151 @@ struct Level {
|
|||||||
|
|
||||||
TR::Level level;
|
TR::Level level;
|
||||||
Shader *shaders[shMAX];
|
Shader *shaders[shMAX];
|
||||||
Texture *atlas;
|
Texture *atlas, *cube;
|
||||||
MeshBuilder *mesh;
|
MeshBuilder *mesh;
|
||||||
|
|
||||||
Lara *lara;
|
Lara *lara;
|
||||||
Camera *camera;
|
Camera *camera;
|
||||||
Texture *shadow;
|
Texture *shadow;
|
||||||
Texture *ambient[6 * 4]; // 64, 16, 4, 1
|
|
||||||
|
|
||||||
float time;
|
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) {
|
Level(const char *name, bool demo, bool home) : level(name, demo), lara(NULL), time(0.0f) {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@@ -49,11 +183,8 @@ struct Level {
|
|||||||
mesh = new MeshBuilder(level);
|
mesh = new MeshBuilder(level);
|
||||||
|
|
||||||
shadow = new Texture(1024, 1024, true, false);
|
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();
|
initShaders();
|
||||||
initOverrides();
|
initOverrides();
|
||||||
|
|
||||||
@@ -156,6 +287,8 @@ struct Level {
|
|||||||
level.cameraController = camera;
|
level.cameraController = camera;
|
||||||
|
|
||||||
initReflections();
|
initReflections();
|
||||||
|
|
||||||
|
ambientCache = new AmbientCache(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Level() {
|
~Level() {
|
||||||
@@ -169,16 +302,16 @@ struct Level {
|
|||||||
delete shaders[i];
|
delete shaders[i];
|
||||||
|
|
||||||
delete shadow;
|
delete shadow;
|
||||||
for (int i = 0; i < 6 * 4; i++)
|
delete ambientCache;
|
||||||
delete ambient[i];
|
|
||||||
|
|
||||||
delete atlas;
|
delete atlas;
|
||||||
|
delete cube;
|
||||||
delete mesh;
|
delete mesh;
|
||||||
|
|
||||||
delete camera;
|
delete camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAtlas() {
|
void initTextures() {
|
||||||
if (!level.tilesCount) {
|
if (!level.tilesCount) {
|
||||||
atlas = NULL;
|
atlas = NULL;
|
||||||
return;
|
return;
|
||||||
@@ -212,6 +345,9 @@ struct Level {
|
|||||||
atlas = new Texture(1024, 1024, false, false, data);
|
atlas = new Texture(1024, 1024, false, false, data);
|
||||||
PROFILE_LABEL(TEXTURE, atlas->ID, "atlas");
|
PROFILE_LABEL(TEXTURE, atlas->ID, "atlas");
|
||||||
|
|
||||||
|
uint32 whitePix = 0xFFFFFFFF;
|
||||||
|
cube = new Texture(1, 1, false, true, &whitePix);
|
||||||
|
|
||||||
delete[] data;
|
delete[] data;
|
||||||
delete[] level.tiles;
|
delete[] level.tiles;
|
||||||
level.tiles = NULL;
|
level.tiles = NULL;
|
||||||
@@ -232,7 +368,7 @@ struct Level {
|
|||||||
else
|
else
|
||||||
strcat(ext, "#define SHADOW_COLOR\n");
|
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);
|
shaders[shCompose] = new Shader(SHADER, def);
|
||||||
sprintf(def, "%s#define PASS_SHADOW\n", ext);
|
sprintf(def, "%s#define PASS_SHADOW\n", ext);
|
||||||
shaders[shShadow] = new Shader(SHADER, def);
|
shaders[shShadow] = new Shader(SHADER, def);
|
||||||
@@ -280,7 +416,7 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initReflections() {
|
void initReflections() {
|
||||||
Core::resetStates();
|
Core::resetStates();
|
||||||
for (int i = 0; i < level.entitiesBaseCount; i++) {
|
for (int i = 0; i < level.entitiesBaseCount; i++) {
|
||||||
TR::Entity &e = level.entities[i];
|
TR::Entity &e = level.entities[i];
|
||||||
if (e.type == TR::Entity::CRYSTAL) {
|
if (e.type == TR::Entity::CRYSTAL) {
|
||||||
@@ -375,68 +511,34 @@ struct Level {
|
|||||||
TR::Room &room = level.rooms[roomIndex];
|
TR::Room &room = level.rooms[roomIndex];
|
||||||
vec3 offset = vec3(float(room.info.x), 0.0f, float(room.info.z));
|
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
|
// room geometry & sprites
|
||||||
if (!room.flags.rendered) { // skip if already rendered
|
if (!room.flags.rendered) { // skip if already rendered
|
||||||
mat4 mTemp = Core::mModel;
|
|
||||||
room.flags.rendered = true;
|
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
|
mat4 mTemp = Core::mModel;
|
||||||
if (Core::pass == Core::passCompose || Core::pass == Core::passAmbient) {
|
Core::mModel.translate(offset);
|
||||||
|
|
||||||
|
sh->setParam(uModel, Core::mModel);
|
||||||
|
|
||||||
|
// render room geometry
|
||||||
mesh->renderRoomGeometry(roomIndex);
|
mesh->renderRoomGeometry(roomIndex);
|
||||||
}
|
|
||||||
|
|
||||||
// render room sprites
|
// render room sprites
|
||||||
if (mesh->hasRoomSprites(roomIndex) && Core::pass != Core::passShadow) {
|
if (mesh->hasRoomSprites(roomIndex)) {
|
||||||
Core::color.w = 1.0;
|
Core::color.w = 1.0;
|
||||||
sh->setParam(uType, Shader::SPRITE);
|
sh->setParam(uType, Shader::SPRITE);
|
||||||
sh->setParam(uColor, Core::color);
|
sh->setParam(uColor, Core::color);
|
||||||
mesh->renderRoomSprites(roomIndex);
|
mesh->renderRoomSprites(roomIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::mModel = mTemp;
|
Core::mModel = mTemp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LEVEL_EDITOR
|
#ifdef LEVEL_EDITOR
|
||||||
@@ -523,9 +625,19 @@ struct Level {
|
|||||||
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
|
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
|
||||||
setRoomParams(room, intensityf(lum));
|
setRoomParams(room, intensityf(lum));
|
||||||
|
|
||||||
|
Controller *controller = (Controller*)entity.controller;
|
||||||
|
|
||||||
if (entity.modelIndex > 0) { // model
|
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(uType, Shader::ENTITY);
|
||||||
|
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.modelIndex < 0) { // sprite
|
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(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||||
Core::active.shader->setParam(uLightColor, Core::lightColor[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() {
|
void update() {
|
||||||
@@ -558,7 +670,8 @@ struct Level {
|
|||||||
|
|
||||||
camera->setup(Core::pass == Core::passCompose);
|
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)
|
if (!Core::support.VAO)
|
||||||
mesh->bind();
|
mesh->bind();
|
||||||
@@ -571,21 +684,14 @@ struct Level {
|
|||||||
sh->setParam(uViewInv, Core::mViewInv);
|
sh->setParam(uViewInv, Core::mViewInv);
|
||||||
sh->setParam(uViewPos, Core::viewPos);
|
sh->setParam(uViewPos, Core::viewPos);
|
||||||
sh->setParam(uTime, time);
|
sh->setParam(uTime, time);
|
||||||
sh->setParam(uLightTarget, lara->pos);
|
|
||||||
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||||
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||||
sh->setParam(uAmbient, cube[0], 6);
|
|
||||||
|
|
||||||
Core::mModel.identity();
|
Core::mModel.identity();
|
||||||
|
|
||||||
// clear visible flags for rooms & static meshes
|
// clear visibility flag for rooms
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
for (int i = 0; i < level.roomsCount; i++)
|
||||||
TR::Room &room = level.rooms[i];
|
level.rooms[i].flags.rendered = false;
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Core::pass != Core::passAmbient)
|
if (Core::pass != Core::passAmbient)
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
@@ -594,6 +700,11 @@ struct Level {
|
|||||||
|
|
||||||
void renderRooms(int roomIndex) {
|
void renderRooms(int roomIndex) {
|
||||||
PROFILE_MARKER("ROOMS");
|
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
|
#ifdef LEVEL_EDITOR
|
||||||
for (int i = 0; i < level.roomsCount; i++)
|
for (int i = 0; i < level.roomsCount; i++)
|
||||||
renderRoom(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) {
|
void renderShadows(int roomIndex) {
|
||||||
PROFILE_MARKER("PASS_SHADOW");
|
PROFILE_MARKER("PASS_SHADOW");
|
||||||
if (!setupLightCamera()) return;
|
if (!setupLightCamera()) return;
|
||||||
@@ -751,8 +822,9 @@ struct Level {
|
|||||||
|
|
||||||
void render() {
|
void render() {
|
||||||
Core::resetStates();
|
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());
|
renderShadows(lara->getRoomIndex());
|
||||||
renderCompose(camera->getRoomIndex());
|
renderCompose(camera->getRoomIndex());
|
||||||
|
|
||||||
@@ -783,14 +855,17 @@ struct Level {
|
|||||||
|
|
||||||
Debug::begin();
|
Debug::begin();
|
||||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
// 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::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||||
// Debug::Level::portals(level);
|
// Debug::Level::portals(level);
|
||||||
// Debug::Level::meshes(level);
|
// Debug::Level::meshes(level);
|
||||||
// Debug::Level::entities(level);
|
// Debug::Level::entities(level);
|
||||||
|
|
||||||
static int dbg_ambient = 0;
|
static int dbg_ambient = 0;
|
||||||
dbg_ambient = int(time * 2) % 4;
|
dbg_ambient = int(time * 2) % 4;
|
||||||
|
|
||||||
|
shadow->unbind(sShadow);
|
||||||
|
cube->unbind(sEnvironment);
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
@@ -807,8 +882,8 @@ struct Level {
|
|||||||
case 5 : glRotatef(180, 0, 1, 0); break;
|
case 5 : glRotatef(180, 0, 1, 0); break;
|
||||||
}
|
}
|
||||||
glTranslatef(0, 0, 256);
|
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);
|
glBegin(GL_QUADS);
|
||||||
glTexCoord2f(0, 0); glVertex3f(-256, 256, 0);
|
glTexCoord2f(0, 0); glVertex3f(-256, 256, 0);
|
||||||
glTexCoord2f(1, 0); glVertex3f( 256, 256, 0);
|
glTexCoord2f(1, 0); glVertex3f( 256, 256, 0);
|
||||||
@@ -819,7 +894,50 @@ struct Level {
|
|||||||
}
|
}
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glDisable(GL_TEXTURE_2D);
|
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();
|
shaders[shGUI]->bind();
|
||||||
Core::mViewProj = mat4(0, (float)Core::width, (float)Core::height, 0, 0, 1);
|
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_DEPTH_TEST);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
//
|
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Debug::Level::info(level, lara->getEntity(), lara->animation);
|
Debug::Level::info(level, lara->getEntity(), lara->animation);
|
||||||
Debug::end();
|
Debug::end();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
325
src/mesh.h
325
src/mesh.h
@@ -30,9 +30,11 @@ struct MeshRange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void bind(GLuint *VAO) const {
|
void bind(GLuint *VAO) const {
|
||||||
if (aIndex > -1)
|
if (aIndex > -1) {
|
||||||
glBindVertexArray(VAO[aIndex]);
|
if (Core::active.VAO != VAO[aIndex]) {
|
||||||
else
|
glBindVertexArray(Core::active.VAO = VAO[aIndex]);
|
||||||
|
}
|
||||||
|
} else
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -126,28 +128,20 @@ uint8 intensity(int lighting) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct MeshBuilder {
|
struct MeshBuilder {
|
||||||
// rooms
|
Mesh *mesh;
|
||||||
|
// level
|
||||||
struct RoomRange {
|
struct RoomRange {
|
||||||
MeshRange geometry;
|
MeshRange geometry;
|
||||||
MeshRange sprites;
|
MeshRange sprites;
|
||||||
} *roomRanges;
|
MeshRange **meshes;
|
||||||
|
} *rooms;
|
||||||
// objects meshes
|
MeshRange *models;
|
||||||
struct MeshInfo : MeshRange {
|
MeshRange *sequences;
|
||||||
int offset;
|
// procedured
|
||||||
TR::Vertex center;
|
|
||||||
TR::Collider collider;
|
|
||||||
} *meshInfo;
|
|
||||||
MeshInfo **meshMap; // meshInfo by meshOffsetIndex
|
|
||||||
|
|
||||||
MeshRange *spriteSequences;
|
|
||||||
MeshRange shadowBlob;
|
MeshRange shadowBlob;
|
||||||
MeshRange bar;
|
MeshRange bar;
|
||||||
MeshRange quad;
|
MeshRange quad;
|
||||||
|
|
||||||
// indexed mesh
|
|
||||||
Mesh *mesh;
|
|
||||||
|
|
||||||
vec2 *animTexRanges;
|
vec2 *animTexRanges;
|
||||||
vec2 *animTexOffsets;
|
vec2 *animTexOffsets;
|
||||||
|
|
||||||
@@ -155,67 +149,82 @@ struct MeshBuilder {
|
|||||||
int animTexOffsetsCount;
|
int animTexOffsetsCount;
|
||||||
|
|
||||||
TR::Level *level;
|
TR::Level *level;
|
||||||
|
TR::ObjectTexture whiteTile;
|
||||||
|
|
||||||
MeshBuilder(TR::Level &level) : level(&level) {
|
MeshBuilder(TR::Level &level) : level(&level) {
|
||||||
initAnimTextures(level);
|
initAnimTextures(level);
|
||||||
|
|
||||||
// create dummy white object textures for non-textured (colored) geometry
|
// create dummy white object textures for non-textured (colored) geometry
|
||||||
TR::ObjectTexture whiteTileQuad;
|
whiteTile.attribute = 0;
|
||||||
whiteTileQuad.attribute = 0;
|
whiteTile.tile.index = 15;
|
||||||
whiteTileQuad.tile.index = 15;
|
whiteTile.tile.triangle = 0;
|
||||||
whiteTileQuad.tile.triangle = 0;
|
whiteTile.texCoord[0] =
|
||||||
whiteTileQuad.texCoord[0] =
|
whiteTile.texCoord[1] =
|
||||||
whiteTileQuad.texCoord[1] =
|
whiteTile.texCoord[2] =
|
||||||
whiteTileQuad.texCoord[2] =
|
whiteTile.texCoord[3] = { 253, 253 };
|
||||||
whiteTileQuad.texCoord[3] = { 253, 253 };
|
|
||||||
|
|
||||||
TR::ObjectTexture whiteTileTri = whiteTileQuad;
|
|
||||||
whiteTileTri.tile.triangle = 1;
|
|
||||||
|
|
||||||
// allocate room geometry ranges
|
// allocate room geometry ranges
|
||||||
roomRanges = new RoomRange[level.roomsCount];
|
rooms = new RoomRange[level.roomsCount];
|
||||||
|
|
||||||
int iCount = 0, vCount = 0, aCount = 0;
|
int iCount = 0, vCount = 0, aCount = 0;
|
||||||
|
|
||||||
// get size of mesh for rooms (geometry & sprites)
|
// get size of mesh for rooms (geometry & sprites)
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
TR::Room::Data &d = level.rooms[i].data;
|
TR::Room &r = level.rooms[i];
|
||||||
RoomRange &r = roomRanges[i];
|
TR::Room::Data &d = r.data;
|
||||||
|
|
||||||
r.geometry.vStart = vCount;
|
RoomRange &range = rooms[i];
|
||||||
r.geometry.iStart = iCount;
|
|
||||||
|
range.geometry.vStart = vCount;
|
||||||
|
range.geometry.iStart = iCount;
|
||||||
iCount += d.rCount * 6 + d.tCount * 3;
|
iCount += d.rCount * 6 + d.tCount * 3;
|
||||||
vCount += d.rCount * 4 + d.tCount * 3;
|
vCount += d.rCount * 4 + d.tCount * 3;
|
||||||
r.geometry.iCount = iCount - r.geometry.iStart;
|
|
||||||
|
|
||||||
r.sprites.vStart = vCount;
|
for (int j = 0; j < r.meshesCount; j++) {
|
||||||
r.sprites.iStart = iCount;
|
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;
|
iCount += d.sCount * 6;
|
||||||
vCount += d.sCount * 4;
|
vCount += d.sCount * 4;
|
||||||
r.sprites.iCount = iCount - r.sprites.iStart;
|
range.sprites.iCount = iCount - range.sprites.iStart;
|
||||||
if (r.sprites.iCount)
|
if (range.sprites.iCount)
|
||||||
aCount++;
|
aCount++;
|
||||||
|
|
||||||
|
ASSERT(vCount - range.sprites.vStart < 0xFFFF);
|
||||||
}
|
}
|
||||||
aCount += level.roomsCount;
|
aCount += level.roomsCount;
|
||||||
|
|
||||||
// get objects mesh info
|
// get models info
|
||||||
for (int i = 0; i < level.meshesCount; i++) {
|
models = new MeshRange[level.modelsCount];
|
||||||
TR::Mesh &mesh = level.meshes[i];
|
for (int i = 0; i < level.modelsCount; i++) {
|
||||||
iCount += mesh.rCount * 6 + mesh.tCount * 3;
|
TR::Model &model = level.models[i];
|
||||||
vCount += mesh.rCount * 4 + mesh.tCount * 3;
|
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
|
// 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++) {
|
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
||||||
// TODO: sequences not only first frame
|
sequences[i].vStart = vCount;
|
||||||
spriteSequences[i].vStart = vCount;
|
sequences[i].iStart = iCount;
|
||||||
spriteSequences[i].iStart = iCount;
|
sequences[i].iCount = level.spriteSequences[i].sCount * 6;
|
||||||
spriteSequences[i].iCount = level.spriteSequences[i].sCount * 6;
|
|
||||||
iCount += level.spriteSequences[i].sCount * 6;
|
iCount += level.spriteSequences[i].sCount * 6;
|
||||||
vCount += level.spriteSequences[i].sCount * 4;
|
vCount += level.spriteSequences[i].sCount * 4;
|
||||||
}
|
}
|
||||||
@@ -252,7 +261,8 @@ struct MeshBuilder {
|
|||||||
|
|
||||||
// build rooms
|
// build rooms
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
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
|
// rooms geometry
|
||||||
int vStart = vCount;
|
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
|
// rooms sprites
|
||||||
vStart = vCount;
|
vStart = vCount;
|
||||||
for (int j = 0; j < d.sCount; j++) {
|
for (int j = 0; j < d.sCount; j++) {
|
||||||
@@ -303,83 +327,30 @@ struct MeshBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// build objects geometry
|
// build models geometry
|
||||||
TR::Color24 COLOR_WHITE = { 255, 255, 255 };
|
for (int i = 0; i < level.modelsCount; i++) {
|
||||||
|
TR::Model &model = level.models[i];
|
||||||
for (int i = 0; i < level.meshesCount; i++) {
|
MeshRange &range = models[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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int vStart = vCount;
|
int vStart = vCount;
|
||||||
for (int j = 0; j < mesh.rCount; j++) {
|
range.vStart = vStart;
|
||||||
TR::Rectangle &f = mesh.rectangles[j];
|
range.iStart = iCount;
|
||||||
bool textured = !(f.texture & 0x8000);
|
|
||||||
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTileQuad;
|
|
||||||
TR::Color24 c = textured ? COLOR_WHITE : level.getColor(f.texture);
|
|
||||||
|
|
||||||
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 &mesh = level.meshes[index];
|
||||||
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
|
buildMesh(mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
|
||||||
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < mesh.tCount; j++) {
|
range.iCount = iCount - range.iStart;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// build sprite sequences
|
// build sprite sequences
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++)
|
for (int i = 0; i < level.spriteSequencesCount; i++)
|
||||||
for (int j = 0; j < level.spriteSequences[i].sCount; j++) {
|
for (int j = 0; j < level.spriteSequences[i].sCount; j++) {
|
||||||
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart + 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
|
// build shadow spot
|
||||||
@@ -403,7 +374,7 @@ struct MeshBuilder {
|
|||||||
iCount += shadowBlob.iCount;
|
iCount += shadowBlob.iCount;
|
||||||
|
|
||||||
// white bar
|
// 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 + 0].coord = { 0, 0, 0, 0 };
|
||||||
vertices[vCount + 1].coord = { 1, 0, 0, 0 };
|
vertices[vCount + 1].coord = { 1, 0, 0, 0 };
|
||||||
vertices[vCount + 2].coord = { 1, 1, 0, 0 };
|
vertices[vCount + 2].coord = { 1, 1, 0, 0 };
|
||||||
@@ -418,11 +389,11 @@ struct MeshBuilder {
|
|||||||
vCount += 4;
|
vCount += 4;
|
||||||
|
|
||||||
// quad
|
// quad
|
||||||
addQuad(indices, iCount, vCount, quad.vStart, vertices, &whiteTileQuad);
|
addQuad(indices, iCount, vCount, quad.vStart, vertices, &whiteTile);
|
||||||
vertices[vCount + 0].coord = { -1, -1, 0, 0 };
|
vertices[vCount + 3].coord = { -1, -1, 0, 0 };
|
||||||
vertices[vCount + 1].coord = { 1, -1, 1, 0 };
|
vertices[vCount + 2].coord = { 1, -1, 1, 0 };
|
||||||
vertices[vCount + 2].coord = { 1, 1, 1, 1 };
|
vertices[vCount + 1].coord = { 1, 1, 1, 1 };
|
||||||
vertices[vCount + 3].coord = { -1, 1, 0, 1 };
|
vertices[vCount + 0].coord = { -1, 1, 0, 1 };
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
Vertex &v = vertices[vCount + i];
|
Vertex &v = vertices[vCount + i];
|
||||||
@@ -442,16 +413,16 @@ struct MeshBuilder {
|
|||||||
|
|
||||||
// initialize Vertex Arrays
|
// initialize Vertex Arrays
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
RoomRange &r = roomRanges[i];
|
RoomRange &r = rooms[i];
|
||||||
mesh->initRange(r.geometry);
|
mesh->initRange(r.geometry);
|
||||||
if (r.sprites.iCount)
|
if (r.sprites.iCount)
|
||||||
mesh->initRange(r.sprites);
|
mesh->initRange(r.sprites);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++)
|
for (int i = 0; i < level.spriteSequencesCount; i++)
|
||||||
mesh->initRange(spriteSequences[i]);
|
mesh->initRange(sequences[i]);
|
||||||
for (int i = 0; i < level.meshesCount; i++)
|
for (int i = 0; i < level.modelsCount; i++)
|
||||||
mesh->initRange(meshInfo[i]);
|
mesh->initRange(models[i]);
|
||||||
mesh->initRange(shadowBlob);
|
mesh->initRange(shadowBlob);
|
||||||
mesh->initRange(bar);
|
mesh->initRange(bar);
|
||||||
mesh->initRange(quad);
|
mesh->initRange(quad);
|
||||||
@@ -460,13 +431,77 @@ struct MeshBuilder {
|
|||||||
~MeshBuilder() {
|
~MeshBuilder() {
|
||||||
delete[] animTexRanges;
|
delete[] animTexRanges;
|
||||||
delete[] animTexOffsets;
|
delete[] animTexOffsets;
|
||||||
delete[] roomRanges;
|
delete[] rooms;
|
||||||
delete[] meshInfo;
|
delete[] models;
|
||||||
delete[] meshMap;
|
delete[] sequences;
|
||||||
delete[] spriteSequences;
|
|
||||||
delete mesh;
|
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) {
|
vec2 getTexCoord(const TR::ObjectTexture &tex) {
|
||||||
int tile = tex.tile.index;
|
int tile = tex.tile.index;
|
||||||
int tx = (tile % 4) * 256;
|
int tx = (tile % 4) * 256;
|
||||||
@@ -611,27 +646,23 @@ struct MeshBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderRoomGeometry(int roomIndex) {
|
void renderRoomGeometry(int roomIndex) {
|
||||||
mesh->render(roomRanges[roomIndex].geometry);
|
mesh->render(rooms[roomIndex].geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderRoomSprites(int roomIndex) {
|
void renderRoomSprites(int roomIndex) {
|
||||||
mesh->render(roomRanges[roomIndex].sprites);
|
mesh->render(rooms[roomIndex].sprites);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasRoomSprites(int roomIndex) {
|
bool hasRoomSprites(int roomIndex) {
|
||||||
return roomRanges[roomIndex].sprites.iCount > 0;
|
return rooms[roomIndex].sprites.iCount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderMesh(MeshInfo *meshInfo) {
|
void renderModel(int modelIndex) {
|
||||||
mesh->render(*meshInfo);
|
mesh->render(models[modelIndex]);
|
||||||
}
|
|
||||||
|
|
||||||
void renderMesh(int meshIndex) {
|
|
||||||
renderMesh(&meshInfo[meshIndex]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSprite(int sequenceIndex, int frame) {
|
void renderSprite(int sequenceIndex, int frame) {
|
||||||
MeshRange range = spriteSequences[sequenceIndex];
|
MeshRange range = sequences[sequenceIndex];
|
||||||
range.iCount = 6;
|
range.iCount = 6;
|
||||||
range.iStart += frame * 6;
|
range.iStart += frame * 6;
|
||||||
mesh->render(range);
|
mesh->render(range);
|
||||||
|
@@ -7,7 +7,6 @@ varying vec2 vTexCoord;
|
|||||||
varying vec4 vNormal;
|
varying vec4 vNormal;
|
||||||
varying vec3 vViewVec;
|
varying vec3 vViewVec;
|
||||||
varying vec4 vLightProj;
|
varying vec4 vLightProj;
|
||||||
varying float vLightTargetDist;
|
|
||||||
#endif
|
#endif
|
||||||
varying vec4 vColor;
|
varying vec4 vColor;
|
||||||
#endif
|
#endif
|
||||||
@@ -32,7 +31,6 @@ uniform int uType;
|
|||||||
#ifndef PASS_AMBIENT
|
#ifndef PASS_AMBIENT
|
||||||
uniform mat4 uViewInv;
|
uniform mat4 uViewInv;
|
||||||
uniform mat4 uLightProj;
|
uniform mat4 uLightProj;
|
||||||
uniform vec3 uLightTarget;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PASS_COMPOSE
|
#ifdef PASS_COMPOSE
|
||||||
@@ -88,11 +86,7 @@ uniform int uType;
|
|||||||
vColor.xyz *= abs(sin(sum / 512.0 + uTime)) * 1.5 + 0.5; // color dodge
|
vColor.xyz *= abs(sin(sum / 512.0 + uTime)) * 1.5 + 0.5; // color dodge
|
||||||
}
|
}
|
||||||
|
|
||||||
vViewVec = uViewPos - coord.xyz;
|
vViewVec = uViewPos - coord.xyz;
|
||||||
|
|
||||||
vec2 dist = (uLightTarget - coord.xyz).xz;
|
|
||||||
vLightTargetDist = dot(dist, dist) / (MAX_SHADOW_DIST * MAX_SHADOW_DIST);
|
|
||||||
|
|
||||||
vLightProj = uLightProj * coord;
|
vLightProj = uLightProj * coord;
|
||||||
|
|
||||||
vCoord = coord.xyz;
|
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 += SHADOW(p + vec3(poissonDisk[i] * 1.5, 0.0) * (1.0 / 1024.0));
|
||||||
rShadow /= 16.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);
|
return mix(rShadow, 1.0, fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
||||||
enum SamplerType { sDiffuse, sShadow, sEnvironment, sMAX };
|
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 *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
|
||||||
const char *SamplerName[sMAX] = { "sDiffuse", "sShadow", "sEnvironment" };
|
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 {
|
struct Shader {
|
||||||
GLuint ID;
|
GLuint ID;
|
||||||
|
@@ -8,9 +8,8 @@ struct Texture {
|
|||||||
int width, height;
|
int width, height;
|
||||||
bool depth;
|
bool depth;
|
||||||
bool cube;
|
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);
|
glGenTextures(1, &ID);
|
||||||
bind(0);
|
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);
|
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 (!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() {
|
virtual ~Texture() {
|
||||||
delete dummy;
|
|
||||||
glDeleteTextures(1, &ID);
|
glDeleteTextures(1, &ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -292,7 +292,7 @@ struct Crystal : Controller {
|
|||||||
Texture *environment;
|
Texture *environment;
|
||||||
|
|
||||||
Crystal(TR::Level *level, int entity) : Controller(level, entity) {
|
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() {
|
virtual ~Crystal() {
|
||||||
@@ -305,7 +305,6 @@ struct Crystal : Controller {
|
|||||||
sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge
|
sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge
|
||||||
environment->bind(sEnvironment);
|
environment->bind(sEnvironment);
|
||||||
Controller::render(frustum, mesh);
|
Controller::render(frustum, mesh);
|
||||||
environment->unbind(sEnvironment);
|
|
||||||
sh->setParam(uType, Shader::ENTITY);
|
sh->setParam(uType, Shader::ENTITY);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user