mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-20 03:41:33 +02:00
136
src/cache.h
136
src/cache.h
@@ -40,55 +40,20 @@ struct ShaderCache {
|
||||
memset(shaders, 0, sizeof(shaders));
|
||||
|
||||
LOG("shader: cache warm up...\n");
|
||||
if (Core::settings.detail.shadows)
|
||||
compile(Core::passShadow, Shader::ENTITY, FX_NONE);
|
||||
prepareCompose(FX_NONE);
|
||||
if (Core::settings.detail.water > Core::Settings::LOW)
|
||||
prepareCompose(FX_CLIP_PLANE);
|
||||
|
||||
if (Core::settings.detail.ambient) {
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_NONE);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_UNDERWATER);
|
||||
compile(Core::passAmbient, Shader::SPRITE, FX_ALPHA_TEST);
|
||||
if (Core::settings.detail.water) {
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_CLIP_PLANE);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passAmbient, Shader::ROOM, FX_UNDERWATER | FX_CLIP_PLANE);
|
||||
compile(Core::passAmbient, Shader::SPRITE, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
}
|
||||
}
|
||||
prepareAmbient(FX_NONE);
|
||||
|
||||
if (Core::settings.detail.water) {
|
||||
compile(Core::passWater, Shader::WATER_MASK, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_STEP, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_CAUSTICS, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_COMPOSE, FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_DROP, FX_NONE);
|
||||
}
|
||||
if (Core::settings.detail.shadows > Core::Settings::LOW)
|
||||
prepareShadows(FX_NONE);
|
||||
|
||||
compile(Core::passFilter, Shader::FILTER_DOWNSAMPLE, FX_NONE);
|
||||
compile(Core::passFilter, Shader::FILTER_GRAYSCALE, FX_NONE);
|
||||
compile(Core::passFilter, Shader::FILTER_BLUR, FX_NONE);
|
||||
compile(Core::passFilter, Shader::FILTER_MIXER, FX_NONE);
|
||||
if (Core::settings.detail.water > Core::Settings::LOW)
|
||||
prepareWater(FX_NONE);
|
||||
|
||||
compile(Core::passCompose, Shader::ROOM, FX_NONE);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_UNDERWATER);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_NONE);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_UNDERWATER);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_UNDERWATER | FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::FLASH, FX_ALPHA_TEST);
|
||||
if (Core::settings.detail.water) {
|
||||
compile(Core::passCompose, Shader::ROOM, FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ROOM, FX_UNDERWATER | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::ENTITY, FX_UNDERWATER | FX_CLIP_PLANE);
|
||||
compile(Core::passCompose, Shader::SPRITE, FX_UNDERWATER | FX_ALPHA_TEST | FX_CLIP_PLANE);
|
||||
}
|
||||
compile(Core::passCompose, Shader::MIRROR, FX_NONE);
|
||||
prepareFilter(FX_NONE);
|
||||
prepareGUI(FX_NONE);
|
||||
|
||||
LOG("shader: cache is ready\n");
|
||||
}
|
||||
@@ -100,6 +65,54 @@ struct ShaderCache {
|
||||
delete shaders[pass][type][fx];
|
||||
}
|
||||
|
||||
void prepareCompose(int fx) {
|
||||
compile(Core::passCompose, Shader::MIRROR, fx | FX_NONE);
|
||||
compile(Core::passCompose, Shader::ROOM, fx | FX_NONE);
|
||||
compile(Core::passCompose, Shader::ROOM, fx | FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::ROOM, fx | FX_UNDERWATER);
|
||||
compile(Core::passCompose, Shader::ROOM, fx | FX_UNDERWATER | FX_ALPHA_TEST);
|
||||
|
||||
compile(Core::passCompose, Shader::ENTITY, fx | FX_NONE);
|
||||
compile(Core::passCompose, Shader::ENTITY, fx | FX_UNDERWATER);
|
||||
compile(Core::passCompose, Shader::ENTITY, fx | FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::SPRITE, fx | FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::SPRITE, fx | FX_UNDERWATER | FX_ALPHA_TEST);
|
||||
compile(Core::passCompose, Shader::FLASH, fx | FX_NONE);
|
||||
compile(Core::passCompose, Shader::FLASH, fx | FX_ALPHA_TEST);
|
||||
}
|
||||
|
||||
void prepareAmbient(int fx) {
|
||||
compile(Core::passAmbient, Shader::ROOM, fx | FX_NONE);
|
||||
compile(Core::passAmbient, Shader::ROOM, fx | FX_ALPHA_TEST);
|
||||
compile(Core::passAmbient, Shader::ROOM, fx | FX_UNDERWATER);
|
||||
compile(Core::passAmbient, Shader::ROOM, fx | FX_UNDERWATER | FX_ALPHA_TEST);
|
||||
compile(Core::passAmbient, Shader::SPRITE, fx | FX_ALPHA_TEST);
|
||||
}
|
||||
|
||||
void prepareShadows(int fx) {
|
||||
compile(Core::passShadow, Shader::ENTITY, fx | FX_NONE);
|
||||
}
|
||||
|
||||
void prepareWater(int fx) {
|
||||
compile(Core::passWater, Shader::WATER_MASK, fx | FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_STEP, fx | FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_CAUSTICS, fx | FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_COMPOSE, fx | FX_NONE);
|
||||
compile(Core::passWater, Shader::WATER_DROP, fx | FX_NONE);
|
||||
}
|
||||
|
||||
void prepareFilter(int fx) {
|
||||
compile(Core::passFilter, Shader::DEFAULT, fx | FX_NONE);
|
||||
compile(Core::passFilter, Shader::FILTER_DOWNSAMPLE, fx | FX_NONE);
|
||||
compile(Core::passFilter, Shader::FILTER_GRAYSCALE, fx | FX_NONE);
|
||||
compile(Core::passFilter, Shader::FILTER_BLUR, fx | FX_NONE);
|
||||
compile(Core::passFilter, Shader::FILTER_MIXER, fx | FX_NONE);
|
||||
}
|
||||
|
||||
void prepareGUI(int fx) {
|
||||
compile(Core::passGUI, Shader::DEFAULT, fx | FX_NONE);
|
||||
}
|
||||
|
||||
Shader* compile(Core::Pass pass, Shader::Type type, int fx) {
|
||||
char def[1024], ext[255];
|
||||
ext[0] = 0;
|
||||
@@ -131,12 +144,22 @@ struct ShaderCache {
|
||||
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define MAX_CONTACTS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_ANIM_TEX_RANGES, MAX_ANIM_TEX_OFFSETS, MAX_CONTACTS, FOG_DIST, WATER_FOG_DIST, SHADOW_TEX_SIZE);
|
||||
if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR);
|
||||
if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\n");
|
||||
if (fx & FX_CLIP_PLANE) strcat(def, "#define CLIP_PLANE\n");
|
||||
if (Core::settings.detail.ambient) strcat(def, "#define OPT_AMBIENT\n");
|
||||
if (Core::settings.detail.lighting) strcat(def, "#define OPT_LIGHTING\n");
|
||||
if (Core::settings.detail.shadows) strcat(def, "#define OPT_SHADOW\n");
|
||||
if (Core::settings.detail.water) strcat(def, "#define OPT_WATER\n");
|
||||
if (Core::settings.detail.contact) strcat(def, "#define OPT_CONTACT\n");
|
||||
if (pass == Core::passCompose) {
|
||||
if (fx & FX_CLIP_PLANE)
|
||||
strcat(def, "#define CLIP_PLANE\n");
|
||||
if (type == Shader::ROOM)
|
||||
strcat(def, "#define OPT_ANIMTEX\n");
|
||||
if (Core::settings.detail.lighting > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM))
|
||||
strcat(def, "#define OPT_LIGHTING\n");
|
||||
if (Core::settings.detail.lighting > Core::Settings::MEDIUM && (type == Shader::ENTITY))
|
||||
strcat(def, "#define OPT_AMBIENT\n");
|
||||
if (Core::settings.detail.shadows > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM))
|
||||
strcat(def, "#define OPT_SHADOW\n");
|
||||
if (Core::settings.detail.shadows > Core::Settings::MEDIUM && (type == Shader::ROOM))
|
||||
strcat(def, "#define OPT_CONTACT\n");
|
||||
if (Core::settings.detail.water > Core::Settings::MEDIUM && (type == Shader::ENTITY || type == Shader::ROOM) && (fx & FX_UNDERWATER))
|
||||
strcat(def, "#define OPT_CAUSTICS\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Core::passWater : {
|
||||
@@ -410,7 +433,7 @@ struct WaterCache {
|
||||
|
||||
data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF);
|
||||
data[1] = new Texture(w * 64, h * 64, Texture::RGBA_HALF);
|
||||
caustics = new Texture(512, 512, Texture::RGB16);
|
||||
caustics = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, Texture::RGBA) : NULL;
|
||||
mask = new Texture(w, h, Texture::RGB16, false, m, false);
|
||||
delete[] m;
|
||||
|
||||
@@ -520,16 +543,11 @@ struct WaterCache {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!item || !item->caustics) {
|
||||
Core::blackTex->bind(sReflect);
|
||||
Core::active.shader->setParam(uRoomSize, vec4(0.0f));
|
||||
game->setWaterParams(-NO_CLIP_PLANE);
|
||||
} else {
|
||||
if (item && item->caustics) {
|
||||
item->caustics->bind(sReflect);
|
||||
Core::active.shader->setParam(uRoomSize, vec4(item->pos.x - item->size.x, item->pos.z - item->size.z, item->pos.x + item->size.x, item->pos.z + item->size.z));
|
||||
game->setWaterParams(item->pos.y);
|
||||
}
|
||||
game->updateParams();
|
||||
}
|
||||
|
||||
void addDrop(const vec3 &pos, float radius, float strength) {
|
||||
@@ -702,12 +720,10 @@ struct WaterCache {
|
||||
|
||||
float sign = underwater ? -1.0f : 1.0f;
|
||||
game->setClipParams(sign, item.pos.y * sign);
|
||||
game->updateParams();
|
||||
game->renderView(underwater ? item.from : item.to, false);
|
||||
}
|
||||
Core::invalidateTarget(false, true);
|
||||
game->setClipParams(1.0f, NO_CLIP_PLANE);
|
||||
game->updateParams();
|
||||
|
||||
camera->reflectPlane = NULL;
|
||||
camera->setup(true);
|
||||
|
@@ -29,6 +29,10 @@ struct ICamera {
|
||||
struct IGame {
|
||||
virtual ~IGame() {}
|
||||
virtual void loadLevel(TR::LevelID id) {}
|
||||
virtual void loadGame(int slot) {}
|
||||
virtual void saveGame(int slot) {}
|
||||
virtual void applySettings(const Core::Settings &settings) {}
|
||||
|
||||
virtual TR::Level* getLevel() { return NULL; }
|
||||
virtual MeshBuilder* getMesh() { return NULL; }
|
||||
virtual ICamera* getCamera() { return NULL; }
|
||||
@@ -38,7 +42,6 @@ struct IGame {
|
||||
virtual uint16 findPath(int ascend, int descend, bool big, int boxStart, int boxEnd, uint16 *zones, uint16 **boxes) { return 0; }
|
||||
virtual void setClipParams(float clipSign, float clipHeight) {}
|
||||
virtual void setWaterParams(float height) {}
|
||||
virtual void updateParams() {}
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
|
||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {}
|
||||
virtual void setupBinding() {}
|
||||
|
156
src/core.h
156
src/core.h
@@ -137,34 +137,108 @@
|
||||
#define glProgramBinary(...)
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
enum ControlKey { cLeft, cRight, cUp, cDown, cJump, cWalk, cAction, cWeapon, cLook, cStepLeft, cStepRight, cRoll, cInventory, cMAX };
|
||||
|
||||
enum InputKey { ikNone,
|
||||
// keyboard
|
||||
ikLeft, ikRight, ikUp, ikDown, ikSpace, ikTab, ikEnter, ikEscape, ikShift, ikCtrl, ikAlt,
|
||||
ik0, ik1, ik2, ik3, ik4, ik5, ik6, ik7, ik8, ik9,
|
||||
ikA, ikB, ikC, ikD, ikE, ikF, ikG, ikH, ikI, ikJ, ikK, ikL, ikM,
|
||||
ikN, ikO, ikP, ikQ, ikR, ikS, ikT, ikU, ikV, ikW, ikX, ikY, ikZ,
|
||||
// mouse
|
||||
ikMouseL, ikMouseR, ikMouseM,
|
||||
// touch
|
||||
ikTouchA, ikTouchB, ikTouchC, ikTouchD, ikTouchE, ikTouchF,
|
||||
// gamepad
|
||||
ikJoyA, ikJoyB, ikJoyX, ikJoyY, ikJoyLB, ikJoyRB, ikJoySelect, ikJoyStart, ikJoyL, ikJoyR, ikJoyLT, ikJoyRT, ikJoyPOV,
|
||||
ikJoyLeft, ikJoyRight, ikJoyUp, ikJoyDown,
|
||||
ikMAX };
|
||||
|
||||
struct KeySet {
|
||||
InputKey key, joy;
|
||||
};
|
||||
|
||||
namespace Core {
|
||||
float deltaTime;
|
||||
int width, height;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
bool ambient;
|
||||
bool lighting;
|
||||
bool shadows;
|
||||
bool water;
|
||||
bool contact;
|
||||
int maxVectors;
|
||||
int maxAniso;
|
||||
bool shaderBinary;
|
||||
bool VAO;
|
||||
bool depthTexture;
|
||||
bool shadowSampler;
|
||||
bool discardFrame;
|
||||
bool texNPOT;
|
||||
bool texRG;
|
||||
bool texBorder;
|
||||
bool colorFloat, texFloat, texFloatLinear;
|
||||
bool colorHalf, texHalf, texHalfLinear;
|
||||
#ifdef PROFILE
|
||||
bool profMarker;
|
||||
bool profTiming;
|
||||
#endif
|
||||
} support;
|
||||
|
||||
struct Settings {
|
||||
enum Quality : uint8 { LOW, MEDIUM, HIGH };
|
||||
|
||||
union {
|
||||
struct {
|
||||
Quality filter;
|
||||
Quality lighting;
|
||||
Quality shadows;
|
||||
Quality water;
|
||||
};
|
||||
Quality quality[4];
|
||||
|
||||
void setFilter(Quality value) {
|
||||
if (value > MEDIUM && !(support.maxAniso > 1))
|
||||
value = MEDIUM;
|
||||
filter = value;
|
||||
}
|
||||
|
||||
void setLighting(Quality value) {
|
||||
lighting = value;
|
||||
}
|
||||
|
||||
void setShadows(Quality value) {
|
||||
if (value > MEDIUM && !(support.maxVectors > 8))
|
||||
value = MEDIUM;
|
||||
shadows = value;
|
||||
}
|
||||
|
||||
void setWater(Quality value) {
|
||||
if (value > LOW && !(support.texFloat || support.texHalf))
|
||||
value = LOW;
|
||||
else
|
||||
if (value > MEDIUM && !(support.maxVectors > 8))
|
||||
value = MEDIUM;
|
||||
water = value;
|
||||
}
|
||||
} detail;
|
||||
|
||||
struct {
|
||||
KeySet keys[cMAX];
|
||||
bool retarget;
|
||||
bool multitarget;
|
||||
bool vibration;
|
||||
} controls;
|
||||
|
||||
struct {
|
||||
float music;
|
||||
float sound;
|
||||
bool reverb;
|
||||
} audio;
|
||||
} settings;
|
||||
}
|
||||
|
||||
#include "utils.h"
|
||||
#include "input.h"
|
||||
#include "sound.h"
|
||||
|
||||
|
||||
#if defined(WIN32) || (defined(LINUX) && !defined(__RPI__)) || defined(ANDROID)
|
||||
|
||||
#ifdef ANDROID
|
||||
@@ -293,26 +367,6 @@ struct Vertex {
|
||||
ubyte4 color; // xyz - color, w - intensity
|
||||
};
|
||||
|
||||
namespace Core {
|
||||
struct {
|
||||
bool shaderBinary;
|
||||
bool VAO;
|
||||
bool depthTexture;
|
||||
bool shadowSampler;
|
||||
bool discardFrame;
|
||||
bool texNPOT;
|
||||
bool texRG;
|
||||
bool texBorder;
|
||||
int8 texAniso;
|
||||
bool colorFloat, texFloat, texFloatLinear;
|
||||
bool colorHalf, texHalf, texHalfLinear;
|
||||
#ifdef PROFILE
|
||||
bool profMarker;
|
||||
bool profTiming;
|
||||
#endif
|
||||
} support;
|
||||
}
|
||||
|
||||
#ifdef PROFILE
|
||||
#define USE_CV_MARKERS
|
||||
|
||||
@@ -563,6 +617,8 @@ namespace Core {
|
||||
}
|
||||
}
|
||||
*/
|
||||
glGetIntegerv(GL_MAX_VARYING_VECTORS, &support.maxVectors);
|
||||
|
||||
support.shaderBinary = extSupport(ext, "_program_binary");
|
||||
support.VAO = extSupport(ext, "_vertex_array_object");
|
||||
support.depthTexture = extSupport(ext, "_depth_texture");
|
||||
@@ -571,7 +627,7 @@ namespace Core {
|
||||
support.texNPOT = extSupport(ext, "_texture_npot") || extSupport(ext, "_texture_non_power_of_two");
|
||||
support.texRG = extSupport(ext, "_texture_rg "); // hope that isn't last extension in string ;)
|
||||
support.texBorder = extSupport(ext, "_texture_border_clamp");
|
||||
support.texAniso = extSupport(ext, "_texture_filter_anisotropic");
|
||||
support.maxAniso = extSupport(ext, "_texture_filter_anisotropic");
|
||||
support.colorFloat = extSupport(ext, "_color_buffer_float");
|
||||
support.colorHalf = extSupport(ext, "_color_buffer_half_float") || extSupport(ext, "GL_ARB_half_float_pixel");
|
||||
support.texFloatLinear = support.colorFloat || extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_float_linear");
|
||||
@@ -579,11 +635,8 @@ namespace Core {
|
||||
support.texHalfLinear = support.colorHalf || extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_half_float_linear") || extSupport(ext, "_color_buffer_half_float");
|
||||
support.texHalf = support.texHalfLinear || extSupport(ext, "_texture_half_float");
|
||||
|
||||
if (support.texAniso) {
|
||||
int maxAniso;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso);
|
||||
support.texAniso = maxAniso;
|
||||
}
|
||||
if (support.maxAniso)
|
||||
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &support.maxAniso);
|
||||
|
||||
#ifdef PROFILE
|
||||
support.profMarker = extSupport(ext, "_KHR_debug");
|
||||
@@ -595,6 +648,7 @@ namespace Core {
|
||||
LOG("Version : %s\n", glGetString(GL_VERSION));
|
||||
LOG("cache : %s\n", Stream::cacheDir);
|
||||
LOG("supports :\n");
|
||||
LOG(" variyngs count : %d\n", support.maxVectors);
|
||||
LOG(" binary shaders : %s\n", support.shaderBinary ? "true" : "false");
|
||||
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
||||
LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false");
|
||||
@@ -603,7 +657,7 @@ namespace Core {
|
||||
LOG(" NPOT textures : %s\n", support.texNPOT ? "true" : "false");
|
||||
LOG(" RG textures : %s\n", support.texRG ? "true" : "false");
|
||||
LOG(" border color : %s\n", support.texBorder ? "true" : "false");
|
||||
LOG(" anisotropic : %d\n", support.texAniso);
|
||||
LOG(" anisotropic : %d\n", support.maxAniso);
|
||||
LOG(" float textures : float = %s, half = %s\n",
|
||||
support.colorFloat ? "full" : (support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false"),
|
||||
support.colorHalf ? "full" : (support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false"));
|
||||
@@ -627,6 +681,38 @@ namespace Core {
|
||||
blackTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
|
||||
data = 0xFFFFFFFF;
|
||||
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
|
||||
|
||||
// init settings
|
||||
settings.detail.setFilter (Core::Settings::HIGH);
|
||||
settings.detail.setLighting (Core::Settings::HIGH);
|
||||
settings.detail.setShadows (Core::Settings::MEDIUM);
|
||||
settings.detail.setWater (Core::Settings::HIGH);
|
||||
|
||||
settings.audio.music = 0.7f;
|
||||
settings.audio.sound = 0.7f;
|
||||
settings.audio.reverb = true;
|
||||
|
||||
settings.controls.retarget = true;
|
||||
settings.controls.multitarget = true;
|
||||
settings.controls.vibration = true;
|
||||
|
||||
settings.controls.keys[ cLeft ] = { ikLeft, ikJoyLeft };
|
||||
settings.controls.keys[ cRight ] = { ikRight, ikJoyRight };
|
||||
settings.controls.keys[ cUp ] = { ikUp, ikJoyUp };
|
||||
settings.controls.keys[ cDown ] = { ikDown, ikJoyDown };
|
||||
settings.controls.keys[ cJump ] = { ikD, ikJoyX };
|
||||
settings.controls.keys[ cWalk ] = { ikShift, ikJoyRB };
|
||||
settings.controls.keys[ cAction ] = { ikCtrl, ikJoyA };
|
||||
settings.controls.keys[ cWeapon ] = { ikSpace, ikJoyY };
|
||||
settings.controls.keys[ cLook ] = { ikC, ikJoyLB };
|
||||
settings.controls.keys[ cStepLeft ] = { ikZ, ikJoyLT };
|
||||
settings.controls.keys[ cStepRight ] = { ikX, ikJoyRT };
|
||||
settings.controls.keys[ cRoll ] = { ikA, ikJoyB };
|
||||
settings.controls.keys[ cInventory ] = { ikTab, ikJoySelect };
|
||||
|
||||
#ifdef __RPI__
|
||||
settings.detail.setShadows(Core::Settings::LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
void free() {
|
||||
|
@@ -487,6 +487,8 @@ struct Wolf : Enemy {
|
||||
jointChest = 2;
|
||||
jointHead = 3;
|
||||
nextState = STATE_NONE;
|
||||
animation.time = animation.timeMax;
|
||||
updateAnimation(false);
|
||||
}
|
||||
|
||||
virtual int getStateGround() {
|
||||
|
22
src/game.h
22
src/game.h
@@ -39,18 +39,6 @@ namespace Game {
|
||||
|
||||
Core::init();
|
||||
|
||||
Core::settings.detail.ambient = true;
|
||||
Core::settings.detail.lighting = true;
|
||||
Core::settings.detail.shadows = true;
|
||||
Core::settings.detail.water = Core::support.texFloat || Core::support.texHalf;
|
||||
Core::settings.detail.contact = false;
|
||||
#ifdef __RPI__
|
||||
Core::settings.detail.ambient = false;
|
||||
Core::settings.detail.shadows = false;
|
||||
#endif
|
||||
Core::settings.controls.retarget = true;
|
||||
Core::settings.audio.reverb = true;
|
||||
|
||||
shaderCache = new ShaderCache();
|
||||
|
||||
UI::init(level);
|
||||
@@ -100,12 +88,14 @@ namespace Game {
|
||||
|
||||
Input::update();
|
||||
|
||||
if (Input::down[ikV]) { // third <-> first person view
|
||||
level->camera->changeView(!level->camera->firstPerson);
|
||||
Input::down[ikV] = false;
|
||||
if (level->camera) {
|
||||
if (Input::down[ikV]) { // third <-> first person view
|
||||
level->camera->changeView(!level->camera->firstPerson);
|
||||
Input::down[ikV] = false;
|
||||
}
|
||||
}
|
||||
|
||||
Core::deltaTime = delta = min(1.0f, delta);
|
||||
Core::deltaTime = delta = min(0.2f, delta);
|
||||
UI::update();
|
||||
|
||||
while (delta > EPS) {
|
||||
|
64
src/input.h
64
src/input.h
@@ -1,68 +1,13 @@
|
||||
#ifndef H_INPUT
|
||||
#define H_INPUT
|
||||
|
||||
#include "core.h"
|
||||
#include "utils.h"
|
||||
|
||||
enum InputKey { ikNone,
|
||||
// keyboard
|
||||
ikLeft, ikRight, ikUp, ikDown, ikSpace, ikTab, ikEnter, ikEscape, ikShift, ikCtrl, ikAlt,
|
||||
ik0, ik1, ik2, ik3, ik4, ik5, ik6, ik7, ik8, ik9,
|
||||
ikA, ikB, ikC, ikD, ikE, ikF, ikG, ikH, ikI, ikJ, ikK, ikL, ikM,
|
||||
ikN, ikO, ikP, ikQ, ikR, ikS, ikT, ikU, ikV, ikW, ikX, ikY, ikZ,
|
||||
// mouse
|
||||
ikMouseL, ikMouseR, ikMouseM,
|
||||
// touch
|
||||
ikTouchA, ikTouchB, ikTouchC, ikTouchD, ikTouchE, ikTouchF,
|
||||
// gamepad
|
||||
ikJoyA, ikJoyB, ikJoyX, ikJoyY, ikJoyLB, ikJoyRB, ikJoySelect, ikJoyStart, ikJoyL, ikJoyR, ikJoyLT, ikJoyRT, ikJoyPOV,
|
||||
ikJoyLeft, ikJoyRight, ikJoyUp, ikJoyDown,
|
||||
ikMAX };
|
||||
|
||||
enum ControlKey { cLeft, cRight, cUp, cDown, cJump, cWalk, cAction, cWeapon, cLook, cStepLeft, cStepRight, cRoll, cInventory, cMAX };
|
||||
|
||||
namespace Input {
|
||||
|
||||
bool down[ikMAX];
|
||||
|
||||
struct KeySet {
|
||||
InputKey key, joy;
|
||||
};
|
||||
|
||||
static const KeySet presets[1][cMAX] = {
|
||||
{ { ikLeft, ikJoyLeft },
|
||||
{ ikRight, ikJoyRight },
|
||||
{ ikUp, ikJoyUp },
|
||||
{ ikDown, ikJoyDown },
|
||||
{ ikD, ikJoyX },
|
||||
{ ikShift, ikJoyRB },
|
||||
{ ikCtrl, ikJoyA },
|
||||
{ ikSpace, ikJoyY },
|
||||
{ ikC, ikJoyLB },
|
||||
{ ikZ, ikJoyLT },
|
||||
{ ikX, ikJoyRT },
|
||||
{ ikA, ikJoyB },
|
||||
{ ikTab, ikJoySelect },
|
||||
},
|
||||
/*
|
||||
{ { ikA, ikJoyLeft },
|
||||
{ ikD, ikJoyRight },
|
||||
{ ikW, ikJoyUp },
|
||||
{ ikS, ikJoyDown },
|
||||
{ ikSpace, ikJoyX },
|
||||
{ ikShift, ikJoyRB },
|
||||
{ ikP, ikJoyA },
|
||||
{ ikMouseM, ikJoyY },
|
||||
{ ikMouseR, ikJoyLB },
|
||||
{ ikLeft, ikJoyLT },
|
||||
{ ikRight, ikJoyRT },
|
||||
{ ikUp, ikJoyB },
|
||||
{ ikTab, ikJoySelect },
|
||||
},
|
||||
*/
|
||||
};
|
||||
|
||||
KeySet controls[cMAX];
|
||||
bool state[cMAX];
|
||||
bool state[cMAX];
|
||||
|
||||
struct {
|
||||
vec2 pos;
|
||||
@@ -186,9 +131,6 @@ namespace Input {
|
||||
|
||||
void init() {
|
||||
reset();
|
||||
for (int i = 0; i < cMAX; i++)
|
||||
controls[i] = presets[0][i];
|
||||
|
||||
touchTimerVis = 0.0f;
|
||||
touchTimerTap = 0.0f;
|
||||
doubleTap = false;
|
||||
@@ -226,7 +168,7 @@ namespace Input {
|
||||
setDown(ikJoyLeft, p == 6 || p == 7 || p == 8);
|
||||
|
||||
for (int i = 0; i < cMAX; i++) {
|
||||
KeySet &c = controls[i];
|
||||
KeySet &c = Core::settings.controls.keys[i];
|
||||
state[i] = (c.key != ikNone && down[c.key]) || (c.joy != ikNone && down[c.joy]);
|
||||
}
|
||||
|
||||
|
361
src/inventory.h
361
src/inventory.h
@@ -29,7 +29,9 @@ struct Inventory {
|
||||
Page page, targetPage;
|
||||
int itemsCount;
|
||||
|
||||
float changeTimer;
|
||||
TR::LevelID nextLevel; // toggle result
|
||||
ControlKey lastKey;
|
||||
|
||||
struct Item {
|
||||
TR::Entity::Type type;
|
||||
@@ -156,7 +158,7 @@ struct Inventory {
|
||||
delete stream;
|
||||
}
|
||||
|
||||
Inventory(IGame *game) : game(game), active(false), chosen(false), index(0), targetIndex(0), page(PAGE_OPTION), targetPage(PAGE_OPTION), itemsCount(0), nextLevel(TR::LEVEL_MAX) {
|
||||
Inventory(IGame *game) : game(game), active(false), chosen(false), index(0), targetIndex(0), page(PAGE_OPTION), targetPage(PAGE_OPTION), itemsCount(0), changeTimer(0.0f), nextLevel(TR::LEVEL_MAX), lastKey(cMAX) {
|
||||
TR::LevelID id = game->getLevel()->id;
|
||||
|
||||
add(TR::Entity::INV_PASSPORT);
|
||||
@@ -331,7 +333,7 @@ struct Inventory {
|
||||
nextLevel = TR::LEVEL_MAX;
|
||||
phasePage = 1.0f;
|
||||
phaseSelect = 1.0f;
|
||||
page = targetPage = curPage;
|
||||
page = targetPage = curPage;
|
||||
|
||||
if (type != TR::Entity::NONE) {
|
||||
int i = contains(type);
|
||||
@@ -403,13 +405,110 @@ struct Inventory {
|
||||
}
|
||||
|
||||
void onChoose(Item *item) {
|
||||
if (item->type == TR::Entity::INV_PASSPORT) {
|
||||
game->playSound(TR::SND_INV_PAGE, vec3(), 0, 0);
|
||||
item->value = 1;
|
||||
passportSlot = 0;
|
||||
passportSlotCount = 2;
|
||||
passportSlots[0] = TR::LEVEL_1;
|
||||
passportSlots[1] = TR::LEVEL_2;
|
||||
slot = 0;
|
||||
|
||||
switch (item->type) {
|
||||
case TR::Entity::INV_PASSPORT : {
|
||||
game->playSound(TR::SND_INV_PAGE, vec3(), 0, 0);
|
||||
item->value = 1;
|
||||
passportSlotCount = 2;
|
||||
passportSlots[0] = TR::LEVEL_1;
|
||||
passportSlots[1] = TR::LEVEL_2;
|
||||
break;
|
||||
}
|
||||
case TR::Entity::INV_DETAIL : {
|
||||
settings = Core::settings;
|
||||
break;
|
||||
}
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
|
||||
void controlItem(Item *item, ControlKey key) {
|
||||
if (item->type == TR::Entity::INV_PASSPORT && passportSlotCount) {
|
||||
// passport slots
|
||||
if (item->value == 0 && item->anim->dir == 0.0f) { // slot select
|
||||
if (key == cUp ) { slot = (slot - 1 + passportSlotCount) % passportSlotCount; };
|
||||
if (key == cDown ) { slot = (slot + 1) % passportSlotCount; };
|
||||
}
|
||||
// passport pages
|
||||
if (key == cLeft && item->value > 0) { item->value--; item->anim->dir = -1.0f; game->playSound(TR::SND_INV_PAGE, vec3(), 0, 0); }
|
||||
if (key == cRight && item->value < 2) { item->value++; item->anim->dir = 1.0f; game->playSound(TR::SND_INV_PAGE, vec3(), 0, 0); }
|
||||
|
||||
if (key == cAction && phaseChoose == 1.0f) {
|
||||
TR::LevelID id = game->getLevel()->id;
|
||||
switch (item->value) {
|
||||
case 0 : nextLevel = passportSlots[slot]; break;
|
||||
case 1 : nextLevel = (id == TR::TITLE) ? TR::LEVEL_1 : game->getLevel()->id; break;
|
||||
case 2 : nextLevel = (id == TR::TITLE) ? TR::LEVEL_MAX : TR::TITLE; break;
|
||||
}
|
||||
|
||||
if (nextLevel != TR::LEVEL_MAX) {
|
||||
item->anim->dir = -1.0f;
|
||||
item->value = -100;
|
||||
toggle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item->type == TR::Entity::INV_DETAIL) {
|
||||
int count = 5;
|
||||
if (key == cUp ) { slot = (slot - 1 + count) % count; };
|
||||
if (key == cDown ) { slot = (slot + 1) % count; };
|
||||
if (slot < count - 1) {
|
||||
Core::Settings::Quality q = settings.detail.quality[slot];
|
||||
if (key == cLeft && q > Core::Settings::LOW ) { q = Core::Settings::Quality(q - 1); }
|
||||
if (key == cRight && q < Core::Settings::HIGH ) { q = Core::Settings::Quality(q + 1); }
|
||||
if (q != settings.detail.quality[slot]) {
|
||||
switch (slot) {
|
||||
case 0 : settings.detail.setFilter(q); break;
|
||||
case 1 : settings.detail.setLighting(q); break;
|
||||
case 2 : settings.detail.setShadows(q); break;
|
||||
case 3 : settings.detail.setWater(q); break;
|
||||
}
|
||||
if (q == settings.detail.quality[slot])
|
||||
game->playSound(TR::SND_INV_PAGE, vec3(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == count -1 && key == cAction) {
|
||||
game->applySettings(settings);
|
||||
chosen = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (item->type == TR::Entity::INV_SOUND) {
|
||||
int count = 3;
|
||||
if (key == cUp ) { slot = (slot - 1 + count) % count; };
|
||||
if (key == cDown ) { slot = (slot + 1) % count; };
|
||||
|
||||
if (slot == 0 || slot == 1) { // music
|
||||
float &v = slot == 0 ? Core::settings.audio.music : Core::settings.audio.sound;
|
||||
if ((key == cLeft && v > 0.0f) || (key == cRight && v < 1.0f)) {
|
||||
v = key == cLeft ? max(0.0f, v - 0.05f) : min(1.0f, v + 0.05f);
|
||||
changeTimer = 0.2f;
|
||||
if (slot == 1)
|
||||
game->playSound(TR::SND_PISTOLS_SHOT, vec3(), 0, 0);
|
||||
game->applySettings(Core::settings);
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == 2 && (key == cLeft || key == cRight)) {
|
||||
Core::settings.audio.reverb = !Core::settings.audio.reverb;
|
||||
game->applySettings(Core::settings);
|
||||
}
|
||||
}
|
||||
|
||||
if (item->type == TR::Entity::INV_HOME && phaseChoose == 1.0f && key == cAction) {
|
||||
nextLevel = TR::GYM;
|
||||
toggle();
|
||||
}
|
||||
|
||||
if ((key == cInventory || key == cJump) && phaseChoose == 1.0f) {
|
||||
chosen = false;
|
||||
item->anim->dir = 1.0f;
|
||||
item->value = 1000;
|
||||
item->angle = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,31 +536,32 @@ struct Inventory {
|
||||
|
||||
bool ready = active && phaseRing == 1.0f && phasePage == 1.0f;
|
||||
|
||||
enum KeyDir { NONE, LEFT, RIGHT, UP, DOWN } dir;
|
||||
|
||||
if (Input::state[cLeft] || Input::joy.L.x < -0.5f || Input::joy.R.x > 0.5f)
|
||||
dir = LEFT;
|
||||
ControlKey key = cMAX;
|
||||
if (Input::state[cAction])
|
||||
key = cAction;
|
||||
else if (Input::state[cInventory] || Input::state[cJump])
|
||||
key = cInventory;
|
||||
else if (Input::state[cLeft] || Input::joy.L.x < -0.5f || Input::joy.R.x > 0.5f)
|
||||
key = cLeft;
|
||||
else if (Input::state[cRight] || Input::joy.L.x > 0.5f || Input::joy.R.x < -0.5f)
|
||||
dir = RIGHT;
|
||||
key = cRight;
|
||||
else if (Input::state[cUp] || Input::joy.L.y < -0.5f || Input::joy.R.y > 0.5f)
|
||||
dir = UP;
|
||||
key = cUp;
|
||||
else if (Input::state[cDown] || Input::joy.L.y > 0.5f || Input::joy.R.y < -0.5f)
|
||||
dir = DOWN;
|
||||
else
|
||||
dir = NONE;
|
||||
key = cDown;
|
||||
|
||||
static KeyDir lastDir = NONE;
|
||||
Item *item = items[getGlobalIndex(page, index)];
|
||||
|
||||
if (index == targetIndex && targetPage == page && ready) {
|
||||
if (!chosen) {
|
||||
if (dir == UP && !(page < PAGE_ITEMS && getItemsCount(page + 1))) dir = NONE;
|
||||
if (dir == DOWN && !(page > PAGE_OPTION && getItemsCount(page - 1))) dir = NONE;
|
||||
if (key == cUp && !(page < PAGE_ITEMS && getItemsCount(page + 1))) key = cMAX;
|
||||
if (key == cDown && !(page > PAGE_OPTION && getItemsCount(page - 1))) key = cMAX;
|
||||
|
||||
switch (dir) {
|
||||
case LEFT : { phaseSelect = 0.0f; targetIndex = (targetIndex - 1 + count) % count; } break;
|
||||
case RIGHT : { phaseSelect = 0.0f; targetIndex = (targetIndex + 1) % count; } break;
|
||||
case UP : { phasePage = 0.0f; targetPage = Page(page + 1); } break;
|
||||
case DOWN : { phasePage = 0.0f; targetPage = Page(page - 1); } break;
|
||||
switch (key) {
|
||||
case cLeft : { phaseSelect = 0.0f; targetIndex = (targetIndex - 1 + count) % count; } break;
|
||||
case cRight : { phaseSelect = 0.0f; targetIndex = (targetIndex + 1) % count; } break;
|
||||
case cUp : { phasePage = 0.0f; targetPage = Page(page + 1); } break;
|
||||
case cDown : { phasePage = 0.0f; targetPage = Page(page - 1); } break;
|
||||
default : ;
|
||||
}
|
||||
|
||||
@@ -469,60 +569,10 @@ struct Inventory {
|
||||
vec3 p;
|
||||
game->playSound(TR::SND_INV_SPIN, p, 0, 0);
|
||||
}
|
||||
} else {
|
||||
Item *item = items[getGlobalIndex(page, index)];
|
||||
|
||||
if (item->type == TR::Entity::INV_PASSPORT && passportSlotCount) {
|
||||
if (lastDir != dir) {
|
||||
// passport slots
|
||||
if (item->value == 0 && item->anim->dir == 0.0f) { // slot select
|
||||
if (dir == UP) { passportSlot = (passportSlot - 1 + passportSlotCount) % passportSlotCount; };
|
||||
if (dir == DOWN) { passportSlot = (passportSlot + 1) % passportSlotCount; };
|
||||
}
|
||||
// passport pages
|
||||
if (dir == LEFT && item->value > 0) { item->value--; item->anim->dir = -1.0f; game->playSound(TR::SND_INV_PAGE, vec3(), 0, 0); }
|
||||
if (dir == RIGHT && item->value < 2) { item->value++; item->anim->dir = 1.0f; game->playSound(TR::SND_INV_PAGE, vec3(), 0, 0); }
|
||||
lastDir = dir;
|
||||
}
|
||||
|
||||
if (Input::state[cAction] && phaseChoose == 1.0f) {
|
||||
TR::LevelID id = game->getLevel()->id;
|
||||
switch (item->value) {
|
||||
case 0 : nextLevel = passportSlots[passportSlot]; break;
|
||||
case 1 : nextLevel = (id == TR::TITLE) ? TR::LEVEL_1 : game->getLevel()->id; break;
|
||||
case 2 : nextLevel = (id == TR::TITLE) ? TR::LEVEL_MAX : TR::TITLE; break;
|
||||
}
|
||||
|
||||
if (nextLevel != TR::LEVEL_MAX) {
|
||||
item->anim->dir = -1.0f;
|
||||
item->value = -100;
|
||||
toggle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item->type == TR::Entity::INV_HOME) {
|
||||
if (Input::state[cAction] && phaseChoose == 1.0f) {
|
||||
nextLevel = TR::GYM;
|
||||
toggle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ready = active && phaseRing == 1.0f && phasePage == 1.0f;
|
||||
|
||||
vec3 p;
|
||||
|
||||
Item *item = items[getGlobalIndex(page, index)];
|
||||
|
||||
if (index == targetIndex && ready) {
|
||||
if (Input::state[cAction] && (phaseChoose == 0.0f || (phaseChoose == 1.0f && item->anim->isEnded))) {
|
||||
chosen = !chosen;
|
||||
if (!chosen) {
|
||||
item->angle = 0.0f;
|
||||
} else {
|
||||
if (lastKey != key && key == cAction && phaseChoose == 0.0f) {
|
||||
vec3 p;
|
||||
chosen = true;
|
||||
switch (item->type) {
|
||||
case TR::Entity::INV_COMPASS : game->playSound(TR::SND_INV_COMPASS, p, 0, 0); break;
|
||||
case TR::Entity::INV_HOME : game->playSound(TR::SND_INV_HOME, p, 0, 0); break;
|
||||
@@ -535,8 +585,22 @@ struct Inventory {
|
||||
}
|
||||
item->choose();
|
||||
}
|
||||
} else {
|
||||
if (changeTimer > 0.0f) {
|
||||
changeTimer -= Core::deltaTime;
|
||||
if (changeTimer <= 0.0f) {
|
||||
changeTimer = 0.0f;
|
||||
lastKey = cMAX;
|
||||
}
|
||||
}
|
||||
|
||||
if (key != cMAX && lastKey != key && changeTimer == 0.0f)
|
||||
controlItem(item, key);
|
||||
}
|
||||
}
|
||||
lastKey = key;
|
||||
|
||||
ready = active && phaseRing == 1.0f && phasePage == 1.0f;
|
||||
|
||||
float w = 90.0f * DEG2RAD * Core::deltaTime;
|
||||
|
||||
@@ -638,16 +702,35 @@ struct Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
int passportSlot, passportSlotCount;
|
||||
int slot, passportSlotCount;
|
||||
TR::LevelID passportSlots[32];
|
||||
Core::Settings settings;
|
||||
|
||||
void renderPassport(Item *item) {
|
||||
if (item->value != 0 || item->anim->dir != 0.0f) return; // check for "Load Game" page
|
||||
if (item->anim->dir != 0.0f) return; // check for "Load Game" page
|
||||
|
||||
float y = 120.0f;
|
||||
float h = 20.0f;
|
||||
float w = 320.0f;
|
||||
|
||||
|
||||
StringID str = STR_LOAD_GAME;
|
||||
|
||||
if (game->getLevel()->id == TR::TITLE) {
|
||||
if (item->value == 1) str = STR_START_GAME;
|
||||
if (item->value == 2) str = STR_EXIT_GAME;
|
||||
} else {
|
||||
if (item->value == 1) str = STR_RESTART_LEVEL;
|
||||
if (item->value == 2) str = STR_EXIT_TO_TITLE;
|
||||
}
|
||||
|
||||
UI::textOut(vec2(0, 480 - 32), str, UI::aCenter, UI::width);
|
||||
float tw = UI::getTextSize(STR[str]).x;
|
||||
|
||||
if (item->value > 0) UI::specOut(vec2((UI::width - tw) * 0.5f - 32.0f, 480 - 32), 108);
|
||||
if (item->value < 2) UI::specOut(vec2((UI::width + tw) * 0.5f + 16.0f, 480 - 32), 109);
|
||||
|
||||
if (item->value != 0) return;
|
||||
|
||||
// background
|
||||
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w - 16.0f) * 0.5f, y - 16.0f), vec2(w + 16.0f, h * 16.0f), 0.0f, 0, 0xC0000000);
|
||||
// title
|
||||
@@ -655,7 +738,7 @@ struct Inventory {
|
||||
UI::textOut(vec2(0, y), STR_SELECT_LEVEL, UI::aCenter, UI::width);
|
||||
|
||||
y += h * 2;
|
||||
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w) * 0.5f, y + passportSlot * h + 6 - h), vec2(w, h - 6), 1.0f, 0xFFD8377C, 0);
|
||||
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w) * 0.5f, y + slot * h + 6 - h), vec2(w, h - 6), 1.0f, 0xFFD8377C, 0);
|
||||
|
||||
for (int i = 0; i < passportSlotCount; i++)
|
||||
if (passportSlots[i] == TR::LEVEL_MAX)
|
||||
@@ -664,21 +747,101 @@ struct Inventory {
|
||||
UI::textOut(vec2(0, y + i * h), TR::LEVEL_INFO[passportSlots[i]].title, UI::aCenter, UI::width);
|
||||
}
|
||||
|
||||
float printBool(float x, float y, float w, StringID oStr, bool active, bool value) {
|
||||
StringID vStr = StringID(STR_OFF + int(value));
|
||||
|
||||
UI::textOut(vec2(x, y), oStr);
|
||||
UI::textOut(vec2(x + w - 96.0f, y), vStr, UI::aCenter, 96.0f);
|
||||
if (active) {
|
||||
UI::specOut(vec2(x + w - 96.0f, y), 108);
|
||||
UI::specOut(vec2(x + w - 12.0f, y), 109);
|
||||
}
|
||||
return y + 20.0f;
|
||||
}
|
||||
|
||||
float printQuality(float x, float y, float w, StringID oStr, bool active, Core::Settings::Quality value) {
|
||||
StringID vStr = StringID(STR_QUALITY_LOW + int(value));
|
||||
|
||||
float d = x + w * 0.5f;
|
||||
UI::textOut(vec2(x + 32.0f, y), oStr);
|
||||
UI::textOut(vec2(d, y), vStr, UI::aCenter, w * 0.5f - 32.0f);
|
||||
if (active) {
|
||||
if (value > Core::Settings::LOW) UI::specOut(vec2(d, y), 108);
|
||||
if (value < Core::Settings::HIGH) UI::specOut(vec2(d + w * 0.5f - 32.0f - 16.0f, y), 109);
|
||||
}
|
||||
return y + 20.0f;
|
||||
}
|
||||
|
||||
float printBar(float x, float y, float w, uint32 color, char icon, bool active, float value) {
|
||||
float h = 20.0f;
|
||||
UI::renderBar(UI::BAR_WHITE, vec2(x + (32.0f + 2.0f), y - h + 6 + 2), vec2(w - (64.0f + 4.0f), h - 6 - 4), value, color, 0xFF000000, 0xFFA0A0A0, 0xFFA0A0A0, 0xFF000000);
|
||||
UI::specOut(vec2(x + 16.0f, y), icon);
|
||||
if (active) {
|
||||
if (value > 0.0f) UI::specOut(vec2(x, y), 108);
|
||||
if (value < 1.0f) UI::specOut(vec2(x + w - 12.0f, y), 109);
|
||||
}
|
||||
return y + 20.0f;
|
||||
}
|
||||
|
||||
void renderDetail(Item *item) {
|
||||
float w = 320.0f;
|
||||
float h = 20.0f;
|
||||
|
||||
float x = (UI::width - w) * 0.5f;
|
||||
float y = 192.0f;
|
||||
|
||||
// background
|
||||
UI::renderBar(UI::BAR_OPTION, vec2(x, y - 16.0f), vec2(w, h * 8.0f + 8.0f), 0.0f, 0, 0xC0000000);
|
||||
// title
|
||||
UI::renderBar(UI::BAR_OPTION, vec2(x, y - h + 6), vec2(w, h - 6), 1.0f, 0x802288FF, 0, 0, 0);
|
||||
UI::textOut(vec2(0, y), STR_SELECT_DETAIL, UI::aCenter, UI::width);
|
||||
|
||||
y += h * 2;
|
||||
x += 8.0f;
|
||||
w -= 16.0f;
|
||||
float aw = slot == 4 ? (w - 128.0f) : w;
|
||||
|
||||
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - aw) * 0.5f, y + (slot > 3 ? 5 : slot) * h + 6 - h), vec2(aw, h - 6), 1.0f, 0xFFD8377C, 0);
|
||||
y = printQuality(x, y, w, STR_OPT_DETAIL_FILTER, slot == 0, settings.detail.filter);
|
||||
y = printQuality(x, y, w, STR_OPT_DETAIL_LIGHTING, slot == 1, settings.detail.lighting);
|
||||
y = printQuality(x, y, w, STR_OPT_DETAIL_SHADOWS, slot == 2, settings.detail.shadows);
|
||||
y = printQuality(x, y, w, STR_OPT_DETAIL_WATER, slot == 3, settings.detail.water);
|
||||
y += h;
|
||||
UI::textOut(vec2(x + 64.0f, y), STR_APPLY, UI::aCenter, w - 128.0f);
|
||||
}
|
||||
|
||||
void renderSound(Item *item) {
|
||||
float w = 320.0f;
|
||||
float h = 20.0f;
|
||||
|
||||
float x = (UI::width - w) * 0.5f;
|
||||
float y = 192.0f;
|
||||
|
||||
// background
|
||||
UI::renderBar(UI::BAR_OPTION, vec2(x, y - 16.0f), vec2(w, h * 5.0f + 8.0f), 0.0f, 0, 0xC0000000);
|
||||
// title
|
||||
UI::renderBar(UI::BAR_OPTION, vec2(x, y - h + 6), vec2(w, h - 6), 1.0f, 0x802288FF, 0, 0, 0);
|
||||
UI::textOut(vec2(0, y), STR_SET_VOLUMES, UI::aCenter, UI::width);
|
||||
|
||||
y += h * 2;
|
||||
x += 8.0f;
|
||||
w -= 16.0f;
|
||||
|
||||
UI::renderBar(UI::BAR_OPTION, vec2((UI::width - w) * 0.5f, y + slot * h + 6 - h), vec2(w, h - 6), 1.0f, 0xFFD8377C, 0);
|
||||
|
||||
float aw = w - 64.0f;
|
||||
aw -= 4.0f;
|
||||
|
||||
y = printBar((UI::width - w) * 0.5f, y, w, 0xFF0080FF, 101, slot == 0, Core::settings.audio.music);
|
||||
y = printBar((UI::width - w) * 0.5f, y, w, 0xFFFF8000, 102, slot == 1, Core::settings.audio.sound);
|
||||
y = printBool(x + 32.0f, y, w - 64.0f, STR_REVERBERATION, slot == 2, Core::settings.audio.reverb);
|
||||
}
|
||||
|
||||
void renderItemText(Item *item) {
|
||||
if (item->type == TR::Entity::INV_PASSPORT && phaseChoose == 1.0f) {
|
||||
StringID str = STR_LOAD_GAME;
|
||||
|
||||
if (game->getLevel()->id == TR::TITLE) {
|
||||
if (item->value == 1) str = STR_START_GAME;
|
||||
if (item->value == 2) str = STR_EXIT_GAME;
|
||||
} else {
|
||||
if (item->value == 1) str = STR_RESTART_LEVEL;
|
||||
if (item->value == 2) str = STR_EXIT_TO_TITLE;
|
||||
}
|
||||
|
||||
UI::textOut(vec2(0, 480 - 16), str, UI::aCenter, UI::width);
|
||||
//
|
||||
} else
|
||||
UI::textOut(vec2(0, 480 - 16), item->desc.str, UI::aCenter, UI::width);
|
||||
UI::textOut(vec2(0, 480 - 32), item->desc.str, UI::aCenter, UI::width);
|
||||
|
||||
renderItemCount(item, vec2(UI::width / 2 - 160, 480 - 96), 320);
|
||||
|
||||
@@ -688,11 +851,15 @@ struct Inventory {
|
||||
renderPassport(item);
|
||||
break;
|
||||
case TR::Entity::INV_HOME :
|
||||
break;
|
||||
case TR::Entity::INV_COMPASS :
|
||||
case TR::Entity::INV_MAP :
|
||||
case TR::Entity::INV_DETAIL :
|
||||
break;
|
||||
case TR::Entity::INV_DETAIL :
|
||||
renderDetail(item);
|
||||
break;
|
||||
case TR::Entity::INV_SOUND :
|
||||
renderSound(item);
|
||||
break;
|
||||
case TR::Entity::INV_CONTROLS :
|
||||
case TR::Entity::INV_GAMMA :
|
||||
UI::textOut(vec2(0, 240), STR_NOT_IMPLEMENTED, UI::aCenter, UI::width);
|
||||
|
@@ -440,6 +440,7 @@ struct Lara : Character {
|
||||
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, STAND_ONWATER); // gym (pool)
|
||||
//reset(0, vec3(74858, 3072, 20795), 0); // level 1 (dart)
|
||||
//reset(14, vec3(20215, 6656, 52942), PI); // level 1 (bridge)
|
||||
//reset(20, vec3(8952, 3840, 68071), PI); // level 1 (crystal)
|
||||
//reset(33, vec3(48229, 4608, 78420), 270 * DEG2RAD); // level 1 (end)
|
||||
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
|
||||
//reset(26, vec3(71980, 1546, 19000), 270 * DEG2RAD); // level 2 (underwater switch)
|
||||
|
98
src/level.h
98
src/level.h
@@ -36,9 +36,9 @@ struct Level : IGame {
|
||||
float clipHeight;
|
||||
} *params = (Params*)&Core::params;
|
||||
|
||||
ZoneCache *zoneCache;
|
||||
AmbientCache *ambientCache;
|
||||
WaterCache *waterCache;
|
||||
ZoneCache *zoneCache;
|
||||
|
||||
Sound::Sample *sndSoundtrack;
|
||||
Sound::Sample *sndUnderwater;
|
||||
@@ -69,6 +69,52 @@ struct Level : IGame {
|
||||
new Stream(buf, loadAsync);
|
||||
}
|
||||
|
||||
virtual void loadGame(int slot) {
|
||||
//
|
||||
}
|
||||
|
||||
virtual void saveGame(int slot) {
|
||||
//
|
||||
}
|
||||
|
||||
virtual void applySettings(const Core::Settings &settings) {
|
||||
if (settings.detail.filter != Core::settings.detail.filter)
|
||||
atlas->setFilterQuality(settings.detail.filter);
|
||||
|
||||
bool rebuildMesh = settings.detail.water != Core::settings.detail.water;
|
||||
bool rebuildAmbient = settings.detail.lighting != Core::settings.detail.lighting;
|
||||
bool rebuildShadows = settings.detail.shadows != Core::settings.detail.shadows;
|
||||
bool rebuildWater = settings.detail.water != Core::settings.detail.water;
|
||||
bool rebuildShaders = rebuildWater || rebuildAmbient || rebuildShadows;
|
||||
|
||||
Core::settings = settings;
|
||||
|
||||
if (rebuildShaders) {
|
||||
delete shaderCache;
|
||||
shaderCache = new ShaderCache();
|
||||
}
|
||||
|
||||
if (rebuildMesh) {
|
||||
delete mesh;
|
||||
mesh = new MeshBuilder(level);
|
||||
}
|
||||
|
||||
if (rebuildAmbient) {
|
||||
delete ambientCache;
|
||||
ambientCache = Core::settings.detail.lighting > Core::Settings::MEDIUM ? new AmbientCache(this) : NULL;
|
||||
}
|
||||
|
||||
if (rebuildShadows) {
|
||||
delete shadow;
|
||||
shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL;
|
||||
}
|
||||
|
||||
if (rebuildWater) {
|
||||
delete waterCache;
|
||||
waterCache = Core::settings.detail.water > Core::Settings::LOW ? new WaterCache(this) : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual TR::Level* getLevel() {
|
||||
return &level;
|
||||
}
|
||||
@@ -108,10 +154,6 @@ struct Level : IGame {
|
||||
params->waterHeight = height;
|
||||
}
|
||||
|
||||
virtual void updateParams() {
|
||||
Core::active.shader->setParam(uParam, Core::params);
|
||||
}
|
||||
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {
|
||||
if (waterCache)
|
||||
waterCache->addDrop(pos, radius, strength);
|
||||
@@ -399,10 +441,10 @@ struct Level : IGame {
|
||||
level.cameraController = camera;
|
||||
level.laraController = lara;
|
||||
|
||||
ambientCache = Core::settings.detail.ambient ? new AmbientCache(this) : NULL;
|
||||
waterCache = Core::settings.detail.water ? new WaterCache(this) : NULL;
|
||||
zoneCache = new ZoneCache(this);
|
||||
shadow = Core::settings.detail.shadows ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL;
|
||||
ambientCache = Core::settings.detail.lighting > Core::Settings::MEDIUM ? new AmbientCache(this) : NULL;
|
||||
waterCache = Core::settings.detail.water > Core::Settings::LOW ? new WaterCache(this) : NULL;
|
||||
shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL;
|
||||
|
||||
initReflections();
|
||||
|
||||
@@ -460,7 +502,6 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
static void fillCallback(int id, int width, int height, int tileX, int tileY, void *userData, void *data) {
|
||||
static const uint32 whiteColor = 0xFFFFFFFF;
|
||||
static const uint32 barColor[UI::BAR_MAX][25] = {
|
||||
// health bar
|
||||
{ 0xFF2C5D71, 0xFF5E81AE, 0xFF2C5D71, 0xFF1B4557, 0xFF16304F },
|
||||
@@ -472,6 +513,8 @@ struct Level : IGame {
|
||||
0x00FFFFFF, 0x80FFFFFF, 0x80FFFFFF, 0x80FFFFFF, 0x00FFFFFF,
|
||||
0x00FFFFFF, 0x60FFFFFF, 0x60FFFFFF, 0x60FFFFFF, 0x00FFFFFF,
|
||||
0x00FFFFFF, 0x20FFFFFF, 0x20FFFFFF, 0x20FFFFFF, 0x00FFFFFF },
|
||||
// white bar (white tile)
|
||||
{ 0xFFFFFFFF },
|
||||
};
|
||||
|
||||
int stride = 256, uvCount;
|
||||
@@ -504,21 +547,20 @@ struct Level : IGame {
|
||||
uvCount = 4;
|
||||
|
||||
switch (id) {
|
||||
case UI::BAR_HEALTH :
|
||||
case UI::BAR_OXYGEN :
|
||||
case UI::BAR_OPTION :
|
||||
case UI::BAR_HEALTH :
|
||||
case UI::BAR_OXYGEN :
|
||||
case UI::BAR_OPTION :
|
||||
case UI::BAR_WHITE :
|
||||
src = (TR::Color32*)&barColor[id][0];
|
||||
tex = &barTile[id];
|
||||
mm.w = 4; // height - 1
|
||||
if (id == UI::BAR_OPTION) {
|
||||
stride = 5;
|
||||
mm.z = 4;
|
||||
if (id != UI::BAR_WHITE) {
|
||||
mm.w = 4; // height - 1
|
||||
if (id == UI::BAR_OPTION) {
|
||||
stride = 5;
|
||||
mm.z = 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3 : // white color
|
||||
src = (TR::Color32*)&whiteColor;
|
||||
tex = &whiteTile;
|
||||
break;
|
||||
default : return;
|
||||
}
|
||||
|
||||
@@ -588,7 +630,7 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
// repack texture tiles
|
||||
Atlas *tiles = new Atlas(level.objectTexturesCount + level.spriteTexturesCount + 4, &level, fillCallback);
|
||||
Atlas *tiles = new Atlas(level.objectTexturesCount + level.spriteTexturesCount + UI::BAR_MAX, &level, fillCallback);
|
||||
// add textures
|
||||
int texIdx = level.version == TR::VER_TR1_PSX ? 256 : 0; // skip palette color for PSX version
|
||||
for (int i = texIdx; i < level.objectTexturesCount; i++) {
|
||||
@@ -626,8 +668,10 @@ struct Level : IGame {
|
||||
tiles->add(short4(8192, 8192, 8192 + 4, 8192 + 4), texIdx++);
|
||||
// add white color
|
||||
tiles->add(short4(2048, 2048, 2048, 2048), texIdx++);
|
||||
|
||||
// get result texture
|
||||
atlas = tiles->pack();
|
||||
atlas->setFilterQuality(Core::settings.detail.filter);
|
||||
|
||||
delete tiles;
|
||||
|
||||
@@ -711,8 +755,9 @@ struct Level : IGame {
|
||||
setWaterParams(float(room.info.yTop));
|
||||
}
|
||||
|
||||
Core::active.shader->setParam(uParam, Core::params);
|
||||
Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha));
|
||||
if (Core::settings.detail.contact)
|
||||
if (Core::settings.detail.shadows > Core::Settings::MEDIUM)
|
||||
Core::active.shader->setParam(uContacts, Core::contacts[0], MAX_CONTACTS);
|
||||
}
|
||||
|
||||
@@ -733,7 +778,7 @@ struct Level : IGame {
|
||||
if (Core::pass == Core::passShadow)
|
||||
return;
|
||||
|
||||
if (Core::settings.detail.contact) {
|
||||
if (Core::settings.detail.shadows > Core::Settings::MEDIUM) {
|
||||
Sphere spheres[MAX_CONTACTS];
|
||||
int spheresCount;
|
||||
lara->getSpheres(spheres, spheresCount);
|
||||
@@ -835,7 +880,7 @@ struct Level : IGame {
|
||||
|
||||
if (isModel) { // model
|
||||
vec3 pos = controller->getPos();
|
||||
if (Core::settings.detail.ambient) {
|
||||
if (ambientCache) {
|
||||
AmbientCache::Cube cube;
|
||||
if (Core::stats.frame != controller->frameIndex) {
|
||||
ambientCache->getAmbient(roomIndex, pos, cube);
|
||||
@@ -1242,14 +1287,15 @@ struct Level : IGame {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
||||
|
||||
if (waterCache->reflect)
|
||||
waterCache->reflect->bind(sDiffuse);
|
||||
if (waterCache && waterCache->count && waterCache->items[0].caustics)
|
||||
waterCache->items[0].caustics->bind(sDiffuse);
|
||||
else
|
||||
atlas->bind(sDiffuse);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
Core::setCulling(cfNone);
|
||||
Core::setDepthTest(false);
|
||||
Core::setBlending(bmNone);
|
||||
Core::validateRenderState();
|
||||
|
||||
glColor3f(10, 10, 10);
|
||||
int w = Core::active.textures[sDiffuse]->width / 2;
|
||||
|
12
src/mesh.h
12
src/mesh.h
@@ -5,7 +5,8 @@
|
||||
#include "format.h"
|
||||
|
||||
|
||||
TR::ObjectTexture whiteTile, barTile[3];
|
||||
TR::ObjectTexture barTile[4 /* UI::BAR_MAX */];
|
||||
TR::ObjectTexture &whiteTile = barTile[3];
|
||||
|
||||
struct MeshRange {
|
||||
int iStart;
|
||||
@@ -198,7 +199,7 @@ struct MeshBuilder {
|
||||
iCount += d.rCount * 6 + d.tCount * 3;
|
||||
vCount += d.rCount * 4 + d.tCount * 3;
|
||||
|
||||
if (Core::settings.detail.water)
|
||||
if (Core::settings.detail.water > Core::Settings::LOW)
|
||||
roomRemoveWaterSurfaces(r, iCount, vCount);
|
||||
|
||||
for (int j = 0; j < r.meshesCount; j++) {
|
||||
@@ -906,7 +907,7 @@ struct MeshBuilder {
|
||||
vCount += 4;
|
||||
}
|
||||
|
||||
void addBar(Index *indices, Vertex *vertices, int &iCount, int &vCount, const TR::ObjectTexture &tile, const vec2 &pos, const vec2 &size, uint32 color) {
|
||||
void addBar(Index *indices, Vertex *vertices, int &iCount, int &vCount, const TR::ObjectTexture &tile, const vec2 &pos, const vec2 &size, uint32 color, uint32 color2 = 0) {
|
||||
addQuad(indices, iCount, vCount, 0, vertices, NULL);
|
||||
|
||||
int16 minX = int16(pos.x);
|
||||
@@ -922,7 +923,10 @@ struct MeshBuilder {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Vertex &v = vertices[vCount + i];
|
||||
v.normal = { 0, 0, 0, 0 };
|
||||
v.color = *((ubyte4*)&color);
|
||||
if (color2 != 0 && (i == 0 || i == 3))
|
||||
v.color = *((ubyte4*)&color2);
|
||||
else
|
||||
v.color = *((ubyte4*)&color);
|
||||
|
||||
short2 uv = tile.texCoord[i];
|
||||
|
||||
|
@@ -117,7 +117,7 @@
|
||||
<input type="button" value="Browse Level" onclick="document.getElementById('browseFile').click();" /> (.PHD, .PSX)
|
||||
<p style="margin:8px">
|
||||
OpenLara on <a target="_blank" href="https://github.com/XProger/OpenLara">github</a> & <a target="_blank" href="https://www.facebook.com/OpenLaraTR">facebook</a><br>
|
||||
<br><i>last update: 16.09.2017</i><br>
|
||||
<br><i>last update: 18.09.2017</i><br>
|
||||
</p>
|
||||
</span>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
R"====(
|
||||
#ifdef GL_ES
|
||||
precision lowp int;
|
||||
precision highp float;
|
||||
precision lowp int;
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
#ifdef OPT_CONTACT
|
||||
@@ -10,8 +10,9 @@ R"====(
|
||||
|
||||
varying vec4 vTexCoord; // xy - atlas coords, zw - trapezoidal correction
|
||||
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
#ifdef OPT_CAUSTICS
|
||||
varying vec2 vCausticsCoord; // - xy caustics texture coord
|
||||
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
|
||||
#endif
|
||||
|
||||
uniform mat4 uLightProj;
|
||||
@@ -20,7 +21,6 @@ uniform vec3 uViewPos;
|
||||
uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height
|
||||
uniform vec3 uLightPos[MAX_LIGHTS];
|
||||
uniform vec4 uLightColor[MAX_LIGHTS]; // xyz - color, w - radius * intensity
|
||||
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
|
||||
|
||||
uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
|
||||
@@ -45,31 +45,28 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
|
||||
#ifdef VERTEX
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
#if defined(OPT_AMBIENT)
|
||||
uniform vec3 uAmbient[6];
|
||||
#ifdef TYPE_ENTITY
|
||||
uniform vec4 uBasis[32 * 2];
|
||||
#else
|
||||
uniform vec4 uBasis[2];
|
||||
#endif
|
||||
uniform vec4 uBasis[32 * 2];
|
||||
#else
|
||||
uniform vec4 uBasis[2];
|
||||
#endif
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
#if defined(OPT_AMBIENT) && defined(TYPE_ENTITY)
|
||||
vec3 calcAmbient(vec3 n) {
|
||||
vec3 sqr = n * n;
|
||||
vec3 pos = step(0.0, n);
|
||||
return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) +
|
||||
sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) +
|
||||
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PASS_COMPOSE) && defined(TYPE_ROOM)
|
||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||
#endif
|
||||
#ifdef OPT_AMBIENT
|
||||
uniform vec3 uAmbient[6];
|
||||
|
||||
vec3 calcAmbient(vec3 n) {
|
||||
vec3 sqr = n * n;
|
||||
vec3 pos = step(0.0, n);
|
||||
return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) +
|
||||
sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) +
|
||||
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OPT_ANIMTEX
|
||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||
#endif
|
||||
|
||||
attribute vec4 aCoord;
|
||||
attribute vec4 aTexCoord;
|
||||
@@ -142,7 +139,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
}
|
||||
|
||||
void _diffuse() {
|
||||
#if !defined(PASS_SHADOW)
|
||||
#ifndef PASS_SHADOW
|
||||
vDiffuse = vec4(aColor.xyz * (uMaterial.x * 2.0), uMaterial.w);
|
||||
|
||||
#ifdef UNDERWATER
|
||||
@@ -182,6 +179,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
lum.y = dot(vNormal.xyz, normalize(lv1)); att.y = dot(lv1, lv1);
|
||||
lum.z = dot(vNormal.xyz, normalize(lv2)); att.z = dot(lv2, lv2);
|
||||
lum.w = dot(vNormal.xyz, normalize(lv3)); att.w = dot(lv3, lv3);
|
||||
@@ -193,13 +191,11 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
|
||||
vec3 ambient;
|
||||
#ifdef TYPE_ENTITY
|
||||
|
||||
#ifdef OPT_AMBIENT
|
||||
ambient = calcAmbient(vNormal.xyz);
|
||||
#else
|
||||
ambient = vec3(uMaterial.y);
|
||||
#endif
|
||||
|
||||
#else
|
||||
ambient = vec3(min(uMaterial.y, light.x));
|
||||
#endif
|
||||
@@ -216,8 +212,8 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
#else
|
||||
vLight.xyz += light.x;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef PASS_AMBIENT
|
||||
@@ -229,7 +225,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
void _uv(vec3 coord) {
|
||||
vTexCoord = aTexCoord;
|
||||
#if defined(PASS_COMPOSE) && !defined(TYPE_SPRITE)
|
||||
#ifdef TYPE_ROOM
|
||||
#ifdef OPT_ANIMTEX
|
||||
// animated texture coordinates
|
||||
vec2 range = uAnimTexRanges[int(aParam.x)]; // x - start index, y - count
|
||||
float frame = fract((aParam.y + uParam.x * 4.0 - range.x) / range.y) * range.y;
|
||||
@@ -239,7 +235,7 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
vTexCoord.xy *= vTexCoord.zw;
|
||||
#endif
|
||||
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
#ifdef OPT_CAUSTICS
|
||||
vCausticsCoord.xy = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
|
||||
#endif
|
||||
}
|
||||
@@ -263,149 +259,138 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
#else
|
||||
uniform sampler2D sDiffuse;
|
||||
|
||||
#if defined(UNDERWATER) && defined(OPT_WATER)
|
||||
uniform sampler2D sReflect;
|
||||
#if defined(PASS_COMPOSE) && defined(TYPE_MIRROR)
|
||||
uniform samplerCube sEnvironment;
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
#ifdef TYPE_MIRROR
|
||||
uniform samplerCube sEnvironment;
|
||||
#endif
|
||||
#if defined(PASS_SHADOW) && defined(SHADOW_COLOR)
|
||||
vec4 pack(in float value) {
|
||||
vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
|
||||
vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
|
||||
vec4 res = fract(value * bitSh);
|
||||
res -= res.xxyz * bitMsk;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PASS_SHADOW
|
||||
#ifdef SHADOW_COLOR
|
||||
vec4 pack(in float value) {
|
||||
vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
|
||||
vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
|
||||
vec4 res = fract(value * bitSh);
|
||||
res -= res.xxyz * bitMsk;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
|
||||
#if defined(OPT_SHADOW) && !defined(TYPE_FLASH)
|
||||
#ifdef SHADOW_SAMPLER
|
||||
uniform sampler2DShadow sShadow;
|
||||
#ifdef GL_ES
|
||||
#define SHADOW(V) (shadow2DEXT(sShadow, V))
|
||||
#else
|
||||
#define SHADOW(V) (shadow2D(sShadow, V).x)
|
||||
#endif
|
||||
#ifdef OPT_SHADOW
|
||||
#ifdef SHADOW_SAMPLER
|
||||
uniform sampler2DShadow sShadow;
|
||||
#ifdef GL_ES
|
||||
#define SHADOW(V) (shadow2DEXT(sShadow, V))
|
||||
#else
|
||||
uniform sampler2D sShadow;
|
||||
#define CMP(a,b) step(min(1.0, b), a)
|
||||
#define SHADOW(V) (shadow2D(sShadow, V).x)
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2D sShadow;
|
||||
#define CMP(a,b) step(min(1.0, b), a)
|
||||
|
||||
#ifdef SHADOW_DEPTH
|
||||
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
|
||||
#elif defined(SHADOW_COLOR)
|
||||
float unpack(vec4 value) {
|
||||
vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
|
||||
return dot(value, bitSh);
|
||||
}
|
||||
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
|
||||
#endif
|
||||
|
||||
float SHADOW(vec3 p) {
|
||||
return compare(p.xy, p.z);
|
||||
#ifdef SHADOW_DEPTH
|
||||
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
|
||||
#elif defined(SHADOW_COLOR)
|
||||
float unpack(vec4 value) {
|
||||
vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
|
||||
return dot(value, bitSh);
|
||||
}
|
||||
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
|
||||
#endif
|
||||
|
||||
#define SHADOW_TEXEL (2.0 / SHADOW_TEX_SIZE)
|
||||
|
||||
float random(vec3 seed, float freq) {
|
||||
float dt = dot(floor(seed * freq), vec3(53.1215, 21.1352, 9.1322));
|
||||
return fract(sin(dt) * 2105.2354);
|
||||
}
|
||||
|
||||
float randomAngle(vec3 seed, float freq) {
|
||||
return random(seed, freq) * 6.283285;
|
||||
}
|
||||
|
||||
vec3 rotate(vec2 sc, vec2 v) {
|
||||
return vec3(v.x * sc.y + v.y * sc.x, v.x * -sc.x + v.y * sc.y, 0.0);
|
||||
}
|
||||
|
||||
float getShadow(vec4 lightProj) {
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
|
||||
float rShadow = SHADOW(SHADOW_TEXEL * vec3(-0.93289, -0.03146, 0.0) + p) +
|
||||
SHADOW(SHADOW_TEXEL * vec3( 0.81628, -0.05965, 0.0) + p) +
|
||||
SHADOW(SHADOW_TEXEL * vec3(-0.18455, 0.97225, 0.0) + p) +
|
||||
SHADOW(SHADOW_TEXEL * vec3( 0.04032, -0.85898, 0.0) + p);
|
||||
|
||||
if (rShadow > 0.1 && rShadow < 3.9) {
|
||||
float angle = randomAngle(vTexCoord.xyy, 15.0);
|
||||
vec2 sc = vec2(sin(angle), cos(angle));
|
||||
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.54316, 0.21186)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.03925, -0.34345)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.07695, 0.40667)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.66378, -0.54068)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.54130, 0.66730)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.69301, 0.46990)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.37228, 0.03811)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.28597, 0.80228)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.44801, -0.43844)) + p);
|
||||
rShadow /= 13.0;
|
||||
} else
|
||||
rShadow /= 4.0;
|
||||
|
||||
float fade = clamp(dot(vLightVec.xyz, vLightVec.xyz), 0.0, 1.0);
|
||||
return rShadow + (1.0 - rShadow) * fade;
|
||||
}
|
||||
|
||||
float getShadow() {
|
||||
#ifdef TYPE_ROOM
|
||||
float vis = min(dot(vNormal.xyz, vLightVec.xyz), vLightProj.w);
|
||||
#else
|
||||
float vis = vLightProj.w;
|
||||
#endif
|
||||
return vis > 0.0 ? getShadow(vLightProj) : 1.0;
|
||||
float SHADOW(vec3 p) {
|
||||
return compare(p.xy, p.z);
|
||||
}
|
||||
#endif
|
||||
|
||||
float calcSpecular(vec3 normal, vec3 viewVec, vec3 lightVec, vec4 color, float intensity) {
|
||||
vec3 vv = normalize(viewVec);
|
||||
vec3 rv = reflect(-vv, normal);
|
||||
vec3 lv = normalize(lightVec);
|
||||
return pow(max(0.0, dot(rv, lv)), 8.0) * intensity;
|
||||
#define SHADOW_TEXEL (2.0 / SHADOW_TEX_SIZE)
|
||||
|
||||
float random(vec3 seed, float freq) {
|
||||
float dt = dot(floor(seed * freq), vec3(53.1215, 21.1352, 9.1322));
|
||||
return fract(sin(dt) * 2105.2354);
|
||||
}
|
||||
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
float calcCaustics(vec3 n) {
|
||||
vec2 cc = vCausticsCoord.xy;
|
||||
vec2 border = vec2(256.0) / (uRoomSize.zw - uRoomSize.xy);
|
||||
vec2 fade = smoothstep(vec2(0.0), border, cc) * (1.0 - smoothstep(vec2(1.0) - border, vec2(1.0), cc));
|
||||
return texture2D(sReflect, cc).g * max(0.0, -n.y) * fade.x * fade.y;
|
||||
}
|
||||
#endif
|
||||
float randomAngle(vec3 seed, float freq) {
|
||||
return random(seed, freq) * 6.283285;
|
||||
}
|
||||
|
||||
vec3 rotate(vec2 sc, vec2 v) {
|
||||
return vec3(v.x * sc.y + v.y * sc.x, v.x * -sc.x + v.y * sc.y, 0.0);
|
||||
}
|
||||
|
||||
float getShadow(vec4 lightProj) {
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
|
||||
float rShadow = SHADOW(SHADOW_TEXEL * vec3(-0.93289, -0.03146, 0.0) + p) +
|
||||
SHADOW(SHADOW_TEXEL * vec3( 0.81628, -0.05965, 0.0) + p) +
|
||||
SHADOW(SHADOW_TEXEL * vec3(-0.18455, 0.97225, 0.0) + p) +
|
||||
SHADOW(SHADOW_TEXEL * vec3( 0.04032, -0.85898, 0.0) + p);
|
||||
|
||||
if (rShadow > 0.1 && rShadow < 3.9) {
|
||||
float angle = randomAngle(vTexCoord.xyy, 15.0);
|
||||
vec2 sc = vec2(sin(angle), cos(angle));
|
||||
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.54316, 0.21186)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.03925, -0.34345)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.07695, 0.40667)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.66378, -0.54068)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2(-0.54130, 0.66730)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.69301, 0.46990)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.37228, 0.03811)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.28597, 0.80228)) + p);
|
||||
rShadow += SHADOW(SHADOW_TEXEL * rotate(sc, vec2( 0.44801, -0.43844)) + p);
|
||||
rShadow /= 13.0;
|
||||
} else
|
||||
rShadow /= 4.0;
|
||||
|
||||
float fade = clamp(dot(vLightVec.xyz, vLightVec.xyz), 0.0, 1.0);
|
||||
return rShadow + (1.0 - rShadow) * fade;
|
||||
}
|
||||
|
||||
float getShadow() {
|
||||
#ifdef TYPE_ROOM
|
||||
float vis = min(dot(vNormal.xyz, vLightVec.xyz), vLightProj.w);
|
||||
#else
|
||||
float vis = vLightProj.w;
|
||||
#endif
|
||||
return vis > 0.0 ? getShadow(vLightProj) : 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OPT_CONTACT
|
||||
uniform vec4 uContacts[MAX_CONTACTS];
|
||||
#ifdef OPT_CAUSTICS
|
||||
uniform sampler2D sReflect;
|
||||
|
||||
float getContactAO(vec3 p, vec3 n) {
|
||||
float res = 1.0;
|
||||
for (int i = 0; i < MAX_CONTACTS; i++) {
|
||||
vec3 v = uContacts[i].xyz - p;
|
||||
float a = uContacts[i].w;
|
||||
float o = a * clamp(dot(n, v), 0.0, 1.0) / dot(v, v);
|
||||
res *= clamp(1.0 - o, 0.0, 1.0);
|
||||
float calcCaustics(vec3 n) {
|
||||
vec2 cc = vCausticsCoord.xy;
|
||||
vec2 border = vec2(256.0) / (uRoomSize.zw - uRoomSize.xy);
|
||||
vec2 fade = smoothstep(vec2(0.0), border, cc) * (1.0 - smoothstep(vec2(1.0) - border, vec2(1.0), cc));
|
||||
return texture2D(sReflect, cc).x * max(0.0, -n.y) * fade.x * fade.y;
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
|
||||
#ifdef OPT_CONTACT
|
||||
uniform vec4 uContacts[MAX_CONTACTS];
|
||||
|
||||
float getContactAO(vec3 p, vec3 n) {
|
||||
float res = 1.0;
|
||||
for (int i = 0; i < MAX_CONTACTS; i++) {
|
||||
vec3 v = uContacts[i].xyz - p;
|
||||
float a = uContacts[i].w;
|
||||
float o = a * clamp(dot(n, v), 0.0, 1.0) / dot(v, v);
|
||||
res *= clamp(1.0 - o, 0.0, 1.0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
float calcSpecular(vec3 normal, vec3 viewVec, vec3 lightVec, vec4 color, float intensity) {
|
||||
vec3 vv = normalize(viewVec);
|
||||
vec3 rv = reflect(-vv, normal);
|
||||
vec3 lv = normalize(lightVec);
|
||||
return pow(max(0.0, dot(rv, lv)), 8.0) * intensity;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
#ifdef PASS_COMPOSE
|
||||
#ifdef CLIP_PLANE
|
||||
if (vViewVec.w * uParam.z > uParam.w)
|
||||
discard;
|
||||
#endif
|
||||
#ifdef CLIP_PLANE
|
||||
if (vViewVec.w * uParam.z > uParam.w)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
vec4 color;
|
||||
@@ -442,57 +427,56 @@ uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
#else
|
||||
|
||||
#ifndef TYPE_FLASH
|
||||
#ifdef OPT_SHADOW
|
||||
#ifdef PASS_COMPOSE
|
||||
vec3 n = normalize(vNormal.xyz);
|
||||
|
||||
#ifdef PASS_AMBIENT
|
||||
color.xyz *= vLight.x;
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
|
||||
vec3 n = normalize(vNormal.xyz);
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
float rSpecular = uMaterial.z + 0.03;
|
||||
#endif
|
||||
|
||||
#ifdef OPT_SHADOW
|
||||
vec3 light = uLightColor[1].xyz * vLight.y + uLightColor[2].xyz * vLight.z;
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
#if defined(TYPE_ENTITY) || defined(TYPE_ROOM)
|
||||
float rShadow = getShadow();
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
rSpecular *= rShadow;
|
||||
light += vAmbient + uLightColor[0].xyz * (vLight.x * rShadow);
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
light += calcCaustics(n);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TYPE_ROOM
|
||||
|
||||
light += mix(vAmbient.x, vLight.x, getShadow());
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
light += calcCaustics(n);
|
||||
#endif
|
||||
|
||||
#ifdef OPT_CONTACT
|
||||
light *= getContactAO(vCoord, n) * 0.5 + 0.5;
|
||||
#endif
|
||||
|
||||
light += mix(vAmbient.x, vLight.x, rShadow);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TYPE_SPRITE
|
||||
light += vLight.x;
|
||||
#endif
|
||||
|
||||
#ifndef TYPE_MIRROR
|
||||
color.xyz *= light;
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
color.xyz += calcSpecular(n, vViewVec.xyz, vLightVec.xyz, uLightColor[0], (uMaterial.z + 0.03) * rShadow);
|
||||
#endif
|
||||
#else
|
||||
vec3 light = vLight.xyz;
|
||||
#endif
|
||||
|
||||
#ifdef PASS_AMBIENT
|
||||
color.xyz *= vLight.x;
|
||||
#ifdef OPT_CAUSTICS
|
||||
light += calcCaustics(n);
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifndef TYPE_MIRROR
|
||||
color.xyz *= vLight.xyz;
|
||||
#ifdef OPT_CONTACT
|
||||
light *= getContactAO(vCoord, n) * 0.5 + 0.5;
|
||||
#endif
|
||||
|
||||
color.xyz *= light;
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
color.xyz += calcSpecular(n, vViewVec.xyz, vLightVec.xyz, uLightColor[0], rSpecular);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PASS_COMPOSE) && !defined(TYPE_FLASH)
|
||||
#ifdef UNDERWATER
|
||||
color.xyz = mix(UNDERWATER_COLOR * 0.2, color.xyz, vLightVec.w);
|
||||
#else
|
||||
|
@@ -165,7 +165,7 @@ uniform sampler2D sNormal;
|
||||
float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz));
|
||||
float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz));
|
||||
float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w;
|
||||
return vec4(0.0, value, 0.0, 0.0);
|
||||
return vec4(value, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
vec4 mask() {
|
||||
|
11
src/sound.h
11
src/sound.h
@@ -531,8 +531,12 @@ namespace Sound {
|
||||
i += res;
|
||||
}
|
||||
// apply volume
|
||||
#define VOL_CONV(x) (1.0f - sqrtf(1.0f - x * x));
|
||||
|
||||
float m = ((flags & Flags::MUSIC) ? Core::settings.audio.music : Core::settings.audio.sound);
|
||||
float v = volume * m;
|
||||
vec2 pan = getPan();
|
||||
vec2 vol = pan * volume;
|
||||
vec2 vol = pan * VOL_CONV(v);
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (volumeDelta != 0.0f) { // increase / decrease channel volume
|
||||
volume += volumeDelta;
|
||||
@@ -543,11 +547,14 @@ namespace Sound {
|
||||
if (stopAfterFade)
|
||||
isPlaying = false;
|
||||
}
|
||||
vol = pan * volume;
|
||||
v = volume * m;
|
||||
vol = pan * VOL_CONV(v);
|
||||
}
|
||||
frames[j].L = int(frames[j].L * vol.x);
|
||||
frames[j].R = int(frames[j].R * vol.y);
|
||||
}
|
||||
#undef VOL_CONV
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -68,7 +68,7 @@ struct Texture {
|
||||
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? (mips ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mips ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
|
||||
struct FormatDesc {
|
||||
GLuint ifmt, fmt;
|
||||
GLenum type;
|
||||
@@ -119,8 +119,8 @@ struct Texture {
|
||||
|
||||
if (mips) {
|
||||
glGenerateMipmap(target);
|
||||
if (!cube && filter && Core::support.texAniso)
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, min(int(Core::support.texAniso), 8));
|
||||
if (!cube && filter && (Core::support.maxAniso > 0))
|
||||
glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, min(int(Core::support.maxAniso), 8));
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,18 @@ struct Texture {
|
||||
glDeleteTextures(1, &ID);
|
||||
}
|
||||
|
||||
void setFilterQuality(Core::Settings::Quality value) {
|
||||
bool filter = value > Core::Settings::LOW;
|
||||
bool mips = value > Core::Settings::MEDIUM;
|
||||
|
||||
Core::active.textures[0] = NULL;
|
||||
bind(0);
|
||||
if (Core::support.maxAniso > 0)
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value > Core::Settings::MEDIUM ? min(int(Core::support.maxAniso), 8) : 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter ? (mips ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mips ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
|
||||
}
|
||||
|
||||
void bind(int sampler) {
|
||||
if (Core::active.textures[sampler] != this) {
|
||||
Core::active.textures[sampler] = this;
|
||||
|
@@ -373,6 +373,7 @@ struct Door : Controller {
|
||||
s.ceiling = TR::NO_FLOOR;
|
||||
|
||||
if (sectors[i].boxIndex != TR::NO_BOX) {
|
||||
ASSERT(sectors[i].boxIndex < level->boxesCount);
|
||||
TR::Box &box = level->boxes[sectors[i].boxIndex];
|
||||
if (box.overlap.blockable)
|
||||
box.overlap.block = true;
|
||||
|
62
src/ui.h
62
src/ui.h
@@ -6,10 +6,16 @@
|
||||
|
||||
enum StringID {
|
||||
STR_NOT_IMPLEMENTED
|
||||
// help
|
||||
// common
|
||||
, STR_LOADING
|
||||
, STR_HELP_PRESS
|
||||
, STR_HELP_TEXT
|
||||
, STR_OFF
|
||||
, STR_ON
|
||||
, STR_QUALITY_LOW
|
||||
, STR_QUALITY_MEDIUM
|
||||
, STR_QUALITY_HIGH
|
||||
, STR_APPLY
|
||||
// inventory pages
|
||||
, STR_OPTION
|
||||
, STR_INVENTORY
|
||||
@@ -31,6 +37,15 @@ enum StringID {
|
||||
, STR_EXIT_TO_TITLE
|
||||
, STR_EXIT_GAME
|
||||
, STR_SELECT_LEVEL
|
||||
// detail options
|
||||
, STR_SELECT_DETAIL
|
||||
, STR_OPT_DETAIL_FILTER
|
||||
, STR_OPT_DETAIL_LIGHTING
|
||||
, STR_OPT_DETAIL_SHADOWS
|
||||
, STR_OPT_DETAIL_WATER
|
||||
// sound options
|
||||
, STR_SET_VOLUMES
|
||||
, STR_REVERBERATION
|
||||
// inventory items
|
||||
, STR_UNKNOWN
|
||||
, STR_PISTOLS
|
||||
@@ -84,6 +99,12 @@ const char *STR[STR_MAX] = {
|
||||
, "Loading..."
|
||||
, "Press H for help"
|
||||
, helpText
|
||||
, "Off"
|
||||
, "On"
|
||||
, "Low"
|
||||
, "Medium"
|
||||
, "High"
|
||||
, "Apply"
|
||||
// inventory pages
|
||||
, "OPTION"
|
||||
, "INVENTORY"
|
||||
@@ -97,7 +118,7 @@ const char *STR[STR_MAX] = {
|
||||
, "Sound"
|
||||
, "Controls"
|
||||
, "Gamma"
|
||||
// passport options
|
||||
// passport menu
|
||||
, "Autosave"
|
||||
, "Load Game"
|
||||
, "Start Game"
|
||||
@@ -105,6 +126,15 @@ const char *STR[STR_MAX] = {
|
||||
, "Exit to Title"
|
||||
, "Exit Game"
|
||||
, "Select Level"
|
||||
// detail options
|
||||
, "Select Detail"
|
||||
, "Filtering"
|
||||
, "Lighting"
|
||||
, "Shadows"
|
||||
, "Water"
|
||||
// sound options
|
||||
, "Set Volumes"
|
||||
, "Reverberation"
|
||||
// inventory items
|
||||
, "Unknown"
|
||||
, "Pistols"
|
||||
@@ -144,7 +174,13 @@ namespace UI {
|
||||
enum Align { aLeft, aRight, aCenter };
|
||||
|
||||
inline int charRemap(char c) {
|
||||
return c > 10 ? (c > 15 ? char_map[c - 32] : c + 91) : c + 81;
|
||||
ASSERT(c <= 126);
|
||||
if (c < 11)
|
||||
return c + 81;
|
||||
if (c < 16)
|
||||
return c + 91;
|
||||
ASSERT(c >= 32)
|
||||
return char_map[c - 32];
|
||||
}
|
||||
|
||||
vec2 getTextSize(const char *text) {
|
||||
@@ -171,6 +207,7 @@ namespace UI {
|
||||
BAR_HEALTH,
|
||||
BAR_OXYGEN,
|
||||
BAR_OPTION,
|
||||
BAR_WHITE,
|
||||
BAR_MAX,
|
||||
};
|
||||
|
||||
@@ -259,6 +296,19 @@ namespace UI {
|
||||
textOut(pos, STR[str], align, width);
|
||||
}
|
||||
|
||||
void specOut(const vec2 &pos, char specChar) {
|
||||
TR::Level *level = game->getLevel();
|
||||
MeshBuilder *mesh = game->getMesh();
|
||||
|
||||
int seq = level->extra.glyphSeq;
|
||||
|
||||
if (buffer.iCount == MAX_CHARS * 6)
|
||||
flush();
|
||||
|
||||
TR::SpriteTexture &sprite = level->spriteTextures[level->spriteSequences[seq].sStart + specChar];
|
||||
mesh->addSprite(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, 0, int(pos.x), int(pos.y), 0, sprite, 255, true);
|
||||
}
|
||||
|
||||
#undef MAX_CHARS
|
||||
/*
|
||||
Texture *texInv, *texAction;
|
||||
@@ -334,15 +384,15 @@ namespace UI {
|
||||
Core::setDepthTest(true);
|
||||
}
|
||||
|
||||
void renderBar(BarType type, const vec2 &pos, const vec2 &size, float value, uint32 fgColor = 0xFFFFFFFF, uint32 bgColor = 0x80000000, uint32 brColor1 = 0xFF4C504C, uint32 brColor2 = 0xFF748474) {
|
||||
void renderBar(BarType type, const vec2 &pos, const vec2 &size, float value, uint32 fgColor = 0xFFFFFFFF, uint32 bgColor = 0x80000000, uint32 brColor1 = 0xFF4C504C, uint32 brColor2 = 0xFF748474, uint32 fgColor2 = 0) {
|
||||
MeshBuilder *mesh = game->getMesh();
|
||||
|
||||
if (brColor1 != 0 || brColor2 != 0)
|
||||
mesh->addFrame(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, pos - 2.0f, size + 4.0f, brColor1, brColor2);
|
||||
if (bgColor != 0)
|
||||
mesh->addBar(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, whiteTile, pos - 1.0f, size + 2.0f, bgColor);
|
||||
if (fgColor != 0 && value > 0.0f)
|
||||
mesh->addBar(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, barTile[type], pos, vec2(size.x * value, size.y), fgColor);
|
||||
if ((fgColor != 0 || fgColor2 != 0) && value > 0.0f)
|
||||
mesh->addBar(buffer.indices, buffer.vertices, buffer.iCount, buffer.vCount, barTile[type], pos, vec2(size.x * value, size.y), fgColor, fgColor2);
|
||||
}
|
||||
|
||||
void renderHelp() {
|
||||
|
@@ -1030,10 +1030,15 @@ struct Stream {
|
||||
}
|
||||
|
||||
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);
|
||||
#else
|
||||
FILE *f = fopen(name, "wb");
|
||||
if (!f) return;
|
||||
fwrite(data, size, 1, f);
|
||||
fclose(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setPos(int pos) {
|
||||
|
Reference in New Issue
Block a user