mirror of
https://github.com/XProger/OpenLara.git
synced 2025-04-20 19:11:50 +02:00
parent
1d3a3c6d2f
commit
5d390a7f7d
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
18
src/camera.h
18
src/camera.h
@ -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);
|
||||
|
794
src/controller.h
794
src/controller.h
@ -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;
|
||||
}
|
||||
|
||||
|
227
src/debug.h
227
src/debug.h
@ -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
|
26
src/format.h
26
src/format.h
@ -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
|
||||
|
256
src/level.h
256
src/level.h
@ -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
|
||||
}
|
||||
};
|
||||
|
27
src/utils.h
27
src/utils.h
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user