- renamed 'common' to 'core'.

We'll need 'common' for something else.
This commit is contained in:
Christoph Oelckers 2020-04-11 23:38:30 +02:00
parent 736337979b
commit e2f5e8fe34
280 changed files with 187 additions and 187 deletions

View file

@ -1,83 +0,0 @@
#pragma once
#include <stddef.h>
#include <assert.h>
class FRenderState;
// The low level code needs to know which attributes exist.
// OpenGL needs to change the state of all of them per buffer binding.
// VAOs are mostly useless for this because they lump buffer and binding state together which the model code does not want.
enum
{
VATTR_VERTEX,
VATTR_TEXCOORD,
VATTR_COLOR,
VATTR_VERTEX2,
VATTR_NORMAL,
VATTR_NORMAL2,
VATTR_MAX
};
enum EVertexAttributeFormat
{
VFmt_Float4,
VFmt_Float3,
VFmt_Float2,
VFmt_Float,
VFmt_Byte4,
VFmt_Packed_A2R10G10B10,
};
struct FVertexBufferAttribute
{
int binding;
int location;
int format;
int offset;
};
class IBuffer
{
protected:
size_t buffersize = 0;
void *map = nullptr;
public:
IBuffer() = default;
IBuffer(const IBuffer &) = delete;
IBuffer &operator=(const IBuffer &) = delete;
virtual ~IBuffer() = default;
virtual void SetData(size_t size, const void *data, bool staticdata = true) = 0;
virtual void SetSubData(size_t offset, size_t size, const void *data) = 0;
virtual void *Lock(unsigned int size) = 0;
virtual void Unlock() = 0;
virtual void Resize(size_t newsize) = 0;
virtual void Map() {} // Only needed by old OpenGL but this needs to be in the interface.
virtual void Unmap() {}
void *Memory() { assert(map); return map; }
size_t Size() { return buffersize; }
};
class IVertexBuffer : virtual public IBuffer
{
public:
virtual void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) = 0;
};
// This merely exists to have a dedicated type for index buffers to inherit from.
class IIndexBuffer : virtual public IBuffer
{
// Element size is fixed to 4, thanks to OpenGL requiring this info to be coded into the glDrawElements call.
// This mostly prohibits a more flexible buffer setup but GZDoom doesn't use any other format anyway.
// Ob Vulkam, element size is a buffer property and of no concern to the drawing functions (as it should be.)
};
class IDataBuffer : virtual public IBuffer
{
// Can be either uniform or shader storage buffer, depending on its needs.
public:
virtual void BindRange(FRenderState *state, size_t start, size_t length) = 0;
};

View file

@ -1,158 +0,0 @@
/*
** hw_flatvertices.cpp
** Creates flat vertex data for hardware rendering.
**
**---------------------------------------------------------------------------
** Copyright 2010-2020 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "c_cvars.h"
#include "flatvertices.h"
#include "v_video.h"
#include "cmdlib.h"
#include "printf.h"
#include "hwrenderer/data/buffers.h"
//==========================================================================
//
//
//
//==========================================================================
FFlatVertexBuffer::FFlatVertexBuffer(int width, int height)
{
vbo_shadowdata.Resize(NUM_RESERVED);
// the first quad is reserved for handling coordinates through uniforms.
vbo_shadowdata[0].Set(0, 0, 0, 0, 0);
vbo_shadowdata[1].Set(1, 0, 0, 0, 0);
vbo_shadowdata[2].Set(2, 0, 0, 0, 0);
vbo_shadowdata[3].Set(3, 0, 0, 0, 0);
// and the second one for the fullscreen quad used for blend overlays.
vbo_shadowdata[4].Set(0, 0, 0, 0, 0);
vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1);
vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0);
vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1);
// and this is for the postprocessing copy operation
vbo_shadowdata[8].Set(-1.0f, -1.0f, 0, 0.0f, 0.0f);
vbo_shadowdata[9].Set(-1.0f, 1.0f, 0, 0.0f, 1.f);
vbo_shadowdata[10].Set(1.0f, -1.0f, 0, 1.f, 0.0f);
vbo_shadowdata[11].Set(1.0f, 1.0f, 0, 1.f, 1.f);
// The next two are the stencil caps.
vbo_shadowdata[12].Set(-32767.0f, 32767.0f, -32767.0f, 0, 0);
vbo_shadowdata[13].Set(-32767.0f, 32767.0f, 32767.0f, 0, 0);
vbo_shadowdata[14].Set(32767.0f, 32767.0f, 32767.0f, 0, 0);
vbo_shadowdata[15].Set(32767.0f, 32767.0f, -32767.0f, 0, 0);
vbo_shadowdata[16].Set(-32767.0f, -32767.0f, -32767.0f, 0, 0);
vbo_shadowdata[17].Set(-32767.0f, -32767.0f, 32767.0f, 0, 0);
vbo_shadowdata[18].Set(32767.0f, -32767.0f, 32767.0f, 0, 0);
vbo_shadowdata[19].Set(32767.0f, -32767.0f, -32767.0f, 0, 0);
mVertexBuffer = screen->CreateVertexBuffer();
mIndexBuffer = screen->CreateIndexBuffer();
unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex);
mVertexBuffer->SetData(bytesize, nullptr, false);
static const FVertexBufferAttribute format[] = {
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FFlatVertex, x) },
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FFlatVertex, u) }
};
mVertexBuffer->SetFormat(1, 2, sizeof(FFlatVertex), format);
mIndex = mCurIndex = NUM_RESERVED;
mNumReserved = NUM_RESERVED;
Copy(0, NUM_RESERVED);
}
//==========================================================================
//
//
//
//==========================================================================
FFlatVertexBuffer::~FFlatVertexBuffer()
{
delete mIndexBuffer;
delete mVertexBuffer;
mIndexBuffer = nullptr;
mVertexBuffer = nullptr;
}
//==========================================================================
//
//
//
//==========================================================================
void FFlatVertexBuffer::OutputResized(int width, int height)
{
vbo_shadowdata[4].Set(0, 0, 0, 0, 0);
vbo_shadowdata[5].Set(0, (float)height, 0, 0, 1);
vbo_shadowdata[6].Set((float)width, 0, 0, 1, 0);
vbo_shadowdata[7].Set((float)width, (float)height, 0, 1, 1);
Copy(4, 4);
}
//==========================================================================
//
//
//
//==========================================================================
std::pair<FFlatVertex *, unsigned int> FFlatVertexBuffer::AllocVertices(unsigned int count)
{
FFlatVertex *p = GetBuffer();
auto index = mCurIndex.fetch_add(count);
auto offset = index;
if (index + count >= BUFFER_SIZE_TO_USE)
{
// If a single scene needs 2'000'000 vertices there must be something very wrong.
I_FatalError("Out of vertex memory. Tried to allocate more than %u vertices for a single frame", index + count);
}
return std::make_pair(p, index);
}
//==========================================================================
//
//
//
//==========================================================================
void FFlatVertexBuffer::Copy(int start, int count)
{
Map();
memcpy(GetBuffer(start), &vbo_shadowdata[0], count * sizeof(FFlatVertex));
Unmap();
}

View file

@ -1,112 +0,0 @@
#ifndef _HW__VERTEXBUFFER_H
#define _HW__VERTEXBUFFER_H
#include "tarray.h"
#include "hwrenderer/data/buffers.h"
#include <atomic>
#include <mutex>
class FRenderState;
struct secplane_t;
struct subsector_t;
struct FFlatVertex
{
float x, z, y; // world position
float u, v; // texture coordinates
void Set(float xx, float zz, float yy, float uu, float vv)
{
x = xx;
z = zz;
y = yy;
u = uu;
v = vv;
}
void SetVertex(float _x, float _y, float _z = 0)
{
x = _x;
z = _y;
y = _z;
}
void SetTexCoord(float _u = 0, float _v = 0)
{
u = _u;
v = _v;
}
};
class FFlatVertexBuffer
{
TArray<FFlatVertex> vbo_shadowdata;
TArray<uint32_t> ibo_data;
IVertexBuffer *mVertexBuffer;
IIndexBuffer *mIndexBuffer;
unsigned int mIndex;
std::atomic<unsigned int> mCurIndex;
unsigned int mNumReserved;
static const unsigned int BUFFER_SIZE = 4000000; // Was upped from 2000000 to account for voxels not being implemented with a separate vertex buffer.
static const unsigned int BUFFER_SIZE_TO_USE = BUFFER_SIZE-500;
public:
enum
{
QUAD_INDEX = 0,
FULLSCREEN_INDEX = 4,
PRESENT_INDEX = 8,
STENCILTOP_INDEX = 12,
STENCILBOTTOM_INDEX = 16,
NUM_RESERVED = 20
};
FFlatVertexBuffer(int width, int height);
~FFlatVertexBuffer();
void OutputResized(int width, int height);
std::pair<IVertexBuffer *, IIndexBuffer *> GetBufferObjects() const
{
return std::make_pair(mVertexBuffer, mIndexBuffer);
}
void Copy(int start, int count);
FFlatVertex *GetBuffer(int index) const
{
FFlatVertex *ff = (FFlatVertex*)mVertexBuffer->Memory();
return &ff[index];
}
FFlatVertex *GetBuffer() const
{
return GetBuffer(mCurIndex);
}
std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count);
void Reset()
{
mCurIndex = mIndex;
}
void Map()
{
mVertexBuffer->Map();
}
void Unmap()
{
mVertexBuffer->Unmap();
}
};
#endif

View file

@ -1,33 +0,0 @@
#pragma once
#include <stdint.h>
#include "tflags.h"
// A render queue is what contains all render commands.
// On Vulkan there can be several of them so this interface is needed to allow for the needed parallelism.
// On OpenGL the render state is global so all this will do is to translate the system independent calls into OpenGL API calls.
enum class ColormaskBits
{
RED = 1,
GREEN = 2,
BLUE = 4,
ALPHA = 8
};
typedef TFlags<ColormaskBits, uint8_t> Colormask;
class IRenderQueue
{
Colormask mColorMask;
Colormask GetColorMask() const
{
return mColorMask;
}
virtual void SetColorMask(Colormask mask) = 0;
};

View file

@ -1,154 +0,0 @@
#pragma once
#include <vector>
#include "hwrenderer/data/buffers.h"
#include "v_video.h"
enum
{
LIGHTBUF_BINDINGPOINT = 1,
POSTPROCESS_BINDINGPOINT = 2,
VIEWPOINT_BINDINGPOINT = 3,
LIGHTNODES_BINDINGPOINT = 4,
LIGHTLINES_BINDINGPOINT = 5,
LIGHTLIST_BINDINGPOINT = 6
};
enum class UniformType
{
Int,
UInt,
Float,
Vec2,
Vec3,
Vec4,
IVec2,
IVec3,
IVec4,
UVec2,
UVec3,
UVec4,
Mat4
};
class UniformFieldDesc
{
public:
UniformFieldDesc() { }
UniformFieldDesc(const char *name, UniformType type, std::size_t offset) : Name(name), Type(type), Offset(offset) { }
const char *Name;
UniformType Type;
std::size_t Offset;
};
class UniformBlockDecl
{
public:
static FString Create(const char *name, const std::vector<UniformFieldDesc> &fields, int bindingpoint)
{
FString decl;
FString layout;
if (bindingpoint == -1)
{
layout = "push_constant";
}
else if (screen->glslversion < 4.20)
{
layout = "std140";
}
else
{
layout.Format("std140, binding = %d", bindingpoint);
}
decl.Format("layout(%s) uniform %s\n{\n", layout.GetChars(), name);
for (size_t i = 0; i < fields.size(); i++)
{
decl.AppendFormat("\t%s %s;\n", GetTypeStr(fields[i].Type), fields[i].Name);
}
decl += "};\n";
return decl;
}
private:
static const char *GetTypeStr(UniformType type)
{
switch (type)
{
default:
case UniformType::Int: return "int";
case UniformType::UInt: return "uint";
case UniformType::Float: return "float";
case UniformType::Vec2: return "vec2";
case UniformType::Vec3: return "vec3";
case UniformType::Vec4: return "vec4";
case UniformType::IVec2: return "ivec2";
case UniformType::IVec3: return "ivec3";
case UniformType::IVec4: return "ivec4";
case UniformType::UVec2: return "uvec2";
case UniformType::UVec3: return "uvec3";
case UniformType::UVec4: return "uvec4";
case UniformType::Mat4: return "mat4";
}
}
};
template<typename T, int bindingpoint>
class ShaderUniforms
{
public:
ShaderUniforms()
{
memset(&Values, 0, sizeof(Values));
}
~ShaderUniforms()
{
if (mBuffer != nullptr)
delete mBuffer;
}
int BindingPoint() const
{
return bindingpoint;
}
FString CreateDeclaration(const char *name, const std::vector<UniformFieldDesc> &fields)
{
mFields = fields;
return UniformBlockDecl::Create(name, fields, bindingpoint);
}
void Init()
{
if (mBuffer == nullptr)
mBuffer = screen->CreateDataBuffer(bindingpoint, false, false);
}
void SetData()
{
if (mBuffer != nullptr)
mBuffer->SetData(sizeof(T), &Values);
}
IDataBuffer* GetBuffer() const
{
// OpenGL needs to mess around with this in ways that should not be part of the interface.
return mBuffer;
}
T *operator->() { return &Values; }
const T *operator->() const { return &Values; }
T Values;
private:
ShaderUniforms(const ShaderUniforms &) = delete;
ShaderUniforms &operator=(const ShaderUniforms &) = delete;
IDataBuffer *mBuffer = nullptr;
std::vector<UniformFieldDesc> mFields;
};

View file

@ -1,846 +0,0 @@
/*
** Postprocessing framework
** Copyright (c) 2016-2020 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
*/
#include "v_video.h"
#include "hw_postprocess.h"
#include "gamecvars.h"
#include "stats.h"
#include "imagehelpers.h"
#include "hwrenderer/utility/hw_cvars.h"
#include "hwrenderer/postprocessing/hw_postprocess_cvars.h"
#include <random>
Postprocess hw_postprocess;
PPResource *PPResource::First = nullptr;
bool gpuStatActive = false;
bool keepGpuStatActive = false;
FString gpuStatOutput;
ADD_STAT(gpu)
{
keepGpuStatActive = true;
return gpuStatOutput;
}
/////////////////////////////////////////////////////////////////////////////
void PPBloom::UpdateTextures(int width, int height)
{
if (width == lastWidth && height == lastHeight)
return;
int bloomWidth = (width + 1) / 2;
int bloomHeight = (height + 1) / 2;
for (int i = 0; i < NumBloomLevels; i++)
{
auto &blevel = levels[i];
blevel.Viewport.left = 0;
blevel.Viewport.top = 0;
blevel.Viewport.width = (bloomWidth + 1) / 2;
blevel.Viewport.height = (bloomHeight + 1) / 2;
blevel.VTexture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::Rgba16f };
blevel.HTexture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::Rgba16f };
bloomWidth = blevel.Viewport.width;
bloomHeight = blevel.Viewport.height;
}
lastWidth = width;
lastHeight = height;
}
void PPBloom::RenderBloom(PPRenderState *renderstate, int sceneWidth, int sceneHeight, int fixedcm)
{
// Only bloom things if enabled and no special fixed light mode is active
if (!gl_bloom || sceneWidth <= 0 || sceneHeight <= 0)
{
return;
}
renderstate->PushGroup("bloom");
UpdateTextures(sceneWidth, sceneHeight);
ExtractUniforms extractUniforms;
extractUniforms.Scale = screen->SceneScale();
extractUniforms.Offset = screen->SceneOffset();
auto &level0 = levels[0];
// Extract blooming pixels from scene texture:
renderstate->Clear();
renderstate->Shader = &BloomExtract;
renderstate->Uniforms.Set(extractUniforms);
renderstate->Viewport = level0.Viewport;
renderstate->SetInputCurrent(0, PPFilterMode::Linear);
renderstate->SetInputTexture(1, &hw_postprocess.exposure.CameraTexture);
renderstate->SetOutputTexture(&level0.VTexture);
renderstate->SetNoBlend();
renderstate->Draw();
const float blurAmount = gl_bloom_amount;
BlurUniforms blurUniforms;
ComputeBlurSamples(7, blurAmount, blurUniforms.SampleWeights);
// Blur and downscale:
for (int i = 0; i < NumBloomLevels - 1; i++)
{
auto &blevel = levels[i];
auto &next = levels[i + 1];
BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false);
BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true);
// Linear downscale:
renderstate->Clear();
renderstate->Shader = &BloomCombine;
renderstate->Uniforms.Clear();
renderstate->Viewport = next.Viewport;
renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear);
renderstate->SetOutputTexture(&next.VTexture);
renderstate->SetNoBlend();
renderstate->Draw();
}
// Blur and upscale:
for (int i = NumBloomLevels - 1; i > 0; i--)
{
auto &blevel = levels[i];
auto &next = levels[i - 1];
BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false);
BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true);
// Linear upscale:
renderstate->Clear();
renderstate->Shader = &BloomCombine;
renderstate->Uniforms.Clear();
renderstate->Viewport = next.Viewport;
renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear);
renderstate->SetOutputTexture(&next.VTexture);
renderstate->SetNoBlend();
renderstate->Draw();
}
BlurStep(renderstate, blurUniforms, level0.VTexture, level0.HTexture, level0.Viewport, false);
BlurStep(renderstate, blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true);
// Add bloom back to scene texture:
renderstate->Clear();
renderstate->Shader = &BloomCombine;
renderstate->Uniforms.Clear();
renderstate->Viewport = screen->mSceneViewport;
renderstate->SetInputTexture(0, &level0.VTexture, PPFilterMode::Linear);
renderstate->SetOutputCurrent();
renderstate->SetAdditiveBlend();
renderstate->Draw();
renderstate->PopGroup();
}
void PPBloom::RenderBlur(PPRenderState *renderstate, int sceneWidth, int sceneHeight, float gameinfobluramount)
{
// No scene, no blur!
if (sceneWidth <= 0 || sceneHeight <= 0)
return;
UpdateTextures(sceneWidth, sceneHeight);
// first, respect the CVar
float blurAmount = gl_menu_blur;
// 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)
{
return;
}
renderstate->PushGroup("blur");
int numLevels = 3;
assert(numLevels <= NumBloomLevels);
auto &level0 = levels[0];
// Grab the area we want to bloom:
renderstate->Clear();
renderstate->Shader = &BloomCombine;
renderstate->Uniforms.Clear();
renderstate->Viewport = level0.Viewport;
renderstate->SetInputCurrent(0, PPFilterMode::Linear);
renderstate->SetOutputTexture(&level0.VTexture);
renderstate->SetNoBlend();
renderstate->Draw();
BlurUniforms blurUniforms;
ComputeBlurSamples(7, blurAmount, blurUniforms.SampleWeights);
// Blur and downscale:
for (int i = 0; i < numLevels - 1; i++)
{
auto &blevel = levels[i];
auto &next = levels[i + 1];
BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false);
BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true);
// Linear downscale:
renderstate->Clear();
renderstate->Shader = &BloomCombine;
renderstate->Uniforms.Clear();
renderstate->Viewport = next.Viewport;
renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear);
renderstate->SetOutputTexture(&next.VTexture);
renderstate->SetNoBlend();
renderstate->Draw();
}
// Blur and upscale:
for (int i = numLevels - 1; i > 0; i--)
{
auto &blevel = levels[i];
auto &next = levels[i - 1];
BlurStep(renderstate, blurUniforms, blevel.VTexture, blevel.HTexture, blevel.Viewport, false);
BlurStep(renderstate, blurUniforms, blevel.HTexture, blevel.VTexture, blevel.Viewport, true);
// Linear upscale:
renderstate->Clear();
renderstate->Shader = &BloomCombine;
renderstate->Uniforms.Clear();
renderstate->Viewport = next.Viewport;
renderstate->SetInputTexture(0, &blevel.VTexture, PPFilterMode::Linear);
renderstate->SetOutputTexture(&next.VTexture);
renderstate->SetNoBlend();
renderstate->Draw();
}
BlurStep(renderstate, blurUniforms, level0.VTexture, level0.HTexture, level0.Viewport, false);
BlurStep(renderstate, blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true);
// Copy blur back to scene texture:
renderstate->Clear();
renderstate->Shader = &BloomCombine;
renderstate->Uniforms.Clear();
renderstate->Viewport = screen->mScreenViewport;
renderstate->SetInputTexture(0, &level0.VTexture, PPFilterMode::Linear);
renderstate->SetOutputCurrent();
renderstate->SetNoBlend();
renderstate->Draw();
renderstate->PopGroup();
}
void PPBloom::BlurStep(PPRenderState *renderstate, const BlurUniforms &blurUniforms, PPTexture &input, PPTexture &output, PPViewport viewport, bool vertical)
{
renderstate->Clear();
renderstate->Shader = vertical ? &BlurVertical : &BlurHorizontal;
renderstate->Uniforms.Set(blurUniforms);
renderstate->Viewport = viewport;
renderstate->SetInputTexture(0, &input);
renderstate->SetOutputTexture(&output);
renderstate->SetNoBlend();
renderstate->Draw();
}
float PPBloom::ComputeBlurGaussian(float n, float theta) // theta = Blur Amount
{
return (float)((1.0f / sqrtf(2 * (float)M_PI * theta)) * expf(-(n * n) / (2.0f * theta * theta)));
}
void PPBloom::ComputeBlurSamples(int sampleCount, float blurAmount, float *sampleWeights)
{
sampleWeights[0] = ComputeBlurGaussian(0, blurAmount);
float totalWeights = sampleWeights[0];
for (int i = 0; i < sampleCount / 2; i++)
{
float weight = ComputeBlurGaussian(i + 1.0f, blurAmount);
sampleWeights[i * 2 + 1] = weight;
sampleWeights[i * 2 + 2] = weight;
totalWeights += weight * 2;
}
for (int i = 0; i < sampleCount; i++)
{
sampleWeights[i] /= totalWeights;
}
}
/////////////////////////////////////////////////////////////////////////////
void PPLensDistort::Render(PPRenderState *renderstate)
{
if (gl_lens == 0)
{
return;
}
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
};
float aspect = screen->mSceneViewport.width / (float)screen->mSceneViewport.height;
// Scale factor to keep sampling within the input texture
float r2 = aspect * aspect * 0.25f + 0.25f;
float sqrt_r2 = sqrt(r2);
float f0 = 1.0f + std::max(r2 * (k[0] + kcube[0] * sqrt_r2), 0.0f);
float f2 = 1.0f + std::max(r2 * (k[2] + kcube[2] * sqrt_r2), 0.0f);
float f = std::max(f0, f2);
float scale = 1.0f / f;
LensUniforms uniforms;
uniforms.AspectRatio = aspect;
uniforms.Scale = scale;
uniforms.LensDistortionCoefficient = k;
uniforms.CubicDistortionValue = kcube;
renderstate->PushGroup("lens");
renderstate->Clear();
renderstate->Shader = &Lens;
renderstate->Uniforms.Set(uniforms);
renderstate->Viewport = screen->mScreenViewport;
renderstate->SetInputCurrent(0, PPFilterMode::Linear);
renderstate->SetOutputNext();
renderstate->SetNoBlend();
renderstate->Draw();
renderstate->PopGroup();
}
/////////////////////////////////////////////////////////////////////////////
void PPFXAA::Render(PPRenderState *renderstate)
{
if (0 == gl_fxaa)
{
return;
}
CreateShaders();
FXAAUniforms uniforms;
uniforms.ReciprocalResolution = { 1.0f / screen->mScreenViewport.width, 1.0f / screen->mScreenViewport.height };
renderstate->PushGroup("fxaa");
renderstate->Clear();
renderstate->Shader = &FXAALuma;
renderstate->Uniforms.Clear();
renderstate->Viewport = screen->mScreenViewport;
renderstate->SetInputCurrent(0, PPFilterMode::Nearest);
renderstate->SetOutputNext();
renderstate->SetNoBlend();
renderstate->Draw();
renderstate->Shader = &FXAA;
renderstate->Uniforms.Set(uniforms);
renderstate->SetInputCurrent(0, PPFilterMode::Linear);
renderstate->Draw();
renderstate->PopGroup();
}
int PPFXAA::GetMaxVersion()
{
return screen->glslversion >= 4.f ? 400 : 330;
}
void PPFXAA::CreateShaders()
{
if (LastQuality == gl_fxaa)
return;
FXAALuma = { "engine/shaders/pp/fxaa.fp", "#define FXAA_LUMA_PASS\n", {} };
FXAA = { "engine/shaders/pp/fxaa.fp", GetDefines(), FXAAUniforms::Desc(), GetMaxVersion() };
LastQuality = gl_fxaa;
}
FString PPFXAA::GetDefines()
{
int quality;
switch (gl_fxaa)
{
default:
case IFXAAShader::Low: quality = 10; break;
case IFXAAShader::Medium: quality = 12; break;
case IFXAAShader::High: quality = 29; break;
case IFXAAShader::Extreme: quality = 39; break;
}
const int gatherAlpha = GetMaxVersion() >= 400 ? 1 : 0;
// TODO: enable FXAA_GATHER4_ALPHA on OpenGL earlier than 4.0
// when GL_ARB_gpu_shader5/GL_NV_gpu_shader5 extensions are supported
FString result;
result.Format(
"#define FXAA_QUALITY__PRESET %i\n"
"#define FXAA_GATHER4_ALPHA %i\n",
quality, gatherAlpha);
return result;
}
/////////////////////////////////////////////////////////////////////////////
void PPCameraExposure::Render(PPRenderState *renderstate, int sceneWidth, int sceneHeight)
{
if (!gl_bloom)
{
return;
}
renderstate->PushGroup("exposure");
UpdateTextures(sceneWidth, sceneHeight);
ExposureExtractUniforms extractUniforms;
extractUniforms.Scale = screen->SceneScale();
extractUniforms.Offset = screen->SceneOffset();
ExposureCombineUniforms combineUniforms;
combineUniforms.ExposureBase = gl_exposure_base;
combineUniforms.ExposureMin = gl_exposure_min;
combineUniforms.ExposureScale = gl_exposure_scale;
combineUniforms.ExposureSpeed = gl_exposure_speed;
auto &level0 = ExposureLevels[0];
// Extract light blevel from scene texture:
renderstate->Clear();
renderstate->Shader = &ExposureExtract;
renderstate->Uniforms.Set(extractUniforms);
renderstate->Viewport = level0.Viewport;
renderstate->SetInputCurrent(0, PPFilterMode::Linear);
renderstate->SetOutputTexture(&level0.Texture);
renderstate->SetNoBlend();
renderstate->Draw();
// Find the average value:
for (size_t i = 0; i + 1 < ExposureLevels.size(); i++)
{
auto &blevel = ExposureLevels[i];
auto &next = ExposureLevels[i + 1];
renderstate->Shader = &ExposureAverage;
renderstate->Uniforms.Clear();
renderstate->Viewport = next.Viewport;
renderstate->SetInputTexture(0, &blevel.Texture, PPFilterMode::Linear);
renderstate->SetOutputTexture(&next.Texture);
renderstate->SetNoBlend();
renderstate->Draw();
}
// Combine average value with current camera exposure:
renderstate->Shader = &ExposureCombine;
renderstate->Uniforms.Set(combineUniforms);
renderstate->Viewport.left = 0;
renderstate->Viewport.top = 0;
renderstate->Viewport.width = 1;
renderstate->Viewport.height = 1;
renderstate->SetInputTexture(0, &ExposureLevels.back().Texture, PPFilterMode::Linear);
renderstate->SetOutputTexture(&CameraTexture);
if (!FirstExposureFrame)
renderstate->SetAlphaBlend();
else
renderstate->SetNoBlend();
renderstate->Draw();
renderstate->PopGroup();
FirstExposureFrame = false;
}
void PPCameraExposure::UpdateTextures(int width, int height)
{
int firstwidth = std::max(width / 2, 1);
int firstheight = std::max(height / 2, 1);
if (ExposureLevels.size() > 0 && ExposureLevels[0].Viewport.width == firstwidth && ExposureLevels[0].Viewport.height == firstheight)
{
return;
}
ExposureLevels.clear();
int i = 0;
do
{
width = std::max(width / 2, 1);
height = std::max(height / 2, 1);
PPExposureLevel blevel;
blevel.Viewport.left = 0;
blevel.Viewport.top = 0;
blevel.Viewport.width = width;
blevel.Viewport.height = height;
blevel.Texture = { blevel.Viewport.width, blevel.Viewport.height, PixelFormat::R32f };
ExposureLevels.push_back(std::move(blevel));
i++;
} while (width > 1 || height > 1);
FirstExposureFrame = true;
}
/////////////////////////////////////////////////////////////////////////////
void PPTonemap::UpdateTextures()
{
if (gl_tonemap == Palette && !PaletteTexture.Data)
{
std::shared_ptr<void> data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; });
uint8_t *lut = (uint8_t *)data.get();
for (int r = 0; r < 64; r++)
{
for (int g = 0; g < 64; g++)
{
for (int b = 0; b < 64; b++)
{
PalEntry color = ImageHelpers::BasePalette[(uint8_t)ImageHelpers::PTM_BestColor((r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4),
gl_paltonemap_reverselookup, gl_paltonemap_powtable, 0, 256)];
int index = ((r * 64 + g) * 64 + b) * 4;
lut[index] = color.r;
lut[index + 1] = color.g;
lut[index + 2] = color.b;
lut[index + 3] = 255;
}
}
}
PaletteTexture = { 512, 512, PixelFormat::Rgba8, data };
}
}
void PPTonemap::Render(PPRenderState *renderstate)
{
if (gl_tonemap == 0)
{
return;
}
UpdateTextures();
PPShader *shader = nullptr;
switch (gl_tonemap)
{
default:
case Linear: shader = &LinearShader; break;
case Reinhard: shader = &ReinhardShader; break;
case HejlDawson: shader = &HejlDawsonShader; break;
case Uncharted2: shader = &Uncharted2Shader; break;
case Palette: shader = &PaletteShader; break;
}
renderstate->PushGroup("tonemap");
renderstate->Clear();
renderstate->Shader = shader;
renderstate->Viewport = screen->mScreenViewport;
renderstate->SetInputCurrent(0);
if (gl_tonemap == Palette)
renderstate->SetInputTexture(1, &PaletteTexture);
renderstate->SetOutputNext();
renderstate->SetNoBlend();
renderstate->Draw();
renderstate->PopGroup();
}
/////////////////////////////////////////////////////////////////////////////
PPAmbientOcclusion::PPAmbientOcclusion()
{
// Must match quality enum in PPAmbientOcclusion::DeclareShaders
double numDirections[NumAmbientRandomTextures] = { 2.0, 4.0, 8.0 };
std::mt19937 generator(1337);
std::uniform_real_distribution<double> distribution(0.0, 1.0);
for (int quality = 0; quality < NumAmbientRandomTextures; quality++)
{
std::shared_ptr<void> data(new int16_t[16 * 4], [](void *p) { delete[](int16_t*)p; });
int16_t *randomValues = (int16_t *)data.get();
for (int i = 0; i < 16; i++)
{
double angle = 2.0 * M_PI * distribution(generator) / numDirections[quality];
double x = cos(angle);
double y = sin(angle);
double z = distribution(generator);
double w = distribution(generator);
randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0);
randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0);
randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0);
randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0);
}
AmbientRandomTexture[quality] = { 4, 4, PixelFormat::Rgba16_snorm, data };
}
}
void PPAmbientOcclusion::CreateShaders()
{
if (gl_ssao == LastQuality)
return;
// Must match quality values in PPAmbientOcclusion::UpdateTextures
int numDirections, numSteps;
switch (gl_ssao)
{
default:
case LowQuality: numDirections = 2; numSteps = 4; break;
case MediumQuality: numDirections = 4; numSteps = 4; break;
case HighQuality: numDirections = 8; numSteps = 4; break;
}
FString defines;
defines.Format(R"(
#define USE_RANDOM_TEXTURE
#define RANDOM_TEXTURE_WIDTH 4.0
#define NUM_DIRECTIONS %d.0
#define NUM_STEPS %d.0
)", numDirections, numSteps);
LinearDepth = { "engine/shaders/pp/lineardepth.fp", "", LinearDepthUniforms::Desc() };
LinearDepthMS = { "engine/shaders/pp/lineardepth.fp", "#define MULTISAMPLE\n", LinearDepthUniforms::Desc() };
AmbientOcclude = { "engine/shaders/pp/ssao.fp", defines, SSAOUniforms::Desc() };
AmbientOccludeMS = { "engine/shaders/pp/ssao.fp", defines + "\n#define MULTISAMPLE\n", SSAOUniforms::Desc() };
BlurVertical = { "engine/shaders/pp/depthblur.fp", "#define BLUR_VERTICAL\n", DepthBlurUniforms::Desc() };
BlurHorizontal = { "engine/shaders/pp/depthblur.fp", "#define BLUR_HORIZONTAL\n", DepthBlurUniforms::Desc() };
Combine = { "engine/shaders/pp/ssaocombine.fp", "", AmbientCombineUniforms::Desc() };
CombineMS = { "engine/shaders/pp/ssaocombine.fp", "#define MULTISAMPLE\n", AmbientCombineUniforms::Desc() };
LastQuality = gl_ssao;
}
void PPAmbientOcclusion::UpdateTextures(int width, int height)
{
if ((width <= 0 || height <= 0) || (width == LastWidth && height == LastHeight))
return;
AmbientWidth = (width + 1) / 2;
AmbientHeight = (height + 1) / 2;
LinearDepthTexture = { AmbientWidth, AmbientHeight, PixelFormat::R32f };
Ambient0 = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f };
Ambient1 = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f };
LastWidth = width;
LastHeight = height;
}
void PPAmbientOcclusion::Render(PPRenderState *renderstate, float m5, int sceneWidth, int sceneHeight)
{
if (gl_ssao == 0 || sceneWidth == 0 || sceneHeight == 0)
{
return;
}
CreateShaders();
UpdateTextures(sceneWidth, sceneHeight);
float bias = gl_ssao_bias;
float aoRadius = gl_ssao_radius;
const float blurAmount = gl_ssao_blur;
float aoStrength = gl_ssao_strength;
//float tanHalfFovy = tan(fovy * (M_PI / 360.0f));
float tanHalfFovy = 1.0f / m5;
float invFocalLenX = tanHalfFovy * (sceneWidth / (float)sceneHeight);
float invFocalLenY = tanHalfFovy;
float nDotVBias = clamp(bias, 0.0f, 1.0f);
float r2 = aoRadius * aoRadius;
float blurSharpness = 1.0f / blurAmount;
auto sceneScale = screen->SceneScale();
auto sceneOffset = screen->SceneOffset();
int randomTexture = clamp(gl_ssao - 1, 0, NumAmbientRandomTextures - 1);
LinearDepthUniforms linearUniforms;
linearUniforms.SampleIndex = 0;
linearUniforms.LinearizeDepthA = 1.0f / screen->GetZFar() - 1.0f / screen->GetZNear();
linearUniforms.LinearizeDepthB = std::max(1.0f / screen->GetZNear(), 1.e-8f);
linearUniforms.InverseDepthRangeA = 1.0f;
linearUniforms.InverseDepthRangeB = 0.0f;
linearUniforms.Scale = sceneScale;
linearUniforms.Offset = sceneOffset;
SSAOUniforms ssaoUniforms;
ssaoUniforms.SampleIndex = 0;
ssaoUniforms.UVToViewA = { 2.0f * invFocalLenX, 2.0f * invFocalLenY };
ssaoUniforms.UVToViewB = { -invFocalLenX, -invFocalLenY };
ssaoUniforms.InvFullResolution = { 1.0f / AmbientWidth, 1.0f / AmbientHeight };
ssaoUniforms.NDotVBias = nDotVBias;
ssaoUniforms.NegInvR2 = -1.0f / r2;
ssaoUniforms.RadiusToScreen = aoRadius * 0.5f / tanHalfFovy * AmbientHeight;
ssaoUniforms.AOMultiplier = 1.0f / (1.0f - nDotVBias);
ssaoUniforms.AOStrength = aoStrength;
ssaoUniforms.Scale = sceneScale;
ssaoUniforms.Offset = sceneOffset;
DepthBlurUniforms blurUniforms;
blurUniforms.BlurSharpness = blurSharpness;
blurUniforms.PowExponent = gl_ssao_exponent;
AmbientCombineUniforms combineUniforms;
combineUniforms.SampleCount = gl_multisample;
combineUniforms.Scale = screen->SceneScale();
combineUniforms.Offset = screen->SceneOffset();
combineUniforms.DebugMode = gl_ssao_debug;
IntRect ambientViewport;
ambientViewport.left = 0;
ambientViewport.top = 0;
ambientViewport.width = AmbientWidth;
ambientViewport.height = AmbientHeight;
renderstate->PushGroup("ssao");
// Calculate linear depth values
renderstate->Clear();
renderstate->Shader = gl_multisample > 1 ? &LinearDepthMS : &LinearDepth;
renderstate->Uniforms.Set(linearUniforms);
renderstate->Viewport = ambientViewport;
renderstate->SetInputSceneDepth(0);
renderstate->SetInputSceneColor(1);
renderstate->SetOutputTexture(&LinearDepthTexture);
renderstate->SetNoBlend();
renderstate->Draw();
// Apply ambient occlusion
renderstate->Clear();
renderstate->Shader = gl_multisample > 1 ? &AmbientOccludeMS : &AmbientOcclude;
renderstate->Uniforms.Set(ssaoUniforms);
renderstate->Viewport = ambientViewport;
renderstate->SetInputTexture(0, &LinearDepthTexture);
renderstate->SetInputSceneNormal(1);
renderstate->SetInputTexture(2, &AmbientRandomTexture[randomTexture], PPFilterMode::Nearest, PPWrapMode::Repeat);
renderstate->SetOutputTexture(&Ambient0);
renderstate->SetNoBlend();
renderstate->Draw();
// Blur SSAO texture
if (gl_ssao_debug < 2)
{
renderstate->Clear();
renderstate->Shader = &BlurHorizontal;
renderstate->Uniforms.Set(blurUniforms);
renderstate->Viewport = ambientViewport;
renderstate->SetInputTexture(0, &Ambient0);
renderstate->SetOutputTexture(&Ambient1);
renderstate->SetNoBlend();
renderstate->Draw();
renderstate->Clear();
renderstate->Shader = &BlurVertical;
renderstate->Uniforms.Set(blurUniforms);
renderstate->Viewport = ambientViewport;
renderstate->SetInputTexture(0, &Ambient1);
renderstate->SetOutputTexture(&Ambient0);
renderstate->SetNoBlend();
renderstate->Draw();
}
// Add SSAO back to scene texture:
renderstate->Clear();
renderstate->Shader = gl_multisample > 1 ? &CombineMS : &Combine;
renderstate->Uniforms.Set(combineUniforms);
renderstate->Viewport = screen->mSceneViewport;
if (gl_ssao_debug < 4)
renderstate->SetInputTexture(0, &Ambient0, PPFilterMode::Linear);
else
renderstate->SetInputSceneNormal(0, PPFilterMode::Linear);
renderstate->SetInputSceneFog(1);
renderstate->SetOutputSceneColor();
if (gl_ssao_debug != 0)
renderstate->SetNoBlend();
else
renderstate->SetAlphaBlend();
renderstate->Draw();
renderstate->PopGroup();
}
/////////////////////////////////////////////////////////////////////////////
PPPresent::PPPresent()
{
static const float data[64] =
{
.0078125, .2578125, .1328125, .3828125, .0234375, .2734375, .1484375, .3984375,
.7578125, .5078125, .8828125, .6328125, .7734375, .5234375, .8984375, .6484375,
.0703125, .3203125, .1953125, .4453125, .0859375, .3359375, .2109375, .4609375,
.8203125, .5703125, .9453125, .6953125, .8359375, .5859375, .9609375, .7109375,
.0390625, .2890625, .1640625, .4140625, .0546875, .3046875, .1796875, .4296875,
.7890625, .5390625, .9140625, .6640625, .8046875, .5546875, .9296875, .6796875,
.1015625, .3515625, .2265625, .4765625, .1171875, .3671875, .2421875, .4921875,
.8515625, .6015625, .9765625, .7265625, .8671875, .6171875, .9921875, .7421875,
};
std::shared_ptr<void> pixels(new float[64], [](void *p) { delete[](float*)p; });
memcpy(pixels.get(), data, 64 * sizeof(float));
Dither = { 8, 8, PixelFormat::R32f, pixels };
}
void Postprocess::Pass1(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight)
{
exposure.Render(state, sceneWidth, sceneHeight);
bloom.RenderBloom(state, sceneWidth, sceneHeight, fixedcm);
}
void Postprocess::Pass2(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight)
{
tonemap.Render(state);
lens.Render(state);
fxaa.Render(state);
}

View file

@ -1,771 +0,0 @@
#pragma once
#include "hwrenderer/data/shaderuniforms.h"
#include <memory>
#include <map>
struct PostProcessShader;
typedef FRenderStyle PPBlendMode;
typedef IntRect PPViewport;
class PPTexture;
class PPShader;
enum class PPFilterMode { Nearest, Linear };
enum class PPWrapMode { Clamp, Repeat };
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap };
class PPTextureInput
{
public:
PPFilterMode Filter = PPFilterMode::Nearest;
PPWrapMode Wrap = PPWrapMode::Clamp;
PPTextureType Type = PPTextureType::CurrentPipelineTexture;
PPTexture *Texture = nullptr;
};
class PPOutput
{
public:
PPTextureType Type = PPTextureType::NextPipelineTexture;
PPTexture *Texture = nullptr;
};
class PPUniforms
{
public:
PPUniforms()
{
}
PPUniforms(const PPUniforms &src)
{
Data = src.Data;
}
~PPUniforms()
{
Clear();
}
PPUniforms &operator=(const PPUniforms &src)
{
Data = src.Data;
return *this;
}
void Clear()
{
Data.Clear();
}
template<typename T>
void Set(const T &v)
{
if (Data.Size() != (int)sizeof(T))
{
Data.Resize(sizeof(T));
memcpy(Data.Data(), &v, Data.Size());
}
}
TArray<uint8_t> Data;
};
class PPRenderState
{
public:
virtual ~PPRenderState() = default;
virtual void PushGroup(const FString &name) = 0;
virtual void PopGroup() = 0;
virtual void Draw() = 0;
void Clear()
{
Shader = nullptr;
Textures = TArray<PPTextureInput>();
Uniforms = PPUniforms();
Viewport = PPViewport();
BlendMode = PPBlendMode();
Output = PPOutput();
ShadowMapBuffers = false;
}
void SetInputTexture(int index, PPTexture *texture, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
if ((int)Textures.Size() < index + 1)
Textures.Resize(index + 1);
auto &tex = Textures[index];
tex.Filter = filter;
tex.Wrap = wrap;
tex.Type = PPTextureType::PPTexture;
tex.Texture = texture;
}
void SetInputCurrent(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::CurrentPipelineTexture, filter, wrap);
}
void SetInputSceneColor(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneColor, filter, wrap);
}
void SetInputSceneFog(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneFog, filter, wrap);
}
void SetInputSceneNormal(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneNormal, filter, wrap);
}
void SetInputSceneDepth(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneDepth, filter, wrap);
}
void SetInputSpecialType(int index, PPTextureType type, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
if ((int)Textures.Size() < index + 1)
Textures.Resize(index + 1);
auto &tex = Textures[index];
tex.Filter = filter;
tex.Wrap = wrap;
tex.Type = type;
tex.Texture = nullptr;
}
void SetShadowMapBuffers(bool enable)
{
ShadowMapBuffers = enable;
}
void SetOutputTexture(PPTexture *texture)
{
Output.Type = PPTextureType::PPTexture;
Output.Texture = texture;
}
void SetOutputCurrent()
{
Output.Type = PPTextureType::CurrentPipelineTexture;
Output.Texture = nullptr;
}
void SetOutputNext()
{
Output.Type = PPTextureType::NextPipelineTexture;
Output.Texture = nullptr;
}
void SetOutputSceneColor()
{
Output.Type = PPTextureType::SceneColor;
Output.Texture = nullptr;
}
void SetOutputSwapChain()
{
Output.Type = PPTextureType::SwapChain;
Output.Texture = nullptr;
}
void SetOutputShadowMap()
{
Output.Type = PPTextureType::ShadowMap;
Output.Texture = nullptr;
}
void SetNoBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
BlendMode.SrcAlpha = STYLEALPHA_One;
BlendMode.DestAlpha = STYLEALPHA_Zero;
BlendMode.Flags = 0;
}
void SetAdditiveBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
BlendMode.SrcAlpha = STYLEALPHA_One;
BlendMode.DestAlpha = STYLEALPHA_One;
BlendMode.Flags = 0;
}
void SetAlphaBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
BlendMode.SrcAlpha = STYLEALPHA_Src;
BlendMode.DestAlpha = STYLEALPHA_InvSrc;
BlendMode.Flags = 0;
}
PPShader *Shader;
TArray<PPTextureInput> Textures;
PPUniforms Uniforms;
PPViewport Viewport;
PPBlendMode BlendMode;
PPOutput Output;
bool ShadowMapBuffers = false;
};
enum class PixelFormat
{
Rgba8,
Rgba16f,
R32f,
Rg16f,
Rgba16_snorm
};
class PPResource
{
public:
PPResource()
{
Next = First;
First = this;
if (Next) Next->Prev = this;
}
PPResource(const PPResource &)
{
Next = First;
First = this;
if (Next) Next->Prev = this;
}
virtual ~PPResource()
{
if (Next) Next->Prev = Prev;
if (Prev) Prev->Next = Next;
else First = Next;
}
PPResource &operator=(const PPResource &other)
{
return *this;
}
static void ResetAll()
{
for (PPResource *cur = First; cur; cur = cur->Next)
cur->ResetBackend();
}
virtual void ResetBackend() = 0;
private:
static PPResource *First;
PPResource *Prev = nullptr;
PPResource *Next = nullptr;
};
class PPTextureBackend
{
public:
virtual ~PPTextureBackend() = default;
};
class PPTexture : public PPResource
{
public:
PPTexture() = default;
PPTexture(int width, int height, PixelFormat format, std::shared_ptr<void> data = {}) : Width(width), Height(height), Format(format), Data(data) { }
void ResetBackend() override { Backend.reset(); }
int Width;
int Height;
PixelFormat Format;
std::shared_ptr<void> Data;
std::unique_ptr<PPTextureBackend> Backend;
};
class PPShaderBackend
{
public:
virtual ~PPShaderBackend() = default;
};
class PPShader : public PPResource
{
public:
PPShader() = default;
PPShader(const FString &fragment, const FString &defines, const std::vector<UniformFieldDesc> &uniforms, int version = 330) : FragmentShader(fragment), Defines(defines), Uniforms(uniforms), Version(version) { }
void ResetBackend() override { Backend.reset(); }
FString VertexShader = "engine/shaders/pp/screenquad.vp";
FString FragmentShader;
FString Defines;
std::vector<UniformFieldDesc> Uniforms;
int Version = 330;
std::unique_ptr<PPShaderBackend> Backend;
};
/////////////////////////////////////////////////////////////////////////////
struct ExtractUniforms
{
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Scale", UniformType::Vec2, offsetof(ExtractUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(ExtractUniforms, Offset) }
};
}
};
struct BlurUniforms
{
float SampleWeights[8];
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "SampleWeights0", UniformType::Float, offsetof(BlurUniforms, SampleWeights[0]) },
{ "SampleWeights1", UniformType::Float, offsetof(BlurUniforms, SampleWeights[1]) },
{ "SampleWeights2", UniformType::Float, offsetof(BlurUniforms, SampleWeights[2]) },
{ "SampleWeights3", UniformType::Float, offsetof(BlurUniforms, SampleWeights[3]) },
{ "SampleWeights4", UniformType::Float, offsetof(BlurUniforms, SampleWeights[4]) },
{ "SampleWeights5", UniformType::Float, offsetof(BlurUniforms, SampleWeights[5]) },
{ "SampleWeights6", UniformType::Float, offsetof(BlurUniforms, SampleWeights[6]) },
{ "SampleWeights7", UniformType::Float, offsetof(BlurUniforms, SampleWeights[7]) },
};
}
};
enum { NumBloomLevels = 4 };
class PPBlurLevel
{
public:
PPViewport Viewport;
PPTexture VTexture;
PPTexture HTexture;
};
class PPBloom
{
public:
void RenderBloom(PPRenderState *renderstate, int sceneWidth, int sceneHeight, int fixedcm);
void RenderBlur(PPRenderState *renderstate, int sceneWidth, int sceneHeight, float gameinfobluramount);
private:
void BlurStep(PPRenderState *renderstate, const BlurUniforms &blurUniforms, PPTexture &input, PPTexture &output, PPViewport viewport, bool vertical);
void UpdateTextures(int width, int height);
static float ComputeBlurGaussian(float n, float theta);
static void ComputeBlurSamples(int sampleCount, float blurAmount, float *sampleWeights);
PPBlurLevel levels[NumBloomLevels];
int lastWidth = 0;
int lastHeight = 0;
PPShader BloomCombine = { "engine/shaders/pp/bloomcombine.fp", "", {} };
PPShader BloomExtract = { "engine/shaders/pp/bloomextract.fp", "", ExtractUniforms::Desc() };
PPShader BlurVertical = { "engine/shaders/pp/blur.fp", "#define BLUR_VERTICAL\n", BlurUniforms::Desc() };
PPShader BlurHorizontal = { "engine/shaders/pp/blur.fp", "#define BLUR_HORIZONTAL\n", BlurUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
struct LensUniforms
{
float AspectRatio;
float Scale;
float Padding0, Padding1;
FVector4 LensDistortionCoefficient;
FVector4 CubicDistortionValue;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Aspect", UniformType::Float, offsetof(LensUniforms, AspectRatio) },
{ "Scale", UniformType::Float, offsetof(LensUniforms, Scale) },
{ "Padding0", UniformType::Float, offsetof(LensUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(LensUniforms, Padding1) },
{ "k", UniformType::Vec4, offsetof(LensUniforms, LensDistortionCoefficient) },
{ "kcube", UniformType::Vec4, offsetof(LensUniforms, CubicDistortionValue) }
};
}
};
class PPLensDistort
{
public:
void Render(PPRenderState *renderstate);
private:
PPShader Lens = { "engine/shaders/pp/lensdistortion.fp", "", LensUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
struct FXAAUniforms
{
FVector2 ReciprocalResolution;
float Padding0, Padding1;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "ReciprocalResolution", UniformType::Vec2, offsetof(FXAAUniforms, ReciprocalResolution) },
{ "Padding0", UniformType::Float, offsetof(FXAAUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(FXAAUniforms, Padding1) }
};
}
};
class PPFXAA
{
public:
void Render(PPRenderState *renderstate);
private:
void CreateShaders();
int GetMaxVersion();
FString GetDefines();
PPShader FXAALuma;
PPShader FXAA;
int LastQuality = -1;
};
/////////////////////////////////////////////////////////////////////////////
struct ExposureExtractUniforms
{
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Scale", UniformType::Vec2, offsetof(ExposureExtractUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(ExposureExtractUniforms, Offset) }
};
}
};
struct ExposureCombineUniforms
{
float ExposureBase;
float ExposureMin;
float ExposureScale;
float ExposureSpeed;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "ExposureBase", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureBase) },
{ "ExposureMin", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureMin) },
{ "ExposureScale", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureScale) },
{ "ExposureSpeed", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureSpeed) }
};
}
};
class PPExposureLevel
{
public:
PPViewport Viewport;
PPTexture Texture;
};
class PPCameraExposure
{
public:
void Render(PPRenderState *renderstate, int sceneWidth, int sceneHeight);
PPTexture CameraTexture = { 1, 1, PixelFormat::R32f };
private:
void UpdateTextures(int width, int height);
std::vector<PPExposureLevel> ExposureLevels;
bool FirstExposureFrame = true;
PPShader ExposureExtract = { "engine/shaders/pp/exposureextract.fp", "", ExposureExtractUniforms::Desc() };
PPShader ExposureAverage = { "engine/shaders/pp/exposureaverage.fp", "", {}, 400 };
PPShader ExposureCombine = { "engine/shaders/pp/exposurecombine.fp", "", ExposureCombineUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
struct ColormapUniforms
{
FVector4 MapStart;
FVector4 MapRange;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "uFixedColormapStart", UniformType::Vec4, offsetof(ColormapUniforms, MapStart) },
{ "uFixedColormapRange", UniformType::Vec4, offsetof(ColormapUniforms, MapRange) },
};
}
};
/////////////////////////////////////////////////////////////////////////////
class PPTonemap
{
public:
void Render(PPRenderState *renderstate);
void ClearTonemapPalette() { PaletteTexture = {}; }
private:
void UpdateTextures();
PPTexture PaletteTexture;
PPShader LinearShader = { "engine/shaders/pp/tonemap.fp", "#define LINEAR\n", {} };
PPShader ReinhardShader = { "engine/shaders/pp/tonemap.fp", "#define REINHARD\n", {} };
PPShader HejlDawsonShader = { "engine/shaders/pp/tonemap.fp", "#define HEJLDAWSON\n", {} };
PPShader Uncharted2Shader = { "engine/shaders/pp/tonemap.fp", "#define UNCHARTED2\n", {} };
PPShader PaletteShader = { "engine/shaders/pp/tonemap.fp", "#define PALETTE\n", {} };
enum TonemapMode
{
None,
Uncharted2,
HejlDawson,
Reinhard,
Linear,
Palette,
NumTonemapModes
};
};
/////////////////////////////////////////////////////////////////////////////
struct LinearDepthUniforms
{
int SampleIndex;
float LinearizeDepthA;
float LinearizeDepthB;
float InverseDepthRangeA;
float InverseDepthRangeB;
float Padding0, Padding1, Padding2;
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "SampleIndex", UniformType::Int, offsetof(LinearDepthUniforms, SampleIndex) },
{ "LinearizeDepthA", UniformType::Float, offsetof(LinearDepthUniforms, LinearizeDepthA) },
{ "LinearizeDepthB", UniformType::Float, offsetof(LinearDepthUniforms, LinearizeDepthB) },
{ "InverseDepthRangeA", UniformType::Float, offsetof(LinearDepthUniforms, InverseDepthRangeA) },
{ "InverseDepthRangeB", UniformType::Float, offsetof(LinearDepthUniforms, InverseDepthRangeB) },
{ "Padding0", UniformType::Float, offsetof(LinearDepthUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(LinearDepthUniforms, Padding1) },
{ "Padding2", UniformType::Float, offsetof(LinearDepthUniforms, Padding2) },
{ "Scale", UniformType::Vec2, offsetof(LinearDepthUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(LinearDepthUniforms, Offset) }
};
}
};
struct SSAOUniforms
{
FVector2 UVToViewA;
FVector2 UVToViewB;
FVector2 InvFullResolution;
float NDotVBias;
float NegInvR2;
float RadiusToScreen;
float AOMultiplier;
float AOStrength;
int SampleIndex;
float Padding0, Padding1;
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "UVToViewA", UniformType::Vec2, offsetof(SSAOUniforms, UVToViewA) },
{ "UVToViewB", UniformType::Vec2, offsetof(SSAOUniforms, UVToViewB) },
{ "InvFullResolution", UniformType::Vec2, offsetof(SSAOUniforms, InvFullResolution) },
{ "NDotVBias", UniformType::Float, offsetof(SSAOUniforms, NDotVBias) },
{ "NegInvR2", UniformType::Float, offsetof(SSAOUniforms, NegInvR2) },
{ "RadiusToScreen", UniformType::Float, offsetof(SSAOUniforms, RadiusToScreen) },
{ "AOMultiplier", UniformType::Float, offsetof(SSAOUniforms, AOMultiplier) },
{ "AOStrength", UniformType::Float, offsetof(SSAOUniforms, AOStrength) },
{ "SampleIndex", UniformType::Int, offsetof(SSAOUniforms, SampleIndex) },
{ "Padding0", UniformType::Float, offsetof(SSAOUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(SSAOUniforms, Padding1) },
{ "Scale", UniformType::Vec2, offsetof(SSAOUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(SSAOUniforms, Offset) },
};
}
};
struct DepthBlurUniforms
{
float BlurSharpness;
float PowExponent;
float Padding0, Padding1;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "BlurSharpness", UniformType::Float, offsetof(DepthBlurUniforms, BlurSharpness) },
{ "PowExponent", UniformType::Float, offsetof(DepthBlurUniforms, PowExponent) },
{ "Padding0", UniformType::Float, offsetof(DepthBlurUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(DepthBlurUniforms, Padding1) }
};
}
};
struct AmbientCombineUniforms
{
int SampleCount;
int DebugMode, Padding1, Padding2;
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "SampleCount", UniformType::Int, offsetof(AmbientCombineUniforms, SampleCount) },
{ "DebugMode", UniformType::Int, offsetof(AmbientCombineUniforms, DebugMode) },
{ "Padding1", UniformType::Int, offsetof(AmbientCombineUniforms, Padding1) },
{ "Padding2", UniformType::Int, offsetof(AmbientCombineUniforms, Padding2) },
{ "Scale", UniformType::Vec2, offsetof(AmbientCombineUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(AmbientCombineUniforms, Offset) }
};
}
};
class PPAmbientOcclusion
{
public:
PPAmbientOcclusion();
void Render(PPRenderState *renderstate, float m5, int sceneWidth, int sceneHeight);
private:
void CreateShaders();
void UpdateTextures(int width, int height);
enum Quality
{
Off,
LowQuality,
MediumQuality,
HighQuality,
NumQualityModes
};
int AmbientWidth = 0;
int AmbientHeight = 0;
int LastQuality = -1;
int LastWidth = 0;
int LastHeight = 0;
PPShader LinearDepth;
PPShader LinearDepthMS;
PPShader AmbientOcclude;
PPShader AmbientOccludeMS;
PPShader BlurVertical;
PPShader BlurHorizontal;
PPShader Combine;
PPShader CombineMS;
PPTexture LinearDepthTexture;
PPTexture Ambient0;
PPTexture Ambient1;
enum { NumAmbientRandomTextures = 3 };
PPTexture AmbientRandomTexture[NumAmbientRandomTextures];
};
struct PresentUniforms
{
float InvGamma;
float Contrast;
float Brightness;
float Saturation;
int GrayFormula;
int WindowPositionParity; // top-of-window might not be top-of-screen
FVector2 Scale;
FVector2 Offset;
float ColorScale;
int HdrMode;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "InvGamma", UniformType::Float, offsetof(PresentUniforms, InvGamma) },
{ "Contrast", UniformType::Float, offsetof(PresentUniforms, Contrast) },
{ "Brightness", UniformType::Float, offsetof(PresentUniforms, Brightness) },
{ "Saturation", UniformType::Float, offsetof(PresentUniforms, Saturation) },
{ "GrayFormula", UniformType::Int, offsetof(PresentUniforms, GrayFormula) },
{ "WindowPositionParity", UniformType::Int, offsetof(PresentUniforms, WindowPositionParity) },
{ "UVScale", UniformType::Vec2, offsetof(PresentUniforms, Scale) },
{ "UVOffset", UniformType::Vec2, offsetof(PresentUniforms, Offset) },
{ "ColorScale", UniformType::Float, offsetof(PresentUniforms, ColorScale) },
{ "HdrMode", UniformType::Int, offsetof(PresentUniforms, HdrMode) }
};
}
};
class PPPresent
{
public:
PPPresent();
PPTexture Dither;
PPShader Present = { "engine/shaders/pp/present.fp", "", PresentUniforms::Desc() };
PPShader Checker3D = { "engine/shaders/pp/present_checker3d.fp", "", PresentUniforms::Desc() };
PPShader Column3D = { "engine/shaders/pp/present_column3d.fp", "", PresentUniforms::Desc() };
PPShader Row3D = { "engine/shaders/pp/present_row3d.fp", "", PresentUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
class Postprocess
{
public:
PPBloom bloom;
PPLensDistort lens;
PPFXAA fxaa;
PPCameraExposure exposure;
PPTonemap tonemap;
PPAmbientOcclusion ssao;
PPPresent present;
void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight);
void Pass2(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight);
};
extern Postprocess hw_postprocess;

View file

@ -1,98 +0,0 @@
/*
** Postprocessing framework
** Copyright (c) 2016-2020 Magnus Norddahl
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
*/
#include "hw_postprocess_cvars.h"
#include "v_video.h"
//==========================================================================
//
// CVARs
//
//==========================================================================
CVAR(Bool, gl_bloom, false, CVAR_ARCHIVE);
CUSTOM_CVAR(Float, gl_bloom_amount, 1.4f, CVAR_ARCHIVE)
{
if (self < 0.1f) self = 0.1f;
}
CVAR(Float, gl_exposure_scale, 1.3f, CVAR_ARCHIVE)
CVAR(Float, gl_exposure_min, 0.35f, CVAR_ARCHIVE)
CVAR(Float, gl_exposure_base, 0.35f, CVAR_ARCHIVE)
CVAR(Float, gl_exposure_speed, 0.05f, CVAR_ARCHIVE)
CUSTOM_CVAR(Int, gl_tonemap, 0, CVAR_ARCHIVE)
{
if (self < 0 || self > 5)
self = 0;
}
CVAR(Bool, gl_lens, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Float, gl_lens_k, -0.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Float, gl_lens_kcube, 0.1f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Float, gl_lens_chromatic, 1.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, gl_fxaa, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < 0 || self >= IFXAAShader::Count)
{
self = 0;
}
}
CUSTOM_CVAR(Int, gl_ssao, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < 0 || self > 3)
self = 0;
}
CUSTOM_CVAR(Int, gl_ssao_portals, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < 0)
self = 0;
}
CVAR(Float, gl_ssao_strength, 0.7f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, gl_ssao_debug, 0, 0)
CVAR(Float, gl_ssao_bias, 0.2f, 0)
CVAR(Float, gl_ssao_radius, 80.0f, 0)
CUSTOM_CVAR(Float, gl_ssao_blur, 16.0f, 0)
{
if (self < 0.1f) self = 0.1f;
}
CUSTOM_CVAR(Float, gl_ssao_exponent, 1.8f, 0)
{
if (self < 0.1f) self = 0.1f;
}
CUSTOM_CVAR(Float, gl_paltonemap_powtable, 2.0f, CVAR_ARCHIVE | CVAR_NOINITCALL)
{
screen->UpdatePalette();
}
CUSTOM_CVAR(Bool, gl_paltonemap_reverselookup, true, CVAR_ARCHIVE | CVAR_NOINITCALL)
{
screen->UpdatePalette();
}
CVAR(Float, gl_menu_blur, -1.0f, CVAR_ARCHIVE)

View file

@ -1,54 +0,0 @@
#pragma once
#include "c_cvars.h"
class IFXAAShader
{
public:
enum Quality
{
None,
Low,
Medium,
High,
Extreme,
Count
};
};
//==========================================================================
//
// CVARs
//
//==========================================================================
EXTERN_CVAR(Bool, gl_bloom)
EXTERN_CVAR(Float, gl_bloom_amount)
EXTERN_CVAR(Float, gl_exposure_scale)
EXTERN_CVAR(Float, gl_exposure_min)
EXTERN_CVAR(Float, gl_exposure_base)
EXTERN_CVAR(Float, gl_exposure_speed)
EXTERN_CVAR(Int, gl_tonemap)
EXTERN_CVAR(Int, gl_bloom_kernel_size)
EXTERN_CVAR(Bool, gl_lens)
EXTERN_CVAR(Float, gl_lens_k)
EXTERN_CVAR(Float, gl_lens_kcube)
EXTERN_CVAR(Float, gl_lens_chromatic)
EXTERN_CVAR(Int, gl_fxaa)
EXTERN_CVAR(Int, gl_ssao)
EXTERN_CVAR(Int, gl_ssao_portals)
EXTERN_CVAR(Float, gl_ssao_strength)
EXTERN_CVAR(Int, gl_ssao_debug)
EXTERN_CVAR(Float, gl_ssao_bias)
EXTERN_CVAR(Float, gl_ssao_radius)
EXTERN_CVAR(Float, gl_ssao_blur)
EXTERN_CVAR(Float, gl_ssao_exponent)
EXTERN_CVAR(Float, gl_paltonemap_powtable)
EXTERN_CVAR(Bool, gl_paltonemap_reverselookup)
EXTERN_CVAR(Float, gl_menu_blur)
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
EXTERN_CVAR(Float, vid_saturation)
EXTERN_CVAR(Int, gl_satformula)

View file

@ -1,30 +0,0 @@
#include "c_cvars.h"
#include "c_dispatch.h"
#include "v_video.h"
#include "hw_cvars.h"
#include "menu/menu.h"
//==========================================================================
//
// Texture CVARs
//
//==========================================================================
#if 0 // left as a reminder that this will have to be refactored later.
CUSTOM_CVAR(Float,gl_texture_filter_anisotropic,8.0f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
{
screen->TextureFilterChanged();
}
CCMD(gl_flush)
{
//TexMan.FlushAll();
}
CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
{
if (self < 0 || self > 6) self=4;
screen->TextureFilterChanged();
}
CVAR(Bool, gl_precache, false, CVAR_ARCHIVE)
#endif

View file

@ -1,71 +0,0 @@
#pragma once
#include "c_cvars.h"
EXTERN_CVAR(Bool,gl_enhanced_nightvision)
EXTERN_CVAR(Int, screenblocks);
EXTERN_CVAR(Bool, gl_texture)
EXTERN_CVAR(Int, gl_texture_filter)
EXTERN_CVAR(Float, gl_texture_filter_anisotropic)
EXTERN_CVAR(Int, gl_texture_format)
EXTERN_CVAR(Bool, gl_texture_usehires)
EXTERN_CVAR(Bool, gl_usefb)
EXTERN_CVAR(Int, gl_weaponlight)
EXTERN_CVAR (Bool, gl_light_sprites);
EXTERN_CVAR (Bool, gl_light_particles);
EXTERN_CVAR (Bool, gl_light_shadowmap);
EXTERN_CVAR (Int, gl_shadowmap_quality);
EXTERN_CVAR(Int, gl_fogmode)
EXTERN_CVAR(Int, gl_lightmode)
EXTERN_CVAR(Bool,gl_mirror_envmap)
EXTERN_CVAR(Bool,gl_mirrors)
EXTERN_CVAR(Bool,gl_mirror_envmap)
EXTERN_CVAR(Float, gl_mask_threshold)
EXTERN_CVAR(Float, gl_mask_sprite_threshold)
EXTERN_CVAR(Int, gl_multisample)
EXTERN_CVAR(Bool, gl_bloom)
EXTERN_CVAR(Float, gl_bloom_amount)
EXTERN_CVAR(Int, gl_bloom_kernel_size)
EXTERN_CVAR(Int, gl_tonemap)
EXTERN_CVAR(Float, gl_exposure)
EXTERN_CVAR(Bool, gl_lens)
EXTERN_CVAR(Float, gl_lens_k)
EXTERN_CVAR(Float, gl_lens_kcube)
EXTERN_CVAR(Float, gl_lens_chromatic)
EXTERN_CVAR(Int, gl_ssao)
EXTERN_CVAR(Int, gl_ssao_portals)
EXTERN_CVAR(Float, gl_ssao_strength)
EXTERN_CVAR(Int, gl_ssao_debug)
EXTERN_CVAR(Float, gl_ssao_bias)
EXTERN_CVAR(Float, gl_ssao_radius)
EXTERN_CVAR(Float, gl_ssao_blur_amount)
EXTERN_CVAR(Int, gl_debug_level)
EXTERN_CVAR(Bool, gl_debug_breakpoint)
EXTERN_CVAR(Bool, gl_usecolorblending)
EXTERN_CVAR(Bool, gl_sprite_blend)
EXTERN_CVAR(Int, gl_spriteclip)
EXTERN_CVAR(Float, gl_sclipthreshold)
EXTERN_CVAR(Float, gl_sclipfactor)
EXTERN_CVAR(Int, gl_particles_style)
EXTERN_CVAR(Int, gl_billboard_mode)
EXTERN_CVAR(Bool, gl_billboard_faces_camera)
EXTERN_CVAR(Bool, gl_billboard_particles)
EXTERN_CVAR(Int, gl_enhanced_nv_stealth)
EXTERN_CVAR(Int, gl_fuzztype)
EXTERN_CVAR(Int, gl_shadowmap_filter)
EXTERN_CVAR(Bool, gl_brightfog)
EXTERN_CVAR(Bool, gl_lightadditivesurfaces)
EXTERN_CVAR(Bool, gl_notexturefill)

View file

@ -1,302 +0,0 @@
/*
** hw_shaderpatcher.cpp
** Modifies shader source to account for different syntax versions or engine changes.
**
**---------------------------------------------------------------------------
** Copyright(C) 2004-2018 Christoph Oelckers
** Copyright(C) 2016-2018 Magnus Norddahl
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "hw_shaderpatcher.h"
static bool IsGlslWhitespace(char c)
{
switch (c)
{
case ' ':
case '\r':
case '\n':
case '\t':
case '\f':
return true;
default:
return false;
}
}
static FString NextGlslToken(const char *chars, long len, long &pos)
{
// Eat whitespace
long tokenStart = pos;
while (tokenStart != len && IsGlslWhitespace(chars[tokenStart]))
tokenStart++;
// Find token end
long tokenEnd = tokenStart;
while (tokenEnd != len && !IsGlslWhitespace(chars[tokenEnd]) && chars[tokenEnd] != ';')
tokenEnd++;
pos = tokenEnd;
return FString(chars + tokenStart, tokenEnd - tokenStart);
}
static bool isShaderType(const char *name)
{
return !strcmp(name, "sampler1D") || !strcmp(name, "sampler2D") || !strcmp(name, "sampler3D") || !strcmp(name, "samplerCube") || !strcmp(name, "sampler2DMS");
}
FString RemoveLegacyUserUniforms(FString code)
{
// User shaders must declare their uniforms via the GLDEFS file.
code.Substitute("uniform sampler2D tex;", " ");
code.Substitute("uniform float timer;", " ");
// The following code searches for legacy uniform declarations in the shader itself and replaces them with whitespace.
long len = (long)code.Len();
char *chars = code.LockBuffer();
long startIndex = 0;
while (true)
{
long matchIndex = code.IndexOf("uniform", startIndex);
if (matchIndex == -1)
break;
bool isLegacyUniformName = false;
bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]);
bool isKeywordEnd = matchIndex + 7 == len || IsGlslWhitespace(chars[matchIndex + 7]);
if (isKeywordStart && isKeywordEnd)
{
long pos = matchIndex + 7;
FString type = NextGlslToken(chars, len, pos);
FString identifier = NextGlslToken(chars, len, pos);
isLegacyUniformName = type.Compare("float") == 0 && identifier.Compare("timer") == 0;
}
if (isLegacyUniformName)
{
long statementEndIndex = code.IndexOf(';', matchIndex + 7);
if (statementEndIndex == -1)
statementEndIndex = len;
for (long i = matchIndex; i <= statementEndIndex; i++)
{
if (!IsGlslWhitespace(chars[i]))
chars[i] = ' ';
}
startIndex = statementEndIndex;
}
else
{
startIndex = matchIndex + 7;
}
}
// Also remove all occurences of the token 'texture2d'. Some shaders may still use this deprecated function to access a sampler.
// Modern GLSL only allows use of 'texture'.
while (true)
{
long matchIndex = code.IndexOf("texture2d", startIndex);
if (matchIndex == -1)
break;
// Check if this is a real token.
bool isKeywordStart = matchIndex == 0 || !isalnum(chars[matchIndex - 1] & 255);
bool isKeywordEnd = matchIndex + 9 == len || !isalnum(chars[matchIndex + 9] & 255);
if (isKeywordStart && isKeywordEnd)
{
chars[matchIndex + 7] = chars[matchIndex + 8] = ' ';
}
startIndex = matchIndex + 9;
}
code.UnlockBuffer();
return code;
}
FString RemoveSamplerBindings(FString code, TArray<std::pair<FString, int>> &samplerstobind)
{
long len = (long)code.Len();
char *chars = code.LockBuffer();
long startIndex = 0;
long startpos, endpos;
while (true)
{
long matchIndex = code.IndexOf("layout(binding", startIndex);
if (matchIndex == -1)
break;
bool isSamplerUniformName = false;
bool isKeywordStart = matchIndex == 0 || IsGlslWhitespace(chars[matchIndex - 1]);
bool isKeywordEnd = matchIndex + 14 == len || IsGlslWhitespace(chars[matchIndex + 14]) || chars[matchIndex + 14] == '=';
if (isKeywordStart && isKeywordEnd)
{
long pos = matchIndex + 14;
startpos = matchIndex;
while (IsGlslWhitespace(chars[pos])) pos++;
if (chars[pos] == '=')
{
char *p;
pos++;
auto val = strtol(&chars[pos], &p, 0);
if (p != &chars[pos])
{
pos = long(p - chars);
while (IsGlslWhitespace(chars[pos])) pos++;
if (chars[pos] == ')')
{
endpos = ++pos;
FString uniform = NextGlslToken(chars, len, pos);
FString type = NextGlslToken(chars, len, pos);
FString identifier = NextGlslToken(chars, len, pos);
isSamplerUniformName = uniform.Compare("uniform") == 0 && isShaderType(type);
if (isSamplerUniformName)
{
samplerstobind.Push(std::make_pair(identifier, val));
for (auto pos = startpos; pos < endpos; pos++)
{
if (!IsGlslWhitespace(chars[pos]))
chars[pos] = ' ';
}
}
}
}
}
}
if (isSamplerUniformName)
{
startIndex = endpos;
}
else
{
startIndex = matchIndex + 7;
}
}
code.UnlockBuffer();
return code;
}
FString RemoveLayoutLocationDecl(FString code, const char *inoutkeyword)
{
long len = (long)code.Len();
char *chars = code.LockBuffer();
long startIndex = 0;
while (true)
{
long matchIndex = code.IndexOf("layout(location", startIndex);
if (matchIndex == -1)
break;
long endIndex = matchIndex;
// Find end of layout declaration
while (chars[endIndex] != ')' && chars[endIndex] != 0)
endIndex++;
if (chars[endIndex] == ')')
endIndex++;
else if (chars[endIndex] == 0)
break;
// Skip whitespace
while (IsGlslWhitespace(chars[endIndex]))
endIndex++;
// keyword following the declaration?
bool keywordFound = true;
long i;
for (i = 0; inoutkeyword[i] != 0; i++)
{
if (chars[endIndex + i] != inoutkeyword[i])
{
keywordFound = false;
break;
}
}
if (keywordFound && IsGlslWhitespace(chars[endIndex + i]))
{
// yes - replace declaration with spaces
for (long i = matchIndex; i < endIndex; i++)
chars[i] = ' ';
}
startIndex = endIndex;
}
code.UnlockBuffer();
return code;
}
/////////////////////////////////////////////////////////////////////////////
// Note: the MaterialShaderIndex enum in gl_shader.h needs to be updated whenever this array is modified.
const FDefaultShader defaultshaders[] =
{
{"Default", "engine/shaders/pp/func_normal.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Warp 1", "engine/shaders/pp/func_warp1.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Warp 2", "engine/shaders/pp/func_warp2.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Brightmap","engine/shaders/pp/func_brightmap.fp", "engine/shaders/pp/material_normal.fp", "#define BRIGHTMAP\n"},
{"Specular", "engine/shaders/pp/func_spec.fp", "engine/shaders/pp/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n"},
{"SpecularBrightmap", "engine/shaders/pp/func_spec.fp", "engine/shaders/pp/material_specular.fp", "#define SPECULAR\n#define NORMALMAP\n#define BRIGHTMAP\n"},
{"PBR","engine/shaders/pp/func_pbr.fp", "engine/shaders/pp/material_pbr.fp", "#define PBR\n#define NORMALMAP\n"},
{"PBRBrightmap","engine/shaders/pp/func_pbr.fp", "engine/shaders/pp/material_pbr.fp", "#define PBR\n#define NORMALMAP\n#define BRIGHTMAP\n"},
{"Paletted", "engine/shaders/pp/func_paletted.fp", "engine/shaders/pp/material_nolight.fp", ""},
{"No Texture", "engine/shaders/pp/func_notexture.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Basic Fuzz", "engine/shaders/pp/fuzz_standard.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Smooth Fuzz", "engine/shaders/pp/fuzz_smooth.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Swirly Fuzz", "engine/shaders/pp/fuzz_swirly.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Translucent Fuzz", "engine/shaders/pp/fuzz_smoothtranslucent.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Jagged Fuzz", "engine/shaders/pp/fuzz_jagged.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Noise Fuzz", "engine/shaders/pp/fuzz_noise.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Smooth Noise Fuzz", "engine/shaders/pp/fuzz_smoothnoise.fp", "engine/shaders/pp/material_normal.fp", ""},
{"Software Fuzz", "engine/shaders/pp/fuzz_software.fp", "engine/shaders/pp/material_normal.fp", ""},
{nullptr,nullptr,nullptr,nullptr}
};
const FEffectShader effectshaders[] =
{
{ "fogboundary", "engine/shaders/pp/main.vp", "engine/shaders/pp/fogboundary.fp", nullptr, nullptr, "#define NO_ALPHATEST\n" },
{ "spheremap", "engine/shaders/pp/main.vp", "engine/shaders/pp/main.fp", "engine/shaders/pp/func_normal.fp", "engine/shaders/pp/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" },
{ "burn", "engine/shaders/pp/main.vp", "engine/shaders/pp/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
{ "stencil", "engine/shaders/pp/main.vp", "engine/shaders/pp/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" },
};

View file

@ -1,30 +0,0 @@
#pragma once
#include "tarray.h"
#include "zstring.h"
#include "utility"
FString RemoveLegacyUserUniforms(FString code);
FString RemoveSamplerBindings(FString code, TArray<std::pair<FString, int>> &samplerstobind); // For GL 3.3 compatibility which cannot declare sampler bindings in the sampler source.
FString RemoveLayoutLocationDecl(FString code, const char *inoutkeyword);
struct FDefaultShader
{
const char * ShaderName;
const char * gettexelfunc;
const char * lightfunc;
const char * Defines;
};
struct FEffectShader
{
const char *ShaderName;
const char *vp;
const char *fp1;
const char *fp2;
const char *fp3;
const char *defines;
};
extern const FDefaultShader defaultshaders[];
extern const FEffectShader effectshaders[];