mirror of
https://github.com/XProger/OpenLara.git
synced 2025-03-13 23:59:41 +01: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:
parent
f22e45ad5f
commit
ec4216f424
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
95
src/camera.h
95
src/camera.h
@ -153,18 +153,17 @@ struct Frustum {
|
||||
|
||||
|
||||
struct Camera : Controller {
|
||||
Controller *owner;
|
||||
Frustum *frustum;
|
||||
Lara *owner;
|
||||
Frustum *frustum;
|
||||
|
||||
float fov, znear, zfar;
|
||||
vec3 target, destPos, lastDest, angleAdv;
|
||||
float fov, znear, zfar;
|
||||
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;
|
||||
znear = 0.1f * 2048.0f;
|
||||
zfar = 1000.0f * 2048.0f;
|
||||
znear = 128;
|
||||
zfar = 100.0f * 1024.0f;
|
||||
angleAdv = vec3(0.0f);
|
||||
|
||||
room = owner->getEntity().room;
|
||||
@ -212,18 +211,28 @@ struct Camera : Controller {
|
||||
angle = owner->angle + angleAdv;
|
||||
angle.z = 0.0f;
|
||||
//angle.x = min(max(angle.x, -80 * DEG2RAD), 80 * DEG2RAD);
|
||||
|
||||
|
||||
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) {
|
||||
destPos = target - dir * 1024.0f;
|
||||
vec3 eye = target - dir * 1024.0f;
|
||||
destPos = trace(owner->getRoomIndex(), target, eye);
|
||||
lastDest = destPos;
|
||||
} else
|
||||
destPos = lastDest + dir.cross(vec3(0, 1, 0)).normal() * 2048.0f - vec3(0.0f, 512.0f, 0.0f);
|
||||
} else {
|
||||
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;
|
||||
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() {
|
||||
Core::mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
||||
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) {
|
||||
TR::Entity &e = getEntity();
|
||||
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
||||
angle = vec3(0.0f, e.rotation / 16384.0f * PI * 0.5f, 0.0f);
|
||||
angle = vec3(0.0f, e.rotation, 0.0f);
|
||||
stand = STAND_GROUND;
|
||||
animIndex = getModel().animation;
|
||||
animIndex = e.modelIndex > 0 ? level->models[e.modelIndex - 1].animation : 0;
|
||||
state = level->anims[animIndex].state;
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ struct Controller {
|
||||
e.x = int(pos.x);
|
||||
e.y = int(pos.y);
|
||||
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 {
|
||||
@ -80,15 +80,6 @@ struct Controller {
|
||||
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 {
|
||||
int index = getRoomIndex();
|
||||
ASSERT(index >= 0 && index < level->roomsCount);
|
||||
@ -337,7 +328,7 @@ struct Controller {
|
||||
int idx = frame - anim->frameStart;
|
||||
|
||||
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);
|
||||
}
|
||||
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
|
28
src/debug.h
28
src/debug.h
@ -195,19 +195,19 @@ namespace Debug {
|
||||
cmd = (*fd++).cmd;
|
||||
|
||||
switch (cmd.func) {
|
||||
case TR::FD_PORTAL :
|
||||
case TR::FloorData::PORTAL :
|
||||
isPortal = true;
|
||||
fd++;
|
||||
break; // portal
|
||||
case TR::FD_FLOOR : // floor & ceiling
|
||||
case TR::FD_CEILING : {
|
||||
case TR::FloorData::FLOOR : // floor & ceiling
|
||||
case TR::FloorData::CEILING : {
|
||||
TR::FloorData::Slant slant = (*fd++).slant;
|
||||
int sx = 256 * (int)slant.x;
|
||||
int sz = 256 * (int)slant.z;
|
||||
|
||||
auto &p = cmd.func == 0x02 ? vf : vc;
|
||||
|
||||
if (cmd.func == 0x02) { // floor
|
||||
if (cmd.func == TR::FloorData::FLOOR) { // floor
|
||||
if (sx > 0) {
|
||||
p[0].y += sx;
|
||||
p[3].y += sx;
|
||||
@ -242,28 +242,12 @@ namespace Debug {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TR::FD_TRIGGER : {
|
||||
case TR::FloorData::TRIGGER : {
|
||||
TR::FloorData::TriggerInfo info = (*fd++).triggerInfo;
|
||||
TR::FloorData::TriggerCommand trigCmd;
|
||||
glColor3f(1, 0, 1);
|
||||
do {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@ -468,7 +452,7 @@ namespace Debug {
|
||||
matrix.rotateX(controller->angle.x);
|
||||
matrix.rotateZ(controller->angle.z);
|
||||
} else
|
||||
matrix.rotateY(e.rotation / 16384.0f * PI * 0.5f);
|
||||
matrix.rotateY(e.rotation);
|
||||
|
||||
for (int j = 0; j < level.modelsCount; j++) {
|
||||
TR::Model &m = level.models[j];
|
||||
|
263
src/format.h
263
src/format.h
@ -5,6 +5,8 @@
|
||||
|
||||
#define TR1_DEMO
|
||||
|
||||
#define MAX_RESERVED_ENTITIES 64
|
||||
|
||||
namespace TR {
|
||||
|
||||
enum : int32 {
|
||||
@ -12,14 +14,6 @@ namespace TR {
|
||||
ROOM_FLAG_VISIBLE = 0x8000
|
||||
};
|
||||
|
||||
enum {
|
||||
FD_PORTAL = 1,
|
||||
FD_FLOOR = 2,
|
||||
FD_CEILING = 3,
|
||||
FD_TRIGGER = 4,
|
||||
FD_KILL = 5,
|
||||
};
|
||||
|
||||
enum {
|
||||
ANIM_CMD_MOVE = 1,
|
||||
ANIM_CMD_SPEED = 2,
|
||||
@ -56,7 +50,7 @@ namespace TR {
|
||||
NONE = -1, // no action
|
||||
ACTIVATE = 0, // activate item
|
||||
CAMERA_SWITCH = 1, // switch to camera
|
||||
CAMERA_DELAY = 2, // camera delay
|
||||
UNDERWATER = 2, // underwater flow
|
||||
FLIP_MAP = 3, // flip map
|
||||
FLIP_ON = 4, // flip on
|
||||
FLIP_OFF = 5, // flip off
|
||||
@ -70,7 +64,6 @@ namespace TR {
|
||||
CUTSCENE = 13, // play cutscene
|
||||
};
|
||||
|
||||
|
||||
#define DATA_PORTAL 0x01
|
||||
#define DATA_FLOOR 0x02
|
||||
#define DATA_CEILING 0x03
|
||||
@ -79,67 +72,6 @@ namespace TR {
|
||||
#define ENTITY_FLAG_VISIBLE 0x0100
|
||||
#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)
|
||||
|
||||
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 {
|
||||
uint8 r, g, b;
|
||||
};
|
||||
@ -240,7 +180,7 @@ namespace TR {
|
||||
|
||||
struct Mesh {
|
||||
int32 x, y, z;
|
||||
uint16 rotation;
|
||||
angle rotation;
|
||||
uint16 intensity;
|
||||
uint16 meshID;
|
||||
uint16 flags; // ! not exists in file !
|
||||
@ -259,8 +199,16 @@ namespace TR {
|
||||
uint16 timer:8, once:1, mask:5, :2;
|
||||
} triggerInfo;
|
||||
struct TriggerCommand {
|
||||
uint16 args:10, func:5, end:1;
|
||||
uint16 args:10, action:5, end:1;
|
||||
} triggerCmd;
|
||||
|
||||
enum {
|
||||
PORTAL = 1,
|
||||
FLOOR = 2,
|
||||
CEILING = 3,
|
||||
TRIGGER = 4,
|
||||
KILL = 5,
|
||||
};
|
||||
};
|
||||
|
||||
struct Overlap {
|
||||
@ -302,14 +250,92 @@ namespace TR {
|
||||
int16 id; // Object Identifier (matched in Models[], or SpriteSequences[], as appropriate)
|
||||
int16 room; // which room contains this item
|
||||
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)
|
||||
uint16 flags; // 0x0100 indicates "initially invisible", 0x3e00 is Activation Mask
|
||||
// 0x3e00 indicates "open" or "activated"; these can be XORed with
|
||||
// related FloorData::FDlist fields (e.g. for switches)
|
||||
// not exists in file
|
||||
uint16 align;
|
||||
int16 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
|
||||
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 {
|
||||
@ -396,8 +422,8 @@ namespace TR {
|
||||
MinMax box[2]; // visible (minX, maxX, minY, maxY, minZ, maxZ) & collision
|
||||
uint16 flags;
|
||||
|
||||
void getBox(bool collision, int rotation, vec3 &min, vec3 &max) {
|
||||
int k = rotation / 16384;
|
||||
void getBox(bool collision, angle rotation, vec3 &min, vec3 &max) {
|
||||
int k = rotation.value / 0x4000;
|
||||
|
||||
MinMax &m = box[collision];
|
||||
|
||||
@ -574,6 +600,7 @@ namespace TR {
|
||||
int32 animTexturesDataSize;
|
||||
uint16 *animTexturesData;
|
||||
|
||||
int32 entitiesBaseCount;
|
||||
int32 entitiesCount;
|
||||
Entity *entities;
|
||||
|
||||
@ -666,6 +693,8 @@ namespace TR {
|
||||
stream.read(objectTextures, stream.read(objectTexturesCount));
|
||||
stream.read(spriteTextures, stream.read(spriteTexturesCount));
|
||||
stream.read(spriteSequences, stream.read(spriteSequencesCount));
|
||||
for (int i = 0; i < spriteSequencesCount; i++)
|
||||
spriteSequences[i].sCount = -spriteSequences[i].sCount;
|
||||
|
||||
#ifdef TR1_DEMO
|
||||
stream.read(palette, 256);
|
||||
@ -682,12 +711,17 @@ namespace TR {
|
||||
// animated textures
|
||||
stream.read(animTexturesData, stream.read(animTexturesDataSize));
|
||||
// entities (enemies, items, lara etc.)
|
||||
entities = new Entity[stream.read(entitiesCount)];
|
||||
for (int i = 0; i < entitiesCount; i++) {
|
||||
stream.raw(&entities[i], sizeof(entities[i]) - sizeof(entities[i].align) - sizeof(entities[i].controller));
|
||||
entities[i].align = 0;
|
||||
entities[i].controller = NULL;
|
||||
entitiesCount = stream.read(entitiesBaseCount) + MAX_RESERVED_ENTITIES;
|
||||
entities = new Entity[entitiesCount];
|
||||
for (int i = 0; i < entitiesBaseCount; i++) {
|
||||
Entity &e = entities[i];
|
||||
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
|
||||
stream.seek(32 * 256); // skip lightmap palette
|
||||
|
||||
@ -769,6 +803,43 @@ namespace TR {
|
||||
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 {
|
||||
int floor, ceiling;
|
||||
int roomNext, roomBelow, roomAbove;
|
||||
@ -822,16 +893,16 @@ namespace TR {
|
||||
|
||||
switch (cmd.func) {
|
||||
|
||||
case FD_PORTAL :
|
||||
case FloorData::PORTAL :
|
||||
info.roomNext = (*fd++).data;
|
||||
break;
|
||||
|
||||
case FD_FLOOR : // floor & ceiling
|
||||
case FD_CEILING : {
|
||||
case FloorData::FLOOR : // floor & ceiling
|
||||
case FloorData::CEILING : {
|
||||
FloorData::Slant slant = (*fd++).slant;
|
||||
int sx = (int)slant.x;
|
||||
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 -= sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||
} else {
|
||||
@ -841,7 +912,7 @@ namespace TR {
|
||||
break;
|
||||
}
|
||||
|
||||
case FD_TRIGGER : {
|
||||
case FloorData::TRIGGER : {
|
||||
info.trigger = cmd.sub;
|
||||
info.trigCmdCount = 0;
|
||||
info.trigInfo = (*fd++).triggerInfo;
|
||||
@ -849,28 +920,14 @@ namespace TR {
|
||||
do {
|
||||
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||
info.trigCmd[info.trigCmdCount++] = trigCmd;
|
||||
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 (playSound(175))
|
||||
case 11 : break; // clear bodies
|
||||
case 12 : break; // flyby camera sequence
|
||||
case 13 : break; // play cutscene
|
||||
if (trigCmd.action == Action::CAMERA_SWITCH) {
|
||||
|
||||
}
|
||||
// ..
|
||||
} while (!trigCmd.end);
|
||||
break;
|
||||
}
|
||||
|
||||
case FD_KILL :
|
||||
case FloorData::KILL :
|
||||
info.kill = true;
|
||||
break;
|
||||
|
||||
|
58
src/lara.h
58
src/lara.h
@ -17,7 +17,7 @@
|
||||
struct Lara : Controller {
|
||||
|
||||
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
||||
enum LaraAnim : int32 {
|
||||
enum {
|
||||
ANIM_STAND = 11,
|
||||
ANIM_FALL = 34,
|
||||
ANIM_SMASH_JUMP = 32,
|
||||
@ -35,7 +35,7 @@ struct Lara : Controller {
|
||||
};
|
||||
|
||||
// http://www.tombraiderforums.com/showthread.php?t=211681
|
||||
enum LaraState : int32 {
|
||||
enum {
|
||||
STATE_WALK,
|
||||
STATE_RUN,
|
||||
STATE_STOP,
|
||||
@ -94,7 +94,10 @@ struct Lara : Controller {
|
||||
STATE_WATER_OUT,
|
||||
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)
|
||||
pos = vec3(70067, -256, 29104);
|
||||
@ -195,6 +198,7 @@ struct Lara : Controller {
|
||||
return;
|
||||
break;
|
||||
default :
|
||||
LOG("unsupported trigger type %d\n", info.trigger);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -203,25 +207,38 @@ struct Lara : Controller {
|
||||
|
||||
// build trigger activation chain
|
||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||
if (info.trigCmd[i].func != TR::Action::ACTIVATE) continue; // TODO: other trigger types
|
||||
Controller *controller = (Controller*)level->entities[info.trigCmd[i].args].controller;
|
||||
if (!controller) {
|
||||
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
||||
playSound(2);
|
||||
return;
|
||||
} 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);
|
||||
TR::FloorData::TriggerCommand &cmd = info.trigCmd[i];
|
||||
switch (cmd.action) {
|
||||
case TR::Action::ACTIVATE : {
|
||||
Controller *controller = (Controller*)level->entities[cmd.args].controller;
|
||||
if (!controller) {
|
||||
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
||||
playSound(2);
|
||||
return;
|
||||
} 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);
|
||||
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
|
||||
Controller *controller = (Controller*)level->entities[info.trigCmd[0].args].controller;
|
||||
if (info.trigger == TR::TRIGGER_KEY) {
|
||||
nextAction = controller->nextAction;
|
||||
controller->nextAction.action = TR::Action::NONE;
|
||||
} else
|
||||
controller->activate((float)info.trigInfo.timer);
|
||||
if (controller) {
|
||||
if (info.trigger == TR::TRIGGER_KEY) {
|
||||
nextAction = controller->nextAction;
|
||||
controller->nextAction.action = TR::Action::NONE;
|
||||
} else
|
||||
controller->activate((float)info.trigInfo.timer);
|
||||
}
|
||||
}
|
||||
|
||||
virtual Stand getStand() {
|
||||
@ -381,6 +398,11 @@ struct Lara : Controller {
|
||||
}
|
||||
|
||||
virtual void updateState() {
|
||||
if (targetTimer > 0.0f && (targetTimer -= Core::deltaTime) <= 0.0f) {
|
||||
targetEntity = -1;
|
||||
targetTimer = 0.0f;
|
||||
}
|
||||
|
||||
performTrigger();
|
||||
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
|
167
src/level.h
167
src/level.h
@ -25,7 +25,7 @@ struct Level {
|
||||
Texture *atlas;
|
||||
MeshBuilder *mesh;
|
||||
|
||||
Controller *lara;
|
||||
Lara *lara;
|
||||
Camera *camera;
|
||||
|
||||
float time;
|
||||
@ -43,60 +43,59 @@ struct Level {
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
TR::Entity &entity = level.entities[i];
|
||||
switch (entity.id) {
|
||||
case ENTITY_LARA :
|
||||
case ENTITY_LARA_CUT :
|
||||
case TR::Entity::LARA :
|
||||
case TR::Entity::LARA_CUT :
|
||||
entity.controller = (lara = new Lara(&level, i));
|
||||
break;
|
||||
case ENTITY_ENEMY_WOLF :
|
||||
case TR::Entity::ENEMY_WOLF :
|
||||
entity.controller = new Wolf(&level, i);
|
||||
break;
|
||||
case ENTITY_ENEMY_BEAR :
|
||||
case TR::Entity::ENEMY_BEAR :
|
||||
entity.controller = new Bear(&level, i);
|
||||
break;
|
||||
case ENTITY_ENEMY_BAT :
|
||||
case TR::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 :
|
||||
case TR::Entity::ENEMY_TWIN :
|
||||
case TR::Entity::ENEMY_CROCODILE_LAND :
|
||||
case TR::Entity::ENEMY_CROCODILE_WATER :
|
||||
case TR::Entity::ENEMY_LION_MALE :
|
||||
case TR::Entity::ENEMY_LION_FEMALE :
|
||||
case TR::Entity::ENEMY_PUMA :
|
||||
case TR::Entity::ENEMY_GORILLA :
|
||||
case TR::Entity::ENEMY_RAT_LAND :
|
||||
case TR::Entity::ENEMY_RAT_WATER :
|
||||
case TR::Entity::ENEMY_REX :
|
||||
case TR::Entity::ENEMY_RAPTOR :
|
||||
case TR::Entity::ENEMY_MUTANT :
|
||||
case TR::Entity::ENEMY_CENTAUR :
|
||||
case TR::Entity::ENEMY_MUMMY :
|
||||
case TR::Entity::ENEMY_LARSON :
|
||||
entity.controller = new Enemy(&level, i);
|
||||
break;
|
||||
case ENTITY_DOOR_1 :
|
||||
case ENTITY_DOOR_2 :
|
||||
case ENTITY_DOOR_3 :
|
||||
case ENTITY_DOOR_4 :
|
||||
case ENTITY_DOOR_5 :
|
||||
case ENTITY_DOOR_6 :
|
||||
case ENTITY_DOOR_BIG_1 :
|
||||
case ENTITY_DOOR_BIG_2 :
|
||||
case ENTITY_DOOR_FLOOR_1 :
|
||||
case ENTITY_DOOR_FLOOR_2 :
|
||||
case ENTITY_TRAP_FLOOR :
|
||||
case ENTITY_TRAP_BLADE :
|
||||
case ENTITY_TRAP_SPIKES :
|
||||
case ENTITY_TRAP_STONE :
|
||||
//case ENTITY_TRAP_DART :
|
||||
case TR::Entity::DOOR_1 :
|
||||
case TR::Entity::DOOR_2 :
|
||||
case TR::Entity::DOOR_3 :
|
||||
case TR::Entity::DOOR_4 :
|
||||
case TR::Entity::DOOR_5 :
|
||||
case TR::Entity::DOOR_6 :
|
||||
case TR::Entity::DOOR_BIG_1 :
|
||||
case TR::Entity::DOOR_BIG_2 :
|
||||
case TR::Entity::DOOR_FLOOR_1 :
|
||||
case TR::Entity::DOOR_FLOOR_2 :
|
||||
case TR::Entity::TRAP_FLOOR :
|
||||
case TR::Entity::TRAP_BLADE :
|
||||
case TR::Entity::TRAP_SPIKES :
|
||||
case TR::Entity::TRAP_STONE :
|
||||
entity.controller = new Trigger(&level, i, true);
|
||||
break;
|
||||
case ENTITY_TRAP_DARTGUN :
|
||||
entity.controller = new Dart(&level, i);
|
||||
case TR::Entity::TRAP_DARTGUN :
|
||||
entity.controller = new Dartgun(&level, i);
|
||||
break;
|
||||
case ENTITY_SWITCH :
|
||||
case ENTITY_SWITCH_WATER :
|
||||
case ENTITY_HOLE_PUZZLE :
|
||||
case ENTITY_HOLE_KEY :
|
||||
case TR::Entity::SWITCH :
|
||||
case TR::Entity::SWITCH_WATER :
|
||||
case TR::Entity::HOLE_PUZZLE :
|
||||
case TR::Entity::HOLE_KEY :
|
||||
entity.controller = new Trigger(&level, i, false);
|
||||
break;
|
||||
}
|
||||
@ -111,7 +110,8 @@ struct Level {
|
||||
Debug::free();
|
||||
#endif
|
||||
for (int i = 0; i < level.entitiesCount; i++)
|
||||
delete (Controller*)level.entities[i].controller;
|
||||
if (level.entities[i].id > -1)
|
||||
delete (Controller*)level.entities[i].controller;
|
||||
|
||||
for (int i = 0; i < shMAX; i++)
|
||||
delete shaders[i];
|
||||
@ -246,7 +246,7 @@ struct Level {
|
||||
// render static mesh
|
||||
mat4 mTemp = Core::mModel;
|
||||
Core::mModel.translate(offset);
|
||||
Core::mModel.rotateY(rMesh.rotation / 16384.0f * PI * 0.5f);
|
||||
Core::mModel.rotateY(rMesh.rotation);
|
||||
renderMesh(sMesh->mesh);
|
||||
Core::mModel = mTemp;
|
||||
}
|
||||
@ -365,7 +365,7 @@ struct Level {
|
||||
fTime = controller->animTime;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 idx = -1;
|
||||
float dist;
|
||||
@ -474,6 +488,8 @@ struct Level {
|
||||
}
|
||||
|
||||
void renderEntity(const TR::Entity &entity) {
|
||||
if (entity.id < 0) return;
|
||||
|
||||
TR::Room &room = level.rooms[entity.room];
|
||||
if (!(room.flags & TR::ROOM_FLAG_VISIBLE)) // check for room visibility
|
||||
return;
|
||||
@ -491,42 +507,27 @@ struct Level {
|
||||
// get light parameters for entity
|
||||
getLight(vec3(entity.x, entity.y, entity.z), entity.room);
|
||||
|
||||
// render entity models (TODO: remapping or consider model and entity id's)
|
||||
bool isModel = false;
|
||||
|
||||
for (int i = 0; i < level.modelsCount; i++)
|
||||
if (entity.id == level.models[i].id) {
|
||||
isModel = true;
|
||||
renderModel(level.models[i], entity);
|
||||
break;
|
||||
}
|
||||
|
||||
// render entity models
|
||||
if (entity.modelIndex > 0)
|
||||
renderModel(level.models[entity.modelIndex - 1], entity);
|
||||
// if entity is billboard
|
||||
if (!isModel) {
|
||||
if (entity.modelIndex < 0) {
|
||||
Core::color = vec4(c, c, c, 1.0f);
|
||||
shaders[shSprite]->bind();
|
||||
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;
|
||||
}
|
||||
renderSequence(entity);
|
||||
}
|
||||
|
||||
|
||||
Core::mModel = m;
|
||||
}
|
||||
|
||||
float tickTextureAnimation = 0.0f;
|
||||
|
||||
void update() {
|
||||
time += Core::deltaTime;
|
||||
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
Controller *controller = (Controller*)level.entities[i].controller;
|
||||
if (controller)
|
||||
controller->update();
|
||||
}
|
||||
for (int i = 0; i < level.entitiesCount; i++)
|
||||
if (level.entities[i].id > -1) {
|
||||
Controller *controller = (Controller*)level.entities[i].controller;
|
||||
if (controller)
|
||||
controller->update();
|
||||
}
|
||||
|
||||
camera->update();
|
||||
}
|
||||
@ -578,6 +579,28 @@ struct Level {
|
||||
for (int i = 0; i < level.entitiesCount; 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
|
||||
Debug::begin();
|
||||
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
|
33
src/mesh.h
33
src/mesh.h
@ -74,7 +74,7 @@ struct MeshBuilder {
|
||||
int mCount;
|
||||
|
||||
// sprite sequences
|
||||
MeshRange *spriteRanges;
|
||||
MeshRange *sequenceRanges;
|
||||
|
||||
// indexed mesh
|
||||
Mesh *mesh;
|
||||
@ -160,14 +160,14 @@ struct MeshBuilder {
|
||||
meshInfo = new MeshInfo[mCount];
|
||||
|
||||
// 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++) {
|
||||
// TODO: sequences not only first frame
|
||||
spriteRanges[i].vStart = vCount;
|
||||
spriteRanges[i].iStart = iCount;
|
||||
spriteRanges[i].iCount = 6;
|
||||
iCount += 6;
|
||||
vCount += 4;
|
||||
sequenceRanges[i].vStart = vCount;
|
||||
sequenceRanges[i].iStart = iCount;
|
||||
sequenceRanges[i].iCount = level.spriteSequences[i].sCount * 6;
|
||||
iCount += level.spriteSequences[i].sCount * 6;
|
||||
vCount += level.spriteSequences[i].sCount * 4;
|
||||
}
|
||||
|
||||
// make meshes buffer (single vertex buffer object for all geometry & sprites on level)
|
||||
@ -363,10 +363,11 @@ struct MeshBuilder {
|
||||
}
|
||||
|
||||
// build sprite sequences
|
||||
for (int i = 0; i < level.spriteSequencesCount; i++) {
|
||||
TR::SpriteTexture &sprite = level.spriteTextures[level.spriteSequences[i].sStart];
|
||||
addSprite(indices, vertices, iCount, vCount, vCount, 0, -16, 0, sprite, 255);
|
||||
}
|
||||
for (int i = 0; i < level.spriteSequencesCount; i++)
|
||||
for (int j = 0; j < level.spriteSequences[i].sCount; j++) {
|
||||
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);
|
||||
delete[] indices;
|
||||
@ -378,7 +379,7 @@ struct MeshBuilder {
|
||||
delete[] animTexOffsets;
|
||||
delete[] roomRanges;
|
||||
delete[] meshInfo;
|
||||
delete[] spriteRanges;
|
||||
delete[] sequenceRanges;
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
@ -543,8 +544,12 @@ struct MeshBuilder {
|
||||
renderMesh(&meshInfo[meshIndex]);
|
||||
}
|
||||
|
||||
void renderSprite(int spriteIndex) {
|
||||
mesh->render(spriteRanges[spriteIndex]);
|
||||
void renderSprite(int sequenceIndex, int frame) {
|
||||
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())
|
||||
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);
|
||||
updateEntity();
|
||||
}
|
||||
};
|
||||
|
||||
struct Dart : Trigger {
|
||||
vec3 origin;
|
||||
struct Dart : Controller {
|
||||
|
||||
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) {
|
||||
bool res = Trigger::activate(timer);
|
||||
if (res)
|
||||
playSound(151);
|
||||
return res;
|
||||
Dart(TR::Level *level, int entity) : Controller(level, entity), inWall(true) {
|
||||
dir = vec3(sinf(angle.y), 0, cosf(angle.y));
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
Trigger::update();
|
||||
if (state != baseState) {
|
||||
pos = origin + vec3(angle.x, angle.y) * (animTime * 4096.0f);
|
||||
updateEntity();
|
||||
} else {
|
||||
pos = origin;
|
||||
updateEntity();
|
||||
}
|
||||
velocity = dir * level->anims[animIndex].speed;
|
||||
pos = pos + velocity * (Core::deltaTime * 30.0f);
|
||||
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
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "game.h"
|
||||
|
||||
int lastTime, fpsTime, FPS;
|
||||
int lastTime, fpsTime, fps;
|
||||
EGLDisplay display;
|
||||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
@ -18,23 +18,28 @@ void main_loop() {
|
||||
if (time - lastTime <= 0)
|
||||
return;
|
||||
|
||||
Core::deltaTime = (time - lastTime) * 0.001f;
|
||||
lastTime = time;
|
||||
|
||||
if (time > fpsTime) {
|
||||
fpsTime = time + 1000;
|
||||
LOG("FPS: %d\n", FPS);
|
||||
FPS = 0;
|
||||
float delta = (time - lastTime) * 0.001f;
|
||||
while (delta > EPS) {
|
||||
Core::deltaTime = min(delta, 1.0f / 30.0f);
|
||||
Game::update();
|
||||
delta -= Core::deltaTime;
|
||||
}
|
||||
lastTime = time;
|
||||
|
||||
int f;
|
||||
emscripten_get_canvas_size(&Core::width, &Core::height, &f);
|
||||
|
||||
Game::update();
|
||||
Core::stats.dips = 0;
|
||||
Core::stats.tris = 0;
|
||||
Game::render();
|
||||
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() {
|
||||
@ -182,7 +187,7 @@ int main() {
|
||||
|
||||
lastTime = getTime();
|
||||
fpsTime = lastTime + 1000;
|
||||
FPS = 0;
|
||||
fps = 0;
|
||||
|
||||
emscripten_set_main_loop(main_loop, 0, true);
|
||||
|
||||
|
@ -196,33 +196,31 @@ int main() {
|
||||
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
|
||||
DWORD time, lastTime = getTime();
|
||||
|
||||
DWORD time, lastTime = getTime(), fpsTime = lastTime + 1000, fps = 0;
|
||||
MSG msg;
|
||||
msg.message = WM_PAINT;
|
||||
|
||||
DWORD fps = 0, fpsTime = getTime() + 1000;
|
||||
|
||||
while (msg.message != WM_QUIT)
|
||||
do {
|
||||
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
} else {
|
||||
joyUpdate();
|
||||
|
||||
time = getTime();
|
||||
if (time <= lastTime)
|
||||
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;
|
||||
|
||||
joyUpdate();
|
||||
|
||||
Core::stats.dips = 0;
|
||||
Core::stats.tris = 0;
|
||||
|
||||
Game::update();
|
||||
Game::render();
|
||||
|
||||
SwapBuffers(hDC);
|
||||
|
||||
if (fpsTime < getTime()) {
|
||||
@ -232,6 +230,7 @@ int main() {
|
||||
} else
|
||||
fps++;
|
||||
}
|
||||
} while (msg.message != WM_QUIT);
|
||||
|
||||
Game::free();
|
||||
freeGL(hRC);
|
||||
|
Loading…
x
Reference in New Issue
Block a user