From aeb7df09de843542c3da7c889e5cc18540e59f87 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 26 Jul 2016 21:27:02 +0200 Subject: [PATCH] Added hardware gamma option and improved window handling on Windows --- src/CMakeLists.txt | 3 + src/gl/renderer/gl_renderbuffers.cpp | 159 ++++++++++++++++++++ src/gl/renderer/gl_renderbuffers.h | 29 ++++ src/gl/renderer/gl_renderer.cpp | 69 +++++++++ src/gl/renderer/gl_renderer.h | 14 +- src/gl/scene/gl_scene.cpp | 146 +++++++++++++----- src/gl/shaders/gl_presentshader.cpp | 67 +++++++++ src/gl/shaders/gl_presentshader.h | 20 +++ src/gl/shaders/gl_shaderprogram.cpp | 205 ++++++++++++++++++++++++++ src/gl/shaders/gl_shaderprogram.h | 36 +++++ src/gl/system/gl_framebuffer.cpp | 29 +++- src/gl/system/gl_framebuffer.h | 4 +- src/gl/system/gl_wipe.cpp | 32 +++- src/posix/cocoa/i_video.mm | 14 ++ src/posix/cocoa/sdlglvideo.h | 6 +- src/posix/sdl/sdlglvideo.cpp | 31 +++- src/posix/sdl/sdlglvideo.h | 4 + src/win32/hardware.cpp | 2 +- src/win32/win32gliface.cpp | 49 ++++-- src/win32/win32gliface.h | 3 + wadsrc/static/language.enu | 2 + wadsrc/static/menudef.txt | 1 + wadsrc/static/menudef.z | 7 + wadsrc/static/shaders/glsl/present.fp | 23 +++ wadsrc/static/shaders/glsl/present.vp | 11 ++ 25 files changed, 899 insertions(+), 67 deletions(-) create mode 100644 src/gl/renderer/gl_renderbuffers.cpp create mode 100644 src/gl/renderer/gl_renderbuffers.h create mode 100644 src/gl/shaders/gl_presentshader.cpp create mode 100644 src/gl/shaders/gl_presentshader.h create mode 100644 src/gl/shaders/gl_shaderprogram.cpp create mode 100644 src/gl/shaders/gl_shaderprogram.h create mode 100644 wadsrc/static/shaders/glsl/present.fp create mode 100644 wadsrc/static/shaders/glsl/present.vp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be053d1bb4..cad3299628 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1060,6 +1060,7 @@ set( FASTMATH_SOURCES gl/utility/gl_geometric.cpp gl/renderer/gl_renderer.cpp gl/renderer/gl_renderstate.cpp + gl/renderer/gl_renderbuffers.cpp gl/renderer/gl_lightdata.cpp gl/hqnx/init.cpp gl/hqnx/hq2x.cpp @@ -1103,6 +1104,8 @@ set( FASTMATH_SOURCES gl/dynlights/gl_lightbuffer.cpp gl/shaders/gl_shader.cpp gl/shaders/gl_texshader.cpp + gl/shaders/gl_shaderprogram.cpp + gl/shaders/gl_presentshader.cpp gl/system/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_menu.cpp diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp new file mode 100644 index 0000000000..9468c23ef8 --- /dev/null +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -0,0 +1,159 @@ +/* +** gl_renderbuffers.cpp +** Render buffers used during rendering +** +**--------------------------------------------------------------------------- +** Copyright 2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be +** covered by the terms of the GNU Lesser General Public License as published +** by the Free Software Foundation; either version 2.1 of the License, or (at +** your option) any later version. +** 5. Full disclosure of the entire project's source code, except for third +** party libraries is mandatory. (NOTE: This clause is non-negotiable!) +** +** 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/system/gl_system.h" +#include "files.h" +#include "m_swap.h" +#include "v_video.h" +#include "gl/gl_functions.h" +#include "vectors.h" +#include "gl/system/gl_interface.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_cvars.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_renderbuffers.h" +#include "w_wad.h" +#include "i_system.h" +#include "doomerrors.h" + +//========================================================================== +// +// Initialize render buffers and textures used in rendering passes +// +//========================================================================== + +FGLRenderBuffers::FGLRenderBuffers() +{ + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&mOutputFB); +} + +//========================================================================== +// +// Free render buffer resources +// +//========================================================================== + +FGLRenderBuffers::~FGLRenderBuffers() +{ + if (mSceneFB != 0) + glDeleteFramebuffers(1, &mSceneFB); + if (mSceneTexture != 0) + glDeleteTextures(1, &mSceneTexture); + if (mSceneDepthStencil != 0) + glDeleteRenderbuffers(1, &mSceneDepthStencil); +} + +//========================================================================== +// +// Makes sure all render buffers have sizes suitable for rending at the +// specified resolution +// +//========================================================================== + +void FGLRenderBuffers::Setup(int width, int height) +{ + if (width <= mWidth && height <= mHeight) + return; + + if (mSceneFB != 0) + glDeleteFramebuffers(1, &mSceneFB); + if (mSceneTexture != 0) + glDeleteTextures(1, &mSceneTexture); + if (mSceneDepthStencil != 0) + glDeleteRenderbuffers(1, &mSceneDepthStencil); + + glGenFramebuffers(1, &mSceneFB); + glGenTextures(1, &mSceneTexture); + glGenRenderbuffers(1, &mSceneDepthStencil); + + glBindTexture(GL_TEXTURE_2D, mSceneTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, mSceneDepthStencil); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mSceneTexture, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mSceneDepthStencil); + glBindFramebuffer(GL_FRAMEBUFFER, mOutputFB); + + mWidth = width; + mHeight = height; +} + +//========================================================================== +// +// Makes the scene frame buffer active +// +//========================================================================== + +void FGLRenderBuffers::BindSceneFB() +{ + glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); +} + +//========================================================================== +// +// Makes the screen frame buffer active +// +//========================================================================== + +void FGLRenderBuffers::BindOutputFB() +{ + glBindFramebuffer(GL_FRAMEBUFFER, mOutputFB); +} + +//========================================================================== +// +// Binds the scene frame buffer texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindSceneTexture(int index) +{ + glActiveTexture(index); + glBindTexture(GL_TEXTURE_2D, mSceneTexture); +} diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h new file mode 100644 index 0000000000..bbb38b533a --- /dev/null +++ b/src/gl/renderer/gl_renderbuffers.h @@ -0,0 +1,29 @@ +#ifndef __GL_RENDERBUFFERS_H +#define __GL_RENDERBUFFERS_H + +#include "gl/shaders/gl_shader.h" + +class FGLRenderBuffers +{ +public: + FGLRenderBuffers(); + ~FGLRenderBuffers(); + + void Setup(int width, int height); + void BindSceneFB(); + void BindOutputFB(); + void BindSceneTexture(int index); + + static bool IsSupported() { return gl.version >= 3.3f; } + +private: + int mWidth = 0; + int mHeight = 0; + + GLuint mSceneTexture = 0; + GLuint mSceneDepthStencil = 0; + GLuint mSceneFB = 0; + GLuint mOutputFB = 0; +}; + +#endif \ No newline at end of file diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 0a00494262..6c1677b7b3 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -49,6 +49,7 @@ //#include "gl/gl_intern.h" #include "gl/gl_functions.h" #include "vectors.h" +#include "doomstat.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_framebuffer.h" @@ -56,10 +57,12 @@ #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_lightdata.h" #include "gl/renderer/gl_renderstate.h" +#include "gl/renderer/gl_renderbuffers.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/scene/gl_drawinfo.h" #include "gl/shaders/gl_shader.h" +#include "gl/shaders/gl_presentshader.h" #include "gl/textures/gl_texture.h" #include "gl/textures/gl_translate.h" #include "gl/textures/gl_material.h" @@ -69,6 +72,8 @@ #include "gl/models/gl_models.h" #include "gl/dynlights/gl_lightbuffer.h" +EXTERN_CVAR(Int, screenblocks) + //=========================================================================== // // Renderer interface @@ -104,6 +109,9 @@ void gl_FlushModels(); void FGLRenderer::Initialize() { + mBuffers = new FGLRenderBuffers(); + mPresentShader = new FPresentShader(); + // Only needed for the core profile, because someone decided it was a good idea to remove the default VAO. if (gl.version >= 4.0) { @@ -150,7 +158,57 @@ FGLRenderer::~FGLRenderer() glBindVertexArray(0); glDeleteVertexArrays(1, &mVAOID); } + if (mBuffers) delete mBuffers; + if (mPresentShader) delete mPresentShader; +} +//========================================================================== +// +// Calculates the viewport values needed for 2D and 3D operations +// +//========================================================================== + +void FGLRenderer::SetOutputViewport(GL_IRECT *bounds) +{ + if (bounds) + { + mOutputViewport = *bounds; + mOutputViewportLB = *bounds; + return; + } + + int height, width; + + // Special handling so the view with a visible status bar displays properly + + if (screenblocks >= 10) + { + height = framebuffer->GetHeight(); + width = framebuffer->GetWidth(); + } + else + { + height = (screenblocks*framebuffer->GetHeight() / 10) & ~7; + width = (screenblocks*framebuffer->GetWidth() / 10); + } + + int trueheight = framebuffer->GetTrueHeight(); // ugh... + int bars = (trueheight - framebuffer->GetHeight()) / 2; + + int vw = viewwidth; + int vh = viewheight; + + // Letterboxed viewport for the main scene + mOutputViewportLB.left = viewwindowx; + mOutputViewportLB.top = trueheight - bars - (height + viewwindowy - ((height - vh) / 2)); + mOutputViewportLB.width = vw; + mOutputViewportLB.height = height; + + // Entire canvas for player sprites + mOutputViewport.left = 0; + mOutputViewport.top = (trueheight - framebuffer->GetHeight()) / 2; + mOutputViewport.width = framebuffer->GetWidth(); + mOutputViewport.height = framebuffer->GetHeight(); } //=========================================================================== @@ -166,6 +224,17 @@ void FGLRenderer::SetupLevel() void FGLRenderer::Begin2D() { + if (FGLRenderBuffers::IsSupported()) + { + mBuffers->Setup(framebuffer->GetWidth(), framebuffer->GetHeight()); + mBuffers->BindSceneFB(); + glViewport(0, 0, mOutputViewport.width, mOutputViewport.height); + } + else + { + glViewport(mOutputViewport.left, mOutputViewport.top, mOutputViewport.width, mOutputViewport.height); + } + gl_RenderState.EnableFog(false); gl_RenderState.Set2DMode(true); } diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index e8ef87157e..9920765287 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -18,6 +18,8 @@ class GLPortal; class FLightBuffer; class FSamplerManager; class DPSprite; +class FGLRenderBuffers; +class FPresentShader; inline float DEG2RAD(float deg) { @@ -79,6 +81,9 @@ public: unsigned int mVAOID; int mOldFBID; + FGLRenderBuffers *mBuffers; + FPresentShader *mPresentShader; + FTexture *gllight; FTexture *glpart2; FTexture *glpart; @@ -93,14 +98,17 @@ public: FSkyVertexBuffer *mSkyVBO; FLightBuffer *mLights; + GL_IRECT mOutputViewportLB; + GL_IRECT mOutputViewport; FGLRenderer(OpenGLFrameBuffer *fb); ~FGLRenderer() ; angle_t FrustumAngle(); void SetViewArea(); - void ResetViewport(); - void SetViewport(GL_IRECT *bounds); + void SetOutputViewport(GL_IRECT *bounds); + void Set3DViewport(); + void Reset3DViewport(); sector_t *RenderViewpoint (AActor * camera, GL_IRECT * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen); void RenderView(player_t *player); void SetViewAngle(DAngle viewangle); @@ -139,7 +147,7 @@ public: void SetFixedColormap (player_t *player); void WriteSavePic (player_t *player, FILE *file, int width, int height); void EndDrawScene(sector_t * viewsector); - void Flush() {} + void Flush(); void SetProjection(float fov, float ratio, float fovratio); void SetProjection(VSMatrix matrix); // raw matrix input from stereo 3d modes diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 4cb79262e7..3f52ce2b13 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -63,6 +63,7 @@ #include "gl/system/gl_cvars.h" #include "gl/renderer/gl_lightdata.h" #include "gl/renderer/gl_renderstate.h" +#include "gl/renderer/gl_renderbuffers.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/dynlights/gl_dynlight.h" @@ -71,6 +72,7 @@ #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_portal.h" #include "gl/shaders/gl_shader.h" +#include "gl/shaders/gl_presentshader.h" #include "gl/stereo3d/gl_stereo3d.h" #include "gl/stereo3d/scoped_view_shifter.h" #include "gl/textures/gl_translate.h" @@ -91,9 +93,10 @@ CVAR(Float, gl_mask_threshold, 0.5f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Float, gl_mask_sprite_threshold, 0.5f,CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, gl_sort_textures, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -EXTERN_CVAR (Int, screenblocks) EXTERN_CVAR (Bool, cl_capfps) EXTERN_CVAR (Bool, r_deathcamera) +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) extern int viewpitch; @@ -155,10 +158,12 @@ void FGLRenderer::SetViewArea() // //----------------------------------------------------------------------------- -void FGLRenderer::ResetViewport() +void FGLRenderer::Reset3DViewport() { - int trueheight = static_cast(screen)->GetTrueHeight(); // ugh... - glViewport(0, (trueheight-screen->GetHeight())/2, screen->GetWidth(), screen->GetHeight()); + if (FGLRenderBuffers::IsSupported()) + glViewport(0, 0, mOutputViewport.width, mOutputViewport.height); + else + glViewport(mOutputViewport.left, mOutputViewport.top, mOutputViewport.width, mOutputViewport.height); } //----------------------------------------------------------------------------- @@ -167,38 +172,22 @@ void FGLRenderer::ResetViewport() // //----------------------------------------------------------------------------- -void FGLRenderer::SetViewport(GL_IRECT *bounds) +void FGLRenderer::Set3DViewport() { - if (!bounds) + const auto &bounds = mOutputViewportLB; + if (FGLRenderBuffers::IsSupported()) { - int height, width; - - // Special handling so the view with a visible status bar displays properly - - if (screenblocks >= 10) - { - height = SCREENHEIGHT; - width = SCREENWIDTH; - } - else - { - height = (screenblocks*SCREENHEIGHT/10) & ~7; - width = (screenblocks*SCREENWIDTH/10); - } - - int trueheight = static_cast(screen)->GetTrueHeight(); // ugh... - int bars = (trueheight-screen->GetHeight())/2; - - int vw = viewwidth; - int vh = viewheight; - glViewport(viewwindowx, trueheight-bars-(height+viewwindowy-((height-vh)/2)), vw, height); - glScissor(viewwindowx, trueheight-bars-(vh+viewwindowy), vw, vh); + mBuffers->Setup(mOutputViewport.width, mOutputViewport.height); + mBuffers->BindSceneFB(); + glViewport(0, 0, bounds.width, bounds.height); + glScissor(0, 0, bounds.width, bounds.height); } else { - glViewport(bounds->left, bounds->top, bounds->width, bounds->height); - glScissor(bounds->left, bounds->top, bounds->width, bounds->height); + glViewport(bounds.left, bounds.top, bounds.width, bounds.height); + glScissor(bounds.left, bounds.top, bounds.width, bounds.height); } + glEnable(GL_SCISSOR_TEST); #ifdef _DEBUG @@ -215,6 +204,97 @@ void FGLRenderer::SetViewport(GL_IRECT *bounds) glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE); } +//----------------------------------------------------------------------------- +// +// Run post processing steps and copy to frame buffer +// +//----------------------------------------------------------------------------- + +void FGLRenderer::Flush() +{ + if (FGLRenderBuffers::IsSupported()) + { + glDisable(GL_MULTISAMPLE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + + mBuffers->BindOutputFB(); + + // Calculate letterbox + int clientWidth = framebuffer->GetClientWidth(); + int clientHeight = framebuffer->GetClientHeight(); + float scaleX = clientWidth / (float)mOutputViewport.width; + float scaleY = clientHeight / (float)mOutputViewport.height; + float scale = MIN(scaleX, scaleY); + int width = (int)round(mOutputViewport.width * scale); + int height = (int)round(mOutputViewport.height * scale); + int x = (clientWidth - width) / 2; + int y = (clientHeight - height) / 2; + + // Black bars around the box: + glViewport(0, 0, clientWidth, clientHeight); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_SCISSOR_TEST); + if (y > 0) + { + glScissor(0, 0, clientWidth, y); + glClear(GL_COLOR_BUFFER_BIT); + } + if (clientHeight - y - height > 0) + { + glScissor(0, y + height, clientWidth, clientHeight - y - height); + glClear(GL_COLOR_BUFFER_BIT); + } + if (x > 0) + { + glScissor(0, y, x, height); + glClear(GL_COLOR_BUFFER_BIT); + } + if (clientWidth - x - width > 0) + { + glScissor(x + width, y, clientWidth - x - width, height); + glClear(GL_COLOR_BUFFER_BIT); + } + glDisable(GL_SCISSOR_TEST); + + // Present what was rendered: + glViewport(x, y, width, height); + + GLboolean blendEnabled; + GLint currentProgram; + glGetBooleanv(GL_BLEND, &blendEnabled); + glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); + glDisable(GL_BLEND); + + mPresentShader->Bind(); + mPresentShader->InputTexture.Set(0); + if (framebuffer->IsHWGammaActive()) + { + mPresentShader->Gamma.Set(1.0f); + mPresentShader->Contrast.Set(1.0f); + mPresentShader->Brightness.Set(0.0f); + } + else + { + mPresentShader->Gamma.Set(clamp(Gamma, 0.1f, 4.f)); + mPresentShader->Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); + mPresentShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); + } + mBuffers->BindSceneTexture(0); + + FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); + ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; + ptr->Set(-1.0f, 1.0f, 0, 0.0f, 1.0f); ptr++; + ptr->Set(1.0f, -1.0f, 0, 1.0f, 0.0f); ptr++; + ptr->Set(1.0f, 1.0f, 0, 1.0f, 1.0f); ptr++; + GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + + if (blendEnabled) + glEnable(GL_BLEND); + glUseProgram(currentProgram); + } +} + //----------------------------------------------------------------------------- // // Setup the camera position @@ -707,7 +787,7 @@ void FGLRenderer::EndDrawScene(sector_t * viewsector) framebuffer->Begin2D(false); - ResetViewport(); + Reset3DViewport(); // [BB] Only draw the sprites if we didn't render a HUD model before. if ( renderHUDModel == false ) { @@ -846,7 +926,8 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo const s3d::EyePose * eye = stereo3dMode.getEyePose(eye_ix); eye->SetUp(); // TODO: stereo specific viewport - needed when implementing side-by-side modes etc. - SetViewport(bounds); + SetOutputViewport(bounds); + Set3DViewport(); mCurrentFoV = fov; // Stereo mode specific perspective projection SetProjection( eye->GetProjection(fov, ratio, fovratio) ); @@ -873,7 +954,6 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo return retval; } - //----------------------------------------------------------------------------- // // renders the view diff --git a/src/gl/shaders/gl_presentshader.cpp b/src/gl/shaders/gl_presentshader.cpp new file mode 100644 index 0000000000..36266ded37 --- /dev/null +++ b/src/gl/shaders/gl_presentshader.cpp @@ -0,0 +1,67 @@ +/* +** gl_presentshader.cpp +** Copy rendered texture to back buffer, possibly with gamma correction +** +**--------------------------------------------------------------------------- +** Copyright 2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be +** covered by the terms of the GNU Lesser General Public License as published +** by the Free Software Foundation; either version 2.1 of the License, or (at +** your option) any later version. +** 5. Full disclosure of the entire project's source code, except for third +** party libraries is mandatory. (NOTE: This clause is non-negotiable!) +** +** 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/system/gl_system.h" +#include "files.h" +#include "m_swap.h" +#include "v_video.h" +#include "gl/gl_functions.h" +#include "vectors.h" +#include "gl/system/gl_interface.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_cvars.h" +#include "gl/shaders/gl_presentshader.h" + +void FPresentShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/present.vp"); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present.fp"); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/present"); + mShader.SetAttribLocation(0, "PositionInProjection"); + InputTexture.Init(mShader, "InputTexture"); + Gamma.Init(mShader, "Gamma"); + Contrast.Init(mShader, "Contrast"); + Brightness.Init(mShader, "Brightness"); + } + mShader.Bind(); +} diff --git a/src/gl/shaders/gl_presentshader.h b/src/gl/shaders/gl_presentshader.h new file mode 100644 index 0000000000..6bec79625e --- /dev/null +++ b/src/gl/shaders/gl_presentshader.h @@ -0,0 +1,20 @@ +#ifndef __GL_PRESENTSHADER_H +#define __GL_PRESENTSHADER_H + +#include "gl_shaderprogram.h" + +class FPresentShader +{ +public: + void Bind(); + + FBufferedUniform1i InputTexture; + FBufferedUniform1f Gamma; + FBufferedUniform1f Contrast; + FBufferedUniform1f Brightness; + +private: + FShaderProgram mShader; +}; + +#endif \ No newline at end of file diff --git a/src/gl/shaders/gl_shaderprogram.cpp b/src/gl/shaders/gl_shaderprogram.cpp new file mode 100644 index 0000000000..bcbdf0c1a7 --- /dev/null +++ b/src/gl/shaders/gl_shaderprogram.cpp @@ -0,0 +1,205 @@ +/* +** gl_shaderprogram.cpp +** GLSL shader program compile and link +** +**--------------------------------------------------------------------------- +** Copyright 2008 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be +** covered by the terms of the GNU Lesser General Public License as published +** by the Free Software Foundation; either version 2.1 of the License, or (at +** your option) any later version. +** 5. Full disclosure of the entire project's source code, except for third +** party libraries is mandatory. (NOTE: This clause is non-negotiable!) +** +** 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/system/gl_system.h" +#include "files.h" +#include "m_swap.h" +#include "v_video.h" +#include "gl/gl_functions.h" +#include "vectors.h" +#include "gl/system/gl_interface.h" +#include "gl/system/gl_cvars.h" +#include "gl/shaders/gl_shaderprogram.h" +#include "w_wad.h" +#include "i_system.h" +#include "doomerrors.h" + +//========================================================================== +// +// Free shader program resources +// +//========================================================================== + +FShaderProgram::~FShaderProgram() +{ + if (mProgram != 0) + glDeleteProgram(mProgram); + + for (int i = 0; i < NumShaderTypes; i++) + { + if (mShaders[i] != 0) + glDeleteShader(mShaders[i]); + } +} + +//========================================================================== +// +// Creates an OpenGL shader object for the specified type of shader +// +//========================================================================== + +void FShaderProgram::CreateShader(ShaderType type) +{ + GLenum gltype = 0; + switch (type) + { + default: + case Vertex: gltype = GL_VERTEX_SHADER; break; + case Fragment: gltype = GL_FRAGMENT_SHADER; break; + } + mShaders[type] = glCreateShader(gltype); +} + +//========================================================================== +// +// Compiles a shader and attaches it the program object +// +//========================================================================== + +void FShaderProgram::Compile(ShaderType type, const char *lumpName) +{ + CreateShader(type); + + const auto &handle = mShaders[type]; + + int lump = Wads.CheckNumForFullName(lumpName); + if (lump == -1) I_Error("Unable to load '%s'", lumpName); + FString code = Wads.ReadLump(lump).GetString().GetChars(); + + int lengths[1] = { (int)code.Len() }; + const char *sources[1] = { code.GetChars() }; + glShaderSource(handle, 1, sources, lengths); + + glCompileShader(handle); + + GLint status = 0; + glGetShaderiv(handle, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) + { + I_Error("Compile Shader '%s':\n%s\n", lumpName, GetShaderInfoLog(handle).GetChars()); + } + else + { + if (mProgram == 0) + mProgram = glCreateProgram(); + glAttachShader(mProgram, handle); + } +} + +//========================================================================== +// +// Binds a fragment output variable to a frame buffer render target +// +//========================================================================== + +void FShaderProgram::SetFragDataLocation(int index, const char *name) +{ + glBindFragDataLocation(mProgram, index, name); +} + +//========================================================================== +// +// Links a program with the compiled shaders +// +//========================================================================== + +void FShaderProgram::Link(const char *name) +{ + glLinkProgram(mProgram); + + GLint status = 0; + glGetProgramiv(mProgram, GL_LINK_STATUS, &status); + if (status == GL_FALSE) + { + I_Error("Link Shader '%s':\n%s\n", name, GetProgramInfoLog(mProgram).GetChars()); + } +} + +//========================================================================== +// +// Set vertex attribute location +// +//========================================================================== + +void FShaderProgram::SetAttribLocation(int index, const char *name) +{ + glBindAttribLocation(mProgram, index, name); +} + +//========================================================================== +// +// Makes the shader the active program +// +//========================================================================== + +void FShaderProgram::Bind() +{ + glUseProgram(mProgram); +} + +//========================================================================== +// +// Returns the shader info log (warnings and compile errors) +// +//========================================================================== + +FString FShaderProgram::GetShaderInfoLog(GLuint handle) +{ + static char buffer[10000]; + GLsizei length = 0; + buffer[0] = 0; + glGetShaderInfoLog(handle, 10000, &length, buffer); + return FString(buffer); +} + +//========================================================================== +// +// Returns the program info log (warnings and compile errors) +// +//========================================================================== + +FString FShaderProgram::GetProgramInfoLog(GLuint handle) +{ + static char buffer[10000]; + GLsizei length = 0; + buffer[0] = 0; + glGetProgramInfoLog(handle, 10000, &length, buffer); + return FString(buffer); +} diff --git a/src/gl/shaders/gl_shaderprogram.h b/src/gl/shaders/gl_shaderprogram.h new file mode 100644 index 0000000000..9cc3315259 --- /dev/null +++ b/src/gl/shaders/gl_shaderprogram.h @@ -0,0 +1,36 @@ +#ifndef __GL_SHADERPROGRAM_H +#define __GL_SHADERPROGRAM_H + +#include "gl_shader.h" + +class FShaderProgram +{ +public: + ~FShaderProgram(); + + enum ShaderType + { + Vertex, + Fragment, + NumShaderTypes + }; + + void Compile(ShaderType type, const char *lumpName); + void SetFragDataLocation(int index, const char *name); + void Link(const char *name); + void SetAttribLocation(int index, const char *name); + void Bind(); + + operator GLuint() const { return mProgram; } + explicit operator bool() const { return mProgram != 0; } + +private: + void CreateShader(ShaderType type); + FString GetShaderInfoLog(GLuint handle); + FString GetProgramInfoLog(GLuint handle); + + GLuint mProgram = 0; + GLuint mShaders[NumShaderTypes]; +}; + +#endif \ No newline at end of file diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 8180847062..1b3a880b27 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -78,6 +78,12 @@ void gl_LoadExtensions(); void gl_PrintStartupLog(); void gl_SetupMenu(); +CUSTOM_CVAR(Int, vid_hwgamma, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (self < 0 || self > 2) self = 2; + if (GLRenderer != NULL && GLRenderer->framebuffer != NULL) GLRenderer->framebuffer->DoSetGamma(); +} + //========================================================================== // // @@ -150,12 +156,13 @@ void OpenGLFrameBuffer::InitializeState() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - int trueH = GetTrueHeight(); - int h = GetHeight(); - glViewport(0, (trueH - h)/2, GetWidth(), GetHeight()); + //int trueH = GetTrueHeight(); + //int h = GetHeight(); + //glViewport(0, (trueH - h)/2, GetWidth(), GetHeight()); - Begin2D(false); GLRenderer->Initialize(); + GLRenderer->SetOutputViewport(nullptr); + Begin2D(false); } //========================================================================== @@ -230,10 +237,11 @@ void OpenGLFrameBuffer::Swap() void OpenGLFrameBuffer::DoSetGamma() { - WORD gammaTable[768]; - - if (m_supportsGamma) + bool useHWGamma = m_supportsGamma && ((vid_hwgamma == 0) || (vid_hwgamma == 2 && IsFullscreen())); + if (useHWGamma) { + WORD gammaTable[768]; + // This formula is taken from Doomsday float gamma = clamp(Gamma, 0.1f, 4.f); float contrast = clamp(vid_contrast, 0.1f, 3.f); @@ -251,6 +259,13 @@ void OpenGLFrameBuffer::DoSetGamma() gammaTable[i] = gammaTable[i + 256] = gammaTable[i + 512] = (WORD)clamp(val*256, 0, 0xffff); } SetGammaTable(gammaTable); + + HWGammaActive = true; + } + else if (HWGammaActive) + { + ResetGammaTable(); + HWGammaActive = false; } } diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index ad25851afc..3da60fac42 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -77,7 +77,7 @@ public: void WipeCleanup(); void Swap(); bool Is8BitMode() { return false; } - + bool IsHWGammaActive() const { return HWGammaActive; } private: PalEntry Flash; @@ -107,6 +107,8 @@ private: FHardwareTexture *wipestartscreen; FHardwareTexture *wipeendscreen; + bool HWGammaActive = false; + public: AActor * LastCamera; int palette_brightness; diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index 00fc002f37..6b15e0b6d6 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -52,7 +52,9 @@ #include "gl/system/gl_interface.h" #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderstate.h" +#include "gl/renderer/gl_renderbuffers.h" #include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_cvars.h" #include "gl/shaders/gl_shader.h" #include "gl/textures/gl_translate.h" #include "gl/textures/gl_material.h" @@ -153,11 +155,21 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type) GLRenderer->mSamplerManager->Bind(1, CLAMP_NONE, -1); glFinish(); wipestartscreen->Bind(0, false, false); - GLint readbuffer = 0; - glGetIntegerv(GL_READ_BUFFER, &readbuffer); - glReadBuffer(GL_FRONT); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); - glReadBuffer(readbuffer); + + if (FGLRenderBuffers::IsSupported()) + { + GLRenderer->mBuffers->BindSceneFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); + } + else + { + GLint readbuffer = 0; + glGetIntegerv(GL_READ_BUFFER, &readbuffer); + glReadBuffer(GL_FRONT); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); + glReadBuffer(readbuffer); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -179,6 +191,10 @@ void OpenGLFrameBuffer::WipeEndScreen() GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1); glFinish(); wipeendscreen->Bind(0, false, false); + + if (FGLRenderBuffers::IsSupported()) + GLRenderer->mBuffers->BindSceneFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -214,6 +230,12 @@ bool OpenGLFrameBuffer::WipeDo(int ticks) glDisable(GL_DEPTH_TEST); glDepthMask(false); + if (FGLRenderBuffers::IsSupported()) + { + GLRenderer->mBuffers->BindSceneFB(); + glViewport(0, 0, GLRenderer->mOutputViewport.width, GLRenderer->mOutputViewport.height); + } + bool done = ScreenWipe->Run(ticks, this); glDepthMask(true); //DrawLetterbox(); diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index c3fe258b88..4fa4f55744 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -1239,6 +1239,20 @@ void SDLGLFB::SetGammaTable(WORD* table) { } +void SDLGLFB::ResetGammaTable() +{ +} + +int SDLGLFB::GetClientWidth() +{ + return GetWidth(); +} + +int SDLGLFB::GetClientHeight() +{ + return GetHeight(); +} + // --------------------------------------------------------------------------- diff --git a/src/posix/cocoa/sdlglvideo.h b/src/posix/cocoa/sdlglvideo.h index 439b4d5cef..4a63a91931 100644 --- a/src/posix/cocoa/sdlglvideo.h +++ b/src/posix/cocoa/sdlglvideo.h @@ -62,13 +62,16 @@ public: virtual bool IsFullscreen(); virtual void SetVSync(bool vsync); + int GetClientWidth(); + int GetClientHeight(); + int GetTrueHeight() { return GetHeight(); } protected: int m_lock; bool m_isUpdatePending; - static const bool m_supportsGamma = true; + static const bool m_supportsGamma = false; SDLGLFB(); @@ -78,6 +81,7 @@ protected: void SwapBuffers(); void SetGammaTable(WORD* table); + void ResetGammaTable(); }; #endif // COCOA_SDLGLVIDEO_H_INCLUDED diff --git a/src/posix/sdl/sdlglvideo.cpp b/src/posix/sdl/sdlglvideo.cpp index 54506b8137..aa87f6eb8e 100644 --- a/src/posix/sdl/sdlglvideo.cpp +++ b/src/posix/sdl/sdlglvideo.cpp @@ -350,10 +350,7 @@ SDLGLFB::~SDLGLFB () { if (Screen) { - if (m_supportsGamma) - { - SDL_SetWindowGammaRamp(Screen, m_origGamma[0], m_origGamma[1], m_origGamma[2]); - } + ResetGammaTable(); if (GLContext) { @@ -387,7 +384,18 @@ bool SDLGLFB::CanUpdate () void SDLGLFB::SetGammaTable(WORD *tbl) { - SDL_SetWindowGammaRamp(Screen, &tbl[0], &tbl[256], &tbl[512]); + if (m_supportsGamma) + { + SDL_SetWindowGammaRamp(Screen, &tbl[0], &tbl[256], &tbl[512]); + } +} + +void SDLGLFB::ResetGammaTable() +{ + if (m_supportsGamma) + { + SDL_SetWindowGammaRamp(Screen, m_origGamma[0], m_origGamma[1], m_origGamma[2]); + } } bool SDLGLFB::Lock(bool buffered) @@ -447,3 +455,16 @@ void SDLGLFB::SwapBuffers() SDL_GL_SwapWindow (Screen); } +int SDLGLFB::GetClientWidth() +{ + int width = 0; + SDL_GL_GetDrawableSize(Screen, &width, nullptr); + return width; +} + +int SDLGLFB::GetClientHeight() +{ + int height = 0; + SDL_GL_GetDrawableSize(Screen, nullptr, &height); + return width; +} diff --git a/src/posix/sdl/sdlglvideo.h b/src/posix/sdl/sdlglvideo.h index 19e6a5ff57..0b6a46c12d 100644 --- a/src/posix/sdl/sdlglvideo.h +++ b/src/posix/sdl/sdlglvideo.h @@ -58,12 +58,16 @@ public: friend class SDLGLVideo; + int GetClientWidth(); + int GetClientHeight(); + //[C] int GetTrueHeight() { return GetHeight();} protected: bool CanUpdate(); void SetGammaTable(WORD *tbl); + void ResetGammaTable(); void InitializeState(); SDLGLFB () {} diff --git a/src/win32/hardware.cpp b/src/win32/hardware.cpp index fd92694cd4..787c0a4f38 100644 --- a/src/win32/hardware.cpp +++ b/src/win32/hardware.cpp @@ -357,7 +357,7 @@ void I_RestoreWindowedPos () extern int NewWidth, NewHeight, NewBits, DisplayBits; -CUSTOM_CVAR (Bool, fullscreen, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) +CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { NewWidth = screen->GetWidth(); NewHeight = screen->GetHeight(); diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index 11c359a32a..2e61ae3a63 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -951,7 +951,7 @@ Win32GLFrameBuffer::Win32GLFrameBuffer(void *hMonitor, int width, int height, in style |= WS_POPUP; else { - style |= WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX; + style |= WS_OVERLAPPEDWINDOW; exStyle |= WS_EX_WINDOWEDGE; } @@ -967,7 +967,13 @@ Win32GLFrameBuffer::Win32GLFrameBuffer(void *hMonitor, int width, int height, in } else { - MoveWindow(Window, r.left, r.top, width + (GetSystemMetrics(SM_CXSIZEFRAME) * 2), height + (GetSystemMetrics(SM_CYSIZEFRAME) * 2) + GetSystemMetrics(SM_CYCAPTION), FALSE); + RECT windowRect; + windowRect.left = r.left; + windowRect.top = r.top; + windowRect.right = windowRect.left + width; + windowRect.bottom = windowRect.top + height; + AdjustWindowRectEx(&windowRect, style, FALSE, exStyle); + MoveWindow(Window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, FALSE); I_RestoreWindowedPos(); } @@ -993,12 +999,7 @@ Win32GLFrameBuffer::Win32GLFrameBuffer(void *hMonitor, int width, int height, in Win32GLFrameBuffer::~Win32GLFrameBuffer() { - if (m_supportsGamma) - { - HDC hDC = GetDC(Window); - SetDeviceGammaRamp(hDC, (void *)m_origGamma); - ReleaseDC(Window, hDC); - } + ResetGammaTable(); I_SaveWindowedPos(); static_cast(Video)->SetFullscreen(m_displayDeviceName, 0,0,0,0); @@ -1041,11 +1042,24 @@ bool Win32GLFrameBuffer::CanUpdate() // //========================================================================== +void Win32GLFrameBuffer::ResetGammaTable() +{ + if (m_supportsGamma) + { + HDC hDC = GetDC(Window); + SetDeviceGammaRamp(hDC, (void *)m_origGamma); + ReleaseDC(Window, hDC); + } +} + void Win32GLFrameBuffer::SetGammaTable(WORD *tbl) { - HDC hDC = GetDC(Window); - SetDeviceGammaRamp(hDC, (void *)tbl); - ReleaseDC(Window, hDC); + if (m_supportsGamma) + { + HDC hDC = GetDC(Window); + SetDeviceGammaRamp(hDC, (void *)tbl); + ReleaseDC(Window, hDC); + } } //========================================================================== @@ -1152,6 +1166,19 @@ void Win32GLFrameBuffer::NewRefreshRate () } } +int Win32GLFrameBuffer::GetClientWidth() +{ + RECT rect = { 0 }; + GetClientRect(Window, &rect); + return rect.right - rect.left; +} + +int Win32GLFrameBuffer::GetClientHeight() +{ + RECT rect = { 0 }; + GetClientRect(Window, &rect); + return rect.bottom - rect.top; +} IVideo *gl_CreateVideo() { diff --git a/src/win32/win32gliface.h b/src/win32/win32gliface.h index 4ef48ce18b..00e6cba819 100644 --- a/src/win32/win32gliface.h +++ b/src/win32/win32gliface.h @@ -118,6 +118,8 @@ public: void SwapBuffers(); void NewRefreshRate (); + int GetClientWidth(); + int GetClientHeight(); int GetTrueHeight() { return static_cast(Video)->GetTrueHeight(); } @@ -136,6 +138,7 @@ public: protected: bool CanUpdate(); + void ResetGammaTable(); void SetGammaTable(WORD * tbl); float m_Gamma, m_Brightness, m_Contrast; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index b8abd71ec0..30b0f542fd 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2281,6 +2281,7 @@ OPTVAL_SINC = "Sinc"; OPTVAL_NOTEONOFFONLY = "Note on/off only"; OPTVAL_FULLRAMPING = "Full ramping"; OPTVAL_ALLUNACKNOWLEDGED = "All unacknowledged"; +OPTVAL_FULLSCREENONLY = "Fullscreen only"; // Colors C_BRICK = "\cabrick"; C_TAN = "\cbtan"; @@ -2562,6 +2563,7 @@ MUSIC_DM2INT = "dm2int"; DSPLYMNU_GLOPT = "OpenGL Options"; DSPLYMNU_GAMMA = "Gamma correction"; DSPLYMNU_CONTRAST ="Contrast"; +DSPLYMNU_HWGAMMA = "Hardware Gamma"; // OpenGL Options GLMNU_TITLE = "OPENGL OPTIONS"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 209d8267c2..6a584d2927 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -670,6 +670,7 @@ OptionMenu "VideoOptions" Slider "$DSPLYMNU_GAMMA", "Gamma", 0.75, 3.0, 0.05, 2 Slider "$DSPLYMNU_BRIGHTNESS", "vid_brightness", -0.8,0.8, 0.05 Slider "$DSPLYMNU_CONTRAST", "vid_contrast", 0.1, 3.0, 0.1 + Option "$DSPLYMNU_HWGAMMA", "vid_hwgamma", "HWGammaModes" Option "$DSPLYMNU_VSYNC", "vid_vsync", "OnOff" Option "$DSPLYMNU_CAPFPS", "cl_capfps", "OffOn" diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index 59cb94f73e..e96f6b55c3 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -25,6 +25,13 @@ OptionValue "FilterModes" 4, "$OPTVAL_TRILINEAR" } +OptionValue "HWGammaModes" +{ + 0, "$OPTVAL_ON" + 1, "$OPTVAL_OFF" + 2, "$OPTVAL_FULLSCREENONLY" +} + OptionValue "TextureFormats" { 0, "$OPTVAL_RGBA8" diff --git a/wadsrc/static/shaders/glsl/present.fp b/wadsrc/static/shaders/glsl/present.fp new file mode 100644 index 0000000000..93534ba7f7 --- /dev/null +++ b/wadsrc/static/shaders/glsl/present.fp @@ -0,0 +1,23 @@ + +#version 330 + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D InputTexture; +uniform float Gamma; +uniform float Contrast; +uniform float Brightness; + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val = pow(val, vec3(1.0 / Gamma)); + val += Brightness * 0.5; + return vec4(val, c.a); +} + +void main() +{ + FragColor = ApplyGamma(texture(InputTexture, TexCoord)); +} diff --git a/wadsrc/static/shaders/glsl/present.vp b/wadsrc/static/shaders/glsl/present.vp new file mode 100644 index 0000000000..b73fe7fc81 --- /dev/null +++ b/wadsrc/static/shaders/glsl/present.vp @@ -0,0 +1,11 @@ + +#version 330 + +in vec4 PositionInProjection; +out vec2 TexCoord; + +void main() +{ + gl_Position = PositionInProjection; + TexCoord = PositionInProjection.xy * 0.5 + 0.5; +}