From 6dfb86f379a8c262911c1efa40a4decf44e9c8ed Mon Sep 17 00:00:00 2001 From: XProger Date: Sat, 11 May 2019 12:44:40 +0300 Subject: [PATCH] add anaglyph (Red/Cyan) stereo support (WIP) --- src/cache.h | 3 +- src/camera.h | 4 +- src/controller.h | 2 +- src/core.h | 10 +- src/inventory.h | 16 +-- src/lang.h | 3 + src/lang/de.h | 3 + src/lang/en.h | 3 + src/lang/es.h | 3 + src/lang/fi.h | 3 + src/lang/fr.h | 3 + src/lang/gr.h | 6 ++ src/lang/it.h | 3 + src/lang/ja.h | 6 ++ src/lang/pl.h | 3 + src/lang/pt.h | 3 + src/lang/ru.h | 3 + src/level.h | 232 ++++++++++++++++++---------------------- src/shader.h | 2 +- src/shaders/filter.glsl | 98 ++++++++++------- 20 files changed, 228 insertions(+), 181 deletions(-) diff --git a/src/cache.h b/src/cache.h index ad0b757..b832748 100644 --- a/src/cache.h +++ b/src/cache.h @@ -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); diff --git a/src/camera.h b/src/camera.h index e273303..5fe11eb 100644 --- a/src/camera.h +++ b/src/camera.h @@ -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; diff --git a/src/controller.h b/src/controller.h index 6d14269..10676f2 100644 --- a/src/controller.h +++ b/src/controller.h @@ -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) {} diff --git a/src/core.h b/src/core.h index 9e64b10..e4b5d57 100644 --- a/src/core.h +++ b/src/core.h @@ -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; diff --git a/src/inventory.h b/src/inventory.h index ad4b133..f61f323 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -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)); diff --git a/src/lang.h b/src/lang.h index 7d294f3..3e2b9fe 100644 --- a/src/lang.h +++ b/src/lang.h @@ -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 diff --git a/src/lang/de.h b/src/lang/de.h index e9e72e5..2fc7837 100644 --- a/src/lang/de.h +++ b/src/lang/de.h @@ -20,6 +20,9 @@ const char *STR_DE[] = { "" , "NEIN" , "Aus" , "An" + , "Aus" + , "Side-By-Side" + , "Anaglyph" , "Geteilter Bildschirm" , "VR" , "Niedrig" diff --git a/src/lang/en.h b/src/lang/en.h index 413bd2e..f7d26b3 100644 --- a/src/lang/en.h +++ b/src/lang/en.h @@ -20,6 +20,9 @@ const char *STR_EN[] = { "" , "NO" , "Off" , "On" + , "Off" + , "Side-By-Side" + , "Anaglyph" , "Split Screen" , "VR" , "Low" diff --git a/src/lang/es.h b/src/lang/es.h index d388c2a..5d76cb0 100644 --- a/src/lang/es.h +++ b/src/lang/es.h @@ -20,6 +20,9 @@ const char *STR_ES[] = { "" , "NO" , "No" , "S)i" + , "No" + , "Side-By-Side" + , "Anaglyph" , "Pantalla dividida" , "VR" , "Bajo" diff --git a/src/lang/fi.h b/src/lang/fi.h index 78a6eb4..17d6d7f 100644 --- a/src/lang/fi.h +++ b/src/lang/fi.h @@ -20,6 +20,9 @@ const char *STR_FI[] = { "Suomi" , "Ei" , "Off" , "On" + , "Off" + , "Side-By-Side" + , "Anaglyph" , "Jaettu Ruutu" , "VR" , "Alhainen" diff --git a/src/lang/fr.h b/src/lang/fr.h index 86c20dd..452dc91 100644 --- a/src/lang/fr.h +++ b/src/lang/fr.h @@ -20,6 +20,9 @@ const char *STR_FR[] = { "" , "NON" , "Arret" , "Marche" + , "Arret" + , "Side-By-Side" + , "Anaglyph" , ")Ecran Divis)e" , "VR" , "Bas" diff --git a/src/lang/gr.h b/src/lang/gr.h index 09e4a40..7cdbe56 100644 --- a/src/lang/gr.h +++ b/src/lang/gr.h @@ -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" diff --git a/src/lang/it.h b/src/lang/it.h index 25b11bd..eab29f5 100644 --- a/src/lang/it.h +++ b/src/lang/it.h @@ -20,6 +20,9 @@ const char *STR_IT[] = { "" , "NO" , "Off" , "On" + , "Off" + , "Side-By-Side" + , "Anaglyph" , "Schermo diviso" , "VR" , "Basso" diff --git a/src/lang/ja.h b/src/lang/ja.h index 1fff489..00ebf41 100644 --- a/src/lang/ja.h +++ b/src/lang/ja.h @@ -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" diff --git a/src/lang/pl.h b/src/lang/pl.h index c7e0283..2f6b260 100644 --- a/src/lang/pl.h +++ b/src/lang/pl.h @@ -20,6 +20,9 @@ const char *STR_PL[] = { "" , "NIE" , "Wy}l" , "W}l" + , "Wy}l" + , "Side-By-Side" + , "Anaglyph" , "Podzielony ekran" , "VR" , "Niska" diff --git a/src/lang/pt.h b/src/lang/pt.h index f225463..01d470c 100644 --- a/src/lang/pt.h +++ b/src/lang/pt.h @@ -20,6 +20,9 @@ const char *STR_PT[] = { "" , "N+AO" , "Desligado" , "Ligado" + , "Desligado" + , "Side-By-Side" + , "Anaglyph" , "Tela Separada" , "VR" , "Baixo" diff --git a/src/lang/ru.h b/src/lang/ru.h index 553801b..619288e 100644 --- a/src/lang/ru.h +++ b/src/lang/ru.h @@ -24,6 +24,9 @@ const char *STR_RU[] = { "" , "" , "" , "" + , "" + , "" + , "" , "~{ " , "VR" , "" diff --git a/src/level.h b/src/level.h index fcdaef2..2a8d491 100644 --- a/src/level.h +++ b/src/level.h @@ -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 diff --git a/src/shader.h b/src/shader.h index 4a3d4dc..8ef85ba 100644 --- a/src/shader.h +++ b/src/shader.h @@ -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 diff --git a/src/shaders/filter.glsl b/src/shaders/filter.glsl index f542d39..42c3e02 100644 --- a/src/shaders/filter.glsl +++ b/src/shaders/filter.glsl @@ -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() {