From 1067386e650d410d9fdd892eefac1761e1489423 Mon Sep 17 00:00:00 2001 From: XProger Date: Thu, 23 May 2019 01:32:04 +0300 Subject: [PATCH] fix stereo render; add anaglyph --- src/cache.h | 31 +----- src/controller.h | 2 +- src/core.h | 23 +++++ src/gapi/gl.h | 178 +++++++++++++++++++++------------ src/inventory.h | 215 ++++++++++++++++++++++++---------------- src/level.h | 192 ++++++++++++++++++----------------- src/shaders/filter.glsl | 7 +- 7 files changed, 381 insertions(+), 267 deletions(-) diff --git a/src/cache.h b/src/cache.h index b832748..131ec4a 100644 --- a/src/cache.h +++ b/src/cache.h @@ -284,6 +284,11 @@ struct AmbientCache { // second pass - downsample it Core::setDepthTest(false); + mat4 mProj, mView; + mView.identity(); + mProj.identity(); + mProj.scale(vec3(1.0f / 32767.0f)); + Core::setViewProj(mView, mProj); game->setShader(Core::passFilter, Shader::FILTER_DOWNSAMPLE); for (int i = 1; i < 4; i++) { @@ -445,9 +450,6 @@ struct WaterCache { vec3 pos, size; Texture *mask; Texture *caustics; - #ifdef BLUR_CAUSTICS - Texture *caustics_tmp; - #endif Texture *data[2]; Item() { @@ -531,9 +533,6 @@ struct WaterCache { delete[] mf; caustics = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, 1, FMT_RGBA, OPT_TARGET | OPT_DEPEND) : NULL; - #ifdef BLUR_CAUSTICS - caustics_tmp = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, 1, Texture::RGBA) : NULL; - #endif blank = false; } @@ -542,9 +541,6 @@ struct WaterCache { delete data[0]; delete data[1]; delete caustics; - #ifdef BLUR_CAUSTICS - delete caustics_tmp; - #endif delete mask; mask = caustics = data[0] = data[1] = NULL; } @@ -739,23 +735,6 @@ struct WaterCache { Core::validateRenderState(); // force clear color for borders Core::setViewport(1, 1, item.caustics->width - 1, item.caustics->width - 1); // leave 2px for black border game->getMesh()->renderPlane(); - #ifdef BLUR_CAUSTICS - // v blur - Core::setTarget(item.caustics_tmp, CLEAR_ALL); - game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); - Core::active.shader->setParam(uParam, vec4(0, 1, 1.0f / item.caustics->width, 0));; - item.caustics->bind(sDiffuse); - game->getMesh()->renderQuad(); - Core::invalidateTarget(false, true); - - // h blur - Core::setTarget(item.caustics, CLEAR_ALL); - game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); - Core::active.shader->setParam(uParam, vec4(1, 0, 1.0f / item.caustics->width, 0));; - item.caustics_tmp->bind(sDiffuse); - game->getMesh()->renderQuad(); - Core::invalidateTarget(false, true); - #endif } void renderRays() { diff --git a/src/controller.h b/src/controller.h index 10676f2..a141de8 100644 --- a/src/controller.h +++ b/src/controller.h @@ -75,7 +75,7 @@ struct IGame { virtual void renderModelFull(int modelIndex, bool underwater, Basis *joints) {} virtual void renderCompose(int roomIndex) {} virtual void renderView(int roomIndex, bool water, bool showUI, int roomsCount = 0, int *roomsList = NULL) {} - virtual void renderGame(bool showUI) {} + virtual void renderGame(bool showUI, bool invBG) {} virtual void setEffect(Controller *controller, TR::Effect::Type effect) {} virtual void checkTrigger(Controller *controller, bool heavy) {} diff --git a/src/core.h b/src/core.h index e4b5d57..d42d900 100644 --- a/src/core.h +++ b/src/core.h @@ -351,6 +351,7 @@ namespace Core { #include "napi_dummy.h" #endif +#define LIGHT_STACK_SIZE 1 #define MAX_LIGHTS 4 #define MAX_RENDER_BUFFERS 32 #define MAX_CONTACTS 15 @@ -567,6 +568,12 @@ namespace Core { vec4 fogParams; vec4 contacts[MAX_CONTACTS]; + struct LightStack { + vec4 pos[MAX_LIGHTS]; + vec4 color[MAX_LIGHTS]; + } lightStack[LIGHT_STACK_SIZE]; + int lightStackCount; + Texture *whiteTex, *whiteCube, *blackTex, *ditherTex, *noiseTex, *perlinTex; enum Pass { passCompose, passShadow, passAmbient, passSky, passWater, passFilter, passGUI, passMAX } pass; @@ -707,6 +714,7 @@ namespace Core { x = y = 0; eyeTex[0] = eyeTex[1] = NULL; + lightStackCount = 0; memset(&support, 0, sizeof(support)); support.texMinSize = 1; @@ -1101,6 +1109,21 @@ namespace Core { updateLights(); } + void pushLights() { + ASSERT(lightStackCount < LIGHT_STACK_SIZE); + memcpy(lightStack[lightStackCount].pos, lightPos, sizeof(lightPos)); + memcpy(lightStack[lightStackCount].color, lightColor, sizeof(lightColor)); + lightStackCount++; + } + + void popLights() { + ASSERT(lightStackCount > 0); + lightStackCount--; + memcpy(lightPos, lightStack[lightStackCount].pos, sizeof(lightPos)); + memcpy(lightColor, lightStack[lightStackCount].color, sizeof(lightColor)); + updateLights(); + } + void copyTarget(Texture *dst, int xOffset, int yOffset, int x, int y, int width, int height) { validateRenderState(); GAPI::copyTarget(dst, xOffset, yOffset, x, y, width, height); diff --git a/src/gapi/gl.h b/src/gapi/gl.h index e1b1b7c..729297f 100644 --- a/src/gapi/gl.h +++ b/src/gapi/gl.h @@ -13,59 +13,104 @@ #elif _OS_ANDROID #include - #include - #include - #include +// #define _GAPI_GLES2 // for old devices + + #ifdef _GAPI_GLES2 + #include + #include + + #define GL_CLAMP_TO_BORDER 0x812D + #define GL_TEXTURE_BORDER_COLOR 0x1004 + + #define GL_TEXTURE_COMPARE_MODE 0x884C + #define GL_TEXTURE_COMPARE_FUNC 0x884D + #define GL_COMPARE_REF_TO_TEXTURE 0x884E + + #undef GL_RG + #undef GL_RG32F + #undef GL_RG16F + #undef GL_RGBA32F + #undef GL_RGBA16F + #undef GL_HALF_FLOAT + + #define GL_RG GL_RGBA + #define GL_RGBA32F GL_RGBA + #define GL_RGBA16F GL_RGBA + #define GL_RG32F GL_RGBA + #define GL_RG16F GL_RGBA + #define GL_HALF_FLOAT GL_HALF_FLOAT_OES + + #define GL_TEXTURE_3D 0 + #define GL_TEXTURE_WRAP_R 0 + #define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES + #define GL_UNSIGNED_INT_24_8 GL_UNSIGNED_INT_24_8_OES + + #define glTexImage3D(...) 0 + + #define glGenVertexArrays(...) + #define glDeleteVertexArrays(...) + #define glBindVertexArray(...) + + #define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES + #define glGetProgramBinary(...) + #define glProgramBinary(...) + + #define glInvalidateFramebuffer(...) + #else + #include + #include + #include + #endif #elif defined(__SDL2__) #include #if defined(_GAPI_GLES) - #define GL_GLEXT_PROTOTYPES 1 - #include - #include + #define GL_GLEXT_PROTOTYPES 1 + #include + #include - #define GL_CLAMP_TO_BORDER 0x812D - #define GL_TEXTURE_BORDER_COLOR 0x1004 + #define GL_CLAMP_TO_BORDER 0x812D + #define GL_TEXTURE_BORDER_COLOR 0x1004 - #define GL_TEXTURE_COMPARE_MODE 0x884C - #define GL_TEXTURE_COMPARE_FUNC 0x884D - #define GL_COMPARE_REF_TO_TEXTURE 0x884E + #define GL_TEXTURE_COMPARE_MODE 0x884C + #define GL_TEXTURE_COMPARE_FUNC 0x884D + #define GL_COMPARE_REF_TO_TEXTURE 0x884E - #undef GL_RG - #undef GL_RG32F - #undef GL_RG16F - #undef GL_RGBA32F - #undef GL_RGBA16F - #undef GL_HALF_FLOAT + #undef GL_RG + #undef GL_RG32F + #undef GL_RG16F + #undef GL_RGBA32F + #undef GL_RGBA16F + #undef GL_HALF_FLOAT - #define GL_RG GL_RGBA - #define GL_RGBA32F GL_RGBA - #define GL_RGBA16F GL_RGBA - #define GL_RG32F GL_RGBA - #define GL_RG16F GL_RGBA - #define GL_HALF_FLOAT GL_HALF_FLOAT_OES + #define GL_RG GL_RGBA + #define GL_RGBA32F GL_RGBA + #define GL_RGBA16F GL_RGBA + #define GL_RG32F GL_RGBA + #define GL_RG16F GL_RGBA + #define GL_HALF_FLOAT GL_HALF_FLOAT_OES - #define GL_TEXTURE_WRAP_R 0 - #define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES - #define GL_UNSIGNED_INT_24_8 GL_UNSIGNED_INT_24_8_OES + #define GL_TEXTURE_WRAP_R 0 + #define GL_DEPTH_STENCIL GL_DEPTH_STENCIL_OES + #define GL_UNSIGNED_INT_24_8 GL_UNSIGNED_INT_24_8_OES - #define glTexImage3D(...) 0 + #define glTexImage3D(...) 0 #ifndef GL_TEXTURE_3D // WUUUUUT!? - #define GL_TEXTURE_3D GL_TEXTURE_3D_OES + #define GL_TEXTURE_3D GL_TEXTURE_3D_OES #endif - #define glGenVertexArrays(...) - #define glDeleteVertexArrays(...) - #define glBindVertexArray(...) - - #define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES - #define glGetProgramBinary(...) - #define glProgramBinary(...) + #define glGenVertexArrays(...) + #define glDeleteVertexArrays(...) + #define glBindVertexArray(...) + + #define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES + #define glGetProgramBinary(...) + #define glProgramBinary(...) #else - #define GL_GLEXT_PROTOTYPES 1 - #include - #include + #define GL_GLEXT_PROTOTYPES 1 + #include + #include #endif #elif defined(_OS_PSC) @@ -811,7 +856,7 @@ namespace GAPI { glGenerateMipmap(target); if ((opt & (OPT_VOLUME | OPT_CUBEMAP | OPT_NEAREST)) == 0 && (Core::support.maxAniso > 0)) { glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, min(int(Core::support.maxAniso), 8)); - #if !defined(_OS_RPI) && !defined(_OS_CLOVER) // TODO + #if !defined(_OS_RPI) && !defined(_OS_CLOVER) && !defined(_GAPI_GLES2) // TODO glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 3); #endif } @@ -998,14 +1043,12 @@ namespace GAPI { GLuint FBO, defaultFBO; - struct RenderTargetCache { - int count; - struct Item { - GLuint ID; - int width; - int height; - } items[MAX_RENDER_BUFFERS]; - } rtCache[2]; + struct RenderTargetCacheItem { + GLuint ID; + int width; + int height; + }; + Array rtCache[2]; bool extSupport(const char *str, const char *ext) { if (!str) return false; @@ -1013,10 +1056,8 @@ namespace GAPI { } void init() { - memset(rtCache, 0, sizeof(rtCache)); - #ifdef _OS_ANDROID - void *libGL = dlopen("libGLESv2.so", RTLD_LAZY); + //void *libGL = dlopen("libGLESv2.so", RTLD_LAZY); #endif #if defined(_OS_WIN) || defined(_OS_LINUX) @@ -1125,7 +1166,7 @@ namespace GAPI { #ifdef _OS_WEB GLES3 = WEBGL_VERSION != 1; #else - #ifdef _GAPI_GLES + #if defined(_GAPI_GLES) && !defined(_GAPI_GLES2) int GLES_VERSION = 1; #if defined(__SDL2__) SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &GLES_VERSION); @@ -1151,6 +1192,12 @@ namespace GAPI { support.discardFrame = extSupport(ext, "_discard_framebuffer"); support.texNPOT = GLES3 || extSupport(ext, "_texture_npot") || extSupport(ext, "_texture_non_power_of_two"); support.texRG = GLES3 || extSupport(ext, "_texture_rg "); // hope that isn't last extension in string ;) + #ifdef _GAPI_GLES2 // TODO + support.shaderBinary = false; + support.VAO = false; + support.texRG = false; + support.discardFrame = false; + #endif #ifdef _GAPI_GLES support.derivatives = GLES3 || _GL_OES_standard_derivatives; support.tex3D = GLES3; @@ -1282,9 +1329,12 @@ namespace GAPI { glDeleteFramebuffers(1, &FBO); glBindRenderbuffer(GL_RENDERBUFFER, 0); - for (int b = 0; b < 2; b++) - for (int i = 0; i < rtCache[b].count; i++) - glDeleteRenderbuffers(1, &rtCache[b].items[i].ID); + for (int b = 0; b < 2; b++) { + for (int i = 0; i < rtCache[b].length; i++) { + glDeleteRenderbuffers(1, &rtCache[b][i].ID); + } + rtCache[b].clear(); + } } mat4 ortho(float l, float r, float b, float t, float znear, float zfar) { @@ -1315,15 +1365,21 @@ namespace GAPI { } int cacheRenderTarget(bool depth, int width, int height) { - RenderTargetCache &cache = rtCache[depth]; + Array &items = rtCache[depth]; - for (int i = 0; i < cache.count; i++) - if (cache.items[i].width == width && cache.items[i].height == height) - return i; + for (int i = 0; i < items.length; i++) + if (items[i].width == width && items[i].height == height) { + RenderTargetCacheItem item = items[i]; + items.remove(i); + return items.push(item); + } - ASSERT(cache.count < MAX_RENDER_BUFFERS); + if (items.length >= MAX_RENDER_BUFFERS) { + glDeleteRenderbuffers(1, &items[0].ID); + items.remove(0); + } - RenderTargetCache::Item &item = cache.items[cache.count]; + RenderTargetCacheItem item; item.width = width; item.height = height; @@ -1331,7 +1387,7 @@ namespace GAPI { glBindRenderbuffer(GL_RENDERBUFFER, item.ID); glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_DEPTH_COMPONENT16 : GL_RGB565, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); - return cache.count++; + return items.push(item); } void bindTarget(Texture *target, int face) { diff --git a/src/inventory.h b/src/inventory.h index b739ae1..98fc448 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -14,16 +14,16 @@ #define INV_BG_SIZE 512 #endif -#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_HEIGHT 2048.0f +#define INV_EYE_SEPARATION 8.0f +#define INV_EYE_FOCAL_LENGTH 512.0f #define INV_ZNEAR 32.0f #define INV_ZFAR 2048.0f #define INV_FOV 70.0f +#define TITLE_LOADING 64.0f +#define LINE_HEIGHT 20.0f + static const struct OptionItem *waitForKey = NULL; struct OptionItem { @@ -202,7 +202,7 @@ struct Inventory { }; IGame *game; - Texture *background[2]; + Texture *background[3]; // [LEFT EYE or SINGLE, RIGHT EYE, TEMP] Video *video; bool playLogo; @@ -1351,7 +1351,7 @@ struct Inventory { return false; } - Texture* getBackgroundTarget() { + Texture* getBackgroundTarget(int view) { if (background[0] && (background[0]->origWidth != INV_BG_SIZE || background[0]->origHeight != INV_BG_SIZE)) { delete background[0]; background[0] = NULL; @@ -1361,7 +1361,36 @@ struct Inventory { if (!background[i]) background[i] = new Texture(INV_BG_SIZE, INV_BG_SIZE, 1, FMT_RGBA, OPT_TARGET); - return background[0]; + return background[view]; + } + + void blur(Texture *texInOut, Texture *tmp) { + #ifdef FFP + return; // TODO + #endif + game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); + // vertical + Core::setTarget(tmp, NULL, RT_STORE_COLOR); + Core::active.shader->setParam(uParam, vec4(0, 1.0f / INV_BG_SIZE, 0, 0)); + texInOut->bind(sDiffuse); + game->getMesh()->renderQuad(); + // horizontal + Core::setTarget(texInOut, NULL, RT_STORE_COLOR); + game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); + Core::active.shader->setParam(uParam, vec4(1.0f / INV_BG_SIZE, 0, 0, 0)); + tmp->bind(sDiffuse); + game->getMesh()->renderQuad(); + } + + void grayscale(Texture *texIn, Texture *texOut) { + #ifdef FFP + return; // TODO + #endif + game->setShader(Core::passFilter, Shader::FILTER_GRAYSCALE, false, false); + Core::setTarget(texOut, NULL, RT_STORE_COLOR); + Core::active.shader->setParam(uParam, vec4(0.75f, 0.75f, 1.0f, 1.0f)); + texIn->bind(sDiffuse); + game->getMesh()->renderQuad(); } void prepareBackground() { @@ -1371,9 +1400,8 @@ struct Inventory { #ifdef _OS_PSP return; #endif - Core::defaultTarget = getBackgroundTarget(); - game->renderGame(false); - Core::defaultTarget = NULL; + + game->renderGame(false, true); Core::setDepthTest(false); Core::setBlendMode(bmNone); @@ -1385,36 +1413,27 @@ struct Inventory { Core::mModel.identity(); #endif - #ifdef _OS_PSP - // - #else - // 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 / INV_BG_SIZE, 0, 0)); - background[0]->bind(sDiffuse); - game->getMesh()->renderQuad(); + int viewsCount = (Core::settings.detail.stereo == Core::Settings::STEREO_OFF) ? 1 : 2; - // 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 / INV_BG_SIZE, 0, 0, 0)); - background[1]->bind(sDiffuse); - game->getMesh()->renderQuad(); + mat4 mProj, mView; + mView.identity(); + mProj.identity(); + mProj.scale(vec3(1.0f / 32767.0f)); + Core::setViewProj(mView, mProj); - // grayscale - Core::setTarget(background[1], NULL, RT_STORE_COLOR); - game->setShader(Core::passFilter, Shader::FILTER_GRAYSCALE, false, false); - Core::active.shader->setParam(uParam, vec4(0.75f, 0.75f, 1.0f, 1.0f)); - background[0]->bind(sDiffuse); - game->getMesh()->renderQuad(); - - swap(background[0], background[1]); - #endif + for (int view = 0; view < viewsCount; view++) { + blur(background[view], background[2]); + grayscale(background[view], background[2]); + swap(background[view], background[2]); + } Core::setDepthTest(true); } + float getEyeOffset() { + return -Core::eye * INV_EYE_SEPARATION * 0.75f; + } + void renderItemCount(const Item *item, const vec2 &pos, float width) { char spec; switch (item->type) { @@ -1446,11 +1465,13 @@ struct Inventory { if (item->value == 2) str = STR_EXIT_TO_TITLE; } - UI::textOut(vec2(0, 480 - 32), str, UI::aCenter, UI::width); + float eye = getEyeOffset(); + + UI::textOut(vec2(eye, 480 - 32), str, UI::aCenter, UI::width); int 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) UI::specOut(vec2((UI::width - tw) * 0.5f - 32.0f + eye, 480 - 32), 108); + if (item->value < 2) UI::specOut(vec2((UI::width + tw) * 0.5f + 16.0f + eye, 480 - 32), 109); if (item->value != 0) return; @@ -1473,7 +1494,7 @@ struct Inventory { if (item->type == TR::Entity::INV_CONTROLS || item->type == TR::Entity::INV_DETAIL) width += 80; - float x = ( UI::width - width ) * 0.5f; + float x = ( UI::width - width ) * 0.5f + getEyeOffset(); float y = ( UI::height - height ) * 0.5f + LINE_HEIGHT; // background @@ -1540,11 +1561,13 @@ struct Inventory { } void renderItemText(Item *item) { + float eye = getEyeOffset() * 0.5f; + 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(0, 480 - 32), str, UI::aCenter, UI::width); + UI::textOut(vec2(eye, 480 - 32), str, UI::aCenter, UI::width); } renderItemCount(item, vec2(UI::width / 2 - 160, 480 - 96), 320); @@ -1644,7 +1667,7 @@ struct Inventory { } void renderTitleBG(float sx = 1.0f, float sy = 1.0f, uint8 alpha = 255, float cropW = 1.0f, float cropH = 1.0f) { - float aspectSrc, aspectDst, aspectImg, ax, ay, tx, ty; + float aspectSrc, ax, ay, tx, ty; if (background[0]) { Texture *tex = background[0]; @@ -1655,15 +1678,15 @@ struct Inventory { float ox = sx * origW; float oy = sy * origH; aspectSrc = ox / oy; - aspectDst = float(Core::width) / float(Core::height); ax = origW / tex->width; ay = origH / tex->height; } else { tx = ty = 0.0f; aspectSrc = ax = ay = 1.0f; - aspectDst = float(Core::width) / float(Core::height); } - aspectImg = aspectSrc / aspectDst; + + float aspectDst = float(Core::width) / float(Core::height); + float aspectImg = aspectSrc / aspectDst; #ifdef FFP mat4 m; @@ -1673,46 +1696,41 @@ struct Inventory { Core::mModel.scale(vec3(1.0f / 32767.0f)); #endif - Index indices[6 * 3] = { 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11 }; - Vertex vertices[4 * 3]; + short o_frame = 32767; + short i_frame = 16384; - short2 size; + short2 size = short2(short(i_frame * aspectImg), i_frame); if (aspectImg < 1.0f) { - size.x = short(32767 * aspectImg); - size.y = 32767; - - vertices[ 4].coord = short4( -32767, size.y, 0, 0); - vertices[ 5].coord = short4(-size.x, size.y, 0, 0); - vertices[ 6].coord = short4(-size.x, -size.y, 0, 0); - vertices[ 7].coord = short4( -32767, -size.y, 0, 0); - - vertices[ 8].coord = short4( size.x, size.y, 0, 0); - vertices[ 9].coord = short4( 32767, size.y, 0, 0); - vertices[10].coord = short4( 32767, -size.y, 0, 0); - vertices[11].coord = short4( size.x, -size.y, 0, 0); + size.x = short(i_frame * aspectImg); + size.y = i_frame; } else { - size.x = 32767; - size.y = short(32767 / aspectImg); - - vertices[ 4].coord = short4(-size.x, 32767, 0, 0); - vertices[ 5].coord = short4( size.x, 32767, 0, 0); - vertices[ 6].coord = short4( size.x, size.y, 0, 0); - vertices[ 7].coord = short4(-size.x, size.y, 0, 0); - - vertices[ 8].coord = short4(-size.x, -size.y, 0, 0); - vertices[ 9].coord = short4( size.x, -size.y, 0, 0); - vertices[10].coord = short4( size.x, -32767, 0, 0); - vertices[11].coord = short4(-size.x, -32767, 0, 0); + size.x = i_frame; + size.y = short(i_frame / aspectImg); } - short2 t0(short(tx * 32767), short(ty * 32767)); - short2 t1(t0.x + short(ax * 32767), t0.y + short(ay * 32767)); + float eye = -getEyeOffset() * size.x / 320.0f; + if (titleTimer > 0.0f || video) { + eye = 0.0f; + } + + Index indices[10 * 3] = { 0,1,2, 0,2,3, 8,9,5, 8,5,4, 9,10,6, 9,6,5, 10,11,7, 10,7,6, 11,8,4, 11,4,7 }; + Vertex vertices[4 * 3]; vertices[ 0].coord = short4(-size.x, size.y, 0, 0); vertices[ 1].coord = short4( size.x, size.y, 0, 0); vertices[ 2].coord = short4( size.x, -size.y, 0, 0); vertices[ 3].coord = short4(-size.x, -size.y, 0, 0); + vertices[ 4].coord = vertices[0].coord; + vertices[ 5].coord = vertices[1].coord; + vertices[ 6].coord = vertices[2].coord; + vertices[ 7].coord = vertices[3].coord; + + vertices[ 8].coord = short4(-o_frame, o_frame, 0, 0); + vertices[ 9].coord = short4( o_frame, o_frame, 0, 0); + vertices[10].coord = short4( o_frame, -o_frame, 0, 0); + vertices[11].coord = short4(-o_frame, -o_frame, 0, 0); + vertices[ 0].light = vertices[ 1].light = vertices[ 2].light = @@ -1726,6 +1744,9 @@ struct Inventory { vertices[10].light = vertices[11].light = ubyte4(0, 0, 0, alpha); + short2 t0(short(tx * 32767), short(ty * 32767)); + short2 t1(t0.x + short(ax * 32767), t0.y + short(ay * 32767)); + vertices[ 0].texCoord = short4(t0.x, t0.y, 0, 0); vertices[ 1].texCoord = short4(t1.x, t0.y, 0, 0); vertices[ 2].texCoord = short4(t1.x, t1.y, 0, 0); @@ -1747,12 +1768,19 @@ struct Inventory { Core::setBlendMode(alpha < 255 ? bmAlpha : bmNone); + mat4 mProj, mView; + mView.identity(); + mProj.identity(); + mProj.scale(vec3(1.0f / max(size.x, size.y))); + mProj.translate(vec3(eye, 0.0f, 0.0f)); + Core::setViewProj(mView, mProj); + game->setShader(Core::passFilter, Shader::FILTER_UPSCALE, false, false); Core::active.shader->setParam(uParam, vec4(float(Core::active.textures[sDiffuse]->width), float(Core::active.textures[sDiffuse]->height), Core::getTime() * 0.001f, 0.0f)); game->getMesh()->renderBuffer(indices, COUNT(indices), vertices, COUNT(vertices)); } - void renderGameBG() { + void renderGameBG(int view) { Index indices[6] = { 0, 1, 2, 0, 2, 3 }; Vertex vertices[4]; vertices[0].coord = short4(-32767, 32767, 0, 0); @@ -1780,11 +1808,23 @@ struct Inventory { #else if (Core::settings.detail.stereo == Core::Settings::STEREO_VR || !background[0]) { backTex = Core::blackTex; // black background - } else - backTex = background[0]; // blured grayscale image + } else { + // blured grayscale image + if (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT) { + backTex = background[view]; + } else { + backTex = background[Core::eye <= 0.0f ? 0 : 1]; + } + } #endif backTex->bind(sDiffuse); + mat4 mProj, mView; + mView.identity(); + mProj.identity(); + mProj.scale(vec3(1.0f / 32767.0f)); + Core::setViewProj(mView, mProj); + game->setShader(Core::passFilter, Shader::FILTER_UPSCALE, false, false); Core::active.shader->setParam(uParam, vec4(float(Core::active.textures[sDiffuse]->width), float(Core::active.textures[sDiffuse]->height), 0.0f, 0.0f)); @@ -1792,7 +1832,7 @@ struct Inventory { game->getMesh()->renderBuffer(indices, COUNT(indices), vertices, COUNT(vertices)); } - void renderBackground() { + void renderBackground(int view) { if (!isActive() && titleTimer == 0.0f) return; @@ -1813,10 +1853,10 @@ struct Inventory { if (game->getLevel()->isTitle()) renderTitleBG(1.0f, sy, alpha); else - renderGameBG(); + renderGameBG(view); } else { if (background[1]) - renderGameBG(); + renderGameBG(view); else renderTitleBG(1.0f, sy, alpha); } @@ -1947,6 +1987,8 @@ struct Inventory { Core::active.shader->setParam(uViewProj, Core::mViewProj); } + float eye = getEyeOffset() * 0.5f; + if (page == PAGE_SAVEGAME) { 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); @@ -1962,7 +2004,7 @@ struct Inventory { } if (!game->getLevel()->isTitle()) - UI::textOut(vec2(0, 32), pageTitle[page], UI::aCenter, UI::width); + UI::textOut(vec2(eye, 32), pageTitle[page], UI::aCenter, UI::width); if (canFlipPage(-1)) { UI::textOut(vec2(16, 32), "[", UI::aLeft, UI::width); @@ -1974,9 +2016,6 @@ struct Inventory { UI::textOut(vec2( 0, 480 - 16), "]", UI::aRight, UI::width - 20); } - if (index == targetIndex && page == targetPage) - renderItemText(items[getGlobalIndex(page, index)]); - // inventory controls help if (page == targetPage && Input::touchTimerVis <= 0.0f) { float dx = 32.0f; @@ -1990,12 +2029,16 @@ struct Inventory { #endif sprintf(buf, STR[STR_HELP_SELECT], bSelect); - UI::textOut(vec2(dx, 480 - 64), buf, UI::aLeft, UI::width); + UI::textOut(vec2(eye + dx, 480 - 64), buf, UI::aLeft, UI::width); if (chosen) { sprintf(buf, STR[STR_HELP_BACK], bBack); - UI::textOut(vec2(0, 480 - 64), buf, UI::aRight, UI::width - dx); + UI::textOut(vec2(eye, 480 - 64), buf, UI::aRight, UI::width - dx); } } + + if (index == targetIndex && page == targetPage) { + renderItemText(items[getGlobalIndex(page, index)]); + } } }; diff --git a/src/level.h b/src/level.h index 893c8c9..140e933 100644 --- a/src/level.h +++ b/src/level.h @@ -63,6 +63,7 @@ struct Level : IGame { bool needRedrawTitleBG; bool needRedrawReflections; bool needRenderGame; + bool needRenderInventory; bool showStats; bool skyIsVisible; @@ -2512,7 +2513,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, 0.0f); + Core::mProj = GAPI::perspective(90, 1.0f, 32.0f, 45.0f * 1024.0f, 0.0f); Core::mViewProj = Core::mProj * Core::mView; Core::viewPos = Core::mViewInv.offset().xyz(); @@ -2889,7 +2890,7 @@ struct Level : IGame { } #endif - void setViewport(int view, int eye, bool isUI) { + float setViewport(int view, int eye) { int vX = Core::x; int vY = Core::y; int vW = Core::width; @@ -2905,13 +2906,15 @@ struct Level : IGame { } Viewport &vp = Core::viewportDef; + vp = Viewport(vX, vY, vW, vH); - if (players[1] != NULL) { + if (players[1] != NULL && view >= 0) { vp = Viewport(vX + vW / 2 * view, vY, vW / 2, vH); - if (Core::settings.detail.stereo != Core::Settings::STEREO_SPLIT) + + if (Core::settings.detail.stereo != Core::Settings::STEREO_SPLIT) { aspect *= 0.5f; - } else - vp = Viewport(vX, vY, vW, vH); + } + } if (Core::settings.detail.stereo == Core::Settings::STEREO_SBS) { switch (eye) { @@ -2922,10 +2925,7 @@ struct Level : IGame { Core::setViewport(vp.x, vp.y, vp.width, vp.height); - if (isUI) - UI::updateAspect(aspect); - else - camera->aspect = aspect; + return aspect; } void renderPrepare() { @@ -2948,20 +2948,14 @@ struct Level : IGame { } needRenderGame = !inventory->video && !level.isTitle() && ((inventory->phaseRing < 1.0f && inventory->titleTimer <= 1.0f) || needRedrawTitleBG); + needRenderInventory = inventory->video || level.isTitle() || inventory->phaseRing > 0.0f || inventory->titleTimer > 0.0f; - if (inventory->video) { - inventory->render(1.0); + bool title = inventory->isActive() || level.isTitle(); + bool copyBg = title && (lastTitle != title || needRedrawTitleBG); + lastTitle = title; + needRedrawTitleBG = false; - if (UI::subsStr != STR_EMPTY) { - UI::begin(); - UI::updateAspect(float(Core::width) / float(Core::height)); - atlasGlyphs->bind(sDiffuse); - UI::renderSubs(); - UI::end(); - } - } - - if (!needRenderGame) + if (!needRenderGame && !copyBg) return; if (needRedrawReflections) { @@ -2986,39 +2980,44 @@ struct Level : IGame { renderShadows(player->getRoomIndex(), shadow[1]); } } + + if (copyBg) { + inventory->prepareBackground(); + } } - void renderEye(int eye, bool showUI) { + void setDefaultTarget(int eye, int view, bool invBG) { + int texIndex = eye <= 0 ? 0 : 1; + + #ifdef _OS_3DS + Core::eye *= osGet3DSliderState() / 3.0f; + + GAPI::curTarget = GAPI::defTarget[texIndex]; + + C3D_FrameDrawOn(GAPI::curTarget); + #else + if (invBG) { + if (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT) { + Core::defaultTarget = inventory->getBackgroundTarget(view); + } else { + Core::defaultTarget = inventory->getBackgroundTarget(texIndex); + } + } else { + if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH || Core::settings.detail.stereo == Core::Settings::STEREO_VR) { + Core::defaultTarget = invBG ? inventory->getBackgroundTarget(texIndex) : Core::eyeTex[texIndex]; + } + } + #endif + } + + void renderEye(int eye, bool showUI, bool invBG) { float oldEye = Core::eye; Viewport oldViewport = Core::viewportDef; GAPI::Texture *oldTarget = Core::defaultTarget; 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]; - } - } - #endif - if (Core::lightColor[1].x > 0.5f) { - LOG("hello"); - } - - if (needRenderGame) { + if (needRenderGame || invBG) { int viewsCount = players[1] ? 2 : 1; for (int view = 0; view < viewsCount; view++) { player = players[view]; @@ -3029,22 +3028,27 @@ struct Level : IGame { Core::pass = Core::passCompose; - setViewport(view, eye, false); + setDefaultTarget(eye, view, invBG); + + if (Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT) { + camera->aspect = setViewport(invBG ? -1 : view, invBG ? 0 : eye); + } else { + camera->aspect = setViewport(view, invBG ? 0 : eye); + } + 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(); + if (needRenderInventory && !invBG) { + if (players[1] && Core::settings.detail.stereo == Core::Settings::STEREO_SPLIT) { + renderInventoryEye(eye, 0); + renderInventoryEye(eye, 1); + } else { + renderInventoryEye(eye, -1); + } + } Core::defaultTarget = oldTarget; Core::viewportDef = oldViewport; @@ -3056,15 +3060,21 @@ struct Level : IGame { } } - void renderGame(bool showUI) { + void renderGame(bool showUI, bool invBG) { if (Core::eye == 0.0f && Core::settings.detail.isStereo()) { - renderEye(-1, showUI); - renderEye(+1, showUI); + renderEye(-1, showUI, invBG); + renderEye(+1, showUI, invBG); } else { - renderEye(int(Core::eye), showUI); + renderEye(int(Core::eye), showUI, invBG); } - if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH) { + if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH && !invBG) { + mat4 mProj, mView; + mView.identity(); + mProj.identity(); + mProj.scale(vec3(1.0f / 32767.0f)); + Core::setViewProj(mView, mProj); + Core::setTarget(NULL, NULL, RT_STORE_COLOR); setShader(Core::passFilter, Shader::FILTER_ANAGLYPH, false, false); Core::eyeTex[0]->bind(sDiffuse); @@ -3133,24 +3143,32 @@ struct Level : IGame { Core::popLights(); } - void renderInventoryEye(int eye) { - float aspect = float(Core::width) / float(Core::height); + void renderInventoryEye(int eye, int view) { + setDefaultTarget(eye, view, false); - 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; + Core::setTarget(NULL, NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR); + + float aspect = setViewport(view, eye); + + Core::pushLights(); + Core::resetLights(); + + if (inventory->video) { + inventory->render(1.0); + + if (UI::subsStr != STR_EMPTY) { + UI::begin(); + UI::updateAspect(float(Core::width) / float(Core::height)); + atlasGlyphs->bind(sDiffuse); + UI::renderSubs(); + UI::end(); } } - if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH) { - Core::setViewport(Core::x, Core::y, Core::width, Core::height); + if (!inventory->video) { + inventory->renderBackground(max(0, view)); } - if (level.isTitle() || inventory->titleTimer > 0.0f) - inventory->renderBackground(); - setupBinding(); atlasObjects->bind(sDiffuse); inventory->render(aspect); @@ -3158,20 +3176,18 @@ struct Level : IGame { UI::begin(); UI::updateAspect(aspect); atlasGlyphs->bind(sDiffuse); - inventory->renderUI(); + if (!inventory->video) { + inventory->renderUI(); + } else { + UI::renderSubs(); + } UI::end(); + + Core::popLights(); } void render() { - if (inventory->video) - return; - - bool title = inventory->isActive() || level.isTitle(); - bool copyBg = title && (lastTitle != title || needRedrawTitleBG); - lastTitle = title; - needRedrawTitleBG = false; - - if (isEnded) { + if (isEnded && !inventory->video) { Core::setTarget(NULL, NULL, RT_CLEAR_COLOR | RT_STORE_COLOR); UI::begin(); UI::updateAspect(float(Core::width) / float(Core::height)); @@ -3181,11 +3197,7 @@ struct Level : IGame { return; } - if (copyBg) { - inventory->prepareBackground(); - } - - renderGame(true); + renderGame(true, false); } }; diff --git a/src/shaders/filter.glsl b/src/shaders/filter.glsl index 42c3e02..7f872a3 100644 --- a/src/shaders/filter.glsl +++ b/src/shaders/filter.glsl @@ -2,6 +2,7 @@ R"====( varying vec2 vTexCoord; varying vec4 vColor; uniform vec4 uParam; +uniform mat4 uViewProj; #ifdef VERTEX attribute vec4 aCoord; @@ -9,9 +10,9 @@ uniform vec4 uParam; attribute vec4 aLight; void main() { - vTexCoord = aTexCoord.xy; - vColor = aLight; - gl_Position = vec4(aCoord.xy * (1.0 / 32767.0), 0.0, 1.0); + vTexCoord = aTexCoord.xy; + vColor = aLight; + gl_Position = uViewProj * vec4(aCoord.xy, 0.0, 1.0); } #else uniform sampler2D sDiffuse;