mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-09 14:47:02 +02:00
#8 trace obstacles for camera, #13 "look-at" triggers, #13 dart mesh, smoke & sparks sprite sequences, #15 split long time steps to 1/30 steps
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
85
src/camera.h
85
src/camera.h
@@ -153,18 +153,17 @@ struct Frustum {
|
|||||||
|
|
||||||
|
|
||||||
struct Camera : Controller {
|
struct Camera : Controller {
|
||||||
Controller *owner;
|
Lara *owner;
|
||||||
Frustum *frustum;
|
Frustum *frustum;
|
||||||
|
|
||||||
float fov, znear, zfar;
|
float fov, znear, zfar;
|
||||||
vec3 target, destPos, lastDest, angleAdv;
|
vec3 target, destPos, lastDest, angleAdv;
|
||||||
|
|
||||||
int room;
|
int room;
|
||||||
|
|
||||||
Camera(TR::Level *level, Controller *owner) : Controller(level, owner->entity), owner(owner), frustum(new Frustum()) {
|
Camera(TR::Level *level, Lara *owner) : Controller(level, owner->entity), owner(owner), frustum(new Frustum()) {
|
||||||
fov = 75.0f;
|
fov = 75.0f;
|
||||||
znear = 0.1f * 2048.0f;
|
znear = 128;
|
||||||
zfar = 1000.0f * 2048.0f;
|
zfar = 100.0f * 1024.0f;
|
||||||
angleAdv = vec3(0.0f);
|
angleAdv = vec3(0.0f);
|
||||||
|
|
||||||
room = owner->getEntity().room;
|
room = owner->getEntity().room;
|
||||||
@@ -215,15 +214,25 @@ struct Camera : Controller {
|
|||||||
|
|
||||||
target = vec3(owner->pos.x, owner->pos.y - height, owner->pos.z);
|
target = vec3(owner->pos.x, owner->pos.y - height, owner->pos.z);
|
||||||
|
|
||||||
vec3 dir = getDir();
|
vec3 dir;
|
||||||
|
float lerpFactor = 2.0f;
|
||||||
|
if (owner->targetEntity > -1) {
|
||||||
|
TR::Entity &e = level->entities[owner->targetEntity];
|
||||||
|
dir = (vec3(e.x, e.y, e.z) - target).normal();
|
||||||
|
lerpFactor = 10.0f;
|
||||||
|
} else
|
||||||
|
dir = getDir();
|
||||||
|
|
||||||
if (owner->state != Lara::STATE_BACK_JUMP) {
|
if (owner->state != Lara::STATE_BACK_JUMP) {
|
||||||
destPos = target - dir * 1024.0f;
|
vec3 eye = target - dir * 1024.0f;
|
||||||
|
destPos = trace(owner->getRoomIndex(), target, eye);
|
||||||
lastDest = destPos;
|
lastDest = destPos;
|
||||||
} else
|
} else {
|
||||||
destPos = lastDest + dir.cross(vec3(0, 1, 0)).normal() * 2048.0f - vec3(0.0f, 512.0f, 0.0f);
|
vec3 eye = lastDest + dir.cross(vec3(0, 1, 0)).normal() * 2048.0f - vec3(0.0f, 512.0f, 0.0f);
|
||||||
|
destPos = trace(owner->getRoomIndex(), target, eye);
|
||||||
|
}
|
||||||
|
|
||||||
pos = pos.lerp(destPos, min(1.0f, Core::deltaTime * 2.0f));
|
pos = pos.lerp(destPos, min(1.0f, Core::deltaTime * lerpFactor));
|
||||||
|
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
level->getFloorInfo(room, (int)pos.x, (int)pos.z, info);
|
level->getFloorInfo(room, (int)pos.x, (int)pos.z, info);
|
||||||
@@ -248,6 +257,62 @@ struct Camera : Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 trace(int fromRoom, const vec3 &from, const vec3 &to) { // TODO: use Bresenham
|
||||||
|
int room = fromRoom;
|
||||||
|
|
||||||
|
vec3 pos = from, dir = to - from;
|
||||||
|
int px = (int)pos.x, py = (int)pos.y, pz = (int)pos.z;
|
||||||
|
|
||||||
|
float dist = dir.length();
|
||||||
|
dir = dir * (1.0f / dist);
|
||||||
|
|
||||||
|
int lx = -1, lz = -1;
|
||||||
|
TR::Level::FloorInfo info;
|
||||||
|
while (dist > 1.0f) {
|
||||||
|
int sx = px / 1024 * 1024 + 512,
|
||||||
|
sz = pz / 1024 * 1024 + 512;
|
||||||
|
|
||||||
|
if (lx != sx || lz != sz) {
|
||||||
|
level->getFloorInfo(room, sx, sz, info);
|
||||||
|
lx = sx;
|
||||||
|
lz = sz;
|
||||||
|
if (info.roomNext != 0xFF) room = info.roomNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (py > info.floor && info.roomBelow != 0xFF)
|
||||||
|
room = info.roomBelow;
|
||||||
|
else if (py < info.ceiling && info.roomAbove != 0xFF)
|
||||||
|
room = info.roomAbove;
|
||||||
|
else if (py > info.floor || py < info.ceiling) {
|
||||||
|
int minX = px / 1024 * 1024;
|
||||||
|
int minZ = pz / 1024 * 1024;
|
||||||
|
int maxX = minX + 1024;
|
||||||
|
int maxZ = minZ + 1024;
|
||||||
|
|
||||||
|
pos = vec3(clamp(px, minX, maxX), pos.y, clamp(pz, minZ, maxZ)) + boxNormal(px, pz) * 256.0f;
|
||||||
|
dir = (pos - from).normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
float d = min(dist, 128.0f); // STEP = 128
|
||||||
|
dist -= d;
|
||||||
|
pos = pos + dir * d;
|
||||||
|
|
||||||
|
px = (int)pos.x, py = (int)pos.y, pz = (int)pos.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 boxNormal(int x, int z) {
|
||||||
|
x %= 1024;
|
||||||
|
z %= 1024;
|
||||||
|
|
||||||
|
if (x > 1024 - z)
|
||||||
|
return x < z ? vec3(0, 0, 1) : vec3(1, 0, 0);
|
||||||
|
else
|
||||||
|
return x < z ? vec3(-1, 0, 0) : vec3(0, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Core::mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
Core::mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
||||||
Core::mView = Core::mViewInv.inverse();
|
Core::mView = Core::mViewInv.inverse();
|
||||||
|
@@ -52,9 +52,9 @@ struct Controller {
|
|||||||
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), animTime(0.0f), animPrevFrame(0), health(100), turnTime(0.0f), nextAction(TR::Action::NONE, 0, 0.0f) {
|
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), animTime(0.0f), animPrevFrame(0), health(100), turnTime(0.0f), nextAction(TR::Action::NONE, 0, 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, 0.0f);
|
||||||
stand = STAND_GROUND;
|
stand = STAND_GROUND;
|
||||||
animIndex = getModel().animation;
|
animIndex = e.modelIndex > 0 ? level->models[e.modelIndex - 1].animation : 0;
|
||||||
state = level->anims[animIndex].state;
|
state = level->anims[animIndex].state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ struct Controller {
|
|||||||
e.x = int(pos.x);
|
e.x = int(pos.x);
|
||||||
e.y = int(pos.y);
|
e.y = int(pos.y);
|
||||||
e.z = int(pos.z);
|
e.z = int(pos.z);
|
||||||
e.rotation = int(angle.y / (PI * 0.5f) * 16384.0f);
|
e.rotation = angle.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool insideRoom(const vec3 &pos, int room) const {
|
bool insideRoom(const vec3 &pos, int room) const {
|
||||||
@@ -80,15 +80,6 @@ struct Controller {
|
|||||||
return level->entities[entity];
|
return level->entities[entity];
|
||||||
}
|
}
|
||||||
|
|
||||||
TR::Model& getModel() const {
|
|
||||||
TR::Entity &entity = getEntity();
|
|
||||||
for (int i = 0; i < level->modelsCount; i++)
|
|
||||||
if (entity.id == level->models[i].id)
|
|
||||||
return level->models[i];
|
|
||||||
ASSERT(false);
|
|
||||||
return level->models[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
TR::Room& getRoom() const {
|
TR::Room& getRoom() const {
|
||||||
int index = getRoomIndex();
|
int index = getRoomIndex();
|
||||||
ASSERT(index >= 0 && index < level->roomsCount);
|
ASSERT(index >= 0 && index < level->roomsCount);
|
||||||
@@ -337,7 +328,7 @@ struct Controller {
|
|||||||
int idx = frame - anim->frameStart;
|
int idx = frame - anim->frameStart;
|
||||||
|
|
||||||
if (idx > animPrevFrame && idx <= frameIndex) {
|
if (idx > animPrevFrame && idx <= frameIndex) {
|
||||||
if (getEntity().id != ENTITY_ENEMY_BAT) // temporary mute the bat
|
if (getEntity().id != TR::Entity::ENEMY_BAT) // temporary mute the bat
|
||||||
playSound(id);
|
playSound(id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -375,4 +366,51 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct SpriteController : Controller {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FRAME_ANIMATED = -1,
|
||||||
|
FRAME_RANDOM = -2,
|
||||||
|
};
|
||||||
|
|
||||||
|
int frame;
|
||||||
|
bool instant, animated;
|
||||||
|
|
||||||
|
SpriteController(TR::Level *level, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(level, entity), instant(instant), animated(frame == FRAME_ANIMATED) {
|
||||||
|
if (frame >= 0) { // specific frame
|
||||||
|
this->frame = frame;
|
||||||
|
} else if (frame == FRAME_RANDOM) { // random frame
|
||||||
|
this->frame = rand() % getSequence().sCount;
|
||||||
|
} else if (frame == FRAME_ANIMATED) { // animated
|
||||||
|
this->frame = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TR::SpriteSequence& getSequence() {
|
||||||
|
return level->spriteSequences[-(getEntity().modelIndex + 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
bool remove = false;
|
||||||
|
animTime += Core::deltaTime;
|
||||||
|
|
||||||
|
if (animated) {
|
||||||
|
frame = int(animTime * 10.0f);
|
||||||
|
TR::SpriteSequence &seq = getSequence();
|
||||||
|
if (instant && frame >= seq.sCount)
|
||||||
|
remove = true;
|
||||||
|
else
|
||||||
|
frame %= seq.sCount;
|
||||||
|
} else
|
||||||
|
if (instant && animTime >= 0.1f)
|
||||||
|
remove = true;
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
level->entityRemove(entity);
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
28
src/debug.h
28
src/debug.h
@@ -195,19 +195,19 @@ namespace Debug {
|
|||||||
cmd = (*fd++).cmd;
|
cmd = (*fd++).cmd;
|
||||||
|
|
||||||
switch (cmd.func) {
|
switch (cmd.func) {
|
||||||
case TR::FD_PORTAL :
|
case TR::FloorData::PORTAL :
|
||||||
isPortal = true;
|
isPortal = true;
|
||||||
fd++;
|
fd++;
|
||||||
break; // portal
|
break; // portal
|
||||||
case TR::FD_FLOOR : // floor & ceiling
|
case TR::FloorData::FLOOR : // floor & ceiling
|
||||||
case TR::FD_CEILING : {
|
case TR::FloorData::CEILING : {
|
||||||
TR::FloorData::Slant slant = (*fd++).slant;
|
TR::FloorData::Slant slant = (*fd++).slant;
|
||||||
int sx = 256 * (int)slant.x;
|
int sx = 256 * (int)slant.x;
|
||||||
int sz = 256 * (int)slant.z;
|
int sz = 256 * (int)slant.z;
|
||||||
|
|
||||||
auto &p = cmd.func == 0x02 ? vf : vc;
|
auto &p = cmd.func == 0x02 ? vf : vc;
|
||||||
|
|
||||||
if (cmd.func == 0x02) { // floor
|
if (cmd.func == TR::FloorData::FLOOR) { // floor
|
||||||
if (sx > 0) {
|
if (sx > 0) {
|
||||||
p[0].y += sx;
|
p[0].y += sx;
|
||||||
p[3].y += sx;
|
p[3].y += sx;
|
||||||
@@ -242,28 +242,12 @@ namespace Debug {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TR::FD_TRIGGER : {
|
case TR::FloorData::TRIGGER : {
|
||||||
TR::FloorData::TriggerInfo info = (*fd++).triggerInfo;
|
TR::FloorData::TriggerInfo info = (*fd++).triggerInfo;
|
||||||
TR::FloorData::TriggerCommand trigCmd;
|
TR::FloorData::TriggerCommand trigCmd;
|
||||||
glColor3f(1, 0, 1);
|
glColor3f(1, 0, 1);
|
||||||
do {
|
do {
|
||||||
trigCmd = (*fd++).triggerCmd; // trigger action
|
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||||
switch (trigCmd.func) {
|
|
||||||
case 0 : break; // activate item
|
|
||||||
case 1 : break; // switch to camera
|
|
||||||
case 2 : break; // camera delay
|
|
||||||
case 3 : break; // flip map
|
|
||||||
case 4 : break; // flip on
|
|
||||||
case 5 : break; // flip off
|
|
||||||
case 6 : break; // look at item
|
|
||||||
case 7 : break; // end level
|
|
||||||
case 8 : break; // play soundtrack
|
|
||||||
case 9 : break; // special hadrdcode trigger
|
|
||||||
case 10 : break; // secret found
|
|
||||||
case 11 : break; // clear bodies
|
|
||||||
case 12 : break; // flyby camera sequence
|
|
||||||
case 13 : break; // play cutscene
|
|
||||||
}
|
|
||||||
} while (!trigCmd.end);
|
} while (!trigCmd.end);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -468,7 +452,7 @@ namespace Debug {
|
|||||||
matrix.rotateX(controller->angle.x);
|
matrix.rotateX(controller->angle.x);
|
||||||
matrix.rotateZ(controller->angle.z);
|
matrix.rotateZ(controller->angle.z);
|
||||||
} else
|
} else
|
||||||
matrix.rotateY(e.rotation / 16384.0f * PI * 0.5f);
|
matrix.rotateY(e.rotation);
|
||||||
|
|
||||||
for (int j = 0; j < level.modelsCount; j++) {
|
for (int j = 0; j < level.modelsCount; j++) {
|
||||||
TR::Model &m = level.models[j];
|
TR::Model &m = level.models[j];
|
||||||
|
263
src/format.h
263
src/format.h
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#define TR1_DEMO
|
#define TR1_DEMO
|
||||||
|
|
||||||
|
#define MAX_RESERVED_ENTITIES 64
|
||||||
|
|
||||||
namespace TR {
|
namespace TR {
|
||||||
|
|
||||||
enum : int32 {
|
enum : int32 {
|
||||||
@@ -12,14 +14,6 @@ namespace TR {
|
|||||||
ROOM_FLAG_VISIBLE = 0x8000
|
ROOM_FLAG_VISIBLE = 0x8000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
|
||||||
FD_PORTAL = 1,
|
|
||||||
FD_FLOOR = 2,
|
|
||||||
FD_CEILING = 3,
|
|
||||||
FD_TRIGGER = 4,
|
|
||||||
FD_KILL = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ANIM_CMD_MOVE = 1,
|
ANIM_CMD_MOVE = 1,
|
||||||
ANIM_CMD_SPEED = 2,
|
ANIM_CMD_SPEED = 2,
|
||||||
@@ -56,7 +50,7 @@ namespace TR {
|
|||||||
NONE = -1, // no action
|
NONE = -1, // no action
|
||||||
ACTIVATE = 0, // activate item
|
ACTIVATE = 0, // activate item
|
||||||
CAMERA_SWITCH = 1, // switch to camera
|
CAMERA_SWITCH = 1, // switch to camera
|
||||||
CAMERA_DELAY = 2, // camera delay
|
UNDERWATER = 2, // underwater flow
|
||||||
FLIP_MAP = 3, // flip map
|
FLIP_MAP = 3, // flip map
|
||||||
FLIP_ON = 4, // flip on
|
FLIP_ON = 4, // flip on
|
||||||
FLIP_OFF = 5, // flip off
|
FLIP_OFF = 5, // flip off
|
||||||
@@ -70,7 +64,6 @@ namespace TR {
|
|||||||
CUTSCENE = 13, // play cutscene
|
CUTSCENE = 13, // play cutscene
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define DATA_PORTAL 0x01
|
#define DATA_PORTAL 0x01
|
||||||
#define DATA_FLOOR 0x02
|
#define DATA_FLOOR 0x02
|
||||||
#define DATA_CEILING 0x03
|
#define DATA_CEILING 0x03
|
||||||
@@ -79,67 +72,6 @@ namespace TR {
|
|||||||
#define ENTITY_FLAG_VISIBLE 0x0100
|
#define ENTITY_FLAG_VISIBLE 0x0100
|
||||||
#define ENTITY_FLAG_ACTIVE 0x3E00
|
#define ENTITY_FLAG_ACTIVE 0x3E00
|
||||||
|
|
||||||
|
|
||||||
#define ENTITY_LARA 0
|
|
||||||
#define ENTITY_LARA_CUT 77
|
|
||||||
|
|
||||||
#define ENTITY_ENEMY_TWIN 6
|
|
||||||
#define ENTITY_ENEMY_WOLF 7
|
|
||||||
#define ENTITY_ENEMY_BEAR 8
|
|
||||||
#define ENTITY_ENEMY_BAT 9
|
|
||||||
#define ENTITY_ENEMY_CROCODILE_LAND 10
|
|
||||||
#define ENTITY_ENEMY_CROCODILE_WATER 11
|
|
||||||
#define ENTITY_ENEMY_LION_MALE 12
|
|
||||||
#define ENTITY_ENEMY_LION_FEMALE 13
|
|
||||||
#define ENTITY_ENEMY_PUMA 14
|
|
||||||
#define ENTITY_ENEMY_GORILLA 15
|
|
||||||
#define ENTITY_ENEMY_RAT_LAND 16
|
|
||||||
#define ENTITY_ENEMY_RAT_WATER 17
|
|
||||||
#define ENTITY_ENEMY_REX 18
|
|
||||||
#define ENTITY_ENEMY_RAPTOR 19
|
|
||||||
#define ENTITY_ENEMY_MUTANT 20
|
|
||||||
|
|
||||||
#define ENTITY_ENEMY_CENTAUR 23
|
|
||||||
#define ENTITY_ENEMY_MUMMY 24
|
|
||||||
#define ENTITY_ENEMY_LARSON 27
|
|
||||||
|
|
||||||
#define ENTITY_TRAP_FLOOR 35
|
|
||||||
#define ENTITY_TRAP_BLADE 36
|
|
||||||
#define ENTITY_TRAP_SPIKES 37
|
|
||||||
#define ENTITY_TRAP_STONE 38
|
|
||||||
#define ENTITY_TRAP_DART 39
|
|
||||||
#define ENTITY_TRAP_DARTGUN 40
|
|
||||||
|
|
||||||
#define ENTITY_CRYSTAL 83
|
|
||||||
|
|
||||||
#define ENTITY_MEDIKIT_SMALL 93
|
|
||||||
#define ENTITY_MEDIKIT_BIG 94
|
|
||||||
|
|
||||||
|
|
||||||
#define ENTITY_SWITCH 55
|
|
||||||
#define ENTITY_SWITCH_WATER 56
|
|
||||||
|
|
||||||
#define ENTITY_DOOR_1 57
|
|
||||||
#define ENTITY_DOOR_2 58
|
|
||||||
#define ENTITY_DOOR_3 59
|
|
||||||
#define ENTITY_DOOR_4 60
|
|
||||||
#define ENTITY_DOOR_BIG_1 61
|
|
||||||
#define ENTITY_DOOR_BIG_2 62
|
|
||||||
#define ENTITY_DOOR_5 63
|
|
||||||
#define ENTITY_DOOR_6 64
|
|
||||||
#define ENTITY_DOOR_FLOOR_1 65
|
|
||||||
#define ENTITY_DOOR_FLOOR_2 66
|
|
||||||
|
|
||||||
#define ENTITY_GUN_SHOTGUN 85
|
|
||||||
|
|
||||||
#define ENTITY_AMMO_UZI 91
|
|
||||||
#define ENTITY_AMMO_SHOTGUN 89
|
|
||||||
#define ENTITY_AMMO_MAGNUM 90
|
|
||||||
|
|
||||||
#define ENTITY_HOLE_PUZZLE 118
|
|
||||||
#define ENTITY_HOLE_KEY 137
|
|
||||||
#define ENTITY_VIEW_TARGET 169
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct fixed {
|
struct fixed {
|
||||||
@@ -150,6 +82,14 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct angle {
|
||||||
|
uint16 value;
|
||||||
|
|
||||||
|
angle() {}
|
||||||
|
angle(float value) : value(uint16(value / (PI * 0.5f) * 16384.0f)) {}
|
||||||
|
operator float() const { return value / 16384.0f * PI * 0.5f; };
|
||||||
|
};
|
||||||
|
|
||||||
struct RGB {
|
struct RGB {
|
||||||
uint8 r, g, b;
|
uint8 r, g, b;
|
||||||
};
|
};
|
||||||
@@ -240,7 +180,7 @@ namespace TR {
|
|||||||
|
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
int32 x, y, z;
|
int32 x, y, z;
|
||||||
uint16 rotation;
|
angle rotation;
|
||||||
uint16 intensity;
|
uint16 intensity;
|
||||||
uint16 meshID;
|
uint16 meshID;
|
||||||
uint16 flags; // ! not exists in file !
|
uint16 flags; // ! not exists in file !
|
||||||
@@ -259,8 +199,16 @@ namespace TR {
|
|||||||
uint16 timer:8, once:1, mask:5, :2;
|
uint16 timer:8, once:1, mask:5, :2;
|
||||||
} triggerInfo;
|
} triggerInfo;
|
||||||
struct TriggerCommand {
|
struct TriggerCommand {
|
||||||
uint16 args:10, func:5, end:1;
|
uint16 args:10, action:5, end:1;
|
||||||
} triggerCmd;
|
} triggerCmd;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PORTAL = 1,
|
||||||
|
FLOOR = 2,
|
||||||
|
CEILING = 3,
|
||||||
|
TRIGGER = 4,
|
||||||
|
KILL = 5,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Overlap {
|
struct Overlap {
|
||||||
@@ -302,14 +250,92 @@ namespace TR {
|
|||||||
int16 id; // Object Identifier (matched in Models[], or SpriteSequences[], as appropriate)
|
int16 id; // Object Identifier (matched in Models[], or SpriteSequences[], as appropriate)
|
||||||
int16 room; // which room contains this item
|
int16 room; // which room contains this item
|
||||||
int32 x, y, z; // world coords
|
int32 x, y, z; // world coords
|
||||||
int16 rotation; // ((0xc000 >> 14) * 90) degrees
|
angle rotation; // ((0xc000 >> 14) * 90) degrees
|
||||||
int16 intensity; // (constant lighting; -1 means use mesh lighting)
|
int16 intensity; // (constant lighting; -1 means use mesh lighting)
|
||||||
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)
|
||||||
// not exists in file
|
// not exists in file
|
||||||
uint16 align;
|
uint16 align;
|
||||||
|
int16 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
|
||||||
void *controller; // Controller implementation or NULL
|
void *controller; // Controller implementation or NULL
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LARA = 0,
|
||||||
|
|
||||||
|
ENEMY_TWIN = 6,
|
||||||
|
ENEMY_WOLF = 7,
|
||||||
|
ENEMY_BEAR = 8,
|
||||||
|
ENEMY_BAT = 9,
|
||||||
|
ENEMY_CROCODILE_LAND = 10,
|
||||||
|
ENEMY_CROCODILE_WATER = 11,
|
||||||
|
ENEMY_LION_MALE = 12,
|
||||||
|
ENEMY_LION_FEMALE = 13,
|
||||||
|
ENEMY_PUMA = 14,
|
||||||
|
ENEMY_GORILLA = 15,
|
||||||
|
ENEMY_RAT_LAND = 16,
|
||||||
|
ENEMY_RAT_WATER = 17,
|
||||||
|
ENEMY_REX = 18,
|
||||||
|
ENEMY_RAPTOR = 19,
|
||||||
|
ENEMY_MUTANT = 20,
|
||||||
|
|
||||||
|
ENEMY_CENTAUR = 23,
|
||||||
|
ENEMY_MUMMY = 24,
|
||||||
|
ENEMY_LARSON = 27,
|
||||||
|
|
||||||
|
TRAP_FLOOR = 35,
|
||||||
|
TRAP_BLADE = 36,
|
||||||
|
TRAP_SPIKES = 37,
|
||||||
|
TRAP_STONE = 38,
|
||||||
|
TRAP_DART = 39,
|
||||||
|
TRAP_DARTGUN = 40,
|
||||||
|
|
||||||
|
SWITCH = 55,
|
||||||
|
SWITCH_WATER = 56,
|
||||||
|
DOOR_1 = 57,
|
||||||
|
DOOR_2 = 58,
|
||||||
|
DOOR_3 = 59,
|
||||||
|
DOOR_4 = 60,
|
||||||
|
DOOR_BIG_1 = 61,
|
||||||
|
DOOR_BIG_2 = 62,
|
||||||
|
DOOR_5 = 63,
|
||||||
|
DOOR_6 = 64,
|
||||||
|
DOOR_FLOOR_1 = 65,
|
||||||
|
DOOR_FLOOR_2 = 66,
|
||||||
|
|
||||||
|
LARA_CUT = 77,
|
||||||
|
|
||||||
|
CRYSTAL = 83, // sprite
|
||||||
|
WEAPON_PISTOLS = 84, // sprite
|
||||||
|
WEAPON_SHOTGUN = 85, // sprite
|
||||||
|
WEAPON_MAGNUMS = 86, // sprite
|
||||||
|
WEAPON_UZIS = 87, // sprite
|
||||||
|
AMMO_SHOTGUN = 89, // sprite
|
||||||
|
AMMO_MAGNUMS = 90, // sprite
|
||||||
|
AMMO_UZIS = 91, // sprite
|
||||||
|
MEDIKIT_SMALL = 93, // sprite
|
||||||
|
MEDIKIT_BIG = 94, // sprite
|
||||||
|
|
||||||
|
HOLE_PUZZLE = 118,
|
||||||
|
|
||||||
|
HOLE_KEY = 137,
|
||||||
|
|
||||||
|
ARTIFACT = 143, // sprite
|
||||||
|
|
||||||
|
WATER_SPLASH = 153, // sprite
|
||||||
|
|
||||||
|
BUBBLE = 155, // sprite
|
||||||
|
|
||||||
|
BLOOD = 158, // sprite
|
||||||
|
|
||||||
|
SMOKE = 160, // sprite
|
||||||
|
|
||||||
|
SPARK = 164, // sprite
|
||||||
|
|
||||||
|
VIEW_TARGET = 169,
|
||||||
|
|
||||||
|
GLYPH = 190, // sprite
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Animation {
|
struct Animation {
|
||||||
@@ -396,8 +422,8 @@ namespace TR {
|
|||||||
MinMax box[2]; // visible (minX, maxX, minY, maxY, minZ, maxZ) & collision
|
MinMax box[2]; // visible (minX, maxX, minY, maxY, minZ, maxZ) & collision
|
||||||
uint16 flags;
|
uint16 flags;
|
||||||
|
|
||||||
void getBox(bool collision, int rotation, vec3 &min, vec3 &max) {
|
void getBox(bool collision, angle rotation, vec3 &min, vec3 &max) {
|
||||||
int k = rotation / 16384;
|
int k = rotation.value / 0x4000;
|
||||||
|
|
||||||
MinMax &m = box[collision];
|
MinMax &m = box[collision];
|
||||||
|
|
||||||
@@ -574,6 +600,7 @@ namespace TR {
|
|||||||
int32 animTexturesDataSize;
|
int32 animTexturesDataSize;
|
||||||
uint16 *animTexturesData;
|
uint16 *animTexturesData;
|
||||||
|
|
||||||
|
int32 entitiesBaseCount;
|
||||||
int32 entitiesCount;
|
int32 entitiesCount;
|
||||||
Entity *entities;
|
Entity *entities;
|
||||||
|
|
||||||
@@ -666,6 +693,8 @@ namespace TR {
|
|||||||
stream.read(objectTextures, stream.read(objectTexturesCount));
|
stream.read(objectTextures, stream.read(objectTexturesCount));
|
||||||
stream.read(spriteTextures, stream.read(spriteTexturesCount));
|
stream.read(spriteTextures, stream.read(spriteTexturesCount));
|
||||||
stream.read(spriteSequences, stream.read(spriteSequencesCount));
|
stream.read(spriteSequences, stream.read(spriteSequencesCount));
|
||||||
|
for (int i = 0; i < spriteSequencesCount; i++)
|
||||||
|
spriteSequences[i].sCount = -spriteSequences[i].sCount;
|
||||||
|
|
||||||
#ifdef TR1_DEMO
|
#ifdef TR1_DEMO
|
||||||
stream.read(palette, 256);
|
stream.read(palette, 256);
|
||||||
@@ -682,12 +711,17 @@ namespace TR {
|
|||||||
// animated textures
|
// animated textures
|
||||||
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)];
|
entitiesCount = stream.read(entitiesBaseCount) + MAX_RESERVED_ENTITIES;
|
||||||
for (int i = 0; i < entitiesCount; i++) {
|
entities = new Entity[entitiesCount];
|
||||||
stream.raw(&entities[i], sizeof(entities[i]) - sizeof(entities[i].align) - sizeof(entities[i].controller));
|
for (int i = 0; i < entitiesBaseCount; i++) {
|
||||||
entities[i].align = 0;
|
Entity &e = entities[i];
|
||||||
entities[i].controller = NULL;
|
stream.raw(&e, sizeof(e) - sizeof(e.align) - sizeof(e.controller) - sizeof(e.modelIndex));
|
||||||
|
e.align = 0;
|
||||||
|
e.controller = NULL;
|
||||||
|
e.modelIndex = getModelIndex(e.id);
|
||||||
}
|
}
|
||||||
|
for (int i = entitiesBaseCount; i < entitiesCount; i++)
|
||||||
|
entities[i].id = -1;
|
||||||
// palette
|
// palette
|
||||||
stream.seek(32 * 256); // skip lightmap palette
|
stream.seek(32 * 256); // skip lightmap palette
|
||||||
|
|
||||||
@@ -769,6 +803,43 @@ namespace TR {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16 getModelIndex(int16 id) const {
|
||||||
|
for (int i = 0; i < modelsCount; i++)
|
||||||
|
if (id == models[i].id)
|
||||||
|
return i + 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < spriteSequencesCount; i++)
|
||||||
|
if (id == spriteSequences[i].id)
|
||||||
|
return -(i + 1);
|
||||||
|
|
||||||
|
ASSERT(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int entityAdd(int16 id, int16 room, int32 x, int32 y, int32 z, angle rotation, int16 intensity) {
|
||||||
|
int entityIndex = -1;
|
||||||
|
for (int i = entitiesBaseCount; i < entitiesCount; i++)
|
||||||
|
if (entities[i].id == -1) {
|
||||||
|
Entity &e = entities[i];
|
||||||
|
e.id = id;
|
||||||
|
e.room = room;
|
||||||
|
e.x = x;
|
||||||
|
e.y = y;
|
||||||
|
e.z = z;
|
||||||
|
e.rotation = rotation;
|
||||||
|
e.intensity = intensity;
|
||||||
|
e.flags = 0;
|
||||||
|
e.modelIndex = getModelIndex(e.id);
|
||||||
|
e.controller = NULL;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityRemove(int entityIndex) {
|
||||||
|
entities[entityIndex].id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
struct FloorInfo {
|
struct FloorInfo {
|
||||||
int floor, ceiling;
|
int floor, ceiling;
|
||||||
int roomNext, roomBelow, roomAbove;
|
int roomNext, roomBelow, roomAbove;
|
||||||
@@ -822,16 +893,16 @@ namespace TR {
|
|||||||
|
|
||||||
switch (cmd.func) {
|
switch (cmd.func) {
|
||||||
|
|
||||||
case FD_PORTAL :
|
case FloorData::PORTAL :
|
||||||
info.roomNext = (*fd++).data;
|
info.roomNext = (*fd++).data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FD_FLOOR : // floor & ceiling
|
case FloorData::FLOOR : // floor & ceiling
|
||||||
case FD_CEILING : {
|
case FloorData::CEILING : {
|
||||||
FloorData::Slant slant = (*fd++).slant;
|
FloorData::Slant slant = (*fd++).slant;
|
||||||
int sx = (int)slant.x;
|
int sx = (int)slant.x;
|
||||||
int sz = (int)slant.z;
|
int sz = (int)slant.z;
|
||||||
if (cmd.func == FD_FLOOR) {
|
if (cmd.func == FloorData::FLOOR) {
|
||||||
info.floor -= sx * (sx > 0 ? (dx - 1024) : dx) >> 2;
|
info.floor -= sx * (sx > 0 ? (dx - 1024) : dx) >> 2;
|
||||||
info.floor -= sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
info.floor -= sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||||
} else {
|
} else {
|
||||||
@@ -841,7 +912,7 @@ namespace TR {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FD_TRIGGER : {
|
case FloorData::TRIGGER : {
|
||||||
info.trigger = cmd.sub;
|
info.trigger = cmd.sub;
|
||||||
info.trigCmdCount = 0;
|
info.trigCmdCount = 0;
|
||||||
info.trigInfo = (*fd++).triggerInfo;
|
info.trigInfo = (*fd++).triggerInfo;
|
||||||
@@ -849,28 +920,14 @@ namespace TR {
|
|||||||
do {
|
do {
|
||||||
trigCmd = (*fd++).triggerCmd; // trigger action
|
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||||
info.trigCmd[info.trigCmdCount++] = trigCmd;
|
info.trigCmd[info.trigCmdCount++] = trigCmd;
|
||||||
switch (trigCmd.func) {
|
if (trigCmd.action == Action::CAMERA_SWITCH) {
|
||||||
case 0 : break; // activate item
|
|
||||||
case 1 : break; // switch to camera
|
|
||||||
case 2 : break; // camera delay
|
|
||||||
case 3 : break; // flip map
|
|
||||||
case 4 : break; // flip on
|
|
||||||
case 5 : break; // flip off
|
|
||||||
case 6 : break; // look at item
|
|
||||||
case 7 : break; // end level
|
|
||||||
case 8 : break; // play soundtrack
|
|
||||||
case 9 : break; // special hadrdcode trigger
|
|
||||||
case 10 : break; // secret found (playSound(175))
|
|
||||||
case 11 : break; // clear bodies
|
|
||||||
case 12 : break; // flyby camera sequence
|
|
||||||
case 13 : break; // play cutscene
|
|
||||||
}
|
}
|
||||||
// ..
|
|
||||||
} while (!trigCmd.end);
|
} while (!trigCmd.end);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FD_KILL :
|
case FloorData::KILL :
|
||||||
info.kill = true;
|
info.kill = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
36
src/lara.h
36
src/lara.h
@@ -17,7 +17,7 @@
|
|||||||
struct Lara : Controller {
|
struct Lara : Controller {
|
||||||
|
|
||||||
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
||||||
enum LaraAnim : int32 {
|
enum {
|
||||||
ANIM_STAND = 11,
|
ANIM_STAND = 11,
|
||||||
ANIM_FALL = 34,
|
ANIM_FALL = 34,
|
||||||
ANIM_SMASH_JUMP = 32,
|
ANIM_SMASH_JUMP = 32,
|
||||||
@@ -35,7 +35,7 @@ struct Lara : Controller {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// http://www.tombraiderforums.com/showthread.php?t=211681
|
// http://www.tombraiderforums.com/showthread.php?t=211681
|
||||||
enum LaraState : int32 {
|
enum {
|
||||||
STATE_WALK,
|
STATE_WALK,
|
||||||
STATE_RUN,
|
STATE_RUN,
|
||||||
STATE_STOP,
|
STATE_STOP,
|
||||||
@@ -94,7 +94,10 @@ struct Lara : Controller {
|
|||||||
STATE_WATER_OUT,
|
STATE_WATER_OUT,
|
||||||
STATE_MAX };
|
STATE_MAX };
|
||||||
|
|
||||||
Lara(TR::Level *level, int entity) : Controller(level, entity) {
|
int targetEntity;
|
||||||
|
float targetTimer;
|
||||||
|
|
||||||
|
Lara(TR::Level *level, int entity) : Controller(level, entity), targetEntity(-1), targetTimer(0.0f) {
|
||||||
/*
|
/*
|
||||||
// level 2 (pool)
|
// level 2 (pool)
|
||||||
pos = vec3(70067, -256, 29104);
|
pos = vec3(70067, -256, 29104);
|
||||||
@@ -195,6 +198,7 @@ struct Lara : Controller {
|
|||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
|
LOG("unsupported trigger type %d\n", info.trigger);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,26 +207,39 @@ struct Lara : Controller {
|
|||||||
|
|
||||||
// build trigger activation chain
|
// build trigger activation chain
|
||||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||||
if (info.trigCmd[i].func != TR::Action::ACTIVATE) continue; // TODO: other trigger types
|
TR::FloorData::TriggerCommand &cmd = info.trigCmd[i];
|
||||||
Controller *controller = (Controller*)level->entities[info.trigCmd[i].args].controller;
|
switch (cmd.action) {
|
||||||
|
case TR::Action::ACTIVATE : {
|
||||||
|
Controller *controller = (Controller*)level->entities[cmd.args].controller;
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
||||||
playSound(2);
|
playSound(2);
|
||||||
return;
|
return;
|
||||||
} else
|
} else
|
||||||
controller->nextAction = (i < info.trigCmdCount - 1) ? Action(TR::Action::ACTIVATE, info.trigCmd[i + 1].args, 0.0f) : Action(TR::Action::NONE, 0, 0.0f);
|
controller->nextAction = (i < info.trigCmdCount - 1) ? Action(TR::Action::ACTIVATE, info.trigCmd[i + 1].args, 0.0f) : Action(TR::Action::NONE, 0, 0.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TR::Action::LOOK_AT :
|
||||||
|
level->entities[cmd.args].flags |= ENTITY_FLAG_ACTIVE;
|
||||||
|
targetEntity = cmd.args;
|
||||||
|
targetTimer = info.trigInfo.timer;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
LOG("unsupported trigger action %d\n", cmd.action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.trigCmd[0].func != TR::Action::ACTIVATE) return; // see above TODO
|
|
||||||
|
|
||||||
// activate first entity in chain
|
// activate first entity in chain
|
||||||
Controller *controller = (Controller*)level->entities[info.trigCmd[0].args].controller;
|
Controller *controller = (Controller*)level->entities[info.trigCmd[0].args].controller;
|
||||||
|
if (controller) {
|
||||||
if (info.trigger == TR::TRIGGER_KEY) {
|
if (info.trigger == TR::TRIGGER_KEY) {
|
||||||
nextAction = controller->nextAction;
|
nextAction = controller->nextAction;
|
||||||
controller->nextAction.action = TR::Action::NONE;
|
controller->nextAction.action = TR::Action::NONE;
|
||||||
} else
|
} else
|
||||||
controller->activate((float)info.trigInfo.timer);
|
controller->activate((float)info.trigInfo.timer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual Stand getStand() {
|
virtual Stand getStand() {
|
||||||
if (stand == STAND_ONWATER && state != STATE_DIVE && state != STATE_STOP)
|
if (stand == STAND_ONWATER && state != STATE_DIVE && state != STATE_STOP)
|
||||||
@@ -381,6 +398,11 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateState() {
|
virtual void updateState() {
|
||||||
|
if (targetTimer > 0.0f && (targetTimer -= Core::deltaTime) <= 0.0f) {
|
||||||
|
targetEntity = -1;
|
||||||
|
targetTimer = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
performTrigger();
|
performTrigger();
|
||||||
|
|
||||||
TR::Animation *anim = &level->anims[animIndex];
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
155
src/level.h
155
src/level.h
@@ -25,7 +25,7 @@ struct Level {
|
|||||||
Texture *atlas;
|
Texture *atlas;
|
||||||
MeshBuilder *mesh;
|
MeshBuilder *mesh;
|
||||||
|
|
||||||
Controller *lara;
|
Lara *lara;
|
||||||
Camera *camera;
|
Camera *camera;
|
||||||
|
|
||||||
float time;
|
float time;
|
||||||
@@ -43,60 +43,59 @@ struct Level {
|
|||||||
for (int i = 0; i < level.entitiesCount; i++) {
|
for (int i = 0; i < level.entitiesCount; i++) {
|
||||||
TR::Entity &entity = level.entities[i];
|
TR::Entity &entity = level.entities[i];
|
||||||
switch (entity.id) {
|
switch (entity.id) {
|
||||||
case ENTITY_LARA :
|
case TR::Entity::LARA :
|
||||||
case ENTITY_LARA_CUT :
|
case TR::Entity::LARA_CUT :
|
||||||
entity.controller = (lara = new Lara(&level, i));
|
entity.controller = (lara = new Lara(&level, i));
|
||||||
break;
|
break;
|
||||||
case ENTITY_ENEMY_WOLF :
|
case TR::Entity::ENEMY_WOLF :
|
||||||
entity.controller = new Wolf(&level, i);
|
entity.controller = new Wolf(&level, i);
|
||||||
break;
|
break;
|
||||||
case ENTITY_ENEMY_BEAR :
|
case TR::Entity::ENEMY_BEAR :
|
||||||
entity.controller = new Bear(&level, i);
|
entity.controller = new Bear(&level, i);
|
||||||
break;
|
break;
|
||||||
case ENTITY_ENEMY_BAT :
|
case TR::Entity::ENEMY_BAT :
|
||||||
entity.controller = new Bat(&level, i);
|
entity.controller = new Bat(&level, i);
|
||||||
break;
|
break;
|
||||||
case ENTITY_ENEMY_TWIN :
|
case TR::Entity::ENEMY_TWIN :
|
||||||
case ENTITY_ENEMY_CROCODILE_LAND :
|
case TR::Entity::ENEMY_CROCODILE_LAND :
|
||||||
case ENTITY_ENEMY_CROCODILE_WATER :
|
case TR::Entity::ENEMY_CROCODILE_WATER :
|
||||||
case ENTITY_ENEMY_LION_MALE :
|
case TR::Entity::ENEMY_LION_MALE :
|
||||||
case ENTITY_ENEMY_LION_FEMALE :
|
case TR::Entity::ENEMY_LION_FEMALE :
|
||||||
case ENTITY_ENEMY_PUMA :
|
case TR::Entity::ENEMY_PUMA :
|
||||||
case ENTITY_ENEMY_GORILLA :
|
case TR::Entity::ENEMY_GORILLA :
|
||||||
case ENTITY_ENEMY_RAT_LAND :
|
case TR::Entity::ENEMY_RAT_LAND :
|
||||||
case ENTITY_ENEMY_RAT_WATER :
|
case TR::Entity::ENEMY_RAT_WATER :
|
||||||
case ENTITY_ENEMY_REX :
|
case TR::Entity::ENEMY_REX :
|
||||||
case ENTITY_ENEMY_RAPTOR :
|
case TR::Entity::ENEMY_RAPTOR :
|
||||||
case ENTITY_ENEMY_MUTANT :
|
case TR::Entity::ENEMY_MUTANT :
|
||||||
case ENTITY_ENEMY_CENTAUR :
|
case TR::Entity::ENEMY_CENTAUR :
|
||||||
case ENTITY_ENEMY_MUMMY :
|
case TR::Entity::ENEMY_MUMMY :
|
||||||
case ENTITY_ENEMY_LARSON :
|
case TR::Entity::ENEMY_LARSON :
|
||||||
entity.controller = new Enemy(&level, i);
|
entity.controller = new Enemy(&level, i);
|
||||||
break;
|
break;
|
||||||
case ENTITY_DOOR_1 :
|
case TR::Entity::DOOR_1 :
|
||||||
case ENTITY_DOOR_2 :
|
case TR::Entity::DOOR_2 :
|
||||||
case ENTITY_DOOR_3 :
|
case TR::Entity::DOOR_3 :
|
||||||
case ENTITY_DOOR_4 :
|
case TR::Entity::DOOR_4 :
|
||||||
case ENTITY_DOOR_5 :
|
case TR::Entity::DOOR_5 :
|
||||||
case ENTITY_DOOR_6 :
|
case TR::Entity::DOOR_6 :
|
||||||
case ENTITY_DOOR_BIG_1 :
|
case TR::Entity::DOOR_BIG_1 :
|
||||||
case ENTITY_DOOR_BIG_2 :
|
case TR::Entity::DOOR_BIG_2 :
|
||||||
case ENTITY_DOOR_FLOOR_1 :
|
case TR::Entity::DOOR_FLOOR_1 :
|
||||||
case ENTITY_DOOR_FLOOR_2 :
|
case TR::Entity::DOOR_FLOOR_2 :
|
||||||
case ENTITY_TRAP_FLOOR :
|
case TR::Entity::TRAP_FLOOR :
|
||||||
case ENTITY_TRAP_BLADE :
|
case TR::Entity::TRAP_BLADE :
|
||||||
case ENTITY_TRAP_SPIKES :
|
case TR::Entity::TRAP_SPIKES :
|
||||||
case ENTITY_TRAP_STONE :
|
case TR::Entity::TRAP_STONE :
|
||||||
//case ENTITY_TRAP_DART :
|
|
||||||
entity.controller = new Trigger(&level, i, true);
|
entity.controller = new Trigger(&level, i, true);
|
||||||
break;
|
break;
|
||||||
case ENTITY_TRAP_DARTGUN :
|
case TR::Entity::TRAP_DARTGUN :
|
||||||
entity.controller = new Dart(&level, i);
|
entity.controller = new Dartgun(&level, i);
|
||||||
break;
|
break;
|
||||||
case ENTITY_SWITCH :
|
case TR::Entity::SWITCH :
|
||||||
case ENTITY_SWITCH_WATER :
|
case TR::Entity::SWITCH_WATER :
|
||||||
case ENTITY_HOLE_PUZZLE :
|
case TR::Entity::HOLE_PUZZLE :
|
||||||
case ENTITY_HOLE_KEY :
|
case TR::Entity::HOLE_KEY :
|
||||||
entity.controller = new Trigger(&level, i, false);
|
entity.controller = new Trigger(&level, i, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -111,6 +110,7 @@ struct Level {
|
|||||||
Debug::free();
|
Debug::free();
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
|
if (level.entities[i].id > -1)
|
||||||
delete (Controller*)level.entities[i].controller;
|
delete (Controller*)level.entities[i].controller;
|
||||||
|
|
||||||
for (int i = 0; i < shMAX; i++)
|
for (int i = 0; i < shMAX; i++)
|
||||||
@@ -246,7 +246,7 @@ struct Level {
|
|||||||
// render static mesh
|
// render static mesh
|
||||||
mat4 mTemp = Core::mModel;
|
mat4 mTemp = Core::mModel;
|
||||||
Core::mModel.translate(offset);
|
Core::mModel.translate(offset);
|
||||||
Core::mModel.rotateY(rMesh.rotation / 16384.0f * PI * 0.5f);
|
Core::mModel.rotateY(rMesh.rotation);
|
||||||
renderMesh(sMesh->mesh);
|
renderMesh(sMesh->mesh);
|
||||||
Core::mModel = mTemp;
|
Core::mModel = mTemp;
|
||||||
}
|
}
|
||||||
@@ -365,7 +365,7 @@ struct Level {
|
|||||||
fTime = controller->animTime;
|
fTime = controller->animTime;
|
||||||
} else {
|
} else {
|
||||||
anim = &level.anims[model.animation];
|
anim = &level.anims[model.animation];
|
||||||
angle = vec3(0.0f, entity.rotation / 16384.0f * PI * 0.5f, 0.0f);
|
angle = vec3(0.0f, entity.rotation, 0.0f);
|
||||||
fTime = time;
|
fTime = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,6 +436,20 @@ struct Level {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void renderSequence(const TR::Entity &entity) {
|
||||||
|
shaders[shSprite]->bind();
|
||||||
|
Core::active.shader->setParam(uModel, Core::mModel);
|
||||||
|
Core::active.shader->setParam(uColor, Core::color);
|
||||||
|
|
||||||
|
int sIndex = -(entity.modelIndex + 1);
|
||||||
|
int sFrame;
|
||||||
|
if (entity.controller)
|
||||||
|
sFrame = ((SpriteController*)entity.controller)->frame;
|
||||||
|
else
|
||||||
|
sFrame = int(time * 10.0f) % level.spriteSequences[sIndex].sCount;
|
||||||
|
mesh->renderSprite(sIndex, sFrame);
|
||||||
|
}
|
||||||
|
|
||||||
int getLightIndex(const vec3 &pos, int &room) {
|
int getLightIndex(const vec3 &pos, int &room) {
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
float dist;
|
float dist;
|
||||||
@@ -474,6 +488,8 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderEntity(const TR::Entity &entity) {
|
void renderEntity(const TR::Entity &entity) {
|
||||||
|
if (entity.id < 0) 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;
|
||||||
@@ -491,38 +507,23 @@ struct Level {
|
|||||||
// get light parameters for entity
|
// get light parameters for entity
|
||||||
getLight(vec3(entity.x, entity.y, entity.z), entity.room);
|
getLight(vec3(entity.x, entity.y, entity.z), entity.room);
|
||||||
|
|
||||||
// render entity models (TODO: remapping or consider model and entity id's)
|
// render entity models
|
||||||
bool isModel = false;
|
if (entity.modelIndex > 0)
|
||||||
|
renderModel(level.models[entity.modelIndex - 1], entity);
|
||||||
for (int i = 0; i < level.modelsCount; i++)
|
|
||||||
if (entity.id == level.models[i].id) {
|
|
||||||
isModel = true;
|
|
||||||
renderModel(level.models[i], entity);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if entity is billboard
|
// if entity is billboard
|
||||||
if (!isModel) {
|
if (entity.modelIndex < 0) {
|
||||||
Core::color = vec4(c, c, c, 1.0f);
|
Core::color = vec4(c, c, c, 1.0f);
|
||||||
shaders[shSprite]->bind();
|
renderSequence(entity);
|
||||||
Core::active.shader->setParam(uModel, Core::mModel);
|
|
||||||
Core::active.shader->setParam(uColor, Core::color);
|
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++)
|
|
||||||
if (entity.id == level.spriteSequences[i].id) {
|
|
||||||
mesh->renderSprite(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::mModel = m;
|
Core::mModel = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
float tickTextureAnimation = 0.0f;
|
|
||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
time += Core::deltaTime;
|
time += Core::deltaTime;
|
||||||
|
|
||||||
for (int i = 0; i < level.entitiesCount; i++) {
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
|
if (level.entities[i].id > -1) {
|
||||||
Controller *controller = (Controller*)level.entities[i].controller;
|
Controller *controller = (Controller*)level.entities[i].controller;
|
||||||
if (controller)
|
if (controller)
|
||||||
controller->update();
|
controller->update();
|
||||||
@@ -578,6 +579,28 @@ struct Level {
|
|||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
renderEntity(level.entities[i]);
|
renderEntity(level.entities[i]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
static int modelIndex = 0;
|
||||||
|
static bool lastStateK = false;
|
||||||
|
|
||||||
|
if (Input::down[ikM]) {
|
||||||
|
if (!lastStateK) {
|
||||||
|
lastStateK = true;
|
||||||
|
// modelIndex = (modelIndex + 1) % level.modelsCount;
|
||||||
|
modelIndex = (modelIndex + 1) % level.spriteSequencesCount;
|
||||||
|
LOG("model: %d %d\n", modelIndex, level.spriteSequences[modelIndex].id);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
lastStateK = false;
|
||||||
|
|
||||||
|
Core::mModel.translate(lara->pos + vec3(512, -512, 0));
|
||||||
|
//renderModel(level.models[modelIndex], level.entities[4]);
|
||||||
|
TR::Entity seq;
|
||||||
|
seq.modelIndex = -(modelIndex + 1);
|
||||||
|
seq.controller = NULL;
|
||||||
|
Core::color = vec4(1.0f);
|
||||||
|
renderSequence(seq);
|
||||||
|
*/
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Debug::begin();
|
Debug::begin();
|
||||||
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||||
|
31
src/mesh.h
31
src/mesh.h
@@ -74,7 +74,7 @@ struct MeshBuilder {
|
|||||||
int mCount;
|
int mCount;
|
||||||
|
|
||||||
// sprite sequences
|
// sprite sequences
|
||||||
MeshRange *spriteRanges;
|
MeshRange *sequenceRanges;
|
||||||
|
|
||||||
// indexed mesh
|
// indexed mesh
|
||||||
Mesh *mesh;
|
Mesh *mesh;
|
||||||
@@ -160,14 +160,14 @@ struct MeshBuilder {
|
|||||||
meshInfo = new MeshInfo[mCount];
|
meshInfo = new MeshInfo[mCount];
|
||||||
|
|
||||||
// get size of mesh for sprite sequences
|
// get size of mesh for sprite sequences
|
||||||
spriteRanges = new MeshRange[level.spriteSequencesCount];
|
sequenceRanges = new MeshRange[level.spriteSequencesCount];
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
||||||
// TODO: sequences not only first frame
|
// TODO: sequences not only first frame
|
||||||
spriteRanges[i].vStart = vCount;
|
sequenceRanges[i].vStart = vCount;
|
||||||
spriteRanges[i].iStart = iCount;
|
sequenceRanges[i].iStart = iCount;
|
||||||
spriteRanges[i].iCount = 6;
|
sequenceRanges[i].iCount = level.spriteSequences[i].sCount * 6;
|
||||||
iCount += 6;
|
iCount += level.spriteSequences[i].sCount * 6;
|
||||||
vCount += 4;
|
vCount += level.spriteSequences[i].sCount * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make meshes buffer (single vertex buffer object for all geometry & sprites on level)
|
// make meshes buffer (single vertex buffer object for all geometry & sprites on level)
|
||||||
@@ -363,9 +363,10 @@ struct MeshBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// build sprite sequences
|
// build sprite sequences
|
||||||
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
for (int i = 0; i < level.spriteSequencesCount; i++)
|
||||||
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart];
|
for (int j = 0; j < level.spriteSequences[i].sCount; j++) {
|
||||||
addSprite(indices, vertices, iCount, vCount, vCount, 0, -16, 0, sprite, 255);
|
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart + j];
|
||||||
|
addSprite(indices, vertices, iCount, vCount, vCount, 0, 0, 0, sprite, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh = new Mesh(indices, iCount, vertices, vCount);
|
mesh = new Mesh(indices, iCount, vertices, vCount);
|
||||||
@@ -378,7 +379,7 @@ struct MeshBuilder {
|
|||||||
delete[] animTexOffsets;
|
delete[] animTexOffsets;
|
||||||
delete[] roomRanges;
|
delete[] roomRanges;
|
||||||
delete[] meshInfo;
|
delete[] meshInfo;
|
||||||
delete[] spriteRanges;
|
delete[] sequenceRanges;
|
||||||
delete mesh;
|
delete mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,8 +544,12 @@ struct MeshBuilder {
|
|||||||
renderMesh(&meshInfo[meshIndex]);
|
renderMesh(&meshInfo[meshIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSprite(int spriteIndex) {
|
void renderSprite(int sequenceIndex, int frame) {
|
||||||
mesh->render(spriteRanges[spriteIndex]);
|
MeshRange range = sequenceRanges[sequenceIndex];
|
||||||
|
range.iCount = 6;
|
||||||
|
range.iStart += frame * 6;
|
||||||
|
range.vStart += frame * 4;
|
||||||
|
mesh->render(range);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -49,35 +49,73 @@ struct Trigger : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!inState())
|
if (!inState())
|
||||||
setState(state != baseState ? baseState : (entity.id == ENTITY_TRAP_BLADE ? 2 : (baseState ^ 1)));
|
setState(state != baseState ? baseState : (entity.id == TR::Entity::TRAP_BLADE ? 2 : (baseState ^ 1)));
|
||||||
|
|
||||||
updateAnimation(true);
|
updateAnimation(true);
|
||||||
updateEntity();
|
updateEntity();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dart : Trigger {
|
struct Dart : Controller {
|
||||||
vec3 origin;
|
|
||||||
|
|
||||||
Dart(TR::Level *level, int entity) : Trigger(level, entity, true), origin(pos) {}
|
vec3 dir;
|
||||||
|
bool inWall; // dart starts from wall
|
||||||
|
|
||||||
virtual bool activate(float timer) {
|
Dart(TR::Level *level, int entity) : Controller(level, entity), inWall(true) {
|
||||||
bool res = Trigger::activate(timer);
|
dir = vec3(sinf(angle.y), 0, cosf(angle.y));
|
||||||
if (res)
|
|
||||||
playSound(151);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update() {
|
virtual void update() {
|
||||||
Trigger::update();
|
velocity = dir * level->anims[animIndex].speed;
|
||||||
if (state != baseState) {
|
pos = pos + velocity * (Core::deltaTime * 30.0f);
|
||||||
pos = origin + vec3(angle.x, angle.y) * (animTime * 4096.0f);
|
|
||||||
updateEntity();
|
|
||||||
} else {
|
|
||||||
pos = origin;
|
|
||||||
updateEntity();
|
updateEntity();
|
||||||
|
TR::Level::FloorInfo info;
|
||||||
|
level->getFloorInfo(getRoomIndex(), (int)pos.x, (int)pos.z, info);
|
||||||
|
if (pos.y > info.floor || pos.y < info.ceiling || !insideRoom(pos, getRoomIndex())) {
|
||||||
|
if (!inWall) {
|
||||||
|
TR::Entity &e = getEntity();
|
||||||
|
|
||||||
|
vec3 p = pos - dir * 64.0f; // wall offset = 64
|
||||||
|
int sparkIndex = level->entityAdd(TR::Entity::SPARK, e.room, (int)p.x, (int)p.y, (int)p.z, e.rotation, -1);
|
||||||
|
if (sparkIndex > -1)
|
||||||
|
level->entities[sparkIndex].controller = new SpriteController(level, sparkIndex, true, SpriteController::FRAME_RANDOM);
|
||||||
|
|
||||||
|
level->entityRemove(entity);
|
||||||
|
delete this;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
inWall = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Dartgun : Trigger {
|
||||||
|
vec3 origin;
|
||||||
|
|
||||||
|
Dartgun(TR::Level *level, int entity) : Trigger(level, entity, true), origin(pos) {}
|
||||||
|
|
||||||
|
virtual bool activate(float timer) {
|
||||||
|
if (!Trigger::activate(timer))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// add dart (bullet)
|
||||||
|
TR::Entity &entity = getEntity();
|
||||||
|
|
||||||
|
vec3 pos = vec3(0.0f, -512.0f, 256.0f).rotateY(PI - entity.rotation);
|
||||||
|
pos = pos + vec3(entity.x, entity.y, entity.z);
|
||||||
|
|
||||||
|
int dartIndex = level->entityAdd(TR::Entity::TRAP_DART, entity.room, (int)pos.x, (int)pos.y, (int)pos.z, entity.rotation, entity.intensity);
|
||||||
|
if (dartIndex > -1)
|
||||||
|
level->entities[dartIndex].controller = new Dart(level, dartIndex);
|
||||||
|
|
||||||
|
int smokeIndex = level->entityAdd(TR::Entity::SMOKE, entity.room, (int)pos.x, (int)pos.y, (int)pos.z, entity.rotation, -1);
|
||||||
|
if (smokeIndex > -1)
|
||||||
|
level->entities[smokeIndex].controller = new SpriteController(level, smokeIndex);
|
||||||
|
|
||||||
|
playSound(151);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
int lastTime, fpsTime, FPS;
|
int lastTime, fpsTime, fps;
|
||||||
EGLDisplay display;
|
EGLDisplay display;
|
||||||
EGLSurface surface;
|
EGLSurface surface;
|
||||||
EGLContext context;
|
EGLContext context;
|
||||||
@@ -18,23 +18,28 @@ void main_loop() {
|
|||||||
if (time - lastTime <= 0)
|
if (time - lastTime <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Core::deltaTime = (time - lastTime) * 0.001f;
|
float delta = (time - lastTime) * 0.001f;
|
||||||
lastTime = time;
|
while (delta > EPS) {
|
||||||
|
Core::deltaTime = min(delta, 1.0f / 30.0f);
|
||||||
if (time > fpsTime) {
|
Game::update();
|
||||||
fpsTime = time + 1000;
|
delta -= Core::deltaTime;
|
||||||
LOG("FPS: %d\n", FPS);
|
|
||||||
FPS = 0;
|
|
||||||
}
|
}
|
||||||
|
lastTime = time;
|
||||||
|
|
||||||
int f;
|
int f;
|
||||||
emscripten_get_canvas_size(&Core::width, &Core::height, &f);
|
emscripten_get_canvas_size(&Core::width, &Core::height, &f);
|
||||||
|
|
||||||
Game::update();
|
Core::stats.dips = 0;
|
||||||
|
Core::stats.tris = 0;
|
||||||
Game::render();
|
Game::render();
|
||||||
eglSwapBuffers(display, surface);
|
eglSwapBuffers(display, surface);
|
||||||
|
|
||||||
FPS++;
|
if (fpsTime < getTime()) {
|
||||||
|
LOG("FPS: %d DIP: %d TRI: %d\n", fps, Core::stats.dips, Core::stats.tris);
|
||||||
|
fps = 0;
|
||||||
|
fpsTime = getTime() + 1000;
|
||||||
|
} else
|
||||||
|
fps++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initGL() {
|
bool initGL() {
|
||||||
@@ -182,7 +187,7 @@ int main() {
|
|||||||
|
|
||||||
lastTime = getTime();
|
lastTime = getTime();
|
||||||
fpsTime = lastTime + 1000;
|
fpsTime = lastTime + 1000;
|
||||||
FPS = 0;
|
fps = 0;
|
||||||
|
|
||||||
emscripten_set_main_loop(main_loop, 0, true);
|
emscripten_set_main_loop(main_loop, 0, true);
|
||||||
|
|
||||||
|
@@ -196,33 +196,31 @@ int main() {
|
|||||||
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
|
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
|
||||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||||
|
|
||||||
DWORD time, lastTime = getTime();
|
DWORD time, lastTime = getTime(), fpsTime = lastTime + 1000, fps = 0;
|
||||||
|
|
||||||
MSG msg;
|
MSG msg;
|
||||||
msg.message = WM_PAINT;
|
|
||||||
|
|
||||||
DWORD fps = 0, fpsTime = getTime() + 1000;
|
do {
|
||||||
|
|
||||||
while (msg.message != WM_QUIT)
|
|
||||||
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
} else {
|
} else {
|
||||||
|
joyUpdate();
|
||||||
|
|
||||||
time = getTime();
|
time = getTime();
|
||||||
if (time <= lastTime)
|
if (time <= lastTime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Core::deltaTime = (time - lastTime) * 0.001f;
|
float delta = (time - lastTime) * 0.001f;
|
||||||
|
while (delta > EPS) {
|
||||||
|
Core::deltaTime = min(delta, 1.0f / 30.0f);
|
||||||
|
Game::update();
|
||||||
|
delta -= Core::deltaTime;
|
||||||
|
}
|
||||||
lastTime = time;
|
lastTime = time;
|
||||||
|
|
||||||
joyUpdate();
|
|
||||||
|
|
||||||
Core::stats.dips = 0;
|
Core::stats.dips = 0;
|
||||||
Core::stats.tris = 0;
|
Core::stats.tris = 0;
|
||||||
|
|
||||||
Game::update();
|
|
||||||
Game::render();
|
Game::render();
|
||||||
|
|
||||||
SwapBuffers(hDC);
|
SwapBuffers(hDC);
|
||||||
|
|
||||||
if (fpsTime < getTime()) {
|
if (fpsTime < getTime()) {
|
||||||
@@ -232,6 +230,7 @@ int main() {
|
|||||||
} else
|
} else
|
||||||
fps++;
|
fps++;
|
||||||
}
|
}
|
||||||
|
} while (msg.message != WM_QUIT);
|
||||||
|
|
||||||
Game::free();
|
Game::free();
|
||||||
freeGL(hRC);
|
freeGL(hRC);
|
||||||
|
Reference in New Issue
Block a user