mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-11 15:45:05 +02:00
add off-axis (parallel axis asymmetric frustum perspective projection) for stereo mode
This commit is contained in:
15
src/camera.h
15
src/camera.h
@@ -13,6 +13,9 @@
|
||||
#define CAM_SPEED_FOLLOW 12
|
||||
#define CAM_SPEED_COMBAT 8
|
||||
|
||||
#define CAM_FOCAL_LENGTH 1536.0f
|
||||
#define CAM_EYE_SEPARATION 16.0f
|
||||
|
||||
#define CAM_FOLLOW_ANGLE 0.0f
|
||||
#define CAM_LOOK_ANGLE_XMAX ( 55.0f * DEG2RAD)
|
||||
#define CAM_LOOK_ANGLE_XMIN (-75.0f * DEG2RAD)
|
||||
@@ -512,7 +515,7 @@ struct Camera : ICamera {
|
||||
Core::mViewInv.setPos(Core::mViewInv.getPos() + vec3(0.0f, sinf(shake * PI * 7) * shake * 48.0f, 0.0f));
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_SBS || Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH)
|
||||
Core::mViewInv.setPos(Core::mViewInv.getPos() + Core::mViewInv.right().xyz() * (Core::eye * 16.0f) );
|
||||
Core::mViewInv.setPos(Core::mViewInv.getPos() + Core::mViewInv.right().xyz() * (Core::eye * CAM_EYE_SEPARATION) );
|
||||
|
||||
if (reflectPlane) {
|
||||
Core::mViewInv = mat4(*reflectPlane) * Core::mViewInv;
|
||||
@@ -521,17 +524,19 @@ struct Camera : ICamera {
|
||||
|
||||
Core::mView = Core::mViewInv.inverseOrtho();
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
|
||||
Core::mProj = Input::hmd.proj[Core::eye == -1.0f ? 0 : 1];
|
||||
else
|
||||
Core::mProj = GAPI::perspective(fov, aspect, znear, zfar);
|
||||
} else {
|
||||
float eyeSep = (Core::eye * CAM_EYE_SEPARATION) * znear / CAM_FOCAL_LENGTH;
|
||||
Core::mProj = GAPI::perspective(fov, aspect, znear, zfar, eyeSep);
|
||||
}
|
||||
}
|
||||
|
||||
Core::setViewProj(Core::mView, Core::mProj);
|
||||
Core::viewPos = Core::mViewInv.getPos();
|
||||
|
||||
// update room for eye (with HMD offset)
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
|
||||
if (Core::settings.detail.isStereo())
|
||||
level->getSector(eye.room, Core::viewPos.xyz());
|
||||
|
||||
frustum->pos = Core::viewPos.xyz();
|
||||
|
@@ -487,7 +487,7 @@ namespace GAPI {
|
||||
return res;
|
||||
}
|
||||
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar) {
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
|
||||
mat4 m;
|
||||
Mtx_PerspTilt((C3D_Mtx*)&m, fov * DEG2RAD, aspect, znear, zfar, false);
|
||||
|
||||
|
@@ -717,13 +717,16 @@ namespace GAPI {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mat4 ortho(float l, float r, float b, float t, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar);
|
||||
mat4 m;
|
||||
m.ortho(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar);
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar);
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
|
||||
mat4 m;
|
||||
m.perspective(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar, eye);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool beginFrame() {
|
||||
|
@@ -540,11 +540,15 @@ namespace GAPI {
|
||||
}
|
||||
|
||||
mat4 ortho(float l, float r, float b, float t, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar);
|
||||
mat4 m;
|
||||
m.ortho(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar);
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar);
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
|
||||
mat4 m;
|
||||
m.perspective(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar, eye);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool beginFrame() {
|
||||
|
@@ -1288,11 +1288,15 @@ namespace GAPI {
|
||||
}
|
||||
|
||||
mat4 ortho(float l, float r, float b, float t, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_NEG_POS, l, r, b, t, znear, zfar);
|
||||
mat4 m;
|
||||
m.ortho(mat4::PROJ_NEG_POS, l, r, b, t, znear, zfar);
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_NEG_POS, fov, aspect, znear, zfar);
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
|
||||
mat4 m;
|
||||
m.perspective(mat4::PROJ_NEG_POS, fov, aspect, znear, zfar, eye);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool beginFrame() {
|
||||
|
@@ -296,11 +296,15 @@ namespace GAPI {
|
||||
}
|
||||
|
||||
mat4 ortho(float l, float r, float b, float t, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_NEG_POS, l, r, b, t, znear, zfar);
|
||||
mat4 m;
|
||||
m.ortho(mat4::PROJ_NEG_POS, l, r, b, t, znear, zfar);
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_NEG_POS, fov, aspect, znear, zfar);
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
|
||||
mat4 m;
|
||||
m.perspective(mat4::PROJ_NEG_POS, fov, aspect, znear, zfar, eye);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool beginFrame() {
|
||||
|
@@ -1206,11 +1206,15 @@ namespace GAPI {
|
||||
}
|
||||
|
||||
mat4 ortho(float l, float r, float b, float t, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar);
|
||||
mat4 m;
|
||||
m.ortho(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar);
|
||||
return m;
|
||||
}
|
||||
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar) {
|
||||
return mat4(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar);
|
||||
mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
|
||||
mat4 m;
|
||||
m.perspective(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar, eye);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool beginFrame() {
|
||||
|
@@ -6,18 +6,24 @@
|
||||
#include "ui.h"
|
||||
#include "savegame.h"
|
||||
|
||||
#define INVENTORY_MAX_ITEMS 32
|
||||
#define INVENTORY_MAX_RADIUS 688.0f
|
||||
#define INV_MAX_ITEMS 32
|
||||
#define INV_MAX_RADIUS 688.0f
|
||||
#ifdef _OS_PSP
|
||||
#define INVENTORY_BG_SIZE 256
|
||||
#define INV_BG_SIZE 256
|
||||
#else
|
||||
#define INVENTORY_BG_SIZE 512
|
||||
#define INV_BG_SIZE 512
|
||||
#endif
|
||||
|
||||
#define INVENTORY_HEIGHT 2048.0f
|
||||
#define INV_HEIGHT 2048.0f
|
||||
#define TITLE_LOADING 64.0f
|
||||
#define LINE_HEIGHT 20.0f
|
||||
|
||||
#define INV_EYE_SEPARATION 16.0f
|
||||
#define INV_EYE_FOCAL_LENGTH 256.0f
|
||||
#define INV_ZNEAR 32.0f
|
||||
#define INV_ZFAR 2048.0f
|
||||
#define INV_FOV 70.0f
|
||||
|
||||
static const struct OptionItem *waitForKey = NULL;
|
||||
|
||||
struct OptionItem {
|
||||
@@ -539,7 +545,7 @@ struct Inventory {
|
||||
anim->setAnim(0, 0, false);
|
||||
}
|
||||
|
||||
} *items[INVENTORY_MAX_ITEMS];
|
||||
} *items[INV_MAX_ITEMS];
|
||||
|
||||
static void loadTitleBG(Stream *stream, void *userData) {
|
||||
Inventory *inv = (Inventory*)userData;
|
||||
@@ -759,7 +765,7 @@ struct Inventory {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(itemsCount < INVENTORY_MAX_ITEMS);
|
||||
ASSERT(itemsCount < INV_MAX_ITEMS);
|
||||
|
||||
count = min(UNLIMITED_AMMO, count);
|
||||
|
||||
@@ -1346,14 +1352,14 @@ struct Inventory {
|
||||
}
|
||||
|
||||
Texture* getBackgroundTarget() {
|
||||
if (background[0] && (background[0]->origWidth != INVENTORY_BG_SIZE || background[0]->origHeight != INVENTORY_BG_SIZE)) {
|
||||
if (background[0] && (background[0]->origWidth != INV_BG_SIZE || background[0]->origHeight != INV_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, 1, FMT_RGBA, OPT_TARGET);
|
||||
background[i] = new Texture(INV_BG_SIZE, INV_BG_SIZE, 1, FMT_RGBA, OPT_TARGET);
|
||||
|
||||
return background[0];
|
||||
}
|
||||
@@ -1385,14 +1391,14 @@ struct Inventory {
|
||||
// vertical blur
|
||||
Core::setTarget(background[1], NULL, RT_STORE_COLOR);
|
||||
game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false);
|
||||
Core::active.shader->setParam(uParam, vec4(0, 1.0f / INVENTORY_BG_SIZE, 0, 0));
|
||||
Core::active.shader->setParam(uParam, vec4(0, 1.0f / INV_BG_SIZE, 0, 0));
|
||||
background[0]->bind(sDiffuse);
|
||||
game->getMesh()->renderQuad();
|
||||
|
||||
// horizontal blur
|
||||
Core::setTarget(background[0], NULL, RT_STORE_COLOR);
|
||||
game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false);
|
||||
Core::active.shader->setParam(uParam, vec4(1.0f / INVENTORY_BG_SIZE, 0, 0, 0));
|
||||
Core::active.shader->setParam(uParam, vec4(1.0f / INV_BG_SIZE, 0, 0, 0));
|
||||
background[1]->bind(sDiffuse);
|
||||
game->getMesh()->renderQuad();
|
||||
|
||||
@@ -1467,8 +1473,7 @@ struct Inventory {
|
||||
if (item->type == TR::Entity::INV_CONTROLS || item->type == TR::Entity::INV_DETAIL)
|
||||
width += 80;
|
||||
|
||||
float eye = UI::width * Core::eye * 0.02f;
|
||||
float x = ( UI::width - width ) * 0.5f - eye;
|
||||
float x = ( UI::width - width ) * 0.5f;
|
||||
float y = ( UI::height - height ) * 0.5f + LINE_HEIGHT;
|
||||
|
||||
// background
|
||||
@@ -1534,15 +1539,15 @@ struct Inventory {
|
||||
return def;
|
||||
}
|
||||
|
||||
void renderItemText(float eye, Item *item) {
|
||||
void renderItemText(Item *item) {
|
||||
if (item->type == TR::Entity::INV_PASSPORT && phaseChoose == 1.0f) {
|
||||
//
|
||||
} else {
|
||||
StringID str = getItemName(item->desc.str, game->getLevel()->id, item->type);
|
||||
UI::textOut(vec2(-eye, 480 - 32), str, UI::aCenter, UI::width);
|
||||
UI::textOut(vec2(0, 480 - 32), str, UI::aCenter, UI::width);
|
||||
}
|
||||
|
||||
renderItemCount(item, vec2(UI::width / 2 - 160 - eye, 480 - 96), 320);
|
||||
renderItemCount(item, vec2(UI::width / 2 - 160, 480 - 96), 320);
|
||||
|
||||
// show health bar in inventory when selector is over medikit
|
||||
if (item->type == TR::Entity::INV_MEDIKIT_BIG || item->type == TR::Entity::INV_MEDIKIT_SMALL) {
|
||||
@@ -1553,12 +1558,12 @@ struct Inventory {
|
||||
vec2 size = vec2(180, 10);
|
||||
vec2 pos;
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
|
||||
pos = vec2((UI::width - size.x) * 0.5f - eye * 4.0f, 96);
|
||||
pos = vec2((UI::width - size.x) * 0.5f, 96);
|
||||
} else {
|
||||
if (game->getLara(1) && playerIndex == 0) {
|
||||
pos = vec2(32 - eye, 32);
|
||||
pos = vec2(32, 32);
|
||||
} else {
|
||||
pos = vec2(UI::width - 32 - size.x - eye, 32);
|
||||
pos = vec2(UI::width - 32 - size.x, 32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1579,7 +1584,7 @@ struct Inventory {
|
||||
case TR::Entity::INV_GAMMA :
|
||||
case TR::Entity::INV_STOPWATCH :
|
||||
case TR::Entity::INV_MAP :
|
||||
UI::textOut(vec2(-eye, 240), STR_EMPTY, UI::aCenter, UI::width);
|
||||
UI::textOut(vec2(0, 240), STR_EMPTY, UI::aCenter, UI::width);
|
||||
break;
|
||||
default : ;
|
||||
}
|
||||
@@ -1598,9 +1603,9 @@ struct Inventory {
|
||||
|
||||
vec2 cpos(1286, 256 + 1280 * (1.0f - phaseRing));
|
||||
float ringTilt = cpos.angle();
|
||||
float radius = phaseRing * INVENTORY_MAX_RADIUS * phase;
|
||||
float radius = phaseRing * INV_MAX_RADIUS * phase;
|
||||
float collapseAngle = phaseRing * phase * PI - PI;
|
||||
float ringHeight = lerp(float(this->page), float(targetPage), quintic(phasePage)) * INVENTORY_HEIGHT;
|
||||
float ringHeight = lerp(float(this->page), float(targetPage), quintic(phasePage)) * INV_HEIGHT;
|
||||
float angle = getAngle(pageItemIndex[page], count);
|
||||
|
||||
if (phaseSelect < 1.0f)
|
||||
@@ -1626,7 +1631,7 @@ struct Inventory {
|
||||
rd += 296 * phaseChoose;
|
||||
}
|
||||
|
||||
Basis b = basis * Basis(quat(vec3(0, 1, 0), PI + ia - a), vec3(sinf(a), 0, -cosf(a)) * rd - vec3(0, item->desc.page * INVENTORY_HEIGHT - rh, 0));
|
||||
Basis b = basis * Basis(quat(vec3(0, 1, 0), PI + ia - a), vec3(sinf(a), 0, -cosf(a)) * rd - vec3(0, item->desc.page * INV_HEIGHT - rh, 0));
|
||||
|
||||
if (item->type == TR::Entity::INV_COMPASS) {
|
||||
b.rotate(quat(vec3(1.0f, 0.0f, 0.0f), -phaseChoose * PI * 0.1f));
|
||||
@@ -1833,7 +1838,7 @@ struct Inventory {
|
||||
pos.z -= 256.0f;
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_SBS || Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH)
|
||||
pos.x += Core::eye * 8.0f;
|
||||
pos.x += Core::eye * INV_EYE_SEPARATION;
|
||||
|
||||
Core::mViewInv = mat4(pos, pos + vec3(0, 0, 1), vec3(0, -1, 0));
|
||||
|
||||
@@ -1844,10 +1849,12 @@ struct Inventory {
|
||||
} else
|
||||
head.e00 = INF;
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
|
||||
Core::mProj = Input::hmd.proj[Core::eye == -1.0f ? 0 : 1];
|
||||
else
|
||||
Core::mProj = GAPI::perspective(70.0f, aspect, 32.0f, 2048.0f);
|
||||
} else {
|
||||
float eyeSep = Core::eye * INV_EYE_SEPARATION * INV_ZNEAR / INV_EYE_FOCAL_LENGTH;
|
||||
Core::mProj = GAPI::perspective(INV_FOV, aspect, INV_ZNEAR, INV_ZFAR, eyeSep);
|
||||
}
|
||||
|
||||
Core::mView = Core::mViewInv.inverseOrtho();
|
||||
Core::viewPos = Core::mViewInv.getPos();
|
||||
@@ -1935,47 +1942,44 @@ struct Inventory {
|
||||
|
||||
static const StringID pageTitle[PAGE_MAX] = { STR_OPTION, STR_INVENTORY, STR_ITEMS, STR_SAVEGAME, STR_LEVEL_STATS };
|
||||
|
||||
float eye = UI::width * Core::eye * 0.01f;
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
|
||||
setupCamera(1.0f, true);
|
||||
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
||||
eye = 0.0f;
|
||||
}
|
||||
|
||||
if (page == PAGE_SAVEGAME) {
|
||||
UI::renderBar(CTEX_OPTION, vec2(-eye + UI::width / 2 - 120, 240 - 14), vec2(240, LINE_HEIGHT - 6), 1.0f, 0x802288FF, 0, 0, 0);
|
||||
UI::textOut(vec2(-eye, 240), pageTitle[page], UI::aCenter, UI::width);
|
||||
UI::renderBar(CTEX_OPTION, vec2(-eye - 48 * slot + UI::width / 2, 240 + 24 - 16), vec2(48, 18), 1.0f, 0xFFD8377C, 0);
|
||||
UI::textOut(vec2(-eye - 48 + UI::width / 2, 240 + 24), STR_YES, UI::aCenter, 48);
|
||||
UI::textOut(vec2(-eye + UI::width / 2, 240 + 24), STR_NO, UI::aCenter, 48);
|
||||
UI::renderBar(CTEX_OPTION, vec2(UI::width / 2 - 120, 240 - 14), vec2(240, LINE_HEIGHT - 6), 1.0f, 0x802288FF, 0, 0, 0);
|
||||
UI::textOut(vec2(0, 240), pageTitle[page], UI::aCenter, UI::width);
|
||||
UI::renderBar(CTEX_OPTION, vec2(slot + UI::width / 2 - 48, 240 + 24 - 16), vec2(48, 18), 1.0f, 0xFFD8377C, 0);
|
||||
UI::textOut(vec2(UI::width / 2 - 48, 240 + 24), STR_YES, UI::aCenter, 48);
|
||||
UI::textOut(vec2(UI::width / 2, 240 + 24), STR_NO, UI::aCenter, 48);
|
||||
return;
|
||||
}
|
||||
|
||||
if (page == PAGE_LEVEL_STATS) {
|
||||
showLevelStats(vec2(-eye, 180));
|
||||
showLevelStats(vec2(0, 180));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!game->getLevel()->isTitle())
|
||||
UI::textOut(vec2(-eye, 32), pageTitle[page], UI::aCenter, UI::width);
|
||||
UI::textOut(vec2(0, 32), pageTitle[page], UI::aCenter, UI::width);
|
||||
|
||||
if (canFlipPage(-1)) {
|
||||
UI::textOut(vec2(16 - eye, 32), "[", UI::aLeft, UI::width);
|
||||
UI::textOut(vec2(-eye, 32), "[", UI::aRight, UI::width - 20);
|
||||
UI::textOut(vec2(16, 32), "[", UI::aLeft, UI::width);
|
||||
UI::textOut(vec2( 0, 32), "[", UI::aRight, UI::width - 20);
|
||||
}
|
||||
|
||||
if (canFlipPage(1)) {
|
||||
UI::textOut(vec2(16 - eye, 480 - 16), "]", UI::aLeft, UI::width);
|
||||
UI::textOut(vec2(-eye, 480 - 16), "]", UI::aRight, UI::width - 20);
|
||||
UI::textOut(vec2(16, 480 - 16), "]", UI::aLeft, UI::width);
|
||||
UI::textOut(vec2( 0, 480 - 16), "]", UI::aRight, UI::width - 20);
|
||||
}
|
||||
|
||||
if (index == targetIndex && page == targetPage)
|
||||
renderItemText(eye, items[getGlobalIndex(page, index)]);
|
||||
renderItemText(items[getGlobalIndex(page, index)]);
|
||||
|
||||
// inventory controls help
|
||||
if (page == targetPage && Input::touchTimerVis <= 0.0f) {
|
||||
float dx = 32.0f - eye;
|
||||
float dx = 32.0f;
|
||||
char buf[64];
|
||||
const char *bSelect = STR[STR_KEY_FIRST + ikEnter];
|
||||
const char *bBack = STR[STR_KEY_FIRST + Core::settings.controls[playerIndex].keys[cInventory].key];
|
||||
|
@@ -22,7 +22,7 @@ const char *STR_ES[] = { ""
|
||||
, "S)i"
|
||||
, "No"
|
||||
, "Side-By-Side"
|
||||
, "Anaglyph"
|
||||
, "Anaglifo"
|
||||
, "Pantalla dividida"
|
||||
, "VR"
|
||||
, "Bajo"
|
||||
|
@@ -22,7 +22,7 @@ const char *STR_FR[] = { ""
|
||||
, "Marche"
|
||||
, "Arret"
|
||||
, "Side-By-Side"
|
||||
, "Anaglyph"
|
||||
, "Anaglyphe"
|
||||
, ")Ecran Divis)e"
|
||||
, "VR"
|
||||
, "Bas"
|
||||
|
@@ -22,7 +22,7 @@ const char *STR_IT[] = { ""
|
||||
, "On"
|
||||
, "Off"
|
||||
, "Side-By-Side"
|
||||
, "Anaglyph"
|
||||
, "Anaglifo"
|
||||
, "Schermo diviso"
|
||||
, "VR"
|
||||
, "Basso"
|
||||
|
@@ -22,7 +22,7 @@ const char *STR_PL[] = { ""
|
||||
, "W}l"
|
||||
, "Wy}l"
|
||||
, "Side-By-Side"
|
||||
, "Anaglyph"
|
||||
, "Anaglif"
|
||||
, "Podzielony ekran"
|
||||
, "VR"
|
||||
, "Niska"
|
||||
|
@@ -22,7 +22,7 @@ const char *STR_PT[] = { ""
|
||||
, "Ligado"
|
||||
, "Desligado"
|
||||
, "Side-By-Side"
|
||||
, "Anaglyph"
|
||||
, "An)aglifo"
|
||||
, "Tela Separada"
|
||||
, "VR"
|
||||
, "Baixo"
|
||||
|
132
src/level.h
132
src/level.h
@@ -590,7 +590,7 @@ struct Level : IGame {
|
||||
Core::whiteTex->bind(sReflect);
|
||||
Core::whiteCube->bind(sEnvironment);
|
||||
|
||||
Texture *shadowMap = shadow[player->camera->cameraIndex];
|
||||
Texture *shadowMap = shadow[player ? player->camera->cameraIndex : 0];
|
||||
if (shadowMap) shadowMap->bind(sShadow);
|
||||
|
||||
Core::basis.identity();
|
||||
@@ -2512,7 +2512,7 @@ struct Level : IGame {
|
||||
|
||||
Core::mViewInv = mat4(pos, pos + dir, up);
|
||||
Core::mView = Core::mViewInv.inverseOrtho();
|
||||
Core::mProj = GAPI::perspective(90, 1.0f, camera->znear, camera->zfar);
|
||||
Core::mProj = GAPI::perspective(90, 1.0f, camera->znear, camera->zfar, 0.0f);
|
||||
Core::mViewProj = Core::mProj * Core::mView;
|
||||
Core::viewPos = Core::mViewInv.offset().xyz();
|
||||
|
||||
@@ -2527,7 +2527,7 @@ struct Level : IGame {
|
||||
|
||||
Core::mViewInv = mat4(player->mainLightPos, pos, vec3(0, -1, 0));
|
||||
Core::mView = Core::mViewInv.inverseOrtho();
|
||||
Core::mProj = GAPI::perspective(90.0f, 1.0f, znear, zfar);
|
||||
Core::mProj = GAPI::perspective(90.0f, 1.0f, znear, zfar, 0.0f);
|
||||
|
||||
Core::mLightProj = Core::mProj * Core::mView;
|
||||
|
||||
@@ -2913,34 +2913,12 @@ struct Level : IGame {
|
||||
} else
|
||||
vp = Viewport(vX, vY, vW, vH);
|
||||
|
||||
|
||||
Core::eye = float(eye);
|
||||
|
||||
#ifdef _OS_3DS
|
||||
Core::eye *= osGet3DSliderState() / 3.0f;
|
||||
|
||||
if (eye <= 0) {
|
||||
GAPI::curTarget = GAPI::defTarget[0];
|
||||
} else {
|
||||
GAPI::curTarget = GAPI::defTarget[1];
|
||||
}
|
||||
|
||||
C3D_FrameDrawOn(GAPI::curTarget);
|
||||
#else
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH || Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
|
||||
if (eye <= 0) {
|
||||
Core::defaultTarget = Core::eyeTex[0];
|
||||
} else {
|
||||
Core::defaultTarget = Core::eyeTex[1];
|
||||
}
|
||||
Core::setTarget(Core::defaultTarget, NULL, 0);
|
||||
} else {
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_SBS) {
|
||||
switch (eye) {
|
||||
case -1 : vp = Viewport(vX + vp.x - vp.x / 2, vY + vp.y, vp.width / 2, vp.height); break;
|
||||
case +1 : vp = Viewport(vX + vW / 2 + vp.x / 2, vY + vp.y, vp.width / 2, vp.height); break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Core::setViewport(vp.x, vp.y, vp.width, vp.height);
|
||||
|
||||
@@ -3015,35 +2993,67 @@ struct Level : IGame {
|
||||
Viewport oldViewport = Core::viewportDef;
|
||||
GAPI::Texture *oldTarget = Core::defaultTarget;
|
||||
|
||||
int viewsCount = players[1] ? 2 : 1;
|
||||
for (int view = 0; view < viewsCount; view++) {
|
||||
player = players[view];
|
||||
camera = player->camera;
|
||||
Core::eye = float(eye);
|
||||
|
||||
setClipParams(1.0f, NO_CLIP_PLANE);
|
||||
params->waterHeight = params->clipHeight;
|
||||
#ifdef _OS_3DS
|
||||
Core::eye *= osGet3DSliderState() / 3.0f;
|
||||
|
||||
Core::pass = Core::passCompose;
|
||||
|
||||
setViewport(view, eye, false);
|
||||
setup();
|
||||
renderView(camera->getRoomIndex(), true, showUI);
|
||||
if (eye <= 0) {
|
||||
GAPI::curTarget = GAPI::defTarget[0];
|
||||
} else {
|
||||
GAPI::curTarget = GAPI::defTarget[1];
|
||||
}
|
||||
|
||||
Core::setTarget(NULL, NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR);
|
||||
C3D_FrameDrawOn(GAPI::curTarget);
|
||||
#else
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH || Core::settings.detail.stereo == Core::Settings::STEREO_VR) {
|
||||
if (eye <= 0) {
|
||||
Core::defaultTarget = Core::eyeTex[0];
|
||||
} else {
|
||||
Core::defaultTarget = Core::eyeTex[1];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (Core::lightColor[1].x > 0.5f) {
|
||||
LOG("hello");
|
||||
}
|
||||
|
||||
if (needRenderGame) {
|
||||
int viewsCount = players[1] ? 2 : 1;
|
||||
for (int view = 0; view < viewsCount; view++) {
|
||||
player = players[view];
|
||||
camera = player->camera;
|
||||
|
||||
setClipParams(1.0f, NO_CLIP_PLANE);
|
||||
params->waterHeight = params->clipHeight;
|
||||
|
||||
Core::pass = Core::passCompose;
|
||||
|
||||
setViewport(view, eye, false);
|
||||
setup();
|
||||
renderView(camera->getRoomIndex(), true, showUI);
|
||||
}
|
||||
} else {
|
||||
Core::setTarget(NULL, NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR);
|
||||
}
|
||||
|
||||
Core::pushLights();
|
||||
Core::resetLights();
|
||||
|
||||
if (!(level.isTitle() || inventory->titleTimer > 0.0f))
|
||||
inventory->renderBackground();
|
||||
|
||||
renderInventoryEye(eye);
|
||||
Core::popLights();
|
||||
|
||||
Core::defaultTarget = oldTarget;
|
||||
Core::viewportDef = oldViewport;
|
||||
Core::eye = oldEye;
|
||||
|
||||
player = players[0];
|
||||
camera = player->camera;
|
||||
if (player) {
|
||||
camera = player->camera;
|
||||
}
|
||||
}
|
||||
|
||||
void renderGame(bool showUI) {
|
||||
@@ -3067,6 +3077,8 @@ struct Level : IGame {
|
||||
void renderUI() {
|
||||
if (inventory->titleTimer > 1.0f || level.isTitle()) return;
|
||||
|
||||
Core::pushLights();
|
||||
|
||||
UI::begin();
|
||||
UI::updateAspect(camera->aspect);
|
||||
|
||||
@@ -3089,13 +3101,11 @@ struct Level : IGame {
|
||||
if (oxygen <= 0.2f) oxygen = 0.0f;
|
||||
}
|
||||
|
||||
float eye = inventory->active ? 0.0f : UI::width * Core::eye * 0.02f;
|
||||
|
||||
vec2 pos;
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
|
||||
pos = vec2((UI::width - size.x) * 0.5f - eye * 4.0f, 96);
|
||||
pos = vec2((UI::width - size.x) * 0.5f, 96);
|
||||
else
|
||||
pos = vec2(UI::width - 32 - size.x - eye, 32);
|
||||
pos = vec2(UI::width - 32 - size.x, 32);
|
||||
|
||||
if (!player->dozy && (player->stand == Lara::STAND_ONWATER || player->stand == Character::STAND_UNDERWATER)) {
|
||||
UI::renderBar(CTEX_OXYGEN, pos, size, oxygen);
|
||||
@@ -3119,22 +3129,24 @@ struct Level : IGame {
|
||||
UI::renderSubs();
|
||||
|
||||
UI::end();
|
||||
|
||||
Core::popLights();
|
||||
}
|
||||
|
||||
void renderInventoryEye(int eye) {
|
||||
float aspect = float(Core::width) / float(Core::height);
|
||||
|
||||
if (Core::settings.detail.stereo != Core::Settings::STEREO_VR)
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_SBS) {
|
||||
switch (eye) {
|
||||
case -1 : Core::setViewport(Core::x, Core::y, Core::width / 2, Core::height); break;
|
||||
case 0 : Core::setViewport(Core::x, Core::y, Core::width, Core::height); break;
|
||||
case +1 : Core::setViewport(Core::x + Core::width / 2, Core::y, Core::width / 2, Core::height); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT)
|
||||
eye = 0;
|
||||
|
||||
Core::eye = float(eye);
|
||||
if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH) {
|
||||
Core::setViewport(Core::x, Core::y, Core::width, Core::height);
|
||||
}
|
||||
|
||||
if (level.isTitle() || inventory->titleTimer > 0.0f)
|
||||
inventory->renderBackground();
|
||||
@@ -3150,25 +3162,6 @@ struct Level : IGame {
|
||||
UI::end();
|
||||
}
|
||||
|
||||
void renderInventory() {
|
||||
Core::setTarget(NULL, NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR);
|
||||
Core::resetLights();
|
||||
|
||||
if (!(level.isTitle() || inventory->titleTimer > 0.0f))
|
||||
inventory->renderBackground();
|
||||
|
||||
float oldEye = Core::eye;
|
||||
|
||||
if ((Core::settings.detail.stereo == Core::Settings::STEREO_SBS) || (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH) || (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT && players[1])) {
|
||||
renderInventoryEye(-1);
|
||||
renderInventoryEye(+1);
|
||||
} else
|
||||
renderInventoryEye(int(Core::eye));
|
||||
|
||||
Core::setViewport(Core::x, Core::y, Core::width, Core::height);
|
||||
Core::eye = oldEye;
|
||||
}
|
||||
|
||||
void render() {
|
||||
if (inventory->video)
|
||||
return;
|
||||
@@ -3192,10 +3185,7 @@ struct Level : IGame {
|
||||
inventory->prepareBackground();
|
||||
}
|
||||
|
||||
if (needRenderGame)
|
||||
renderGame(true);
|
||||
|
||||
renderInventory();
|
||||
renderGame(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
19
src/ui.h
19
src/ui.h
@@ -643,7 +643,7 @@ namespace UI {
|
||||
delete item.animation;
|
||||
pickups.remove(i);
|
||||
} else {
|
||||
vec2 target = vec2(w - 48.0f - Core::eye * 16.0f - (i % 4) * 96.0f, UI::height - 48.0f - (i / 4) * 96.0f);
|
||||
vec2 target = vec2(w - 48.0f - (i % 4) * 96.0f, UI::height - 48.0f - (i / 4) * 96.0f);
|
||||
item.pos = item.pos.lerp(target, Core::deltaTime * 5.0f);
|
||||
i++;
|
||||
}
|
||||
@@ -710,18 +710,16 @@ namespace UI {
|
||||
#ifdef _NAPI_SOCKET
|
||||
textOut(vec2(16, height - 32), command, aLeft, width - 32, 255, UI::SHADE_GRAY);
|
||||
#endif
|
||||
float eye = UI::width * Core::eye * 0.02f;
|
||||
|
||||
if (hintTime > 0.0f) {
|
||||
textOut(vec2(16 - eye, 32), hintStr, aLeft, width - 32, 255, UI::SHADE_GRAY);
|
||||
textOut(vec2(16, 32), hintStr, aLeft, width - 32, 255, UI::SHADE_GRAY);
|
||||
}
|
||||
|
||||
#if defined(_OS_WEB) || defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_MAC) || defined(_OS_RPI)
|
||||
if (showHelp) {
|
||||
textOut(vec2(32 - eye, 32), STR_HELP_TEXT, aLeft, width - 32, 255, UI::SHADE_GRAY);
|
||||
textOut(vec2(32, 32), STR_HELP_TEXT, aLeft, width - 32, 255, UI::SHADE_GRAY);
|
||||
} else {
|
||||
if (helpTipTime > 0.0f) {
|
||||
textOut(vec2(0 - eye, height - 16), STR_HELP_PRESS, aCenter, width, 255, UI::SHADE_ORANGE);
|
||||
textOut(vec2(0, height - 16), STR_HELP_PRESS, aCenter, width, 255, UI::SHADE_ORANGE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -736,12 +734,10 @@ namespace UI {
|
||||
void renderSubs() {
|
||||
if (!Core::settings.audio.subtitles) return;
|
||||
|
||||
float eye = UI::width * Core::eye * 0.02f;
|
||||
|
||||
if (subsTime > 0.0f) {
|
||||
const char *subs = STR[subsStr] + subsPos;
|
||||
textOut(vec2(16 - eye, height - 48) + vec2(1, 1), subs, aCenterV, width - 32, 255, UI::SHADE_GRAY, true);
|
||||
textOut(vec2(16 - eye, height - 48), subs, aCenterV, width - 32, 255, UI::SHADE_GRAY);
|
||||
textOut(vec2(16, height - 48) + vec2(1, 1), subs, aCenterV, width - 32, 255, UI::SHADE_GRAY, true);
|
||||
textOut(vec2(16, height - 48), subs, aCenterV, width - 32, 255, UI::SHADE_GRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,7 +758,7 @@ namespace UI {
|
||||
|
||||
void setupInventoryShading(vec3 offset) {
|
||||
Core::mView.identity();
|
||||
Core::mProj = GAPI::perspective(1.0f, 1.0f, 1.0f, 2.0f);
|
||||
Core::mProj = GAPI::perspective(1.0f, 1.0f, 1.0f, 2.0f, 0.0f);
|
||||
Core::mLightProj = Core::mProj * Core::mView;
|
||||
|
||||
game->setShader(Core::passCompose, Shader::ENTITY, false, false);
|
||||
@@ -797,6 +793,7 @@ namespace UI {
|
||||
|
||||
mat4 mView = Core::mView;
|
||||
Core::mView.scale(vec3(0.5f));
|
||||
Core::mView.translate(vec3(-Core::eye * CAM_EYE_SEPARATION, 0.0f, 0.0f));
|
||||
Core::setViewProj(Core::mView, Core::mProj);
|
||||
|
||||
vec3 lightOffset = vec3(UI::width - 64.0f, UI::height - 64.0f, 2048.0f);
|
||||
|
36
src/utils.h
36
src/utils.h
@@ -646,13 +646,15 @@ struct mat4 {
|
||||
e33 = 1.0f;
|
||||
}
|
||||
|
||||
mat4(ProjRange range, float l, float r, float b, float t, float znear, float zfar) {
|
||||
void ortho(ProjRange range, float l, float r, float b, float t, float znear, float zfar) {
|
||||
identity();
|
||||
|
||||
e00 = 2.0f / (r - l);
|
||||
e11 = 2.0f / (t - b);
|
||||
e22 = 2.0f / (znear - zfar);
|
||||
e03 = (l + r) / (l - r);
|
||||
e13 = (t + b) / (b - t);
|
||||
|
||||
switch (range) {
|
||||
case PROJ_NEG_POS :
|
||||
e23 = (zfar + znear) / (znear - zfar);
|
||||
@@ -663,18 +665,16 @@ struct mat4 {
|
||||
}
|
||||
}
|
||||
|
||||
mat4(ProjRange range, float fov, float aspect, float znear, float zfar) {
|
||||
float k = 1.0f / tanf(fov * 0.5f * DEG2RAD);
|
||||
void frustum(ProjRange range, float l, float r, float b, float t, float znear, float zfar) {
|
||||
identity();
|
||||
if (aspect >= 1.0f) {
|
||||
e00 = k / aspect;
|
||||
e11 = k;
|
||||
} else {
|
||||
e00 = k;
|
||||
e11 = k * aspect;
|
||||
}
|
||||
e33 = 0.0f;
|
||||
|
||||
e00 = 2.0f * znear / (r - l);
|
||||
e11 = 2.0f * znear / (t - b);
|
||||
e02 = (r + l) / (r - l);
|
||||
e12 = (t + b) / (t - b);
|
||||
e32 = -1.0f;
|
||||
e33 = 0.0f;
|
||||
|
||||
switch (range) {
|
||||
case PROJ_NEG_POS :
|
||||
e22 = (znear + zfar) / (znear - zfar);
|
||||
@@ -687,6 +687,20 @@ struct mat4 {
|
||||
}
|
||||
}
|
||||
|
||||
void perspective(ProjRange range, float fov, float aspect, float znear, float zfar, float eye = 0.0f) {
|
||||
float y = tanf(fov * 0.5f * DEG2RAD) * znear;
|
||||
float x = y;
|
||||
|
||||
if (aspect >= 1.0f) {
|
||||
x = y * aspect;
|
||||
} else {
|
||||
x = y;
|
||||
y /= aspect;
|
||||
}
|
||||
|
||||
frustum(range, -x - eye, x - eye, -y, y, znear, zfar);
|
||||
}
|
||||
|
||||
mat4(const vec3 &from, const vec3 &at, const vec3 &up) {
|
||||
vec3 r, u, d;
|
||||
d = (from - at).normal();
|
||||
|
Reference in New Issue
Block a user