- updated common code.

Most of what got added is still unused.

# Conflicts:
#	source/build/src/palette.cpp

# Conflicts:
#	source/build/src/palette.cpp

# Conflicts:
#	source/common/engine/i_interface.h
This commit is contained in:
Christoph Oelckers 2020-04-26 00:01:04 +02:00
parent 82eb807090
commit ea08fa0a4e
20 changed files with 1494 additions and 62 deletions

View file

@ -643,7 +643,9 @@ file( GLOB HEADER_FILES
common/thirdparty/*.h
common/thirdparty/rapidjson/*.h
common/thirdparty/math/*h
common/rendering/*.h
common/rendering/gl_load/*.h
common/rendering/hwrenderer/data/*.h
common/scripting/core/*h
common/scripting/vm/*h
common/scripting/jit/*h
@ -862,6 +864,10 @@ set (PCH_SOURCES
common/objects/dobject.cpp
common/objects/dobjgc.cpp
common/objects/dobjtype.cpp
common/rendering/r_videoscale.cpp
common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp
common/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp
common/rendering/gl_load/gl_interface.cpp
common/rendering/gl/gl_debug.cpp
common/rendering/gl/gl_hwtexture.cpp
@ -905,7 +911,6 @@ set (PCH_SOURCES
#core/input/i_input.cpp
core/input/m_joy.cpp
core/rendering/r_videoscale.cpp
core/rendering/v_framebuffer.cpp
core/rendering/v_video.cpp
core/rendering/gl/renderer/gl_renderer.cpp
@ -916,8 +921,6 @@ set (PCH_SOURCES
core/rendering/gl/system/gl_buffers.cpp
core/rendering/gl/system/gl_framebuffer.cpp
core/rendering/hwrenderer/data/flatvertices.cpp
core/rendering/hwrenderer/postprocessing/hw_postprocess.cpp
core/rendering/hwrenderer/postprocessing/hw_postprocess_cvars.cpp
core/rendering/hwrenderer/utility/hw_shaderpatcher.cpp
)
@ -1034,6 +1037,7 @@ include_directories(
common/fonts
common/objects
common/rendering
common/rendering/hwrenderer/data
common/rendering/gl_load
common/rendering/gl
common/scripting/vm
@ -1169,6 +1173,9 @@ source_group("Common\\Platforms\\Unix Files" REGULAR_EXPRESSION "^${CMAKE_CURREN
source_group("Common\\Platforms\\SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/platform/posix/sdl/.+")
source_group("Common\\Platforms\\Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/platform/win32/.+")
source_group("Common\\Rendering" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/.+")
source_group("Common\\Rendering\\Hardware Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/hwrenderer/.+")
source_group("Common\\Rendering\\Hardware Renderer\\Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/hwrenderer/data/.+")
source_group("Common\\Rendering\\Hardware Renderer\\Postprocessing" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/hwrenderer/postprocessing/.+")
source_group("Common\\Rendering\\OpenGL Loader" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/gl_load/.+")
source_group("Common\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/.+")
source_group("Common\\Textures\\Hires" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/.+")

View file

@ -2096,10 +2096,12 @@ int32_t enginePostInit(void)
{
if (!(paletteloaded & PALETTE_MAIN))
I_FatalError("No palette found.");
#if 0
if (!(paletteloaded & PALETTE_SHADE))
I_FatalError("No shade table found.");
if (!(paletteloaded & PALETTE_TRANSLUC))
I_FatalError("No translucency table found.");
#endif
V_LoadTranslations(); // loading the translations must be delayed until the palettes have been fully set up.
lookups.postLoadTables();

View file

@ -0,0 +1,665 @@
#pragma once
#include "v_palette.h"
#include "vectors.h"
#include "matrix.h"
#include "hw_material.h"
#include "texmanip.h"
struct FColormap;
class IVertexBuffer;
class IIndexBuffer;
enum EClearTarget
{
CT_Depth = 1,
CT_Stencil = 2,
CT_Color = 4
};
enum ERenderEffect
{
EFF_NONE = -1,
EFF_FOGBOUNDARY,
EFF_SPHEREMAP,
EFF_BURN,
EFF_STENCIL,
MAX_EFFECTS
};
enum EAlphaFunc
{
Alpha_GEqual = 0,
Alpha_Greater = 1
};
enum EDrawType
{
DT_Points = 0,
DT_Lines = 1,
DT_Triangles = 2,
DT_TriangleFan = 3,
DT_TriangleStrip = 4
};
enum EDepthFunc
{
DF_Less,
DF_LEqual,
DF_Always
};
enum EStencilFlags
{
SF_AllOn = 0,
SF_ColorMaskOff = 1,
SF_DepthMaskOff = 2,
};
enum EStencilOp
{
SOP_Keep = 0,
SOP_Increment = 1,
SOP_Decrement = 2
};
enum ECull
{
Cull_None,
Cull_CCW,
Cull_CW
};
struct FStateVec4
{
float vec[4];
void Set(float r, float g, float b, float a)
{
vec[0] = r;
vec[1] = g;
vec[2] = b;
vec[3] = a;
}
};
struct FMaterialState
{
FMaterial *mMaterial;
int mClampMode;
int mTranslation;
int mOverrideShader;
bool mChanged;
void Reset()
{
mMaterial = nullptr;
mTranslation = 0;
mClampMode = CLAMP_NONE;
mOverrideShader = -1;
mChanged = false;
}
};
struct FDepthBiasState
{
float mFactor;
float mUnits;
bool mChanged;
void Reset()
{
mFactor = 0;
mUnits = 0;
mChanged = false;
}
};
enum EPassType
{
NORMAL_PASS,
GBUFFER_PASS,
MAX_PASS_TYPES
};
struct FVector4PalEntry
{
float r, g, b, a;
bool operator==(const FVector4PalEntry &other) const
{
return r == other.r && g == other.g && b == other.b && a == other.a;
}
bool operator!=(const FVector4PalEntry &other) const
{
return r != other.r || g != other.g || b != other.b || a != other.a;
}
FVector4PalEntry &operator=(PalEntry newvalue)
{
const float normScale = 1.0f / 255.0f;
r = newvalue.r * normScale;
g = newvalue.g * normScale;
b = newvalue.b * normScale;
a = newvalue.a * normScale;
return *this;
}
FVector4PalEntry& SetIA(PalEntry newvalue)
{
const float normScale = 1.0f / 255.0f;
r = newvalue.r * normScale;
g = newvalue.g * normScale;
b = newvalue.b * normScale;
a = 1;
return *this;
}
FVector4PalEntry& SetFlt(float v1, float v2, float v3, float v4)
{
r = v1;
g = v2;
b = v3;
a = v4;
return *this;
}
};
struct StreamData
{
FVector4PalEntry uObjectColor;
FVector4PalEntry uObjectColor2;
FVector4 uDynLightColor;
FVector4PalEntry uAddColor;
FVector4PalEntry uTextureAddColor;
FVector4PalEntry uTextureModulateColor;
FVector4PalEntry uTextureBlendColor;
FVector4PalEntry uFogColor;
float uDesaturationFactor;
float uInterpolationFactor;
float timer;
int useVertexData;
FVector4 uVertexColor;
FVector4 uVertexNormal;
FVector4 uGlowTopPlane;
FVector4 uGlowTopColor;
FVector4 uGlowBottomPlane;
FVector4 uGlowBottomColor;
FVector4 uGradientTopPlane;
FVector4 uGradientBottomPlane;
FVector4 uSplitTopPlane;
FVector4 uSplitBottomPlane;
FVector4 uDetailParms;
};
class FRenderState
{
protected:
uint8_t mFogEnabled;
uint8_t mTextureEnabled:1;
uint8_t mGlowEnabled : 1;
uint8_t mGradientEnabled : 1;
uint8_t mModelMatrixEnabled : 1;
uint8_t mTextureMatrixEnabled : 1;
uint8_t mSplitEnabled : 1;
uint8_t mBrightmapEnabled : 1;
int mLightIndex;
int mSpecialEffect;
int mTextureMode;
int mTextureModeFlags;
int mSoftLight;
float mLightParms[4];
float mAlphaThreshold;
float mClipSplit[2];
StreamData mStreamData = {};
PalEntry mFogColor;
FRenderStyle mRenderStyle;
FMaterialState mMaterial;
FDepthBiasState mBias;
IVertexBuffer *mVertexBuffer;
int mVertexOffsets[2]; // one per binding point
IIndexBuffer *mIndexBuffer;
EPassType mPassType = NORMAL_PASS;
public:
uint64_t firstFrame = 0;
VSMatrix mModelMatrix;
VSMatrix mTextureMatrix;
public:
void Reset()
{
mTextureEnabled = true;
mBrightmapEnabled = mGradientEnabled = mFogEnabled = mGlowEnabled = false;
mFogColor = 0xffffffff;
mStreamData.uFogColor = mFogColor;
mTextureMode = -1;
mTextureModeFlags = 0;
mStreamData.uDesaturationFactor = 0.0f;
mAlphaThreshold = 0.5f;
mModelMatrixEnabled = false;
mTextureMatrixEnabled = false;
mSplitEnabled = false;
mStreamData.uAddColor = 0;
mStreamData.uObjectColor = 0xffffffff;
mStreamData.uObjectColor2 = 0;
mStreamData.uTextureBlendColor = 0;
mStreamData.uTextureAddColor = 0;
mStreamData.uTextureModulateColor = 0;
mSoftLight = 0;
mLightParms[0] = mLightParms[1] = mLightParms[2] = 0.0f;
mLightParms[3] = -1.f;
mSpecialEffect = EFF_NONE;
mLightIndex = -1;
mStreamData.uInterpolationFactor = 0;
mRenderStyle = DefaultRenderStyle();
mMaterial.Reset();
mBias.Reset();
mPassType = NORMAL_PASS;
mVertexBuffer = nullptr;
mVertexOffsets[0] = mVertexOffsets[1] = 0;
mIndexBuffer = nullptr;
mStreamData.uVertexColor = { 1.0f, 1.0f, 1.0f, 1.0f };
mStreamData.uGlowTopColor = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uGlowBottomColor = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uGlowTopPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uGlowBottomPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uGradientTopPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uGradientBottomPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uSplitTopPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uSplitBottomPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uDynLightColor = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uDetailParms = { 0.0f, 0.0f, 0.0f, 0.0f };
mModelMatrix.loadIdentity();
mTextureMatrix.loadIdentity();
ClearClipSplit();
}
void SetNormal(FVector3 norm)
{
mStreamData.uVertexNormal = { norm.X, norm.Y, norm.Z, 0.f };
}
void SetNormal(float x, float y, float z)
{
mStreamData.uVertexNormal = { x, y, z, 0.f };
}
void SetColor(float r, float g, float b, float a = 1.f, int desat = 0)
{
mStreamData.uVertexColor = { r, g, b, a };
mStreamData.uDesaturationFactor = desat * (1.0f / 255.0f);
}
void SetColor(PalEntry pe, int desat = 0)
{
const float scale = 1.0f / 255.0f;
mStreamData.uVertexColor = { pe.r * scale, pe.g * scale, pe.b * scale, pe.a * scale };
mStreamData.uDesaturationFactor = desat * (1.0f / 255.0f);
}
void SetColorAlpha(PalEntry pe, float alpha = 1.f, int desat = 0)
{
const float scale = 1.0f / 255.0f;
mStreamData.uVertexColor = { pe.r * scale, pe.g * scale, pe.b * scale, alpha };
mStreamData.uDesaturationFactor = desat * (1.0f / 255.0f);
}
void ResetColor()
{
mStreamData.uVertexColor = { 1.0f, 1.0f, 1.0f, 1.0f };
mStreamData.uDesaturationFactor = 0.0f;
}
void SetTextureMode(int mode)
{
mTextureMode = mode;
}
void SetTextureMode(FRenderStyle style)
{
if (style.Flags & STYLEF_RedIsAlpha)
{
SetTextureMode(TM_ALPHATEXTURE);
}
else if (style.Flags & STYLEF_ColorIsFixed)
{
SetTextureMode(TM_STENCIL);
}
else if (style.Flags & STYLEF_InvertSource)
{
SetTextureMode(TM_INVERSE);
}
}
int GetTextureMode()
{
return mTextureMode;
}
void EnableTexture(bool on)
{
mTextureEnabled = on;
}
void EnableFog(uint8_t on)
{
mFogEnabled = on;
}
void SetEffect(int eff)
{
mSpecialEffect = eff;
}
void EnableGlow(bool on)
{
if (mGlowEnabled && !on)
{
mStreamData.uGlowTopColor = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uGlowBottomColor = { 0.0f, 0.0f, 0.0f, 0.0f };
}
mGlowEnabled = on;
}
void EnableGradient(bool on)
{
mGradientEnabled = on;
}
void EnableBrightmap(bool on)
{
mBrightmapEnabled = on;
}
void EnableSplit(bool on)
{
if (mSplitEnabled && !on)
{
mStreamData.uSplitTopPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
mStreamData.uSplitBottomPlane = { 0.0f, 0.0f, 0.0f, 0.0f };
}
mSplitEnabled = on;
}
void EnableModelMatrix(bool on)
{
mModelMatrixEnabled = on;
}
void EnableTextureMatrix(bool on)
{
mTextureMatrixEnabled = on;
}
void SetGlowParams(float *t, float *b)
{
mStreamData.uGlowTopColor = { t[0], t[1], t[2], t[3] };
mStreamData.uGlowBottomColor = { b[0], b[1], b[2], b[3] };
}
void SetSoftLightLevel(int llevel, int blendfactor = 0)
{
if (blendfactor == 0) mLightParms[3] = llevel / 255.f;
else mLightParms[3] = -1.f;
}
void SetNoSoftLightLevel()
{
mLightParms[3] = -1.f;
}
void SetGlowPlanes(const FVector4 &tp, const FVector4& bp)
{
mStreamData.uGlowTopPlane = tp;
mStreamData.uGlowBottomPlane = bp;
}
void SetGradientPlanes(const FVector4& tp, const FVector4& bp)
{
mStreamData.uGradientTopPlane = tp;
mStreamData.uGradientBottomPlane = bp;
}
void SetSplitPlanes(const FVector4& tp, const FVector4& bp)
{
mStreamData.uSplitTopPlane = tp;
mStreamData.uSplitBottomPlane = bp;
}
void SetDetailParms(float xscale, float yscale, float bias)
{
mStreamData.uDetailParms = { xscale, yscale, bias, 0 };
}
void SetDynLight(float r, float g, float b)
{
mStreamData.uDynLightColor = { r, g, b, 0.0f };
}
void SetObjectColor(PalEntry pe)
{
mStreamData.uObjectColor = pe;
}
void SetObjectColor2(PalEntry pe)
{
mStreamData.uObjectColor2 = pe;
}
void SetAddColor(PalEntry pe)
{
mStreamData.uAddColor = pe;
}
void ApplyTextureManipulation(TextureManipulation* texfx)
{
if (!texfx || texfx->AddColor.a == 0)
{
mStreamData.uTextureAddColor.a = 0; // we only need to set the flags to 0
}
else
{
// set up the whole thing
mStreamData.uTextureAddColor.SetIA(texfx->AddColor);
auto pe = texfx->ModulateColor;
mStreamData.uTextureModulateColor.SetFlt(pe.r * pe.a / 255.f, pe.g * pe.a / 255.f, pe.b * pe.a / 255.f, texfx->DesaturationFactor);
mStreamData.uTextureBlendColor = texfx->BlendColor;
}
}
void SetFog(PalEntry c, float d)
{
const float LOG2E = 1.442692f; // = 1/log(2)
mFogColor = c;
mStreamData.uFogColor = mFogColor;
if (d >= 0.0f) mLightParms[2] = d * (-LOG2E / 64000.f);
}
void SetLightParms(float f, float d)
{
mLightParms[1] = f;
mLightParms[0] = d;
}
PalEntry GetFogColor() const
{
return mFogColor;
}
void AlphaFunc(int func, float thresh)
{
if (func == Alpha_Greater) mAlphaThreshold = thresh;
else mAlphaThreshold = thresh - 0.001f;
}
void SetLightIndex(int index)
{
mLightIndex = index;
}
void SetRenderStyle(FRenderStyle rs)
{
mRenderStyle = rs;
}
void SetRenderStyle(ERenderStyle rs)
{
mRenderStyle = rs;
}
void SetDepthBias(float a, float b)
{
mBias.mFactor = a;
mBias.mUnits = b;
mBias.mChanged = true;
}
void ClearDepthBias()
{
mBias.mFactor = 0;
mBias.mUnits = 0;
mBias.mChanged = true;
}
void SetMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader)
{
mMaterial.mMaterial = mat;
mMaterial.mClampMode = clampmode;
mMaterial.mTranslation = translation;
mMaterial.mOverrideShader = overrideshader;
mMaterial.mChanged = true;
mTextureModeFlags = mat->GetLayerFlags();
}
void SetMaterial(FGameTexture* tex, EUpscaleFlags upscalemask, int scaleflags, int clampmode, int translation, int overrideshader)
{
if (shouldUpscale(tex, upscalemask)) scaleflags |= CTF_Upscale;
SetMaterial(FMaterial::ValidateTexture(tex, scaleflags), clampmode, translation, overrideshader);
}
void SetClipSplit(float bottom, float top)
{
mClipSplit[0] = bottom;
mClipSplit[1] = top;
}
void SetClipSplit(float *vals)
{
memcpy(mClipSplit, vals, 2 * sizeof(float));
}
void GetClipSplit(float *out)
{
memcpy(out, mClipSplit, 2 * sizeof(float));
}
void ClearClipSplit()
{
mClipSplit[0] = -1000000.f;
mClipSplit[1] = 1000000.f;
}
void SetVertexBuffer(IVertexBuffer *vb, int offset0, int offset1)
{
assert(vb);
mVertexBuffer = vb;
mVertexOffsets[0] = offset0;
mVertexOffsets[1] = offset1;
}
void SetIndexBuffer(IIndexBuffer *ib)
{
mIndexBuffer = ib;
}
template <class T> void SetVertexBuffer(T *buffer)
{
auto ptrs = buffer->GetBufferObjects();
SetVertexBuffer(ptrs.first, 0, 0);
SetIndexBuffer(ptrs.second);
}
void SetInterpolationFactor(float fac)
{
mStreamData.uInterpolationFactor = fac;
}
float GetInterpolationFactor()
{
return mStreamData.uInterpolationFactor;
}
void EnableDrawBufferAttachments(bool on) // Used by fog boundary drawer
{
EnableDrawBuffers(on ? GetPassDrawBufferCount() : 1);
}
int GetPassDrawBufferCount()
{
return mPassType == GBUFFER_PASS ? 3 : 1;
}
void SetPassType(EPassType passType)
{
mPassType = passType;
}
EPassType GetPassType()
{
return mPassType;
}
// API-dependent render interface
// Draw commands
virtual void ClearScreen() = 0;
virtual void Draw(int dt, int index, int count, bool apply = true) = 0;
virtual void DrawIndexed(int dt, int index, int count, bool apply = true) = 0;
// Immediate render state change commands. These only change infrequently and should not clutter the render state.
virtual bool SetDepthClamp(bool on) = 0; // Deactivated only by skyboxes.
virtual void SetDepthMask(bool on) = 0; // Used by decals and indirectly by portal setup.
virtual void SetDepthFunc(int func) = 0; // Used by models, portals and mirror surfaces.
virtual void SetDepthRange(float min, float max) = 0; // Used by portal setup.
virtual void SetColorMask(bool r, bool g, bool b, bool a) = 0; // Used by portals.
virtual void SetStencil(int offs, int op, int flags=-1) = 0; // Used by portal setup and render hacks.
virtual void SetCulling(int mode) = 0; // Used by model drawer only.
virtual void EnableClipDistance(int num, bool state) = 0; // Use by sprite sorter for vertical splits.
virtual void Clear(int targets) = 0; // not used during normal rendering
virtual void EnableStencil(bool on) = 0; // always on for 3D, always off for 2D
virtual void SetScissor(int x, int y, int w, int h) = 0; // constant for 3D, changes for 2D
virtual void SetViewport(int x, int y, int w, int h) = 0; // constant for all 3D and all 2D
virtual void EnableDepthTest(bool on) = 0; // used by 2D, portals and render hacks.
virtual void EnableMultisampling(bool on) = 0; // only active for 2D
virtual void EnableLineSmooth(bool on) = 0; // constant setting for each 2D drawer operation
virtual void EnableDrawBuffers(int count, bool apply = false) = 0; // Used by SSAO and EnableDrawBufferAttachments
void SetColorMask(bool on)
{
SetColorMask(on, on, on, on);
}
};

View file

@ -21,19 +21,19 @@
#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 "palutil.h"
#include "palettecontainer.h"
#include "vectors.h"
#include "hwrenderer/postprocessing/hw_postprocessshader.h"
#include <random>
#include "texturemanager.h"
#include "templates.h"
#include "stats.h"
#include "colormaps.h"
Postprocess hw_postprocess;
PPResource *PPResource::First = nullptr;
TArray<PostProcessShader> PostProcessShaders;
bool gpuStatActive = false;
bool keepGpuStatActive = false;
@ -76,7 +76,7 @@ void PPBloom::UpdateTextures(int width, int 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)
if (!gl_bloom || fixedcm != CM_DEFAULT || gl_ssao_debug || sceneWidth <= 0 || sceneHeight <= 0)
{
return;
}
@ -273,7 +273,7 @@ void PPBloom::BlurStep(PPRenderState *renderstate, const BlurUniforms &blurUnifo
float PPBloom::ComputeBlurGaussian(float n, float theta) // theta = Blur Amount
{
return (float)((1.0f / sqrtf(2 * pi::pif() * theta)) * expf(-(n * n) / (2.0f * theta * theta)));
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)
@ -327,9 +327,9 @@ void PPLensDistort::Render(PPRenderState *renderstate)
// 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 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;
LensUniforms uniforms;
@ -395,8 +395,8 @@ 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() };
FXAALuma = { "shaders/glsl/fxaa.fp", "#define FXAA_LUMA_PASS\n", {} };
FXAA = { "shaders/glsl/fxaa.fp", GetDefines(), FXAAUniforms::Desc(), GetMaxVersion() };
LastQuality = gl_fxaa;
}
@ -499,8 +499,8 @@ void PPCameraExposure::Render(PPRenderState *renderstate, int sceneWidth, int sc
void PPCameraExposure::UpdateTextures(int width, int height)
{
int firstwidth = std::max(width / 2, 1);
int firstheight = std::max(height / 2, 1);
int firstwidth = MAX(width / 2, 1);
int firstheight = MAX(height / 2, 1);
if (ExposureLevels.size() > 0 && ExposureLevels[0].Viewport.width == firstwidth && ExposureLevels[0].Viewport.height == firstheight)
{
@ -512,8 +512,8 @@ void PPCameraExposure::UpdateTextures(int width, int height)
int i = 0;
do
{
width = std::max(width / 2, 1);
height = std::max(height / 2, 1);
width = MAX(width / 2, 1);
height = MAX(height / 2, 1);
PPExposureLevel blevel;
blevel.Viewport.left = 0;
@ -532,6 +532,37 @@ void PPCameraExposure::UpdateTextures(int width, int height)
/////////////////////////////////////////////////////////////////////////////
void PPColormap::Render(PPRenderState *renderstate, int fixedcm)
{
if (fixedcm < CM_FIRSTSPECIALCOLORMAP || fixedcm >= CM_MAXCOLORMAP)
{
return;
}
FSpecialColormap *scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP];
float m[] = { scm->ColorizeEnd[0] - scm->ColorizeStart[0],
scm->ColorizeEnd[1] - scm->ColorizeStart[1], scm->ColorizeEnd[2] - scm->ColorizeStart[2], 0.f };
ColormapUniforms uniforms;
uniforms.MapStart = { scm->ColorizeStart[0], scm->ColorizeStart[1], scm->ColorizeStart[2], 0.f };
uniforms.MapRange = m;
renderstate->PushGroup("colormap");
renderstate->Clear();
renderstate->Shader = &Colormap;
renderstate->Uniforms.Set(uniforms);
renderstate->Viewport = screen->mScreenViewport;
renderstate->SetInputCurrent(0);
renderstate->SetOutputNext();
renderstate->SetNoBlend();
renderstate->Draw();
renderstate->PopGroup();
}
/////////////////////////////////////////////////////////////////////////////
void PPTonemap::UpdateTextures()
{
if (gl_tonemap == Palette && !PaletteTexture.Data)
@ -545,7 +576,7 @@ void PPTonemap::UpdateTextures()
{
for (int b = 0; b < 64; b++)
{
PalEntry color = GPalette.BaseColors[(uint8_t)PTM_BestColor((uint32_t*)GPalette.BaseColors, (r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4),
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)];
int index = ((r * 64 + g) * 64 + b) * 4;
lut[index] = color.r;
@ -611,7 +642,7 @@ PPAmbientOcclusion::PPAmbientOcclusion()
for (int i = 0; i < 16; i++)
{
double angle = 2.0 * pi::pi() * distribution(generator) / numDirections[quality];
double angle = 2.0 * M_PI * distribution(generator) / numDirections[quality];
double x = cos(angle);
double y = sin(angle);
double z = distribution(generator);
@ -650,14 +681,14 @@ void PPAmbientOcclusion::CreateShaders()
#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() };
LinearDepth = { "shaders/glsl/lineardepth.fp", "", LinearDepthUniforms::Desc() };
LinearDepthMS = { "shaders/glsl/lineardepth.fp", "#define MULTISAMPLE\n", LinearDepthUniforms::Desc() };
AmbientOcclude = { "shaders/glsl/ssao.fp", defines, SSAOUniforms::Desc() };
AmbientOccludeMS = { "shaders/glsl/ssao.fp", defines + "\n#define MULTISAMPLE\n", SSAOUniforms::Desc() };
BlurVertical = { "shaders/glsl/depthblur.fp", "#define BLUR_VERTICAL\n", DepthBlurUniforms::Desc() };
BlurHorizontal = { "shaders/glsl/depthblur.fp", "#define BLUR_HORIZONTAL\n", DepthBlurUniforms::Desc() };
Combine = { "shaders/glsl/ssaocombine.fp", "", AmbientCombineUniforms::Desc() };
CombineMS = { "shaders/glsl/ssaocombine.fp", "#define MULTISAMPLE\n", AmbientCombineUniforms::Desc() };
LastQuality = gl_ssao;
}
@ -710,7 +741,7 @@ void PPAmbientOcclusion::Render(PPRenderState *renderstate, float m5, int sceneW
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.LinearizeDepthB = MAX(1.0f / screen->GetZNear(), 1.e-8f);
linearUniforms.InverseDepthRangeA = 1.0f;
linearUniforms.InverseDepthRangeB = 0.0f;
linearUniforms.Scale = sceneScale;
@ -833,17 +864,243 @@ PPPresent::PPPresent()
Dither = { 8, 8, PixelFormat::R32f, pixels };
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
CVAR(Bool, gl_custompost, true, 0)
void PPCustomShaders::Run(PPRenderState *renderstate, FString target)
{
if (!gl_custompost)
return;
CreateShaders();
for (auto &shader : mShaders)
{
if (shader->Desc->Target == target && shader->Desc->Enabled)
{
shader->Run(renderstate);
}
}
}
void PPCustomShaders::CreateShaders()
{
if (mShaders.size() == PostProcessShaders.Size())
return;
mShaders.clear();
for (unsigned int i = 0; i < PostProcessShaders.Size(); i++)
{
mShaders.push_back(std::make_unique<PPCustomShaderInstance>(&PostProcessShaders[i]));
}
}
/////////////////////////////////////////////////////////////////////////////
PPCustomShaderInstance::PPCustomShaderInstance(PostProcessShader *desc) : Desc(desc)
{
// Build an uniform block to be used as input
TMap<FString, PostProcessUniformValue>::Iterator it(Desc->Uniforms);
TMap<FString, PostProcessUniformValue>::Pair *pair;
size_t offset = 0;
while (it.NextPair(pair))
{
FString type;
FString name = pair->Key;
switch (pair->Value.Type)
{
case PostProcessUniformType::Float: AddUniformField(offset, name, UniformType::Float, sizeof(float)); break;
case PostProcessUniformType::Int: AddUniformField(offset, name, UniformType::Int, sizeof(int)); break;
case PostProcessUniformType::Vec2: AddUniformField(offset, name, UniformType::Vec2, sizeof(float) * 2); break;
case PostProcessUniformType::Vec3: AddUniformField(offset, name, UniformType::Vec3, sizeof(float) * 3, sizeof(float) * 4); break;
default: break;
}
}
UniformStructSize = ((int)offset + 15) / 16 * 16;
// Build the input textures
FString uniformTextures;
uniformTextures += "layout(binding=0) uniform sampler2D InputTexture;\n";
TMap<FString, FString>::Iterator itTextures(Desc->Textures);
TMap<FString, FString>::Pair *pairTextures;
int binding = 1;
while (itTextures.NextPair(pairTextures))
{
uniformTextures.AppendFormat("layout(binding=%d) uniform sampler2D %s;\n", binding++, pairTextures->Key.GetChars());
}
// Setup pipeline
FString pipelineInOut;
if (screen->IsVulkan())
{
pipelineInOut += "layout(location=0) in vec2 TexCoord;\n";
pipelineInOut += "layout(location=0) out vec4 FragColor;\n";
}
else
{
pipelineInOut += "in vec2 TexCoord;\n";
pipelineInOut += "out vec4 FragColor;\n";
}
FString prolog;
prolog += uniformTextures;
prolog += pipelineInOut;
Shader = PPShader(Desc->ShaderLumpName, prolog, Fields);
}
void PPCustomShaderInstance::Run(PPRenderState *renderstate)
{
renderstate->PushGroup(Desc->Name);
renderstate->Clear();
renderstate->Shader = &Shader;
renderstate->Viewport = screen->mScreenViewport;
renderstate->SetNoBlend();
renderstate->SetOutputNext();
//renderstate->SetDebugName(Desc->ShaderLumpName.GetChars());
SetTextures(renderstate);
SetUniforms(renderstate);
renderstate->Draw();
renderstate->PopGroup();
}
void PPCustomShaderInstance::SetTextures(PPRenderState *renderstate)
{
renderstate->SetInputCurrent(0, PPFilterMode::Linear);
int textureIndex = 1;
TMap<FString, FString>::Iterator it(Desc->Textures);
TMap<FString, FString>::Pair *pair;
while (it.NextPair(pair))
{
FString name = pair->Value;
auto gtex = TexMan.GetGameTexture(TexMan.CheckForTexture(name, ETextureType::Any), true);
if (gtex && gtex->isValid())
{
// Why does this completely circumvent the normal way of handling textures?
// This absolutely needs fixing because it will also circumvent any potential caching system that may get implemented.
//
// To do: fix the above problem by adding PPRenderState::SetInput(FTexture *tex)
auto tex = gtex->GetTexture();
auto &pptex = Textures[tex];
if (!pptex)
{
auto buffer = tex->CreateTexBuffer(0);
std::shared_ptr<void> data(new uint32_t[buffer.mWidth * buffer.mHeight], [](void *p) { delete[](uint32_t*)p; });
int count = buffer.mWidth * buffer.mHeight;
uint8_t *pixels = (uint8_t *)data.get();
for (int i = 0; i < count; i++)
{
int pos = i << 2;
pixels[pos] = buffer.mBuffer[pos + 2];
pixels[pos + 1] = buffer.mBuffer[pos + 1];
pixels[pos + 2] = buffer.mBuffer[pos];
pixels[pos + 3] = buffer.mBuffer[pos + 3];
}
pptex = std::make_unique<PPTexture>(buffer.mWidth, buffer.mHeight, PixelFormat::Rgba8, data);
}
renderstate->SetInputTexture(textureIndex, pptex.get(), PPFilterMode::Linear, PPWrapMode::Repeat);
textureIndex++;
}
}
}
void PPCustomShaderInstance::SetUniforms(PPRenderState *renderstate)
{
TArray<uint8_t> uniforms;
uniforms.Resize(UniformStructSize);
TMap<FString, PostProcessUniformValue>::Iterator it(Desc->Uniforms);
TMap<FString, PostProcessUniformValue>::Pair *pair;
while (it.NextPair(pair))
{
auto it2 = FieldOffset.find(pair->Key);
if (it2 != FieldOffset.end())
{
uint8_t *dst = &uniforms[it2->second];
float fValues[4];
int iValues[4];
switch (pair->Value.Type)
{
case PostProcessUniformType::Float:
fValues[0] = (float)pair->Value.Values[0];
memcpy(dst, fValues, sizeof(float));
break;
case PostProcessUniformType::Int:
iValues[0] = (int)pair->Value.Values[0];
memcpy(dst, iValues, sizeof(int));
break;
case PostProcessUniformType::Vec2:
fValues[0] = (float)pair->Value.Values[0];
fValues[1] = (float)pair->Value.Values[1];
memcpy(dst, fValues, sizeof(float) * 2);
break;
case PostProcessUniformType::Vec3:
fValues[0] = (float)pair->Value.Values[0];
fValues[1] = (float)pair->Value.Values[1];
fValues[2] = (float)pair->Value.Values[2];
memcpy(dst, fValues, sizeof(float) * 3);
break;
default:
break;
}
}
}
renderstate->Uniforms.Data = uniforms;
}
void PPCustomShaderInstance::AddUniformField(size_t &offset, const FString &name, UniformType type, size_t fieldsize, size_t alignment)
{
if (alignment == 0) alignment = fieldsize;
offset = (offset + alignment - 1) / alignment * alignment;
FieldOffset[name] = offset;
auto name2 = std::make_unique<FString>(name);
auto chars = name2->GetChars();
FieldNames.push_back(std::move(name2));
Fields.push_back({ chars, type, offset });
offset += fieldsize;
if (fieldsize != alignment) // Workaround for buggy OpenGL drivers that does not do std140 layout correctly for vec3
{
name2 = std::make_unique<FString>(name + "_F39350FF12DE_padding");
chars = name2->GetChars();
FieldNames.push_back(std::move(name2));
Fields.push_back({ chars, UniformType::Float, offset });
offset += alignment - fieldsize;
}
}
void Postprocess::Pass1(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight)
{
exposure.Render(state, sceneWidth, sceneHeight);
customShaders.Run(state, "beforebloom");
bloom.RenderBloom(state, sceneWidth, sceneHeight, fixedcm);
}
void Postprocess::Pass2(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight)
{
tonemap.Render(state);
colormap.Render(state, fixedcm);
lens.Render(state);
fxaa.Render(state);
customShaders.Run(state, "scene");
}

View file

@ -303,7 +303,7 @@ public:
void ResetBackend() override { Backend.reset(); }
FString VertexShader = "engine/shaders/pp/screenquad.vp";
FString VertexShader = "shaders/glsl/screenquad.vp";
FString FragmentShader;
FString Defines;
std::vector<UniformFieldDesc> Uniforms;
@ -376,10 +376,10 @@ private:
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() };
PPShader BloomCombine = { "shaders/glsl/bloomcombine.fp", "", {} };
PPShader BloomExtract = { "shaders/glsl/bloomextract.fp", "", ExtractUniforms::Desc() };
PPShader BlurVertical = { "shaders/glsl/blur.fp", "#define BLUR_VERTICAL\n", BlurUniforms::Desc() };
PPShader BlurHorizontal = { "shaders/glsl/blur.fp", "#define BLUR_HORIZONTAL\n", BlurUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
@ -412,7 +412,7 @@ public:
void Render(PPRenderState *renderstate);
private:
PPShader Lens = { "engine/shaders/pp/lensdistortion.fp", "", LensUniforms::Desc() };
PPShader Lens = { "shaders/glsl/lensdistortion.fp", "", LensUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
@ -504,9 +504,9 @@ private:
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() };
PPShader ExposureExtract = { "shaders/glsl/exposureextract.fp", "", ExposureExtractUniforms::Desc() };
PPShader ExposureAverage = { "shaders/glsl/exposureaverage.fp", "", {}, 400 };
PPShader ExposureCombine = { "shaders/glsl/exposurecombine.fp", "", ExposureCombineUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
@ -526,6 +526,15 @@ struct ColormapUniforms
}
};
class PPColormap
{
public:
void Render(PPRenderState *renderstate, int fixedcm);
private:
PPShader Colormap = { "shaders/glsl/colormap.fp", "", ColormapUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
class PPTonemap
@ -539,11 +548,11 @@ private:
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", {} };
PPShader LinearShader = { "shaders/glsl/tonemap.fp", "#define LINEAR\n", {} };
PPShader ReinhardShader = { "shaders/glsl/tonemap.fp", "#define REINHARD\n", {} };
PPShader HejlDawsonShader = { "shaders/glsl/tonemap.fp", "#define HEJLDAWSON\n", {} };
PPShader Uncharted2Shader = { "shaders/glsl/tonemap.fp", "#define UNCHARTED2\n", {} };
PPShader PaletteShader = { "shaders/glsl/tonemap.fp", "#define PALETTE\n", {} };
enum TonemapMode
{
@ -744,10 +753,70 @@ public:
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() };
PPShader Present = { "shaders/glsl/present.fp", "", PresentUniforms::Desc() };
PPShader Checker3D = { "shaders/glsl/present_checker3d.fp", "", PresentUniforms::Desc() };
PPShader Column3D = { "shaders/glsl/present_column3d.fp", "", PresentUniforms::Desc() };
PPShader Row3D = { "shaders/glsl/present_row3d.fp", "", PresentUniforms::Desc() };
};
struct ShadowMapUniforms
{
float ShadowmapQuality;
int NodesCount;
float Padding0, Padding1;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "ShadowmapQuality", UniformType::Float, offsetof(ShadowMapUniforms, ShadowmapQuality) },
{ "NodesCount", UniformType::Int, offsetof(ShadowMapUniforms, NodesCount) },
{ "Padding0", UniformType::Float, offsetof(ShadowMapUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(ShadowMapUniforms, Padding1) },
};
}
};
class PPShadowMap
{
public:
void Update(PPRenderState *renderstate);
private:
PPShader ShadowMap = { "shaders/glsl/shadowmap.fp", "", ShadowMapUniforms::Desc() };
};
class PPCustomShaderInstance
{
public:
PPCustomShaderInstance(PostProcessShader *desc);
void Run(PPRenderState *renderstate);
PostProcessShader *Desc = nullptr;
private:
void AddUniformField(size_t &offset, const FString &name, UniformType type, size_t fieldsize, size_t alignment = 0);
void SetTextures(PPRenderState *renderstate);
void SetUniforms(PPRenderState *renderstate);
PPShader Shader;
int UniformStructSize = 0;
std::vector<UniformFieldDesc> Fields;
std::vector<std::unique_ptr<FString>> FieldNames;
std::map<FTexture*, std::unique_ptr<PPTexture>> Textures;
std::map<FString, size_t> FieldOffset;
};
class PPCustomShaders
{
public:
void Run(PPRenderState *renderstate, FString target);
private:
void CreateShaders();
std::vector<std::unique_ptr<PPCustomShaderInstance>> mShaders;
};
/////////////////////////////////////////////////////////////////////////////
@ -759,9 +828,12 @@ public:
PPLensDistort lens;
PPFXAA fxaa;
PPCameraExposure exposure;
PPColormap colormap;
PPTonemap tonemap;
PPAmbientOcclusion ssao;
PPPresent present;
PPShadowMap shadowmap;
PPCustomShaders customShaders;
void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight);

View file

@ -0,0 +1,32 @@
#pragma once
enum class PostProcessUniformType
{
Undefined,
Int,
Float,
Vec2,
Vec3
};
struct PostProcessUniformValue
{
PostProcessUniformType Type = PostProcessUniformType::Undefined;
double Values[4] = { 0.0, 0.0, 0.0, 0.0 };
};
struct PostProcessShader
{
FString Target;
FString ShaderLumpName;
int ShaderVersion = 0;
FString Name;
bool Enabled = false;
TMap<FString, PostProcessUniformValue> Uniforms;
TMap<FString, FString> Textures;
};
extern TArray<PostProcessShader> PostProcessShaders;

View file

@ -0,0 +1,38 @@
#ifndef __I_VIDEO_H__
#define __I_VIDEO_H__
#include <cstdint>
class DFrameBuffer;
class IVideo
{
public:
virtual ~IVideo() {}
virtual DFrameBuffer *CreateFrameBuffer() = 0;
bool SetResolution();
virtual void DumpAdapters();
};
void I_InitGraphics();
void I_ShutdownGraphics();
extern IVideo *Video;
void I_PolyPresentInit();
uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch);
void I_PolyPresentUnlock(int x, int y, int w, int h);
void I_PolyPresentDeinit();
// Pause a bit.
// [RH] Despite the name, it apparently never waited for the VBL, even in
// the original DOS version (if the Heretic/Hexen source is any indicator).
void I_WaitVBL(int count);
#endif // __I_VIDEO_H__

View file

@ -0,0 +1,306 @@
/*---------------------------------------------------------------------------
**
** Copyright(C) 2017 Magnus Norddahl
** Copyright(C) 2017-2020 Rachael Alexanderson
** 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 <math.h>
#include "c_dispatch.h"
#include "c_cvars.h"
#include "v_video.h"
#include "templates.h"
#include "r_videoscale.h"
#include "cmdlib.h"
#include "v_draw.h"
#include "i_interface.h"
#include "printf.h"
#define NUMSCALEMODES countof(vScaleTable)
extern bool setsizeneeded;
EXTERN_CVAR(Int, vid_aspect)
CUSTOM_CVAR(Int, vid_scale_customwidth, VID_MIN_WIDTH, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < VID_MIN_WIDTH)
self = VID_MIN_WIDTH;
setsizeneeded = true;
}
CUSTOM_CVAR(Int, vid_scale_customheight, VID_MIN_HEIGHT, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < VID_MIN_HEIGHT)
self = VID_MIN_HEIGHT;
setsizeneeded = true;
}
CVAR(Bool, vid_scale_linear, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, vid_scale_custompixelaspect, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
setsizeneeded = true;
if (self < 0.2 || self > 5.0)
self = 1.0;
}
static const int VID_MIN_UI_WIDTH = 640;
static const int VID_MIN_UI_HEIGHT = 400;
namespace
{
uint32_t min_width = VID_MIN_WIDTH;
uint32_t min_height = VID_MIN_HEIGHT;
float v_MinimumToFill(uint32_t inwidth, uint32_t inheight)
{
// sx = screen x dimension, sy = same for y
float sx = (float)inwidth, sy = (float)inheight;
static float lastsx = 0., lastsy = 0., result = 0.;
if (lastsx != sx || lastsy != sy)
{
if (sx <= 0. || sy <= 0.)
return 1.; // prevent x/0 error
// set absolute minimum scale to fill the entire screen but get as close to 640x400 as possible
float ssx = (float)(VID_MIN_UI_WIDTH) / sx, ssy = (float)(VID_MIN_UI_HEIGHT) / sy;
result = (ssx < ssy) ? ssy : ssx;
lastsx = sx;
lastsy = sy;
}
return result;
}
inline uint32_t v_mfillX(uint32_t inwidth, uint32_t inheight)
{
return (uint32_t)((float)inwidth * v_MinimumToFill(inwidth, inheight));
}
inline uint32_t v_mfillY(uint32_t inwidth, uint32_t inheight)
{
return (uint32_t)((float)inheight * v_MinimumToFill(inwidth, inheight));
}
inline void refresh_minimums()
{
// specialUI is tracking a state where high-res console fonts are actually required, and
// aren't actually rendered correctly in 320x200. this forces the game to revert to the 640x400
// minimum set in GZDoom 4.0.0, but only while those fonts are required.
static bool lastspecialUI = false;
bool isInActualMenu = false;
bool specialUI = sysCallbacks && (!sysCallbacks->IsSpecialUI || sysCallbacks->IsSpecialUI());
if (specialUI == lastspecialUI)
return;
lastspecialUI = specialUI;
setsizeneeded = true;
if (!specialUI)
{
min_width = VID_MIN_WIDTH;
min_height = VID_MIN_HEIGHT;
}
else
{
min_width = VID_MIN_UI_WIDTH;
min_height = VID_MIN_UI_HEIGHT;
}
}
// the odd formatting of this struct definition is meant to resemble a table header. set your tab stops to 4 when editing this file.
struct v_ScaleTable
{ bool isValid; uint32_t(*GetScaledWidth)(uint32_t Width, uint32_t Height); uint32_t(*GetScaledHeight)(uint32_t Width, uint32_t Height); float pixelAspect; bool isCustom; };
v_ScaleTable vScaleTable[] =
{
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return Width; }, [](uint32_t Width, uint32_t Height)->uint32_t { return Height; }, 1.0f, false }, // 0 - Native
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillX(Width, Height); }, [](uint32_t Width, uint32_t Height)->uint32_t { return v_mfillY(Width, Height); }, 1.0f, false }, // 6 - Minimum Scale to Fill Entire Screen
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return 640; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 400; }, 1.2f, false }, // 2 - 640x400 (formerly 320x200)
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return 960; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 600; }, 1.2f, false }, // 3 - 960x600 (formerly 640x400)
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return 1280; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 800; }, 1.2f, false }, // 4 - 1280x800
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customwidth; }, [](uint32_t Width, uint32_t Height)->uint32_t { return vid_scale_customheight; }, 1.0f, true }, // 5 - Custom
{ true, [](uint32_t Width, uint32_t Height)->uint32_t { return 320; }, [](uint32_t Width, uint32_t Height)->uint32_t { return 200; }, 1.2f, false }, // 7 - 320x200
};
bool isOutOfBounds(int x)
{
return (x < 0 || x >= int(NUMSCALEMODES) || vScaleTable[x].isValid == false);
}
}
void R_ShowCurrentScaling();
CUSTOM_CVAR(Float, vid_scalefactor, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
setsizeneeded = true;
if (self < 0.05 || self > 2.0)
self = 1.0;
if (self != 1.0)
R_ShowCurrentScaling();
}
CUSTOM_CVAR(Int, vid_scalemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
setsizeneeded = true;
if (isOutOfBounds(self))
self = 0;
}
CUSTOM_CVAR(Bool, vid_cropaspect, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
setsizeneeded = true;
}
bool ViewportLinearScale()
{
if (isOutOfBounds(vid_scalemode))
vid_scalemode = 0;
// always use linear if supersampling
int x = screen->GetClientWidth(), y = screen->GetClientHeight();
float aspectmult = ViewportPixelAspect();
if (aspectmult > 1.f)
aspectmult = 1.f / aspectmult;
if ((ViewportScaledWidth(x,y) > (x * aspectmult)) || (ViewportScaledHeight(x,y) > (y * aspectmult)))
return true;
return vid_scale_linear;
}
int ViewportScaledWidth(int width, int height)
{
if (isOutOfBounds(vid_scalemode))
vid_scalemode = 0;
refresh_minimums();
if (vid_cropaspect && height > 0)
{
width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width;
height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height;
}
return (int)std::max((int32_t)min_width, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledWidth(width, height)));
}
int ViewportScaledHeight(int width, int height)
{
if (isOutOfBounds(vid_scalemode))
vid_scalemode = 0;
if (vid_cropaspect && height > 0)
{
height = ((float)width/height < ActiveRatio(width, height)) ? (int)(width / ActiveRatio(width, height)) : height;
width = ((float)width/height > ActiveRatio(width, height)) ? (int)(height * ActiveRatio(width, height)) : width;
}
return (int)std::max((int32_t)min_height, (int32_t)(vid_scalefactor * vScaleTable[vid_scalemode].GetScaledHeight(width, height)));
}
float ViewportPixelAspect()
{
if (isOutOfBounds(vid_scalemode))
vid_scalemode = 0;
// hack - use custom scaling if in "custom" mode
if (vScaleTable[vid_scalemode].isCustom)
return vid_scale_custompixelaspect;
return vScaleTable[vid_scalemode].pixelAspect;
}
void R_ShowCurrentScaling()
{
int x1 = screen->GetClientWidth(), y1 = screen->GetClientHeight(), x2 = ViewportScaledWidth(x1, y1), y2 = ViewportScaledHeight(x1, y1);
Printf("Current vid_scalefactor: %f\n", (float)(vid_scalefactor));
Printf("Real resolution: %i x %i\nEmulated resolution: %i x %i\n", x1, y1, x2, y2);
}
CCMD (vid_showcurrentscaling)
{
R_ShowCurrentScaling();
}
CCMD (vid_scaletowidth)
{
if (argv.argc() > 1)
{
// the following enables the use of ViewportScaledWidth to get the proper dimensions in custom scale modes
vid_scalefactor = 1;
vid_scalefactor = (float)((double)atof(argv[1]) / ViewportScaledWidth(screen->GetClientWidth(), screen->GetClientHeight()));
}
}
CCMD (vid_scaletoheight)
{
if (argv.argc() > 1)
{
vid_scalefactor = 1;
vid_scalefactor = (float)((double)atof(argv[1]) / ViewportScaledHeight(screen->GetClientWidth(), screen->GetClientHeight()));
}
}
inline bool atob(char* I)
{
if (stricmp (I, "true") == 0 || stricmp (I, "1") == 0)
return true;
return false;
}
CCMD (vid_setscale)
{
if (argv.argc() > 2)
{
vid_scale_customwidth = atoi(argv[1]);
vid_scale_customheight = atoi(argv[2]);
if (argv.argc() > 3)
{
vid_scale_linear = atob(argv[3]);
if (argv.argc() > 4)
{
vid_scale_custompixelaspect = (float)atof(argv[4]);
}
}
vid_scalemode = 5;
vid_scalefactor = 1.0;
}
else
{
Printf("Usage: vid_setscale <x> <y> [bool linear] [float pixel-shape]\nThis command will create a custom viewport scaling mode.\n");
}
}
CCMD (vid_scaletolowest)
{
uint32_t method = 0;
if (argv.argc() > 1)
method = atoi(argv[1]);
switch (method)
{
case 1: // Method 1: set a custom video scaling
vid_scalemode = 5;
vid_scalefactor = 1.0;
vid_scale_custompixelaspect = 1.0;
vid_scale_customwidth = v_mfillX(screen->GetClientWidth(), screen->GetClientHeight());
vid_scale_customheight = v_mfillY(screen->GetClientWidth(), screen->GetClientHeight());
break;
case 2: // Method 2: use the actual downscaling mode directly
vid_scalemode = 1;
vid_scalefactor = 1.0;
break;
default: // Default method: use vid_scalefactor to achieve the result on a default scaling mode
vid_scalemode = 0;
vid_scalefactor = v_MinimumToFill(screen->GetClientWidth(), screen->GetClientHeight());
break;
}
}

View file

@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------
**
** Copyright(C) 2017 Magnus Norddahl
** Copyright(C) 2017-2020 Rachael Alexanderson
** 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.
**---------------------------------------------------------------------------
**
*/
#ifndef __VIDEOSCALE_H__
#define __VIDEOSCALE_H__
EXTERN_CVAR (Int, vid_scalemode)
bool ViewportLinearScale();
int ViewportScaledWidth(int width, int height);
int ViewportScaledHeight(int width, int height);
float ViewportPixelAspect();
#endif //__VIDEOSCALE_H__

17
source/core/colormaps.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef __RES_CMAP_H
#define __RES_CMAP_H
enum EColorManipulation
{
CM_PLAIN2D = -2, // regular 2D drawing.
CM_INVALID = -1,
CM_DEFAULT = 0, // untranslated
CM_FIRSTSPECIALCOLORMAP, // first special fixed colormap
CM_FIRSTSPECIALCOLORMAPFORCED = 0x08000000, // first special fixed colormap, application forced (for 2D overlays)
};
#define CM_MAXCOLORMAP int(CM_FIRSTSPECIALCOLORMAP + SpecialColormaps.Size())
#define CM_MAXCOLORMAPFORCED int(CM_FIRSTSPECIALCOLORMAPFORCED + SpecialColormaps.Size())
#endif

View file

@ -1283,7 +1283,7 @@ void C_FullConsole ()
gamestate = GS_FULLCONSOLE;
primaryLevel->Music = "";
S_Start ();
S_StartMusic();
S_StopMusic(true);
P_FreeLevelData ();
}
else

View file

@ -92,6 +92,7 @@ int myconnectindex, numplayers;
int connecthead, connectpoint2[MAXMULTIPLAYERS];
int32_t xres = -1, yres = -1, bpp = 0;
auto vsnprintfptr = vsnprintf; // This is an inline in Visual Studio but we need an address for it to satisfy the MinGW compiled libraries.
bool setsizeneeded;
MapRecord mapList[512]; // Due to how this gets used it needs to be static. EDuke defines 7 episode plus one spare episode with 64 potential levels each and relies on the static array which is freely accessible by scripts.

View file

@ -27,7 +27,6 @@
#include "hwrenderer/data/shaderuniforms.h"
#include "hwrenderer/scene/hw_viewpointuniforms.h"
#include "hwrenderer/scene/hw_drawinfo.h"
#include "hwrenderer/scene/hw_renderstate.h"
#include "hw_viewpointbuffer.h"

View file

@ -38,6 +38,7 @@
#include "r_videoscale.h"
#include "cmdlib.h"
#include "v_draw.h"
#include "i_interface.h"
#include "c_console.h"
#include "menu/menu.h"
@ -45,12 +46,9 @@
#define NUMSCALEMODES countof(vScaleTable)
bool setsizeneeded;
//extern bool generic_ui;
EXTERN_CVAR(Int, vid_aspect)
EXTERN_CVAR(Bool, log_vgafont)
EXTERN_CVAR(Bool, dlg_vgafont)
CUSTOM_CVAR(Int, vid_scale_customwidth, VID_MIN_WIDTH, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
@ -72,6 +70,9 @@ CUSTOM_CVAR(Float, vid_scale_custompixelaspect, 1.0, CVAR_ARCHIVE | CVAR_GLOBALC
self = 1.0;
}
static const int VID_MIN_UI_WIDTH = 640;
static const int VID_MIN_UI_HEIGHT = 400;
namespace
{
uint32_t min_width = VID_MIN_WIDTH;
@ -87,7 +88,7 @@ namespace
if (sx <= 0. || sy <= 0.)
return 1.; // prevent x/0 error
// set absolute minimum scale to fill the entire screen but get as close to 640x400 as possible
float ssx = (float)(min_width) / sx, ssy = (float)(min_height) / sy;
float ssx = (float)(VID_MIN_UI_WIDTH) / sx, ssy = (float)(VID_MIN_UI_HEIGHT) / sy;
result = (ssx < ssy) ? ssy : ssx;
lastsx = sx;
lastsy = sy;
@ -111,9 +112,7 @@ namespace
static bool lastspecialUI = false;
bool isInActualMenu = false;
// bool specialUI = (generic_ui || !!log_vgafont || !!dlg_vgafont || ConsoleState != c_up ||
// (menuactive == MENU_On && CurrentMenu && !CurrentMenu->IsKindOf("ConversationMenu")));
bool specialUI = true;
bool specialUI = sysCallbacks && (!sysCallbacks->IsSpecialUI || sysCallbacks->IsSpecialUI());
if (specialUI == lastspecialUI)
return;
@ -148,7 +147,7 @@ namespace
};
bool isOutOfBounds(int x)
{
return (x < 0 || x >= NUMSCALEMODES || vScaleTable[x].isValid == false);
return (x < 0 || x >= int(NUMSCALEMODES) || vScaleTable[x].isValid == false);
}
}

View file

@ -47,9 +47,6 @@
static const int VID_MIN_WIDTH = 640;
static const int VID_MIN_HEIGHT = 400;
static const int VID_MIN_UI_WIDTH = 640;
static const int VID_MIN_UI_HEIGHT = 400;
struct sector_t;
struct FPortalSceneState;
class FSkyVertexBuffer;