1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-04-20 19:11:50 +02:00

#3 ground & underwater movement

#4 ceiling collisions
This commit is contained in:
XProger 2016-09-04 00:05:53 +03:00
parent 1d3a3c6d2f
commit 5d390a7f7d
7 changed files with 752 additions and 596 deletions

Binary file not shown.

View File

@ -122,7 +122,7 @@ struct Camera {
} *frustum;
float fov, znear, zfar;
vec3 pos, angle, offset;
vec3 pos, angle, offset, deltaPos, deltaAngle, targetDeltaPos, targetAngle;
Camera() : frustum(new Frustum()) {}
@ -141,12 +141,14 @@ struct Camera {
if (Input::down[ikA]) v = v - dir.cross(vec3(0, 1, 0));
pos = pos + v.normal() * (Core::deltaTime * 2048.0f);
#endif
deltaPos = deltaPos.lerp(targetDeltaPos, Core::deltaTime * 10.0f);
angle = angle.lerp(targetAngle, Core::deltaTime);
if (Input::down[ikMouseL]) {
vec2 delta = Input::mouse.pos - Input::mouse.start.L;
angle.x -= delta.y * 0.01f;
angle.y -= delta.x * 0.01f;
angle.x = min(max(angle.x, -PI * 0.5f + EPS), PI * 0.5f - EPS);
deltaAngle.x -= delta.y * 0.01f;
deltaAngle.y -= delta.x * 0.01f;
deltaAngle.x = min(max(deltaAngle.x + angle.x, -PI * 0.5f + EPS), PI * 0.5f - EPS) - angle.x;
Input::mouse.start.L = Input::mouse.pos;
}
}
@ -154,10 +156,10 @@ struct Camera {
void setup() {
Core::mView.identity();
Core::mView.translate(vec3(-offset.x, -offset.y, -offset.z));
Core::mView.rotateZ(-angle.z);
Core::mView.rotateX(-angle.x);
Core::mView.rotateY(-angle.y);
Core::mView.translate(vec3(-pos.x, -pos.y, -pos.z));
Core::mView.rotateZ(-(angle.z + deltaAngle.z));
Core::mView.rotateX(-(angle.x + deltaAngle.x));
Core::mView.rotateY(-(angle.y + deltaAngle.y));
Core::mView.translate(deltaPos - pos);
Core::mView.scale(vec3(-1, -1, 1));
Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);

View File

@ -6,310 +6,27 @@
#define GRAVITY 7.0f
struct Controller {
TR::Level *level;
int entity;
TR::Level *level;
int entity;
TR::Animation *anim;
float fTime;
float fTime;
int lastFrame;
vec3 pos, velocity;
float angle;
vec3 pos, velocity;
vec3 angle;
int state; // target state
int lastFrame;
int health;
int sc;
bool lState;
bool onGround;
float turnTime;
Controller(TR::Level *level, int entity) : level(level), entity(entity), pos(0.0f), velocity(0.0f), angle(0.0f), fTime(0.0f) {
anim = &level->anims[getModel().animation];
lastFrame = 0;
bool onGround;
bool inWater;
TR::Entity &e = level->entities[entity];
pos = vec3((float)e.x, (float)e.y, (float)e.z);
angle = e.rotation / 16384.0f * PI * 0.5f;
sc = 0;
lState = false;
state = TR::STATE_STOP;
}
void update() {
float rot = 0.0f;
enum { LEFT = 1, RIGHT = 2, FORTH = 4, BACK = 8,
JUMP = 16, WALK = 32, ACTION = 64, WEAPON = 128, ROLL = 256,
GROUND = 512, WATER = 1024, DEATH = 2048,
PULL = 4096, PICKUP = 8192, SWITCH_ON = 16 * 1024, SWITCH_OFF = 32 * 1024, KEY = 64 * 1024, PUZZLE = 128 * 1024, HANG = 256 * 1024, FALL = 512 * 1024, COMPRESS = 1024 * 1024};
int mask = 0;
if (Input::down[ikW] || Input::joy.L.y < 0) mask |= FORTH;
if (Input::down[ikS] || Input::joy.L.y > 0) mask |= BACK;
if (Input::down[ikA] || Input::joy.L.x < 0) mask |= LEFT;
if (Input::down[ikD] || Input::joy.L.x > 0) mask |= RIGHT;
if (Input::down[ikSpace] || Input::down[ikJoyX]) mask |= JUMP;
if (Input::down[ikShift] || Input::down[ikJoyLT]) mask |= WALK;
if (Input::down[ikE] || /*Input::down[ikMouseL] ||*/ Input::down[ikJoyA]) mask |= ACTION;
if (Input::down[ikQ] || Input::down[ikMouseR] || Input::down[ikJoyY]) mask |= WEAPON;
if (onGround) mask |= GROUND;
if (getRoom().flags & 1) mask |= WATER;
if (velocity.y > 2048) mask |= FALL;
if (anim->state == TR::STATE_COMPRESS) mask |= COMPRESS;
int origMask = mask;
if (origMask & (FORTH | BACK))
mask &= ~(LEFT | RIGHT);
int stateMask[TR::STATE_MAX];
for (int i = 0; i < TR::STATE_MAX; i++)
stateMask[i] = -1;
stateMask[TR::STATE_WALK] = GROUND | FORTH | WALK;
stateMask[TR::STATE_RUN] = GROUND | FORTH;
stateMask[TR::STATE_STOP] = GROUND;
stateMask[TR::STATE_FORWARD_JUMP] = GROUND | JUMP | FORTH;
// stateMask[TR::STATE_FAST_TURN] = 0;
stateMask[TR::STATE_FAST_BACK] = GROUND | BACK;
stateMask[TR::STATE_TURN_RIGHT] = GROUND | RIGHT;
stateMask[TR::STATE_TURN_LEFT] = GROUND | LEFT;
stateMask[TR::STATE_DEATH] = DEATH;
stateMask[TR::STATE_FAST_FALL] = FALL;
stateMask[TR::STATE_HANG] = HANG | ACTION;
stateMask[TR::STATE_REACH] = ACTION;
// stateMask[TR::STATE_SPLAT]
// stateMask[TR::STATE_TREAD]
// stateMask[TR::STATE_FAST_TURN_14]
stateMask[TR::STATE_COMPRESS] = GROUND | JUMP;
stateMask[TR::STATE_BACK] = GROUND | WALK | BACK;
stateMask[TR::STATE_SWIM] = WATER | JUMP;
// stateMask[TR::STATE_GLIDE]
// stateMask[TR::STATE_NULL_19]
// stateMask[TR::STATE_FAST_TURN_20]
stateMask[TR::STATE_FAST_TURN_20] = GROUND | LEFT | RIGHT;
stateMask[TR::STATE_STEP_RIGHT] = GROUND | WALK | RIGHT;
stateMask[TR::STATE_STEP_LEFT] = GROUND | WALK | LEFT;
stateMask[TR::STATE_ROLL] = GROUND | ROLL;
// stateMask[TR::STATE_SLIDE]
stateMask[TR::STATE_BACK_JUMP] = GROUND | COMPRESS | BACK;
stateMask[TR::STATE_RIGHT_JUMP] = GROUND | COMPRESS | RIGHT;
stateMask[TR::STATE_LEFT_JUMP] = GROUND | COMPRESS | LEFT;
stateMask[TR::STATE_UP_JUMP] = GROUND | COMPRESS;
stateMask[TR::STATE_DIVE] = WATER;
stateMask[TR::STATE_PUSH_PULL_READY] = GROUND | ACTION | PULL;
stateMask[TR::STATE_PICK_UP] = GROUND | ACTION | PICKUP;
stateMask[TR::STATE_SWITCH_ON] = GROUND | ACTION | SWITCH_ON;
stateMask[TR::STATE_SWITCH_OFF] = GROUND | ACTION | SWITCH_OFF;
stateMask[TR::STATE_USE_KEY] = GROUND | ACTION | KEY;
stateMask[TR::STATE_USE_PUZZLE] = GROUND | ACTION | PUZZLE;
stateMask[TR::STATE_GLIDE] = WATER | JUMP;
stateMask[TR::STATE_SWAN_DIVE] = JUMP | WALK | FORTH;
stateMask[TR::STATE_TREAD] = WATER | GROUND;
stateMask[TR::STATE_UNDERWATER_DEATH] = WATER | DEATH;
fTime += Core::deltaTime;
int fCount = anim->frameEnd - anim->frameStart + 1;
int fIndex = int(fTime * 30.0f);
state = -1;
int maxMask = 0;
if (stateMask[anim->state] != mask)
for (int i = 0; i < anim->scCount; i++) {
TR::AnimState &sc = level->states[anim->scOffset + i];
if (sc.state >= TR::STATE_MAX || stateMask[sc.state] == -1)
LOG("unknown state %d\n", sc.state);
else
if (stateMask[sc.state] > maxMask && ((stateMask[sc.state] & mask) == stateMask[sc.state])) {
maxMask = stateMask[sc.state];
state = anim->scOffset + i;
}
}
if (state > -1 && anim->state != level->states[state].state) {
TR::AnimState &sc = level->states[state];
for (int j = 0; j < sc.rangesCount; j++) {
TR::AnimRange &range = level->ranges[sc.rangesOffset + j];
if ( anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high) {
int st = anim->state;
anim = &level->anims[range.nextAnimation];
fIndex = range.nextFrame - anim->frameStart;
fCount = anim->frameEnd - anim->frameStart + 1;
fTime = fIndex / 30.0f;
break;
}
}
}
#ifdef _DEBUG
if (Input::down[ikEnter]) {
if (!lState) {
lState = true;
// state = TR::STATE_ROLL;
// fTime = 0;
// sc = (sc + 1) % level->statesCount;
// anim = &level->anims[146];//level->ranges[ level->states[sc].rangesOffset ].nextAnimation ];
// fTime = 0;
// state = level->states[sc].state;
LOG("state: %d\n", anim->state);
for (int i = 0; i < anim->scCount; i++) {
auto &sc = level->states[anim->scOffset + i];
LOG("-> %d : ", (int)sc.state);
for (int j = 0; j < sc.rangesCount; j++) {
TR::AnimRange &range = level->ranges[sc.rangesOffset + j];
LOG("%d ", range.nextAnimation);
//range.
}
LOG("\n");
}
}
} else
lState = false;
#endif
if (anim->state == TR::STATE_RUN ||
anim->state == TR::STATE_FAST_BACK ||
anim->state == TR::STATE_WALK ||
anim->state == TR::STATE_BACK ||
anim->state == TR::STATE_TURN_LEFT ||
anim->state == TR::STATE_TURN_RIGHT) {
if (origMask & LEFT) angle -= Core::deltaTime * PI;
if (origMask & RIGHT) angle += Core::deltaTime * PI;
}
float d = 0.0f;
switch (anim->state) {
case TR::STATE_BACK :
case TR::STATE_BACK_JUMP :
case TR::STATE_FAST_BACK :
d = PI;
break;
case TR::STATE_STEP_LEFT :
case TR::STATE_LEFT_JUMP :
d = -PI * 0.5f;
break;
case TR::STATE_STEP_RIGHT :
case TR::STATE_RIGHT_JUMP :
d = PI * 0.5f;
break;
}
d += angle;
bool endFrame = fIndex >= fCount;
int16 *ptr = &level->commands[anim->animCommand];
for (int i = 0; i < anim->acCount; i++) {
switch (*ptr++) {
case 0x01 : { // cmd position
int16 sx = *ptr++;
int16 sy = *ptr++;
int16 sz = *ptr++;
LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz);
break;
}
case 0x02 : { // cmd jump speed
int16 sy = *ptr++;
int16 sz = *ptr++;
if (endFrame) {
LOG("jump: %d %d\n", (int)sy, (int)sz);
velocity.x = sinf(d) * sz;
velocity.y = sy;
velocity.z = cosf(d) * sz;
onGround = false;
}
break;
}
case 0x03 : // empty hands
break;
case 0x04 : // kill
break;
case 0x05 : { // play sound
int frame = (*ptr++);
int id = (*ptr++) & 0x3FFF;
if (fIndex == frame - anim->frameStart && fIndex != lastFrame) {
auto a = level->soundsMap[id];
auto b = level->soundsInfo[a].index;
auto c = level->soundOffsets[b];
void *p = &level->soundData[c];
#ifdef WIN32
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
#endif
}
break;
}
case 0x06 :
if (fIndex != lastFrame && fIndex + anim->frameStart == ptr[0]) {
if (ptr[1] == 0) {
angle = angle + PI;
}
}
ptr += 2;
break;
}
}
float dt = Core::deltaTime * 30.0f;
if (onGround) {
float speed = anim->speed.toFloat() + anim->accel.toFloat() * (fTime * 30.0f);
velocity.x = sinf(d) * speed;
velocity.z = cosf(d) * speed;
}
velocity.y += GRAVITY * dt;
if (endFrame) {
fIndex = anim->nextFrame;
int id = anim->nextAnimation;
anim = &level->anims[anim->nextAnimation];
fIndex -= anim->frameStart;
fTime = fIndex / 30.0f;
fCount = anim->frameEnd - anim->frameStart + 1;
}
move(velocity * dt);
collide();
lastFrame = fIndex;
}
void move(const vec3 &offset) {
vec3 p = pos;
pos = pos + offset;
updateEntity();
TR::Room &room = getRoom();
TR::Entity &entity = getEntity();
int dx, dz;
TR::Room::Sector &s = getSector(dx, dz);
int d = entity.y - s.floor * 256;
if (d >= 256 * 4) {
pos.x = p.x;//vec3(entity.x, entity.y, entity.z);
pos.z = p.z;
updateEntity();
if (d >= 256 * 4)
anim = &level->anims[53]; // forward smash
else
anim = &level->anims[11]; // instant stand
state = anim->state;
fTime = 0;
}
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), fTime(0.0f), lastFrame(0), health(100), turnTime(0.0f) {
TR::Entity &e = getEntity();
pos = vec3((float)e.x, (float)e.y, (float)e.z);
angle = vec3(0.0f, e.rotation / 16384.0f * PI * 0.5f, 0.0f);
onGround = inWater = false;
}
void updateEntity() {
@ -317,7 +34,7 @@ struct Controller {
e.x = int(pos.x);
e.y = int(pos.y);
e.z = int(pos.z);
e.rotation = int(angle / (PI * 0.5f) * 16384.0f);
e.rotation = int(angle.y / (PI * 0.5f) * 16384.0f);
}
bool insideRoom(const vec3 &pos, int room) {
@ -361,12 +78,418 @@ struct Controller {
return room.sectors[sx * room.zSectors + sz];
}
bool changeState(int state) {
TR::Model &model = getModel();
TR::Animation *anim = &level->anims[model.animation];
if (state == anim->state)
return true;
int fIndex = int(fTime * 30.0f);
bool exists = false;
for (int i = 0; i < anim->scCount; i++) {
TR::AnimState &s = level->states[anim->scOffset + i];
if (s.state == state) {
exists = true;
for (int j = 0; j < s.rangesCount; j++) {
TR::AnimRange &range = level->ranges[s.rangesOffset + j];
if (anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high) {
model.animation = range.nextAnimation;
fTime = (range.nextFrame - level->anims[model.animation].frameStart) / 30.0f;
break;
}
}
}
}
return exists;
}
virtual void update() {}
};
#define FAST_TURN_TIME 1.0f
#define TURN_FAST PI
#define TURN_FAST_BACK PI * 3.0f / 4.0f
#define TURN_NORMAL PI / 2.0f
#define TURN_SLOW PI / 3.0f
#define TURN_TILT PI / 18.0f
#define TURN_WATER_FAST PI * 3.0f / 4.0f
#define TURN_WATER_SLOW PI * 2.0f / 3.0f
#define GLIDE_SPEED 50.0f
struct Lara : Controller {
int sc;
bool lState;
Lara(TR::Level *level, int entity) : Controller(level, entity) {
pos = vec3(70067, -256, 29104);
angle = vec3(0.0f, -0.68f, 0.0f);
getEntity().room = 15;
}
virtual void update() {
TR::Model &model = getModel();
TR::Animation *anim = &level->anims[model.animation];
float rot = 0.0f;
enum { LEFT = 1 << 1,
RIGHT = 1 << 2,
FORTH = 1 << 3,
BACK = 1 << 4,
JUMP = 1 << 5,
WALK = 1 << 6,
ACTION = 1 << 7,
WEAPON = 1 << 8,
GROUND = 1 << 9,
WATER = 1 << 10,
DEATH = 1 << 11 };
int mask = 0;
if (Input::down[ikW] || Input::joy.L.y < 0) mask |= FORTH;
if (Input::down[ikS] || Input::joy.L.y > 0) mask |= BACK;
if (Input::down[ikA] || Input::joy.L.x < 0) mask |= LEFT;
if (Input::down[ikD] || Input::joy.L.x > 0) mask |= RIGHT;
if (Input::down[ikSpace] || Input::down[ikJoyX]) mask |= JUMP;
if (Input::down[ikShift] || Input::down[ikJoyLT]) mask |= WALK;
if (Input::down[ikE] || Input::down[ikMouseL] || Input::down[ikJoyA]) mask |= ACTION;
if (Input::down[ikQ] || Input::down[ikMouseR] || Input::down[ikJoyY]) mask |= WEAPON;
if (health <= 0) mask |= DEATH;
if (onGround) mask |= GROUND;
if (inWater) mask |= WATER;
int state = anim->state;
if ((mask & (GROUND | WATER)) == (GROUND | WATER)) { // on water surface
angle.x = 0.0f;
state = TR::STATE_SURF_TREAD;
} else if (mask & GROUND) {
angle.x = 0.0f;
if (state == TR::STATE_COMPRESS) {
switch (mask & (RIGHT | LEFT | FORTH | BACK)) {
case RIGHT : state = TR::STATE_RIGHT_JUMP; break;
case LEFT : state = TR::STATE_LEFT_JUMP; break;
case FORTH : state = TR::STATE_FORWARD_JUMP; break;
case BACK : state = TR::STATE_BACK_JUMP; break;
default : state = TR::STATE_UP_JUMP; break;
}
} else
if (mask & JUMP) { // jump button is pressed
if ((mask & FORTH) && state == TR::STATE_FORWARD_JUMP)
state = TR::STATE_RUN;
else
state = state == TR::STATE_RUN ? TR::STATE_FORWARD_JUMP : TR::STATE_COMPRESS;
} else
if (mask & WALK) { // walk button is pressed
if (mask & FORTH)
state = TR::STATE_WALK;
else if (mask & BACK)
state = TR::STATE_BACK;
else if (mask & LEFT)
state = TR::STATE_STEP_LEFT;
else if (mask & RIGHT)
state = TR::STATE_STEP_RIGHT;
else
state = TR::STATE_STOP;
} else { // only dpad buttons pressed
if (mask & FORTH)
state = TR::STATE_RUN;
else if (mask & BACK)
state = TR::STATE_FAST_BACK;
else if (mask & LEFT)
state = turnTime < FAST_TURN_TIME ? TR::STATE_TURN_LEFT : TR::STATE_FAST_TURN;
else if (mask & RIGHT)
state = turnTime < FAST_TURN_TIME ? TR::STATE_TURN_RIGHT : TR::STATE_FAST_TURN;
else
state = TR::STATE_STOP;
}
} else if (mask & WATER) { // underwater
if (state == TR::STATE_FORWARD_JUMP || state == TR::STATE_BACK_JUMP || state == TR::STATE_LEFT_JUMP || state == TR::STATE_RIGHT_JUMP || state == TR::STATE_FAST_FALL) {
model.animation = TR::ANIM_WATER_FALL;
fTime = 0.0f;
state = level->anims[model.animation].state;
} else
if (mask & JUMP)
state = TR::STATE_SWIM;
else
state = (state == TR::STATE_SWIM || velocity.y > GLIDE_SPEED) ? TR::STATE_GLIDE : TR::STATE_TREAD;
} else { // in the air
angle.x = 0.0f;
if (state == TR::STATE_FORWARD_JUMP) {
if (mask & ACTION)
state = TR::STATE_REACH;
else if ((mask & (FORTH | WALK)) == (FORTH | WALK))
state = TR::STATE_SWAN_DIVE;
}
// LOG("- speed: %f\n", velocity.length());
}
// try to set new state
if (!changeState(state)) {
int stopState = TR::STATE_FAST_FALL;
if ((mask & (GROUND | WATER)) == (GROUND | WATER))
stopState = TR::STATE_SURF_TREAD;
else if (mask & WATER)
stopState = TR::STATE_TREAD;
else if (mask & GROUND)
stopState = TR::STATE_STOP;
if (state != stopState)
changeState(stopState);
}
anim = &level->anims[model.animation]; // get new animation and state (if it has been changed)
state = anim->state;
fTime += Core::deltaTime;
int fCount = anim->frameEnd - anim->frameStart + 1;
int fIndex = int(fTime * 30.0f);
#ifdef _DEBUG
// show state transitions for current animation
if (Input::down[ikEnter]) {
LOG("state: %d\n", anim->state);
for (int i = 0; i < anim->scCount; i++) {
auto &sc = level->states[anim->scOffset + i];
LOG("-> %d : ", (int)sc.state);
for (int j = 0; j < sc.rangesCount; j++) {
TR::AnimRange &range = level->ranges[sc.rangesOffset + j];
LOG("%d ", range.nextAnimation);
}
LOG("\n");
}
}
#endif
// calculate turn tilt
if (state == TR::STATE_RUN && (mask & (GROUND | WATER)) == GROUND && (mask & (LEFT | RIGHT))) {
if (mask & LEFT) angle.z -= Core::deltaTime * TURN_TILT;
if (mask & RIGHT) angle.z += Core::deltaTime * TURN_TILT;
angle.z = clamp(angle.z, -TURN_TILT, TURN_TILT);
} else
angle.z -= angle.z * min(Core::deltaTime * 8.0f, 1.0f);
if (state == TR::STATE_TURN_LEFT || state == TR::STATE_TURN_RIGHT || state == TR::STATE_FAST_TURN)
turnTime += Core::deltaTime;
else
turnTime = 0.0f;
// get turning angle
float w = 0.0f;
if (state == TR::STATE_SWIM || state == TR::STATE_GLIDE)
w = TURN_WATER_FAST;
else if (state == TR::STATE_TREAD)
w = TURN_WATER_SLOW;
else if (state == TR::STATE_RUN || state == TR::STATE_FAST_TURN)
w = TURN_FAST;
else if (state == TR::STATE_FAST_BACK)
w = TURN_FAST_BACK;
else if (state == TR::STATE_TURN_LEFT || state == TR::STATE_TURN_RIGHT || state == TR::STATE_WALK)
w = TURN_NORMAL;
else if (state == TR::STATE_FORWARD_JUMP || state == TR::STATE_BACK)
w = TURN_SLOW;
if (w != 0.0f) {
w *= Core::deltaTime;
// yaw
if (mask & LEFT) { angle.y -= w; velocity = velocity.rotateY(+w); }
if (mask & RIGHT) { angle.y += w; velocity = velocity.rotateY(-w); }
// pitch (underwater only)
if ( ((mask & (GROUND | WATER)) == WATER) && (mask & (FORTH | BACK)) ) {
angle.x += ((mask & FORTH) ? -w : w) * 0.5f;
angle.x = clamp(angle.x, -PI * 0.5f, PI * 0.5f);
}
}
// get animation direction
float d = 0.0f;
switch (state) {
case TR::STATE_BACK :
case TR::STATE_BACK_JUMP :
case TR::STATE_FAST_BACK :
d = PI;
break;
case TR::STATE_STEP_LEFT :
case TR::STATE_LEFT_JUMP :
d = -PI * 0.5f;
break;
case TR::STATE_STEP_RIGHT :
case TR::STATE_RIGHT_JUMP :
d = PI * 0.5f;
break;
}
d += angle.y;
bool endFrame = fIndex >= fCount;
// calculate moving speed
float dt = Core::deltaTime * 30.0f;
if (mask & (GROUND | WATER)) {
if ((mask & (GROUND | WATER)) == (GROUND | WATER)) { // on water
} else if (mask & WATER) { // underwater
if (state == TR::STATE_SWIM) {
velocity = vec3(angle.x, angle.y) * 35.0f;
} else if (state == TR::STATE_GLIDE || state == TR::STATE_TREAD)
velocity = velocity - velocity * Core::deltaTime;
// TODO: apply flow velocity
} else { // on ground
float speed = anim->speed + anim->accel * (fTime * 30.0f);
velocity.x = sinf(d) * speed;
velocity.z = cosf(d) * speed;
velocity.y += GRAVITY * dt;
}
} else
velocity.y += GRAVITY * dt;
// apply animation commands
int16 *ptr = &level->commands[anim->animCommand];
for (int i = 0; i < anim->acCount; i++) {
switch (*ptr++) {
case 0x01 : { // cmd position
int16 sx = *ptr++;
int16 sy = *ptr++;
int16 sz = *ptr++;
LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz);
break;
}
case 0x02 : { // cmd jump speed
int16 sy = *ptr++;
int16 sz = *ptr++;
if (endFrame) {
LOG("jump: %d %d\n", (int)sy, (int)sz);
velocity.x = sinf(d) * sz;
velocity.y = sy;
velocity.z = cosf(d) * sz;
LOG("speed: %f\n", velocity.length());
onGround = false;
}
break;
}
case 0x03 : // empty hands
break;
case 0x04 : // kill
break;
case 0x05 : { // play sound
int frame = (*ptr++);
int id = (*ptr++) & 0x3FFF;
if (fIndex == frame - anim->frameStart && fIndex != lastFrame) {
int16 a = level->soundsMap[id];
TR::SoundInfo &b = level->soundsInfo[a];
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
uint32 c = level->soundOffsets[b.offset + rand() % ((b.flags & 0xFF) >> 2)];
LOG("count %d\n", int(((b.flags & 0xFF) >> 2)));
void *p = &level->soundData[c];
#ifdef WIN32
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
#endif
}
}
break;
}
case 0x06 :
if (fIndex != lastFrame && fIndex + anim->frameStart == ptr[0]) {
if (ptr[1] == 0) {
angle = angle + PI;
}
}
ptr += 2;
break;
default :
LOG("unknown animation command\n");
}
}
// check for next animation
if (endFrame) {
model.animation = anim->nextAnimation;
TR::Animation *nextAnim = &level->anims[anim->nextAnimation];
fTime = (anim->nextFrame - nextAnim->frameStart) / 30.0f;
}
move(velocity * dt);
collide();
lastFrame = fIndex;
}
void move(const vec3 &offset) {
vec3 p = pos;
pos = pos + offset;
updateEntity();
inWater = getRoom().flags & TR::ROOM_FLAG_WATER;
TR::Room &room = getRoom();
TR::Entity &entity = getEntity();
int dx, dz;
TR::Room::Sector &s = getSector(dx, dz);
int d = entity.y - s.floor * 256;
if (d >= 256 * 4) {
LOG("wall %d\n", d);
pos = p;
updateEntity();
TR::Model &model = getModel();
TR::Animation *anim = &level->anims[model.animation];
// smashes
if (onGround) { // onGround
if (d >= 256 * 4 && anim->state == TR::STATE_RUN)
model.animation = TR::ANIM_SMASH_RUN_LEFT; // TODO: RIGHT
else
model.animation = TR::ANIM_STAND;
velocity.x = velocity.z = 0.0f;
} else if (inWater) { // in water
// do nothing
//velocity.x = velocity.z = 0.0f;
} else { // in the air
model.animation = TR::ANIM_SMASH_JUMP;
velocity.x = -velocity.x * 0.5f;
velocity.z = -velocity.z * 0.5f;
velocity.y = 0.0f;
}
fTime = 0;
}
}
void collide() {
int dx, dz;
TR::Room::Sector &s = getSector(dx, dz);
TR::Entity &entity = getEntity();
float bottom = s.floor * 256.0f;
float floor = s.floor * 256.0f;
float ceiling = s.ceiling * 256.0f;
float fx = dx / 1024.0f, fz = dz / 1024.0f;
@ -384,37 +507,29 @@ struct Controller {
break;
case 2 :
case 3 : {
int8 sx = (int8)(*d & 0x00FF);
int8 sz = (int8)((*d & 0xFF00) >> 8);
int sx = (int8)(*d & 0x00FF);
int sz = (int8)((*d & 0xFF00) >> 8);
if (func == 2) {
if (sx > 0)
bottom += (int)sx * (1024 - dx) >> 2;
floor += sx * (1024 - dx) >> 2;
else
bottom -= (int)sx * dx >> 2;
floor -= sx * dx >> 2;
if (sz > 0)
bottom += (int)sz * (1024 - dz) >> 2;
floor += sz * (1024 - dz) >> 2;
else
bottom -= (int)sz * dz >> 2;
} else {
/*
if (sx < 0) {
p[0].y += sx;
p[3].y += sx;
} else {
p[1].y -= sx;
p[2].y -= sx;
}
floor -= sz * dz >> 2;
} else {
if (sx < 0)
ceiling += sx * (1024 - dx) >> 2;
else
ceiling -= sx * dx >> 2;
if (sz > 0) {
p[0].y -= sz;
p[1].y -= sz;
} else {
p[3].y += sz;
p[2].y += sz;
}
*/
if (sz > 0)
ceiling -= sz * (1024 - dz) >> 2;
else
ceiling += sz * dz >> 2;
}
d++;
break;
@ -445,19 +560,30 @@ struct Controller {
} while (!(cmd & 0x8000));
onGround = pos.y > bottom;
if (onGround) {
onGround = true;
if (s.roomBelow != 255) {
entity.room = s.roomBelow;
onGround = false;
return;
}
pos.y = bottom;
velocity.y = 0.0f;
float hmin = 0.0f, hmax = -768.0f;
if (inWater) {
hmin = 256.0f + 128.0f;
hmax = -256.0f - 128.0f;
}
onGround = (pos.y >= floor) && (s.roomBelow == 0xFF) && !(getRoom().flags & TR::ROOM_FLAG_WATER);
if (pos.y + hmin >= floor) {
if (s.roomBelow == 0xFF) {
pos.y = floor - hmin;
velocity.y = 0.0f;
} else
entity.room = s.roomBelow;
}
if (pos.y + hmax <= ceiling) {
if (s.roomAbove == 0xFF) {
pos.y = ceiling - hmax;
velocity.y = 0.0f;
} else
entity.room = s.roomAbove;
}
entity.y = (int)pos.y;
}

View File

@ -2,28 +2,29 @@
#define H_DEBUG
#include "core.h"
#include "format.h"
namespace Debug {
void begin() {
glMatrixMode(GL_PROJECTION);
glLoadMatrixf((GLfloat*)&Core::mProj);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLoadMatrixf((GLfloat*)&Core::mView);
glLineWidth(3);
glPointSize(32);
glUseProgram(0);
}
void end() {
//
}
namespace Draw {
void begin() {
glMatrixMode(GL_PROJECTION);
glLoadMatrixf((GLfloat*)&Core::mProj);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLoadMatrixf((GLfloat*)&Core::mView);
glLineWidth(3);
glPointSize(32);
glUseProgram(0);
}
void end() {
//
}
void box(const vec3 &min, const vec3 &max) {
glBegin(GL_LINES);
glVertex3f(min.x, min.y, min.z);
@ -108,6 +109,198 @@ namespace Debug {
glEnd();
}
}
namespace Level {
void debugFloor(const TR::Level &level, const vec3 &f, const vec3 &c, int floorIndex, bool current) {
vec3 vf[4] = { f, f + vec3(1024, 0, 0), f + vec3(1024, 0, 1024), f + vec3(0, 0, 1024) };
vec3 vc[4] = { c, c + vec3(1024, 0, 0), c + vec3(1024, 0, 1024), c + vec3(0, 0, 1024) };
uint16 cmd, *d = &level.floors[floorIndex];
if (floorIndex)
do {
cmd = *d++;
int func = cmd & 0x00FF; // function
int sub = (cmd & 0x7F00) >> 8; // sub function
if (func == 0x01) { // portal
d++;
// d += 2;
}
if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling corners
int sx = 256 * int((int8)(*d & 0x00FF));
int sz = 256 * int((int8)((*d & 0xFF00) >> 8));
auto &p = func == 0x02 ? vf : vc;
if (func == 0x02) {
// if (current)
// LOG("%d\n", sx);
if (sx > 0) {
p[0].y += sx;
p[3].y += sx;
} else {
p[1].y -= sx;
p[2].y -= sx;
}
if (sz > 0) {
p[0].y += sz;
p[1].y += sz;
} else {
p[3].y -= sz;
p[2].y -= sz;
}
} else {
if (sx < 0) {
p[0].y += sx;
p[3].y += sx;
} else {
p[1].y -= sx;
p[2].y -= sx;
}
if (sz > 0) {
p[0].y -= sz;
p[1].y -= sz;
} else {
p[3].y += sz;
p[2].y += sz;
}
}
d++;
}
if (func == 0x04) {
//*d++; // trigger setup
/*
if (sub == 0x00) LOG("trigger\n");
if (sub == 0x01) LOG("pad\n");
if (sub == 0x02) LOG("switch\n");
if (sub == 0x03) LOG("key\n");
if (sub == 0x04) LOG("pickup\n");
if (sub == 0x05) LOG("heavy-trigger\n");
if (sub == 0x06) LOG("anti-pad\n");
if (sub == 0x07) LOG("combat\n");
if (sub == 0x08) LOG("dummy\n");
if (sub == 0x09) LOG("anti-trigger\n");
*/
uint16 act;
do {
act = *d++; // trigger action
} while (!(act & 0x8000));
break;
}
} while (!(cmd & 0x8000));
if (current)
glColor3f(1, 1, 1);
else
glColor3f(0, 1, 0);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < 5; i++)
glVertex3fv((GLfloat*)&vf[i % 4]);
glEnd();
glColor3f(1, 0, 0);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < 5; i++)
glVertex3fv((GLfloat*)&vc[i % 4]);
glEnd();
}
void debugSectors(const TR::Level &level, const vec3 &pos, int roomIndex) {
TR::Room &room = level.rooms[roomIndex];
vec3 p = (pos - vec3(room.info.x, 0, room.info.z)) / vec3(1024, 1, 1024);
for (int z = 0; z < room.zSectors; z++)
for (int x = 0; x < room.xSectors; x++) {
auto &s = room.sectors[x * room.zSectors + z];
vec3 f(x * 1024 + room.info.x, s.floor * 256, z * 1024 + room.info.z);
vec3 c(x * 1024 + room.info.x, s.ceiling * 256, z * 1024 + room.info.z);
debugFloor(level, f, c, s.floorIndex, (int)p.x == x && (int)p.z == z);
}
}
void rooms(const TR::Level &level, const vec3 &pos, int roomIndex) {
Core::setBlending(bmAdd);
glDepthMask(GL_FALSE);
for (int i = 0; i < level.roomsCount; i++) {
TR::Room &r = level.rooms[i];
vec3 p = vec3(r.info.x, r.info.yTop, r.info.z);
if (i == roomIndex) {
//if (lara->insideRoom(Core::viewPos, i)) {
debugSectors(level, pos, i);
glColor3f(0, 1, 0);
} else
glColor3f(1, 1, 1);
Debug::Draw::box(p, p + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024));
}
glDepthMask(GL_TRUE);
Core::setBlending(bmAlpha);
}
void portals(const TR::Level &level) {
Core::setBlending(bmAdd);
glColor3f(0, 0.25f, 0.25f);
glDepthMask(GL_FALSE);
glBegin(GL_QUADS);
for (int i = 0; i < level.roomsCount; i++) {
TR::Room &r = level.rooms[i];
for (int j = 0; j < r.portalsCount; j++) {
TR::Room::Portal &p = r.portals[j];
for (int k = 0; k < 4; k++) {
TR::Vertex &v = p.vertices[k];
glVertex3f(v.x + r.info.x, v.y, v.z + r.info.z);
}
}
}
glEnd();
glDepthMask(GL_TRUE);
Core::setBlending(bmAlpha);
}
void lights(const TR::Level &level) {
// int roomIndex = level.entities[lara->entity].room;
// int lightIndex = getLightIndex(lara->pos, roomIndex);
glPointSize(8);
glBegin(GL_POINTS);
for (int i = 0; i < level.roomsCount; i++)
for (int j = 0; j < level.rooms[i].lightsCount; j++) {
TR::Room::Light &l = level.rooms[i].lights[j];
float a = l.intensity / 8191.0f;
vec3 p = vec3(l.x, l.y, l.z);
vec4 color = vec4(a, a, a, 1);
Debug::Draw::point(p, color);
//if (i == roomIndex && j == lightIndex)
// color = vec4(0, 1, 0, 1);
Debug::Draw::sphere(p, l.attenuation, color);
}
glEnd();
}
}
}
#endif

View File

@ -6,7 +6,10 @@
#define TR1_DEMO
namespace TR {
#define ROOM_FLAG_VISIBLE 0x8000
enum : int32 {
ROOM_FLAG_WATER = 0x0001,
ROOM_FLAG_VISIBLE = 0x8000
};
#define DATA_PORTAL 0x01
#define DATA_FLOOR 0x02
@ -59,13 +62,22 @@ namespace TR {
#define ENTITY_AMMO_SHOTGUN 89
#define ENTITY_AMMO_MAGNUM 90
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
enum LaraAnim : int32 {
ANIM_STAND = 11,
ANIM_SMASH_JUMP = 32,
ANIM_SMASH_RUN_LEFT = 53,
ANIM_SMASH_RUN_RIGHT = 54,
ANIM_WATER_FALL = 112,
};
enum LaraState {
// http://www.tombraiderforums.com/showthread.php?t=211681
enum LaraState : int32 {
STATE_WALK,
STATE_RUN,
STATE_STOP,
STATE_FORWARD_JUMP,
STATE_FAST_TURN,
STATE_4,
STATE_FAST_BACK,
STATE_TURN_RIGHT,
STATE_TURN_LEFT,
@ -81,7 +93,7 @@ namespace TR {
STATE_SWIM,
STATE_GLIDE,
STATE_NULL_19,
STATE_FAST_TURN_20,
STATE_FAST_TURN,
STATE_STEP_RIGHT,
STATE_STEP_LEFT,
STATE_ROLL,
@ -143,7 +155,7 @@ namespace TR {
struct fixed {
uint16 L;
int16 H;
float toFloat() {
operator float() const {
return H + L / 65535.0f;
}
};
@ -368,7 +380,7 @@ namespace TR {
struct SpriteTexture {
uint16 tile;
uint8 u, v;
uint16 w, h;
uint16 w, h; // (ActualValue * 256) + 255
int16 l, t, r, b;
};
@ -417,7 +429,7 @@ namespace TR {
};
struct SoundInfo {
uint16 index; // (index into soundsIndices) -- NOT USED IN TR4-5!!!
uint16 offset;
uint16 volume;
uint16 chance; // If !=0 and ((rand()&0x7fff) > Chance), this sound is not played
uint16 flags; // Bits 0-1: Looped flag, bits 2-5: num samples, bits 6-7: UNUSED

View File

@ -55,14 +55,15 @@ struct Level {
break;
}
lara = new Controller(&level, entity);
lara = new Lara(&level, entity);
camera.fov = 75.0f;
camera.znear = 0.1f * 2048.0f;
camera.zfar = 1000.0f * 2048.0f;
camera.offset = vec3(0, 0, 768);
camera.pos = vec3(0.0f);
camera.angle = vec3(0, PI, 0);
camera.fov = 75.0f;
camera.znear = 0.1f * 2048.0f;
camera.zfar = 1000.0f * 2048.0f;
camera.offset = vec3(0, 0, 768);
camera.deltaPos = vec3(0.0f, 768.0f, 0.0f);
camera.deltaAngle = vec3(0.0f, PI, 0.0f);
camera.angle = vec3(0.0f);
}
~Level() {
@ -488,8 +489,8 @@ struct Level {
void renderRoom(int index) {
TR::Room &room = level.rooms[index];
if (room.flags & ROOM_FLAG_VISIBLE) return; // already rendered
room.flags |= ROOM_FLAG_VISIBLE;
if (room.flags & TR::ROOM_FLAG_VISIBLE) return; // already rendered
room.flags |= TR::ROOM_FLAG_VISIBLE;
vec3 offset = vec3(room.info.x, 0.0f, room.info.z);
@ -614,16 +615,20 @@ struct Level {
return ma.getRot().slerp(mb.getRot(), t).normal();
}
void renderModel(const TR::Model &model) {
void renderModel(const TR::Model &model, vec3 angle) {
TR::Animation *anim = &level.anims[model.animation];
float fTime = time;
if (model.id == ENTITY_LARA) {
anim = lara->anim;
fTime = lara->fTime;
angle = lara->angle;
}
if (angle.y != 0.0f) Core::mModel.rotateY(angle.y);
if (angle.x != 0.0f) Core::mModel.rotateX(angle.x);
if (angle.z != 0.0f) Core::mModel.rotateZ(angle.z);
float k = fTime * 30.0f / anim->frameRate;
int fIndex = (int)k;
int fCount = (anim->frameEnd - anim->frameStart) / anim->frameRate + 1;
@ -737,7 +742,7 @@ struct Level {
void renderEntity(const TR::Entity &entity) {
// if (!(entity.flags & ENTITY_FLAG_VISIBLE))
// return;
if (!(level.rooms[entity.room].flags & ROOM_FLAG_VISIBLE)) // check for room visibility
if (!(level.rooms[entity.room].flags & TR::ROOM_FLAG_VISIBLE)) // check for room visibility
return;
mat4 m = Core::mModel;
@ -753,8 +758,7 @@ struct Level {
for (int i = 0; i < level.modelsCount; i++)
if (entity.id == level.models[i].id) {
Core::mModel.rotateY(entity.rotation / 16384.0f * PI * 0.5f);
renderModel(level.models[i]);
renderModel(level.models[i], vec3(0, entity.rotation / 16384.0f * PI * 0.5f, 0));
break;
}
/*
@ -767,210 +771,17 @@ struct Level {
Core::mModel = m;
}
#ifdef _DEBUG
void debugPortals() {
Core::setBlending(bmAdd);
glColor3f(0, 0.25f, 0.25f);
glDepthMask(GL_FALSE);
glBegin(GL_QUADS);
for (int i = 0; i < level.roomsCount; i++) {
TR::Room &r = level.rooms[i];
for (int j = 0; j < r.portalsCount; j++) {
TR::Room::Portal &p = r.portals[j];
for (int k = 0; k < 4; k++) {
TR::Vertex &v = p.vertices[k];
glVertex3f(v.x + r.info.x, v.y, v.z + r.info.z);
}
}
}
glEnd();
glDepthMask(GL_TRUE);
Core::setBlending(bmAlpha);
}
void debugFloor(const vec3 &f, const vec3 &c, int floorIndex, bool current) {
vec3 vf[4] = { f, f + vec3(1024, 0, 0), f + vec3(1024, 0, 1024), f + vec3(0, 0, 1024) };
vec3 vc[4] = { c, c + vec3(1024, 0, 0), c + vec3(1024, 0, 1024), c + vec3(0, 0, 1024) };
uint16 cmd, *d = &level.floors[floorIndex];
if (floorIndex)
do {
cmd = *d++;
int func = cmd & 0x00FF; // function
int sub = (cmd & 0x7F00) >> 8; // sub function
if (func == 0x01) { // portal
d++;
// d += 2;
}
if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling corners
int sx = 256 * int((int8)(*d & 0x00FF));
int sz = 256 * int((int8)((*d & 0xFF00) >> 8));
auto &p = func == 0x02 ? vf : vc;
if (func == 0x02) {
// if (current)
// LOG("%d\n", sx);
if (sx > 0) {
p[0].y += sx;
p[3].y += sx;
} else {
p[1].y -= sx;
p[2].y -= sx;
}
if (sz > 0) {
p[0].y += sz;
p[1].y += sz;
} else {
p[3].y -= sz;
p[2].y -= sz;
}
} else {
if (sx < 0) {
p[0].y += sx;
p[3].y += sx;
} else {
p[1].y -= sx;
p[2].y -= sx;
}
if (sz > 0) {
p[0].y -= sz;
p[1].y -= sz;
} else {
p[3].y += sz;
p[2].y += sz;
}
}
d++;
}
if (func == 0x04) {
//*d++; // trigger setup
/*
if (sub == 0x00) LOG("trigger\n");
if (sub == 0x01) LOG("pad\n");
if (sub == 0x02) LOG("switch\n");
if (sub == 0x03) LOG("key\n");
if (sub == 0x04) LOG("pickup\n");
if (sub == 0x05) LOG("heavy-trigger\n");
if (sub == 0x06) LOG("anti-pad\n");
if (sub == 0x07) LOG("combat\n");
if (sub == 0x08) LOG("dummy\n");
if (sub == 0x09) LOG("anti-trigger\n");
*/
uint16 act;
do {
act = *d++; // trigger action
} while (!(act & 0x8000));
break;
}
} while (!(cmd & 0x8000));
if (current)
glColor3f(1, 1, 1);
else
glColor3f(0, 1, 0);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < 5; i++)
glVertex3fv((GLfloat*)&vf[i % 4]);
glEnd();
glColor3f(1, 0, 0);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < 5; i++)
glVertex3fv((GLfloat*)&vc[i % 4]);
glEnd();
}
void debugSectors(int index) {
TR::Room &room = level.rooms[index];
vec3 p = (lara->pos - vec3(room.info.x, 0, room.info.z)) / vec3(1024, 1, 1024);
for (int z = 0; z < room.zSectors; z++)
for (int x = 0; x < room.xSectors; x++) {
auto &s = room.sectors[x * room.zSectors + z];
vec3 f(x * 1024 + room.info.x, s.floor * 256, z * 1024 + room.info.z);
vec3 c(x * 1024 + room.info.x, s.ceiling * 256, z * 1024 + room.info.z);
debugFloor(f, c, s.floorIndex, (int)p.x == x && (int)p.z == z);
}
}
void debugRooms() {
Core::setBlending(bmAdd);
glDepthMask(GL_FALSE);
for (int i = 0; i < level.roomsCount; i++) {
TR::Room &r = level.rooms[i];
vec3 p = vec3(r.info.x, r.info.yTop, r.info.z);
if (i == level.entities[lara->entity].room) {
//if (lara->insideRoom(Core::viewPos, i)) {
debugSectors(i);
glColor3f(0, 1, 0);
} else
glColor3f(1, 1, 1);
Debug::Draw::box(p, p + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024));
}
glDepthMask(GL_TRUE);
Core::setBlending(bmAlpha);
}
void debugMeshes() {
mat4 m = Core::mModel;
for (int i = 0; i < level.meshOffsetsCount; i++) {
renderMesh(i);
Core::mModel.translate(vec3(-128, 0, 0));
}
Core::mModel = m;
}
void debugLights() {
int roomIndex = level.entities[lara->entity].room;
int lightIndex = getLightIndex(lara->pos, roomIndex);
glPointSize(8);
glBegin(GL_POINTS);
for (int i = 0; i < level.roomsCount; i++)
for (int j = 0; j < level.rooms[i].lightsCount; j++) {
TR::Room::Light &l = level.rooms[i].lights[j];
float a = l.intensity / 8191.0f;
vec3 p = vec3(l.x, l.y, l.z);
vec4 color = vec4(a, a, a, 1);
Debug::Draw::point(p, color);
if (i == roomIndex && j == lightIndex)
color = vec4(0, 1, 0, 1);
Debug::Draw::sphere(p, l.attenuation, color);
}
glEnd();
}
#endif
float tickTextureAnimation = 0.0f;
void update() {
time += Core::deltaTime;
lara->update();
#ifndef FREE_CAMERA
camera.pos = vec3(-lara->pos.x, -lara->pos.y, lara->pos.z);
#endif
camera.targetDeltaPos = lara->inWater ? vec3(0.0f, -256.0f, 0.0f) : vec3(0.0f, -768.0f, 0.0f);
camera.targetAngle = vec3(lara->angle.x, -lara->angle.y, 0.0f); //-lara->angle.z);
camera.update();
/*
@ -1003,9 +814,7 @@ struct Level {
void render() {
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#ifndef FREE_CAMERA
camera.pos = vec3(-lara->pos.x, -lara->pos.y + 768, lara->pos.z);
#endif
camera.setup();;
atlas->bind(0);
@ -1025,8 +834,9 @@ struct Level {
Core::mModel.identity();
for (int i = 0; i < level.roomsCount; i++)
level.rooms[i].flags &= ~ROOM_FLAG_VISIBLE; // clear visible flag
level.rooms[i].flags &= ~TR::ROOM_FLAG_VISIBLE; // clear visible flag
// TODO: collision detection for camera
renderRoom(getCameraRoomIndex());
renderRoom(lara->getEntity().room);
@ -1038,13 +848,11 @@ struct Level {
renderEntity(level.entities[i]);
#ifdef _DEBUG
// debugMeshes();
Debug::Draw::begin();
// debugRooms();
// debugLights();
debugPortals();
Debug::Draw::end();
Debug::begin();
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
Debug::Level::lights(level);
Debug::Level::portals(level);
Debug::end();
#endif
}
};

View File

@ -1,6 +1,7 @@
#ifndef H_UTILS
#define H_UTILS
#include <stdlib.h>
#include <cstring>
#include <math.h>
#include <float.h>
@ -8,16 +9,19 @@
#ifdef _DEBUG
#define debugBreak() _asm { int 3 }
#define ASSERT(expr) if (expr) {} else { LOG("ASSERT %s in %s:%d\n", #expr, __FILE__, __LINE__); debugBreak(); }
#ifndef ANDROID
#define LOG(...) printf(__VA_ARGS__)
#else
#include <android/log.h>
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"X5",__VA_ARGS__)
#endif
#else
#define ASSERT(expr)
#define LOG(...) ((void)0)
#endif
#ifndef ANDROID
#define LOG(...) printf(__VA_ARGS__)
#else
#include <android/log.h>
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"X5",__VA_ARGS__)
#endif
#define PI 3.14159265358979323846f
#define DEG2RAD (PI / 180.0f)
@ -57,6 +61,11 @@ inline const T& max(const T &a, const T &b) {
return a > b ? a : b;
}
template <class T>
inline const T& clamp(const T &x, const T &a, const T &b) {
return x < a ? a : (x > b ? b : x);
}
template <class T>
inline const int sign(const T &x) {
return x > 0 ? 1 : (x < 0 ? -1 : 0);
@ -84,6 +93,7 @@ struct vec3 {
vec3(float s) : x(s), y(s), z(s) {}
vec3(float x, float y, float z) : x(x), y(y), z(z) {}
vec3(const vec2 &xy, float z = 0.0f) : x(xy.x), y(xy.y), z(z) {}
vec3(float lng, float lat) : x(sinf(lat) * cosf(lng)), y(-sinf(lng)), z(cosf(lat) * cosf(lng)) {}
float& operator [] (int index) const { return ((float*)this)[index]; }
@ -102,6 +112,11 @@ struct vec3 {
vec3 lerp(const vec3 &v, const float t) const {
return *this + (v - *this) * t;
}
vec3 rotateY(float angle) const {
float s = sinf(angle), c = cosf(angle);
return vec3(x*c - z*s, y, x*s + z*c);
}
};
struct vec4 {