mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-10 23:24:06 +02:00
#3 №14 separated lara.h & enemy.h for controllers, add basic enemy controllers, add roll animation for lara, add text in debug mode, #8 smooth following camera, side view while backflip
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
69
src/camera.h
69
src/camera.h
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
|
#include "lara.h"
|
||||||
|
|
||||||
#define MAX_CLIP_PLANES 10
|
#define MAX_CLIP_PLANES 10
|
||||||
|
|
||||||
|
|
||||||
struct Frustum {
|
struct Frustum {
|
||||||
|
|
||||||
struct Poly {
|
struct Poly {
|
||||||
@@ -47,39 +47,8 @@ struct Frustum {
|
|||||||
planes[i].w = -(pos.dot(planes[i].xyz));
|
planes[i].w = -(pos.dot(planes[i].xyz));
|
||||||
e1 = e2;
|
e1 = e2;
|
||||||
}
|
}
|
||||||
#ifdef _DEBUG
|
|
||||||
dbg++;
|
|
||||||
debugPoly = poly;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
void debug() {
|
|
||||||
if (debugPoly.count < 3) return;
|
|
||||||
|
|
||||||
glUseProgram(0);
|
|
||||||
Core::setBlending(bmAdd);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glBegin(GL_TRIANGLES);
|
|
||||||
for (int i = 0; i < debugPoly.count; i++) {
|
|
||||||
glVertex3fv((GLfloat*)&pos);
|
|
||||||
glVertex3fv((GLfloat*)&debugPoly.vertices[i]);
|
|
||||||
glVertex3fv((GLfloat*)&debugPoly.vertices[(i + 1) % debugPoly.count]);
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glColor3f(0, 1, 0);
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
for (int i = 0; i <= debugPoly.count; i++) {
|
|
||||||
glVertex3fv((GLfloat*)&debugPoly.vertices[i % debugPoly.count]);
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
Core::setBlending(bmAlpha);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void clipPlane(const Poly &src, Poly &dst, const vec4 &plane) {
|
void clipPlane(const Poly &src, Poly &dst, const vec4 &plane) {
|
||||||
dst.count = 0;
|
dst.count = 0;
|
||||||
if (!src.count) return;
|
if (!src.count) return;
|
||||||
@@ -168,7 +137,7 @@ struct Camera : Controller {
|
|||||||
Frustum *frustum;
|
Frustum *frustum;
|
||||||
|
|
||||||
float fov, znear, zfar;
|
float fov, znear, zfar;
|
||||||
vec3 pos, target;
|
vec3 target, destPos, lastDest;
|
||||||
|
|
||||||
int room;
|
int room;
|
||||||
|
|
||||||
@@ -179,13 +148,14 @@ struct Camera : Controller {
|
|||||||
angle.y += PI;
|
angle.y += PI;
|
||||||
|
|
||||||
room = owner->getEntity().room;
|
room = owner->getEntity().room;
|
||||||
|
pos = pos - getDir() * 1024.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Camera() {
|
~Camera() {
|
||||||
delete frustum;
|
delete frustum;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual TR::Room& getRoom() {
|
virtual TR::Room& getRoom() const {
|
||||||
return level->rooms[room];
|
return level->rooms[room];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,10 +170,6 @@ struct Camera : Controller {
|
|||||||
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
|
#endif
|
||||||
// deltaPos = deltaPos.lerp(targetDeltaPos, Core::deltaTime * 10.0f);
|
|
||||||
// angle = angle.lerp(targetAngle, Core::deltaTime);
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
||||||
angle.x += delta.y * 0.01f;
|
angle.x += delta.y * 0.01f;
|
||||||
@@ -211,25 +177,31 @@ struct Camera : Controller {
|
|||||||
Input::mouse.start.L = Input::mouse.pos;
|
Input::mouse.start.L = Input::mouse.pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// angle.x = owner->angle.x;
|
|
||||||
angle.y = PI - owner->angle.y;
|
angle.y = PI - owner->angle.y;
|
||||||
angle.z = 0.0f;
|
angle.z = 0.0f;
|
||||||
|
|
||||||
angle.x = min(max(angle.x, -80 * DEG2RAD), 80 * DEG2RAD);
|
angle.x = min(max(angle.x, -80 * DEG2RAD), 80 * DEG2RAD);
|
||||||
|
|
||||||
vec3 dir = vec3(sinf(PI - angle.y) * cosf(-angle.x), -sinf(-angle.x), cosf(PI - angle.y) * cosf(-angle.x));
|
vec3 dir = getDir();
|
||||||
|
|
||||||
float height = owner->inWater ? 256.0f : 768.0f;
|
float height = owner->stand == Controller::STAND_UNDERWATER ? 256.0f : 768.0f;
|
||||||
|
|
||||||
target = vec3(owner->pos.x, owner->pos.y - height, owner->pos.z);
|
target = vec3(owner->pos.x, owner->pos.y - height, owner->pos.z);
|
||||||
pos = target - dir * 1024.0;
|
|
||||||
|
if (owner->state != Lara::STATE_BACK_JUMP) {
|
||||||
|
destPos = target - dir * 1024.0f;
|
||||||
|
lastDest = destPos;
|
||||||
|
} else
|
||||||
|
destPos = lastDest + dir.cross(vec3(0, 1, 0)).normal() * 2048.0f - vec3(0.0f, 512.0f, 0.0f);
|
||||||
|
|
||||||
|
pos = pos.lerp(destPos, min(1.0f, Core::deltaTime * 2.0f));
|
||||||
|
|
||||||
FloorInfo info = getFloorInfo((int)pos.x, (int)pos.z);
|
FloorInfo info = getFloorInfo((int)pos.x, (int)pos.z);
|
||||||
|
|
||||||
if (info.roomNext != 255)
|
if (info.roomNext != 255)
|
||||||
room = info.roomNext;
|
room = info.roomNext;
|
||||||
|
|
||||||
if (pos.y < info.ceiling) {
|
if (destPos.y < info.ceiling) {
|
||||||
if (info.roomAbove != 255)
|
if (info.roomAbove != 255)
|
||||||
room = info.roomAbove;
|
room = info.roomAbove;
|
||||||
else
|
else
|
||||||
@@ -256,17 +228,6 @@ struct Camera : Controller {
|
|||||||
|
|
||||||
frustum->pos = Core::viewPos;
|
frustum->pos = Core::viewPos;
|
||||||
frustum->calcPlanes(Core::mViewProj);
|
frustum->calcPlanes(Core::mViewProj);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
vec3 offset = vec3(0.0f) - (Input::down[ikR] ? (Core::mViewInv.dir.xyz * 2048 - vec3(0, 2048, 0)) : vec3(0.0f));
|
|
||||||
|
|
||||||
Core::mViewInv = mat4(pos - offset, target - offset, vec3(0, -1, 0));
|
|
||||||
Core::mView = Core::mViewInv.inverse();
|
|
||||||
Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);
|
|
||||||
|
|
||||||
Core::mViewProj = Core::mProj * Core::mView;
|
|
||||||
Core::viewPos = Core::mViewInv.offset.xyz;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
617
src/controller.h
617
src/controller.h
@@ -12,28 +12,43 @@ struct Controller {
|
|||||||
TR::Level *level;
|
TR::Level *level;
|
||||||
int entity;
|
int entity;
|
||||||
|
|
||||||
float fTime;
|
enum Stand {
|
||||||
int lastFrame;
|
STAND_AIR, STAND_GROUND, STAND_UNDERWATER, STAND_ONWATER
|
||||||
|
} stand;
|
||||||
|
int state;
|
||||||
|
int mask;
|
||||||
|
|
||||||
|
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,
|
||||||
|
DEATH = 1 << 11 };
|
||||||
|
|
||||||
|
float animTime;
|
||||||
|
int animIndex;
|
||||||
|
int animPrevFrame;
|
||||||
|
|
||||||
vec3 pos, velocity;
|
vec3 pos, velocity;
|
||||||
vec3 angle;
|
vec3 angle;
|
||||||
|
|
||||||
|
float angleExt;
|
||||||
|
|
||||||
int health;
|
int health;
|
||||||
|
|
||||||
float turnTime;
|
float turnTime;
|
||||||
|
|
||||||
bool onGround;
|
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), animTime(0.0f), animPrevFrame(0), health(100), turnTime(0.0f) {
|
||||||
bool inWater;
|
|
||||||
|
|
||||||
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();
|
TR::Entity &e = getEntity();
|
||||||
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
||||||
angle = vec3(0.0f, e.rotation / 16384.0f * PI * 0.5f, 0.0f);
|
angle = vec3(0.0f, e.rotation / 16384.0f * PI * 0.5f, 0.0f);
|
||||||
onGround = inWater = false;
|
stand = STAND_GROUND;
|
||||||
|
animIndex = getModel().animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update() {}
|
|
||||||
|
|
||||||
void updateEntity() {
|
void updateEntity() {
|
||||||
TR::Entity &e = getEntity();
|
TR::Entity &e = getEntity();
|
||||||
e.x = int(pos.x);
|
e.x = int(pos.x);
|
||||||
@@ -42,7 +57,7 @@ struct Controller {
|
|||||||
e.rotation = int(angle.y / (PI * 0.5f) * 16384.0f);
|
e.rotation = int(angle.y / (PI * 0.5f) * 16384.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool insideRoom(const vec3 &pos, int room) {
|
bool insideRoom(const vec3 &pos, int room) const {
|
||||||
TR::Room &r = level->rooms[room];
|
TR::Room &r = level->rooms[room];
|
||||||
vec3 min = vec3(r.info.x, r.info.yTop, r.info.z);
|
vec3 min = vec3(r.info.x, r.info.yTop, r.info.z);
|
||||||
vec3 max = min + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024);
|
vec3 max = min + vec3(r.xSectors * 1024, r.info.yBottom - r.info.yTop, r.zSectors * 1024);
|
||||||
@@ -52,11 +67,11 @@ struct Controller {
|
|||||||
pos.z >= min.z && pos.z <= max.z;
|
pos.z >= min.z && pos.z <= max.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
TR::Entity& getEntity() {
|
TR::Entity& getEntity() const {
|
||||||
return level->entities[entity];
|
return level->entities[entity];
|
||||||
}
|
}
|
||||||
|
|
||||||
TR::Model& getModel() {
|
TR::Model& getModel() const {
|
||||||
TR::Entity &entity = getEntity();
|
TR::Entity &entity = getEntity();
|
||||||
for (int i = 0; i < level->modelsCount; i++)
|
for (int i = 0; i < level->modelsCount; i++)
|
||||||
if (entity.id == level->models[i].id)
|
if (entity.id == level->models[i].id)
|
||||||
@@ -65,13 +80,13 @@ struct Controller {
|
|||||||
return level->models[0];
|
return level->models[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual TR::Room& getRoom() {
|
virtual TR::Room& getRoom() const {
|
||||||
int index = getEntity().room;
|
int index = getEntity().room;
|
||||||
ASSERT(index >= 0 && index < level->roomsCount);
|
ASSERT(index >= 0 && index < level->roomsCount);
|
||||||
return level->rooms[index];
|
return level->rooms[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
TR::Room::Sector& getSector(int x, int z, int &dx, int &dz) {
|
TR::Room::Sector& getSector(int x, int z, int &dx, int &dz) const {
|
||||||
TR::Room &room = getRoom();
|
TR::Room &room = getRoom();
|
||||||
|
|
||||||
int sx = x - room.info.x;
|
int sx = x - room.info.x;
|
||||||
@@ -88,19 +103,26 @@ struct Controller {
|
|||||||
return room.sectors[sx * room.zSectors + sz];
|
return room.sectors[sx * room.zSectors + sz];
|
||||||
}
|
}
|
||||||
|
|
||||||
TR::Room::Sector& getSector(int &dx, int &dz) {
|
TR::Room::Sector& getSector(int &dx, int &dz) const {
|
||||||
TR::Entity &entity = getEntity();
|
TR::Entity &entity = getEntity();
|
||||||
return getSector(entity.x, entity.z, dx, dz);
|
return getSector(entity.x, entity.z, dx, dz);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool changeState(int state) {
|
int setAnimation(int index, int frame = -1) {
|
||||||
TR::Model &model = getModel();
|
animIndex = index;
|
||||||
TR::Animation *anim = &level->anims[model.animation];
|
TR::Animation &anim = level->anims[animIndex];
|
||||||
|
animTime = frame == -1 ? 0.0f : ((frame - anim.frameStart) / 30.0f);
|
||||||
|
animPrevFrame = -1;
|
||||||
|
return state = anim.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setState(int state) {
|
||||||
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
|
||||||
if (state == anim->state)
|
if (state == anim->state)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int fIndex = int(fTime * 30.0f);
|
int fIndex = int(animTime * 30.0f);
|
||||||
|
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
|
|
||||||
@@ -111,8 +133,7 @@ struct Controller {
|
|||||||
for (int j = 0; j < s.rangesCount; j++) {
|
for (int j = 0; j < s.rangesCount; j++) {
|
||||||
TR::AnimRange &range = level->ranges[s.rangesOffset + j];
|
TR::AnimRange &range = level->ranges[s.rangesOffset + j];
|
||||||
if (anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high) {
|
if (anim->frameStart + fIndex >= range.low && anim->frameStart + fIndex <= range.high) {
|
||||||
model.animation = range.nextAnimation;
|
setAnimation(range.nextAnimation, range.nextFrame);
|
||||||
fTime = (range.nextFrame - level->anims[model.animation].frameStart) / 30.0f;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +143,7 @@ struct Controller {
|
|||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getOverlap(int fromX, int fromY, int fromZ, int toX, int toZ, int &delta) {
|
int getOverlap(int fromX, int fromY, int fromZ, int toX, int toZ, int &delta) const {
|
||||||
int dx, dz;
|
int dx, dz;
|
||||||
TR::Room::Sector &s = getSector(fromX, fromZ, dx, dz);
|
TR::Room::Sector &s = getSector(fromX, fromZ, dx, dz);
|
||||||
|
|
||||||
@@ -236,7 +257,7 @@ struct Controller {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void playSound(int id) {
|
void playSound(int id) const {
|
||||||
int16 a = level->soundsMap[id];
|
int16 a = level->soundsMap[id];
|
||||||
TR::SoundInfo &b = level->soundsInfo[a];
|
TR::SoundInfo &b = level->soundsInfo[a];
|
||||||
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
if (b.chance == 0 || (rand() & 0x7fff) <= b.chance) {
|
||||||
@@ -248,418 +269,8 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
vec3 getDir() const {
|
||||||
|
return vec3(sinf(PI - angle.y) * cosf(-angle.x), -sinf(-angle.x), cosf(PI - angle.y) * cosf(-angle.x));
|
||||||
|
|
||||||
#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 {
|
|
||||||
|
|
||||||
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;
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
pos = vec3(41015, 3584, 34494);
|
|
||||||
angle = vec3(0.0f, -PI, 0.0f);
|
|
||||||
getEntity().room = 51;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void update() {
|
|
||||||
TR::Model &model = getModel();
|
|
||||||
TR::Animation *anim = &level->anims[model.animation];
|
|
||||||
|
|
||||||
fTime += Core::deltaTime;
|
|
||||||
// return;
|
|
||||||
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 };
|
|
||||||
|
|
||||||
inWater = (getRoom().flags & TR::ROOM_FLAG_WATER);
|
|
||||||
|
|
||||||
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 & DEATH)
|
|
||||||
state = TR::STATE_DEATH;
|
|
||||||
else 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_UP_JUMP || state == TR::STATE_BACK_JUMP || state == TR::STATE_LEFT_JUMP || state == TR::STATE_RIGHT_JUMP || state == TR::STATE_FALL || state == TR::STATE_REACH) {
|
|
||||||
model.animation = TR::ANIM_WATER_FALL;
|
|
||||||
fTime = 0.0f;
|
|
||||||
state = level->anims[model.animation].state;
|
|
||||||
} else if (state == TR::STATE_SWAN_DIVE) {
|
|
||||||
state = TR::STATE_DIVE;
|
|
||||||
angle.x = -PI * 0.5f;
|
|
||||||
} 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;
|
|
||||||
} else if (state != TR::STATE_SWAN_DIVE && state != TR::STATE_REACH && state != TR::STATE_FALL && state != TR::STATE_UP_JUMP && state != TR::STATE_BACK_JUMP && state != TR::STATE_LEFT_JUMP && state != TR::STATE_RIGHT_JUMP) {
|
|
||||||
model.animation = TR::ANIM_FALL;
|
|
||||||
state = level->anims[model.animation].state;
|
|
||||||
}
|
|
||||||
// state = TR::STATE_FALL;
|
|
||||||
// LOG("- speed: %f\n", velocity.length());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to set new state
|
|
||||||
if (!changeState(state)) {
|
|
||||||
int stopState = TR::STATE_FALL;
|
|
||||||
|
|
||||||
if (state == TR::STATE_DIVE)
|
|
||||||
stopState = state;
|
|
||||||
else 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;
|
|
||||||
|
|
||||||
changeState(stopState);
|
|
||||||
/*
|
|
||||||
if (state == stopState || !changeState(stopState)) {
|
|
||||||
int stopAnim = -1;
|
|
||||||
switch (stopState) {
|
|
||||||
case TR::STATE_FALL : stopAnim = TR::ANIM_FALL; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopAnim > -1) {
|
|
||||||
model.animation = stopAnim;
|
|
||||||
fTime = 0.0f;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
anim = &level->anims[model.animation]; // get new animation and state (if it has been changed)
|
|
||||||
state = anim->state;
|
|
||||||
|
|
||||||
int fCount = anim->frameEnd - anim->frameStart + 1;
|
|
||||||
int fIndex = int(fTime * 30.0f);
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
// show state transitions for current animation
|
|
||||||
static bool lState = false;
|
|
||||||
if (Input::down[ikEnter]) {
|
|
||||||
if (!lState) {
|
|
||||||
lState = true;
|
|
||||||
static int snd_id = 0;
|
|
||||||
playSound(snd_id);
|
|
||||||
LOG("sound: %d\n", snd_id++);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
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");
|
|
||||||
}*/
|
|
||||||
} else
|
|
||||||
lState = false;
|
|
||||||
#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
|
|
||||||
velocity = velocity - velocity * min(1.0f, Core::deltaTime * 2.0f);
|
|
||||||
|
|
||||||
// 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++) {
|
|
||||||
int cmd = *ptr++;
|
|
||||||
switch (cmd) {
|
|
||||||
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;
|
|
||||||
int idx = frame - anim->frameStart;
|
|
||||||
|
|
||||||
// if (fIndex != lastFrame)
|
|
||||||
// LOG("play sound at %d current %d last %d (%d)\n", idx, fIndex, lastFrame, (int)id);
|
|
||||||
|
|
||||||
if (idx > lastFrame && idx <= fIndex) {
|
|
||||||
playSound(id);
|
|
||||||
}
|
|
||||||
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 %d\n", cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for next animation
|
|
||||||
if (endFrame) {
|
|
||||||
model.animation = anim->nextAnimation;
|
|
||||||
TR::Animation *nextAnim = &level->anims[anim->nextAnimation];
|
|
||||||
fIndex = anim->nextFrame - nextAnim->frameStart;
|
|
||||||
fTime = fIndex / 30.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
move(velocity * dt);
|
|
||||||
collide();
|
|
||||||
|
|
||||||
updateEntity();
|
|
||||||
|
|
||||||
lastFrame = fIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void move(const vec3 &offset) {
|
|
||||||
vec3 p = pos;
|
|
||||||
pos = pos + offset;
|
|
||||||
|
|
||||||
int delta;
|
|
||||||
int d = getOverlap((int)p.x, (int)p.y, (int)p.z, (int)pos.x, (int)pos.z, delta);
|
|
||||||
|
|
||||||
int state = level->anims[getModel().animation].state;
|
|
||||||
bool stop = false;
|
|
||||||
|
|
||||||
if ((d == NO_OVERLAP) ||
|
|
||||||
((state == TR::STATE_WALK || state == TR::STATE_BACK || state == TR::STATE_STEP_LEFT || state == TR::STATE_STEP_RIGHT) && delta > 256) /*||
|
|
||||||
(delta < -256) */) {
|
|
||||||
|
|
||||||
pos = p;
|
|
||||||
|
|
||||||
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;
|
|
||||||
fTime = 0;
|
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
TR::Entity &entity = getEntity();
|
|
||||||
entity.x = (int)pos.x;
|
|
||||||
entity.y = (int)pos.y;
|
|
||||||
entity.z = (int)pos.z;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void collide() {
|
void collide() {
|
||||||
@@ -713,27 +324,125 @@ struct Lara : Controller {
|
|||||||
entity.room = s.roomAbove;
|
entity.room = s.roomAbove;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int state = level->anims[getModel().animation].state;
|
|
||||||
|
|
||||||
// TODO: use a brain!
|
|
||||||
float extra = 0;
|
|
||||||
if (state == TR::STATE_WALK ||
|
|
||||||
state == TR::STATE_RUN ||
|
|
||||||
state == TR::STATE_STOP ||
|
|
||||||
state == TR::STATE_FAST_BACK ||
|
|
||||||
state == TR::STATE_TURN_RIGHT ||
|
|
||||||
state == TR::STATE_TURN_LEFT ||
|
|
||||||
state == TR::STATE_BACK ||
|
|
||||||
state == TR::STATE_FAST_TURN ||
|
|
||||||
state == TR::STATE_STEP_RIGHT ||
|
|
||||||
state == TR::STATE_STEP_LEFT ||
|
|
||||||
state == TR::STATE_ROLL)
|
|
||||||
extra = 256 + 128;
|
|
||||||
|
|
||||||
onGround = (pos.y + extra >= info.floor) && (info.roomBelow == 0xFF) && !(getRoom().flags & TR::ROOM_FLAG_WATER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void updateVelocity() {}
|
||||||
|
virtual void move() {}
|
||||||
|
virtual Stand getStand() { return STAND_AIR; }
|
||||||
|
virtual int getStateAir() { return state; }
|
||||||
|
virtual int getStateGround() { return state; }
|
||||||
|
virtual int getStateUnderwater() { return state; }
|
||||||
|
virtual int getStateOnwater() { return state; }
|
||||||
|
virtual int getStateDeath() { return state; }
|
||||||
|
virtual int getStateDefault() { return state; }
|
||||||
|
virtual int getInputMask() { return 0; }
|
||||||
|
|
||||||
|
virtual int getState(Stand stand) {
|
||||||
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
|
||||||
|
int state = anim->state;
|
||||||
|
|
||||||
|
if (mask & DEATH)
|
||||||
|
state = getStateDeath();
|
||||||
|
else if (stand == STAND_GROUND)
|
||||||
|
state = getStateGround();
|
||||||
|
else if (stand == STAND_AIR)
|
||||||
|
state = getStateAir();
|
||||||
|
else if (stand == STAND_UNDERWATER)
|
||||||
|
state = getStateUnderwater();
|
||||||
|
else
|
||||||
|
state = getStateOnwater();
|
||||||
|
|
||||||
|
// try to set new state
|
||||||
|
if (!setState(state))
|
||||||
|
setState(getStateDefault());
|
||||||
|
|
||||||
|
return level->anims[animIndex].state;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void updateBegin() {
|
||||||
|
animTime += Core::deltaTime;
|
||||||
|
mask = getInputMask();
|
||||||
|
state = getState(stand = getStand());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void updateEnd() {
|
||||||
|
int frameIndex = int(animTime * 30.0f);
|
||||||
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
bool endFrame = frameIndex > anim->frameEnd - anim->frameStart;
|
||||||
|
|
||||||
|
// apply animation commands
|
||||||
|
int16 *ptr = &level->commands[anim->animCommand];
|
||||||
|
|
||||||
|
for (int i = 0; i < anim->acCount; i++) {
|
||||||
|
int cmd = *ptr++;
|
||||||
|
switch (cmd) {
|
||||||
|
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(angleExt) * sz;
|
||||||
|
velocity.y = sy;
|
||||||
|
velocity.z = cosf(angleExt) * sz;
|
||||||
|
LOG("speed: %f\n", velocity.length());
|
||||||
|
stand = STAND_AIR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x03 : // empty hands
|
||||||
|
break;
|
||||||
|
case 0x04 : // kill
|
||||||
|
break;
|
||||||
|
case 0x05 : { // play sound
|
||||||
|
int frame = (*ptr++);
|
||||||
|
int id = (*ptr++) & 0x3FFF;
|
||||||
|
int idx = frame - anim->frameStart;
|
||||||
|
|
||||||
|
if (idx > animPrevFrame && idx <= frameIndex) {
|
||||||
|
playSound(id);
|
||||||
|
// LOG("play sound %d\n", getEntity().id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x06 : // effect
|
||||||
|
if (frameIndex != animPrevFrame && frameIndex + anim->frameStart == ptr[0]) {
|
||||||
|
if (ptr[1] == 0) // rolling
|
||||||
|
angle.y = angle.y + PI;
|
||||||
|
}
|
||||||
|
ptr += 2;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
LOG("unknown animation command %d\n", cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endFrame) // if animation is end - switch to next
|
||||||
|
setAnimation(anim->nextAnimation, anim->nextFrame);
|
||||||
|
else
|
||||||
|
animPrevFrame = frameIndex;
|
||||||
|
|
||||||
|
updateVelocity();
|
||||||
|
move();
|
||||||
|
collide();
|
||||||
|
|
||||||
|
updateEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void updateState() {}
|
||||||
|
|
||||||
|
virtual void update() {
|
||||||
|
updateBegin();
|
||||||
|
updateState();
|
||||||
|
updateEnd();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
76
src/debug.h
76
src/debug.h
@@ -4,8 +4,28 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
extern HDC hDC;
|
||||||
|
|
||||||
namespace Debug {
|
namespace Debug {
|
||||||
|
|
||||||
|
static GLuint font;
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
font = glGenLists(256);
|
||||||
|
HDC hdc = hDC;
|
||||||
|
HFONT hfont = CreateFontA(-MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0,
|
||||||
|
0, 0, FW_BOLD, 0, 0, 0,
|
||||||
|
ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||||||
|
ANTIALIASED_QUALITY, DEFAULT_PITCH, "Courier New");
|
||||||
|
SelectObject(hdc, hfont);
|
||||||
|
wglUseFontBitmaps(hdc, 0, 256, font);
|
||||||
|
DeleteObject(hfont);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free() {
|
||||||
|
glDeleteLists(font, 256);
|
||||||
|
}
|
||||||
|
|
||||||
void begin() {
|
void begin() {
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadMatrixf((GLfloat*)&Core::mProj);
|
glLoadMatrixf((GLfloat*)&Core::mProj);
|
||||||
@@ -111,6 +131,41 @@ namespace Debug {
|
|||||||
glVertex3fv((GLfloat*)&p);
|
glVertex3fv((GLfloat*)&p);
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void text(const vec2 &pos, const vec4 &color, const char *str) {
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(0, Core::width, Core::height, 0, 0, 1);
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
glColor4fv((GLfloat*)&color);
|
||||||
|
glRasterPos2f(pos.x, pos.y);
|
||||||
|
glListBase(font);
|
||||||
|
glCallLists(strlen(str), GL_UNSIGNED_BYTE, str);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void text(const vec3 &pos, const vec4 &color, const char *str) {
|
||||||
|
vec4 p = Core::mViewProj * vec4(pos, 1);
|
||||||
|
if (p.w > 0) {
|
||||||
|
p.xyz = p.xyz * (1.0f / p.w);
|
||||||
|
p.y = -p.y;
|
||||||
|
p.xyz = (p.xyz * 0.5f + vec3(0.5f)) * vec3(Core::width, Core::height, 1.0f);
|
||||||
|
text(vec2(p.x, p.y), color, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Level {
|
namespace Level {
|
||||||
@@ -373,12 +428,14 @@ namespace Debug {
|
|||||||
sm->getBox(true, m.rotation, min, max);
|
sm->getBox(true, m.rotation, min, max);
|
||||||
Debug::Draw::box(offset + min - vec3(10.0f), offset + max + vec3(10.0f), vec4(1, 0, 0, 0.50));
|
Debug::Draw::box(offset + min - vec3(10.0f), offset + max + vec3(10.0f), vec4(1, 0, 0, 0.50));
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
TR::Mesh *mesh = (TR::Mesh*)&level.meshData[level.meshOffsets[sm->mesh] / 2];
|
TR::Mesh *mesh = (TR::Mesh*)&level.meshData[level.meshOffsets[sm->mesh] / 2];
|
||||||
|
{ //if (mesh->collider.info || mesh->collider.flags) {
|
||||||
ASSERT(mesh->radius == 0 || mesh->radius == 0x10000);
|
char buf[255];
|
||||||
|
sprintf(buf, "radius %d info %d flags %d", (int)mesh->collider.radius, (int)mesh->collider.info, (int)mesh->collider.flags);
|
||||||
Debug::Draw::sphere(offset + (min + max) * 0.5f, 128, mesh->radius == 0 ? vec4(0, 0, 1, 1) : vec4(0, 1, 0, 1));
|
Debug::Draw::text(offset + (min + max) * 0.5f, vec4(0.5, 0.5, 0.5, 1), buf);
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// dynamic objects
|
// dynamic objects
|
||||||
@@ -435,7 +492,14 @@ namespace Debug {
|
|||||||
|
|
||||||
int offset = level.meshOffsets[m.mStart + k];
|
int offset = level.meshOffsets[m.mStart + k];
|
||||||
TR::Mesh *mesh = (TR::Mesh*)&level.meshData[offset / 2];
|
TR::Mesh *mesh = (TR::Mesh*)&level.meshData[offset / 2];
|
||||||
Debug::Draw::sphere(matrix * joint * mesh->center, mesh->radius & 0x3FF, mesh->radius > 0x3FF ? vec4(1, 0, 0, 0.5f) : vec4(0, 1, 1, 0.5f));
|
Debug::Draw::sphere(matrix * joint * mesh->center, mesh->collider.radius, mesh->collider.info ? vec4(1, 0, 0, 0.5f) : vec4(0, 1, 1, 0.5f));
|
||||||
|
/*
|
||||||
|
{ //if (e.id != 0) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "(%d) radius %d info %d flags %d", e.id, (int)mesh->collider.radius, (int)mesh->collider.info, (int)mesh->collider.flags);
|
||||||
|
Debug::Draw::text(matrix * joint * mesh->center, vec4(0.5, 1, 0.5, 1), buf);
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
84
src/enemy.h
Normal file
84
src/enemy.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#ifndef H_ENEMY
|
||||||
|
#define H_ENEMY
|
||||||
|
|
||||||
|
#include "controller.h"
|
||||||
|
|
||||||
|
struct Enemy : Controller {
|
||||||
|
Enemy(TR::Level *level, int entity) : Controller(level, entity) {}
|
||||||
|
|
||||||
|
virtual Stand getStand() {
|
||||||
|
return STAND_GROUND;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Wolf : Enemy {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STATE_STOP = 1,
|
||||||
|
STATE_WALK = 2,
|
||||||
|
STATE_RUN = 3,
|
||||||
|
STATE_STALKING = 5,
|
||||||
|
STATE_JUMP = 6,
|
||||||
|
STATE_HOWL = 7,
|
||||||
|
STATE_SLEEP = 8,
|
||||||
|
STATE_GROWL = 9,
|
||||||
|
STATE_10 = 10, // WTF?
|
||||||
|
STATE_ATTACK = 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
Wolf(TR::Level *level, int entity) : Enemy(level, entity) {}
|
||||||
|
|
||||||
|
virtual int getStateGround() {
|
||||||
|
// STATE_SLEEP -> STATE_STOP
|
||||||
|
// STATE_STOP -> STATE_WALK, STATE_HOWL, STATE_SLEEP, STATE_GROWL
|
||||||
|
// STATE_WALK -> NULL
|
||||||
|
// STATE_RUN -> STaTE_JUMP, STATe_GROWL, STATE_10
|
||||||
|
// STATE_STALKING -> STATE_RUN, STATE_GROWL, STATE_BITING
|
||||||
|
// STATE_JUMP -> STATE_RUN
|
||||||
|
// STATE_GROWL -> STATE_STOP, STATE_RUN, STATE_STALKING, STATE_HOWL, STATE_ATTACK
|
||||||
|
// STATE_BITING -> NULL
|
||||||
|
|
||||||
|
// if (state == STATE_SLEEP) return STATE_STOP;
|
||||||
|
// if (state == STATE_STOP) return STATE_GROWL;
|
||||||
|
// if (state == STATE_GROWL) return STATE_ATTACK;
|
||||||
|
// if (state == STATE_RUN) return STATE_10;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Bear : Enemy {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STATE_STOP = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
Bear(TR::Level *level, int entity) : Enemy(level, entity) {}
|
||||||
|
|
||||||
|
virtual int getStateGround() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Bat : Enemy {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STATE_AWAKE = 1,
|
||||||
|
STATE_FLY = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
Bat(TR::Level *level, int entity) : Enemy(level, entity) {}
|
||||||
|
|
||||||
|
virtual Stand getStand() {
|
||||||
|
return STAND_AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getStateAir() {
|
||||||
|
animTime = 0.0f;
|
||||||
|
return STATE_AWAKE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
92
src/format.h
92
src/format.h
@@ -71,76 +71,6 @@ namespace TR {
|
|||||||
#define ENTITY_AMMO_SHOTGUN 89
|
#define ENTITY_AMMO_SHOTGUN 89
|
||||||
#define ENTITY_AMMO_MAGNUM 90
|
#define ENTITY_AMMO_MAGNUM 90
|
||||||
|
|
||||||
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
|
||||||
enum LaraAnim : int32 {
|
|
||||||
ANIM_STAND = 11,
|
|
||||||
ANIM_FALL = 34,
|
|
||||||
ANIM_SMASH_JUMP = 32,
|
|
||||||
ANIM_SMASH_RUN_LEFT = 53,
|
|
||||||
ANIM_SMASH_RUN_RIGHT = 54,
|
|
||||||
ANIM_WATER_FALL = 112,
|
|
||||||
};
|
|
||||||
|
|
||||||
// http://www.tombraiderforums.com/showthread.php?t=211681
|
|
||||||
enum LaraState : int32 {
|
|
||||||
STATE_WALK,
|
|
||||||
STATE_RUN,
|
|
||||||
STATE_STOP,
|
|
||||||
STATE_FORWARD_JUMP,
|
|
||||||
STATE_4,
|
|
||||||
STATE_FAST_BACK,
|
|
||||||
STATE_TURN_RIGHT,
|
|
||||||
STATE_TURN_LEFT,
|
|
||||||
STATE_DEATH,
|
|
||||||
STATE_FALL,
|
|
||||||
STATE_HANG,
|
|
||||||
STATE_REACH,
|
|
||||||
STATE_SPLAT,
|
|
||||||
STATE_TREAD,
|
|
||||||
STATE_FAST_TURN_14,
|
|
||||||
STATE_COMPRESS,
|
|
||||||
STATE_BACK,
|
|
||||||
STATE_SWIM,
|
|
||||||
STATE_GLIDE,
|
|
||||||
STATE_NULL_19,
|
|
||||||
STATE_FAST_TURN,
|
|
||||||
STATE_STEP_RIGHT,
|
|
||||||
STATE_STEP_LEFT,
|
|
||||||
STATE_ROLL,
|
|
||||||
STATE_SLIDE,
|
|
||||||
STATE_BACK_JUMP,
|
|
||||||
STATE_RIGHT_JUMP,
|
|
||||||
STATE_LEFT_JUMP,
|
|
||||||
STATE_UP_JUMP,
|
|
||||||
STATE_FALL_BACK,
|
|
||||||
STATE_HANG_LEFT,
|
|
||||||
STATE_HANG_RIGHT,
|
|
||||||
STATE_SLIDE_BACK,
|
|
||||||
STATE_SURF_TREAD,
|
|
||||||
STATE_SURF_SWIM,
|
|
||||||
STATE_DIVE,
|
|
||||||
STATE_PUSH_BLOCK,
|
|
||||||
STATE_PULL_BLOCK,
|
|
||||||
STATE_PUSH_PULL_READY,
|
|
||||||
STATE_PICK_UP,
|
|
||||||
STATE_SWITCH_ON,
|
|
||||||
STATE_SWITCH_OFF,
|
|
||||||
STATE_USE_KEY,
|
|
||||||
STATE_USE_PUZZLE,
|
|
||||||
STATE_UNDERWATER_DEATH,
|
|
||||||
STATE_ROLL_45,
|
|
||||||
STATE_SPECIAL,
|
|
||||||
STATE_SURF_BACK,
|
|
||||||
STATE_SURF_LEFT,
|
|
||||||
STATE_SURF_RIGHT,
|
|
||||||
STATE_NULL_50,
|
|
||||||
STATE_NULL_51,
|
|
||||||
STATE_SWAN_DIVE,
|
|
||||||
STATE_FAST_DIVE,
|
|
||||||
STATE_HANDSTAND,
|
|
||||||
STATE_WATER_OUT,
|
|
||||||
STATE_MAX };
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct fixed {
|
struct fixed {
|
||||||
@@ -268,11 +198,16 @@ namespace TR {
|
|||||||
uint16 boxIndex:15, end:1;
|
uint16 boxIndex:15, end:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Collider {
|
||||||
|
uint16 radius:10, info:6;
|
||||||
|
uint16 flags:16;
|
||||||
|
};
|
||||||
|
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
Vertex center;
|
Vertex center;
|
||||||
int32 radius;
|
Collider collider;
|
||||||
|
|
||||||
int16 vCount;
|
uint16 vCount;
|
||||||
Vertex *vertices; // List of vertices (relative coordinates)
|
Vertex *vertices; // List of vertices (relative coordinates)
|
||||||
|
|
||||||
int16 nCount;
|
int16 nCount;
|
||||||
@@ -303,7 +238,9 @@ namespace TR {
|
|||||||
uint16 flags; // 0x0100 indicates "initially invisible", 0x3e00 is Activation Mask
|
uint16 flags; // 0x0100 indicates "initially invisible", 0x3e00 is Activation Mask
|
||||||
// 0x3e00 indicates "open" or "activated"; these can be XORed with
|
// 0x3e00 indicates "open" or "activated"; these can be XORed with
|
||||||
// related FloorData::FDlist fields (e.g. for switches)
|
// related FloorData::FDlist fields (e.g. for switches)
|
||||||
uint16 align; // ! not exists in file !
|
// not exists in file
|
||||||
|
uint16 align;
|
||||||
|
void *controller; // Controller implementation or NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Animation {
|
struct Animation {
|
||||||
@@ -474,7 +411,7 @@ namespace TR {
|
|||||||
int16 floor; // Height value in global units
|
int16 floor; // Height value in global units
|
||||||
uint16 overlap; // Index into Overlaps[].
|
uint16 overlap; // Index into Overlaps[].
|
||||||
|
|
||||||
bool contains(int x, int z) {
|
bool contains(uint32 x, uint32 z) {
|
||||||
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
|
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -673,8 +610,11 @@ namespace TR {
|
|||||||
stream.read(animTexturesData, stream.read(animTexturesDataSize));
|
stream.read(animTexturesData, stream.read(animTexturesDataSize));
|
||||||
// entities (enemies, items, lara etc.)
|
// entities (enemies, items, lara etc.)
|
||||||
entities = new Entity[stream.read(entitiesCount)];
|
entities = new Entity[stream.read(entitiesCount)];
|
||||||
for (int i = 0; i < entitiesCount; i++)
|
for (int i = 0; i < entitiesCount; i++) {
|
||||||
stream.raw(&entities[i], sizeof(entities[i]) - sizeof(entities[i].align));
|
stream.raw(&entities[i], sizeof(entities[i]) - sizeof(entities[i].align) - sizeof(entities[i].controller));
|
||||||
|
entities[i].align = 0;
|
||||||
|
entities[i].controller = NULL;
|
||||||
|
}
|
||||||
// palette
|
// palette
|
||||||
stream.seek(32 * 256); // skip lightmap palette
|
stream.seek(32 * 256); // skip lightmap palette
|
||||||
|
|
||||||
|
401
src/lara.h
Normal file
401
src/lara.h
Normal file
@@ -0,0 +1,401 @@
|
|||||||
|
#ifndef H_LARA
|
||||||
|
#define H_LARA
|
||||||
|
|
||||||
|
#include "controller.h"
|
||||||
|
|
||||||
|
#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 {
|
||||||
|
|
||||||
|
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
||||||
|
enum LaraAnim : int32 {
|
||||||
|
ANIM_STAND = 11,
|
||||||
|
ANIM_FALL = 34,
|
||||||
|
ANIM_SMASH_JUMP = 32,
|
||||||
|
ANIM_SMASH_RUN_LEFT = 53,
|
||||||
|
ANIM_SMASH_RUN_RIGHT = 54,
|
||||||
|
ANIM_WATER_FALL = 112,
|
||||||
|
ANIM_STAND_ROLL = 146,
|
||||||
|
};
|
||||||
|
|
||||||
|
// http://www.tombraiderforums.com/showthread.php?t=211681
|
||||||
|
enum LaraState : int32 {
|
||||||
|
STATE_WALK,
|
||||||
|
STATE_RUN,
|
||||||
|
STATE_STOP,
|
||||||
|
STATE_FORWARD_JUMP,
|
||||||
|
STATE_4,
|
||||||
|
STATE_FAST_BACK,
|
||||||
|
STATE_TURN_RIGHT,
|
||||||
|
STATE_TURN_LEFT,
|
||||||
|
STATE_DEATH,
|
||||||
|
STATE_FALL,
|
||||||
|
STATE_HANG,
|
||||||
|
STATE_REACH,
|
||||||
|
STATE_SPLAT,
|
||||||
|
STATE_TREAD,
|
||||||
|
STATE_FAST_TURN_14,
|
||||||
|
STATE_COMPRESS,
|
||||||
|
STATE_BACK,
|
||||||
|
STATE_SWIM,
|
||||||
|
STATE_GLIDE,
|
||||||
|
STATE_NULL_19,
|
||||||
|
STATE_FAST_TURN,
|
||||||
|
STATE_STEP_RIGHT,
|
||||||
|
STATE_STEP_LEFT,
|
||||||
|
STATE_ROLL,
|
||||||
|
STATE_SLIDE,
|
||||||
|
STATE_BACK_JUMP,
|
||||||
|
STATE_RIGHT_JUMP,
|
||||||
|
STATE_LEFT_JUMP,
|
||||||
|
STATE_UP_JUMP,
|
||||||
|
STATE_FALL_BACK,
|
||||||
|
STATE_HANG_LEFT,
|
||||||
|
STATE_HANG_RIGHT,
|
||||||
|
STATE_SLIDE_BACK,
|
||||||
|
STATE_SURF_TREAD,
|
||||||
|
STATE_SURF_SWIM,
|
||||||
|
STATE_DIVE,
|
||||||
|
STATE_PUSH_BLOCK,
|
||||||
|
STATE_PULL_BLOCK,
|
||||||
|
STATE_PUSH_PULL_READY,
|
||||||
|
STATE_PICK_UP,
|
||||||
|
STATE_SWITCH_ON,
|
||||||
|
STATE_SWITCH_OFF,
|
||||||
|
STATE_USE_KEY,
|
||||||
|
STATE_USE_PUZZLE,
|
||||||
|
STATE_UNDERWATER_DEATH,
|
||||||
|
STATE_ROLL_45,
|
||||||
|
STATE_SPECIAL,
|
||||||
|
STATE_SURF_BACK,
|
||||||
|
STATE_SURF_LEFT,
|
||||||
|
STATE_SURF_RIGHT,
|
||||||
|
STATE_NULL_50,
|
||||||
|
STATE_NULL_51,
|
||||||
|
STATE_SWAN_DIVE,
|
||||||
|
STATE_FAST_DIVE,
|
||||||
|
STATE_HANDSTAND,
|
||||||
|
STATE_WATER_OUT,
|
||||||
|
STATE_MAX };
|
||||||
|
|
||||||
|
Lara(TR::Level *level, int entity) : Controller(level, entity) {
|
||||||
|
/*
|
||||||
|
// level 2 (pool)
|
||||||
|
pos = vec3(70067, -256, 29104);
|
||||||
|
angle = vec3(0.0f, -0.68f, 0.0f);
|
||||||
|
getEntity().room = 15;
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
// level 2 (wolf)
|
||||||
|
pos = vec3(75671, -1024, 22862);
|
||||||
|
angle = vec3(0.0f, -PI * 0.25f, 0.0f);
|
||||||
|
getEntity().room = 13;
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
// level 3a
|
||||||
|
pos = vec3(41015, 3584, 34494);
|
||||||
|
angle = vec3(0.0f, -PI, 0.0f);
|
||||||
|
getEntity().room = 51;
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
// level 1
|
||||||
|
pos = vec3(20215, 6656, 52942);
|
||||||
|
angle = vec3(0.0f, PI, 0.0f);
|
||||||
|
getEntity().room = 14;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMovingState(int state) {
|
||||||
|
return state == STATE_RUN || state == STATE_WALK || state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Stand getStand() {
|
||||||
|
if (getRoom().flags & TR::ROOM_FLAG_WATER)
|
||||||
|
return STAND_UNDERWATER; // TODO: ONWATER
|
||||||
|
|
||||||
|
int extra = isMovingState(state) ? 256 : 0;
|
||||||
|
|
||||||
|
TR::Entity &e = getEntity();
|
||||||
|
FloorInfo info = getFloorInfo(e.x, e.z);
|
||||||
|
if (info.roomBelow == 0xFF && e.y + extra >= info.floor)
|
||||||
|
return STAND_GROUND;
|
||||||
|
|
||||||
|
return STAND_AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getStateAir() {
|
||||||
|
angle.x = 0.0f;
|
||||||
|
|
||||||
|
if (state == STATE_FORWARD_JUMP) {
|
||||||
|
if (mask & ACTION) return STATE_REACH;
|
||||||
|
if ((mask & (FORTH | WALK)) == (FORTH | WALK)) return STATE_SWAN_DIVE;
|
||||||
|
} else
|
||||||
|
if (state != STATE_SWAN_DIVE && state != STATE_REACH && state != STATE_FALL && state != STATE_UP_JUMP && state != STATE_BACK_JUMP && state != STATE_LEFT_JUMP && state != STATE_RIGHT_JUMP && state != STATE_ROLL)
|
||||||
|
return setAnimation(ANIM_FALL);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getStateGround() {
|
||||||
|
angle.x = 0.0f;
|
||||||
|
|
||||||
|
if ( (mask & (FORTH | BACK)) == (FORTH | BACK) && (state == STATE_STOP || state == STATE_RUN) )
|
||||||
|
return setAnimation(ANIM_STAND_ROLL);
|
||||||
|
|
||||||
|
// ready to jump
|
||||||
|
if (state == STATE_COMPRESS) {
|
||||||
|
switch (mask & (RIGHT | LEFT | FORTH | BACK)) {
|
||||||
|
case RIGHT : return STATE_RIGHT_JUMP;
|
||||||
|
case LEFT : return STATE_LEFT_JUMP;
|
||||||
|
case FORTH : return STATE_FORWARD_JUMP;
|
||||||
|
case BACK : return STATE_BACK_JUMP;
|
||||||
|
default : return STATE_UP_JUMP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// jump button is pressed
|
||||||
|
if (mask & JUMP) {
|
||||||
|
if ((mask & FORTH) && state == STATE_FORWARD_JUMP)
|
||||||
|
return STATE_RUN;
|
||||||
|
return state == STATE_RUN ? STATE_FORWARD_JUMP : STATE_COMPRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk button is pressed
|
||||||
|
if (mask & WALK) {
|
||||||
|
if (mask & FORTH) return STATE_WALK;
|
||||||
|
if (mask & BACK) return STATE_BACK;
|
||||||
|
if (mask & LEFT) return STATE_STEP_LEFT;
|
||||||
|
if (mask & RIGHT) return STATE_STEP_RIGHT;
|
||||||
|
return STATE_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only dpad buttons pressed
|
||||||
|
if (mask & FORTH) return STATE_RUN;
|
||||||
|
if (mask & BACK) return STATE_FAST_BACK;
|
||||||
|
if (mask & LEFT) return turnTime < FAST_TURN_TIME ? STATE_TURN_LEFT : STATE_FAST_TURN;
|
||||||
|
if (mask & RIGHT) return turnTime < FAST_TURN_TIME ? STATE_TURN_RIGHT : STATE_FAST_TURN;
|
||||||
|
return STATE_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getStateUnderwater() {
|
||||||
|
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH)
|
||||||
|
return setAnimation(ANIM_WATER_FALL);
|
||||||
|
|
||||||
|
if (state == STATE_SWAN_DIVE) {
|
||||||
|
angle.x = -PI * 0.5f;
|
||||||
|
return STATE_DIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & JUMP) return STATE_SWIM;
|
||||||
|
return (state == STATE_SWIM || velocity.y > GLIDE_SPEED) ? STATE_GLIDE : STATE_TREAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getStateOnwater() {
|
||||||
|
angle.x = 0.0f;
|
||||||
|
return STATE_SURF_TREAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getStateDeath() {
|
||||||
|
return STATE_DEATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getStateDefault() {
|
||||||
|
if (state == STATE_DIVE) return state;
|
||||||
|
if (stand == STAND_ONWATER) return STATE_SURF_TREAD;
|
||||||
|
if (stand == STAND_UNDERWATER) return STATE_TREAD;
|
||||||
|
if (stand == STAND_GROUND) return STATE_STOP;
|
||||||
|
return STATE_FALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getInputMask() {
|
||||||
|
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;
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void updateState() {
|
||||||
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
|
||||||
|
int fCount = anim->frameEnd - anim->frameStart;
|
||||||
|
int fIndex = int(animTime * 30.0f);
|
||||||
|
|
||||||
|
float rot = 0.0f;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// show state transitions for current animation
|
||||||
|
static bool lState = false;
|
||||||
|
if (Input::down[ikEnter]) {
|
||||||
|
if (!lState) {
|
||||||
|
lState = true;
|
||||||
|
static int snd_id = 0;
|
||||||
|
playSound(snd_id);
|
||||||
|
LOG("sound: %d\n", snd_id++);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
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++) {
|
||||||
|
AnimRange &range = level->ranges[sc.rangesOffset + j];
|
||||||
|
LOG("%d ", range.nextAnimation);
|
||||||
|
}
|
||||||
|
LOG("\n");
|
||||||
|
}*/
|
||||||
|
} else
|
||||||
|
lState = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// calculate turn tilt
|
||||||
|
if (state == STATE_RUN && (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 == STATE_TURN_LEFT || state == STATE_TURN_RIGHT || state == STATE_FAST_TURN)
|
||||||
|
turnTime += Core::deltaTime;
|
||||||
|
else
|
||||||
|
turnTime = 0.0f;
|
||||||
|
|
||||||
|
// get turning angle
|
||||||
|
float w = 0.0f;
|
||||||
|
|
||||||
|
if (state == STATE_SWIM || state == STATE_GLIDE)
|
||||||
|
w = TURN_WATER_FAST;
|
||||||
|
else if (state == STATE_TREAD)
|
||||||
|
w = TURN_WATER_SLOW;
|
||||||
|
else if (state == STATE_RUN || state == STATE_FAST_TURN)
|
||||||
|
w = TURN_FAST;
|
||||||
|
else if (state == STATE_FAST_BACK)
|
||||||
|
w = TURN_FAST_BACK;
|
||||||
|
else if (state == STATE_TURN_LEFT || state == STATE_TURN_RIGHT || state == STATE_WALK)
|
||||||
|
w = TURN_NORMAL;
|
||||||
|
else if (state == STATE_FORWARD_JUMP || state == 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 (stand == STAND_UNDERWATER && (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
|
||||||
|
angleExt = angle.y;
|
||||||
|
switch (state) {
|
||||||
|
case STATE_BACK :
|
||||||
|
case STATE_BACK_JUMP :
|
||||||
|
case STATE_FAST_BACK :
|
||||||
|
angleExt += PI;
|
||||||
|
break;
|
||||||
|
case STATE_STEP_LEFT :
|
||||||
|
case STATE_LEFT_JUMP :
|
||||||
|
angleExt -= PI * 0.5f;
|
||||||
|
break;
|
||||||
|
case STATE_STEP_RIGHT :
|
||||||
|
case STATE_RIGHT_JUMP :
|
||||||
|
angleExt += PI * 0.5f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void updateVelocity() {
|
||||||
|
// calculate moving speed
|
||||||
|
float dt = Core::deltaTime * 30.0f;
|
||||||
|
|
||||||
|
if (stand == STAND_AIR) {
|
||||||
|
velocity.y += GRAVITY * dt;
|
||||||
|
} else if (stand == STAND_ONWATER) {
|
||||||
|
|
||||||
|
} else if (stand == STAND_UNDERWATER) {
|
||||||
|
|
||||||
|
if (state == STATE_SWIM)
|
||||||
|
velocity = vec3(angle.x, angle.y) * 35.0f;
|
||||||
|
else
|
||||||
|
velocity = velocity - velocity * min(1.0f, Core::deltaTime * 2.0f);
|
||||||
|
|
||||||
|
// TODO: apply flow velocity
|
||||||
|
} else if (stand == STAND_GROUND) {
|
||||||
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
|
||||||
|
float speed = anim->speed + anim->accel * (animTime * 30.0f);
|
||||||
|
|
||||||
|
velocity.x = sinf(angleExt) * speed;
|
||||||
|
velocity.z = cosf(angleExt) * speed;
|
||||||
|
velocity.y += GRAVITY * dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void move() {
|
||||||
|
vec3 offset = velocity * Core::deltaTime * 30.0f;
|
||||||
|
|
||||||
|
vec3 p = pos;
|
||||||
|
pos = pos + offset;
|
||||||
|
|
||||||
|
int delta;
|
||||||
|
int d = getOverlap((int)p.x, (int)p.y, (int)p.z, (int)pos.x, (int)pos.z, delta);
|
||||||
|
|
||||||
|
int state = level->anims[animIndex].state;
|
||||||
|
bool stop = false;
|
||||||
|
|
||||||
|
if ((d == NO_OVERLAP) ||
|
||||||
|
((state == STATE_WALK || state == STATE_BACK || state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT) && delta > 256) /*||
|
||||||
|
(delta < -256) */) {
|
||||||
|
|
||||||
|
pos = p;
|
||||||
|
|
||||||
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
|
||||||
|
// smashes
|
||||||
|
if (stand == STAND_GROUND) { // onGround
|
||||||
|
if (d >= 256 * 4 && anim->state == STATE_RUN)
|
||||||
|
setAnimation(ANIM_SMASH_RUN_LEFT); // TODO: RIGHT
|
||||||
|
else
|
||||||
|
setAnimation(ANIM_STAND);
|
||||||
|
|
||||||
|
velocity.x = velocity.z = 0.0f;
|
||||||
|
} else if (stand == STAND_UNDERWATER) { // in water
|
||||||
|
// do nothing
|
||||||
|
//velocity.x = velocity.z = 0.0f;
|
||||||
|
} else { // in the air
|
||||||
|
setAnimation(ANIM_SMASH_JUMP);
|
||||||
|
|
||||||
|
velocity.x = -velocity.x * 0.5f;
|
||||||
|
velocity.z = -velocity.z * 0.5f;
|
||||||
|
velocity.y = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
TR::Entity &entity = getEntity();
|
||||||
|
entity.x = (int)pos.x;
|
||||||
|
entity.y = (int)pos.y;
|
||||||
|
entity.z = (int)pos.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
99
src/level.h
99
src/level.h
@@ -4,10 +4,10 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "controller.h"
|
#include "lara.h"
|
||||||
|
#include "enemy.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -30,31 +30,68 @@ struct Level {
|
|||||||
float time;
|
float time;
|
||||||
|
|
||||||
Level(Stream &stream) : level{stream}, time(0.0f) {
|
Level(Stream &stream) : level{stream}, time(0.0f) {
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Debug::init();
|
||||||
|
#endif
|
||||||
mesh = new MeshBuilder(level);
|
mesh = new MeshBuilder(level);
|
||||||
|
|
||||||
initAtlas();
|
initAtlas();
|
||||||
initShaders();
|
initShaders();
|
||||||
initOverrides();
|
initOverrides();
|
||||||
|
|
||||||
int entity = 0;
|
for (int i = 0; i < level.entitiesCount; i++) {
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
TR::Entity &entity = level.entities[i];
|
||||||
if (level.entities[i].id == ENTITY_LARA) {
|
switch (entity.id) {
|
||||||
entity = i;
|
case ENTITY_LARA :
|
||||||
|
entity.controller = (lara = new Lara(&level, i));
|
||||||
|
break;
|
||||||
|
case ENTITY_ENEMY_WOLF :
|
||||||
|
entity.controller = new Wolf(&level, i);
|
||||||
|
break;
|
||||||
|
case ENTITY_ENEMY_BEAR :
|
||||||
|
entity.controller = new Bear(&level, i);
|
||||||
|
break;
|
||||||
|
case ENTITY_ENEMY_BAT :
|
||||||
|
entity.controller = new Bat(&level, i);
|
||||||
|
break;
|
||||||
|
case ENTITY_ENEMY_TWIN :
|
||||||
|
case ENTITY_ENEMY_CROCODILE_LAND :
|
||||||
|
case ENTITY_ENEMY_CROCODILE_WATER :
|
||||||
|
case ENTITY_ENEMY_LION_MALE :
|
||||||
|
case ENTITY_ENEMY_LION_FEMALE :
|
||||||
|
case ENTITY_ENEMY_PUMA :
|
||||||
|
case ENTITY_ENEMY_GORILLA :
|
||||||
|
case ENTITY_ENEMY_RAT_LAND :
|
||||||
|
case ENTITY_ENEMY_RAT_WATER :
|
||||||
|
case ENTITY_ENEMY_REX :
|
||||||
|
case ENTITY_ENEMY_RAPTOR :
|
||||||
|
case ENTITY_ENEMY_MUTANT :
|
||||||
|
case ENTITY_ENEMY_CENTAUR :
|
||||||
|
case ENTITY_ENEMY_MUMMY :
|
||||||
|
case ENTITY_ENEMY_LARSON :
|
||||||
|
entity.controller = new Enemy(&level, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lara = new Lara(&level, entity);
|
ASSERT(lara != NULL);
|
||||||
camera = new Camera(&level, lara);
|
camera = new Camera(&level, lara);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Level() {
|
~Level() {
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Debug::free();
|
||||||
|
#endif
|
||||||
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
|
delete (Controller*)level.entities[i].controller;
|
||||||
|
|
||||||
for (int i = 0; i < shMAX; i++)
|
for (int i = 0; i < shMAX; i++)
|
||||||
delete shaders[i];
|
delete shaders[i];
|
||||||
|
|
||||||
delete atlas;
|
delete atlas;
|
||||||
delete mesh;
|
delete mesh;
|
||||||
|
|
||||||
delete camera;
|
delete camera;
|
||||||
delete lara;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAtlas() {
|
void initAtlas() {
|
||||||
@@ -236,11 +273,6 @@ struct Level {
|
|||||||
renderRoom(p.roomIndex, roomIndex);
|
renderRoom(p.roomIndex, roomIndex);
|
||||||
}
|
}
|
||||||
camera->frustum = camFrustum; // pop camera frustum
|
camera->frustum = camFrustum; // pop camera frustum
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
glColor3f(0, 0.05, 0);
|
|
||||||
camera->frustum->debug();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshBuilder::MeshInfo* getMeshInfoByOffset(uint32 meshOffset) {
|
MeshBuilder::MeshInfo* getMeshInfoByOffset(uint32 meshOffset) {
|
||||||
@@ -250,16 +282,15 @@ struct Level {
|
|||||||
for (int i = 0; i < mesh->mCount; i++)
|
for (int i = 0; i < mesh->mCount; i++)
|
||||||
if (mesh->meshInfo[i].offset == level.meshOffsets[meshOffset])
|
if (mesh->meshInfo[i].offset == level.meshOffsets[meshOffset])
|
||||||
return &mesh->meshInfo[i];
|
return &mesh->meshInfo[i];
|
||||||
|
ASSERT(false);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderMesh(uint32 meshOffset) {
|
void renderMesh(uint32 meshOffset) {
|
||||||
MeshBuilder::MeshInfo *m = getMeshInfoByOffset(meshOffset);
|
MeshBuilder::MeshInfo *m = getMeshInfoByOffset(meshOffset);
|
||||||
ASSERT(m != NULL);
|
if (!m) return; // invisible mesh (level.meshOffsets[meshOffset] == 0) camera target entity etc.
|
||||||
if (!m) return;
|
|
||||||
|
|
||||||
if ((m->radius & 0xFFFF) == 0 || camera->frustum->isVisible(Core::mModel * m->center, (m->radius & 0x3FF)) * 2) {
|
if (!m->collider.radius || camera->frustum->isVisible(Core::mModel * m->center, m->collider.radius * 2)) {
|
||||||
Core::active.shader->setParam(uModel, Core::mModel);
|
Core::active.shader->setParam(uModel, Core::mModel);
|
||||||
mesh->renderMesh(m);
|
mesh->renderMesh(m);
|
||||||
}
|
}
|
||||||
@@ -295,14 +326,21 @@ struct Level {
|
|||||||
return ma.getRot().slerp(mb.getRot(), t).normal();
|
return ma.getRot().slerp(mb.getRot(), t).normal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderModel(const TR::Model &model, vec3 angle) {
|
void renderModel(const TR::Model &model, const TR::Entity &entity) {
|
||||||
TR::Animation *anim = &level.anims[model.animation];
|
TR::Animation *anim;
|
||||||
|
float fTime;
|
||||||
|
vec3 angle;
|
||||||
|
|
||||||
float fTime = time;
|
Controller *controller = (Controller*)entity.controller;
|
||||||
|
|
||||||
if (model.id == ENTITY_LARA) {
|
if (controller) {
|
||||||
fTime = lara->fTime;
|
angle = controller->angle;
|
||||||
angle = lara->angle;
|
fTime = controller->animTime;
|
||||||
|
anim = &level.anims[controller->animIndex];
|
||||||
|
} else {
|
||||||
|
anim = &level.anims[model.animation];
|
||||||
|
angle = vec3(0.0f, entity.rotation / 16384.0f * PI * 0.5f, 0.0f);
|
||||||
|
fTime = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (angle.y != 0.0f) Core::mModel.rotateY(angle.y);
|
if (angle.y != 0.0f) Core::mModel.rotateY(angle.y);
|
||||||
@@ -405,9 +443,6 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderEntity(const TR::Entity &entity) {
|
void renderEntity(const TR::Entity &entity) {
|
||||||
// if (!(entity.flags & ENTITY_FLAG_VISIBLE))
|
|
||||||
// return;
|
|
||||||
|
|
||||||
TR::Room &room = level.rooms[entity.room];
|
TR::Room &room = level.rooms[entity.room];
|
||||||
if (!(room.flags & TR::ROOM_FLAG_VISIBLE)) // check for room visibility
|
if (!(room.flags & TR::ROOM_FLAG_VISIBLE)) // check for room visibility
|
||||||
return;
|
return;
|
||||||
@@ -431,7 +466,7 @@ struct Level {
|
|||||||
for (int i = 0; i < level.modelsCount; i++)
|
for (int i = 0; i < level.modelsCount; i++)
|
||||||
if (entity.id == level.models[i].id) {
|
if (entity.id == level.models[i].id) {
|
||||||
isModel = true;
|
isModel = true;
|
||||||
renderModel(level.models[i], vec3(0, entity.rotation / 16384.0f * PI * 0.5f, 0));
|
renderModel(level.models[i], entity);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +490,13 @@ struct Level {
|
|||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
time += Core::deltaTime;
|
time += Core::deltaTime;
|
||||||
lara->update();
|
|
||||||
|
for (int i = 0; i < level.entitiesCount; i++) {
|
||||||
|
Controller *controller = (Controller*)level.entities[i].controller;
|
||||||
|
if (controller)
|
||||||
|
controller->update();
|
||||||
|
}
|
||||||
|
|
||||||
camera->update();
|
camera->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,7 +552,7 @@ struct Level {
|
|||||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||||
// Debug::Level::lights(level);
|
// Debug::Level::lights(level);
|
||||||
// Debug::Level::portals(level);
|
// Debug::Level::portals(level);
|
||||||
Debug::Level::meshes(level);
|
// Debug::Level::meshes(level);
|
||||||
Debug::end();
|
Debug::end();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
30
src/mesh.h
30
src/mesh.h
@@ -69,7 +69,7 @@ struct MeshBuilder {
|
|||||||
struct MeshInfo : MeshRange {
|
struct MeshInfo : MeshRange {
|
||||||
int offset;
|
int offset;
|
||||||
TR::Vertex center;
|
TR::Vertex center;
|
||||||
int32 radius;
|
TR::Collider collider;
|
||||||
} *meshInfo;
|
} *meshInfo;
|
||||||
int mCount;
|
int mCount;
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ struct MeshBuilder {
|
|||||||
|
|
||||||
mCount = 0;
|
mCount = 0;
|
||||||
TR::Mesh *ptr = (TR::Mesh*)level.meshData;
|
TR::Mesh *ptr = (TR::Mesh*)level.meshData;
|
||||||
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * 2 ) {
|
while ( ((intptr_t)ptr - (intptr_t)level.meshData) < level.meshDataSize * 2 ) {
|
||||||
mCount++;
|
mCount++;
|
||||||
|
|
||||||
OFFSET(ptr->vCount * sizeof(TR::Vertex));
|
OFFSET(ptr->vCount * sizeof(TR::Vertex));
|
||||||
@@ -155,7 +155,7 @@ struct MeshBuilder {
|
|||||||
iCount += ptr->ctCount * 3;
|
iCount += ptr->ctCount * 3;
|
||||||
vCount += ptr->ctCount * 3;
|
vCount += ptr->ctCount * 3;
|
||||||
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
||||||
ptr = (TR::Mesh*)(((int)ptr + 3) & -4);
|
ptr = (TR::Mesh*)(((intptr_t)ptr + 3) & -4);
|
||||||
}
|
}
|
||||||
meshInfo = new MeshInfo[mCount];
|
meshInfo = new MeshInfo[mCount];
|
||||||
|
|
||||||
@@ -229,15 +229,14 @@ struct MeshBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// build objects geometry
|
// build objects geometry
|
||||||
mCount = 0;
|
|
||||||
ptr = (TR::Mesh*)level.meshData;
|
ptr = (TR::Mesh*)level.meshData;
|
||||||
while ( ((int)ptr - (int)level.meshData) < level.meshDataSize * sizeof(uint16) ) {
|
for (int i = 0; i < mCount; i++) {
|
||||||
MeshInfo &info = meshInfo[mCount++];
|
MeshInfo &info = meshInfo[i];
|
||||||
info.offset = (int)ptr - (int)level.meshData;
|
info.offset = (intptr_t)ptr - (intptr_t)level.meshData;
|
||||||
info.vStart = vCount;
|
info.vStart = vCount;
|
||||||
info.iStart = iCount;
|
info.iStart = iCount;
|
||||||
info.center = ptr->center;
|
info.center = ptr->center;
|
||||||
info.radius = ptr->radius;
|
info.collider = ptr->collider;
|
||||||
|
|
||||||
TR::Vertex *mVertices = (TR::Vertex*)&ptr->vertices;
|
TR::Vertex *mVertices = (TR::Vertex*)&ptr->vertices;
|
||||||
|
|
||||||
@@ -326,7 +325,7 @@ struct MeshBuilder {
|
|||||||
} else {
|
} else {
|
||||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
|
vertices[vCount].color = { a, a, a, 255 };
|
||||||
}
|
}
|
||||||
vCount++;
|
vCount++;
|
||||||
}
|
}
|
||||||
@@ -352,16 +351,15 @@ struct MeshBuilder {
|
|||||||
} else {
|
} else {
|
||||||
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
uint8 a = 255 - (lights[f.vertices[k]] >> 5);
|
||||||
vertices[vCount].normal = { 0, 0, 0, 1 };
|
vertices[vCount].normal = { 0, 0, 0, 1 };
|
||||||
vertices[vCount].color = { a, a, a, 255 }; // TODO: apply color
|
vertices[vCount].color = { a, a, a, 255 };
|
||||||
}
|
}
|
||||||
vCount++;
|
vCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
|
||||||
|
|
||||||
ptr = (TR::Mesh*)(((int)ptr + 3) & -4);
|
|
||||||
|
|
||||||
info.iCount = iCount - info.iStart;
|
info.iCount = iCount - info.iStart;
|
||||||
|
|
||||||
|
OFFSET(ptr->ctCount * sizeof(TR::Triangle) + sizeof(TR::Mesh));
|
||||||
|
ptr = (TR::Mesh*)(((intptr_t)ptr + 3) & -4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// build sprite sequences
|
// build sprite sequences
|
||||||
@@ -388,8 +386,8 @@ struct MeshBuilder {
|
|||||||
int tile = tex.tile.index;
|
int tile = tex.tile.index;
|
||||||
int tx = (tile % 4) * 256;
|
int tx = (tile % 4) * 256;
|
||||||
int ty = (tile / 4) * 256;
|
int ty = (tile / 4) * 256;
|
||||||
return vec2( ((tx + tex.vertices[0].Xpixel) << 5) + 16,
|
return vec2( (float)(((tx + tex.vertices[0].Xpixel) << 5) + 16),
|
||||||
((ty + tex.vertices[0].Ypixel) << 5) + 16 );
|
(float)(((ty + tex.vertices[0].Ypixel) << 5) + 16) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAnimTextures(TR::Level &level) {
|
void initAnimTextures(TR::Level &level) {
|
||||||
|
@@ -100,8 +100,10 @@
|
|||||||
<ClInclude Include="..\controller.h" />
|
<ClInclude Include="..\controller.h" />
|
||||||
<ClInclude Include="..\core.h" />
|
<ClInclude Include="..\core.h" />
|
||||||
<ClInclude Include="..\debug.h" />
|
<ClInclude Include="..\debug.h" />
|
||||||
|
<ClInclude Include="..\enemy.h" />
|
||||||
<ClInclude Include="..\game.h" />
|
<ClInclude Include="..\game.h" />
|
||||||
<ClInclude Include="..\input.h" />
|
<ClInclude Include="..\input.h" />
|
||||||
|
<ClInclude Include="..\lara.h" />
|
||||||
<ClInclude Include="..\level.h" />
|
<ClInclude Include="..\level.h" />
|
||||||
<ClInclude Include="..\mesh.h" />
|
<ClInclude Include="..\mesh.h" />
|
||||||
<ClInclude Include="..\shader.h" />
|
<ClInclude Include="..\shader.h" />
|
||||||
|
@@ -174,6 +174,8 @@ void freeGL(HGLRC hRC) {
|
|||||||
wglDeleteContext(hRC);
|
wglDeleteContext(hRC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HDC hDC;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
_CrtMemState _ms;
|
_CrtMemState _ms;
|
||||||
@@ -188,7 +190,7 @@ int main() {
|
|||||||
|
|
||||||
joyInit();
|
joyInit();
|
||||||
|
|
||||||
HDC hDC = GetDC(hWnd);
|
hDC = GetDC(hWnd);
|
||||||
HGLRC hRC = initGL(hDC);
|
HGLRC hRC = initGL(hDC);
|
||||||
Game::init();
|
Game::init();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user