mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-15 00:41:55 +00:00
- 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:
parent
82eb807090
commit
ea08fa0a4e
20 changed files with 1494 additions and 62 deletions
|
@ -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/.+")
|
||||
|
|
|
@ -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();
|
||||
|
|
665
source/common/rendering/hwrenderer/data/hw_renderstate.h
Normal file
665
source/common/rendering/hwrenderer/data/hw_renderstate.h
Normal 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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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");
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
|
38
source/common/rendering/i_video.h
Normal file
38
source/common/rendering/i_video.h
Normal 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__
|
306
source/common/rendering/r_videoscale.cpp
Normal file
306
source/common/rendering/r_videoscale.cpp
Normal 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;
|
||||
}
|
||||
}
|
40
source/common/rendering/r_videoscale.h
Normal file
40
source/common/rendering/r_videoscale.h
Normal 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
17
source/core/colormaps.h
Normal 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
|
|
@ -1283,7 +1283,7 @@ void C_FullConsole ()
|
|||
gamestate = GS_FULLCONSOLE;
|
||||
primaryLevel->Music = "";
|
||||
S_Start ();
|
||||
S_StartMusic();
|
||||
S_StopMusic(true);
|
||||
P_FreeLevelData ();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue