1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-16 18:14:05 +02:00

#23 fix items opacity; fix water mask for desktop NVIDIA cards; #22 fix lava trap; cutscene wait timer (for sound sync WIP); #15 extern osGetTime

This commit is contained in:
XProger
2017-12-07 12:11:25 +03:00
parent 1b4a6dadb0
commit 353e09cb64
13 changed files with 281 additions and 194 deletions

View File

@@ -413,7 +413,7 @@ struct Controller {
} while (!cmd.end); } while (!cmd.end);
} }
virtual void getSaveData(TR::SaveGame::Entity &data) { virtual bool getSaveData(TR::SaveGame::Entity &data) {
const TR::Entity &e = getEntity(); const TR::Entity &e = getEntity();
const TR::Model *m = getModel(); const TR::Model *m = getModel();
if (entity < level->entitiesBaseCount) { if (entity < level->entitiesBaseCount) {
@@ -439,6 +439,8 @@ struct Controller {
data.animFrame = m ? animation.frameIndex : 0; data.animFrame = m ? animation.frameIndex : 0;
data.extraSize = 0; data.extraSize = 0;
return true;
} }
virtual void setSaveData(const TR::SaveGame::Entity &data) { virtual void setSaveData(const TR::SaveGame::Entity &data) {
@@ -945,6 +947,7 @@ struct Controller {
virtual void update() { virtual void update() {
updateAnimation(true); updateAnimation(true);
updateExplosion(); updateExplosion();
updateLights(true);
} }
void updateLights(bool lerp = true) { void updateLights(bool lerp = true) {
@@ -1043,9 +1046,7 @@ struct Controller {
} }
void renderShadow(MeshBuilder *mesh) { void renderShadow(MeshBuilder *mesh) {
const TR::Entity &entity = getEntity(); if (Core::pass != Core::passCompose || level->isCutsceneLevel())
if (Core::pass != Core::passCompose || !entity.castShadow() || entity.isActor())
return; return;
Box boxL = getBoundingBoxLocal(); Box boxL = getBoundingBoxLocal();

View File

@@ -162,7 +162,8 @@ struct KeySet {
namespace Core { namespace Core {
float deltaTime; float deltaTime;
int width, height; int lastTime;
int width, height;
struct { struct {
int maxVectors; int maxVectors;
@@ -237,6 +238,17 @@ namespace Core {
bool reverb; bool reverb;
} audio; } audio;
} settings; } settings;
bool resetState;
int getTime() {
return osGetTime();
}
void resetTime() {
lastTime = getTime();
resetState = true;
}
} }
#include "input.h" #include "input.h"
@@ -444,8 +456,6 @@ struct Vertex {
enum CullFace { cfNone, cfBack, cfFront }; enum CullFace { cfNone, cfBack, cfFront };
enum BlendMode { bmNone, bmAlpha, bmAdd, bmMult, bmPremult }; enum BlendMode { bmNone, bmAlpha, bmAdd, bmMult, bmPremult };
extern int getTime();
namespace Core { namespace Core {
float eye; float eye;
vec4 viewport, viewportDef; vec4 viewport, viewportDef;
@@ -506,16 +516,16 @@ namespace Core {
} }
void stop() { void stop() {
if (fpsTime < getTime()) { if (fpsTime < Core::getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, dips, tris); LOG("FPS: %d DIP: %d TRI: %d\n", fps, dips, tris);
#ifdef PROFILE #ifdef PROFILE
LOG("frame time: %d mcs\n", tFrame / 1000); LOG("frame time: %d mcs\n", tFrame / 1000);
#endif #endif
fps = frame; fps = frame;
frame = 0; frame = 0;
fpsTime = getTime() + 1000; fpsTime = Core::getTime() + 1000;
} else } else
frame++; frame++;
} }
} stats; } stats;
} }
@@ -723,6 +733,7 @@ namespace Core {
#ifdef __RPI__ #ifdef __RPI__
settings.detail.setShadows(Core::Settings::LOW); settings.detail.setShadows(Core::Settings::LOW);
#endif #endif
resetTime();
} }
void deinit() { void deinit() {
@@ -762,6 +773,16 @@ namespace Core {
return cache.count++; return cache.count++;
} }
bool update() {
resetState = false;
int time = getTime();
if (time - lastTime <= 0)
return false;
deltaTime = (time - lastTime) * 0.001f;
lastTime = time;
return true;
}
void validateRenderState() { void validateRenderState() {
int32 mask = renderState ^ active.renderState; int32 mask = renderState ^ active.renderState;
if (!mask) return; if (!mask) return;

View File

@@ -77,17 +77,20 @@ struct Enemy : Character {
delete path; delete path;
} }
virtual void getSaveData(TR::SaveGame::Entity &data) { virtual bool getSaveData(TR::SaveGame::Entity &data) {
Character::getSaveData(data); Character::getSaveData(data);
data.extraSize = sizeof(data.extra.enemy); data.extraSize = sizeof(data.extra.enemy);
data.extra.enemy.health = uint16(health); data.extra.enemy.health = health;
data.extra.enemy.mood = uint16(mood); data.extra.enemy.mood = mood;
data.extra.enemy.targetBox = targetBox;
return true;
} }
virtual void setSaveData(const TR::SaveGame::Entity &data) { virtual void setSaveData(const TR::SaveGame::Entity &data) {
Character::setSaveData(data); Character::setSaveData(data);
health = float(data.extra.enemy.health); health = data.extra.enemy.health;
mood = Mood(data.extra.enemy.mood); mood = Mood(data.extra.enemy.mood);
targetBox = data.extra.enemy.targetBox;
} }
virtual bool activate() { virtual bool activate() {
@@ -1321,9 +1324,7 @@ struct Doppelganger : Enemy {
struct ScionTarget : Enemy { struct ScionTarget : Enemy {
float timer; ScionTarget(IGame *game, int entity) : Enemy(game, entity, 5, 0, 0, 0) {}
ScionTarget(IGame *game, int entity) : Enemy(game, entity, 5, 0, 0, 0), timer(0.0f) {}
virtual void update() { virtual void update() {
Controller::update(); Controller::update();

View File

@@ -1648,10 +1648,10 @@ namespace TR {
return type; return type;
if (version & VER_TR2) if (version & VER_TR2)
type = TR::Entity::Type(type + TR2_TYPES_START); type = Type(type + TR2_TYPES_START);
if (version & VER_TR3) if (version & VER_TR3)
type = TR::Entity::Type(type + TR3_TYPES_START); type = Type(type + TR3_TYPES_START);
#define REMAP_2(TYPE) case _##TYPE : return TYPE #define REMAP_2(TYPE) case _##TYPE : return TYPE
#define REMAP_3(TYPE) case __##TYPE : return TYPE #define REMAP_3(TYPE) case __##TYPE : return TYPE
@@ -2327,6 +2327,25 @@ namespace TR {
struct SaveGame { struct SaveGame {
struct Item {
uint16 type;
uint16 count;
};
struct Progress {
uint32 size;
uint32 time;
uint32 distance;
uint8 levelID;
uint8 mediUsed;
uint8 secrets;
uint8 pickups;
uint16 ammoUsed;
uint8 kills;
uint8 itemsCount;
// Item items[itemsCount]
};
struct Entity { struct Entity {
// base // base
int32 x, y, z; int32 x, y, z;
@@ -2338,64 +2357,56 @@ namespace TR {
uint16 animIndex; uint16 animIndex;
uint16 animFrame; uint16 animFrame;
// common // common
uint8 room; uint16 room;
uint8 extraSize; uint16 extraSize;
union Extra { union Extra {
struct { struct {
float velX, velY, velZ; float velX, velY, velZ;
uint16 angleX; float angleX;
uint16 health; float health;
uint16 oxygen; float oxygen;
uint16 stamina; float stamina;
uint8 itemHands; float poison;
uint8 itemBack; float freeze;
uint8 itemHolster; uint16 itemHands;
uint16 itemBack;
uint16 itemHolster;
union { union {
struct { uint8 wet:1, burn:1; }; struct { uint16 wet:1, burn:1; };
uint8 value; uint16 value;
} flags; } flags;
} lara; } lara;
struct { struct {
uint16 health; float health;
uint16 mood; uint16 mood;
uint16 targetBox;
} enemy; } enemy;
struct {
int32 jointIndex;
float sleep;
} flame;
} extra; } extra;
}; };
struct Item {
uint16 type;
uint16 count;
};
struct CurrentState { struct CurrentState {
// EntityState entities[entitiesCount]; ByteFlags flipmaps[MAX_FLIPMAP_COUNT];
ByteFlags tracks[MAX_TRACKS_COUNT];
uint32 fogColor; uint16 fogColor;
uint16 secrets;
union { union {
struct { uint16 track:8, flipped:1; }; struct { uint16 track:8, flipped:1; };
uint16 value; uint16 value;
} flags; } flags;
uint16 entitiesCount;
ByteFlags flipmaps[MAX_FLIPMAP_COUNT]; Progress progress;
ByteFlags tracks[MAX_TRACKS_COUNT]; //Entity entities[entitiesCount];
}; };
uint32 size; int32 size;
uint16 levelID; uint16 version;
// full game stats uint16 progressCount;
uint16 mediUsed; // Progress progress[levelsCount];
uint16 pickups;
uint16 secrets;
uint32 kills;
uint32 ammoUsed;
uint32 distance;
uint32 time;
uint16 itemsCount; // 0 -> skip inventory items array
uint16 entitiesCount; // 0 -> skip current state
// Item items[itemsCount]
// CurrentState currentState; // CurrentState currentState;
}; };

View File

@@ -75,16 +75,21 @@ namespace Game {
Core::deltaTime = dt; Core::deltaTime = dt;
} }
void update(float delta) { bool update() {
PROFILE_MARKER("UPDATE"); PROFILE_MARKER("UPDATE");
if (!Core::update())
return false;
float delta = Core::deltaTime;
if (nextLevel) { if (nextLevel) {
startLevel(nextLevel); startLevel(nextLevel);
nextLevel = NULL; nextLevel = NULL;
} }
if (level->isEnded) if (level->isEnded)
return; return true;
Input::update(); Input::update();
@@ -94,7 +99,7 @@ namespace Game {
Input::down[ikV] = false; Input::down[ikV] = false;
} }
} }
/*
if (Input::down[ikS]) { if (Input::down[ikS]) {
if (level->lara->canSaveGame()) if (level->lara->canSaveGame())
level->saveGame(0); level->saveGame(0);
@@ -105,16 +110,10 @@ namespace Game {
level->loadGame(0); level->loadGame(0);
Input::down[ikL] = false; Input::down[ikL] = false;
} }
*/
if (!level->level.isCutsceneLevel()) if (!level->level.isCutsceneLevel())
delta = min(0.2f, delta); delta = min(0.2f, delta);
if (level->cutsceneFirstFrame) {
level->cutsceneFirstFrame = false;
delta = 1.0f / 30.0f;
}
Core::deltaTime = delta; Core::deltaTime = delta;
UI::update(); UI::update();
@@ -122,7 +121,11 @@ namespace Game {
Core::deltaTime = min(delta, 1.0f / 30.0f); Core::deltaTime = min(delta, 1.0f / 30.0f);
Game::updateTick(); Game::updateTick();
delta -= Core::deltaTime; delta -= Core::deltaTime;
if (Core::resetState) // resetTime was called
break;
} }
return true;
} }
void render() { void render() {

View File

@@ -529,30 +529,33 @@ struct Lara : Character {
return health > 0.0f && (state == STATE_STOP || state == STATE_TREAD || state == STATE_SURF_TREAD); return health > 0.0f && (state == STATE_STOP || state == STATE_TREAD || state == STATE_SURF_TREAD);
} }
virtual void getSaveData(TR::SaveGame::Entity &data) { virtual bool getSaveData(TR::SaveGame::Entity &data) {
Character::getSaveData(data); Character::getSaveData(data);
data.extraSize = sizeof(data.extra.lara); data.extraSize = sizeof(data.extra.lara);
data.extra.lara.velX = velocity.x; data.extra.lara.velX = velocity.x;
data.extra.lara.velY = velocity.y; data.extra.lara.velY = velocity.y;
data.extra.lara.velZ = velocity.z; data.extra.lara.velZ = velocity.z;
data.extra.lara.angleX = TR::angle(normalizeAngle(angle.x)).value; data.extra.lara.angleX = angle.x;
data.extra.lara.health = uint16(health); data.extra.lara.health = health;
data.extra.lara.oxygen = uint16(oxygen); data.extra.lara.oxygen = oxygen;
// data.extra.lara.curWeapon = int8(wpnCurrent); data.extra.lara.stamina = 0.0f;
// data.extra.lara.emptyHands = emptyHands(); data.extra.lara.poison = 0.0f;
/* data.extra.lara.freeze = 0.0f;
uint16 itemHands; data.extra.lara.itemHands = TR::Entity::LARA;
uint16 itemBack; data.extra.lara.itemBack = TR::Entity::SHOTGUN;
uint16 itemHolster; data.extra.lara.itemHolster = TR::Entity::PISTOLS;
*/ data.extra.lara.flags.value = 0;
data.extra.lara.flags.burn = 0; // TODO
data.extra.lara.flags.wet = 0; // TODO
return true;
} }
virtual void setSaveData(const TR::SaveGame::Entity &data) { virtual void setSaveData(const TR::SaveGame::Entity &data) {
Character::setSaveData(data); Character::setSaveData(data);
velocity = vec3(data.extra.lara.velX, data.extra.lara.velY, data.extra.lara.velZ); velocity = vec3(data.extra.lara.velX, data.extra.lara.velY, data.extra.lara.velZ);
angle.x = TR::angle(data.extra.lara.angleX); angle.x = TR::angle(data.extra.lara.angleX);
health = float(data.extra.lara.health); health = data.extra.lara.health;
oxygen = float(data.extra.lara.oxygen); oxygen = data.extra.lara.oxygen;
layers[1].mask = layers[2].mask = layers[3].mask = 0; layers[1].mask = layers[2].mask = layers[3].mask = 0;
wpnState = Weapon::IS_HIDDEN; wpnState = Weapon::IS_HIDDEN;
@@ -1998,8 +2001,8 @@ struct Lara : Character {
effect = TR::Effect(cmd.args); effect = TR::Effect(cmd.args);
break; break;
case TR::Action::SECRET : case TR::Action::SECRET :
if (!(level->state.secrets & (1 << cmd.args))) { if (!(level->state.progress.secrets & (1 << cmd.args))) {
level->state.secrets |= 1 << cmd.args; level->state.progress.secrets |= 1 << cmd.args;
if (!game->playSound(TR::SND_SECRET, pos)) if (!game->playSound(TR::SND_SECRET, pos))
game->playTrack(TR::TRACK_TR1_SECRET); game->playTrack(TR::TRACK_TR1_SECRET);
} }

View File

@@ -46,11 +46,11 @@ struct Level : IGame {
bool lastTitle; bool lastTitle;
bool isEnded; bool isEnded;
bool cutsceneFirstFrame;
TR::Effect effect; TR::Effect effect;
float effectTimer; float effectTimer;
int effectIdx; int effectIdx;
float cutsceneWaitTimer;
Texture *cube360; Texture *cube360;
@@ -105,40 +105,50 @@ struct Level : IGame {
*save = level.save; *save = level.save;
ptr += sizeof(*save); ptr += sizeof(*save);
// inventory items // save levels progress
save->itemsCount = 0; save->progressCount = 0;
for (int i = 0; i < inventory.itemsCount; i++) {
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr;
Inventory::Item *invItem = inventory.items[i];
bool saveCurrentState = true;
if (saveCurrentState) {
TR::SaveGame::CurrentState *currentState = (TR::SaveGame::CurrentState*)ptr;
ptr += sizeof(TR::SaveGame::CurrentState);
*currentState = level.state;
// inventory items
currentState->progress.itemsCount = 0;
for (int i = 0; i < inventory.itemsCount; i++) {
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr;
Inventory::Item *invItem = inventory.items[i];
if (!TR::Entity::isPickup(TR::Entity::convFromInv(invItem->type))) continue; if (!TR::Entity::isPickup(TR::Entity::convFromInv(invItem->type))) continue;
item->type = invItem->type; item->type = invItem->type;
item->count = invItem->count; item->count = invItem->count;
ptr += sizeof(*item); ptr += sizeof(*item);
save->itemsCount++; currentState->progress.itemsCount++;
}
// level entities
currentState->entitiesCount = 0;
for (int i = 0; i < level.entitiesCount; i++) {
Controller *controller = (Controller*)level.entities[i].controller;
TR::SaveGame::Entity *entity = (TR::SaveGame::Entity*)ptr;
if (!controller || !controller->getSaveData(*entity)) continue;
ptr += (sizeof(TR::SaveGame::Entity) - sizeof(TR::SaveGame::Entity::Extra)) + entity->extraSize;
currentState->entitiesCount++;
}
} }
// level entities save->size = ptr - data;
save->entitiesCount = 0; save->version = level.version & TR::VER_VERSION;
for (int i = 0; i < level.entitiesCount; i++) {
Controller *controller = (Controller*)level.entities[i].controller;
if (!controller || (controller->getEntity().isSprite() && !controller->getEntity().isPickup())) continue;
TR::SaveGame::Entity *entity = (TR::SaveGame::Entity*)ptr;
controller->getSaveData(*entity);
ptr += (sizeof(TR::SaveGame::Entity) - sizeof(TR::SaveGame::Entity::Extra)) + entity->extraSize;
save->entitiesCount++;
}
// current level state Stream::write("savegame.dat", data, int(ptr - data));
if (save->entitiesCount) {
TR::SaveGame::CurrentState *state = (TR::SaveGame::CurrentState*)ptr;
*state = level.state;
ptr += sizeof(*state);
}
//Stream::write("savegame.dat", data, int(ptr - data));
delete[] data; delete[] data;
LOG("Ok\n"); LOG("Ok\n");
@@ -160,15 +170,19 @@ struct Level : IGame {
level.save = *save; level.save = *save;
ptr += sizeof(*save); ptr += sizeof(*save);
for (int i = 0; i < save->itemsCount; i++) { if (save->size > (ptr - data)) { // has current state
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr; TR::SaveGame::CurrentState *currentState = (TR::SaveGame::CurrentState*)ptr;
inventory.add(TR::Entity::Type(item->type), item->count, false); ptr += sizeof(TR::SaveGame::CurrentState);
ptr += sizeof(*item);
}
if (save->entitiesCount) { level.state = *currentState;
for (int i = 0; i < save->entitiesCount; i++) { for (int i = 0; i < currentState->progress.itemsCount; i++) {
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr;
inventory.add(TR::Entity::Type(item->type), item->count, false);
ptr += sizeof(*item);
}
for (int i = 0; i < currentState->entitiesCount; i++) {
TR::SaveGame::Entity *entity = (TR::SaveGame::Entity*)ptr; TR::SaveGame::Entity *entity = (TR::SaveGame::Entity*)ptr;
Controller *controller; Controller *controller;
@@ -186,17 +200,13 @@ struct Level : IGame {
ptr += (sizeof(TR::SaveGame::Entity) - sizeof(TR::SaveGame::Entity::Extra)) + entity->extraSize; ptr += (sizeof(TR::SaveGame::Entity) - sizeof(TR::SaveGame::Entity::Extra)) + entity->extraSize;
} }
TR::SaveGame::CurrentState *state = (TR::SaveGame::CurrentState*)ptr;
level.state = *state;
ptr += sizeof(*state);
delete[] data;
uint8 track = level.state.flags.track; uint8 track = level.state.flags.track;
level.state.flags.track = 0; level.state.flags.track = 0;
playTrack(track, true); playTrack(track, true);
} }
delete[] data;
// camera->room = lara->getRoomIndex(); // camera->room = lara->getRoomIndex();
// camera->pos = camera->destPos = lara->pos; // camera->pos = camera->destPos = lara->pos;
LOG("Ok\n"); LOG("Ok\n");
@@ -516,11 +526,15 @@ struct Level : IGame {
Level *level = (Level*)userData; Level *level = (Level*)userData;
level->sndSoundtrack = Sound::play(stream, vec3(0.0f), 0.01f, 1.0f, Sound::MUSIC); level->sndSoundtrack = Sound::play(stream, vec3(0.0f), 0.01f, 1.0f, Sound::MUSIC);
if (level->sndSoundtrack) if (level->sndSoundtrack) {
if (level->level.isCutsceneLevel()) {
// level->sndSoundtrack->setVolume(0.0f, 0.0f);
// level->sndCurrent = level->sndSoundtrack;
Core::resetTime();
}
level->sndSoundtrack->setVolume(1.0f, 0.2f); level->sndSoundtrack->setVolume(1.0f, 0.2f);
}
if (level->level.isCutsceneLevel()) LOG("play soundtrack - %d\n", Core::getTime());
level->cutsceneFirstFrame = true;
} }
virtual void playTrack(uint8 track, bool restart = false) { virtual void playTrack(uint8 track, bool restart = false) {
@@ -575,7 +589,7 @@ struct Level : IGame {
} }
//============================== //==============================
Level(Stream &stream) : level(stream), inventory(this), lara(NULL), isEnded(false), cutsceneFirstFrame(false) { Level(Stream &stream) : level(stream), inventory(this), lara(NULL), isEnded(false), cutsceneWaitTimer(0.0f) {
params->time = 0.0f; params->time = 0.0f;
#ifdef _DEBUG #ifdef _DEBUG
@@ -632,12 +646,14 @@ struct Level : IGame {
inventory.toggle(Inventory::PAGE_OPTION); inventory.toggle(Inventory::PAGE_OPTION);
} }
effect = TR::Effect::NONE;
cube360 = NULL;
sndSoundtrack = NULL; sndSoundtrack = NULL;
playTrack(0); playTrack(0);
sndCurrent = sndSoundtrack; sndCurrent = sndSoundtrack;
effect = TR::Effect::NONE; Core::resetTime();
cube360 = NULL;
} }
virtual ~Level() { virtual ~Level() {
@@ -1252,10 +1268,24 @@ struct Level : IGame {
} }
void update() { void update() {
if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK)) { if (level.isCutsceneLevel()) {
if (camera->timer > 0.0f) if (!sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK) {
loadNextLevel(); if (camera->timer > 0.0f) // for the case that audio stops before animation ends
return; loadNextLevel();
return;
}
if (cutsceneWaitTimer > 0.0f) {
cutsceneWaitTimer -= Core::deltaTime;
if (cutsceneWaitTimer > 0.0f)
return;
if (sndSoundtrack)
sndSoundtrack->setVolume(1.0f, 0.0f);
cutsceneWaitTimer = 0.0f;
Core::resetTime();
LOG("reset timer - %d\n", Core::getTime());
return;
}
} }
if (Input::state[cInventory] && !level.isTitle()) { if (Input::state[cInventory] && !level.isTitle()) {
@@ -1357,10 +1387,8 @@ struct Level : IGame {
mesh->transparent = transp; mesh->transparent = transp;
for (int i = 0; i < level.entitiesCount; i++) { for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &e = level.entities[i]; TR::Entity &e = level.entities[i];
if (!e.controller) continue; if (!e.controller || e.modelIndex == 0) continue;
int modelIndex = e.modelIndex; renderEntity(e);
if (modelIndex != 0)
renderEntity(e);
} }
} }

View File

@@ -388,7 +388,7 @@ struct MeshBuilder {
addSprite(indices, vertices, iCount, vCount, vStartSprite, 0, 0, 0, sprite, TR::Color32(255, 255, 255, 255), TR::Color32(255, 255, 255, 255)); addSprite(indices, vertices, iCount, vCount, vStartSprite, 0, 0, 0, sprite, TR::Color32(255, 255, 255, 255), TR::Color32(255, 255, 255, 255));
} }
range.iCount = iCount - range.iStart; range.iCount = iCount - range.iStart;
sequences[i].transp = 2; sequences[i].transp = 1; // alpha blending by default
} }
ASSERT(vCount - vStartSprite <= 0xFFFF); ASSERT(vCount - vStartSprite <= 0xFFFF);

View File

@@ -3,15 +3,24 @@
#include "game.h" #include "game.h"
int lastTime, lastJoy = -1; int lastJoy = -1;
EGLDisplay display; EGLDisplay display;
EGLSurface surface; EGLSurface surface;
EGLContext context; EGLContext context;
int getTime() { int osGetTime() {
return (int)emscripten_get_now(); return (int)emscripten_get_now();
} }
bool osSave(const char *name, const void *data, int size) {
// TODO cookie? idb?
FILE *f = fopen(name, "wb");
if (!f) return false;
fwrite(data, size, 1, f);
fclose(f);
return true;
}
extern "C" { extern "C" {
void EMSCRIPTEN_KEEPALIVE snd_fill(Sound::Frame *frames, int count) { void EMSCRIPTEN_KEEPALIVE snd_fill(Sound::Frame *frames, int count) {
Sound::fill(frames, count); Sound::fill(frames, count);
@@ -95,14 +104,10 @@ void joyUpdate() {
void main_loop() { void main_loop() {
joyUpdate(); joyUpdate();
int time = getTime(); if (Game::update()) {
if (time - lastTime <= 0) Game::render();
return; eglSwapBuffers(display, surface);
Game::update((time - lastTime) * 0.001f); }
lastTime = time;
Game::render();
eglSwapBuffers(display, surface);
} }
bool initGL() { bool initGL() {
@@ -291,8 +296,6 @@ int main() {
emscripten_run_script("snd_init()"); emscripten_run_script("snd_init()");
resize(); resize();
lastTime = getTime();
emscripten_set_main_loop(main_loop, 0, true); emscripten_set_main_loop(main_loop, 0, true);
Game::deinit(); Game::deinit();

View File

@@ -16,7 +16,7 @@
#include "game.h" #include "game.h"
int getTime() { int osGetTime() {
#ifdef DEBUG #ifdef DEBUG
LARGE_INTEGER Freq, Count; LARGE_INTEGER Freq, Count;
QueryPerformanceFrequency(&Freq); QueryPerformanceFrequency(&Freq);
@@ -28,6 +28,14 @@ int getTime() {
#endif #endif
} }
bool osSave(const char *name, const void *data, int size) {
FILE *f = fopen(name, "wb");
if (!f) return false;
fwrite(data, size, 1, f);
fclose(f);
return true;
}
// common input functions // common input functions
InputKey keyToInputKey(int code) { InputKey keyToInputKey(int code) {
static const int codes[] = { static const int codes[] = {
@@ -295,11 +303,16 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
HGLRC initGL(HDC hDC) { HGLRC initGL(HDC hDC) {
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd)); memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd); pfd.nSize = sizeof(pfd);
pfd.nVersion = 1; pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.cColorBits = 32; pfd.cColorBits = 32;
pfd.cDepthBits = 24; pfd.cRedBits = 8;
pfd.cGreenBits = 8;
pfd.cBlueBits = 8;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
int format = ChoosePixelFormat(hDC, &pfd); int format = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, format, &pfd); SetPixelFormat(hDC, format, &pfd);
@@ -356,7 +369,6 @@ int main(int argc, char** argv) {
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc); SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
ShowWindow(hWnd, SW_SHOWDEFAULT); ShowWindow(hWnd, SW_SHOWDEFAULT);
DWORD lastTime = getTime();
MSG msg; MSG msg;
do { do {
@@ -365,16 +377,10 @@ int main(int argc, char** argv) {
DispatchMessage(&msg); DispatchMessage(&msg);
} else { } else {
joyUpdate(); joyUpdate();
if (Game::update()) {
DWORD time = getTime(); Game::render();
if (time <= lastTime) SwapBuffers(hDC);
continue; }
Game::update((time - lastTime) * 0.001f);
lastTime = time;
Game::render();
SwapBuffers(hDC);
#ifdef _DEBUG #ifdef _DEBUG
Sleep(20); Sleep(20);
#endif #endif

View File

@@ -15,8 +15,6 @@ struct Sprite : Controller {
float time; float time;
vec3 velocity; vec3 velocity;
BlendMode blendMode;
Sprite(IGame *game, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(game, entity), instant(instant), flag(frame), time(0), velocity(0) { Sprite(IGame *game, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(game, entity), instant(instant), flag(frame), time(0), velocity(0) {
if (frame >= 0) { // specific frame if (frame >= 0) { // specific frame
this->frame = frame; this->frame = frame;

View File

@@ -126,7 +126,7 @@ struct Flame : Sprite {
return flame; return flame;
} }
int jointIndex; int32 jointIndex;
float sleep; float sleep;
Flame(IGame *game, int entity) : Sprite(game, entity, false, Sprite::FRAME_ANIMATED), jointIndex(0), sleep(0.0f) { Flame(IGame *game, int entity) : Sprite(game, entity, false, Sprite::FRAME_ANIMATED), jointIndex(0), sleep(0.0f) {
@@ -134,6 +134,20 @@ struct Flame : Sprite {
activate(); activate();
} }
virtual bool getSaveData(TR::SaveGame::Entity &data) {
Controller::getSaveData(data);
data.extraSize = sizeof(data.extra.flame);
data.extra.flame.jointIndex = jointIndex;
data.extra.flame.sleep = sleep;
return true;
}
virtual void setSaveData(const TR::SaveGame::Entity &data) {
Controller::setSaveData(data);
jointIndex = data.extra.flame.jointIndex;
sleep = data.extra.flame.sleep;
}
virtual void update() { virtual void update() {
Sprite::update(); Sprite::update();
game->playSound(TR::SND_FLAME, pos, Sound::PAN); game->playSound(TR::SND_FLAME, pos, Sound::PAN);
@@ -201,10 +215,14 @@ struct LavaParticle : Sprite {
LavaParticle(IGame *game, int entity) : Sprite(game, entity, false, Sprite::FRAME_RANDOM), bounces(0) { LavaParticle(IGame *game, int entity) : Sprite(game, entity, false, Sprite::FRAME_RANDOM), bounces(0) {
float speed = randf() * LAVA_H_SPEED; float speed = randf() * LAVA_H_SPEED;
velocity = vec3(cosf(angle.y) * speed, randf() * LAVA_V_SPEED, sinf(angle.y) * speed); velocity = vec3(cosf(angle.y) * speed, randf() * LAVA_V_SPEED, sinf(angle.y) * speed);
blendMode = bmAdd; game->getMesh()->sequences[-(getEntity().modelIndex + 1)].transp = 2; // fix blending mode to additive
activate(); activate();
} }
virtual bool getSaveData(TR::SaveGame::Entity &data) {
return false;
}
virtual void update() { virtual void update() {
applyGravity(velocity.y); applyGravity(velocity.y);
Sprite::update(); Sprite::update();
@@ -1138,27 +1156,21 @@ struct MidasHand : Controller {
}; };
struct TrapLava : Controller { struct TrapLava : Controller {
bool done; TrapLava(IGame *game, int entity) : Controller(game, entity) {}
TrapLava(IGame *game, int entity) : Controller(game, entity), done(false) {}
virtual void update() { virtual void update() {
Character *lara = (Character*)level->laraController; Character *lara = (Character*)level->laraController;
if (lara->health > 0.0f && collide(lara)) if (lara->health > 0.0f && collide(lara))
lara->hit(1001.0f, this, TR::HIT_LAVA); lara->hit(1001.0f, this, TR::HIT_LAVA);
if (done) {
deactivate();
return;
}
vec3 dir = getDir(); vec3 dir = getDir();
pos += dir * (25.0f * 30.0f * Core::deltaTime);
roomIndex = getRoomIndex(); roomIndex = getRoomIndex();
TR::Room::Sector *s = level->getSector(roomIndex, int(pos.x + dir.x * 2048.0f), int(pos.y), int(pos.z + dir.z * 2048.0f)); TR::Room::Sector *s = level->getSector(roomIndex, int(pos.x + dir.x * 2048.0f), int(pos.y), int(pos.z + dir.z * 2048.0f));
if (!s || s->floor * 256 != int(pos.y)) if (!s || s->floor * 256 != int(pos.y))
done = true; return;
pos += dir * (25.0f * 30.0f * Core::deltaTime);
} }
}; };
@@ -1411,6 +1423,10 @@ struct Bubble : Sprite {
game->waterDrop(pos, 64.0f, 0.01f); game->waterDrop(pos, 64.0f, 0.01f);
} }
virtual bool getSaveData(TR::SaveGame::Entity &data) {
return false;
}
virtual void update() { virtual void update() {
pos.y -= speed * Core::deltaTime; pos.y -= speed * Core::deltaTime;
angle.x += 30.0f * 13.0f * DEG2RAD * Core::deltaTime; angle.x += 30.0f * 13.0f * DEG2RAD * Core::deltaTime;
@@ -1426,6 +1442,7 @@ struct Explosion : Sprite {
Explosion(IGame *game, int entity) : Sprite(game, entity, true, Sprite::FRAME_ANIMATED) { Explosion(IGame *game, int entity) : Sprite(game, entity, true, Sprite::FRAME_ANIMATED) {
game->playSound(TR::SND_EXPLOSION, pos, 0); game->playSound(TR::SND_EXPLOSION, pos, 0);
game->getMesh()->sequences[-(getEntity().modelIndex + 1)].transp = 2; // fix blending mode to additive
} }
}; };

View File

@@ -35,6 +35,9 @@
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__) #define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__)
#endif #endif
extern int osGetTime();
extern bool osSave(const char *name, const void *data, int size);
#define DECL_ENUM(v) v, #define DECL_ENUM(v) v,
#define DECL_STR(v) #v, #define DECL_STR(v) #v,
@@ -1062,15 +1065,7 @@ struct Stream {
} }
static void write(const char *name, const void *data, int size) { static void write(const char *name, const void *data, int size) {
#ifdef __EMSCRIPTEN__
extern void osSave(const char *name, const void *data, int size);
osSave(name, data, size); osSave(name, data, size);
#else
FILE *f = fopen(name, "wb");
if (!f) return;
fwrite(data, size, 1, f);
fclose(f);
#endif
} }
void setPos(int pos) { void setPos(int pos) {