1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-10 07:06:52 +02:00

add anaglyph (Red/Cyan) stereo support (WIP)

This commit is contained in:
XProger
2019-05-11 12:44:40 +03:00
parent 4eb418e796
commit 6dfb86f379
20 changed files with 228 additions and 181 deletions

View File

@@ -110,6 +110,7 @@ struct ShaderCache {
compile(Core::passFilter, Shader::FILTER_DOWNSAMPLE, fx, RS_COLOR_WRITE);
compile(Core::passFilter, Shader::FILTER_GRAYSCALE, fx, RS_COLOR_WRITE);
compile(Core::passFilter, Shader::FILTER_BLUR, fx, RS_COLOR_WRITE);
compile(Core::passFilter, Shader::FILTER_ANAGLYPH, fx, RS_COLOR_WRITE);
}
void prepareGUI(int fx) {
@@ -944,7 +945,7 @@ struct WaterCache {
// render reflections frame
float sign = underwater ? -1.0f : 1.0f;
game->setClipParams(sign, waterLevel * sign);
game->renderView(TR::NO_ROOM, false, roomsCount, roomsList);
game->renderView(TR::NO_ROOM, false, false, roomsCount, roomsList);
}
game->setClipParams(1.0f, NO_CLIP_PLANE);

View File

@@ -511,8 +511,8 @@ struct Camera : ICamera {
if (shake > 0.0f)
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_ON)
Core::mViewInv.setPos(Core::mViewInv.getPos() + Core::mViewInv.right().xyz() * (Core::eye * (firstPerson ? 8.0f : 32.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) );
if (reflectPlane) {
Core::mViewInv = mat4(*reflectPlane) * Core::mViewInv;

View File

@@ -74,7 +74,7 @@ struct IGame {
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0, Core::Pass pass = Core::passAmbient) {}
virtual void renderModelFull(int modelIndex, bool underwater, Basis *joints) {}
virtual void renderCompose(int roomIndex) {}
virtual void renderView(int roomIndex, bool water, int roomsCount = 0, int *roomsList = NULL) {}
virtual void renderView(int roomIndex, bool water, bool showUI, int roomsCount = 0, int *roomsList = NULL) {}
virtual void renderGame(bool showUI) {}
virtual void setEffect(Controller *controller, TR::Effect::Type effect) {}

View File

@@ -230,7 +230,7 @@ namespace Core {
struct Settings {
enum Quality { LOW, MEDIUM, HIGH };
enum Stereo { STEREO_OFF, STEREO_ON, STEREO_SPLIT, STEREO_VR };
enum Stereo { STEREO_OFF, STEREO_SBS, STEREO_ANAGLYPH, STEREO_SPLIT, STEREO_VR };
uint8 version;
@@ -280,6 +280,10 @@ namespace Core {
water = value;
#endif
}
bool isStereo() {
return stereo == STEREO_SBS || stereo == STEREO_ANAGLYPH || stereo == STEREO_VR;
}
} detail;
struct {
@@ -509,6 +513,7 @@ struct MeshRange {
E( FILTER_DOWNSAMPLE_DEPTH ) \
E( FILTER_GRAYSCALE ) \
E( FILTER_BLUR ) \
E( FILTER_ANAGLYPH ) \
E( FILTER_EQUIRECTANGULAR ) \
/* options */ \
E( UNDERWATER ) \
@@ -701,6 +706,7 @@ namespace Core {
LOG("OpenLara (%s)\n", version);
x = y = 0;
eyeTex[0] = eyeTex[1] = NULL;
memset(&support, 0, sizeof(support));
support.texMinSize = 1;
@@ -897,6 +903,8 @@ namespace Core {
}
void deinit() {
delete eyeTex[0];
delete eyeTex[1];
delete whiteTex;
delete whiteCube;
delete blackTex;

View File

@@ -130,13 +130,13 @@ static const OptionItem optDetail[] = {
#if defined(_OS_WIN) || defined(_OS_LINUX) || defined(_OS_PSP) || defined(_OS_RPI) || defined(_OS_PSV)
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_VSYNC, SETTINGS( detail.vsync ), STR_OFF, 0, 1 ),
#endif
#ifndef _OS_PSP
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_STEREO, SETTINGS( detail.stereo ), STR_OFF, 0,
#if /*defined(_OS_WIN) ||*/ defined(_OS_ANDROID)
3 /* with VR option */
#else
2 /* without VR support */
#endif
#if !defined(_OS_PSP) && !defined(_OS_PSV) && !defined(_OS_3DS)
OptionItem( OptionItem::TYPE_PARAM, STR_OPT_DETAIL_STEREO, SETTINGS( detail.stereo ), STR_NO_STEREO, 0,
#if /*defined(_OS_WIN) ||*/ defined(_OS_ANDROID)
4 /* with VR option */
#else
3 /* without VR support */
#endif
),
#endif
OptionItem( ),
@@ -1832,7 +1832,7 @@ struct Inventory {
if (Core::settings.detail.stereo == Core::Settings::STEREO_VR)
pos.z -= 256.0f;
if (Core::settings.detail.stereo == Core::Settings::STEREO_ON)
if (Core::settings.detail.stereo == Core::Settings::STEREO_SBS || Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH)
pos.x += Core::eye * 8.0f;
Core::mViewInv = mat4(pos, pos + vec3(0, 0, 1), vec3(0, -1, 0));

View File

@@ -17,6 +17,9 @@ enum StringID {
, STR_NO
, STR_OFF
, STR_ON
, STR_NO_STEREO
, STR_SBS
, STR_ANAGLYPH
, STR_SPLIT
, STR_VR
, STR_QUALITY_LOW

View File

@@ -20,6 +20,9 @@ const char *STR_DE[] = { ""
, "NEIN"
, "Aus"
, "An"
, "Aus"
, "Side-By-Side"
, "Anaglyph"
, "Geteilter Bildschirm"
, "VR"
, "Niedrig"

View File

@@ -20,6 +20,9 @@ const char *STR_EN[] = { ""
, "NO"
, "Off"
, "On"
, "Off"
, "Side-By-Side"
, "Anaglyph"
, "Split Screen"
, "VR"
, "Low"

View File

@@ -20,6 +20,9 @@ const char *STR_ES[] = { ""
, "NO"
, "No"
, "S)i"
, "No"
, "Side-By-Side"
, "Anaglyph"
, "Pantalla dividida"
, "VR"
, "Bajo"

View File

@@ -20,6 +20,9 @@ const char *STR_FI[] = { "Suomi"
, "Ei"
, "Off"
, "On"
, "Off"
, "Side-By-Side"
, "Anaglyph"
, "Jaettu Ruutu"
, "VR"
, "Alhainen"

View File

@@ -20,6 +20,9 @@ const char *STR_FR[] = { ""
, "NON"
, "Arret"
, "Marche"
, "Arret"
, "Side-By-Side"
, "Anaglyph"
, ")Ecran Divis)e"
, "VR"
, "Bas"

View File

@@ -23,6 +23,9 @@ const char *STR_GR[] = { "Ελληνικά"
, "ΟΧΙ"
, "Όχι"
, "Ναι"
, "Όχι"
, "Side-By-Side"
, "Anaglyph"
, "Χωρισμένη Οθόνη"
, "VR"
, "Χαμηλό"
@@ -376,6 +379,9 @@ const char *STR_GR[] = { "\x11\x01\x22\x01\x0F\x01\x0F\x01\x0E\x01\x06\x01\x04\x
, "\x11\x01\x28\x01\x2A\x01\x30\xFF\xFF"
, "\x11\x01\x32\x01\x18\x01\x04\xFF\xFF"
, "\x11\x01\x27\x01\x01\x01\x04\xFF\xFF"
, "\x11\x01\x32\x01\x18\x01\x04\xFF\xFF"
, "Side-By-Side"
, "Anaglyph"
, "\x11\x01\x2A\x01\x16\x01\x07\x01\x04\x01\x09\x01\x0A\x01\x12\x01\x06\x01\x0E\xFF\xFF"" \x11\x01\x28\x01\x19\x01\x13\x01\x06\x01\x0E\xFF\xFF"
, "VR"
, "\x11\x01\x2A\x01\x01\x01\x0A\x01\x0E\x01\x0F\x01\x13\xFF\xFF"

View File

@@ -20,6 +20,9 @@ const char *STR_IT[] = { ""
, "NO"
, "Off"
, "On"
, "Off"
, "Side-By-Side"
, "Anaglyph"
, "Schermo diviso"
, "VR"
, "Basso"

View File

@@ -23,6 +23,9 @@ const char *STR_JA[] = { "日本語"
, "いいえ"
, "オフ"
, "オン"
, "オフ"
, "Side-By-Side"
, "Anaglyph"
, "画面分割"
, "VR"
, "低"
@@ -329,6 +332,9 @@ const char *STR_JA[] = { "\x11\x02\x70\x01\x97\x01\xD6\xFF\xFF"
, "\x11\x01\x0C\x01\x0C\x01\x4B\xFF\xFF"
, "\x11\x01\x3B\x01\x47\xFF\xFF"
, "\x11\x01\x3B\x01\x02\xFF\xFF"
, "\x11\x01\x3B\x01\x47\xFF\xFF"
, "Side-By-Side"
, "Anaglyph"
, "\x11\x02\x69\x02\x66\x01\xCA\x02\x67\xFF\xFF"
, "VR"
, "\x11\x02\x6C\xFF\xFF"

View File

@@ -20,6 +20,9 @@ const char *STR_PL[] = { ""
, "NIE"
, "Wy}l"
, "W}l"
, "Wy}l"
, "Side-By-Side"
, "Anaglyph"
, "Podzielony ekran"
, "VR"
, "Niska"

View File

@@ -20,6 +20,9 @@ const char *STR_PT[] = { ""
, "N+AO"
, "Desligado"
, "Ligado"
, "Desligado"
, "Side-By-Side"
, "Anaglyph"
, "Tela Separada"
, "VR"
, "Baixo"

View File

@@ -24,6 +24,9 @@ const char *STR_RU[] = { ""
, "<EFBFBD><EFBFBD><EFBFBD>"
, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
, "<EFBFBD><EFBFBD><EFBFBD>"
, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>~<7E><><EFBFBD><EFBFBD>{<7B> <20><><EFBFBD><EFBFBD><EFBFBD>"
, "VR"
, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"

View File

@@ -42,7 +42,7 @@ struct Level : IGame {
Lara *players[2], *player;
Camera *camera;
Texture *shadow;
Texture *shadow[2];
struct Params {
float time;
@@ -348,14 +348,16 @@ struct Level : IGame {
}
void initShadow() {
delete shadow;
delete shadow[0];
delete shadow[1];
shadow[0] = shadow[1] = NULL;
if (Core::settings.detail.shadows > Core::Settings::LOW) {
if (level.isTitle())
shadow = new Texture(32, 32, 1, FMT_SHADOW); // init dummy shadow map
shadow[0] = new Texture(32, 32, 1, FMT_SHADOW); // init dummy shadow map
else
shadow = new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, 1, FMT_SHADOW, OPT_TARGET);
} else
shadow = NULL;
shadow[0] = new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, 1, FMT_SHADOW, OPT_TARGET);
}
}
virtual void applySettings(const Core::Settings &settings) {
@@ -587,7 +589,10 @@ struct Level : IGame {
Core::whiteTex->bind(sMask);
Core::whiteTex->bind(sReflect);
Core::whiteCube->bind(sEnvironment);
if (shadow) shadow->bind(sShadow);
Texture *shadowMap = shadow[player->camera->cameraIndex];
if (shadowMap) shadowMap->bind(sShadow);
Core::basis.identity();
}
@@ -607,7 +612,7 @@ struct Level : IGame {
Core::pass = pass;
Texture *target = (targets[0]->opt & OPT_CUBEMAP) ? targets[0] : targets[i * stride];
Core::setTarget(target, NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR, i);
renderView(rIndex, false);
renderView(rIndex, false, false);
}
Core::pass = tmpPass;
@@ -913,7 +918,7 @@ struct Level : IGame {
mesh = new MeshBuilder(&level, atlasRooms);
initEntities();
shadow = NULL;
shadow[0] = shadow[1] = NULL;
camera = NULL;
ambientCache = NULL;
waterCache = NULL;
@@ -981,7 +986,8 @@ struct Level : IGame {
for (int i = 0; i < level.entitiesCount; i++)
delete (Controller*)level.entities[i].controller;
delete shadow;
delete shadow[0];
delete shadow[1];
delete ambientCache;
delete waterCache;
delete zoneCache;
@@ -2382,7 +2388,7 @@ struct Level : IGame {
Core::fogParams = oldFog;
}
virtual void renderView(int roomIndex, bool water, int roomsCount = 0, int *roomsList = NULL) {
virtual void renderView(int roomIndex, bool water, bool showUI, int roomsCount = 0, int *roomsList = NULL) {
PROFILE_MARKER("VIEW");
if (water && waterCache)
@@ -2485,6 +2491,10 @@ struct Level : IGame {
waterCache->blitTexture(screen);
}
if (showUI) {
renderUI();
}
Core::pass = pass;
}
@@ -2533,7 +2543,7 @@ struct Level : IGame {
camera->frustum->calcPlanes(Core::mViewProj);
setup();
renderView(roomIndex, false);
renderView(roomIndex, false, false);
}
/*
void renderShadowEntity(int index, Controller *controller, Controller *player) {
@@ -2635,7 +2645,7 @@ struct Level : IGame {
return count;
}
*/
void renderShadows(int roomIndex) {
void renderShadows(int roomIndex, Texture *shadowMap) {
PROFILE_MARKER("PASS_SHADOW");
if (Core::settings.detail.shadows == Core::Settings::LOW)
@@ -2647,11 +2657,11 @@ struct Level : IGame {
Core::eye = 0.0f;
Core::pass = Core::passShadow;
shadow->unbind(sShadow);
bool colorShadow = shadow->fmt == FMT_RGBA ? true : false;
shadowMap->unbind(sShadow);
bool colorShadow = shadowMap->fmt == FMT_RGBA ? true : false;
if (colorShadow)
Core::setClearColor(vec4(1.0f));
Core::setTarget(shadow, NULL, RT_CLEAR_DEPTH | (colorShadow ? (RT_CLEAR_COLOR | RT_STORE_COLOR) : RT_STORE_DEPTH));
Core::setTarget(shadowMap, NULL, RT_CLEAR_DEPTH | (colorShadow ? (RT_CLEAR_COLOR | RT_STORE_COLOR) : RT_STORE_DEPTH));
//Core::setCullMode(cmBack);
Core::validateRenderState();
@@ -2917,7 +2927,14 @@ struct Level : IGame {
C3D_FrameDrawOn(GAPI::curTarget);
#else
if (Core::settings.detail.stereo != Core::Settings::STEREO_VR) {
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 {
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;
@@ -2934,6 +2951,26 @@ struct Level : IGame {
}
void renderPrepare() {
#ifdef _OS_3DS
Core::settings.detail.stereo = osGet3DSliderState() > 0.0f ? Core::Settings::STEREO_SBS : Core::Settings::STEREO_OFF;
#endif
if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH) {
for (int i = 0; i < 2; i++) {
Texture *&tex = Core::eyeTex[i];
if (!tex || tex->origWidth != Core::width || tex->origHeight != Core::height) {
delete tex;
tex = new Texture(Core::width, Core::height, 1, FMT_RGBA, OPT_TARGET | OPT_NEAREST);
}
}
} else if (Core::settings.detail.stereo != Core::Settings::STEREO_VR) {
delete Core::eyeTex[0];
delete Core::eyeTex[1];
Core::eyeTex[0] = Core::eyeTex[1] = NULL;
}
needRenderGame = !inventory->video && !level.isTitle() && ((inventory->phaseRing < 1.0f && inventory->titleTimer <= 1.0f) || needRedrawTitleBG);
if (inventory->video) {
inventory->render(1.0);
@@ -2944,11 +2981,8 @@ struct Level : IGame {
UI::renderSubs();
UI::end();
}
return;
}
needRenderGame = !inventory->video && !level.isTitle() && ((inventory->phaseRing < 1.0f && inventory->titleTimer <= 1.0f) || needRedrawTitleBG);
if (!needRenderGame)
return;
@@ -2957,36 +2991,29 @@ struct Level : IGame {
needRedrawReflections = false;
}
if (ambientCache)
if (ambientCache) {
ambientCache->processQueue();
}
if (shadow && player)
renderShadows(player->getRoomIndex());
if (shadow[0] && players[0]) {
player = players[0];
renderShadows(player->getRoomIndex(), shadow[0]);
if (players[1]) {
if (!shadow[1]) {
shadow[1] = new Texture(shadow[0]->origWidth, shadow[0]->origHeight, 1, shadow[0]->fmt, shadow[0]->opt);
}
player = players[1];
renderShadows(player->getRoomIndex(), shadow[1]);
}
}
}
void renderGame(bool showUI) {
//if (Core::settings.detail.stereo || Core::settings.detail.splitscreen) {
// Core::setTarget(NULL, CLEAR_ALL);
// Core::validateRenderState();
//}
/* // catsuit test
lara->bakeEnvironment();
lara->visibleMask = Lara::BODY_HEAD | Lara::BODY_ARM_L3 | Lara::BODY_ARM_R3;
*/
/*
// EQUIRECTANGULAR PROJECTION test
if (!cube360)
cube360 = new Texture(1024, 1024, 1, Texture::RGBA, true, NULL, true, false);
renderEnvironment(camera->getRoomIndex(), camera->pos, &cube360, 0, Core::passCompose);
Core::setTarget(NULL, Core::CLEAR_ALL);
setShader(Core::passFilter, Shader::FILTER_EQUIRECTANGULAR);
cube360->bind(sEnvironment);
mesh->renderQuad();
return;
*/
Viewport vp = Core::viewportDef;
void renderEye(int eye, bool showUI) {
float oldEye = Core::eye;
Viewport oldViewport = Core::viewportDef;
GAPI::Texture *oldTarget = Core::defaultTarget;
int viewsCount = players[1] ? 2 : 1;
for (int view = 0; view < viewsCount; view++) {
@@ -2996,99 +3023,45 @@ struct Level : IGame {
setClipParams(1.0f, NO_CLIP_PLANE);
params->waterHeight = params->clipHeight;
if (shadow) {
if (view > 0/* && Core::settings.detail.shadows < Core::Settings::HIGH*/)
renderShadows(player->getRoomIndex()); // render shadows for player2 for all-in-one shadow technique
shadow->bind(sShadow);
}
Core::pass = Core::passCompose;
if (view == 0 && Input::hmd.ready) {
Core::settings.detail.stereo = Core::Settings::STEREO_VR;
GAPI::Texture *oldTarget = Core::defaultTarget;
Viewport vp = Core::viewportDef;
Core::defaultTarget = Core::eyeTex[0];
Core::viewportDef = Viewport(0, 0, Core::defaultTarget->width, Core::defaultTarget->height);
Core::setTarget(NULL,Core::defaultTarget, 0); // changing to 0 and adding defaultTarget parameter
Core::eye = -1.0f;
setup();
renderView(camera->getRoomIndex(), true);
Core::defaultTarget = Core::eyeTex[1];
Core::viewportDef = Viewport(0, 0, Core::defaultTarget->width, Core::defaultTarget->height);
Core::setTarget(NULL, Core::defaultTarget, 0);
Core::eye = 1.0f;
setup();
renderView(camera->getRoomIndex(), true);
//Core::settings.detail.vr = false;
Core::defaultTarget = oldTarget;
Core::setTarget(NULL, Core::defaultTarget, 0);
Core::viewportDef = vp;
}
#ifdef _OS_3DS
Core::settings.detail.stereo = osGet3DSliderState() > 0.0f ? Core::Settings::STEREO_ON : Core::Settings::STEREO_OFF;
#endif
if (Core::settings.detail.stereo == Core::Settings::STEREO_ON) { // left/right SBS stereo
float oldEye = Core::eye;
setViewport(view, -1, false);
setup();
renderView(camera->getRoomIndex(), true);
setViewport(view, 1, false);
setup();
renderView(camera->getRoomIndex(), true);
Core::eye = oldEye;
} else {
setViewport(view, int(Core::eye), false);
setup();
renderView(camera->getRoomIndex(), true);
}
setViewport(view, eye, false);
setup();
renderView(camera->getRoomIndex(), true, showUI);
}
if (showUI) {
Core::Pass pass = Core::pass;
Core::setTarget(NULL, NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR);
Core::resetLights();
for (int view = 0; view < viewsCount; view++) {
player = players[view];
camera = player->camera;
if (!(level.isTitle() || inventory->titleTimer > 0.0f))
inventory->renderBackground();
setClipParams(1.0f, NO_CLIP_PLANE);
params->waterHeight = params->clipHeight;
renderInventoryEye(eye);
if (Core::settings.detail.stereo == Core::Settings::STEREO_ON) { // left/right SBS stereo
float oldEye = Core::eye;
setViewport(view, -1, false);
renderUI();
setViewport(view, 1, false);
renderUI();
Core::eye = oldEye;
} else {
setViewport(view, int(Core::eye), false);
renderUI();
}
}
Core::pass = pass;
}
Core::viewportDef = vp;
Core::defaultTarget = oldTarget;
Core::viewportDef = oldViewport;
Core::eye = oldEye;
player = players[0];
camera = player->camera;
}
// lara->visibleMask = 0xFFFFFFFF; // catsuit test
void renderGame(bool showUI) {
if (Core::eye == 0.0f && Core::settings.detail.isStereo()) {
renderEye(-1, showUI);
renderEye(+1, showUI);
} else {
renderEye(int(Core::eye), showUI);
}
if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH) {
Core::setTarget(NULL, NULL, RT_STORE_COLOR);
setShader(Core::passFilter, Shader::FILTER_ANAGLYPH, false, false);
Core::eyeTex[0]->bind(sDiffuse);
Core::eyeTex[1]->bind(sNormal);
Core::setDepthTest(false);
mesh->renderQuad();
}
}
void renderUI() {
@@ -3179,7 +3152,6 @@ struct Level : IGame {
void renderInventory() {
Core::setTarget(NULL, NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR);
Core::resetLights();
if (!(level.isTitle() || inventory->titleTimer > 0.0f))
@@ -3187,7 +3159,7 @@ struct Level : IGame {
float oldEye = Core::eye;
if ((Core::settings.detail.stereo == Core::Settings::STEREO_ON) || (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT && players[1])) {
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

View File

@@ -8,7 +8,7 @@ struct Shader : GAPI::Shader {
enum Type {
DEFAULT = 0,
SPRITE = 0, FLASH, ROOM, ENTITY, MIRROR,
FILTER_UPSCALE = 0, FILTER_DOWNSAMPLE, FILTER_DOWNSAMPLE_DEPTH, FILTER_GRAYSCALE, FILTER_BLUR, FILTER_EQUIRECTANGULAR,
FILTER_UPSCALE = 0, FILTER_DOWNSAMPLE, FILTER_DOWNSAMPLE_DEPTH, FILTER_GRAYSCALE, FILTER_BLUR, FILTER_ANAGLYPH, FILTER_EQUIRECTANGULAR,
WATER_DROP = 0, WATER_SIMULATE, WATER_CAUSTICS, WATER_RAYS, WATER_MASK, WATER_COMPOSE,
SKY_TEXTURE = 0, SKY_CLOUDS, SKY_CLOUDS_AZURE,
MAX = 6

View File

@@ -17,19 +17,21 @@ uniform vec4 uParam;
uniform sampler2D sDiffuse;
uniform sampler2D sNormal;
vec4 downsample() { // uParam (textureSize, unused, unused, unused)
vec4 color = vec4(0.0);
for (float y = -1.5; y < 2.0; y++)
for (float x = -1.5; x < 2.0; x++) {
vec4 p;
p.xyz = texture2D(sDiffuse, vTexCoord + vec2(x, y) * uParam.x).xyz;
p.w = dot(p.xyz, vec3(0.299, 0.587, 0.114));
p.xyz *= p.w;
color += p;
}
#ifdef FILTER_DOWNSAMPLE
vec4 downsample() { // uParam (textureSize, unused, unused, unused)
vec4 color = vec4(0.0);
for (float y = -1.5; y < 2.0; y++)
for (float x = -1.5; x < 2.0; x++) {
vec4 p;
p.xyz = texture2D(sDiffuse, vTexCoord + vec2(x, y) * uParam.x).xyz;
p.w = dot(p.xyz, vec3(0.299, 0.587, 0.114));
p.xyz *= p.w;
color += p;
}
return vec4(color.xyz / color.w, 1.0);
}
return vec4(color.xyz / color.w, 1.0);
}
#endif
#ifdef FILTER_DOWNSAMPLE_DEPTH
vec4 downsampleDepth() {
@@ -44,24 +46,28 @@ uniform vec4 uParam;
}
#endif
vec4 grayscale() { // uParam (factor, unused, unused, unused)
vec4 color = texture2D(sDiffuse, vTexCoord);
vec3 gray = vec3(dot(color, vec4(0.299, 0.587, 0.114, 0.0)));
return vec4(mix(color.xyz, gray, uParam.w) * uParam.xyz, color.w);
}
#ifdef FILTER_GRAYSCALE
vec4 grayscale() { // uParam (factor, unused, unused, unused)
vec4 color = texture2D(sDiffuse, vTexCoord);
vec3 gray = vec3(dot(color, vec4(0.299, 0.587, 0.114, 0.0)));
return vec4(mix(color.xyz, gray, uParam.w) * uParam.xyz, color.w);
}
#endif
vec4 blur() { // uParam (dirX, dirY, 1 / textureSize, unused)
const vec3 offset = vec3(0.0, 1.3846153846, 3.2307692308);
const vec3 weight = vec3(0.2270270270, 0.3162162162, 0.0702702703);
#ifdef FILTER_BLUR
vec4 blur() { // uParam (dirX, dirY, 1 / textureSize, unused)
const vec3 offset = vec3(0.0, 1.3846153846, 3.2307692308);
const vec3 weight = vec3(0.2270270270, 0.3162162162, 0.0702702703);
vec2 dir = uParam.xy;
vec4 color = texture2D(sDiffuse, vTexCoord) * weight[0];
color += texture2D(sDiffuse, vTexCoord + dir * offset[1]) * weight[1];
color += texture2D(sDiffuse, vTexCoord - dir * offset[1]) * weight[1];
color += texture2D(sDiffuse, vTexCoord + dir * offset[2]) * weight[2];
color += texture2D(sDiffuse, vTexCoord - dir * offset[2]) * weight[2];
return color;
}
vec2 dir = uParam.xy;
vec4 color = texture2D(sDiffuse, vTexCoord) * weight[0];
color += texture2D(sDiffuse, vTexCoord + dir * offset[1]) * weight[1];
color += texture2D(sDiffuse, vTexCoord - dir * offset[1]) * weight[1];
color += texture2D(sDiffuse, vTexCoord + dir * offset[2]) * weight[2];
color += texture2D(sDiffuse, vTexCoord - dir * offset[2]) * weight[2];
return color;
}
#endif
#ifdef FILTER_EQUIRECTANGULAR
uniform samplerCube sEnvironment;
@@ -75,14 +81,24 @@ uniform vec4 uParam;
}
#endif
vec4 upscale() { // https://www.shadertoy.com/view/XsfGDn
vec2 uv = vTexCoord * uParam.xy + 0.5;
vec2 iuv = floor(uv);
vec2 fuv = fract(uv);
uv = iuv + fuv * fuv * (3.0 - 2.0 * fuv);
uv = (uv - 0.5) / uParam.xy;
return texture2D(sDiffuse, uv) * vColor;
}
#ifdef FILTER_UPSCALE
vec4 upscale() { // https://www.shadertoy.com/view/XsfGDn
vec2 uv = vTexCoord * uParam.xy + 0.5;
vec2 iuv = floor(uv);
vec2 fuv = fract(uv);
uv = iuv + fuv * fuv * (3.0 - 2.0 * fuv);
uv = (uv - 0.5) / uParam.xy;
return texture2D(sDiffuse, uv) * vColor;
}
#endif
#ifdef FILTER_ANAGLYPH
vec4 anaglyph() {
vec3 eyeL = texture2D(sDiffuse, vTexCoord).rgb;
vec3 eyeR = texture2D(sNormal, vTexCoord).rgb;
return vec4(eyeL.r, eyeR.g, eyeR.b, 1.0);
}
#endif
vec4 process() {
#ifdef FILTER_DOWNSAMPLE
@@ -105,7 +121,15 @@ uniform vec4 uParam;
return equirectangular();
#endif
return upscale();
#ifdef FILTER_UPSCALE
return upscale();
#endif
#ifdef FILTER_ANAGLYPH
return anaglyph();
#endif
return vec4(1.0);
}
void main() {