1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-05 20:57:46 +02:00

- simple states controller logic

This commit is contained in:
XProger
2016-08-29 02:42:14 +03:00
parent c55d8c7320
commit 155cee6278
6 changed files with 427 additions and 353 deletions

View File

@@ -5,9 +5,10 @@
struct Camera { struct Camera {
float fov, znear, zfar; float fov, znear, zfar;
vec3 pos, angle; vec3 pos, angle, offset;
void update() { void update() {
#ifdef FREE_CAMERA
vec3 dir = vec3(sinf(angle.y - PI) * cosf(-angle.x), -sinf(-angle.x), cosf(angle.y - PI) * cosf(-angle.x)); vec3 dir = vec3(sinf(angle.y - PI) * cosf(-angle.x), -sinf(-angle.x), cosf(angle.y - PI) * cosf(-angle.x));
vec3 v = vec3(0); vec3 v = vec3(0);
@@ -15,8 +16,8 @@ struct Camera {
if (Input::down[ikS]) v = v - dir; if (Input::down[ikS]) v = v - dir;
if (Input::down[ikD]) v = v + dir.cross(vec3(0, 1, 0)); if (Input::down[ikD]) v = v + dir.cross(vec3(0, 1, 0));
if (Input::down[ikA]) v = v - dir.cross(vec3(0, 1, 0)); if (Input::down[ikA]) v = v - dir.cross(vec3(0, 1, 0));
pos = pos + v.normal() * (Core::deltaTime * 2048.0f); pos = pos + v.normal() * (Core::deltaTime * 2048.0f);
#endif
if (Input::down[ikMouseL]) { if (Input::down[ikMouseL]) {
vec2 delta = Input::mouse.pos - Input::mouse.start.L; vec2 delta = Input::mouse.pos - Input::mouse.start.L;
@@ -29,6 +30,7 @@ struct Camera {
void setup() { void setup() {
Core::mView.identity(); Core::mView.identity();
Core::mView.translate(vec3(-offset.x, -offset.y, -offset.z));
Core::mView.rotateZ(-angle.z); Core::mView.rotateZ(-angle.z);
Core::mView.rotateX(-angle.x); Core::mView.rotateX(-angle.x);
Core::mView.rotateY(-angle.y); Core::mView.rotateY(-angle.y);

View File

@@ -3,6 +3,8 @@
#include "format.h" #include "format.h"
#define GRAVITY 7.0f
struct Controller { struct Controller {
TR::Level *level; TR::Level *level;
int entity; int entity;
@@ -10,17 +12,18 @@ struct Controller {
TR::Animation *anim; TR::Animation *anim;
float fTime; float fTime;
vec3 pos; vec3 pos, velocity;
float angle; float angle;
int state; // LaraState int state; // target state
int lastFrame; int lastFrame;
int sc; int sc;
bool lState; bool lState;
bool onGround;
Controller(TR::Level *level, int entity) : level(level), entity(entity), pos(0.0f), angle(0.0f), fTime(0.0f) { 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[0]; anim = &level->anims[getModel().animation];
lastFrame = 0; lastFrame = 0;
TR::Entity &e = level->entities[entity]; TR::Entity &e = level->entities[entity];
@@ -29,43 +32,117 @@ struct Controller {
sc = 0; sc = 0;
lState = false; lState = false;
state = TR::STATE_STOP;
} }
void update() { void update() {
float rot = 0.0f; float rot = 0.0f;
state = TR::STATE_STOP; 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,
if (Input::down[ikShift]) { 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};
if (Input::down[ikUp]) { state = TR::STATE_WALK; }; int mask = 0;
if (Input::down[ikDown]) { state = TR::STATE_BACK; };
if (Input::down[ikLeft]) { if (!Input::down[ikUp] && !Input::down[ikDown]) { state = TR::STATE_STEP_LEFT; } else rot = -Core::deltaTime * PI; }; if (Input::down[ikW] || Input::joy.L.y < 0) mask |= FORTH;
if (Input::down[ikRight]) { if (!Input::down[ikUp] && !Input::down[ikDown]) { state = TR::STATE_STEP_RIGHT; } else rot = Core::deltaTime * PI; }; if (Input::down[ikS] || Input::joy.L.y > 0) mask |= BACK;
} else if (Input::down[ikA] || Input::joy.L.x < 0) mask |= LEFT;
if (Input::down[ikSpace]) { if (Input::down[ikD] || Input::joy.L.x > 0) mask |= RIGHT;
if (anim->state == TR::STATE_RUN) if (Input::down[ikSpace] || Input::down[ikJoyX]) mask |= JUMP;
state = TR::STATE_FORWARD_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 | FORTH;
// 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_SWAN_DIVE] = JUMP | WALK | FORTH;
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 else
if (Input::down[ikUp]) if (stateMask[sc.state] > maxMask && ((stateMask[sc.state] & mask) == stateMask[sc.state])) {
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_FORWARD_JUMP; maxMask = stateMask[sc.state];
else state = anim->scOffset + i;
if (Input::down[ikDown]) }
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_BACK_JUMP;
else
if (Input::down[ikLeft])
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_LEFT_JUMP;
else
if (Input::down[ikRight])
state = anim->state != TR::STATE_COMPRESS ? TR::STATE_COMPRESS : TR::STATE_RIGHT_JUMP;
else
state = TR::STATE_UP_JUMP;
} else {
if (Input::down[ikUp]) { state = TR::STATE_RUN; };
if (Input::down[ikDown]) { state = TR::STATE_FAST_BACK; };
if (Input::down[ikLeft]) { if (!Input::down[ikUp] && !Input::down[ikDown]) state = TR::STATE_TURN_LEFT; rot = -Core::deltaTime * PI; };
if (Input::down[ikRight]) { if (!Input::down[ikUp] && !Input::down[ikDown]) state = TR::STATE_TURN_RIGHT; rot = Core::deltaTime * PI; };
} }
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 (Input::down[ikEnter]) {
if (!lState) { if (!lState) {
lState = true; lState = true;
@@ -76,7 +153,7 @@ struct Controller {
// anim = &level->anims[146];//level->ranges[ level->states[sc].rangesOffset ].nextAnimation ]; // anim = &level->anims[146];//level->ranges[ level->states[sc].rangesOffset ].nextAnimation ];
// fTime = 0; // fTime = 0;
// state = level->states[sc].state; // state = level->states[sc].state;
/*
LOG("state: %d\n", anim->state); LOG("state: %d\n", anim->state);
for (int i = 0; i < anim->scCount; i++) { for (int i = 0; i < anim->scCount; i++) {
auto &sc = level->states[anim->scOffset + i]; auto &sc = level->states[anim->scOffset + i];
@@ -88,114 +165,23 @@ struct Controller {
} }
LOG("\n"); LOG("\n");
} }
*/
} }
} else } else
lState = false; 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) {
fTime += Core::deltaTime; if (origMask & LEFT) angle -= Core::deltaTime * PI;
int fCount = anim->frameEnd - anim->frameStart + 1; if (origMask & RIGHT) angle += Core::deltaTime * PI;
int fIndex = int(fTime * 30.0f);
// LOG("%d / %d\n", fIndex, fCount);
// fIndex = anim->frameStart + (fIndex % fCount);
//LOG("%d\n", fIndex);
/*
if (anim->state == state) {
for (int i = 0; i < anim->scCount; i++) {
auto &sc = level->stateChanges[anim->scOffset + i];
LOG("%d ", sc.state);
}
LOG("\n");
}
*/
if (anim->state != state) {
for (int i = 0; i < anim->scCount; i++) {
auto &sc = level->states[anim->scOffset + i];
if (sc.state == state) {
for (int j = 0; j < sc.rangesCount; j++) {
auto &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];
fTime = 0.0f;//(ad.nextFrame - anim->frameStart) / (30.0f / anim->frameRate);
fIndex = range.nextFrame - anim->frameStart;
fCount = anim->frameEnd - anim->frameStart + 1;
// LOG("set anim %d %f %f %d -> %d -> %d\n", range.nextAnimation, anim->accel.toFloat(), anim->speed.toFloat(), st, state, anim->state);
//LOG("from %f to %f\n", s, s + a * c);
// LOG("frame: %d\n", fIndex);
break;
}
}
break;
}
}
};
if (fIndex >= fCount) {
fIndex = anim->nextFrame;
int id = anim->nextAnimation;
anim = &level->anims[anim->nextAnimation];
fIndex -= anim->frameStart;
fTime = (fIndex) / 30.0f;
}
if (anim->state == state) {
angle += rot;
} }
float d = 0.0f; float d = 0.0f;
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\n", (int)sx, (int)sy, (int)sz);
break;
}
case 0x02 : { // cmd jump speed
int16 sx = *ptr++;
int16 sz = *ptr++;
LOG("jump: %d %d\n", (int)sx, (int)sz);
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];
//PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
}
break;
}
case 0x06 :
if (fIndex != lastFrame && fIndex + anim->frameStart == ptr[0]) {
if (ptr[1] == 0) {
angle = angle + PI;
}
}
ptr += 2;
break;
}
}
switch (anim->state) { switch (anim->state) {
case TR::STATE_BACK : case TR::STATE_BACK :
case TR::STATE_BACK_JUMP : case TR::STATE_BACK_JUMP :
@@ -213,61 +199,90 @@ struct Controller {
} }
d += angle; d += angle;
float speed = anim->speed.toFloat() + anim->accel.toFloat() * (fTime * 30.0f); bool endFrame = fIndex >= fCount;
move(vec3(sinf(d), 0, cosf(d)) * (speed * Core::deltaTime * 30.0f)); 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\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];
PlaySound((LPSTR)p, NULL, SND_ASYNC | SND_MEMORY);
}
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(); collide();
lastFrame = fIndex; lastFrame = fIndex;
updateEntity();
/*
TR::Room &room = level->rooms[level->entities[entity].room];
for (int i = 0; i < room.portalsCount; i++) {
if (insideRoom(pos, room.portals[i].roomIndex)) {
level->entities[entity].room = room.portals[i].roomIndex;
LOG("set room: %d\n", i);
break;
}
} }
void move(const vec3 &offset) {
for (int i = 0; i < level->roomsCount; i++)
if (insideRoom(pos, i) && i != level->entities[entity].room) {
level->entities[entity].room = i;
LOG("set room: %d\n", i);
break;
}
*/
}
void checkPortals(const vec3 &oldPos, const vec3 &newPos) {
TR::Room &room = getRoom();
TR::Vertex a = { (int)oldPos.x - room.info.x, (int)oldPos.y, (int)oldPos.z - room.info.z };
TR::Vertex b = { (int)newPos.x - room.info.x, (int)newPos.y, (int)newPos.z - room.info.z };
for (int i = 0; i < room.portalsCount; i++) {
TR::Vertex &n = room.portals[i].normal;
TR::Vertex &v = room.portals[i].vertices[0];
int d = -(v.x * n.x + v.y * n.y + v.z * n.z);
int oldSign = sign(a.x * n.x + a.y * n.y + a.z * n.z + d);
int newSign = sign(b.x * n.x + b.y * n.y + b.z * n.z + d);
if (oldSign != newSign) {
getEntity().room = room.portals[i].roomIndex;
break;
}
}
}
void move(const vec3 &speed) {
vec3 p = pos; vec3 p = pos;
pos = pos + speed; pos = pos + offset;
//pos.y += 1.0f; TODO: floor portal
checkPortals(p, pos);
updateEntity(); updateEntity();
@@ -279,13 +294,14 @@ struct Controller {
int d = entity.y - s.floor * 256; int d = entity.y - s.floor * 256;
if (d >= 256 * 4) { if (d >= 256 * 4) {
pos = p;//vec3(entity.x, entity.y, entity.z); pos.x = p.x;//vec3(entity.x, entity.y, entity.z);
pos.z = p.z;
updateEntity(); updateEntity();
state = TR::STATE_STOP;
if (d >= 256 * 4) if (d >= 256 * 4)
anim = &level->anims[53]; // forward smash anim = &level->anims[53]; // forward smash
else else
anim = &level->anims[11]; // instant stand anim = &level->anims[11]; // instant stand
state = anim->state;
fTime = 0; fTime = 0;
} }
} }
@@ -312,6 +328,13 @@ struct Controller {
return level->entities[entity]; return level->entities[entity];
} }
TR::Model& getModel() {
TR::Entity &entity = getEntity();
for (int i = 0; i < level->modelsCount; i++)
if (entity.id == level->models[i].id)
return level->models[i];
}
TR::Room& getRoom() { TR::Room& getRoom() {
return level->rooms[getEntity().room]; return level->rooms[getEntity().room];
} }
@@ -342,35 +365,33 @@ struct Controller {
// dx -= 512; // dx -= 512;
// dz -= 512; // dz -= 512;
uint16 *d = &level->floors[s.floorIndex]; uint16 cmd, *d = &level->floors[s.floorIndex];
auto cmd = *d;
if (s.floorIndex)
do { do {
cmd = *d; cmd = *d++;
int func = cmd & 0x001F; // function int func = cmd & 0x00FF; // function
int sub = (cmd & 0x7F00) >> 8; // sub function int sub = (cmd & 0x7F00) >> 8; // sub function
d++;
switch (func) {
case 1 :
entity.room = *d++;
break;
case 2 :
case 3 : {
int8 sx = (int8)(*d & 0x00FF);
int8 sz = (int8)((*d & 0xFF00) >> 8);
if (func == 0x00) { // portal if (func == 2) {
LOG("portal\n");
// d++;
}
if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling heights
int sx = (int)(int8)(*d & 0x00FF);
int sz = (int)(int8)((*d & 0xFF00) >> 8);
if (func == 0x02) {
if (sx > 0) if (sx > 0)
bottom += sx * (1024 - dx) >> 2; bottom += (int)sx * (1024 - dx) >> 2;
else else
bottom -= sx * dx >> 2; bottom -= (int)sx * dx >> 2;
if (sz > 0) if (sz > 0)
bottom += sz * (1024 - dz) >> 2; bottom += (int)sz * (1024 - dz) >> 2;
else else
bottom -= sz * dz >> 2; bottom -= (int)sz * dz >> 2;
} else { } else {
/* /*
if (sx < 0) { if (sx < 0) {
@@ -390,17 +411,48 @@ struct Controller {
} }
*/ */
} }
d++;
break;
}
case 4 : {
/*
//*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));
// d++; break;
}
default :
LOG("unknown func: %d\n", func);
} }
d++; } while (!(cmd & 0x8000));
// LOG("%d %d\n", func, sub); onGround = pos.y > bottom;
} while ((cmd & 0x8000) == 0); // end if (onGround) {
onGround = true;
if (s.roomBelow != 255) {
entity.room = s.roomBelow;
onGround = false;
return;
}
pos.y = bottom; pos.y = bottom;
velocity.y = 0.0f;
}
entity.y = (int)pos.y; entity.y = (int)pos.y;
} }

View File

@@ -3,8 +3,13 @@
#include "utils.h" #include "utils.h"
//#define TR1_DEMO
namespace TR { namespace TR {
#define TR1_DEMO #define DATA_PORTAL 0x01
#define DATA_FLOOR 0x02
#define DATA_CEILING 0x03
#define ENTITY_FLAG_CLEAR 0x0080 #define ENTITY_FLAG_CLEAR 0x0080
#define ENTITY_FLAG_VISIBLE 0x0100 #define ENTITY_FLAG_VISIBLE 0x0100
@@ -52,6 +57,7 @@ namespace TR {
#define ENTITY_AMMO_SHOTGUN 89 #define ENTITY_AMMO_SHOTGUN 89
#define ENTITY_AMMO_MAGNUM 90 #define ENTITY_AMMO_MAGNUM 90
enum LaraState { enum LaraState {
STATE_WALK, STATE_WALK,
STATE_RUN, STATE_RUN,
@@ -127,12 +133,11 @@ namespace TR {
STATE_DUCK, STATE_DUCK,
STATE_DUCK_72, STATE_DUCK_72,
STATE_DASH, STATE_DASH,
STATE_DASH_DIVE }; STATE_DASH_DIVE,
STATE_MAX };
#pragma pack(push, 1) #pragma pack(push, 1)
struct fixed { struct fixed {
uint16 L; uint16 L;
int16 H; int16 H;

View File

@@ -1,6 +1,8 @@
#ifndef H_GAME_TR #ifndef H_GAME_TR
#define H_GAME_TR #define H_GAME_TR
//#define FREE_CAMERA
#include "core.h" #include "core.h"
#include "format.h" #include "format.h"
#include "level.h" #include "level.h"
@@ -10,7 +12,7 @@ namespace Game {
void init() { void init() {
Core::init(); Core::init();
level = new Level("data\\LEVEL2_DEMO.PHD"); level = new Level("data\\GYM.PHD");
} }
void free() { void free() {
@@ -24,7 +26,7 @@ namespace Game {
} }
void render() { void render() {
Core::clear(vec4(0.0f, 0.0f, 0.0f, 0.0)); Core::clear(vec4(0.0f));
Core::setViewport(0, 0, Core::width, Core::height); Core::setViewport(0, 0, Core::width, Core::height);
Core::setBlending(bmAlpha); Core::setBlending(bmAlpha);

View File

@@ -48,13 +48,11 @@ struct Level {
lara = new Controller(&level, entity); lara = new Controller(&level, entity);
camera.fov = 90.0f; camera.fov = 75.0f;
camera.znear = 0.1f * 2048.0f; camera.znear = 0.1f * 2048.0f;
camera.zfar = 1000.0f * 2048.0f; camera.zfar = 1000.0f * 2048.0f;
camera.pos = vec3(-lara->pos.x, -lara->pos.y, lara->pos.z) + vec3(0, 1024, -512); camera.offset = vec3(0, 0, 768);
// camera.pos = vec3(-10, -2, 26); camera.pos = vec3(0.0f);
// camera.pos = vec3(-13.25f, 0.42f, 38.06f) * 2048.0f;
// camera.pos = vec3(-36, -1, 2);
camera.angle = vec3(0, PI, 0); camera.angle = vec3(0, PI, 0);
} }
@@ -422,12 +420,18 @@ struct Level {
mat4 m = Core::mModel; mat4 m = Core::mModel;
Core::mModel.translate(vec3(room.info.x, 0.0f, room.info.z)); Core::mModel.translate(vec3(room.info.x, 0.0f, room.info.z));
Core::color = vec4(1.0f);
Core::ambient = vec3(1.0f);
Core::lightColor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
shader->setParam(uModel, Core::mModel); shader->setParam(uModel, Core::mModel);
shader->setParam(uColor, Core::color);
shader->setParam(uAmbient, Core::ambient);
shader->setParam(uLightColor, Core::lightColor);
mesh->render(rangeRooms[index]); mesh->render(rangeRooms[index]);
Core::mModel = m; Core::mModel = m;
Core::color = vec4(1.0f);
shader->setParam(uColor, Core::color);
// meshes // meshes
for (int j = 0; j < room.meshesCount; j++) { for (int j = 0; j < room.meshesCount; j++) {
@@ -698,64 +702,57 @@ struct Level {
Core::mModel = m; Core::mModel = m;
} }
/*
void debugPortals() { void debugPortals() {
glDisable(GL_TEXTURE_2D);
Core::setBlending(bmAdd); Core::setBlending(bmAdd);
glColor3f(0, 0.25f, 0); glColor3f(0, 0.25f, 0.25f);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
glPushMatrix();
glScalef(-SCALE, -SCALE, SCALE);
glBegin(GL_QUADS); glBegin(GL_QUADS);
for (int i = 0; i < rooms.count; i++) { for (int i = 0; i < level.roomsCount; i++) {
int x = rooms[i]->info.x; TR::Room &r = level.rooms[i];
int z = rooms[i]->info.z; for (int j = 0; j < r.portalsCount; j++) {
for (int j = 0; j < rooms[i]->portals.count; j++) { TR::Room::Portal &p = r.portals[j];
auto &p = rooms[i]->portals[j];
for (int k = 0; k < 4; k++) { for (int k = 0; k < 4; k++) {
auto &v = p.vertices[k]; TR::Vertex &v = p.vertices[k];
glVertex3f(v.x + x, v.y, v.z + z); glVertex3f(v.x + r.info.x, v.y, v.z + r.info.z);
} }
} }
} }
glEnd(); glEnd();
glPopMatrix();
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
glEnable(GL_TEXTURE_2D);
Core::setBlending(bmAlpha); Core::setBlending(bmAlpha);
} }
*/
void debugFloor(const vec3 &f, const vec3 &c, int floorIndex, bool current) { 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 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) }; vec3 vc[4] = { c, c + vec3(1024, 0, 0), c + vec3(1024, 0, 1024), c + vec3(0, 0, 1024) };
uint16 *d = &level.floors[floorIndex]; uint16 cmd, *d = &level.floors[floorIndex];
auto cmd = *d;
if (floorIndex)
do { do {
cmd = *d; cmd = *d++;
int func = cmd & 0x001F; // function int func = cmd & 0x00FF; // function
int sub = (cmd & 0x7F00) >> 8; // sub function int sub = (cmd & 0x7F00) >> 8; // sub function
if (func == 0x01) { // portal
d++; d++;
// d += 2;
if (func == 0x00) { // portal
// d++;
} }
if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling corners if ((func == 0x02 || func == 0x03) && sub == 0x00) { // floor & ceiling corners
int sx = 256 * (int)(int8)(*d & 0x00FF); int sx = 256 * int((int8)(*d & 0x00FF));
int sz = 256 * (int)(int8)((*d & 0xFF00) >> 8); int sz = 256 * int((int8)((*d & 0xFF00) >> 8));
auto &p = func == 0x02 ? vf : vc; auto &p = func == 0x02 ? vf : vc;
if (func == 0x02) { if (func == 0x02) {
// if (current)
// LOG("%d\n", sx);
if (sx > 0) { if (sx > 0) {
p[0].y += sx; p[0].y += sx;
p[3].y += sx; p[3].y += sx;
@@ -791,15 +788,33 @@ struct Level {
} }
} }
d++;
// d++;
} }
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));
// LOG("%d %d\n", func, sub); break;
} while ((cmd & 0x8000) == 0); // end }
} while (!(cmd & 0x8000));
if (current) if (current)
glColor3f(1, 1, 1); glColor3f(1, 1, 1);
@@ -835,14 +850,14 @@ struct Level {
void debugRooms() { void debugRooms() {
Core::setBlending(bmAdd); Core::setBlending(bmAdd);
glColor3f(0, 0.25f, 0);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
for (int i = 0; i < level.roomsCount; i++) { for (int i = 0; i < level.roomsCount; i++) {
TR::Room &r = level.rooms[i]; TR::Room &r = level.rooms[i];
vec3 p = vec3(r.info.x, r.info.yTop, r.info.z); vec3 p = vec3(r.info.x, r.info.yTop, r.info.z);
if (i == level.entities[lara->entity].room) {// isInsideRoom(Core::viewPos, rooms[i])) { if (i == level.entities[lara->entity].room) {
//if (lara->insideRoom(Core::viewPos, i)) {
debugSectors(i); debugSectors(i);
glColor3f(0, 1, 0); glColor3f(0, 1, 0);
} else } else
@@ -854,17 +869,16 @@ struct Level {
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
Core::setBlending(bmAlpha); Core::setBlending(bmAlpha);
} }
/*
void debugMeshes() { void debugMeshes() {
glPushMatrix(); mat4 m = Core::mModel;
glScalef(-SCALE, -SCALE, SCALE); for (int i = 0; i < level.meshOffsetsCount; i++) {
for (int i = 0; i < meshes.count; i++) { renderMesh(i);
renderMesh(meshes[i], vec3(1.0f)); Core::mModel.translate(vec3(-128, 0, 0));
glTranslatef(-128, 0, 0);
} }
glPopMatrix(); Core::mModel = m;
} }
*/
void debugLights() { void debugLights() {
int roomIndex = level.entities[lara->entity].room; int roomIndex = level.entities[lara->entity].room;
int lightIndex = getLightIndex(lara->pos, roomIndex); int lightIndex = getLightIndex(lara->pos, roomIndex);
@@ -970,7 +984,9 @@ struct Level {
} }
void render() { void render() {
// camera.pos = vec3(-lara->pos.x, -lara->pos.y, lara->pos.z) + vec3(0, 1024, -1024); #ifndef FREE_CAMERA
camera.pos = vec3(-lara->pos.x, -lara->pos.y + 768, lara->pos.z);
#endif
camera.setup();; camera.setup();;
shader->bind(); shader->bind();
@@ -988,27 +1004,23 @@ struct Level {
Core::mModel.identity(); Core::mModel.identity();
Core::color = vec4(1.0f);
Core::ambient = vec3(0.0f);
shader->setParam(uColor, Core::color);
shader->setParam(uAmbient, Core::ambient);
for (int i = 0; i < level.roomsCount; i++) for (int i = 0; i < level.roomsCount; i++)
renderRoom(i); renderRoom(i);
for (int i = 0; i < level.entitiesCount; i++) for (int i = 0; i < level.entitiesCount; i++)
renderEntity(level.entities[i]); renderEntity(level.entities[i]);
#ifdef _DEBUG
// debugMeshes();
Debug::Draw::begin(); Debug::Draw::begin();
debugRooms(); debugRooms();
// debugMeshes(); // debugLights();
debugLights(); debugPortals();
// debugPortals();
// debugEntity(); // debugEntity();
Debug::Draw::end(); Debug::Draw::end();
#endif
} }
}; };
#endif #endif

View File

@@ -113,6 +113,7 @@ struct vec4 {
vec4() {} vec4() {}
vec4(float s) : x(s), y(s), z(s), w(s) {} vec4(float s) : x(s), y(s), z(s), w(s) {}
vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
vec4(const vec3 &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
}; };
struct quat { struct quat {