diff --git a/src/core.h b/src/core.h index ce816b2..a4e5632 100644 --- a/src/core.h +++ b/src/core.h @@ -1,9 +1,7 @@ #ifndef H_CORE #define H_CORE -#ifndef __EMSCRIPTEN__ - #define USE_INFLATE -#endif +#define USE_INFLATE #include #ifdef WIN32 diff --git a/src/game.h b/src/game.h index 3eb899a..d747f77 100644 --- a/src/game.h +++ b/src/game.h @@ -52,14 +52,17 @@ namespace Game { void init(char *lvlName = NULL, char *sndName = NULL) { char fileName[255]; + TR::Version version = TR::getGameVersion(); + if (!lvlName && version != TR::VER_UNKNOWN) { + lvlName = fileName; + TR::getGameLevelFile(lvlName, version, TR::getTitleId(version)); + } + if (!lvlName) { lvlName = fileName; strcpy(lvlName, "level/1/TITLE.PSX"); - - TR::Version version = TR::getGameVersion(); - if (version != TR::VER_UNKNOWN) - TR::getGameLevelFile(lvlName, version, TR::getTitleId(version)); } + init(new Stream(lvlName)); } @@ -123,9 +126,6 @@ namespace Game { if (!level->level.isCutsceneLevel()) delta = min(0.2f, delta); - Core::deltaTime = delta; - UI::update(); - while (delta > EPS) { Core::deltaTime = min(delta, 1.0f / 30.0f); Game::updateTick(); diff --git a/src/gameflow.h b/src/gameflow.h index 62df412..d7ed69b 100644 --- a/src/gameflow.h +++ b/src/gameflow.h @@ -669,46 +669,128 @@ namespace TR { } const char* getGameScreen(Version version, LevelID id) { - if (useEasyStart) { + #define CHECK_FILE(name) if (Stream::existsContent(name)) return name - #define CHECK_FILE(name) if (Stream::existsContent(name)) return name + switch (id) { + // TR1 + case LVL_TR1_TITLE : + CHECK_FILE("TITLEH.png"); // Android + CHECK_FILE("DATA/TITLEH.PCX"); // PC + CHECK_FILE("DELDATA/AMERTIT.RAW"); // PSX + CHECK_FILE("BINDATA/USATIT.BIN"); // SEGA + return "level/1/AMERTIT.PNG"; // WEB + case LVL_TR1_GYM : + CHECK_FILE("DELDATA/GYMLOAD.RAW"); + CHECK_FILE("BINDATA/GYM224.BIN"); + return "level/1/GYMLOAD.PNG"; + case LVL_TR1_1 : + case LVL_TR1_2 : + case LVL_TR1_3A : + case LVL_TR1_3B : + CHECK_FILE("DELDATA/AZTECLOA.RAW"); + CHECK_FILE("BINDATA/AZTEC224.BIN"); + return "level/1/AZTECLOA.PNG"; + case LVL_TR1_4 : + case LVL_TR1_5 : + case LVL_TR1_6 : + case LVL_TR1_7A : + case LVL_TR1_7B : + CHECK_FILE("DELDATA/GREEKLOA.RAW"); + CHECK_FILE("BINDATA/GREEK224.BIN"); + return "level/1/GREEKLOA.PNG"; + case LVL_TR1_8A : + case LVL_TR1_8B : + case LVL_TR1_8C : + CHECK_FILE("DELDATA/EGYPTLOA.RAW"); + CHECK_FILE("BINDATA/EGYPT224.BIN"); + return "level/1/EGYPTLOA.PNG"; + case LVL_TR1_10A : + case LVL_TR1_10B : + case LVL_TR1_10C : + CHECK_FILE("DELDATA/ATLANLOA.RAW"); + CHECK_FILE("BINDATA/ATLAN224.BIN"); + return "level/1/ATLANLOA.PNG"; + // TR2 + case LVL_TR2_TITLE : + CHECK_FILE("TITLE.png"); // Android + CHECK_FILE("data/TITLE.PCX"); // PC + CHECK_FILE("pix/title.pcx"); // PC + CHECK_FILE("PIXUS/TITLEUS.RAW"); // PSX (TODO: add other languages) + return "level/2/TITLEUS.PNG"; // WEB + case LVL_TR2_ASSAULT : + case LVL_TR2_HOUSE : + CHECK_FILE("PIX/MANSION.RAW"); + return "level/2/MANSION.PNG"; + case LVL_TR2_WALL : + case LVL_TR2_EMPRTOMB : + case LVL_TR2_FLOATING : + case LVL_TR2_XIAN : + CHECK_FILE("PIX/CHINA.RAW"); + return "level/2/CHINA.PNG"; + case LVL_TR2_BOAT : + case LVL_TR2_VENICE : + case LVL_TR2_OPERA : + CHECK_FILE("PIX/VENICE.RAW"); + return "level/2/VENICE.PNG"; + case LVL_TR2_RIG : + case LVL_TR2_PLATFORM : + CHECK_FILE("PIX/RIG.RAW"); + return "level/2/RIG.PNG"; + case LVL_TR2_UNWATER : + case LVL_TR2_KEEL : + case LVL_TR2_LIVING : + case LVL_TR2_DECK : + CHECK_FILE("PIX/TITAN.RAW"); + return "level/2/TITAN.PNG"; + case LVL_TR2_SKIDOO : + case LVL_TR2_MONASTRY : + case LVL_TR2_CATACOMB : + case LVL_TR2_ICECAVE : + CHECK_FILE("PIX/TIBET.RAW"); + return "level/2/TIBET.PNG"; + // TR3 + case LVL_TR3_TITLE : + CHECK_FILE("pix/TITLEUK.BMP"); // PC (TODO: add other languages) + return "level/3/TITLEUK.PNG"; // WEB + case LVL_TR3_HOUSE : + CHECK_FILE("pix/HOUSE.BMP"); + return "level/3/HOUSE.PNG"; + case LVL_TR3_JUNGLE : + case LVL_TR3_TEMPLE : + case LVL_TR3_QUADCHAS : + case LVL_TR3_TONYBOSS : + CHECK_FILE("pix/INDIA.BMP"); + return "level/3/INDIA.PNG"; + case LVL_TR3_SHORE : + case LVL_TR3_CRASH : + case LVL_TR3_RAPIDS : + case LVL_TR3_TRIBOSS : + CHECK_FILE("pix/SOUTHPAC.BMP"); + return "level/3/SOUTHPAC.PNG"; + case LVL_TR3_ROOFS : + case LVL_TR3_SEWER : + case LVL_TR3_TOWER : + case LVL_TR3_OFFICE : + case LVL_TR3_STPAUL : + CHECK_FILE("pix/LONDON.BMP"); + return "level/3/LONDON.PNG"; + case LVL_TR3_NEVADA : + case LVL_TR3_COMPOUND : + case LVL_TR3_AREA51 : + CHECK_FILE("pix/NEVADA.BMP"); + return "level/3/NEVADA.PNG"; + case LVL_TR3_ANTARC : + case LVL_TR3_MINES : + case LVL_TR3_CITY : + case LVL_TR3_CHAMBER : + CHECK_FILE("pix/ANTARC.BMP"); + return "level/3/ANTARC.PNG"; - switch (id) { - case LVL_TR1_TITLE : - CHECK_FILE("TITLEH.png"); // Android - CHECK_FILE("DATA/TITLEH.PCX"); // PC - CHECK_FILE("DELDATA/AMERTIT.RAW"); // PSX - CHECK_FILE("BINDATA/USATIT.BIN"); // SEGA - break; - - case LVL_TR2_TITLE : - CHECK_FILE("TITLE.png"); // Android - CHECK_FILE("data/TITLE.PCX"); // PC - CHECK_FILE("pix/title.pcx"); // PC - CHECK_FILE("PIXUS/TITLEUS.RAW"); // PSX (TODO: add other languages) - break; - - case LVL_TR3_TITLE : - CHECK_FILE("pix/TITLEUK.BMP"); // PC (TODO: add other languages) - break; - - default : ; - } - - #undef CHECK_FILE - - } else { - switch (id) { - case LVL_TR1_TITLE : return "level/1/TITLEH.PCX"; - - case LVL_TR2_TITLE : return "level/2/TITLE.PCX"; - - case LVL_TR3_TITLE : return "level/3/TITLEUK.BMP"; - - default : ; - } + default : ; } + #undef CHECK_FILE + return NULL; } } diff --git a/src/inventory.h b/src/inventory.h index 0e1533d..44df6d6 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -10,6 +10,8 @@ #define INVENTORY_BG_SIZE 512 #define INVENTORY_HEIGHT 2048.0f +#define TITLE_LOADING 64.0f + struct Inventory { enum Page { @@ -29,6 +31,7 @@ struct Inventory { Page page, targetPage; int itemsCount; + float titleTimer; float changeTimer; TR::LevelID nextLevel; // toggle result ControlKey lastKey; @@ -168,8 +171,12 @@ struct Inventory { } *items[INVENTORY_MAX_ITEMS]; static void loadTitleBG(Stream *stream, void *userData) { - if (!stream) return; Inventory *inv = (Inventory*)userData; + if (!stream) { + inv->titleTimer = 0.0f; + return; + } + inv->titleTimer = 3.0f; inv->background[0] = Texture::Load(*stream); delete stream; @@ -214,21 +221,20 @@ struct Inventory { TR::Level *level = game->getLevel(); + memset(background, 0, sizeof(background)); + + const char *titleBG = TR::getGameScreen(level->version, level->id); + if (titleBG) { + titleTimer = TITLE_LOADING; + new Stream(titleBG, loadTitleBG, this); + } else + titleTimer = 0.0f; + if (level->isTitle()) { add(TR::Entity::INV_HOME); - - memset(background, 0, sizeof(background)); - - const char *titleBG = TR::getGameScreen(level->version, level->id); - if (titleBG) - new Stream(titleBG, loadTitleBG, this); - } else { add(TR::Entity::INV_COMPASS); add(TR::Entity::INV_STOPWATCH); - - for (int i = 0; i < COUNT(background); i++) - background[i] = new Texture(INVENTORY_BG_SIZE, INVENTORY_BG_SIZE, Texture::RGBA, false); } phaseRing = phasePage = phaseChoose = phaseSelect = 0.0f; @@ -582,6 +588,15 @@ struct Inventory { } void update() { + if (titleTimer != TITLE_LOADING && titleTimer > 0.0f) { + titleTimer -= Core::deltaTime; + if (titleTimer < 0.0f) + titleTimer = 0.0f; + } + + if (!isActive()) + return; + float lastChoose = phaseChoose; if (phaseChoose == 0.0f) @@ -737,6 +752,15 @@ struct Inventory { } void prepareBackground() { + if (background[0]->origWidth != INVENTORY_BG_SIZE || background[0]->origHeight != INVENTORY_BG_SIZE) { + delete background[0]; + background[0] = NULL; + } + + for (int i = 0; i < COUNT(background); i++) + if (!background[i]) + background[i] = new Texture(INVENTORY_BG_SIZE, INVENTORY_BG_SIZE, Texture::RGBA, false); + Core::setDepthTest(false); Core::setBlending(bmNone); @@ -1008,9 +1032,11 @@ struct Inventory { } void render() { + if (!isActive() && titleTimer == 0.0f) + return; + // background Core::setDepthTest(false); - Core::setBlending(bmNone); if (background[0]) { background[0]->bind(sDiffuse); // orignal image @@ -1018,6 +1044,7 @@ struct Inventory { game->setShader(Core::passFilter, Shader::FILTER_MIXER, false, false); Core::active.shader->setParam(uParam, vec4(phaseRing, 1.0f - phaseRing * 0.4f, 0, 0));; background[1]->bind(sNormal); // blured grayscale image + Core::setBlending(bmNone); } else { game->setShader(Core::passFilter, Shader::DEFAULT, false, false); @@ -1026,17 +1053,23 @@ struct Inventory { float aspectImg = aspectDst / aspectSrc; float ax = background[0]->origWidth / float(background[0]->width); float ay = background[0]->origHeight / float(background[0]->height); - Core::active.shader->setParam(uParam, vec4(ax * aspectImg, -ay, (0.5f - aspectImg * 0.5f) * ax, ay)); + + if (!isActive() && titleTimer > 0.0f && titleTimer < 1.0f) { + Core::setBlending(bmAlpha); + Core::active.shader->setParam(uMaterial, vec4(1, 1, 1, titleTimer)); + } else { + Core::setBlending(bmNone); + Core::active.shader->setParam(uMaterial, vec4(1)); + } } - Core::setBlending(bmNone); game->getMesh()->renderQuad(); } Core::setDepthTest(true); Core::setBlending(bmAlpha); - if (game->getLevel()->isCutsceneLevel()) + if (game->getLevel()->isCutsceneLevel() || !isActive()) return; // items diff --git a/src/level.h b/src/level.h index 07ba7ed..ca80be7 100644 --- a/src/level.h +++ b/src/level.h @@ -609,7 +609,12 @@ struct Level : IGame { sndSoundtrack = NULL; playTrack(0); sndCurrent = sndSoundtrack; - + /* + if (level.id == TR::LVL_TR2_RIG) { + lara->animation.setAnim(level.models[level.extra.laraSpec].animation); + camera->doCutscene(lara->pos, lara->angle.y); + } + */ Core::resetTime(); } @@ -1254,9 +1259,15 @@ struct Level : IGame { Sound::Sample *sndChanged = sndCurrent; + inventory.update(); + + if (inventory.titleTimer > 1.0f) + return; + + UI::update(); + if (inventory.isActive() || level.isTitle()) { Sound::reverb.setRoomSize(vec3(1.0f)); - inventory.update(); if (!level.isTitle()) sndChanged = NULL; } else { @@ -1855,8 +1866,8 @@ struct Level : IGame { // lara->visibleMask = 0xFFFFFFFF; // catsuit test } - void renderInventory() { - Core::setTarget(NULL, true); + void renderInventory(bool clear) { + Core::setTarget(NULL, clear); if (Core::settings.detail.stereo) { Core::setViewport(0, 0, Core::width / 2, Core::height); Core::eye = -1.0f; @@ -1871,7 +1882,7 @@ struct Level : IGame { } void renderUI() { - if (level.isCutsceneLevel()) return; + if (level.isCutsceneLevel() || inventory.titleTimer > 1.0f) return; UI::begin(); @@ -1938,8 +1949,7 @@ struct Level : IGame { if (!title) renderGame(); - if (title) - renderInventory(); + renderInventory(title); if (Core::settings.detail.stereo) { Core::setViewport(0, 0, Core::width / 2, Core::height); diff --git a/src/platform/web/build.bat b/src/platform/web/build.bat index 774a247..c4b03c7 100644 --- a/src/platform/web/build.bat +++ b/src/platform/web/build.bat @@ -1,8 +1,8 @@ @echo off cls -set SRC=main.cpp ../../libs/stb_vorbis/stb_vorbis.c +set SRC=main.cpp ../../libs/stb_vorbis/stb_vorbis.c ../../libs/tinf/tinflate.c set PROJ=OpenLara set FLAGS=-O3 -Wno-deprecated-register --llvm-opts 2 -fmax-type-align=2 -std=c++11 -s ALLOW_MEMORY_GROWTH=1 -Wall -I../../ echo. -call em++ %SRC% %FLAGS% -o %PROJ%.js --preload-file ./level/1/TITLE.PSX --preload-file ./level/1/TITLEH.PCX --preload-file ./audio/1/dummy --preload-file ./audio/2/dummy --preload-file ./audio/3/dummy --preload-file ./level/2/dummy --preload-file ./level/3/dummy +call em++ %SRC% %FLAGS% -o %PROJ%.js --preload-file ./level/1/TITLE.PSX --preload-file ./level/1/AMERTIT.PNG --preload-file ./audio/1/dummy --preload-file ./audio/2/dummy --preload-file ./audio/3/dummy --preload-file ./level/2/dummy --preload-file ./level/3/dummy gzip.exe -9 -f %PROJ%.data %PROJ%.js %PROJ%.js.mem \ No newline at end of file diff --git a/src/shaders/filter.glsl b/src/shaders/filter.glsl index a17cfdf..98fa9aa 100644 --- a/src/shaders/filter.glsl +++ b/src/shaders/filter.glsl @@ -5,7 +5,7 @@ R"====( #endif varying vec2 vTexCoord; - +uniform vec4 uMaterial; uniform vec4 uParam; #ifdef VERTEX @@ -95,7 +95,7 @@ uniform vec4 uParam; return equirectangular(); #endif - return texture2D(sDiffuse, vTexCoord); + return texture2D(sDiffuse, vTexCoord) * uMaterial; } void main() { diff --git a/src/texture.h b/src/texture.h index a065fb0..e43ac21 100644 --- a/src/texture.h +++ b/src/texture.h @@ -173,7 +173,40 @@ struct Texture { struct Color32 { uint8 r, g, b, a; }; +/* + static void SaveBMP(const char *name, const char *data32, int width, int height) { + BITMAPINFOHEADER BMIH; + BMIH.biSize = sizeof(BITMAPINFOHEADER); + BMIH.biSizeImage = width * height * 4; + BMIH.biSize = sizeof(BITMAPINFOHEADER); + BMIH.biWidth = width; + BMIH.biHeight = height; + BMIH.biPlanes = 1; + BMIH.biBitCount = 32; + BMIH.biCompression = BI_RGB; + BMIH.biSizeImage = width * height * 4; + + BITMAPFILEHEADER bmfh; + int nBitsOffset = sizeof(BITMAPFILEHEADER) + BMIH.biSize; + LONG lImageSize = BMIH.biSizeImage; + LONG lFileSize = nBitsOffset + lImageSize; + bmfh.bfType = 'B' + ('M' << 8); + bmfh.bfOffBits = nBitsOffset; + bmfh.bfSize = lFileSize; + bmfh.bfReserved1 = bmfh.bfReserved2 = 0; + + char buf[256]; + strcpy(buf, name); + strcat(buf, ".bmp"); + + FILE *f = fopen(buf, "wb"); + fwrite(&bmfh, sizeof(bmfh), 1, f); + fwrite(&BMIH, sizeof(BMIH), 1, f); + fwrite(data32, width * height * 4, 1, f); + fclose(f); + } +*/ static Texture* LoadPCX(Stream &stream) { struct PCX { uint8 magic; @@ -329,7 +362,6 @@ struct Texture { }; } - static Texture* LoadPNG(Stream &stream) { stream.seek(8); @@ -614,8 +646,8 @@ struct Texture { } static Texture* LoadBIN(Stream &stream) { - int width = 352; int height = 224; + int width = stream.size / height / 2; int dw = Core::support.texNPOT ? width : nextPow2(width); int dh = Core::support.texNPOT ? height : nextPow2(height); @@ -836,30 +868,8 @@ struct Atlas { void fillInstances() { for (int i = 0; i < tilesCount; i++) - if (tiles[i].uv.x == 0x7FFF) { + if (tiles[i].uv.x == 0x7FFF) callback(tiles[i].id, width, height, tiles[i].uv.y, 0, userData, NULL); - /* - TR::ObjectTexture &r = level.objectTextures[ref]; - int minXr = min(min(r.texCoord[0].x, r.texCoord[1].x), r.texCoord[2].x); - int minYr = min(min(r.texCoord[0].y, r.texCoord[1].y), r.texCoord[2].y); - - TR::ObjectTexture &t = level.objectTextures[tiles[i].id]; - int minX = min(min(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x); - int maxX = max(max(t.texCoord[0].x, t.texCoord[1].x), t.texCoord[2].x); - int minY = min(min(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y); - int maxY = max(max(t.texCoord[0].y, t.texCoord[1].y), t.texCoord[2].y); - - int cx = minXr - minX; - int cy = minYr - minY; - - for (int i = 0; i < 4; i++) { - if (t.texCoord[i].x == maxX) t.texCoord[i].x++; - if (t.texCoord[i].y == maxY) t.texCoord[i].y++; - t.texCoord[i].x += cx; - t.texCoord[i].y += cy; - } - */ - } } };