Merge remote-tracking branch 'gzdoom/modern' into hw_postprocess

This commit is contained in:
Magnus Norddahl 2018-06-24 17:57:02 +02:00
commit 32d837cdf1
164 changed files with 23408 additions and 12966 deletions

View file

@ -50,7 +50,7 @@ CVAR(Bool, gl_light_models, true, CVAR_ARCHIVE)
VSMatrix FGLModelRenderer::GetViewToWorldMatrix()
{
VSMatrix objectToWorldMatrix;
gl_RenderState.mViewMatrix.inverseMatrix(objectToWorldMatrix);
di->VPUniforms.mViewMatrix.inverseMatrix(objectToWorldMatrix);
return objectToWorldMatrix;
}
@ -65,7 +65,7 @@ void FGLModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, con
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) && !(smf->flags & MDL_DONTCULLBACKFACES))
{
glEnable(GL_CULL_FACE);
glFrontFace((mirrored ^ GLPortal::isMirrored()) ? GL_CCW : GL_CW);
glFrontFace((mirrored ^ GLRenderer->mPortalState.isMirrored()) ? GL_CCW : GL_CW);
}
gl_RenderState.mModelMatrix = objectToWorldMatrix;
@ -91,7 +91,7 @@ void FGLModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectTo
if (!(actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]))
{
glEnable(GL_CULL_FACE);
glFrontFace((mirrored ^ GLPortal::isMirrored()) ? GL_CW : GL_CCW);
glFrontFace((mirrored ^ GLRenderer->mPortalState.isMirrored()) ? GL_CW : GL_CCW);
}
gl_RenderState.mModelMatrix = objectToWorldMatrix;
@ -314,27 +314,3 @@ void FModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame
}
}
}
//===========================================================================
//
// gl_RenderModel
//
//===========================================================================
void gl_RenderModel(GLSprite * spr, int mli)
{
FGLModelRenderer renderer(mli);
renderer.RenderModel(spr->x, spr->y, spr->z, spr->modelframe, spr->actor);
}
//===========================================================================
//
// gl_RenderHUDModel
//
//===========================================================================
void gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY, int mli)
{
FGLModelRenderer renderer(mli);
renderer.RenderHUDModel(psp, ofsX, ofsY);
}

View file

@ -29,12 +29,14 @@
#include "r_data/models/models.h"
class GLSprite;
struct FDrawInfo;
class FGLModelRenderer : public FModelRenderer
{
int modellightindex = -1;
FDrawInfo *di;
public:
FGLModelRenderer(int mli) : modellightindex(mli)
FGLModelRenderer(FDrawInfo *d, int mli) : modellightindex(mli), di(d)
{}
ModelRendererType GetType() const override { return GLModelRendererType; }
void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
@ -51,5 +53,3 @@ public:
void DrawElements(int numIndices, size_t offset) override;
};
void gl_RenderModel(GLSprite * spr, int mli);
void gl_RenderHUDModel(DPSprite *psp, float ofsx, float ofsy, int mli);

View file

@ -173,7 +173,7 @@ void gl_SetFog(int lightlevel, int rellight, bool fullbright, const FColormap *c
}
// Make fog a little denser when inside a skybox
if (GLPortal::inskybox) fogdensity+=fogdensity/2;
if (GLRenderer->mPortalState.inskybox) fogdensity+=fogdensity/2;
// no fog in enhanced vision modes!

View file

@ -2,7 +2,7 @@
#define __GL_LIGHTDATA
#include "v_palette.h"
#include "p_3dfloors.h"
#include "r_defs.h"
#include "r_data/renderstyle.h"
#include "hwrenderer/utility/hw_lighting.h"
#include "r_data/colormaps.h"

View file

@ -43,8 +43,8 @@
#include "hwrenderer/postprocessing/hw_presentshader.h"
#include "hwrenderer/postprocessing/hw_postprocess.h"
#include "hwrenderer/postprocessing/hw_postprocess_cvars.h"
#include "hwrenderer/utility/hw_vrmodes.h"
#include "gl/shaders/gl_postprocessshaderinstance.h"
#include "gl/stereo3d/gl_stereo3d.h"
#include "gl/textures/gl_hwtexture.h"
#include "r_videoscale.h"
@ -239,7 +239,7 @@ void FGLRenderBuffers::RenderEffect(const FString &name)
//
//-----------------------------------------------------------------------------
void FGLRenderer::AmbientOccludeScene()
void FGLRenderer::AmbientOccludeScene(float m5)
{
FGLDebug::PushGroup("AmbientOccludeScene");
@ -252,7 +252,7 @@ void FGLRenderer::AmbientOccludeScene()
float aoStrength = gl_ssao_strength;
//float tanHalfFovy = tan(fovy * (M_PI / 360.0f));
float tanHalfFovy = 1.0f / gl_RenderState.mProjectionMatrix.get()[5];
float tanHalfFovy = 1.0f / m5;
float invFocalLenX = tanHalfFovy * (mBuffers->GetSceneWidth() / (float)mBuffers->GetSceneHeight());
float invFocalLenY = tanHalfFovy;
float nDotVBias = clamp(bias, 0.0f, 1.0f);
@ -272,8 +272,8 @@ void FGLRenderer::AmbientOccludeScene()
mBuffers->BindSceneColorTexture(1);
mLinearDepthShader->Bind(NOQUEUE);
if (gl_multisample > 1) mLinearDepthShader->Uniforms->SampleIndex = 0;
mLinearDepthShader->Uniforms->LinearizeDepthA = 1.0f / GetZFar() - 1.0f / GetZNear();
mLinearDepthShader->Uniforms->LinearizeDepthB = MAX(1.0f / GetZNear(), 1.e-8f);
mLinearDepthShader->Uniforms->LinearizeDepthA = 1.0f / screen->GetZFar() - 1.0f / screen->GetZNear();
mLinearDepthShader->Uniforms->LinearizeDepthB = MAX(1.0f / screen->GetZNear(), 1.e-8f);
mLinearDepthShader->Uniforms->InverseDepthRangeA = 1.0f;
mLinearDepthShader->Uniforms->InverseDepthRangeB = 0.0f;
mLinearDepthShader->Uniforms->Scale = sceneScale;
@ -424,18 +424,18 @@ void FGLRenderer::ApplyFXAA()
void FGLRenderer::Flush()
{
const s3d::Stereo3DMode& stereo3dMode = s3d::Stereo3DMode::getCurrentMode();
auto vrmode = VRMode::GetVRMode(true);
const auto &mSceneViewport = screen->mSceneViewport;
const auto &mScreenViewport = screen->mScreenViewport;
if (stereo3dMode.IsMono())
if (vrmode->mEyeCount == 1)
{
CopyToBackbuffer(nullptr, true);
}
else
{
// Render 2D to eye textures
for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix)
for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix)
{
FGLDebug::PushGroup("Eye2D");
mBuffers->BindEyeFB(eye_ix);
@ -448,7 +448,9 @@ void FGLRenderer::Flush()
FGLPostProcessState savedState;
FGLDebug::PushGroup("PresentEyes");
stereo3dMode.Present();
// Note: This here is the ONLY place in the entire engine where the OpenGL dependent parts of the Stereo3D code need to be dealt with.
// There's absolutely no need to create a overly complex class hierarchy for just this.
GLRenderer->PresentStereo();
FGLDebug::PopGroup();
}
}

View file

@ -42,6 +42,7 @@
#include "gl_load/gl_interface.h"
#include "gl/system/gl_framebuffer.h"
#include "hwrenderer/utility/hw_cvars.h"
#include "gl/scene/gl_portal.h"
#include "gl/system/gl_debug.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/renderer/gl_lightdata.h"
@ -49,13 +50,11 @@
#include "gl/renderer/gl_renderbuffers.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_scenedrawer.h"
#include "hwrenderer/postprocessing/hw_ambientshader.h"
#include "hwrenderer/postprocessing/hw_presentshader.h"
#include "hwrenderer/postprocessing/hw_present3dRowshader.h"
#include "hwrenderer/postprocessing/hw_shadowmapshader.h"
#include "gl/shaders/gl_postprocessshaderinstance.h"
#include "gl/stereo3d/gl_stereo3d.h"
#include "gl/textures/gl_samplers.h"
#include "gl/dynlights/gl_lightbuffer.h"
#include "r_videoscale.h"
@ -80,11 +79,8 @@ extern bool NoInterpolateView;
FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
{
framebuffer = fb;
mCurrentPortal = nullptr;
mMirrorCount = 0;
mPlaneMirrorCount = 0;
mAngles = FRotator(0.f, 0.f, 0.f);
mViewVector = FVector2(0,0);
mVBO = nullptr;
mSkyVBO = nullptr;
mShaderManager = nullptr;
@ -121,6 +117,8 @@ void FGLRenderer::Initialize(int width, int height)
mCustomPostProcessShaders = new FCustomPostProcessShaders();
// needed for the core profile, because someone decided it was a good idea to remove the default VAO.
glGenQueries(1, &PortalQueryObject);
glGenVertexArrays(1, &mVAOID);
glBindVertexArray(mVAOID);
FGLDebug::LabelObject(GL_VERTEX_ARRAY, mVAOID, "FGLRenderer.mVAOID");
@ -135,14 +133,10 @@ void FGLRenderer::Initialize(int width, int height)
SetupLevel();
mShaderManager = new FShaderManager;
mSamplerManager = new FSamplerManager;
GLPortal::Initialize();
}
FGLRenderer::~FGLRenderer()
{
GLPortal::Shutdown();
FlushModels();
AActor::DeleteAllAttachedLights();
FMaterial::FlushAll();
@ -157,6 +151,8 @@ FGLRenderer::~FGLRenderer()
glBindVertexArray(0);
glDeleteVertexArrays(1, &mVAOID);
}
if (PortalQueryObject != 0) glDeleteQueries(1, &PortalQueryObject);
if (swdrawer) delete swdrawer;
if (mBuffers) delete mBuffers;
if (mPresentShader) delete mPresentShader;
@ -195,17 +191,6 @@ void FGLRenderer::SetupLevel()
//
//===========================================================================
void FGLRenderer::FlushTextures()
{
FMaterial::FlushAll();
}
//===========================================================================
//
//
//
//===========================================================================
bool FGLRenderer::StartOffscreen()
{
bool firstBind = (mFBID == 0);
@ -281,10 +266,8 @@ sector_t *FGLRenderer::RenderView(player_t* player)
fovratio = ratio;
}
GLSceneDrawer drawer;
mShadowMap.Update();
retsec = drawer.RenderViewpoint(player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
}
All.Unclock();
return retsec;
@ -311,27 +294,70 @@ void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, doub
bounds.width = FHardwareTexture::GetTexDimension(gltex->GetWidth());
bounds.height = FHardwareTexture::GetTexDimension(gltex->GetHeight());
GLSceneDrawer drawer;
drawer.RenderViewpoint(Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false);
FRenderViewpoint texvp;
RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false);
EndOffscreen();
tex->SetUpdated();
}
void FGLRenderer::WriteSavePic(player_t *player, FileWriter *file, int width, int height)
//===========================================================================
//
// Render the view to a savegame picture
//
//===========================================================================
void FGLRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
{
// Todo: This needs to call the software renderer and process the returned image, if so desired.
// This also needs to take out parts of the scene drawer so they can be shared between renderers.
GLSceneDrawer drawer;
drawer.WriteSavePic(player, file, width, height);
IntRect bounds;
bounds.left = 0;
bounds.top = 0;
bounds.width = width;
bounds.height = height;
// if mVBO is persistently mapped we must be sure the GPU finished reading from it before we fill it with new data.
glFinish();
// Switch to render buffers dimensioned for the savepic
mBuffers = mSaveBuffers;
P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector.
gl_RenderState.SetVertexBuffer(mVBO);
mVBO->Reset();
mLights->Clear();
// This shouldn't overwrite the global viewpoint even for a short time.
FRenderViewpoint savevp;
sector_t *viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false);
glDisable(GL_STENCIL_TEST);
gl_RenderState.SetSoftLightLevel(-1);
CopyToBackbuffer(&bounds, false);
// strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers
glFinish();
uint8_t * scr = (uint8_t *)M_Malloc(width * height * 3);
glReadPixels(0,0,width, height,GL_RGB,GL_UNSIGNED_BYTE,scr);
M_CreatePNG (file, scr + ((height-1) * width * 3), NULL, SS_RGB, width, height, -width * 3, Gamma);
M_Free(scr);
// Switch back the screen render buffers
screen->SetViewportRects(nullptr);
mBuffers = mScreenBuffers;
}
//===========================================================================
//
//
//
//===========================================================================
void FGLRenderer::BeginFrame()
{
buffersActive = GLRenderer->mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height);
buffersActive = mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height);
if (buffersActive)
buffersActive = GLRenderer->mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT);
buffersActive = mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT);
}
//===========================================================================
@ -396,9 +422,11 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
const auto &mScreenViewport = screen->mScreenViewport;
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
gl_RenderState.mViewMatrix.loadIdentity();
gl_RenderState.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f);
gl_RenderState.ApplyMatrices();
HWViewpointUniforms matrices;
matrices.SetDefaults();
matrices.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f);
matrices.CalcDependencies();
GLRenderer->mShaderManager->ApplyMatrices(&matrices, NORMAL_PASS);
glDisable(GL_DEPTH_TEST);
@ -524,7 +552,7 @@ void FGLRenderer::Draw2D(F2DDrawer *drawer)
}
glDisable(GL_SCISSOR_TEST);
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
gl_RenderState.SetVertexBuffer(mVBO);
gl_RenderState.EnableTexture(true);
gl_RenderState.EnableBrightmap(true);
gl_RenderState.SetTextureMode(TM_MODULATE);

View file

@ -6,6 +6,7 @@
#include "vectors.h"
#include "r_renderer.h"
#include "r_data/matrix.h"
#include "hwrenderer/scene/hw_portal.h"
#include "gl/dynlights/gl_shadowmap.h"
#include <functional>
@ -37,8 +38,8 @@ class FGL2DDrawer;
class FHardwareTexture;
class FShadowMapShader;
class FCustomPostProcessShaders;
class GLSceneDrawer;
class SWSceneDrawer;
struct FRenderViewpoint;
#define NOQUEUE nullptr // just some token to be used as a placeholder
enum
@ -54,16 +55,14 @@ class FGLRenderer
public:
OpenGLFrameBuffer *framebuffer;
//GLPortal *mClipPortal;
GLPortal *mCurrentPortal;
int mMirrorCount;
int mPlaneMirrorCount;
float mCurrentFoV;
AActor *mViewActor;
FShaderManager *mShaderManager;
FSamplerManager *mSamplerManager;
unsigned int mFBID;
unsigned int mVAOID;
unsigned int PortalQueryObject;
int mOldFBID;
FGLRenderBuffers *mBuffers;
@ -82,21 +81,19 @@ public:
FShadowMap mShadowMap;
FRotator mAngles;
FVector2 mViewVector;
//FRotator mAngles;
FFlatVertexBuffer *mVBO;
FSkyVertexBuffer *mSkyVBO;
FLightBuffer *mLights;
SWSceneDrawer *swdrawer = nullptr;
bool mDrawingScene2D = false;
FPortalSceneState mPortalState;
bool buffersActive = false;
float mSceneClearColor[3];
float mGlobVis = 0.0f;
FGLRenderer(OpenGLFrameBuffer *fb);
~FGLRenderer() ;
@ -104,13 +101,13 @@ public:
void ClearBorders();
void FlushTextures();
void SetupLevel();
void ResetSWScene();
void PresentStereo();
void RenderScreenQuad();
void PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D);
void AmbientOccludeScene();
void AmbientOccludeScene(float m5);
void UpdateCameraExposure();
void BloomScene(int fixedcm);
void TonemapScene();
@ -127,6 +124,10 @@ public:
void WriteSavePic(player_t *player, FileWriter *file, int width, int height);
sector_t *RenderView(player_t *player);
void BeginFrame();
void Set3DViewport(bool mainview);
sector_t *RenderViewpoint (FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
bool StartOffscreen();
void EndOffscreen();
@ -134,9 +135,6 @@ public:
void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, int lightlevel, int bottomclip);
static float GetZNear() { return 5.f; }
static float GetZFar() { return 65536.f; }
};
#include "hwrenderer/scene/hw_fakeflat.h"

View file

@ -42,7 +42,6 @@ void gl_SetTextureMode(int type);
FRenderState gl_RenderState;
CVAR(Bool, gl_direct_state_change, true, 0)
CVAR(Bool, gl_bandedswlight, false, CVAR_ARCHIVE)
static VSMatrix identityMatrix(1);
@ -62,7 +61,7 @@ static void matrixToGL(const VSMatrix &mat, int loc)
void FRenderState::Reset()
{
mTextureEnabled = true;
mClipLineShouldBeActive = mClipLineEnabled = mSplitEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false;
mSplitEnabled = mBrightmapEnabled = mFogEnabled = mGlowEnabled = false;
mColorMask[0] = mColorMask[1] = mColorMask[2] = mColorMask[3] = true;
currentColorMask[0] = currentColorMask[1] = currentColorMask[2] = currentColorMask[3] = true;
mFogColor.d = -1;
@ -81,8 +80,6 @@ void FRenderState::Reset()
mLightParms[0] = mLightParms[1] = mLightParms[2] = 0.0f;
mLightParms[3] = -1.f;
mSpecialEffect = EFF_NONE;
mClipHeight = 0.f;
mClipHeightDirection = 0.f;
mGlossiness = 0.0f;
mSpecularLevel = 0.0f;
mShaderTimer = 0.0f;
@ -96,19 +93,15 @@ void FRenderState::Reset()
mInterpolationFactor = 0.0f;
mColor.Set(1.0f, 1.0f, 1.0f, 1.0f);
mCameraPos.Set(0.0f, 0.0f, 0.0f, 0.0f);
mGlowTop.Set(0.0f, 0.0f, 0.0f, 0.0f);
mGlowBottom.Set(0.0f, 0.0f, 0.0f, 0.0f);
mGlowTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
mGlowBottomPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
mSplitTopPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
mSplitBottomPlane.Set(0.0f, 0.0f, 0.0f, 0.0f);
mClipLine.Set(0.0f, 0.0f, 0.0f, 0.0f);
mDynColor.Set(0.0f, 0.0f, 0.0f, 0.0f);
mEffectState = 0;
activeShader = nullptr;
mProjectionMatrix.loadIdentity();
mViewMatrix.loadIdentity();
mModelMatrix.loadIdentity();
mTextureMatrix.loadIdentity();
mPassType = NORMAL_PASS;
@ -162,23 +155,17 @@ bool FRenderState::ApplyShader()
activeShader->muDesaturation.Set(mDesaturation / 255.f);
activeShader->muFogEnabled.Set(fogset);
activeShader->muPalLightLevels.Set(static_cast<int>(gl_bandedswlight) | (static_cast<int>(gl_fogmode) << 8));
activeShader->muGlobVis.Set(GLRenderer->mGlobVis / 32.0f);
activeShader->muTextureMode.Set(mTextureMode == TM_MODULATE && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode);
activeShader->muCameraPos.Set(mCameraPos.vec);
activeShader->muLightParms.Set(mLightParms);
activeShader->muFogColor.Set(mFogColor);
activeShader->muObjectColor.Set(mObjectColor);
activeShader->muObjectColor2.Set(mObjectColor2);
activeShader->muDynLightColor.Set(mDynColor.vec);
activeShader->muInterpolationFactor.Set(mInterpolationFactor);
activeShader->muClipHeight.Set(mClipHeight);
activeShader->muClipHeightDirection.Set(mClipHeightDirection);
activeShader->muTimer.Set((double)(screen->FrameTime - firstFrame) * (double)mShaderTimer / 1000.);
activeShader->muAlphaThreshold.Set(mAlphaThreshold);
activeShader->muLightIndex.Set(-1);
activeShader->muClipSplit.Set(mClipSplit);
activeShader->muViewHeight.Set(viewheight);
activeShader->muSpecularMaterial.Set(mGlossiness, mSpecularLevel);
if (mGlowEnabled)
@ -213,17 +200,6 @@ bool FRenderState::ApplyShader()
activeShader->currentsplitstate = 0;
}
if (mClipLineEnabled)
{
activeShader->muClipLine.Set(mClipLine.vec);
activeShader->currentcliplinestate = 1;
}
else if (activeShader->currentcliplinestate)
{
activeShader->muClipLine.Set(-10000000.0, 0, 0, 0);
activeShader->currentcliplinestate = 0;
}
if (mTextureMatrixEnabled)
{
matrixToGL(mTextureMatrix, activeShader->texturematrix_index);
@ -304,14 +280,6 @@ void FRenderState::ApplyColorMask()
}
}
void FRenderState::ApplyMatrices()
{
if (GLRenderer->mShaderManager != NULL)
{
GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix, mPassType);
}
}
void FRenderState::ApplyLightIndex(int index)
{
if (index > -1 && GLRenderer->mLights->GetBufferType() == GL_UNIFORM_BUFFER)
@ -320,20 +288,3 @@ void FRenderState::ApplyLightIndex(int index)
}
activeShader->muLightIndex.Set(index);
}
void FRenderState::SetClipHeight(float height, float direction)
{
mClipHeight = height;
mClipHeightDirection = direction;
if (gl.flags & RFL_NO_CLIP_PLANES) return;
if (direction != 0.f)
{
glEnable(GL_CLIP_DISTANCE0);
}
else
{
glDisable(GL_CLIP_DISTANCE0); // GL_CLIP_PLANE0 is the same value so no need to make a distinction
}
}

View file

@ -79,8 +79,6 @@ class FRenderState
uint8_t mFogEnabled;
bool mGlowEnabled;
bool mSplitEnabled;
bool mClipLineEnabled;
bool mClipLineShouldBeActive;
bool mBrightmapEnabled;
bool mColorMask[4];
bool currentColorMask[4];
@ -96,18 +94,15 @@ class FRenderState
bool mTextureMatrixEnabled;
bool mLastDepthClamp;
float mInterpolationFactor;
float mClipHeight, mClipHeightDirection;
float mGlossiness, mSpecularLevel;
float mShaderTimer;
FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer;
FStateVec4 mNormal;
FStateVec4 mColor;
FStateVec4 mCameraPos;
FStateVec4 mGlowTop, mGlowBottom;
FStateVec4 mGlowTopPlane, mGlowBottomPlane;
FStateVec4 mSplitTopPlane, mSplitBottomPlane;
FStateVec4 mClipLine;
PalEntry mFogColor;
PalEntry mObjectColor;
PalEntry mObjectColor2;
@ -131,11 +126,8 @@ class FRenderState
public:
VSMatrix mProjectionMatrix;
VSMatrix mViewMatrix;
VSMatrix mModelMatrix;
VSMatrix mTextureMatrix;
VSMatrix mNormalViewMatrix;
FRenderState()
{
@ -162,7 +154,6 @@ public:
void Apply();
void ApplyColorMask();
void ApplyMatrices();
void ApplyLightIndex(int index);
void SetVertexBuffer(FVertexBuffer *vb)
@ -176,33 +167,6 @@ public:
mCurrentVertexBuffer = NULL;
}
float GetClipHeight()
{
return mClipHeight;
}
float GetClipHeightDirection()
{
return mClipHeightDirection;
}
FStateVec4 &GetClipLine()
{
return mClipLine;
}
bool GetClipLineState()
{
return mClipLineEnabled;
}
bool GetClipLineShouldBeActive()
{
return mClipLineShouldBeActive;
}
void SetClipHeight(float height, float direction);
void SetNormal(FVector3 norm)
{
mNormal.Set(norm.X, norm.Y, norm.Z, 0.f);
@ -307,32 +271,6 @@ public:
}
}
void SetClipLine(line_t *line)
{
mClipLine.Set(line->v1->fX(), line->v1->fY(), line->Delta().X, line->Delta().Y);
}
void EnableClipLine(bool on)
{
if (!(gl.flags & RFL_NO_CLIP_PLANES))
{
mClipLineEnabled = on;
if (on)
{
glEnable(GL_CLIP_DISTANCE0);
}
else
{
glDisable(GL_CLIP_DISTANCE0);
}
}
else
{
// this needs to be flagged because in this case per-sector plane rendering needs to be disabled if a clip plane is active.
mClipLineShouldBeActive = on;
}
}
void EnableBrightmap(bool on)
{
mBrightmapEnabled = on;
@ -348,11 +286,6 @@ public:
mTextureMatrixEnabled = on;
}
void SetCameraPos(float x, float y, float z)
{
mCameraPos.Set(x, z, y, 0);
}
void SetGlowParams(float *t, float *b)
{
mGlowTop.Set(t[0], t[1], t[2], t[3]);

View file

@ -0,0 +1,364 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_stereo3d.cpp
** Stereoscopic 3D API
**
*/
#include "gl_load/gl_system.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/renderer/gl_renderbuffers.h"
#include "hwrenderer/utility/hw_vrmodes.h"
#include "gl/system/gl_framebuffer.h"
#include "gl/renderer/gl_postprocessstate.h"
#include "hwrenderer/postprocessing/hw_presentshader.h"
#include "hwrenderer/postprocessing/hw_present3dRowshader.h"
EXTERN_CVAR(Int, vr_mode)
EXTERN_CVAR(Float, vid_saturation)
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
EXTERN_CVAR(Int, gl_satformula)
//==========================================================================
//
//
//
//==========================================================================
static void PresentAnaglyph(bool r, bool g, bool b)
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
glColorMask(r, g, b, 1);
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
glColorMask(!r, !g, !b, 1);
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
glColorMask(1, 1, 1, 1);
}
//==========================================================================
//
//
//
//==========================================================================
static void PresentSideBySide()
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
// Compute screen regions to use for left and right eye views
int leftWidth = screen->mOutputLetterbox.width / 2;
int rightWidth = screen->mOutputLetterbox.width - leftWidth;
IntRect leftHalfScreen = screen->mOutputLetterbox;
leftHalfScreen.width = leftWidth;
IntRect rightHalfScreen = screen->mOutputLetterbox;
rightHalfScreen.width = rightWidth;
rightHalfScreen.left += leftWidth;
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(leftHalfScreen, true);
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(rightHalfScreen, true);
}
//==========================================================================
//
//
//
//==========================================================================
static void PresentTopBottom()
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
// Compute screen regions to use for left and right eye views
int topHeight = screen->mOutputLetterbox.height / 2;
int bottomHeight = screen->mOutputLetterbox.height - topHeight;
IntRect topHalfScreen = screen->mOutputLetterbox;
topHalfScreen.height = topHeight;
topHalfScreen.top = topHeight;
IntRect bottomHalfScreen = screen->mOutputLetterbox;
bottomHalfScreen.height = bottomHeight;
bottomHalfScreen.top = 0;
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(topHalfScreen, true);
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(bottomHalfScreen, true);
}
//==========================================================================
//
//
//
//==========================================================================
static void prepareInterleavedPresent(FPresentShaderBase& shader)
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
// Bind each eye texture, for composition in the shader
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->mBuffers->BindEyeTexture(1, 1);
glActiveTexture(GL_TEXTURE0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture(GL_TEXTURE1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
const IntRect& box = screen->mOutputLetterbox;
glViewport(box.left, box.top, box.width, box.height);
shader.Bind(NOQUEUE);
if (GLRenderer->framebuffer->IsHWGammaActive())
{
shader.Uniforms->InvGamma = 1.0f;
shader.Uniforms->Contrast = 1.0f;
shader.Uniforms->Brightness = 0.0f;
shader.Uniforms->Saturation = 1.0f;
}
else
{
shader.Uniforms->InvGamma = 1.0f / clamp<float>(Gamma, 0.1f, 4.f);
shader.Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
shader.Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
shader.Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.0f);
shader.Uniforms->GrayFormula = static_cast<int>(gl_satformula);
}
shader.Uniforms->Scale = {
screen->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(),
screen->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()
};
shader.Uniforms.Set();
}
//==========================================================================
//
//
//
//==========================================================================
static void PresentColumnInterleaved()
{
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
// Todo:
//auto clientoffset = screen->GetClientOffset();
//auto windowHOffset = clientoffset.X % 2;
int windowHOffset = 0;
GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset;
GLRenderer->mPresent3dColumnShader->Uniforms.Set();
GLRenderer->RenderScreenQuad();
}
//==========================================================================
//
//
//
//==========================================================================
static void PresentRowInterleaved()
{
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader);
// Todo:
//auto clientoffset = screen->GetClientOffset();
//auto windowVOffset = clientoffset.Y % 2;
int windowVOffset = 0;
GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity =
(windowVOffset
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
) % 2;
GLRenderer->mPresent3dRowShader->Uniforms.Set();
GLRenderer->RenderScreenQuad();
}
//==========================================================================
//
//
//
//==========================================================================
static void PresentCheckerInterleaved()
{
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
//auto clientoffset = screen->GetClientOffset();
//auto windowHOffset = clientoffset.X % 2;
//auto windowVOffset = clientoffset.Y % 2;
int windowHOffset = 0;
int windowVOffset = 0;
GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity =
(windowVOffset
+ windowHOffset
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset
GLRenderer->mPresent3dCheckerShader->Uniforms.Set();
GLRenderer->RenderScreenQuad();
}
//==========================================================================
//
// Sometimes the stereo render context is not ready immediately at start up
//
//==========================================================================
bool QuadStereoCheckInitialRenderContextState()
{
// Keep trying until we see at least one good OpenGL context to render to
static bool bQuadStereoSupported = false;
static bool bDecentContextWasFound = false;
static int contextCheckCount = 0;
if ((!bDecentContextWasFound) && (contextCheckCount < 200))
{
contextCheckCount += 1;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context
GLboolean supportsStereo, supportsBuffered;
glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered);
if (supportsBuffered) // Finally, a useful OpenGL context
{
// This block will be executed exactly ONCE during a game run
bDecentContextWasFound = true; // now we can stop checking every frame...
// Now check whether this context supports hardware stereo
glGetBooleanv(GL_STEREO, &supportsStereo);
bQuadStereoSupported = supportsStereo && supportsBuffered;
}
}
return bQuadStereoSupported;
}
//==========================================================================
//
//
//
//==========================================================================
static void PresentQuadStereo()
{
if (QuadStereoCheckInitialRenderContextState())
{
GLRenderer->mBuffers->BindOutputFB();
glDrawBuffer(GL_BACK_LEFT);
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
glDrawBuffer(GL_BACK_RIGHT);
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
glDrawBuffer(GL_BACK);
}
else
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
}
}
void FGLRenderer::PresentStereo()
{
switch (vr_mode)
{
default:
return;
case VR_GREENMAGENTA:
PresentAnaglyph(false, true, false);
break;
case VR_REDCYAN:
PresentAnaglyph(true, false, false);
break;
case VR_AMBERBLUE:
PresentAnaglyph(true, true, false);
break;
case VR_SIDEBYSIDEFULL:
case VR_SIDEBYSIDESQUISHED:
PresentSideBySide();
break;
case VR_TOPBOTTOM:
PresentTopBottom();
break;
case VR_ROWINTERLEAVED:
PresentRowInterleaved();
break;
case VR_COLUMNINTERLEAVED:
PresentColumnInterleaved();
break;
case VR_CHECKERINTERLEAVED:
PresentCheckerInterleaved();
break;
case VR_QUADSTEREO:
PresentQuadStereo();
break;
}
}

View file

@ -37,13 +37,23 @@
#include "gl/data/gl_vertexbuffer.h"
#include "gl/scene/gl_drawinfo.h"
#include "hwrenderer/scene/hw_clipper.h"
#include "gl/scene/gl_portal.h"
#include "gl/scene/gl_scenedrawer.h"
#include "gl/renderer/gl_renderstate.h"
#include "gl/stereo3d/scoped_color_mask.h"
#include "gl/renderer/gl_quaddrawer.h"
#include "gl/dynlights/gl_lightbuffer.h"
class FDrawInfoList
{
public:
TDeletingArray<FDrawInfo *> mList;
FDrawInfo * GetNew();
void Release(FDrawInfo *);
};
static FDrawInfo * gl_drawinfo;
FDrawInfoList di_list;
@ -63,7 +73,7 @@ void FDrawInfo::DoDrawSorted(HWDrawList *dl, SortNode * head)
if (dl->drawitems[head->itemindex].rendertype == GLDIT_FLAT)
{
z = dl->flats[dl->drawitems[head->itemindex].index]->z;
relation = z > r_viewpoint.Pos.Z ? 1 : -1;
relation = z > Viewpoint.Pos.Z ? 1 : -1;
}
@ -164,23 +174,6 @@ void FDrawInfoList::Release(FDrawInfo * di)
mList.Push(di);
}
//==========================================================================
//
//
//
//==========================================================================
FDrawInfo::FDrawInfo()
{
next = NULL;
}
FDrawInfo::~FDrawInfo()
{
ClearBuffers();
}
//==========================================================================
//
// Sets up a new drawinfo struct
@ -190,12 +183,21 @@ FDrawInfo::~FDrawInfo()
// OpenGL has no use for multiple clippers so use the same one for all DrawInfos.
static Clipper staticClipper;
FDrawInfo *FDrawInfo::StartDrawInfo(GLSceneDrawer *drawer)
FDrawInfo *FDrawInfo::StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms)
{
FDrawInfo *di=di_list.GetNew();
di->mDrawer = drawer;
di->mVBO = GLRenderer->mVBO;
di->mClipper = &staticClipper;
di->Viewpoint = parentvp;
if (uniforms)
{
di->VPUniforms = *uniforms;
// The clip planes will never be inherited from the parent drawinfo.
di->VPUniforms.mClipLine.X = -1000001.f;
di->VPUniforms.mClipHeight = 0;
}
else di->VPUniforms.SetDefaults();
di->mClipper->SetViewpoint(di->Viewpoint);
staticClipper.Clear();
di->StartScene();
return di;
@ -205,7 +207,7 @@ void FDrawInfo::StartScene()
{
ClearBuffers();
next = gl_drawinfo;
outer = gl_drawinfo;
gl_drawinfo = this;
for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset();
decals[0].Clear();
@ -213,7 +215,7 @@ void FDrawInfo::StartScene()
hudsprites.Clear();
// Fullbright information needs to be propagated from the main view.
if (next != nullptr) FullbrightFlags = next->FullbrightFlags;
if (outer != nullptr) FullbrightFlags = outer->FullbrightFlags;
else FullbrightFlags = 0;
}
@ -223,15 +225,15 @@ void FDrawInfo::StartScene()
//
//
//==========================================================================
void FDrawInfo::EndDrawInfo()
FDrawInfo *FDrawInfo::EndDrawInfo()
{
FDrawInfo * di = gl_drawinfo;
for(int i=0;i<GLDL_TYPES;i++) di->drawlists[i].Reset();
gl_drawinfo=di->next;
di_list.Release(di);
assert(this == gl_drawinfo);
for(int i=0;i<GLDL_TYPES;i++) drawlists[i].Reset();
gl_drawinfo=static_cast<FDrawInfo*>(outer);
di_list.Release(this);
if (gl_drawinfo == nullptr)
ResetRenderDataAllocator();
return gl_drawinfo;
}
@ -245,31 +247,30 @@ void FDrawInfo::EndDrawInfo()
void FDrawInfo::SetupFloodStencil(wallseg * ws)
{
int recursion = GLPortal::GetRecursion();
int recursion = GLRenderer->mPortalState.GetRecursion();
// Create stencil
glStencilFunc(GL_EQUAL, recursion, ~0); // create stencil
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels
{
// Use revertible color mask, to avoid stomping on anaglyph 3D state
ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0, 0, 0, 0); // don't write to the graphics buffer
gl_RenderState.EnableTexture(false);
gl_RenderState.ResetColor();
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
glColorMask(0, 0, 0, 0); // don't write to the graphics buffer
gl_RenderState.EnableTexture(false);
gl_RenderState.ResetColor();
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
gl_RenderState.Apply();
FQuadDrawer qd;
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
qd.Render(GL_TRIANGLE_FAN);
gl_RenderState.Apply();
FQuadDrawer qd;
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
qd.Render(GL_TRIANGLE_FAN);
glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil
glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil
} // glColorMask(1, 1, 1, 1); // don't write to the graphics buffer
glColorMask(1, 1, 1, 1); // don't write to the graphics buffer
gl_RenderState.EnableTexture(true);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
@ -277,28 +278,27 @@ void FDrawInfo::SetupFloodStencil(wallseg * ws)
void FDrawInfo::ClearFloodStencil(wallseg * ws)
{
int recursion = GLPortal::GetRecursion();
int recursion = GLRenderer->mPortalState.GetRecursion();
glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
gl_RenderState.EnableTexture(false);
{
// Use revertible color mask, to avoid stomping on anaglyph 3D state
ScopedColorMask colorMask(0, 0, 0, 0); // glColorMask(0,0,0,0); // don't write to the graphics buffer
gl_RenderState.ResetColor();
// Use revertible color mask, to avoid stomping on anaglyph 3D state
glColorMask(0, 0, 0, 0); // don't write to the graphics buffer
gl_RenderState.ResetColor();
gl_RenderState.Apply();
FQuadDrawer qd;
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
qd.Render(GL_TRIANGLE_FAN);
gl_RenderState.Apply();
FQuadDrawer qd;
qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0);
qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0);
qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0);
qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0);
qd.Render(GL_TRIANGLE_FAN);
// restore old stencil op.
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc(GL_EQUAL, recursion, ~0);
gl_RenderState.EnableTexture(true);
} // glColorMask(1, 1, 1, 1);
// restore old stencil op.
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc(GL_EQUAL, recursion, ~0);
gl_RenderState.EnableTexture(true);
glColorMask(1, 1, 1, 1);
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
}
@ -341,9 +341,9 @@ void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, boo
SetFog(lightlevel, rel, &Colormap, false);
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
float fviewx = r_viewpoint.Pos.X;
float fviewy = r_viewpoint.Pos.Y;
float fviewz = r_viewpoint.Pos.Z;
float fviewx = Viewpoint.Pos.X;
float fviewy = Viewpoint.Pos.Y;
float fviewz = Viewpoint.Pos.Z;
gl_RenderState.SetPlaneTextureRotation(&plane, gltexture);
gl_RenderState.Apply();
@ -394,7 +394,7 @@ void FDrawInfo::FloodUpperGap(seg_t * seg)
double frontz = fakefsector->ceilingplane.ZatPoint(seg->v1);
if (fakebsector->GetTexture(sector_t::ceiling)==skyflatnum) return;
if (backz < r_viewpoint.Pos.Z) return;
if (backz < Viewpoint.Pos.Z) return;
if (seg->sidedef == seg->linedef->sidedef[0])
{
@ -447,7 +447,7 @@ void FDrawInfo::FloodLowerGap(seg_t * seg)
if (fakebsector->GetTexture(sector_t::floor) == skyflatnum) return;
if (fakebsector->GetPlaneTexZ(sector_t::floor) > r_viewpoint.Pos.Z) return;
if (fakebsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) return;
if (seg->sidedef == seg->linedef->sidedef[0])
{
@ -478,22 +478,17 @@ void FDrawInfo::FloodLowerGap(seg_t * seg)
ClearFloodStencil(&ws);
}
// This was temporarily moved out of gl_renderhacks.cpp so that the dependency on GLWall could be eliminated until things have progressed a bit.
void FDrawInfo::ProcessLowerMinisegs(TArray<seg_t *> &lowersegs)
{
for(unsigned int j=0;j<lowersegs.Size();j++)
{
seg_t * seg=lowersegs[j];
GLWall wall;
wall.ProcessLowerMiniseg(this, seg, seg->Subsector->render_sector, seg->PartnerSeg->Subsector->render_sector);
rendered_lines++;
}
}
// Same here for the dependency on the portal.
void FDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub)
void FDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *ptg, subsector_t *sub)
{
portal->GetRenderState()->AddSubsector(sub);
auto portal = FindPortal(ptg);
if (!portal)
{
portal = new GLScenePortal(&GLRenderer->mPortalState, new HWSectorStackPortal(ptg));
Portals.Push(portal);
}
auto ptl = static_cast<HWSectorStackPortal*>(static_cast<GLScenePortal*>(portal)->mScene);
ptl->AddSubsector(sub);
}
std::pair<FFlatVertex *, unsigned int> FDrawInfo::AllocVertices(unsigned int count)
@ -515,5 +510,10 @@ int FDrawInfo::UploadLights(FDynLightData &data)
return GLRenderer->mLights->UploadLights(data);
}
bool FDrawInfo::SetDepthClamp(bool on)
{
return gl_RenderState.SetDepthClamp(on);
}

View file

@ -4,13 +4,12 @@
#include "gl/renderer/gl_lightdata.h"
#include "hwrenderer/scene/hw_drawlist.h"
#include "hwrenderer/scene/hw_weapon.h"
#include "hwrenderer/scene/hw_viewpointuniforms.h"
#ifdef _MSC_VER
#pragma warning(disable:4244)
#endif
class GLSceneDrawer;
enum DrawListType
{
GLDL_PLAINWALLS,
@ -36,16 +35,12 @@ enum Drawpasses
struct FDrawInfo : public HWDrawInfo
{
GLSceneDrawer *mDrawer;
FDrawInfo * next;
HWDrawList drawlists[GLDL_TYPES];
TArray<HUDSprite> hudsprites; // These may just be stored by value.
TArray<GLDecal *> decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
FDrawInfo();
~FDrawInfo();
void ApplyVPUniforms() override;
void AddWall(GLWall *wall) override;
void AddMirrorSurface(GLWall *w) override;
GLDecal *AddDecal(bool onmirror) override;
@ -57,15 +52,6 @@ struct FDrawInfo : public HWDrawInfo
std::pair<FFlatVertex *, unsigned int> AllocVertices(unsigned int count) override;
int UploadLights(FDynLightData &data) override;
// Legacy GL only.
bool PutWallCompat(GLWall *wall, int passflag);
bool PutFlatCompat(GLFlat *flat, bool fog);
void RenderFogBoundaryCompat(GLWall *wall);
void RenderLightsCompat(GLWall *wall, int pass);
void DrawSubsectorLights(GLFlat *flat, subsector_t * sub, int pass);
void DrawLightsCompat(GLFlat *flat, int pass);
void DrawDecal(GLDecal *gldecal);
void DrawDecals();
void DrawDecalsForMirror(GLWall *wall);
@ -103,11 +89,19 @@ struct FDrawInfo : public HWDrawInfo
void DrawSorted(int listindex);
// These two may be moved to the API independent part of the renderer later.
void ProcessLowerMinisegs(TArray<seg_t *> &lowersegs) override;
void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub) override;
void CreateScene();
void RenderScene(int recursion);
void RenderTranslucent();
void DrawScene(int drawmode);
void ProcessScene(bool toscreen = false);
void EndDrawScene(sector_t * viewsector);
void DrawEndScene2D(sector_t * viewsector);
bool SetDepthClamp(bool on) override;
static FDrawInfo *StartDrawInfo(GLSceneDrawer *drawer);
static void EndDrawInfo();
static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms);
FDrawInfo *EndDrawInfo();
gl_subsectorrendernode * GetOtherFloorPlanes(unsigned int sector)
{
@ -133,16 +127,6 @@ struct FDrawInfo : public HWDrawInfo
};
class FDrawInfoList
{
TDeletingArray<FDrawInfo *> mList;
public:
FDrawInfo *GetNew();
void Release(FDrawInfo *);
};
void gl_SetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblending);

View file

@ -45,7 +45,6 @@
#include "gl/data/gl_vertexbuffer.h"
#include "gl/dynlights/gl_lightbuffer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_scenedrawer.h"
#include "gl/renderer/gl_quaddrawer.h"
//==========================================================================
@ -167,7 +166,7 @@ void FDrawInfo::ProcessLights(GLFlat *flat, bool istrans)
{
flat->dynlightindex = GLRenderer->mLights->GetIndexPtr();
if (flat->sector->ibocount > 0 && !gl_RenderState.GetClipLineShouldBeActive())
if (flat->sector->ibocount > 0 && !ClipLineShouldBeActive())
{
SetupSectorLights(flat, GLPASS_LIGHTSONLY, nullptr);
}
@ -216,7 +215,7 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool processlights, bool
if (iboindex >= 0)
{
if (vcount > 0 && !gl_RenderState.GetClipLineShouldBeActive())
if (vcount > 0 && !ClipLineShouldBeActive())
{
if (processlights) SetupSectorLights(flat, GLPASS_ALL, &dli);
drawcalls.Clock();

File diff suppressed because it is too large Load diff

View file

@ -37,218 +37,59 @@
#define __GL_PORTAL_H
#include "tarray.h"
#include "r_utility.h"
#include "actor.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/scene/gl_drawinfo.h"
#include "hwrenderer/scene/hw_drawstructs.h"
#include "hwrenderer/scene/hw_portal.h"
extern UniqueList<GLSkyInfo> UniqueSkies;
extern UniqueList<GLHorizonInfo> UniqueHorizons;
extern UniqueList<secplane_t> UniquePlaneMirrors;
struct GLEEHorizonPortal;
class GLSceneDrawer;
class GLPortal : public IPortal
{
static TArray<GLPortal *> portals;
static int recursion;
static unsigned int QueryObject;
protected:
static TArray<float> planestack;
static int MirrorFlag;
static int PlaneMirrorFlag;
static int renderdepth;
public:
static GLSceneDrawer *drawer;
static int PlaneMirrorMode;
static int inupperstack;
static bool inskybox;
private:
void DrawPortalStencil();
DVector3 savedviewpath[2];
DVector3 savedViewPos;
DVector3 savedViewActorPos;
DRotator savedAngles;
bool savedshowviewer;
AActor * savedviewactor;
ActorRenderFlags savedvisibility;
GLPortal *PrevPortal;
TArray<unsigned int> mPrimIndices;
protected:
TArray<GLWall> lines;
int level;
GLPortal(bool local = false) { if (!local) portals.Push(this); }
virtual ~GLPortal() { }
GLPortal(FPortalSceneState *state, bool local = false) : IPortal(state, local) { }
bool Start(bool usestencil, bool doquery, FDrawInfo *outer_di, FDrawInfo **pDi);
void End(bool usestencil);
virtual void DrawContents(FDrawInfo *di)=0;
virtual void * GetSource() const =0; // GetSource MUST be implemented!
void ClearClipper(FDrawInfo *di);
bool Start(bool usestencil, bool doquery, HWDrawInfo *outer_di, HWDrawInfo **pDi) override;
void End(HWDrawInfo *di, bool usestencil) override;
void ClearScreen(HWDrawInfo *di);
};
class GLScenePortal : public GLPortal
{
public:
HWScenePortalBase *mScene;
GLScenePortal(FPortalSceneState *state, HWScenePortalBase *handler) : GLPortal(state)
{
mScene = handler;
handler->SetOwner(this);
}
~GLScenePortal() { delete mScene; }
virtual void * GetSource() const { return mScene->GetSource(); }
virtual const char *GetName() { return mScene->GetName(); }
virtual bool IsSky() { return false; }
virtual bool NeedCap() { return true; }
virtual bool NeedDepthBuffer() { return true; }
void ClearScreen();
virtual const char *GetName() = 0;
virtual void PushState() {}
virtual void PopState() {}
public:
void RenderPortal(bool usestencil, bool doquery, FDrawInfo *outer_di)
{
// Start may perform an occlusion query. If that returns 0 there
// is no need to draw the stencil's contents and there's also no
// need to restore the affected area becasue there is none!
FDrawInfo *di;
if (Start(usestencil, doquery, outer_di, &di))
virtual void DrawContents(HWDrawInfo *di)
{
if (mScene->Setup(di, di->mClipper))
{
DrawContents(di);
End(usestencil);
static_cast<FDrawInfo*>(di)->DrawScene(DM_PORTAL);
mScene->Shutdown(di);
}
else ClearScreen(di);
}
void AddLine(GLWall * l)
{
lines.Push(*l);
}
static int GetRecursion()
{
return recursion;
}
static bool isMirrored() { return !!((MirrorFlag ^ PlaneMirrorFlag) & 1); }
virtual void RenderAttached(FDrawInfo *di) {}
static void BeginScene();
static void StartFrame();
static bool RenderFirstSkyPortal(int recursion, FDrawInfo *outer_di);
static void EndFrame(FDrawInfo *outer_di);
static GLPortal * FindPortal(const void * src);
static void Initialize();
static void Shutdown();
};
struct GLLinePortal : public GLPortal
{
// this must be the same as at the start of line_t, so that we can pass in this structure directly to P_ClipLineToPortal.
vertex_t *v1, *v2; // vertices, from v1 to v2
DVector2 delta; // precalculated v2 - v1 for side checking
angle_t angv1, angv2; // for quick comparisons with a line or subsector
GLLinePortal(line_t *line)
{
v1 = line->v1;
v2 = line->v2;
CalcDelta();
}
GLLinePortal(FLinePortalSpan *line)
{
if (line->lines[0]->mType != PORTT_LINKED || line->v1 == nullptr)
{
// For non-linked portals we must check the actual linedef.
line_t *lline = line->lines[0]->mDestination;
v1 = lline->v1;
v2 = lline->v2;
}
else
{
// For linked portals we can check the merged span.
v1 = line->v1;
v2 = line->v2;
}
CalcDelta();
}
void CalcDelta()
{
delta = v2->fPos() - v1->fPos();
}
line_t *line()
{
vertex_t **pv = &v1;
return reinterpret_cast<line_t*>(pv);
}
virtual int ClipSeg(seg_t *seg);
virtual int ClipSubsector(subsector_t *sub);
virtual int ClipPoint(const DVector2 &pos);
virtual bool NeedCap() { return false; }
virtual void PushState();
virtual void PopState();
};
struct GLMirrorPortal : public GLLinePortal
{
// mirror portals always consist of single linedefs!
line_t * linedef;
protected:
virtual void DrawContents(FDrawInfo *di);
virtual void * GetSource() const { return linedef; }
virtual const char *GetName();
public:
GLMirrorPortal(line_t * line)
: GLLinePortal(line)
{
linedef=line;
}
};
struct GLLineToLinePortal : public GLLinePortal
{
FLinePortalSpan *glport;
protected:
virtual void DrawContents(FDrawInfo *di);
virtual void * GetSource() const { return glport; }
virtual const char *GetName();
virtual line_t *ClipLine() { return line(); }
virtual void RenderAttached(FDrawInfo *di);
public:
GLLineToLinePortal(FLinePortalSpan *ll)
: GLLinePortal(ll)
{
glport = ll;
}
};
struct GLSkyboxPortal : public GLPortal
{
FSectorPortal * portal;
protected:
virtual void DrawContents(FDrawInfo *di);
virtual void * GetSource() const { return portal; }
virtual bool IsSky() { return true; }
virtual const char *GetName();
public:
GLSkyboxPortal(FSectorPortal * pt)
{
portal=pt;
}
virtual void RenderAttached(HWDrawInfo *di) { return mScene->RenderAttached(di); }
};
@ -258,7 +99,7 @@ struct GLSkyPortal : public GLPortal
friend struct GLEEHorizonPortal;
protected:
virtual void DrawContents(FDrawInfo *di);
virtual void DrawContents(HWDrawInfo *di);
virtual void * GetSource() const { return origin; }
virtual bool IsSky() { return true; }
virtual bool NeedDepthBuffer() { return false; }
@ -267,61 +108,14 @@ protected:
public:
GLSkyPortal(GLSkyInfo * pt, bool local = false)
: GLPortal(local)
GLSkyPortal(FPortalSceneState *state, GLSkyInfo * pt, bool local = false)
: GLPortal(state, local)
{
origin=pt;
}
};
struct GLSectorStackPortal : public GLPortal
{
TArray<subsector_t *> subsectors;
protected:
virtual ~GLSectorStackPortal();
virtual void DrawContents(FDrawInfo *di);
virtual void * GetSource() const { return origin; }
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
virtual const char *GetName();
FSectorPortalGroup *origin;
public:
GLSectorStackPortal(FSectorPortalGroup *pt)
{
origin=pt;
}
void SetupCoverage(FDrawInfo *di);
void AddSubsector(subsector_t *sub)
{
subsectors.Push(sub);
}
};
struct GLPlaneMirrorPortal : public GLPortal
{
protected:
virtual void DrawContents(FDrawInfo *di);
virtual void * GetSource() const { return origin; }
virtual const char *GetName();
virtual void PushState();
virtual void PopState();
secplane_t * origin;
public:
GLPlaneMirrorPortal(secplane_t * pt)
{
origin=pt;
}
};
struct GLHorizonPortal : public GLPortal
{
GLHorizonInfo * origin;
@ -330,7 +124,7 @@ struct GLHorizonPortal : public GLPortal
friend struct GLEEHorizonPortal;
protected:
virtual void DrawContents(FDrawInfo *di);
virtual void DrawContents(HWDrawInfo *di);
virtual void * GetSource() const { return origin; }
virtual bool NeedDepthBuffer() { return false; }
virtual bool NeedCap() { return false; }
@ -338,7 +132,7 @@ protected:
public:
GLHorizonPortal(GLHorizonInfo * pt, bool local = false);
GLHorizonPortal(FPortalSceneState *state, GLHorizonInfo * pt, FRenderViewpoint &vp, bool local = false);
};
struct GLEEHorizonPortal : public GLPortal
@ -346,7 +140,7 @@ struct GLEEHorizonPortal : public GLPortal
FSectorPortal * portal;
protected:
virtual void DrawContents(FDrawInfo *di);
virtual void DrawContents(HWDrawInfo *di);
virtual void * GetSource() const { return portal; }
virtual bool NeedDepthBuffer() { return false; }
virtual bool NeedCap() { return false; }
@ -354,7 +148,7 @@ protected:
public:
GLEEHorizonPortal(FSectorPortal *pt)
GLEEHorizonPortal(FPortalSceneState *state, FSectorPortal *pt) : GLPortal(state)
{
portal=pt;
}

View file

@ -50,11 +50,10 @@
#include "gl/renderer/gl_renderbuffers.h"
#include "gl/data/gl_vertexbuffer.h"
#include "hwrenderer/scene/hw_clipper.h"
#include "hwrenderer/scene/hw_portal.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_portal.h"
#include "gl/scene/gl_scenedrawer.h"
#include "gl/stereo3d/gl_stereo3d.h"
#include "hwrenderer/utility/scoped_view_shifter.h"
#include "hwrenderer/utility/hw_vrmodes.h"
//==========================================================================
//
@ -72,136 +71,25 @@ EXTERN_CVAR (Bool, r_deathcamera)
EXTERN_CVAR (Float, r_visibility)
EXTERN_CVAR (Bool, r_drawvoxels)
//-----------------------------------------------------------------------------
//
// R_FrustumAngle
//
//-----------------------------------------------------------------------------
angle_t GLSceneDrawer::FrustumAngle()
void FDrawInfo::ApplyVPUniforms()
{
float tilt = fabs(GLRenderer->mAngles.Pitch.Degrees);
VPUniforms.CalcDependencies();
GLRenderer->mShaderManager->ApplyMatrices(&VPUniforms, NORMAL_PASS);
// If the pitch is larger than this you can look all around at a FOV of 90°
if (tilt > 46.0f) return 0xffffffff;
// ok, this is a gross hack that barely works...
// but at least it doesn't overestimate too much...
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*GLRenderer->mCurrentFoV*48.0 / AspectMultiplier(r_viewwindow.WidescreenRatio) / 90.0;
angle_t a1 = DAngle(floatangle).BAMs();
if (a1 >= ANGLE_180) return 0xffffffff;
return a1;
}
//-----------------------------------------------------------------------------
//
// resets the 3D viewport
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::Reset3DViewport()
{
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
}
//-----------------------------------------------------------------------------
//
// sets 3D viewport and initial state
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::Set3DViewport(bool mainview)
{
if (mainview && GLRenderer->buffersActive)
if (!(gl.flags & RFL_NO_CLIP_PLANES))
{
bool useSSAO = (gl_ssao != 0);
GLRenderer->mBuffers->BindSceneFB(useSSAO);
gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
gl_RenderState.Apply();
if (VPUniforms.mClipHeightDirection != 0.f || VPUniforms.mClipLine.X > -10000000.0f)
{
glEnable(GL_CLIP_DISTANCE0);
}
else
{
glDisable(GL_CLIP_DISTANCE0);
}
}
// Always clear all buffers with scissor test disabled.
// This is faster on newer hardware because it allows the GPU to skip
// reading from slower memory where the full buffers are stored.
glDisable(GL_SCISSOR_TEST);
glClearColor(GLRenderer->mSceneClearColor[0], GLRenderer->mSceneClearColor[1], GLRenderer->mSceneClearColor[2], 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
const auto &bounds = screen->mSceneViewport;
glViewport(bounds.left, bounds.top, bounds.width, bounds.height);
glScissor(bounds.left, bounds.top, bounds.width, bounds.height);
glEnable(GL_SCISSOR_TEST);
glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS,0,~0); // default stencil
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
}
//-----------------------------------------------------------------------------
//
// Setup the camera position
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::SetViewAngle(DAngle viewangle)
{
GLRenderer->mAngles.Yaw = float(270.0-viewangle.Degrees);
DVector2 v = r_viewpoint.Angles.Yaw.ToVector();
GLRenderer->mViewVector.X = v.X;
GLRenderer->mViewVector.Y = v.Y;
R_SetViewAngle(r_viewpoint, r_viewwindow);
}
//-----------------------------------------------------------------------------
//
// SetProjection
// sets projection matrix
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::SetProjection(VSMatrix matrix)
{
gl_RenderState.mProjectionMatrix.loadIdentity();
gl_RenderState.mProjectionMatrix.multMatrix(matrix);
}
//-----------------------------------------------------------------------------
//
// Setup the modelview matrix
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::SetViewMatrix(float vx, float vy, float vz, bool mirror, bool planemirror)
{
float mult = mirror? -1:1;
float planemult = planemirror? -level.info->pixelstretch : level.info->pixelstretch;
gl_RenderState.mViewMatrix.loadIdentity();
gl_RenderState.mViewMatrix.rotate(GLRenderer->mAngles.Roll.Degrees, 0.0f, 0.0f, 1.0f);
gl_RenderState.mViewMatrix.rotate(GLRenderer->mAngles.Pitch.Degrees, 1.0f, 0.0f, 0.0f);
gl_RenderState.mViewMatrix.rotate(GLRenderer->mAngles.Yaw.Degrees, 0.0f, mult, 0.0f);
gl_RenderState.mViewMatrix.translate(vx * mult, -vz * planemult , -vy);
gl_RenderState.mViewMatrix.scale(-mult, planemult, 1);
}
//-----------------------------------------------------------------------------
//
// SetupView
// Setup the view rotation matrix for the given viewpoint
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::SetupView(float vx, float vy, float vz, DAngle va, bool mirror, bool planemirror)
{
SetViewAngle(va);
SetViewMatrix(vx, vy, vz, mirror, planemirror);
gl_RenderState.ApplyMatrices();
}
//-----------------------------------------------------------------------------
//
@ -211,48 +99,45 @@ void GLSceneDrawer::SetupView(float vx, float vy, float vz, DAngle va, bool mirr
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::CreateScene(FDrawInfo *di)
void FDrawInfo::CreateScene()
{
const auto &vp = Viewpoint;
angle_t a1 = FrustumAngle();
di->mClipper->SafeAddClipRangeRealAngles(r_viewpoint.Angles.Yaw.BAMs() + a1, r_viewpoint.Angles.Yaw.BAMs() - a1);
mClipper->SafeAddClipRangeRealAngles(vp.Angles.Yaw.BAMs() + a1, vp.Angles.Yaw.BAMs() - a1);
// reset the portal manager
GLPortal::StartFrame();
GLRenderer->mPortalState.StartFrame();
PO_LinkToSubsectors();
ProcessAll.Clock();
// clip the scene and fill the drawlists
for(auto p : level.portalGroups) p->glportal = nullptr;
Bsp.Clock();
GLRenderer->mVBO->Map();
GLRenderer->mLights->Begin();
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
di->viewx = FLOAT2FIXED(r_viewpoint.Pos.X);
di->viewy = FLOAT2FIXED(r_viewpoint.Pos.Y);
viewx = FLOAT2FIXED(vp.Pos.X);
viewy = FLOAT2FIXED(vp.Pos.Y);
validcount++; // used for processing sidedefs only once by the renderer.
di->mAngles = GLRenderer->mAngles;
di->mViewVector = GLRenderer->mViewVector;
di->mViewActor = GLRenderer->mViewActor;
di->mShadowMap = &GLRenderer->mShadowMap;
mShadowMap = &GLRenderer->mShadowMap;
di->RenderBSPNode (level.HeadNode());
di->PreparePlayerSprites(r_viewpoint.sector, di->in_area);
RenderBSPNode (level.HeadNode());
PreparePlayerSprites(vp.sector, in_area);
// Process all the sprites on the current portal's back side which touch the portal.
if (GLRenderer->mCurrentPortal != NULL) GLRenderer->mCurrentPortal->RenderAttached(di);
if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this);
Bsp.Unclock();
// And now the crappy hacks that have to be done to avoid rendering anomalies.
// These cannot be multithreaded when the time comes because all these depend
// on the global 'validcount' variable.
di->HandleMissingTextures(di->in_area); // Missing upper/lower textures
di->HandleHackedSubsectors(); // open sector hacks for deep water
di->ProcessSectorStacks(di->in_area); // merge visplanes of sector stacks
HandleMissingTextures(in_area); // Missing upper/lower textures
HandleHackedSubsectors(); // open sector hacks for deep water
ProcessSectorStacks(in_area); // merge visplanes of sector stacks
GLRenderer->mLights->Finish();
GLRenderer->mVBO->Unmap();
@ -268,36 +153,35 @@ void GLSceneDrawer::CreateScene(FDrawInfo *di)
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
void FDrawInfo::RenderScene(int recursion)
{
const auto &vp = Viewpoint;
RenderAll.Clock();
glDepthMask(true);
if (!gl_no_skyclear) GLPortal::RenderFirstSkyPortal(recursion, di);
gl_RenderState.SetCameraPos(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z);
if (!gl_no_skyclear) GLRenderer->mPortalState.RenderFirstSkyPortal(recursion, this);
gl_RenderState.EnableFog(true);
gl_RenderState.BlendFunc(GL_ONE,GL_ZERO);
if (gl_sort_textures)
{
di->drawlists[GLDL_PLAINWALLS].SortWalls();
di->drawlists[GLDL_PLAINFLATS].SortFlats();
di->drawlists[GLDL_MASKEDWALLS].SortWalls();
di->drawlists[GLDL_MASKEDFLATS].SortFlats();
di->drawlists[GLDL_MASKEDWALLSOFS].SortWalls();
drawlists[GLDL_PLAINWALLS].SortWalls();
drawlists[GLDL_PLAINFLATS].SortFlats();
drawlists[GLDL_MASKEDWALLS].SortWalls();
drawlists[GLDL_MASKEDFLATS].SortFlats();
drawlists[GLDL_MASKEDWALLSOFS].SortWalls();
}
// if we don't have a persistently mapped buffer, we have to process all the dynamic lights up front,
// so that we don't have to do repeated map/unmap calls on the buffer.
if (gl.lightmethod == LM_DEFERRED && level.HasDynamicLights && !di->isFullbrightScene())
if (gl.lightmethod == LM_DEFERRED && level.HasDynamicLights && !isFullbrightScene())
{
GLRenderer->mLights->Begin();
di->drawlists[GLDL_PLAINFLATS].DrawFlats(di, GLPASS_LIGHTSONLY);
di->drawlists[GLDL_MASKEDFLATS].DrawFlats(di, GLPASS_LIGHTSONLY);
di->drawlists[GLDL_TRANSLUCENTBORDER].Draw(di, GLPASS_LIGHTSONLY);
di->drawlists[GLDL_TRANSLUCENT].Draw(di, GLPASS_LIGHTSONLY, true);
drawlists[GLDL_PLAINFLATS].DrawFlats(this, GLPASS_LIGHTSONLY);
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, GLPASS_LIGHTSONLY);
drawlists[GLDL_TRANSLUCENTBORDER].Draw(this, GLPASS_LIGHTSONLY);
drawlists[GLDL_TRANSLUCENT].Draw(this, GLPASS_LIGHTSONLY, true);
GLRenderer->mLights->Finish();
}
@ -310,8 +194,8 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
gl_RenderState.EnableTexture(gl_texture);
gl_RenderState.EnableBrightmap(true);
di->drawlists[GLDL_PLAINWALLS].DrawWalls(di, pass);
di->drawlists[GLDL_PLAINFLATS].DrawFlats(di, pass);
drawlists[GLDL_PLAINWALLS].DrawWalls(this, pass);
drawlists[GLDL_PLAINFLATS].DrawFlats(this, pass);
// Part 2: masked geometry. This is set up so that only pixels with alpha>gl_mask_threshold will show
@ -321,20 +205,20 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
gl_RenderState.SetTextureMode(TM_MASK);
}
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold);
di->drawlists[GLDL_MASKEDWALLS].DrawWalls(di, pass);
di->drawlists[GLDL_MASKEDFLATS].DrawFlats(di, pass);
drawlists[GLDL_MASKEDWALLS].DrawWalls(this, pass);
drawlists[GLDL_MASKEDFLATS].DrawFlats(this, pass);
// Part 3: masked geometry with polygon offset. This list is empty most of the time so only waste time on it when in use.
if (di->drawlists[GLDL_MASKEDWALLSOFS].Size() > 0)
if (drawlists[GLDL_MASKEDWALLSOFS].Size() > 0)
{
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -128.0f);
di->drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(di, pass);
drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(this, pass);
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0, 0);
}
di->drawlists[GLDL_MODELS].Draw(di, pass);
drawlists[GLDL_MODELS].Draw(this, pass);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -343,7 +227,7 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -128.0f);
glDepthMask(false);
di->DrawDecals();
DrawDecals();
gl_RenderState.SetTextureMode(TM_MODULATE);
@ -361,7 +245,7 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
gl_RenderState.EnableFog(true);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.BlendFunc(GL_ONE,GL_ZERO);
di->DrawUnhandledMissingTextures();
DrawUnhandledMissingTextures();
glDepthMask(true);
glPolygonOffset(0.0f, 0.0f);
@ -378,20 +262,18 @@ void GLSceneDrawer::RenderScene(FDrawInfo *di, int recursion)
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::RenderTranslucent(FDrawInfo *di)
void FDrawInfo::RenderTranslucent()
{
RenderAll.Clock();
gl_RenderState.SetCameraPos(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z);
// final pass: translucent stuff
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.EnableBrightmap(true);
di->drawlists[GLDL_TRANSLUCENTBORDER].Draw(di, GLPASS_TRANSLUCENT);
drawlists[GLDL_TRANSLUCENTBORDER].Draw(this, GLPASS_TRANSLUCENT);
glDepthMask(false);
di->DrawSorted(GLDL_TRANSLUCENT);
DrawSorted(GLDL_TRANSLUCENT);
gl_RenderState.EnableBrightmap(false);
@ -411,10 +293,11 @@ void GLSceneDrawer::RenderTranslucent(FDrawInfo *di)
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::DrawScene(FDrawInfo *di, int drawmode)
void FDrawInfo::DrawScene(int drawmode)
{
static int recursion=0;
static int ssao_portals_available = 0;
const auto &vp = Viewpoint;
bool applySSAO = false;
if (drawmode == DM_MAINVIEW)
@ -432,35 +315,35 @@ void GLSceneDrawer::DrawScene(FDrawInfo *di, int drawmode)
ssao_portals_available--;
}
if (r_viewpoint.camera != nullptr)
if (vp.camera != nullptr)
{
ActorRenderFlags savedflags = r_viewpoint.camera->renderflags;
CreateScene(di);
r_viewpoint.camera->renderflags = savedflags;
ActorRenderFlags savedflags = vp.camera->renderflags;
CreateScene();
vp.camera->renderflags = savedflags;
}
else
{
CreateScene(di);
CreateScene();
}
RenderScene(di, recursion);
RenderScene(recursion);
if (applySSAO && gl_RenderState.GetPassType() == GBUFFER_PASS)
{
gl_RenderState.EnableDrawBuffers(1);
GLRenderer->AmbientOccludeScene();
GLRenderer->AmbientOccludeScene(VPUniforms.mProjectionMatrix.get()[5]);
GLRenderer->mBuffers->BindSceneFB(true);
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
gl_RenderState.Apply();
gl_RenderState.ApplyMatrices();
ApplyVPUniforms();
}
// Handle all portals after rendering the opaque objects but before
// doing all translucent stuff
recursion++;
GLPortal::EndFrame(di);
GLRenderer->mPortalState.EndFrame(this);
recursion--;
RenderTranslucent(di);
RenderTranslucent();
}
//-----------------------------------------------------------------------------
@ -470,7 +353,7 @@ void GLSceneDrawer::DrawScene(FDrawInfo *di, int drawmode)
//-----------------------------------------------------------------------------
void GLSceneDrawer::EndDrawScene(FDrawInfo *di, sector_t * viewsector)
void FDrawInfo::EndDrawScene(sector_t * viewsector)
{
gl_RenderState.EnableFog(false);
@ -480,12 +363,11 @@ void GLSceneDrawer::EndDrawScene(FDrawInfo *di, sector_t * viewsector)
{
// [BB] The HUD model should be drawn over everything else already drawn.
glClear(GL_DEPTH_BUFFER_BIT);
di->DrawPlayerSprites(true);
DrawPlayerSprites(true);
}
glDisable(GL_STENCIL_TEST);
Reset3DViewport();
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
// Restore standard rendering state
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -494,19 +376,19 @@ void GLSceneDrawer::EndDrawScene(FDrawInfo *di, sector_t * viewsector)
glDisable(GL_SCISSOR_TEST);
}
void GLSceneDrawer::DrawEndScene2D(FDrawInfo *di, sector_t * viewsector)
void FDrawInfo::DrawEndScene2D(sector_t * viewsector)
{
const bool renderHUDModel = IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
auto vrmode = VRMode::GetVRMode(true);
// This should be removed once all 2D stuff is really done through the 2D interface.
gl_RenderState.mViewMatrix.loadIdentity();
gl_RenderState.mProjectionMatrix.ortho(0, screen->GetWidth(), screen->GetHeight(), 0, -1.0f, 1.0f);
gl_RenderState.ApplyMatrices();
VPUniforms.mViewMatrix.loadIdentity();
VPUniforms.mProjectionMatrix = vrmode->GetHUDSpriteProjection();
ApplyVPUniforms();
glDisable(GL_DEPTH_TEST);
glDisable(GL_MULTISAMPLE);
di->DrawPlayerSprites(false);
DrawPlayerSprites(false);
gl_RenderState.SetSoftLightLevel(-1);
@ -523,152 +405,99 @@ void GLSceneDrawer::DrawEndScene2D(FDrawInfo *di, sector_t * viewsector)
//
//-----------------------------------------------------------------------------
void GLSceneDrawer::ProcessScene(FDrawInfo *di, bool toscreen)
void FDrawInfo::ProcessScene(bool toscreen)
{
iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0;
GLPortal::BeginScene();
GLRenderer->mPortalState.BeginScene();
int mapsection = R_PointInSubsector(r_viewpoint.Pos)->mapsection;
di->CurrentMapSections.Set(mapsection);
GLRenderer->mCurrentPortal = nullptr;
DrawScene(di, toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
int mapsection = R_PointInSubsector(Viewpoint.Pos)->mapsection;
CurrentMapSections.Set(mapsection);
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
}
//-----------------------------------------------------------------------------
//
// sets 3D viewport and initial state
//
//-----------------------------------------------------------------------------
void FGLRenderer::Set3DViewport(bool mainview)
{
if (mainview && buffersActive)
{
bool useSSAO = (gl_ssao != 0);
mBuffers->BindSceneFB(useSSAO);
gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
gl_RenderState.Apply();
}
// Always clear all buffers with scissor test disabled.
// This is faster on newer hardware because it allows the GPU to skip
// reading from slower memory where the full buffers are stored.
glDisable(GL_SCISSOR_TEST);
glClearColor(mSceneClearColor[0], mSceneClearColor[1], mSceneClearColor[2], 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
const auto &bounds = screen->mSceneViewport;
glViewport(bounds.left, bounds.top, bounds.width, bounds.height);
glScissor(bounds.left, bounds.top, bounds.width, bounds.height);
glEnable(GL_SCISSOR_TEST);
glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS,0,~0); // default stencil
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
}
//-----------------------------------------------------------------------------
//
// Renders one viewpoint in a scene
//
//-----------------------------------------------------------------------------
sector_t * GLSceneDrawer::RenderViewpoint (AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
{
sector_t * lviewsector;
GLRenderer->mSceneClearColor[0] = 0.0f;
GLRenderer->mSceneClearColor[1] = 0.0f;
GLRenderer->mSceneClearColor[2] = 0.0f;
R_SetupFrame (r_viewpoint, r_viewwindow, camera);
sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
{
R_SetupFrame (mainvp, r_viewwindow, camera);
GLRenderer->mGlobVis = R_GetGlobVis(r_viewwindow, r_visibility);
// We have to scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
double radPitch = r_viewpoint.Angles.Pitch.Normalized180().Radians();
double angx = cos(radPitch);
double angy = sin(radPitch) * level.info->pixelstretch;
double alen = sqrt(angx*angx + angy*angy);
GLRenderer->mAngles.Pitch = (float)RAD2DEG(asin(angy / alen));
GLRenderer->mAngles.Roll.Degrees = r_viewpoint.Angles.Roll.Degrees;
if (camera->player && camera->player-players==consoleplayer &&
((camera->player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) && camera==camera->player->mo)
// Render (potentially) multiple views for stereo 3d
// Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode.
auto vrmode = VRMode::GetVRMode(mainview && toscreen);
for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix)
{
GLRenderer->mViewActor=NULL;
}
else
{
GLRenderer->mViewActor=camera;
}
// 'viewsector' will not survive the rendering so it cannot be used anymore below.
lviewsector = r_viewpoint.sector;
// Render (potentially) multiple views for stereo 3d
float viewShift[3];
const s3d::Stereo3DMode& stereo3dMode = mainview && toscreen? s3d::Stereo3DMode::getCurrentMode() : s3d::Stereo3DMode::getMonoMode();
stereo3dMode.SetUp();
for (int eye_ix = 0; eye_ix < stereo3dMode.eye_count(); ++eye_ix)
{
const s3d::EyePose * eye = stereo3dMode.getEyePose(eye_ix);
eye->SetUp();
const auto &eye = vrmode->mEyes[eye_ix];
screen->SetViewportRects(bounds);
Set3DViewport(mainview);
GLRenderer->mDrawingScene2D = true;
GLRenderer->mCurrentFoV = fov;
FDrawInfo *di = FDrawInfo::StartDrawInfo(this);
FDrawInfo *di = FDrawInfo::StartDrawInfo(mainvp, nullptr);
auto &vp = di->Viewpoint;
di->SetViewArea();
auto cm = di->SetFullbrightFlags(mainview ? r_viewpoint.camera->player : nullptr);
auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr);
di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
// Stereo mode specific perspective projection
SetProjection( eye->GetProjection(fov, ratio, fovratio) );
// SetProjection(fov, ratio, fovratio); // switch to perspective mode and set up clipper
SetViewAngle(r_viewpoint.Angles.Yaw);
// Stereo mode specific viewpoint adjustment - temporarily shifts global ViewPos
eye->GetViewShift(GLRenderer->mAngles.Yaw.Degrees, viewShift);
ScopedViewShifter viewShifter(r_viewpoint.Pos, viewShift);
SetViewMatrix(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z, false, false);
gl_RenderState.ApplyMatrices();
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
// Stereo mode specific viewpoint adjustment
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees);
di->SetupView(vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
ProcessScene(di, toscreen);
di->ProcessScene(toscreen);
if (mainview)
{
if (toscreen) EndDrawScene(di, lviewsector); // do not call this for camera textures.
GLRenderer->PostProcessScene(cm, [&]() { DrawEndScene2D(di, lviewsector); });
// This should be done after postprocessing, not before.
GLRenderer->mBuffers->BindCurrentFB();
glViewport(screen->mScreenViewport.left, screen->mScreenViewport.top, screen->mScreenViewport.width, screen->mScreenViewport.height);
if (!toscreen)
{
gl_RenderState.mViewMatrix.loadIdentity();
gl_RenderState.mProjectionMatrix.ortho(screen->mScreenViewport.left, screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mScreenViewport.top, -1.0f, 1.0f);
gl_RenderState.ApplyMatrices();
}
if (toscreen) di->EndDrawScene(mainvp.sector); // do not call this for camera textures.
PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector); });
}
FDrawInfo::EndDrawInfo();
GLRenderer->mDrawingScene2D = false;
if (!stereo3dMode.IsMono())
GLRenderer->mBuffers->BlitToEyeTexture(eye_ix);
eye->TearDown();
di->EndDrawInfo();
if (vrmode->mEyeCount > 1)
mBuffers->BlitToEyeTexture(eye_ix);
}
stereo3dMode.TearDown();
interpolator.RestoreInterpolations ();
return lviewsector;
return mainvp.sector;
}
//===========================================================================
//
// Render the view to a savegame picture
//
//===========================================================================
void GLSceneDrawer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
{
IntRect bounds;
bounds.left = 0;
bounds.top = 0;
bounds.width = width;
bounds.height = height;
// if GLRenderer->mVBO is persistently mapped we must be sure the GPU finished reading from it before we fill it with new data.
glFinish();
// Switch to render buffers dimensioned for the savepic
GLRenderer->mBuffers = GLRenderer->mSaveBuffers;
P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector.
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
GLRenderer->mVBO->Reset();
GLRenderer->mLights->Clear();
sector_t *viewsector = RenderViewpoint(players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false);
glDisable(GL_STENCIL_TEST);
gl_RenderState.SetSoftLightLevel(-1);
GLRenderer->CopyToBackbuffer(&bounds, false);
// strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers
glFinish();
uint8_t * scr = (uint8_t *)M_Malloc(width * height * 3);
glReadPixels(0,0,width, height,GL_RGB,GL_UNSIGNED_BYTE,scr);
M_CreatePNG (file, scr + ((height-1) * width * 3), NULL, SS_RGB, width, height, -width * 3, Gamma);
M_Free(scr);
// Switch back the screen render buffers
screen->SetViewportRects(nullptr);
GLRenderer->mBuffers = GLRenderer->mScreenBuffers;
}

View file

@ -1,47 +0,0 @@
#pragma once
#include "r_defs.h"
#include "m_fixed.h"
#include "hwrenderer/scene/hw_clipper.h"
#include "gl_portal.h"
#include "gl/renderer/gl_lightdata.h"
#include "gl/renderer/gl_renderer.h"
#include "r_utility.h"
#include "c_cvars.h"
struct HUDSprite;
class GLSceneDrawer
{
TMap<DPSprite*, int> weapondynlightindex;
void RenderMultipassStuff(FDrawInfo *di);
void RenderScene(FDrawInfo *di, int recursion);
void RenderTranslucent(FDrawInfo *di);
void CreateScene(FDrawInfo *di);
public:
GLSceneDrawer()
{
GLPortal::drawer = this;
}
angle_t FrustumAngle();
void SetViewMatrix(float vx, float vy, float vz, bool mirror, bool planemirror);
void SetupView(float vx, float vy, float vz, DAngle va, bool mirror, bool planemirror);
void SetViewAngle(DAngle viewangle);
void SetProjection(VSMatrix matrix);
void Set3DViewport(bool mainview);
void Reset3DViewport();
void DrawScene(FDrawInfo *di, int drawmode);
void ProcessScene(FDrawInfo *di, bool toscreen = false);
void EndDrawScene(FDrawInfo *di, sector_t * viewsector);
void DrawEndScene2D(FDrawInfo *di, sector_t * viewsector);
sector_t *RenderViewpoint(AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
sector_t *RenderView(player_t *player);
void WriteSavePic(player_t *player, FileWriter *file, int width, int height);
};

View file

@ -32,9 +32,10 @@
#include "gl_load/gl_interface.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/renderer/gl_lightdata.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/renderer/gl_renderstate.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_scenedrawer.h"
#include "gl/scene/gl_portal.h"
#include "gl/shaders/gl_shader.h"
@ -209,9 +210,10 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool
//
//
//-----------------------------------------------------------------------------
void GLSkyPortal::DrawContents(FDrawInfo *di)
void GLSkyPortal::DrawContents(HWDrawInfo *di)
{
bool drawBoth = false;
auto &vp = di->Viewpoint;
// We have no use for Doom lighting special handling here, so disable it for this function.
int oldlightmode = ::level.lightmode;
@ -228,8 +230,7 @@ void GLSkyPortal::DrawContents(FDrawInfo *di)
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
bool oldClamp = gl_RenderState.SetDepthClamp(true);
gl_MatrixStack.Push(gl_RenderState.mViewMatrix);
drawer->SetupView(0, 0, 0, r_viewpoint.Angles.Yaw, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1));
di->SetupView(0, 0, 0, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1));
gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO);
if (origin->texture[0] && origin->texture[0]->tex->bSkybox)
@ -268,8 +269,7 @@ void GLSkyPortal::DrawContents(FDrawInfo *di)
}
}
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
gl_MatrixStack.Pop(gl_RenderState.mViewMatrix);
gl_RenderState.ApplyMatrices();
di->ApplyVPUniforms();
::level.lightmode = oldlightmode;
gl_RenderState.SetDepthClamp(oldClamp);
}

View file

@ -47,7 +47,6 @@
#include "gl/renderer/gl_renderstate.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_scenedrawer.h"
#include "gl/models/gl_models.h"
#include "gl/renderer/gl_quaddrawer.h"
#include "gl/dynlights/gl_lightbuffer.h"
@ -79,6 +78,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
bool additivefog = false;
bool foglayer = false;
int rel = sprite->fullbright? 0 : getExtraLight();
auto &vp = Viewpoint;
if (pass==GLPASS_TRANSLUCENT)
{
@ -112,7 +112,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
// fog + fuzz don't work well without some fiddling with the alpha value!
if (!sprite->Colormap.FadeColor.isBlack())
{
float dist=Dist2(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, sprite->x, sprite->y);
float dist=Dist2(vp.Pos.X, vp.Pos.Y, sprite->x, sprite->y);
int fogd = hw_GetFogDensity(sprite->lightlevel, sprite->Colormap.FadeColor, sprite->Colormap.FogDensity);
// this value was determined by trial and error and is scale dependent!
@ -221,7 +221,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
secplane_t *lowplane = i == (*lightlist).Size() - 1 ? &bottomp : &(*lightlist)[i + 1].plane;
int thislight = (*lightlist)[i].caster != nullptr ? hw_ClampLight(*(*lightlist)[i].p_lightlevel) : sprite->lightlevel;
int thisll = sprite->actor == nullptr? thislight : (uint8_t)sprite->actor->Sector->CheckSpriteGlow(thislight, sprite->actor->InterpolatedPosition(r_viewpoint.TicFrac));
int thisll = sprite->actor == nullptr? thislight : (uint8_t)sprite->actor->Sector->CheckSpriteGlow(thislight, sprite->actor->InterpolatedPosition(vp.TicFrac));
FColormap thiscm;
thiscm.CopyFog(sprite->Colormap);
@ -249,7 +249,8 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
FVector3 v[4];
gl_RenderState.SetNormal(0, 0, 0);
if (sprite->CalculateVertices(this, v))
if (sprite->CalculateVertices(this, v, &vp.Pos))
{
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -128.0f);
@ -276,7 +277,8 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass)
}
else
{
gl_RenderModel(sprite, sprite->dynlightindex);
FGLModelRenderer renderer(this, sprite->dynlightindex);
renderer.RenderModel(sprite->x, sprite->y, sprite->z, sprite->modelframe, sprite->actor, vp.TicFrac);
}
}

View file

@ -37,7 +37,6 @@
#include "gl/dynlights/gl_lightbuffer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_portal.h"
#include "gl/scene/gl_scenedrawer.h"
EXTERN_CVAR(Bool, gl_seamless)
@ -94,7 +93,6 @@ void FDrawInfo::RenderMirrorSurface(GLWall *wall)
// we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is.
gl_RenderState.EnableTextureMatrix(true);
gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix);
// Use sphere mapping for this
gl_RenderState.SetEffect(EFF_SPHEREMAP);
@ -339,7 +337,8 @@ void FDrawInfo::AddMirrorSurface(GLWall *w)
void FDrawInfo::AddPortal(GLWall *wall, int ptype)
{
GLPortal * portal;
auto &pstate = GLRenderer->mPortalState;
IPortal * portal;
wall->MakeVertices(this, false);
switch (ptype)
@ -347,42 +346,63 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
// portals don't go into the draw list.
// Instead they are added to the portal manager
case PORTALTYPE_HORIZON:
wall->horizon = UniqueHorizons.Get(wall->horizon);
portal = GLPortal::FindPortal(wall->horizon);
if (!portal) portal = new GLHorizonPortal(wall->horizon);
wall->horizon = pstate.UniqueHorizons.Get(wall->horizon);
portal = FindPortal(wall->horizon);
if (!portal)
{
portal = new GLHorizonPortal(&pstate, wall->horizon, Viewpoint);
Portals.Push(portal);
}
portal->AddLine(wall);
break;
case PORTALTYPE_SKYBOX:
portal = GLPortal::FindPortal(wall->secportal);
portal = FindPortal(wall->secportal);
if (!portal)
{
// either a regular skybox or an Eternity-style horizon
if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(wall->secportal);
else portal = new GLSkyboxPortal(wall->secportal);
if (wall->secportal->mType != PORTS_SKYVIEWPOINT) portal = new GLEEHorizonPortal(&pstate, wall->secportal);
else
{
portal = new GLScenePortal(&pstate, new HWSkyboxPortal(wall->secportal));
Portals.Push(portal);
}
}
portal->AddLine(wall);
break;
case PORTALTYPE_SECTORSTACK:
portal = wall->portal->GetRenderState();
portal = FindPortal(wall->portal);
if (!portal)
{
portal = new GLScenePortal(&pstate, new HWSectorStackPortal(wall->portal));
Portals.Push(portal);
}
portal->AddLine(wall);
break;
case PORTALTYPE_PLANEMIRROR:
if (GLPortal::PlaneMirrorMode * wall->planemirror->fC() <= 0)
if (pstate.PlaneMirrorMode * wall->planemirror->fC() <= 0)
{
//@sync-portal
wall->planemirror = UniquePlaneMirrors.Get(wall->planemirror);
portal = GLPortal::FindPortal(wall->planemirror);
if (!portal) portal = new GLPlaneMirrorPortal(wall->planemirror);
wall->planemirror = pstate.UniquePlaneMirrors.Get(wall->planemirror);
portal = FindPortal(wall->planemirror);
if (!portal)
{
portal = new GLScenePortal(&pstate, new HWPlaneMirrorPortal(wall->planemirror));
Portals.Push(portal);
}
portal->AddLine(wall);
}
break;
case PORTALTYPE_MIRROR:
portal = GLPortal::FindPortal(wall->seg->linedef);
if (!portal) portal = new GLMirrorPortal(wall->seg->linedef);
portal = FindPortal(wall->seg->linedef);
if (!portal)
{
portal = new GLScenePortal(&pstate, new HWMirrorPortal(wall->seg->linedef));
Portals.Push(portal);
}
portal->AddLine(wall);
if (gl_mirror_envmap)
{
@ -392,23 +412,28 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
break;
case PORTALTYPE_LINETOLINE:
portal = GLPortal::FindPortal(wall->lineportal);
portal = FindPortal(wall->lineportal);
if (!portal)
{
line_t *otherside = wall->lineportal->lines[0]->mDestination;
if (otherside != NULL && otherside->portalindex < level.linePortals.Size())
if (otherside != nullptr && otherside->portalindex < level.linePortals.Size())
{
ProcessActorsInPortal(otherside->getPortal()->mGroup, in_area);
}
portal = new GLLineToLinePortal(wall->lineportal);
portal = new GLScenePortal(&pstate, new HWLineToLinePortal(wall->lineportal));
Portals.Push(portal);
}
portal->AddLine(wall);
break;
case PORTALTYPE_SKY:
wall->sky = UniqueSkies.Get(wall->sky);
portal = GLPortal::FindPortal(wall->sky);
if (!portal) portal = new GLSkyPortal(wall->sky);
wall->sky = pstate.UniqueSkies.Get(wall->sky);
portal = FindPortal(wall->sky);
if (!portal)
{
portal = new GLSkyPortal(&pstate, wall->sky);
Portals.Push(portal);
}
portal->AddLine(wall);
break;
}

View file

@ -37,9 +37,7 @@
#include "gl/renderer/gl_renderstate.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_scenedrawer.h"
#include "gl/models/gl_models.h"
#include "gl/stereo3d/gl_stereo3d.h"
#include "gl/dynlights/gl_lightbuffer.h"
//==========================================================================
@ -66,7 +64,8 @@ void FDrawInfo::DrawPSprite (HUDSprite *huds)
if (huds->mframe)
{
gl_RenderState.AlphaFunc(GL_GEQUAL, 0);
gl_RenderHUDModel(huds->weapon, huds->mx, huds->my, huds->lightindex);
FGLModelRenderer renderer(this, huds->lightindex);
renderer.RenderHUDModel(huds->weapon, huds->mx, huds->my);
}
else
{
@ -91,8 +90,6 @@ void FDrawInfo::DrawPSprite (HUDSprite *huds)
void FDrawInfo::DrawPlayerSprites(bool hudModelStep)
{
s3d::Stereo3DMode::getCurrentMode().AdjustPlayerSprites();
int oldlightmode = level.lightmode;
if (!hudModelStep && level.lightmode == 8) level.lightmode = 2; // Software lighting cannot handle 2D content so revert to lightmode 2 for that.
for(auto &hudsprite : hudsprites)

View file

@ -34,6 +34,7 @@
#include "cmdlib.h"
#include "hwrenderer/utility/hw_shaderpatcher.h"
#include "hwrenderer/data/shaderuniforms.h"
#include "hwrenderer/scene/hw_viewpointuniforms.h"
#include "gl_load/gl_interface.h"
#include "gl/system/gl_debug.h"
@ -307,10 +308,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
muDesaturation.Init(hShader, "uDesaturationFactor");
muFogEnabled.Init(hShader, "uFogEnabled");
muPalLightLevels.Init(hShader, "uPalLightLevels");
muGlobVis.Init(hShader, "uGlobVis");
muTextureMode.Init(hShader, "uTextureMode");
muCameraPos.Init(hShader, "uCameraPos");
muLightParms.Init(hShader, "uLightAttr");
muClipSplit.Init(hShader, "uClipSplit");
muLightIndex.Init(hShader, "uLightIndex");
@ -324,13 +322,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
muGlowTopPlane.Init(hShader, "uGlowTopPlane");
muSplitBottomPlane.Init(hShader, "uSplitBottomPlane");
muSplitTopPlane.Init(hShader, "uSplitTopPlane");
muClipLine.Init(hShader, "uClipLine");
muInterpolationFactor.Init(hShader, "uInterpolationFactor");
muClipHeight.Init(hShader, "uClipHeight");
muClipHeightDirection.Init(hShader, "uClipHeightDirection");
muAlphaThreshold.Init(hShader, "uAlphaThreshold");
muSpecularMaterial.Init(hShader, "uSpecularMaterial");
muViewHeight.Init(hShader, "uViewHeight");
muTimer.Init(hShader, "timer");
lights_index = glGetUniformLocation(hShader, "lights");
@ -344,6 +338,13 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
normalviewmatrix_index = glGetUniformLocation(hShader, "NormalViewMatrix");
normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix");
quadmode_index = glGetUniformLocation(hShader, "uQuadMode");
viewheight_index = glGetUniformLocation(hShader, "uViewHeight");
camerapos_index = glGetUniformLocation(hShader, "uCameraPos");
pallightlevels_index = glGetUniformLocation(hShader, "uPalLightLevels");
globvis_index = glGetUniformLocation(hShader, "uGlobVis");
clipheight_index = glGetUniformLocation(hShader, "uClipHeight");
clipheightdirection_index = glGetUniformLocation(hShader, "uClipHeightDirection");
clipline_index = glGetUniformLocation(hShader, "uClipLine");
if (!(gl.flags & RFL_SHADER_STORAGE_BUFFER))
{
@ -434,12 +435,19 @@ FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderP
//
//==========================================================================
void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm)
void FShader::ApplyMatrices(HWViewpointUniforms *u)
{
Bind();
glUniformMatrix4fv(projectionmatrix_index, 1, false, proj->get());
glUniformMatrix4fv(viewmatrix_index, 1, false, view->get());
glUniformMatrix4fv(normalviewmatrix_index, 1, false, norm->get());
glUniformMatrix4fv(projectionmatrix_index, 1, false, u->mProjectionMatrix.get());
glUniformMatrix4fv(viewmatrix_index, 1, false, u->mViewMatrix.get());
glUniformMatrix4fv(normalviewmatrix_index, 1, false, u->mNormalViewMatrix.get());
glUniform4fv(camerapos_index, 1, &u->mCameraPos[0]);
glUniform1i(viewheight_index, u->mViewHeight);
glUniform1i(pallightlevels_index, u->mPalLightLevels);
glUniform1f(globvis_index, u->mGlobVis);
glUniform1f(clipheight_index, u->mClipHeight);
glUniform1f(clipheightdirection_index, u->mClipHeightDirection);
}
//==========================================================================
@ -539,10 +547,10 @@ FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passT
return nullptr;
}
void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType)
void FShaderManager::ApplyMatrices(HWViewpointUniforms *u, EPassType passType)
{
if (passType < mPassShaders.Size())
mPassShaders[passType]->ApplyMatrices(proj, view);
mPassShaders[passType]->ApplyMatrices(u);
if (mActiveShader)
mActiveShader->Bind();
@ -687,28 +695,25 @@ FShader *FShaderCollection::BindEffect(int effect)
//==========================================================================
EXTERN_CVAR(Int, gl_fuzztype)
void FShaderCollection::ApplyMatrices(VSMatrix *proj, VSMatrix *view)
void FShaderCollection::ApplyMatrices(HWViewpointUniforms *u)
{
VSMatrix norm;
norm.computeNormalMatrix(*view);
for (int i = 0; i < SHADER_NoTexture; i++)
{
mMaterialShaders[i]->ApplyMatrices(proj, view, &norm);
mMaterialShadersNAT[i]->ApplyMatrices(proj, view, &norm);
mMaterialShaders[i]->ApplyMatrices(u);
mMaterialShadersNAT[i]->ApplyMatrices(u);
}
mMaterialShaders[SHADER_NoTexture]->ApplyMatrices(proj, view, &norm);
mMaterialShaders[SHADER_NoTexture]->ApplyMatrices(u);
if (gl_fuzztype != 0)
{
mMaterialShaders[SHADER_NoTexture + gl_fuzztype]->ApplyMatrices(proj, view, &norm);
mMaterialShaders[SHADER_NoTexture + gl_fuzztype]->ApplyMatrices(u);
}
for (unsigned i = FIRST_USER_SHADER; i < mMaterialShaders.Size(); i++)
{
mMaterialShaders[i]->ApplyMatrices(proj, view, &norm);
mMaterialShaders[i]->ApplyMatrices(u);
}
for (int i = 0; i < MAX_EFFECTS; i++)
{
mEffectShaders[i]->ApplyMatrices(proj, view, &norm);
mEffectShaders[i]->ApplyMatrices(u);
}
}

View file

@ -38,6 +38,7 @@ enum
};
class FShaderCollection;
struct HWViewpointUniforms;
//==========================================================================
//
@ -242,10 +243,7 @@ class FShader
FBufferedUniform1f muDesaturation;
FBufferedUniform1i muFogEnabled;
FBufferedUniform1i muPalLightLevels;
FBufferedUniform1f muGlobVis;
FBufferedUniform1i muTextureMode;
FBufferedUniform4f muCameraPos;
FBufferedUniform4f muLightParms;
FBufferedUniform2f muClipSplit;
FBufferedUniform1i muLightIndex;
@ -259,22 +257,27 @@ class FShader
FUniform4f muGlowTopPlane;
FUniform4f muSplitBottomPlane;
FUniform4f muSplitTopPlane;
FUniform4f muClipLine;
FBufferedUniform1f muInterpolationFactor;
FBufferedUniform1f muClipHeight;
FBufferedUniform1f muClipHeightDirection;
FBufferedUniform1f muAlphaThreshold;
FBufferedUniform1i muViewHeight;
FBufferedUniform2f muSpecularMaterial;
FBufferedUniform1f muTimer;
int lights_index;
int projectionmatrix_index;
int viewmatrix_index;
int normalviewmatrix_index;
int modelmatrix_index;
int normalmodelmatrix_index;
int texturematrix_index;
int projectionmatrix_index;
int viewmatrix_index;
int normalviewmatrix_index;
int viewheight_index;
int camerapos_index;
int pallightlevels_index;
int globvis_index;
int clipheight_index;
int clipheightdirection_index;
int clipline_index;
public:
int vertexmatrix_index;
int texcoordmatrix_index;
@ -306,7 +309,7 @@ public:
bool Bind();
unsigned int GetHandle() const { return hShader; }
void ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm);
void ApplyMatrices(HWViewpointUniforms *u);
};
@ -326,7 +329,7 @@ public:
FShader *BindEffect(int effect, EPassType passType);
FShader *Get(unsigned int eff, bool alphateston, EPassType passType);
void ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType);
void ApplyMatrices(HWViewpointUniforms *u, EPassType passType);
private:
FShader *mActiveShader = nullptr;
@ -348,7 +351,7 @@ public:
FShader *Compile(const char *ShaderName, const char *ShaderPath, const char *LightModePath, const char *shaderdefines, bool usediscard, EPassType passType);
int Find(const char *mame);
FShader *BindEffect(int effect);
void ApplyMatrices(VSMatrix *proj, VSMatrix *view);
void ApplyMatrices(HWViewpointUniforms *u);
FShader *Get(unsigned int eff, bool alphateston)
{

View file

@ -1,84 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_anaglyph.cpp
** Color mask based stereoscopic 3D modes for GZDoom
**
*/
#include "gl_anaglyph.h"
#include "gl/renderer/gl_renderbuffers.h"
namespace s3d {
MaskAnaglyph::MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters)
: leftEye(leftColorMask, ipdMeters), rightEye(leftColorMask.inverse(), ipdMeters)
{
eye_ptrs.Push(&leftEye);
eye_ptrs.Push(&rightEye);
}
void MaskAnaglyph::Present() const
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
gl_RenderState.SetColorMask(leftEye.GetColorMask().r, leftEye.GetColorMask().g, leftEye.GetColorMask().b, true);
gl_RenderState.ApplyColorMask();
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
gl_RenderState.SetColorMask(rightEye.GetColorMask().r, rightEye.GetColorMask().g, rightEye.GetColorMask().b, true);
gl_RenderState.ApplyColorMask();
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
gl_RenderState.ResetColorMask();
gl_RenderState.ApplyColorMask();
}
/* static */
const GreenMagenta& GreenMagenta::getInstance(float ipd)
{
static GreenMagenta instance(ipd);
return instance;
}
/* static */
const RedCyan& RedCyan::getInstance(float ipd)
{
static RedCyan instance(ipd);
return instance;
}
/* static */
const AmberBlue& AmberBlue::getInstance(float ipd)
{
static AmberBlue instance(ipd);
return instance;
}
} /* namespace s3d */

View file

@ -1,113 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_anaglyph.h
** Color mask based stereoscopic 3D modes for GZDoom
**
*/
#ifndef GL_ANAGLYPH_H_
#define GL_ANAGLYPH_H_
#include "gl_stereo3d.h"
#include "gl_stereo_leftright.h"
#include "gl_load/gl_system.h"
#include "gl/renderer/gl_renderstate.h"
namespace s3d {
class ColorMask
{
public:
ColorMask(bool r, bool g, bool b) : r(r), g(g), b(b) {}
ColorMask inverse() const { return ColorMask(!r, !g, !b); }
bool r;
bool g;
bool b;
};
class AnaglyphLeftPose : public LeftEyePose
{
public:
AnaglyphLeftPose(const ColorMask& colorMask, float ipd) : LeftEyePose(ipd), colorMask(colorMask) {}
ColorMask GetColorMask() const { return colorMask; }
private:
ColorMask colorMask;
};
class AnaglyphRightPose : public RightEyePose
{
public:
AnaglyphRightPose(const ColorMask& colorMask, float ipd) : RightEyePose(ipd), colorMask(colorMask) {}
ColorMask GetColorMask() const { return colorMask; }
private:
ColorMask colorMask;
};
class MaskAnaglyph : public Stereo3DMode
{
public:
MaskAnaglyph(const ColorMask& leftColorMask, double ipdMeters);
void Present() const override;
private:
AnaglyphLeftPose leftEye;
AnaglyphRightPose rightEye;
};
class RedCyan : public MaskAnaglyph
{
public:
static const RedCyan& getInstance(float ipd);
RedCyan(float ipd) : MaskAnaglyph(ColorMask(true, false, false), ipd) {}
};
class GreenMagenta : public MaskAnaglyph
{
public:
static const GreenMagenta& getInstance(float ipd);
GreenMagenta(float ipd) : MaskAnaglyph(ColorMask(false, true, false), ipd) {}
};
class AmberBlue : public MaskAnaglyph
{
public:
static const AmberBlue& getInstance(float ipd);
AmberBlue(float ipd) : MaskAnaglyph(ColorMask(true, true, false), ipd) {}
};
// TODO matrix anaglyph
} /* namespace s3d */
#endif /* GL_ANAGLYPH_H_ */

View file

@ -1,232 +0,0 @@
/*
** gl_interleaved3d.cpp
** Interleaved image stereoscopic 3D modes for GZDoom
**
**---------------------------------------------------------------------------
** Copyright 2016 Christopher Bruns
** 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 "gl_interleaved3d.h"
#include "gl/renderer/gl_renderbuffers.h"
#include "gl/renderer/gl_postprocessstate.h"
#include "gl/system/gl_framebuffer.h"
#include "hwrenderer/postprocessing/hw_present3dRowshader.h"
#ifdef _WIN32
#include "hardware.h"
#endif // _WIN32
EXTERN_CVAR(Float, vid_saturation)
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
EXTERN_CVAR(Int, gl_satformula)
EXTERN_CVAR(Bool, fullscreen)
EXTERN_CVAR(Int, win_x) // screen pixel position of left of display window
EXTERN_CVAR(Int, win_y) // screen pixel position of top of display window
namespace s3d {
/* static */
const CheckerInterleaved3D& CheckerInterleaved3D::getInstance(float ipd)
{
static CheckerInterleaved3D instance(ipd);
return instance;
}
/* static */
const ColumnInterleaved3D& ColumnInterleaved3D::getInstance(float ipd)
{
static ColumnInterleaved3D instance(ipd);
return instance;
}
/* static */
const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd)
{
static RowInterleaved3D instance(ipd);
return instance;
}
static void prepareInterleavedPresent(FPresentShaderBase& shader)
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
// Bind each eye texture, for composition in the shader
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->mBuffers->BindEyeTexture(1, 1);
glActiveTexture(GL_TEXTURE0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glActiveTexture(GL_TEXTURE1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
const IntRect& box = screen->mOutputLetterbox;
glViewport(box.left, box.top, box.width, box.height);
shader.Bind(NOQUEUE);
if ( GLRenderer->framebuffer->IsHWGammaActive() )
{
shader.Uniforms->InvGamma = 1.0f;
shader.Uniforms->Contrast = 1.0f;
shader.Uniforms->Brightness = 0.0f;
shader.Uniforms->Saturation = 1.0f;
}
else
{
shader.Uniforms->InvGamma = 1.0f / clamp<float>(Gamma, 0.1f, 4.f);
shader.Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
shader.Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
shader.Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.0f);
shader.Uniforms->GrayFormula = static_cast<int>(gl_satformula);
}
shader.Uniforms->Scale = {
screen->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(),
screen->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()
};
shader.Uniforms.Set();
}
// fixme: I don't know how to get absolute window position on Mac and Linux
// fixme: I don't know how to get window border decoration size anywhere
// So for now I'll hard code the border effect on my test machine.
// Workaround for others is to fuss with vr_swap_eyes CVAR until it looks right.
// Presumably the top/left window border on my test machine has an odd number of pixels
// in the horizontal direction, and an even number in the vertical direction.
#define WINDOW_BORDER_HORIZONTAL_PARITY 1
#define WINDOW_BORDER_VERTICAL_PARITY 0
void CheckerInterleaved3D::Present() const
{
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
int windowVOffset = 0;
int windowHOffset = 0;
#ifdef _WIN32
/* this needs to be done differently!
if (!fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
}
*/
#endif // _WIN32
GLRenderer->mPresent3dCheckerShader->Uniforms->WindowPositionParity =
(windowVOffset
+ windowHOffset
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset
GLRenderer->mPresent3dCheckerShader->Uniforms.Set();
GLRenderer->RenderScreenQuad();
}
void s3d::CheckerInterleaved3D::AdjustViewports() const
{
// decrease the total pixel count by 2, but keep the same aspect ratio
const float sqrt2 = 1.41421356237f;
// Change size of renderbuffer, and align to screen
screen->mSceneViewport.height /= sqrt2;
screen->mSceneViewport.top /= sqrt2;
screen->mSceneViewport.width /= sqrt2;
screen->mSceneViewport.left /= sqrt2;
screen->mScreenViewport.height /= sqrt2;
screen->mScreenViewport.top /= sqrt2;
screen->mScreenViewport.width /= sqrt2;
screen->mScreenViewport.left /= sqrt2;
}
void ColumnInterleaved3D::Present() const
{
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
int windowHOffset = 0;
#ifdef _WIN32
/* this needs to be done differently!
if (!fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR
windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2;
}
*/
#endif // _WIN32
GLRenderer->mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset;
GLRenderer->mPresent3dColumnShader->Uniforms.Set();
GLRenderer->RenderScreenQuad();
}
void RowInterleaved3D::Present() const
{
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader);
// Compute absolute offset from top of screen to top of current display window
// because we need screen-relative, not window-relative, scan line parity
int windowVOffset = 0;
#ifdef _WIN32
/* this needs to be done differently!
if (! fullscreen) {
I_SaveWindowedPos(); // update win_y CVAR
windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2;
}
*/
#endif // _WIN32
GLRenderer->mPresent3dRowShader->Uniforms->WindowPositionParity =
(windowVOffset
+ screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom
) % 2;
GLRenderer->mPresent3dRowShader->Uniforms.Set();
GLRenderer->RenderScreenQuad();
}
} /* namespace s3d */

View file

@ -1,75 +0,0 @@
/*
** gl_interleaved3d.h
** Interleaved stereoscopic 3D modes for GZDoom
**
**---------------------------------------------------------------------------
** Copyright 2016 Christopher Bruns
** 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 GL_INTERLEAVED3D_H_
#define GL_INTERLEAVED3D_H_
#include "gl_stereo3d.h"
#include "gl_stereo_leftright.h"
#include "gl_sidebyside3d.h"
#include "gl_load/gl_system.h"
#include "gl/renderer/gl_renderstate.h"
namespace s3d {
class CheckerInterleaved3D : public SideBySideSquished
{
public:
static const CheckerInterleaved3D& getInstance(float ipd);
CheckerInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
void Present() const override;
void AdjustViewports() const override;
};
class ColumnInterleaved3D : public SideBySideSquished
{
public:
static const ColumnInterleaved3D& getInstance(float ipd);
ColumnInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
void Present() const override;
};
class RowInterleaved3D : public TopBottom3D
{
public:
static const RowInterleaved3D& getInstance(float ipd);
RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {}
void Present() const override;
};
} /* namespace s3d */
#endif /* GL_INTERLEAVED3D_H_ */

View file

@ -1,115 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_quadstereo.cpp
** Quad-buffered OpenGL stereoscopic 3D mode for GZDoom
**
*/
#include "gl_quadstereo.h"
#include "gl/renderer/gl_renderbuffers.h"
namespace s3d {
QuadStereo::QuadStereo(double ipdMeters)
: leftEye(ipdMeters), rightEye(ipdMeters)
{
// Check whether quad-buffered stereo is supported in the current context
// We are assuming the OpenGL context is already current at this point,
// i.e. this constructor is called "just in time".
// First initialize to mono-ish initial state
bQuadStereoSupported = leftEye.bQuadStereoSupported = rightEye.bQuadStereoSupported = false;
eye_ptrs.Push(&leftEye); // We ALWAYS want to show at least this one view...
// We will possibly advance to true stereo mode in the Setup() method...
}
// Sometimes the stereo render context is not ready immediately at start up
/* private */
void QuadStereo::checkInitialRenderContextState()
{
// Keep trying until we see at least one good OpenGL context to render to
static bool bDecentContextWasFound = false;
static int contextCheckCount = 0;
if ( (! bDecentContextWasFound) && (contextCheckCount < 200) )
{
contextCheckCount += 1;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context
GLboolean supportsStereo, supportsBuffered;
glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered);
if (supportsBuffered) // Finally, a useful OpenGL context
{
// This block will be executed exactly ONCE during a game run
bDecentContextWasFound = true; // now we can stop checking every frame...
// Now check whether this context supports hardware stereo
glGetBooleanv(GL_STEREO, &supportsStereo);
bQuadStereoSupported = supportsStereo && supportsBuffered;
leftEye.bQuadStereoSupported = bQuadStereoSupported;
rightEye.bQuadStereoSupported = bQuadStereoSupported;
if (bQuadStereoSupported)
eye_ptrs.Push(&rightEye); // Use the other eye too, if we can do stereo
}
}
}
void QuadStereo::Present() const
{
if (bQuadStereoSupported)
{
GLRenderer->mBuffers->BindOutputFB();
glDrawBuffer(GL_BACK_LEFT);
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
glDrawBuffer(GL_BACK_RIGHT);
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
glDrawBuffer(GL_BACK);
}
else
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
}
}
void QuadStereo::SetUp() const
{
Stereo3DMode::SetUp();
// Maybe advance to true stereo mode (ONCE), after the stereo context is finally ready
const_cast<QuadStereo*>(this)->checkInitialRenderContextState();
}
/* static */
const QuadStereo& QuadStereo::getInstance(float ipd)
{
static QuadStereo instance(ipd);
return instance;
}
} /* namespace s3d */

View file

@ -1,77 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_quadstereo.h
** Quad-buffered OpenGL stereoscopic 3D mode for GZDoom
**
*/
#ifndef GL_QUADSTEREO_H_
#define GL_QUADSTEREO_H_
#include "gl_stereo3d.h"
#include "gl_stereo_leftright.h"
#include "gl_load/gl_system.h"
namespace s3d {
class QuadStereoLeftPose : public LeftEyePose
{
public:
QuadStereoLeftPose(float ipd) : LeftEyePose(ipd), bQuadStereoSupported(false) {}
bool bQuadStereoSupported;
};
class QuadStereoRightPose : public RightEyePose
{
public:
QuadStereoRightPose(float ipd) : RightEyePose(ipd), bQuadStereoSupported(false){}
bool bQuadStereoSupported;
};
// To use Quad-buffered stereo mode with nvidia 3d vision glasses,
// you must either:
// A) be using a Quadro series video card, OR
//
// B) be using nvidia driver version 314.07 or later
// AND have your monitor set to 120 Hz refresh rate
// AND have gzdoom in true full screen mode
class QuadStereo : public Stereo3DMode
{
public:
QuadStereo(double ipdMeters);
void Present() const override;
void SetUp() const override;
static const QuadStereo& getInstance(float ipd);
private:
QuadStereoLeftPose leftEye;
QuadStereoRightPose rightEye;
bool bQuadStereoSupported;
void checkInitialRenderContextState();
};
} /* namespace s3d */
#endif /* GL_QUADSTEREO_H_ */

View file

@ -1,149 +0,0 @@
/*
** gl_sidebyside3d.cpp
** Mosaic image stereoscopic 3D modes for GZDoom
**
**---------------------------------------------------------------------------
** Copyright 2016 Christopher Bruns
** 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 "gl_sidebyside3d.h"
#include "gl/renderer/gl_renderbuffers.h"
namespace s3d {
void SideBySideBase::Present() const
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
// Compute screen regions to use for left and right eye views
int leftWidth = screen->mOutputLetterbox.width / 2;
int rightWidth = screen->mOutputLetterbox.width - leftWidth;
IntRect leftHalfScreen = screen->mOutputLetterbox;
leftHalfScreen.width = leftWidth;
IntRect rightHalfScreen = screen->mOutputLetterbox;
rightHalfScreen.width = rightWidth;
rightHalfScreen.left += leftWidth;
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(leftHalfScreen, true);
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(rightHalfScreen, true);
}
// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...)
void SideBySideBase::AdjustViewports() const
{
// Change size of renderbuffer, and align to screen
screen->mSceneViewport.width /= 2;
screen->mSceneViewport.left /= 2;
screen->mScreenViewport.width /= 2;
screen->mScreenViewport.left /= 2;
}
/* static */
const SideBySideSquished& SideBySideSquished::getInstance(float ipd)
{
static SideBySideSquished instance(ipd);
return instance;
}
SideBySideSquished::SideBySideSquished(double ipdMeters)
: leftEye(ipdMeters), rightEye(ipdMeters)
{
eye_ptrs.Push(&leftEye);
eye_ptrs.Push(&rightEye);
}
/* static */
const SideBySideFull& SideBySideFull::getInstance(float ipd)
{
static SideBySideFull instance(ipd);
return instance;
}
SideBySideFull::SideBySideFull(double ipdMeters)
: leftEye(ipdMeters), rightEye(ipdMeters)
{
eye_ptrs.Push(&leftEye);
eye_ptrs.Push(&rightEye);
}
/* virtual */
void SideBySideFull::AdjustPlayerSprites() const /* override */
{
// Show weapon at double width, so it would appear normal width after rescaling
int w = screen->mScreenViewport.width;
int h = screen->mScreenViewport.height;
gl_RenderState.mProjectionMatrix.ortho(w/2, w + w/2, h, 0, -1.0f, 1.0f);
gl_RenderState.ApplyMatrices();
}
/* static */
const TopBottom3D& TopBottom3D::getInstance(float ipd)
{
static TopBottom3D instance(ipd);
return instance;
}
void TopBottom3D::Present() const
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
// Compute screen regions to use for left and right eye views
int topHeight = screen->mOutputLetterbox.height / 2;
int bottomHeight = screen->mOutputLetterbox.height - topHeight;
IntRect topHalfScreen = screen->mOutputLetterbox;
topHalfScreen.height = topHeight;
topHalfScreen.top = topHeight;
IntRect bottomHalfScreen = screen->mOutputLetterbox;
bottomHalfScreen.height = bottomHeight;
bottomHalfScreen.top = 0;
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(topHalfScreen, true);
GLRenderer->mBuffers->BindEyeTexture(1, 0);
GLRenderer->DrawPresentTexture(bottomHalfScreen, true);
}
// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...)
void TopBottom3D::AdjustViewports() const
{
// Change size of renderbuffer, and align to screen
screen->mSceneViewport.height /= 2;
screen->mSceneViewport.top /= 2;
screen->mScreenViewport.height /= 2;
screen->mScreenViewport.top /= 2;
}
} /* namespace s3d */

View file

@ -1,103 +0,0 @@
/*
** gl_sidebyside3d.h
** Mosaic image stereoscopic 3D modes for GZDoom
**
**---------------------------------------------------------------------------
** Copyright 2016 Christopher Bruns
** 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 GL_SIDEBYSIDE3D_H_
#define GL_SIDEBYSIDE3D_H_
#include "gl_stereo3d.h"
#include "gl_stereo_leftright.h"
#include "gl_load/gl_system.h"
#include "gl/renderer/gl_renderstate.h"
namespace s3d {
class SideBySideBase : public Stereo3DMode
{
public:
void Present() const override;
virtual void AdjustViewports() const override;
};
class SideBySideSquished : public SideBySideBase
{
public:
static const SideBySideSquished& getInstance(float ipd);
SideBySideSquished(double ipdMeters);
private:
LeftEyePose leftEye;
RightEyePose rightEye;
};
class SBSFLeftEyePose : public LeftEyePose {
public:
SBSFLeftEyePose(double ipdMeters) : LeftEyePose(ipdMeters) {}
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const override {
return LeftEyePose::GetProjection(fov, 0.5f * aspectRatio, fovRatio);
}
};
class SBSFRightEyePose : public RightEyePose {
public:
SBSFRightEyePose(double ipdMeters) : RightEyePose(ipdMeters) {}
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const override {
return RightEyePose::GetProjection(fov, 0.5f * aspectRatio, fovRatio);
}
};
class SideBySideFull : public SideBySideBase
{
public:
static const SideBySideFull& getInstance(float ipd);
SideBySideFull(double ipdMeters);
virtual void AdjustPlayerSprites() const override;
private:
SBSFLeftEyePose leftEye;
SBSFRightEyePose rightEye;
};
class TopBottom3D : public SideBySideSquished
{
public:
static const TopBottom3D& getInstance(float ipd);
TopBottom3D(double ipdMeters) : SideBySideSquished(ipdMeters) {}
void Present() const override;
virtual void AdjustViewports() const override;
};
} /* namespace s3d */
#endif /* GL_SIDEBYSIDE3D_H_ */

View file

@ -1,82 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_stereo3d.cpp
** Stereoscopic 3D API
**
*/
#include "gl_load/gl_system.h"
#include "gl/stereo3d/gl_stereo3d.h"
namespace s3d {
/* virtual */
VSMatrix EyePose::GetProjection(float fov, float aspectRatio, float fovRatio) const
{
VSMatrix result;
// Lifted from gl_scene.cpp FGLRenderer::SetProjection()
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
result.perspective(fovy, aspectRatio, FGLRenderer::GetZNear(), FGLRenderer::GetZFar());
return result;
}
/* virtual */
Viewport EyePose::GetViewport(const Viewport& fullViewport) const
{
return fullViewport;
}
/* virtual */
void EyePose::GetViewShift(float yaw, float outViewShift[3]) const
{
// pass-through for Mono view
outViewShift[0] = 0;
outViewShift[1] = 0;
outViewShift[2] = 0;
}
Stereo3DMode::Stereo3DMode()
{
}
Stereo3DMode::~Stereo3DMode()
{
}
// Avoid static initialization order fiasco by declaring first Mode type (Mono) here in the
// same source file as Stereo3DMode::getCurrentMode()
// https://isocpp.org/wiki/faq/ctors#static-init-order
/* static */
const MonoView& MonoView::getInstance()
{
static MonoView instance;
return instance;
}
} /* namespace s3d */

View file

@ -1,115 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_stereo3d.h
** Stereoscopic 3D API
**
*/
#ifndef GL_STEREO3D_H_
#define GL_STEREO3D_H_
#include <cstring> // needed for memcpy on linux, which is needed by VSMatrix copy ctor
#include "tarray.h"
#include "r_data/matrix.h"
#include "gl/renderer/gl_renderer.h"
/* stereoscopic 3D API */
namespace s3d {
/* Subregion of current display window */
class Viewport
{
public:
int x, y;
int width, height;
};
/* Viewpoint of one eye */
class EyePose
{
public:
EyePose() {}
virtual ~EyePose() {}
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
virtual Viewport GetViewport(const Viewport& fullViewport) const;
virtual void GetViewShift(float yaw, float outViewShift[3]) const;
virtual void SetUp() const {};
virtual void TearDown() const {};
};
/* Base class for stereoscopic 3D rendering modes */
class Stereo3DMode
{
public:
/* static methods for managing the selected stereoscopic view state */
static const Stereo3DMode& getCurrentMode();
static const Stereo3DMode& getMonoMode();
Stereo3DMode();
virtual ~Stereo3DMode();
virtual int eye_count() const { return eye_ptrs.Size(); }
virtual const EyePose * getEyePose(int ix) const { return eye_ptrs(ix); }
/* hooks for setup and cleanup operations for each stereo mode */
virtual void SetUp() const {};
virtual void TearDown() const {};
virtual bool IsMono() const { return false; }
virtual void AdjustViewports() const {};
virtual void AdjustPlayerSprites() const {};
virtual void Present() const = 0;
protected:
TArray<const EyePose *> eye_ptrs;
private:
static Stereo3DMode const * currentStereo3DMode;
static void setCurrentMode(const Stereo3DMode& mode);
};
/**
* Ordinary non-3D rendering
*/
class MonoView : public Stereo3DMode
{
public:
static const MonoView& getInstance();
bool IsMono() const override { return true; }
void Present() const override { }
protected:
MonoView() { eye_ptrs.Push(&centralEye); }
EyePose centralEye;
};
} /* namespace st3d */
#endif /* GL_STEREO3D_H_ */

View file

@ -1,127 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_stereo_cvars.cpp
** Console variables related to stereoscopic 3D in GZDoom
**
*/
#include "gl/stereo3d/gl_stereo3d.h"
#include "gl/stereo3d/gl_stereo_leftright.h"
#include "gl/stereo3d/gl_anaglyph.h"
#include "gl/stereo3d/gl_quadstereo.h"
#include "gl/stereo3d/gl_sidebyside3d.h"
#include "gl/stereo3d/gl_interleaved3d.h"
#include "version.h"
// Set up 3D-specific console variables:
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG)
// switch left and right eye views
CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG)
// intraocular distance in meters
CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS
// distance between viewer and the display screen
CVAR(Float, vr_screendist, 0.80f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
// default conversion between (vertical) DOOM units and meters
CVAR(Float, vr_hunits_per_meter, 41.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // METERS
// Manage changing of 3D modes:
namespace s3d {
// Initialize static member
Stereo3DMode const * Stereo3DMode::currentStereo3DMode = 0; // "nullptr" not resolved on linux (presumably not C++11)
/* static */
void Stereo3DMode::setCurrentMode(const Stereo3DMode& mode) {
Stereo3DMode::currentStereo3DMode = &mode;
}
/* static */
const Stereo3DMode& Stereo3DMode::getCurrentMode()
{
// NOTE: Ensure that these vr_mode values correspond to the ones in wadsrc/static/menudef.z
switch (vr_mode)
{
case 1:
setCurrentMode(GreenMagenta::getInstance(vr_ipd));
break;
case 2:
setCurrentMode(RedCyan::getInstance(vr_ipd));
break;
case 3:
setCurrentMode(SideBySideFull::getInstance(vr_ipd));
break;
case 4:
setCurrentMode(SideBySideSquished::getInstance(vr_ipd));
break;
case 5:
setCurrentMode(LeftEyeView::getInstance(vr_ipd));
break;
case 6:
setCurrentMode(RightEyeView::getInstance(vr_ipd));
break;
case 7:
if (screen->enable_quadbuffered) {
setCurrentMode(QuadStereo::getInstance(vr_ipd));
}
else {
setCurrentMode(MonoView::getInstance());
}
break;
// TODO: 8: Oculus Rift
case 9:
setCurrentMode(AmberBlue::getInstance(vr_ipd));
break;
// TODO: 10: HTC Vive/OpenVR
case 11:
setCurrentMode(TopBottom3D::getInstance(vr_ipd));
break;
case 12:
setCurrentMode(RowInterleaved3D::getInstance(vr_ipd));
break;
case 13:
setCurrentMode(ColumnInterleaved3D::getInstance(vr_ipd));
break;
case 14:
setCurrentMode(CheckerInterleaved3D::getInstance(vr_ipd));
break;
case 0:
default:
setCurrentMode(MonoView::getInstance());
break;
}
return *currentStereo3DMode;
}
const Stereo3DMode& Stereo3DMode::getMonoMode()
{
setCurrentMode(MonoView::getInstance());
return *currentStereo3DMode;
}
} /* namespace s3d */

View file

@ -1,116 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_stereo_leftright.cpp
** Offsets for left and right eye views
**
*/
#include "gl_stereo_leftright.h"
#include "vectors.h" // RAD2DEG
#include "doomtype.h" // M_PI
#include "hwrenderer/utility/hw_cvars.h"
#include "gl_load/gl_system.h"
#include "gl/renderer/gl_renderstate.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/renderer/gl_renderbuffers.h"
EXTERN_CVAR(Float, vr_screendist)
EXTERN_CVAR(Float, vr_hunits_per_meter)
EXTERN_CVAR(Bool, vr_swap_eyes)
namespace s3d {
/* virtual */
VSMatrix ShiftedEyePose::GetProjection(float fov, float aspectRatio, float fovRatio) const
{
double zNear = 5.0;
double zFar = 65536.0;
// For stereo 3D, use asymmetric frustum shift in projection matrix
// Q: shouldn't shift vary with roll angle, at least for desktop display?
// A: No. (lab) roll is not measured on desktop display (yet)
double frustumShift = zNear * getShift() / vr_screendist; // meters cancel, leaving doom units
// double frustumShift = 0; // Turning off shift for debugging
double fH = zNear * tan(DEG2RAD(fov) / 2) / fovRatio;
double fW = fH * aspectRatio;
double left = -fW - frustumShift;
double right = fW - frustumShift;
double bottom = -fH;
double top = fH;
VSMatrix result(1);
result.frustum(left, right, bottom, top, zNear, zFar);
return result;
}
/* virtual */
void ShiftedEyePose::GetViewShift(float yaw, float outViewShift[3]) const
{
float dx = -cos(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
float dy = sin(DEG2RAD(yaw)) * vr_hunits_per_meter * getShift();
outViewShift[0] = dx;
outViewShift[1] = dy;
outViewShift[2] = 0;
}
float ShiftedEyePose::getShift() const
{
return vr_swap_eyes ? -shift : shift;
}
/* static */
const LeftEyeView& LeftEyeView::getInstance(float ipd)
{
static LeftEyeView instance(ipd);
instance.setIpd(ipd);
return instance;
}
void LeftEyeView::Present() const
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
}
/* static */
const RightEyeView& RightEyeView::getInstance(float ipd)
{
static RightEyeView instance(ipd);
instance.setIpd(ipd);
return instance;
}
void RightEyeView::Present() const
{
GLRenderer->mBuffers->BindOutputFB();
GLRenderer->ClearBorders();
GLRenderer->mBuffers->BindEyeTexture(0, 0);
GLRenderer->DrawPresentTexture(screen->mOutputLetterbox, true);
}
} /* namespace s3d */

View file

@ -1,103 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_stereo_leftright.h
** Offsets for left and right eye views
**
*/
#ifndef GL_STEREO_LEFTRIGHT_H_
#define GL_STEREO_LEFTRIGHT_H_
#include "gl_stereo3d.h"
namespace s3d {
class ShiftedEyePose : public EyePose
{
public:
ShiftedEyePose(float shift) : shift(shift) {};
float getShift() const;
virtual VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const;
virtual void GetViewShift(float yaw, float outViewShift[3]) const;
protected:
void setShift(float shift) { this->shift = shift; }
private:
float shift;
};
class LeftEyePose : public ShiftedEyePose
{
public:
LeftEyePose(float ipd) : ShiftedEyePose( float(-0.5) * ipd) {}
float getIpd() const { return float(fabs(2.0f*getShift())); }
void setIpd(float ipd) { setShift(float(-0.5)*ipd); }
};
class RightEyePose : public ShiftedEyePose
{
public:
RightEyePose(float ipd) : ShiftedEyePose(float(+0.5)*ipd) {}
float getIpd() const { return float(fabs(2.0f*getShift())); }
void setIpd(float ipd) { setShift(float(+0.5)*ipd); }
};
/**
* As if viewed through the left eye only
*/
class LeftEyeView : public Stereo3DMode
{
public:
static const LeftEyeView& getInstance(float ipd);
LeftEyeView(float ipd) : eye(ipd) { eye_ptrs.Push(&eye); }
float getIpd() const { return eye.getIpd(); }
void setIpd(float ipd) { eye.setIpd(ipd); }
void Present() const override;
protected:
LeftEyePose eye;
};
class RightEyeView : public Stereo3DMode
{
public:
static const RightEyeView& getInstance(float ipd);
RightEyeView(float ipd) : eye(ipd) { eye_ptrs.Push(&eye); }
float getIpd() const { return eye.getIpd(); }
void setIpd(float ipd) { eye.setIpd(ipd); }
void Present() const override;
protected:
RightEyePose eye;
};
} /* namespace s3d */
#endif /* GL_STEREO_LEFTRIGHT_H_ */

View file

@ -1,56 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2015 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** scoped_color_mask.h
** Stack-scoped class for temporarily changing the OpenGL color mask setting.
**
*/
#ifndef GL_STEREO3D_SCOPED_COLOR_MASK_H_
#define GL_STEREO3D_SCOPED_COLOR_MASK_H_
#include "gl_load/gl_system.h"
/**
* Temporarily change color mask
*/
class ScopedColorMask
{
public:
ScopedColorMask(bool r, bool g, bool b, bool a)
{
gl_RenderState.GetColorMask(saved[0], saved[1], saved[2], saved[3]);
gl_RenderState.SetColorMask(r, g, b, a);
gl_RenderState.ApplyColorMask();
gl_RenderState.EnableDrawBuffers(1);
}
~ScopedColorMask() {
gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
gl_RenderState.SetColorMask(saved[0], saved[1], saved[2], saved[3]);
gl_RenderState.ApplyColorMask();
}
private:
bool saved[4];
};
#endif // GL_STEREO3D_SCOPED_COLOR_MASK_H_

View file

@ -37,10 +37,10 @@
#include "gl/renderer/gl_renderbuffers.h"
#include "gl/textures/gl_samplers.h"
#include "hwrenderer/utility/hw_clock.h"
#include "hwrenderer/utility/hw_vrmodes.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/data/gl_uniformbuffer.h"
#include "gl/models/gl_models.h"
#include "gl/stereo3d/gl_stereo3d.h"
#include "gl/shaders/gl_shaderprogram.h"
#include "gl_debug.h"
#include "r_videoscale.h"
@ -342,7 +342,7 @@ IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture(FTexture *tex)
FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli)
{
return new FGLModelRenderer(mli);
return new FGLModelRenderer(nullptr, mli);
}
IUniformBuffer *OpenGLFrameBuffer::CreateUniformBuffer(size_t size, bool staticuse)
@ -361,11 +361,6 @@ void OpenGLFrameBuffer::UnbindTexUnit(int no)
FHardwareTexture::Unbind(no);
}
void OpenGLFrameBuffer::FlushTextures()
{
if (GLRenderer) GLRenderer->FlushTextures();
}
void OpenGLFrameBuffer::TextureFilterChanged()
{
if (GLRenderer != NULL && GLRenderer->mSamplerManager != NULL) GLRenderer->mSamplerManager->SetTextureFilterMode();
@ -380,7 +375,10 @@ void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds)
{
Super::SetViewportRects(bounds);
if (!bounds)
s3d::Stereo3DMode::getCurrentMode().AdjustViewports();
{
auto vrmode = VRMode::GetVRMode(true);
vrmode->AdjustViewport(this);
}
}

View file

@ -37,7 +37,6 @@ public:
IHardwareTexture *CreateHardwareTexture(FTexture *tex) override;
FModelRenderer *CreateModelRenderer(int mli) override;
void UnbindTexUnit(int no) override;
void FlushTextures() override;
void TextureFilterChanged() override;
void BeginFrame() override;
void SetViewportRects(IntRect *bounds) override;