2016-09-14 18:01:13 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright(C) 2016 Magnus Norddahl
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
|
|
//
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
2016-07-29 22:02:26 +00:00
|
|
|
/*
|
|
|
|
** gl_postprocess.cpp
|
|
|
|
** Post processing effects in the render pipeline
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
2018-05-16 21:34:52 +00:00
|
|
|
#include "gl_load/gl_system.h"
|
2016-07-29 22:02:26 +00:00
|
|
|
#include "gi.h"
|
|
|
|
#include "m_png.h"
|
|
|
|
#include "r_utility.h"
|
|
|
|
#include "d_player.h"
|
|
|
|
#include "gl/system/gl_framebuffer.h"
|
2018-04-25 18:33:55 +00:00
|
|
|
#include "hwrenderer/utility/hw_cvars.h"
|
2016-08-17 21:18:47 +00:00
|
|
|
#include "gl/system/gl_debug.h"
|
2016-07-29 22:02:26 +00:00
|
|
|
#include "gl/renderer/gl_lightdata.h"
|
|
|
|
#include "gl/renderer/gl_renderstate.h"
|
|
|
|
#include "gl/renderer/gl_renderbuffers.h"
|
|
|
|
#include "gl/renderer/gl_renderer.h"
|
2016-08-05 15:12:00 +00:00
|
|
|
#include "gl/renderer/gl_postprocessstate.h"
|
2016-07-29 22:02:26 +00:00
|
|
|
#include "gl/data/gl_vertexbuffer.h"
|
2016-08-29 11:10:22 +00:00
|
|
|
#include "gl/shaders/gl_ambientshader.h"
|
2016-07-29 22:02:26 +00:00
|
|
|
#include "gl/shaders/gl_bloomshader.h"
|
|
|
|
#include "gl/shaders/gl_blurshader.h"
|
|
|
|
#include "gl/shaders/gl_tonemapshader.h"
|
2016-09-01 15:14:51 +00:00
|
|
|
#include "gl/shaders/gl_colormapshader.h"
|
2016-08-02 15:32:21 +00:00
|
|
|
#include "gl/shaders/gl_lensshader.h"
|
2016-09-25 09:25:01 +00:00
|
|
|
#include "gl/shaders/gl_fxaashader.h"
|
2016-07-29 22:02:26 +00:00
|
|
|
#include "gl/shaders/gl_presentshader.h"
|
2018-04-02 10:28:20 +00:00
|
|
|
#include "gl/shaders/gl_postprocessshaderinstance.h"
|
2016-09-07 19:52:43 +00:00
|
|
|
#include "gl/stereo3d/gl_stereo3d.h"
|
2018-04-24 20:37:52 +00:00
|
|
|
#include "gl/textures/gl_hwtexture.h"
|
2017-07-27 07:05:01 +00:00
|
|
|
#include "r_videoscale.h"
|
2016-07-29 22:02:26 +00:00
|
|
|
|
2016-08-08 14:06:02 +00:00
|
|
|
void FGLRenderer::RenderScreenQuad()
|
2016-08-06 12:12:40 +00:00
|
|
|
{
|
|
|
|
mVBO->BindVBO();
|
|
|
|
gl_RenderState.ResetVertexBuffer();
|
2016-08-29 08:43:03 +00:00
|
|
|
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4);
|
2016-08-06 12:12:40 +00:00
|
|
|
}
|
|
|
|
|
2018-01-06 04:11:12 +00:00
|
|
|
void FGLRenderer::PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
|
2016-08-29 11:10:22 +00:00
|
|
|
{
|
2016-09-03 02:12:00 +00:00
|
|
|
mBuffers->BlitSceneToTexture();
|
2016-08-29 11:10:22 +00:00
|
|
|
UpdateCameraExposure();
|
2017-07-06 03:36:01 +00:00
|
|
|
mCustomPostProcessShaders->Run("beforebloom");
|
2017-03-12 20:57:39 +00:00
|
|
|
BloomScene(fixedcm);
|
2018-01-06 04:11:12 +00:00
|
|
|
afterBloomDrawEndScene2D();
|
2016-08-29 11:10:22 +00:00
|
|
|
TonemapScene();
|
2017-03-12 20:57:39 +00:00
|
|
|
ColormapScene(fixedcm);
|
2016-08-29 11:10:22 +00:00
|
|
|
LensDistortScene();
|
2016-10-03 22:01:03 +00:00
|
|
|
ApplyFXAA();
|
2017-07-06 03:36:01 +00:00
|
|
|
mCustomPostProcessShaders->Run("scene");
|
2016-08-29 11:10:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Adds ambient occlusion to the scene
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void FGLRenderer::AmbientOccludeScene()
|
|
|
|
{
|
|
|
|
FGLDebug::PushGroup("AmbientOccludeScene");
|
|
|
|
|
|
|
|
FGLPostProcessState savedState;
|
2016-10-05 05:57:27 +00:00
|
|
|
savedState.SaveTextureBindings(3);
|
2016-08-29 11:10:22 +00:00
|
|
|
|
|
|
|
float bias = gl_ssao_bias;
|
|
|
|
float aoRadius = gl_ssao_radius;
|
2016-10-09 04:17:48 +00:00
|
|
|
const float blurAmount = gl_ssao_blur;
|
2016-08-29 23:09:21 +00:00
|
|
|
float aoStrength = gl_ssao_strength;
|
2016-08-29 11:10:22 +00:00
|
|
|
|
|
|
|
//float tanHalfFovy = tan(fovy * (M_PI / 360.0f));
|
2016-09-09 07:47:46 +00:00
|
|
|
float tanHalfFovy = 1.0f / gl_RenderState.mProjectionMatrix.get()[5];
|
2016-09-01 05:15:40 +00:00
|
|
|
float invFocalLenX = tanHalfFovy * (mBuffers->GetSceneWidth() / (float)mBuffers->GetSceneHeight());
|
2016-08-29 11:10:22 +00:00
|
|
|
float invFocalLenY = tanHalfFovy;
|
|
|
|
float nDotVBias = clamp(bias, 0.0f, 1.0f);
|
|
|
|
float r2 = aoRadius * aoRadius;
|
|
|
|
|
2016-09-10 20:39:09 +00:00
|
|
|
float blurSharpness = 1.0f / blurAmount;
|
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
const auto &mSceneViewport = screen->mSceneViewport;
|
|
|
|
const auto &mScreenViewport = screen->mScreenViewport;
|
|
|
|
|
2016-10-06 05:36:49 +00:00
|
|
|
float sceneScaleX = mSceneViewport.width / (float)mScreenViewport.width;
|
|
|
|
float sceneScaleY = mSceneViewport.height / (float)mScreenViewport.height;
|
|
|
|
float sceneOffsetX = mSceneViewport.left / (float)mScreenViewport.width;
|
|
|
|
float sceneOffsetY = mSceneViewport.top / (float)mScreenViewport.height;
|
|
|
|
|
|
|
|
int randomTexture = clamp(gl_ssao - 1, 0, FGLRenderBuffers::NumAmbientRandomTextures - 1);
|
|
|
|
|
2016-08-29 11:10:22 +00:00
|
|
|
// Calculate linear depth values
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->LinearDepthFB.Bind();
|
2016-08-29 11:10:22 +00:00
|
|
|
glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight);
|
|
|
|
mBuffers->BindSceneDepthTexture(0);
|
2016-09-04 06:15:29 +00:00
|
|
|
mBuffers->BindSceneColorTexture(1);
|
2016-10-05 05:57:27 +00:00
|
|
|
mLinearDepthShader->Bind();
|
|
|
|
mLinearDepthShader->DepthTexture.Set(0);
|
|
|
|
mLinearDepthShader->ColorTexture.Set(1);
|
2018-06-11 18:48:43 +00:00
|
|
|
if (gl_multisample > 1) mLinearDepthShader->Uniforms->SampleIndex = 0;
|
|
|
|
mLinearDepthShader->Uniforms->LinearizeDepthA = 1.0f / GetZFar() - 1.0f / GetZNear();
|
|
|
|
mLinearDepthShader->Uniforms->LinearizeDepthB = MAX(1.0f / GetZNear(), 1.e-8f);
|
|
|
|
mLinearDepthShader->Uniforms->InverseDepthRangeA = 1.0f;
|
|
|
|
mLinearDepthShader->Uniforms->InverseDepthRangeB = 0.0f;
|
|
|
|
mLinearDepthShader->Uniforms->Scale = { sceneScaleX, sceneScaleY };
|
|
|
|
mLinearDepthShader->Uniforms->Offset = { sceneOffsetX, sceneOffsetY };
|
|
|
|
mLinearDepthShader->Uniforms.Set();
|
2016-08-29 11:10:22 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
|
|
|
|
// Apply ambient occlusion
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->AmbientFB1.Bind();
|
|
|
|
mBuffers->LinearDepthTexture.Bind(0);
|
|
|
|
mBuffers->AmbientRandomTexture[randomTexture].Bind(1, GL_NEAREST, GL_REPEAT);
|
2016-10-05 05:57:27 +00:00
|
|
|
mBuffers->BindSceneNormalTexture(2);
|
2016-08-29 11:10:22 +00:00
|
|
|
mSSAOShader->Bind();
|
|
|
|
mSSAOShader->DepthTexture.Set(0);
|
2016-08-29 23:09:21 +00:00
|
|
|
mSSAOShader->RandomTexture.Set(1);
|
2016-10-05 05:57:27 +00:00
|
|
|
mSSAOShader->NormalTexture.Set(2);
|
2018-06-11 18:48:43 +00:00
|
|
|
if (gl_multisample > 1) mSSAOShader->Uniforms->SampleIndex = 0;
|
|
|
|
mSSAOShader->Uniforms->UVToViewA = { 2.0f * invFocalLenX, 2.0f * invFocalLenY };
|
|
|
|
mSSAOShader->Uniforms->UVToViewB = { -invFocalLenX, -invFocalLenY };
|
|
|
|
mSSAOShader->Uniforms->InvFullResolution = { 1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight };
|
|
|
|
mSSAOShader->Uniforms->NDotVBias = nDotVBias;
|
|
|
|
mSSAOShader->Uniforms->NegInvR2 = -1.0f / r2;
|
|
|
|
mSSAOShader->Uniforms->RadiusToScreen = aoRadius * 0.5 / tanHalfFovy * mBuffers->AmbientHeight;
|
|
|
|
mSSAOShader->Uniforms->AOMultiplier = 1.0f / (1.0f - nDotVBias);
|
|
|
|
mSSAOShader->Uniforms->AOStrength = aoStrength;
|
|
|
|
mSSAOShader->Uniforms->Scale = { sceneScaleX, sceneScaleY };
|
|
|
|
mSSAOShader->Uniforms->Offset = { sceneOffsetX, sceneOffsetY };
|
|
|
|
mSSAOShader->Uniforms.Set();
|
2016-08-29 11:10:22 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
|
|
|
|
// Blur SSAO texture
|
2016-10-06 05:36:49 +00:00
|
|
|
if (gl_ssao_debug < 2)
|
|
|
|
{
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->AmbientFB0.Bind();
|
|
|
|
mBuffers->AmbientTexture1.Bind(0);
|
2016-10-06 05:36:49 +00:00
|
|
|
mDepthBlurShader->Bind(false);
|
2018-06-11 18:48:43 +00:00
|
|
|
mDepthBlurShader->Uniforms[false]->BlurSharpness = blurSharpness;
|
|
|
|
mDepthBlurShader->Uniforms[false]->InvFullResolution = { 1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight };
|
|
|
|
mDepthBlurShader->Uniforms[false].Set();
|
2016-10-06 05:36:49 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->AmbientFB1.Bind();
|
|
|
|
mBuffers->AmbientTexture0.Bind(0);
|
2016-10-06 05:36:49 +00:00
|
|
|
mDepthBlurShader->Bind(true);
|
2018-06-11 18:48:43 +00:00
|
|
|
mDepthBlurShader->Uniforms[true]->BlurSharpness = blurSharpness;
|
|
|
|
mDepthBlurShader->Uniforms[true]->InvFullResolution = { 1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight };
|
|
|
|
mDepthBlurShader->Uniforms[true]->PowExponent = gl_ssao_exponent;
|
|
|
|
mDepthBlurShader->Uniforms[true].Set();
|
2016-10-06 05:36:49 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
}
|
2016-08-29 11:10:22 +00:00
|
|
|
|
|
|
|
// Add SSAO back to scene texture:
|
2016-09-21 00:04:56 +00:00
|
|
|
mBuffers->BindSceneFB(false);
|
2018-05-12 15:23:56 +00:00
|
|
|
glViewport(screen->mSceneViewport.left, screen->mSceneViewport.top, screen->mSceneViewport.width, screen->mSceneViewport.height);
|
2016-08-29 11:10:22 +00:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
2016-10-06 05:36:49 +00:00
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
if (gl_ssao_debug != 0)
|
2016-10-05 05:57:27 +00:00
|
|
|
{
|
|
|
|
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->AmbientTexture1.Bind(0, GL_LINEAR);
|
2016-10-05 05:57:27 +00:00
|
|
|
mBuffers->BindSceneFogTexture(1);
|
|
|
|
mSSAOCombineShader->Bind();
|
|
|
|
mSSAOCombineShader->AODepthTexture.Set(0);
|
|
|
|
mSSAOCombineShader->SceneFogTexture.Set(1);
|
2018-06-11 18:48:43 +00:00
|
|
|
if (gl_multisample > 1) mSSAOCombineShader->Uniforms->SampleCount = gl_multisample;
|
|
|
|
mSSAOCombineShader->Uniforms->Scale = { sceneScaleX, sceneScaleY };
|
|
|
|
mSSAOCombineShader->Uniforms->Offset = { sceneOffsetX, sceneOffsetY };
|
|
|
|
mSSAOCombineShader->Uniforms.Set();
|
2016-08-29 11:10:22 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
|
|
|
}
|
|
|
|
|
2016-09-18 13:57:22 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Extracts light average from the scene and updates the camera exposure texture
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void FGLRenderer::UpdateCameraExposure()
|
|
|
|
{
|
|
|
|
if (!gl_bloom && gl_tonemap == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
FGLDebug::PushGroup("UpdateCameraExposure");
|
|
|
|
|
|
|
|
FGLPostProcessState savedState;
|
2016-10-05 05:57:27 +00:00
|
|
|
savedState.SaveTextureBindings(2);
|
2016-09-18 13:57:22 +00:00
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
const auto &mSceneViewport = screen->mSceneViewport;
|
|
|
|
const auto &mScreenViewport = screen->mScreenViewport;
|
|
|
|
|
2016-09-18 13:57:22 +00:00
|
|
|
// Extract light level from scene texture:
|
2018-05-10 12:43:34 +00:00
|
|
|
auto &level0 = mBuffers->ExposureLevels[0];
|
|
|
|
level0.Framebuffer.Bind();
|
2016-09-18 13:57:22 +00:00
|
|
|
glViewport(0, 0, level0.Width, level0.Height);
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->BindCurrentTexture(0, GL_LINEAR);
|
2016-09-18 13:57:22 +00:00
|
|
|
mExposureExtractShader->Bind();
|
|
|
|
mExposureExtractShader->SceneTexture.Set(0);
|
2018-06-11 19:18:20 +00:00
|
|
|
mExposureExtractShader->Uniforms->Scale = { mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height };
|
|
|
|
mExposureExtractShader->Uniforms->Offset = { mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height };
|
|
|
|
mExposureExtractShader->Uniforms.Set();
|
2016-09-18 13:57:22 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
|
|
|
|
// Find the average value:
|
2017-01-05 13:45:15 +00:00
|
|
|
for (unsigned int i = 0; i + 1 < mBuffers->ExposureLevels.Size(); i++)
|
2016-09-18 13:57:22 +00:00
|
|
|
{
|
2018-05-10 12:43:34 +00:00
|
|
|
auto &level = mBuffers->ExposureLevels[i];
|
|
|
|
auto &next = mBuffers->ExposureLevels[i + 1];
|
2016-09-18 13:57:22 +00:00
|
|
|
|
2018-05-10 12:43:34 +00:00
|
|
|
next.Framebuffer.Bind();
|
2016-09-18 13:57:22 +00:00
|
|
|
glViewport(0, 0, next.Width, next.Height);
|
2018-05-10 12:43:34 +00:00
|
|
|
level.Texture.Bind(0);
|
2016-09-18 13:57:22 +00:00
|
|
|
mExposureAverageShader->Bind();
|
|
|
|
mExposureAverageShader->ExposureTexture.Set(0);
|
|
|
|
RenderScreenQuad();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Combine average value with current camera exposure:
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->ExposureFB.Bind();
|
2016-09-18 13:57:22 +00:00
|
|
|
glViewport(0, 0, 1, 1);
|
|
|
|
if (!mBuffers->FirstExposureFrame)
|
|
|
|
{
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mBuffers->FirstExposureFrame = false;
|
|
|
|
}
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->ExposureLevels.Last().Texture.Bind(0);
|
2016-09-18 13:57:22 +00:00
|
|
|
mExposureCombineShader->Bind();
|
|
|
|
mExposureCombineShader->ExposureTexture.Set(0);
|
2018-06-11 19:18:20 +00:00
|
|
|
mExposureCombineShader->Uniforms->ExposureBase = gl_exposure_base;
|
|
|
|
mExposureCombineShader->Uniforms->ExposureMin = gl_exposure_min;
|
|
|
|
mExposureCombineShader->Uniforms->ExposureScale = gl_exposure_scale;
|
|
|
|
mExposureCombineShader->Uniforms->ExposureSpeed = gl_exposure_speed;
|
|
|
|
mExposureCombineShader->Uniforms.Set();
|
2016-09-18 13:57:22 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
|
|
|
}
|
|
|
|
|
2016-07-29 22:02:26 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Adds bloom contribution to scene texture
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2017-03-12 20:57:39 +00:00
|
|
|
void FGLRenderer::BloomScene(int fixedcm)
|
2016-07-29 22:02:26 +00:00
|
|
|
{
|
|
|
|
// Only bloom things if enabled and no special fixed light mode is active
|
2017-03-12 20:57:39 +00:00
|
|
|
if (!gl_bloom || fixedcm != CM_DEFAULT || gl_ssao_debug)
|
2016-07-29 22:02:26 +00:00
|
|
|
return;
|
|
|
|
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::PushGroup("BloomScene");
|
|
|
|
|
2016-08-05 15:12:00 +00:00
|
|
|
FGLPostProcessState savedState;
|
2016-10-05 05:57:27 +00:00
|
|
|
savedState.SaveTextureBindings(2);
|
2016-08-05 15:12:00 +00:00
|
|
|
|
2016-07-29 22:02:26 +00:00
|
|
|
const float blurAmount = gl_bloom_amount;
|
|
|
|
int sampleCount = gl_bloom_kernel_size;
|
|
|
|
|
2018-05-10 12:43:34 +00:00
|
|
|
auto &level0 = mBuffers->BloomLevels[0];
|
2016-07-29 22:02:26 +00:00
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
const auto &mSceneViewport = screen->mSceneViewport;
|
|
|
|
const auto &mScreenViewport = screen->mScreenViewport;
|
|
|
|
|
2016-07-29 22:02:26 +00:00
|
|
|
// Extract blooming pixels from scene texture:
|
2018-05-10 12:43:34 +00:00
|
|
|
level0.VFramebuffer.Bind();
|
2016-07-29 22:02:26 +00:00
|
|
|
glViewport(0, 0, level0.Width, level0.Height);
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->BindCurrentTexture(0, GL_LINEAR);
|
|
|
|
mBuffers->ExposureTexture.Bind(1);
|
2016-07-29 22:02:26 +00:00
|
|
|
mBloomExtractShader->Bind();
|
|
|
|
mBloomExtractShader->SceneTexture.Set(0);
|
2016-09-18 13:57:22 +00:00
|
|
|
mBloomExtractShader->ExposureTexture.Set(1);
|
2016-08-12 15:44:59 +00:00
|
|
|
mBloomExtractShader->Scale.Set(mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height);
|
|
|
|
mBloomExtractShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height);
|
2016-08-06 12:12:40 +00:00
|
|
|
RenderScreenQuad();
|
2016-07-29 22:02:26 +00:00
|
|
|
|
|
|
|
// Blur and downscale:
|
|
|
|
for (int i = 0; i < FGLRenderBuffers::NumBloomLevels - 1; i++)
|
|
|
|
{
|
2018-05-10 12:43:34 +00:00
|
|
|
auto &level = mBuffers->BloomLevels[i];
|
|
|
|
auto &next = mBuffers->BloomLevels[i + 1];
|
2016-08-12 15:51:06 +00:00
|
|
|
mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height);
|
|
|
|
mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, next.VFramebuffer, next.Width, next.Height);
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Blur and upscale:
|
|
|
|
for (int i = FGLRenderBuffers::NumBloomLevels - 1; i > 0; i--)
|
|
|
|
{
|
2018-05-10 12:43:34 +00:00
|
|
|
auto &level = mBuffers->BloomLevels[i];
|
|
|
|
auto &next = mBuffers->BloomLevels[i - 1];
|
2016-07-29 22:02:26 +00:00
|
|
|
|
2016-08-12 15:51:06 +00:00
|
|
|
mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height);
|
|
|
|
mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, level.VFramebuffer, level.Width, level.Height);
|
2016-07-29 22:02:26 +00:00
|
|
|
|
|
|
|
// Linear upscale:
|
2018-05-10 12:43:34 +00:00
|
|
|
next.VFramebuffer.Bind();
|
2016-07-29 22:02:26 +00:00
|
|
|
glViewport(0, 0, next.Width, next.Height);
|
2018-05-10 12:43:34 +00:00
|
|
|
level.VTexture.Bind(0, GL_LINEAR);
|
2016-07-29 22:02:26 +00:00
|
|
|
mBloomCombineShader->Bind();
|
|
|
|
mBloomCombineShader->BloomTexture.Set(0);
|
2016-08-06 12:12:40 +00:00
|
|
|
RenderScreenQuad();
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 15:51:06 +00:00
|
|
|
mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height);
|
|
|
|
mBlurShader->BlurVertical(this, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height);
|
2016-07-29 22:02:26 +00:00
|
|
|
|
|
|
|
// Add bloom back to scene texture:
|
2016-08-04 15:16:49 +00:00
|
|
|
mBuffers->BindCurrentFB();
|
2016-08-12 15:44:59 +00:00
|
|
|
glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height);
|
2016-07-29 22:02:26 +00:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
2018-05-10 12:43:34 +00:00
|
|
|
level0.VTexture.Bind(0, GL_LINEAR);
|
2016-07-29 22:02:26 +00:00
|
|
|
mBloomCombineShader->Bind();
|
|
|
|
mBloomCombineShader->BloomTexture.Set(0);
|
2016-08-06 12:12:40 +00:00
|
|
|
RenderScreenQuad();
|
2016-08-12 15:44:59 +00:00
|
|
|
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
2016-08-17 21:18:47 +00:00
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
2017-02-17 07:08:22 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Blur the scene
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2017-03-14 23:11:13 +00:00
|
|
|
void FGLRenderer::BlurScene(float gameinfobluramount)
|
2017-02-17 07:08:22 +00:00
|
|
|
{
|
2017-03-14 23:11:13 +00:00
|
|
|
// first, respect the CVar
|
2017-03-14 22:46:51 +00:00
|
|
|
float blurAmount = gl_menu_blur;
|
2017-03-14 23:11:13 +00:00
|
|
|
|
|
|
|
// if CVar is negative, use the gameinfo entry
|
|
|
|
if (gl_menu_blur < 0)
|
|
|
|
blurAmount = gameinfobluramount;
|
|
|
|
|
|
|
|
// if blurAmount == 0 or somehow still returns negative, exit to prevent a crash, clearly we don't want this
|
|
|
|
if ((blurAmount <= 0.0) || !FGLRenderBuffers::IsEnabled())
|
2017-03-14 21:50:47 +00:00
|
|
|
return;
|
2017-03-14 22:46:51 +00:00
|
|
|
|
2017-02-17 07:08:22 +00:00
|
|
|
FGLDebug::PushGroup("BlurScene");
|
|
|
|
|
|
|
|
FGLPostProcessState savedState;
|
|
|
|
savedState.SaveTextureBindings(2);
|
|
|
|
|
|
|
|
int sampleCount = 9;
|
|
|
|
int numLevels = 3; // Must be 4 or less (since FGLRenderBuffers::NumBloomLevels is 4 and we are using its buffers).
|
|
|
|
assert(numLevels <= FGLRenderBuffers::NumBloomLevels);
|
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
const auto &viewport = screen->mScreenViewport; // The area we want to blur. Could also be mSceneViewport if only the scene area is to be blured
|
2017-02-17 07:08:22 +00:00
|
|
|
|
|
|
|
const auto &level0 = mBuffers->BloomLevels[0];
|
|
|
|
|
|
|
|
// Grab the area we want to bloom:
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->BlitLinear(mBuffers->GetCurrentFB(), level0.VFramebuffer, viewport.left, viewport.top, viewport.width, viewport.height, 0, 0, level0.Width, level0.Height);
|
2017-02-17 07:08:22 +00:00
|
|
|
|
|
|
|
// Blur and downscale:
|
|
|
|
for (int i = 0; i < numLevels - 1; i++)
|
|
|
|
{
|
2018-05-10 12:43:34 +00:00
|
|
|
auto &level = mBuffers->BloomLevels[i];
|
|
|
|
auto &next = mBuffers->BloomLevels[i + 1];
|
2017-02-17 07:08:22 +00:00
|
|
|
mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height);
|
|
|
|
mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, next.VFramebuffer, next.Width, next.Height);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Blur and upscale:
|
|
|
|
for (int i = numLevels - 1; i > 0; i--)
|
|
|
|
{
|
2018-05-10 12:43:34 +00:00
|
|
|
auto &level = mBuffers->BloomLevels[i];
|
|
|
|
auto &next = mBuffers->BloomLevels[i - 1];
|
2017-02-17 07:08:22 +00:00
|
|
|
|
|
|
|
mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height);
|
|
|
|
mBlurShader->BlurVertical(this, blurAmount, sampleCount, level.HTexture, level.VFramebuffer, level.Width, level.Height);
|
|
|
|
|
|
|
|
// Linear upscale:
|
2018-05-10 12:43:34 +00:00
|
|
|
next.VFramebuffer.Bind();
|
2017-02-17 07:08:22 +00:00
|
|
|
glViewport(0, 0, next.Width, next.Height);
|
2018-05-10 12:43:34 +00:00
|
|
|
level.VTexture.Bind(0, GL_LINEAR);
|
2017-02-17 07:08:22 +00:00
|
|
|
mBloomCombineShader->Bind();
|
|
|
|
mBloomCombineShader->BloomTexture.Set(0);
|
|
|
|
RenderScreenQuad();
|
|
|
|
}
|
|
|
|
|
|
|
|
mBlurShader->BlurHorizontal(this, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height);
|
|
|
|
mBlurShader->BlurVertical(this, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height);
|
|
|
|
|
|
|
|
// Copy blur back to scene texture:
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->BlitLinear(level0.VFramebuffer, mBuffers->GetCurrentFB(), 0, 0, level0.Width, level0.Height, viewport.left, viewport.top, viewport.width, viewport.height);
|
2017-02-17 07:08:22 +00:00
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
glViewport(viewport.left, viewport.top, viewport.width, viewport.height);
|
2017-02-17 07:08:22 +00:00
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
|
|
|
}
|
|
|
|
|
2016-07-29 22:02:26 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Tonemap scene texture and place the result in the HUD/2D texture
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void FGLRenderer::TonemapScene()
|
|
|
|
{
|
2016-09-01 09:52:52 +00:00
|
|
|
if (gl_tonemap == 0)
|
2016-07-29 22:02:26 +00:00
|
|
|
return;
|
|
|
|
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::PushGroup("TonemapScene");
|
|
|
|
|
2016-11-28 01:32:57 +00:00
|
|
|
CreateTonemapPalette();
|
|
|
|
|
2016-08-05 15:12:00 +00:00
|
|
|
FGLPostProcessState savedState;
|
2016-11-28 01:32:57 +00:00
|
|
|
savedState.SaveTextureBindings(2);
|
2016-07-29 22:02:26 +00:00
|
|
|
|
2016-08-04 15:16:49 +00:00
|
|
|
mBuffers->BindNextFB();
|
|
|
|
mBuffers->BindCurrentTexture(0);
|
2016-07-29 22:02:26 +00:00
|
|
|
mTonemapShader->Bind();
|
|
|
|
mTonemapShader->SceneTexture.Set(0);
|
2016-08-23 07:18:18 +00:00
|
|
|
|
|
|
|
if (mTonemapShader->IsPaletteMode())
|
|
|
|
{
|
2016-11-28 01:32:57 +00:00
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, mTonemapPalette->GetTextureHandle(0));
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
2016-08-23 07:18:18 +00:00
|
|
|
mTonemapShader->PaletteLUT.Set(1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->ExposureTexture.Bind(1);
|
2016-09-18 13:57:22 +00:00
|
|
|
mTonemapShader->ExposureTexture.Set(1);
|
2016-08-23 07:18:18 +00:00
|
|
|
}
|
|
|
|
|
2016-08-06 12:12:40 +00:00
|
|
|
RenderScreenQuad();
|
2016-08-04 15:16:49 +00:00
|
|
|
mBuffers->NextTexture();
|
2016-08-17 21:18:47 +00:00
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
2016-11-28 01:32:57 +00:00
|
|
|
void FGLRenderer::CreateTonemapPalette()
|
2016-08-23 07:18:18 +00:00
|
|
|
{
|
2016-11-28 01:32:57 +00:00
|
|
|
if (!mTonemapPalette)
|
2016-08-23 07:18:18 +00:00
|
|
|
{
|
|
|
|
TArray<unsigned char> lut;
|
|
|
|
lut.Resize(512 * 512 * 4);
|
|
|
|
for (int r = 0; r < 64; r++)
|
|
|
|
{
|
|
|
|
for (int g = 0; g < 64; g++)
|
|
|
|
{
|
|
|
|
for (int b = 0; b < 64; b++)
|
|
|
|
{
|
2018-04-29 11:10:30 +00:00
|
|
|
PalEntry color = GPalette.BaseColors[(uint8_t)PTM_BestColor((uint32_t *)GPalette.BaseColors, (r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4),
|
|
|
|
gl_paltonemap_reverselookup, gl_paltonemap_powtable, 0, 256)];
|
2016-08-23 07:18:18 +00:00
|
|
|
int index = ((r * 64 + g) * 64 + b) * 4;
|
2017-06-21 23:00:39 +00:00
|
|
|
lut[index] = color.b;
|
2016-08-23 07:18:18 +00:00
|
|
|
lut[index + 1] = color.g;
|
2017-06-21 23:00:39 +00:00
|
|
|
lut[index + 2] = color.r;
|
2016-08-23 07:18:18 +00:00
|
|
|
lut[index + 3] = 255;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-01 15:16:53 +00:00
|
|
|
mTonemapPalette = new FHardwareTexture(true);
|
2016-11-28 01:32:57 +00:00
|
|
|
mTonemapPalette->CreateTexture(&lut[0], 512, 512, 0, false, 0, "mTonemapPalette");
|
2016-08-23 07:18:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-25 17:58:50 +00:00
|
|
|
void FGLRenderer::ClearTonemapPalette()
|
|
|
|
{
|
2017-01-24 16:33:42 +00:00
|
|
|
if (mTonemapPalette)
|
|
|
|
{
|
|
|
|
delete mTonemapPalette;
|
|
|
|
mTonemapPalette = nullptr;
|
|
|
|
}
|
2016-08-25 17:58:50 +00:00
|
|
|
}
|
|
|
|
|
2016-09-01 15:14:51 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Colormap scene texture and place the result in the HUD/2D texture
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2017-03-12 20:57:39 +00:00
|
|
|
void FGLRenderer::ColormapScene(int fixedcm)
|
2016-09-01 15:14:51 +00:00
|
|
|
{
|
2017-03-12 20:57:39 +00:00
|
|
|
if (fixedcm < CM_FIRSTSPECIALCOLORMAP || fixedcm >= CM_MAXCOLORMAP)
|
2016-09-01 15:14:51 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
FGLDebug::PushGroup("ColormapScene");
|
|
|
|
|
|
|
|
FGLPostProcessState savedState;
|
|
|
|
|
|
|
|
mBuffers->BindNextFB();
|
|
|
|
mBuffers->BindCurrentTexture(0);
|
|
|
|
mColormapShader->Bind();
|
|
|
|
|
2017-03-12 20:57:39 +00:00
|
|
|
FSpecialColormap *scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP];
|
2016-09-01 15:14:51 +00:00
|
|
|
float m[] = { scm->ColorizeEnd[0] - scm->ColorizeStart[0],
|
|
|
|
scm->ColorizeEnd[1] - scm->ColorizeStart[1], scm->ColorizeEnd[2] - scm->ColorizeStart[2], 0.f };
|
|
|
|
|
2018-06-11 19:03:55 +00:00
|
|
|
mColormapShader->Uniforms->MapStart = { scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], 0.f };
|
|
|
|
mColormapShader->Uniforms->MapRange = m;
|
|
|
|
mColormapShader->Uniforms.Set();
|
2016-09-01 15:14:51 +00:00
|
|
|
|
|
|
|
RenderScreenQuad();
|
|
|
|
mBuffers->NextTexture();
|
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
|
|
|
}
|
|
|
|
|
2016-08-02 15:32:21 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Apply lens distortion and place the result in the HUD/2D texture
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void FGLRenderer::LensDistortScene()
|
|
|
|
{
|
2016-09-01 09:52:52 +00:00
|
|
|
if (gl_lens == 0)
|
2016-08-02 15:32:21 +00:00
|
|
|
return;
|
|
|
|
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::PushGroup("LensDistortScene");
|
|
|
|
|
2016-08-02 15:32:21 +00:00
|
|
|
float k[4] =
|
|
|
|
{
|
|
|
|
gl_lens_k,
|
|
|
|
gl_lens_k * gl_lens_chromatic,
|
|
|
|
gl_lens_k * gl_lens_chromatic * gl_lens_chromatic,
|
|
|
|
0.0f
|
|
|
|
};
|
|
|
|
float kcube[4] =
|
|
|
|
{
|
|
|
|
gl_lens_kcube,
|
|
|
|
gl_lens_kcube * gl_lens_chromatic,
|
|
|
|
gl_lens_kcube * gl_lens_chromatic * gl_lens_chromatic,
|
|
|
|
0.0f
|
|
|
|
};
|
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
float aspect = screen->mSceneViewport.width / (float)screen->mSceneViewport.height;
|
2016-08-04 13:47:15 +00:00
|
|
|
|
|
|
|
// Scale factor to keep sampling within the input texture
|
|
|
|
float r2 = aspect * aspect * 0.25 + 0.25f;
|
|
|
|
float sqrt_r2 = sqrt(r2);
|
|
|
|
float f0 = 1.0f + MAX(r2 * (k[0] + kcube[0] * sqrt_r2), 0.0f);
|
|
|
|
float f2 = 1.0f + MAX(r2 * (k[2] + kcube[2] * sqrt_r2), 0.0f);
|
|
|
|
float f = MAX(f0, f2);
|
|
|
|
float scale = 1.0f / f;
|
|
|
|
|
2016-08-05 15:12:00 +00:00
|
|
|
FGLPostProcessState savedState;
|
|
|
|
|
2016-08-04 15:16:49 +00:00
|
|
|
mBuffers->BindNextFB();
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->BindCurrentTexture(0, GL_LINEAR);
|
2016-08-02 15:32:21 +00:00
|
|
|
mLensShader->Bind();
|
|
|
|
mLensShader->InputTexture.Set(0);
|
2018-06-11 18:58:20 +00:00
|
|
|
mLensShader->Uniforms->AspectRatio = aspect;
|
|
|
|
mLensShader->Uniforms->Scale = scale;
|
|
|
|
mLensShader->Uniforms->LensDistortionCoefficient = k;
|
|
|
|
mLensShader->Uniforms->CubicDistortionValue = kcube;
|
|
|
|
mLensShader->Uniforms.Set();
|
2016-08-06 12:12:40 +00:00
|
|
|
RenderScreenQuad();
|
2016-08-04 15:16:49 +00:00
|
|
|
mBuffers->NextTexture();
|
2016-08-17 21:18:47 +00:00
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
2016-08-02 15:32:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-25 09:25:01 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Apply FXAA and place the result in the HUD/2D texture
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void FGLRenderer::ApplyFXAA()
|
|
|
|
{
|
|
|
|
if (0 == gl_fxaa)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FGLDebug::PushGroup("ApplyFXAA");
|
|
|
|
|
|
|
|
const GLfloat rpcRes[2] =
|
|
|
|
{
|
|
|
|
1.0f / mBuffers->GetWidth(),
|
|
|
|
1.0f / mBuffers->GetHeight()
|
|
|
|
};
|
|
|
|
|
|
|
|
FGLPostProcessState savedState;
|
|
|
|
|
|
|
|
mBuffers->BindNextFB();
|
|
|
|
mBuffers->BindCurrentTexture(0);
|
|
|
|
mFXAALumaShader->Bind();
|
|
|
|
mFXAALumaShader->InputTexture.Set(0);
|
|
|
|
RenderScreenQuad();
|
|
|
|
mBuffers->NextTexture();
|
|
|
|
|
|
|
|
mBuffers->BindNextFB();
|
2018-05-10 12:43:34 +00:00
|
|
|
mBuffers->BindCurrentTexture(0, GL_LINEAR);
|
2016-09-25 09:25:01 +00:00
|
|
|
mFXAAShader->Bind();
|
|
|
|
mFXAAShader->InputTexture.Set(0);
|
|
|
|
mFXAAShader->ReciprocalResolution.Set(rpcRes);
|
|
|
|
RenderScreenQuad();
|
|
|
|
mBuffers->NextTexture();
|
|
|
|
|
|
|
|
FGLDebug::PopGroup();
|
|
|
|
}
|
|
|
|
|
2016-09-07 19:52:43 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copies the rendered screen to its final destination
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void FGLRenderer::Flush()
|
|
|
|
{
|
|
|
|
const s3d::Stereo3DMode& stereo3dMode = s3d::Stereo3DMode::getCurrentMode();
|
2018-05-12 15:23:56 +00:00
|
|
|
const auto &mSceneViewport = screen->mSceneViewport;
|
|
|
|
const auto &mScreenViewport = screen->mScreenViewport;
|
2016-09-07 19:52:43 +00:00
|
|
|
|
|
|
|
if (stereo3dMode.IsMono() || !FGLRenderBuffers::IsEnabled())
|
|
|
|
{
|
|
|
|
CopyToBackbuffer(nullptr, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Render 2D to eye textures
|
|
|
|
for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix)
|
|
|
|
{
|
|
|
|
FGLDebug::PushGroup("Eye2D");
|
|
|
|
mBuffers->BindEyeFB(eye_ix);
|
2016-09-08 17:02:13 +00:00
|
|
|
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
|
|
|
glScissor(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
2018-03-28 14:40:09 +00:00
|
|
|
screen->Draw2D();
|
2016-09-07 19:52:43 +00:00
|
|
|
FGLDebug::PopGroup();
|
|
|
|
}
|
2018-03-28 14:40:09 +00:00
|
|
|
screen->Clear2D();
|
2016-09-07 19:52:43 +00:00
|
|
|
|
|
|
|
FGLPostProcessState savedState;
|
|
|
|
FGLDebug::PushGroup("PresentEyes");
|
|
|
|
stereo3dMode.Present();
|
|
|
|
FGLDebug::PopGroup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-29 22:02:26 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Gamma correct while copying to frame buffer
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
void FGLRenderer::CopyToBackbuffer(const IntRect *bounds, bool applyGamma)
|
2016-07-29 22:02:26 +00:00
|
|
|
{
|
2018-03-28 14:40:09 +00:00
|
|
|
screen->Draw2D(); // draw all pending 2D stuff before copying the buffer
|
|
|
|
screen->Clear2D();
|
2016-09-08 07:18:10 +00:00
|
|
|
|
2017-07-06 03:36:01 +00:00
|
|
|
mCustomPostProcessShaders->Run("screen");
|
2017-07-03 01:04:22 +00:00
|
|
|
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::PushGroup("CopyToBackbuffer");
|
2016-07-29 22:02:26 +00:00
|
|
|
if (FGLRenderBuffers::IsEnabled())
|
|
|
|
{
|
2016-08-05 15:12:00 +00:00
|
|
|
FGLPostProcessState savedState;
|
2016-07-29 22:02:26 +00:00
|
|
|
mBuffers->BindOutputFB();
|
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
IntRect box;
|
2016-07-31 14:23:21 +00:00
|
|
|
if (bounds)
|
2016-07-29 22:02:26 +00:00
|
|
|
{
|
2016-08-12 05:28:29 +00:00
|
|
|
box = *bounds;
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
2016-07-31 14:23:21 +00:00
|
|
|
else
|
2016-07-29 22:02:26 +00:00
|
|
|
{
|
2016-08-12 05:28:29 +00:00
|
|
|
ClearBorders();
|
2018-05-12 15:23:56 +00:00
|
|
|
box = screen->mOutputLetterbox;
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
|
|
|
|
2016-08-04 15:16:49 +00:00
|
|
|
mBuffers->BindCurrentTexture(0);
|
2016-09-08 17:02:13 +00:00
|
|
|
DrawPresentTexture(box, applyGamma);
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
2016-08-12 05:28:29 +00:00
|
|
|
else if (!bounds)
|
|
|
|
{
|
|
|
|
FGLPostProcessState savedState;
|
|
|
|
ClearBorders();
|
|
|
|
}
|
2016-08-17 21:18:47 +00:00
|
|
|
FGLDebug::PopGroup();
|
2016-08-12 05:28:29 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
void FGLRenderer::DrawPresentTexture(const IntRect &box, bool applyGamma)
|
2016-09-08 17:02:13 +00:00
|
|
|
{
|
|
|
|
glViewport(box.left, box.top, box.width, box.height);
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
2017-07-24 06:35:27 +00:00
|
|
|
if (ViewportLinearScale())
|
2017-07-23 15:24:04 +00:00
|
|
|
{
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
}
|
2016-09-08 17:02:13 +00:00
|
|
|
|
|
|
|
mPresentShader->Bind();
|
|
|
|
mPresentShader->InputTexture.Set(0);
|
|
|
|
if (!applyGamma || framebuffer->IsHWGammaActive())
|
|
|
|
{
|
|
|
|
mPresentShader->InvGamma.Set(1.0f);
|
|
|
|
mPresentShader->Contrast.Set(1.0f);
|
|
|
|
mPresentShader->Brightness.Set(0.0f);
|
2017-06-25 23:33:07 +00:00
|
|
|
mPresentShader->Saturation.Set(1.0f);
|
2016-09-08 17:02:13 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mPresentShader->InvGamma.Set(1.0f / clamp<float>(Gamma, 0.1f, 4.f));
|
|
|
|
mPresentShader->Contrast.Set(clamp<float>(vid_contrast, 0.1f, 3.f));
|
|
|
|
mPresentShader->Brightness.Set(clamp<float>(vid_brightness, -0.8f, 0.8f));
|
2017-06-26 07:50:49 +00:00
|
|
|
mPresentShader->Saturation.Set(clamp<float>(vid_saturation, -15.0f, 15.f));
|
2017-06-26 10:33:59 +00:00
|
|
|
mPresentShader->GrayFormula.Set(static_cast<int>(gl_satformula));
|
2016-09-08 17:02:13 +00:00
|
|
|
}
|
2018-05-12 15:23:56 +00:00
|
|
|
mPresentShader->Scale.Set(screen->mScreenViewport.width / (float)mBuffers->GetWidth(), screen->mScreenViewport.height / (float)mBuffers->GetHeight());
|
2016-09-08 17:02:13 +00:00
|
|
|
RenderScreenQuad();
|
|
|
|
}
|
|
|
|
|
2016-08-12 05:28:29 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Fills the black bars around the screen letterbox
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void FGLRenderer::ClearBorders()
|
|
|
|
{
|
2018-05-12 15:23:56 +00:00
|
|
|
const auto &box = screen->mOutputLetterbox;
|
2016-08-12 05:28:29 +00:00
|
|
|
|
|
|
|
int clientWidth = framebuffer->GetClientWidth();
|
|
|
|
int clientHeight = framebuffer->GetClientHeight();
|
2016-09-04 01:15:50 +00:00
|
|
|
if (clientWidth == 0 || clientHeight == 0)
|
|
|
|
return;
|
2016-08-12 05:28:29 +00:00
|
|
|
|
|
|
|
glViewport(0, 0, clientWidth, clientHeight);
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
if (box.top > 0)
|
|
|
|
{
|
|
|
|
glScissor(0, 0, clientWidth, box.top);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
if (clientHeight - box.top - box.height > 0)
|
|
|
|
{
|
|
|
|
glScissor(0, box.top + box.height, clientWidth, clientHeight - box.top - box.height);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
if (box.left > 0)
|
|
|
|
{
|
|
|
|
glScissor(0, box.top, box.left, box.height);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
if (clientWidth - box.left - box.width > 0)
|
|
|
|
{
|
|
|
|
glScissor(box.left + box.width, box.top, clientWidth - box.left - box.width, box.height);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
2016-07-29 22:02:26 +00:00
|
|
|
}
|
2016-09-07 07:34:08 +00:00
|
|
|
|