1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-11 23:54:09 +02:00

fix stereo render; add anaglyph

This commit is contained in:
XProger
2019-05-23 01:32:04 +03:00
parent 7f7e2a7b09
commit 1067386e65
7 changed files with 381 additions and 267 deletions

View File

@@ -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() {

View File

@@ -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) {}

View File

@@ -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);

View File

@@ -13,9 +13,54 @@
#elif _OS_ANDROID
#include <dlfcn.h>
// #define _GAPI_GLES2 // for old devices
#ifdef _GAPI_GLES2
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#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 <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <GLES2/gl2ext.h>
#endif
#elif defined(__SDL2__)
#include <SDL2/SDL.h>
@@ -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 {
struct RenderTargetCacheItem {
GLuint ID;
int width;
int height;
} items[MAX_RENDER_BUFFERS];
} rtCache[2];
};
Array<RenderTargetCacheItem> 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<RenderTargetCacheItem> &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) {

View File

@@ -15,15 +15,15 @@
#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_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)]);
}
}
};

View File

@@ -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,14 +2906,16 @@ struct Level : IGame {
}
Viewport &vp = Core::viewportDef;
if (players[1] != NULL) {
vp = Viewport(vX + vW / 2 * view, vY, vW / 2, vH);
if (Core::settings.detail.stereo != Core::Settings::STEREO_SPLIT)
aspect *= 0.5f;
} else
vp = Viewport(vX, vY, vW, vH);
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) {
aspect *= 0.5f;
}
}
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;
@@ -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);
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);
}
};

View File

@@ -2,6 +2,7 @@ R"====(
varying vec2 vTexCoord;
varying vec4 vColor;
uniform vec4 uParam;
uniform mat4 uViewProj;
#ifdef VERTEX
attribute vec4 aCoord;
@@ -11,7 +12,7 @@ uniform vec4 uParam;
void main() {
vTexCoord = aTexCoord.xy;
vColor = aLight;
gl_Position = vec4(aCoord.xy * (1.0 / 32767.0), 0.0, 1.0);
gl_Position = uViewProj * vec4(aCoord.xy, 0.0, 1.0);
}
#else
uniform sampler2D sDiffuse;