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:
parent
2cd339138b
commit
916700fc0f
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; }
|
||||
|
||||
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);
|
||||
|
@ -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);
|
||||
|
45
src/core.h
45
src/core.h
@ -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() {
|
||||
|
29
src/format.h
29
src/format.h
@ -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 : {
|
||||
|
43
src/lara.h
43
src/lara.h
@ -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) {
|
||||
|
372
src/level.h
372
src/level.h
@ -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
|
||||
}
|
||||
|
325
src/mesh.h
325
src/mesh.h
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user