From 6b9529d70f52879ffb885fcad05789eb83cce162 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 2 Aug 2016 17:32:21 +0200 Subject: [PATCH 01/53] Added lens distortion shader --- src/CMakeLists.txt | 1 + src/gl/renderer/gl_postprocess.cpp | 73 ++++++++++++++++++++ src/gl/renderer/gl_renderbuffers.cpp | 4 +- src/gl/renderer/gl_renderer.cpp | 3 + src/gl/renderer/gl_renderer.h | 3 + src/gl/scene/gl_scene.cpp | 1 + src/gl/shaders/gl_lensshader.cpp | 66 ++++++++++++++++++ src/gl/shaders/gl_lensshader.h | 19 +++++ src/gl/system/gl_cvars.h | 4 ++ wadsrc/static/shaders/glsl/lensdistortion.fp | 55 +++++++++++++++ wadsrc/static/shaders/glsl/lensdistortion.vp | 9 +++ 11 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 src/gl/shaders/gl_lensshader.cpp create mode 100644 src/gl/shaders/gl_lensshader.h create mode 100644 wadsrc/static/shaders/glsl/lensdistortion.fp create mode 100644 wadsrc/static/shaders/glsl/lensdistortion.vp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d3d339e0f..5317c277a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1110,6 +1110,7 @@ set( FASTMATH_SOURCES gl/shaders/gl_bloomshader.cpp gl/shaders/gl_blurshader.cpp gl/shaders/gl_tonemapshader.cpp + gl/shaders/gl_lensshader.cpp gl/system/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_menu.cpp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index a8e5867c9..373f7c635 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -68,6 +68,7 @@ #include "gl/shaders/gl_bloomshader.h" #include "gl/shaders/gl_blurshader.h" #include "gl/shaders/gl_tonemapshader.h" +#include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_presentshader.h" //========================================================================== @@ -95,6 +96,12 @@ CUSTOM_CVAR(Int, gl_bloom_kernel_size, 7, 0) self = 7; } +CVAR(Bool, gl_lens, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + +CVAR(Float, gl_lens_k, -0.15f, 0) +CVAR(Float, gl_lens_kcube, 0.15f, 0) +CVAR(Float, gl_lens_chromatic, 1.2f, 0) + EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) @@ -260,6 +267,70 @@ void FGLRenderer::TonemapScene() glActiveTexture(activeTex); } +//----------------------------------------------------------------------------- +// +// Apply lens distortion and place the result in the HUD/2D texture +// +//----------------------------------------------------------------------------- + +void FGLRenderer::LensDistortScene() +{ + if (gl_lens == 0) + return; + + GLint activeTex, textureBinding, samplerBinding; + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); + glActiveTexture(GL_TEXTURE0); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + if (gl.flags & RFL_SAMPLER_OBJECTS) + { + glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding); + glBindSampler(0, 0); + } + + GLboolean blendEnabled, scissorEnabled; + glGetBooleanv(GL_BLEND, &blendEnabled); + glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); + + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + + float k[4] = + { + gl_lens_k, + gl_lens_k * gl_lens_chromatic, + gl_lens_k * gl_lens_chromatic * gl_lens_chromatic, + 0.0f + }; + float kcube[4] = + { + gl_lens_kcube, + gl_lens_kcube * gl_lens_chromatic, + gl_lens_kcube * gl_lens_chromatic * gl_lens_chromatic, + 0.0f + }; + + mBuffers->BindHudFB(); + mBuffers->BindSceneTexture(0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + mLensShader->Bind(); + mLensShader->InputTexture.Set(0); + mLensShader->LensDistortionCoefficient.Set(k); + mLensShader->CubicDistortionValue.Set(kcube); + mVBO->BindVBO(); + mVBO->RenderScreenQuad(); + + if (blendEnabled) + glEnable(GL_BLEND); + if (scissorEnabled) + glEnable(GL_SCISSOR_TEST); + glBindTexture(GL_TEXTURE_2D, textureBinding); + if (gl.flags & RFL_SAMPLER_OBJECTS) + glBindSampler(0, samplerBinding); + glActiveTexture(activeTex); +} + //----------------------------------------------------------------------------- // // Gamma correct while copying to frame buffer @@ -357,6 +428,8 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) mPresentShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); } mBuffers->BindHudTexture(0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mVBO->BindVBO(); mVBO->RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index a65626007..d9a8823cd 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -432,7 +432,7 @@ void FGLRenderBuffers::BindSceneTextureFB() void FGLRenderBuffers::BindHudFB() { - if (gl_tonemap != 0) + if (gl_tonemap != 0 || gl_lens) glBindFramebuffer(GL_FRAMEBUFFER, mHudFB); else glBindFramebuffer(GL_FRAMEBUFFER, mSceneTextureFB); @@ -470,7 +470,7 @@ void FGLRenderBuffers::BindSceneTexture(int index) void FGLRenderBuffers::BindHudTexture(int index) { glActiveTexture(GL_TEXTURE0 + index); - if (gl_tonemap != 0) + if (gl_tonemap != 0 || gl_lens) glBindTexture(GL_TEXTURE_2D, mHudTexture); else glBindTexture(GL_TEXTURE_2D, mSceneTexture); diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index d2a0cb959..5fa52ec6b 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -65,6 +65,7 @@ #include "gl/shaders/gl_bloomshader.h" #include "gl/shaders/gl_blurshader.h" #include "gl/shaders/gl_tonemapshader.h" +#include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_presentshader.h" #include "gl/textures/gl_texture.h" #include "gl/textures/gl_translate.h" @@ -117,6 +118,7 @@ void FGLRenderer::Initialize() mBloomCombineShader = new FBloomCombineShader(); mBlurShader = new FBlurShader(); mTonemapShader = new FTonemapShader(); + mLensShader = new FLensShader(); mPresentShader = new FPresentShader(); // Only needed for the core profile, because someone decided it was a good idea to remove the default VAO. @@ -171,6 +173,7 @@ FGLRenderer::~FGLRenderer() if (mBloomCombineShader) delete mBloomCombineShader; if (mBlurShader) delete mBlurShader; if (mTonemapShader) delete mTonemapShader; + if (mLensShader) delete mLensShader; } //========================================================================== diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 78eac4cbf..9be66bbfb 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -23,6 +23,7 @@ class FBloomExtractShader; class FBloomCombineShader; class FBlurShader; class FTonemapShader; +class FLensShader; class FPresentShader; inline float DEG2RAD(float deg) @@ -90,6 +91,7 @@ public: FBloomCombineShader *mBloomCombineShader; FBlurShader *mBlurShader; FTonemapShader *mTonemapShader; + FLensShader *mLensShader; FPresentShader *mPresentShader; FTexture *gllight; @@ -160,6 +162,7 @@ public: void EndDrawScene(sector_t * viewsector); void BloomScene(); void TonemapScene(); + void LensDistortScene(); void CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma); void Flush() { CopyToBackbuffer(nullptr, true); } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 87197d09d..16bb6cd34 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -864,6 +864,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture(); BloomScene(); TonemapScene(); + LensDistortScene(); } mDrawingScene2D = false; eye->TearDown(); diff --git a/src/gl/shaders/gl_lensshader.cpp b/src/gl/shaders/gl_lensshader.cpp new file mode 100644 index 000000000..9181d260d --- /dev/null +++ b/src/gl/shaders/gl_lensshader.cpp @@ -0,0 +1,66 @@ +/* +** gl_lensshader.cpp +** Lens distortion with chromatic aberration shader +** +**--------------------------------------------------------------------------- +** Copyright 2016 Magnus Norddahl +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 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_lensshader.h" + +void FLensShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/lensdistortion.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/lensdistortion.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/lensdistortion"); + mShader.SetAttribLocation(0, "PositionInProjection"); + InputTexture.Init(mShader, "InputTexture"); + LensDistortionCoefficient.Init(mShader, "k"); + CubicDistortionValue.Init(mShader, "kcube"); + } + mShader.Bind(); +} diff --git a/src/gl/shaders/gl_lensshader.h b/src/gl/shaders/gl_lensshader.h new file mode 100644 index 000000000..a83532161 --- /dev/null +++ b/src/gl/shaders/gl_lensshader.h @@ -0,0 +1,19 @@ +#ifndef __GL_LENSSHADER_H +#define __GL_LENSSHADER_H + +#include "gl_shaderprogram.h" + +class FLensShader +{ +public: + void Bind(); + + FBufferedUniform1i InputTexture; + FBufferedUniform4f LensDistortionCoefficient; + FBufferedUniform4f CubicDistortionValue; + +private: + FShaderProgram mShader; +}; + +#endif \ No newline at end of file diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 30f4cc4f3..4b28bb667 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -49,5 +49,9 @@ EXTERN_CVAR(Float, gl_bloom_amount) EXTERN_CVAR(Int, gl_bloom_kernel_size) EXTERN_CVAR(Int, gl_tonemap) EXTERN_CVAR(Float, gl_exposure) +EXTERN_CVAR(Bool, gl_lens) +EXTERN_CVAR(Float, gl_lens_k) +EXTERN_CVAR(Float, gl_lens_kcube) +EXTERN_CVAR(Float, gl_lens_chromatic) #endif // _GL_INTERN_H diff --git a/wadsrc/static/shaders/glsl/lensdistortion.fp b/wadsrc/static/shaders/glsl/lensdistortion.fp new file mode 100644 index 000000000..9d6fd1a26 --- /dev/null +++ b/wadsrc/static/shaders/glsl/lensdistortion.fp @@ -0,0 +1,55 @@ +/* + Original Lens Distortion Algorithm from SSontech + http://www.ssontech.com/content/lensalg.htm + + If (u,v) are the coordinates of a feature in the undistorted perfect + image plane, then (u', v') are the coordinates of the feature on the + distorted image plate, ie the scanned or captured image from the + camera. The distortion occurs radially away from the image center, + with correction for the image aspect ratio (image_aspect = physical + image width/height), as follows: + + r2 = image_aspect*image_aspect*u*u + v*v + f = 1 + r2*(k + kcube*sqrt(r2)) + u' = f*u + v' = f*v + + The constant k is the distortion coefficient that appears on the lens + panel and through Sizzle. It is generally a small positive or negative + number under 1%. The constant kcube is the cubic distortion value found + on the image preprocessor's lens panel: it can be used to undistort or + redistort images, but it does not affect or get computed by the solver. + When no cubic distortion is needed, neither is the square root, saving + time. + + Chromatic Aberration example, + using red distord channel with green and blue undistord channel: + + k = vec3(-0.15, 0.0, 0.0); + kcube = vec3(0.15, 0.0, 0.0); +*/ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D InputTexture; +uniform vec4 k; // lens distortion coefficient +uniform vec4 kcube; // cubic distortion value + +void main() +{ + vec2 position = TexCoord - vec2(0.5); + + float r2 = dot(position, position); + vec3 f = vec3(1.0) + r2 * (k.rgb + kcube.rgb * sqrt(r2)); + + vec3 x = f * position.x + 0.5; + vec3 y = f * position.y + 0.5; + + vec3 c; + c.r = texture(InputTexture, vec2(x.r, y.r)).r; + c.g = texture(InputTexture, vec2(x.g, y.g)).g; + c.b = texture(InputTexture, vec2(x.b, y.b)).b; + + FragColor = vec4(c, 1.0); +} diff --git a/wadsrc/static/shaders/glsl/lensdistortion.vp b/wadsrc/static/shaders/glsl/lensdistortion.vp new file mode 100644 index 000000000..5990669a5 --- /dev/null +++ b/wadsrc/static/shaders/glsl/lensdistortion.vp @@ -0,0 +1,9 @@ + +in vec4 PositionInProjection; +out vec2 TexCoord; + +void main() +{ + gl_Position = PositionInProjection; + TexCoord = PositionInProjection.xy * 0.5 + 0.5; +} From 95c346497371395b401be2c9e4e37c8eaa3c8c60 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 3 Aug 2016 12:17:22 +0200 Subject: [PATCH 02/53] - properly handle 3D floors with inverted planes in the list sorter. --- src/p_3dfloors.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 5e2117b9b..d27ebe4d1 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -514,6 +514,17 @@ void P_Recalculate3DFloors(sector_t * sector) clipped_bottom = pick_bottom; } } + else if (pick_bottom > height) // do not allow inverted planes + { + F3DFloor * dyn = new F3DFloor; + *dyn = *pick; + pick->flags |= FF_CLIPPED; + pick->flags &= ~FF_EXISTS; + dyn->flags |= FF_DYNAMIC; + dyn->bottom.copyPlane(&pick->top); + ffloors.Push(pick); + ffloors.Push(dyn); + } else { clipped = pick; From c1a4dd74c46bad62a8ba7aca7f45b8267edeb2f2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 3 Aug 2016 12:59:40 +0200 Subject: [PATCH 03/53] - added handling for Eternity's 'gap' parameter to: Ceiling_LowerToFloor Ceiling_LowerToHighestFloor Ceiling_ToFloorInstant Floor_RaiseToCeiling Floor_RaiseToLowestCeiling Floor_ToCeilingInstant --- src/actionspecials.h | 12 ++++++------ src/p_ceiling.cpp | 6 +++--- src/p_floor.cpp | 6 +++--- src/p_lnspec.cpp | 22 +++++++++++----------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 6d9d2feb8..4ab222b2c 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -176,7 +176,7 @@ DEFINE_SPECIAL(Sector_SetCeilingScale, 188, 5, 5, 5) DEFINE_SPECIAL(Sector_SetFloorScale, 189, 5, 5, 5) DEFINE_SPECIAL(Static_Init, 190, -1, -1, 4) DEFINE_SPECIAL(SetPlayerProperty, 191, 3, 3, 3) -DEFINE_SPECIAL(Ceiling_LowerToHighestFloor, 192, 2, 4, 4) +DEFINE_SPECIAL(Ceiling_LowerToHighestFloor, 192, 2, 4, 5) DEFINE_SPECIAL(Ceiling_LowerInstant, 193, 3, 5, 5) DEFINE_SPECIAL(Ceiling_RaiseInstant, 194, 3, 4, 4) DEFINE_SPECIAL(Ceiling_CrushRaiseAndStayA, 195, 4, 5, 5) @@ -222,7 +222,7 @@ DEFINE_SPECIAL(Light_MaxNeighbor, 234, 1, 1, 1) DEFINE_SPECIAL(Floor_TransferTrigger, 235, 1, 1, 1) DEFINE_SPECIAL(Floor_TransferNumeric, 236, 1, 1, 1) DEFINE_SPECIAL(ChangeCamera, 237, 3, 3, 3) -DEFINE_SPECIAL(Floor_RaiseToLowestCeiling, 238, 2, 4, 4) +DEFINE_SPECIAL(Floor_RaiseToLowestCeiling, 238, 2, 4, 5) DEFINE_SPECIAL(Floor_RaiseByValueTxTy, 239, 3, 3, 3) DEFINE_SPECIAL(Floor_RaiseByTexture, 240, 2, 4, 4) DEFINE_SPECIAL(Floor_LowerToLowestTxTy, 241, 2, 2, 2) @@ -238,21 +238,21 @@ DEFINE_SPECIAL(Floor_Donut, 250, 3, 3, 3) DEFINE_SPECIAL(FloorAndCeiling_LowerRaise, 251, 3, 4, 4) DEFINE_SPECIAL(Ceiling_RaiseToNearest, 252, 2, 3, 3) DEFINE_SPECIAL(Ceiling_LowerToLowest, 253, 2, 4, 4) -DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 4, 4) +DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 4, 5) DEFINE_SPECIAL(Ceiling_CrushRaiseAndStaySilA, 255, 4, 5, 5) DEFINE_SPECIAL(Floor_LowerToHighestEE, 256, 2, 3, 3) DEFINE_SPECIAL(Floor_RaiseToLowest, 257, 1, 3, 3) DEFINE_SPECIAL(Floor_LowerToLowestCeiling, 258, 2, 3, 3) -DEFINE_SPECIAL(Floor_RaiseToCeiling, 259, 2, 4, 4) -DEFINE_SPECIAL(Floor_ToCeilingInstant, 260, 1, 3, 3) +DEFINE_SPECIAL(Floor_RaiseToCeiling, 259, 2, 4, 5) +DEFINE_SPECIAL(Floor_ToCeilingInstant, 260, 1, 3, 4) DEFINE_SPECIAL(Floor_LowerByTexture, 261, 2, 3, 3) DEFINE_SPECIAL(Ceiling_RaiseToHighest, 262, 2, 3, 3) DEFINE_SPECIAL(Ceiling_ToHighestInstant, 263, 1, 3, 3) DEFINE_SPECIAL(Ceiling_LowerToNearest, 264, 2, 4, 4) DEFINE_SPECIAL(Ceiling_RaiseToLowest, 265, 2, 3, 3) DEFINE_SPECIAL(Ceiling_RaiseToHighestFloor, 266, 2, 3, 3) -DEFINE_SPECIAL(Ceiling_ToFloorInstant, 267, 1, 3, 3) +DEFINE_SPECIAL(Ceiling_ToFloorInstant, 267, 1, 3, 4) DEFINE_SPECIAL(Ceiling_RaiseByTexture, 268, 2, 3, 3) DEFINE_SPECIAL(Ceiling_LowerByTexture, 269, 2, 4, 4) DEFINE_SPECIAL(Stairs_BuildDownDoom, 270, 5, 5, 5) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 8a0c8f9ef..c635d9743 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -309,7 +309,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t break; case DCeiling::ceilLowerToHighestFloor: - targheight = sec->FindHighestFloorSurrounding (&spot); + targheight = sec->FindHighestFloorSurrounding (&spot) + height; ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); ceiling->m_Direction = -1; break; @@ -359,13 +359,13 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t break; case DCeiling::ceilLowerToFloor: - targheight = sec->FindHighestFloorPoint (&spot); + targheight = sec->FindHighestFloorPoint (&spot) + height; ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); ceiling->m_Direction = -1; break; case DCeiling::ceilRaiseToFloor: // [RH] What's this for? - targheight = sec->FindHighestFloorPoint (&spot); + targheight = sec->FindHighestFloorPoint (&spot) + height; ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); ceiling->m_Direction = 1; break; diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 3f2b06f95..10bcf6d7e 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -387,13 +387,13 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, case DFloor::floorRaiseToCeiling: floor->m_Direction = 1; - newheight = sec->FindLowestCeilingPoint(&spot); + newheight = sec->FindLowestCeilingPoint(&spot) - height; floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); break; case DFloor::floorLowerToLowestCeiling: floor->m_Direction = -1; - newheight = sec->FindLowestCeilingSurrounding(&spot); + newheight = sec->FindLowestCeilingSurrounding(&spot) - height; floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); break; @@ -406,7 +406,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, case DFloor::floorLowerToCeiling: // [RH] Essentially instantly raises the floor to the ceiling floor->m_Direction = -1; - newheight = sec->FindLowestCeilingPoint(&spot); + newheight = sec->FindLowestCeilingPoint(&spot) - height; floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); break; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 307529636..dc6170c24 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -420,9 +420,9 @@ FUNC(LS_Floor_RaiseInstant) } FUNC(LS_Floor_ToCeilingInstant) -// Floor_ToCeilingInstant (tag, change, crush) +// Floor_ToCeilingInstant (tag, change, crush, gap) { - return EV_DoFloor (DFloor::floorLowerToCeiling, ln, arg0, 0, 0, CRUSH(arg2), CHANGE(arg1), true); + return EV_DoFloor (DFloor::floorLowerToCeiling, ln, arg0, 0, arg3, CRUSH(arg2), CHANGE(arg1), true); } FUNC(LS_Floor_MoveToValueTimes8) @@ -448,7 +448,7 @@ FUNC(LS_Floor_RaiseToLowestCeiling) FUNC(LS_Floor_LowerToLowestCeiling) // Floor_LowerToLowestCeiling (tag, speed, change) { - return EV_DoFloor (DFloor::floorLowerToLowestCeiling, ln, arg0, SPEED(arg1), 0, -1, CHANGE(arg2), true); + return EV_DoFloor (DFloor::floorLowerToLowestCeiling, ln, arg0, SPEED(arg1), arg4, -1, CHANGE(arg2), true); } FUNC(LS_Floor_RaiseByTexture) @@ -464,9 +464,9 @@ FUNC(LS_Floor_LowerByTexture) } FUNC(LS_Floor_RaiseToCeiling) -// Floor_RaiseToCeiling (tag, speed, change, crush) +// Floor_RaiseToCeiling (tag, speed, change, crush, gap) { - return EV_DoFloor (DFloor::floorRaiseToCeiling, ln, arg0, SPEED(arg1), 0, CRUSH(arg3), CHANGE(arg2), true); + return EV_DoFloor (DFloor::floorRaiseToCeiling, ln, arg0, SPEED(arg1), arg4, CRUSH(arg3), CHANGE(arg2), true); } FUNC(LS_Floor_RaiseByValueTxTy) @@ -706,9 +706,9 @@ FUNC(LS_Ceiling_MoveToValue) } FUNC(LS_Ceiling_LowerToHighestFloor) -// Ceiling_LowerToHighestFloor (tag, speed, change, crush) +// Ceiling_LowerToHighestFloor (tag, speed, change, crush, gap) { - return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg2)); + return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, arg4, CRUSH(arg3), 0, CHANGE(arg2)); } FUNC(LS_Ceiling_LowerInstant) @@ -808,15 +808,15 @@ FUNC(LS_Ceiling_ToHighestInstant) } FUNC(LS_Ceiling_ToFloorInstant) -// Ceiling_ToFloorInstant (tag, change, crush) +// Ceiling_ToFloorInstant (tag, change, crush, gap) { - return EV_DoCeiling (DCeiling::ceilRaiseToFloor, ln, arg0, 2, 0, 0, CRUSH(arg2), 0, CHANGE(arg1)); + return EV_DoCeiling (DCeiling::ceilRaiseToFloor, ln, arg0, 2, 0, arg3, CRUSH(arg2), 0, CHANGE(arg1)); } FUNC(LS_Ceiling_LowerToFloor) -// Ceiling_LowerToFloor (tag, speed, change, crush) +// Ceiling_LowerToFloor (tag, speed, change, crush, gap) { - return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg4)); + return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, arg4, CRUSH(arg3), 0, CHANGE(arg4)); } FUNC(LS_Ceiling_LowerByTexture) From 2c38e203525a0c8f158c42a32a6e7673e6dd3de9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 3 Aug 2016 13:16:14 +0200 Subject: [PATCH 04/53] - update xlat/eternity.txt for reference. --- wadsrc/static/xlat/eternity.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index 4db96f2da..90a41a4e8 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -251,3 +251,13 @@ enum 466 = 0, Floor_TransferTrigger(0) 467 = 0, Floor_TransferNumeric(0) 468 = 0, FloorAndCeiling_LowerRaise(0) +469 = 0, HealThing(0) +470 = 0, Sector_SetRotation(0) +471 = 0, Sector_SetFloorPanning(0) +472 = 0, Sector_SetCeilingPanning(0) +473 = 0, Light_MinNeighbor(0) +474 = 0, Polyobj_Stop(0) +475 = 0, Plat_RaiseAndStayTx0(0) +476 = 0, Plat_UpByValueStayTx(0) +477 = 0, ACS_ExecuteAlways(0) +478 = 0, Thing_Remove(0) From 7ba62694502124306c4d9a49b3a60f1de5cbb778 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 4 Aug 2016 12:16:53 +0200 Subject: [PATCH 05/53] - changed rendering of sky cubemaps to use precalculated vertex data from the SkyVertexBuffer. --- src/gl/data/gl_setup.cpp | 2 +- src/gl/data/gl_vertexbuffer.h | 9 ++ src/gl/scene/gl_skydome.cpp | 168 +++++++++++++++------------------- 3 files changed, 86 insertions(+), 93 deletions(-) diff --git a/src/gl/data/gl_setup.cpp b/src/gl/data/gl_setup.cpp index 04ed4c427..f45995d90 100644 --- a/src/gl/data/gl_setup.cpp +++ b/src/gl/data/gl_setup.cpp @@ -322,7 +322,7 @@ static void PrepareTransparentDoors(sector_t * sector) sector_t * nextsec=NULL; #ifdef _DEBUG - if (sector-sectors==2) + if (sector-sectors==34) { int a = 0; } diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index eeb3ace48..f7a48a3e3 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -167,6 +167,10 @@ private: int mRows, mColumns; + // indices for sky cubemap faces + int mFaceStart[7]; + int mSideStart; + void SkyVertex(int r, int c, bool yflip); void CreateSkyHemisphere(int hemi); void CreateDome(); @@ -178,6 +182,11 @@ public: virtual ~FSkyVertexBuffer(); void RenderDome(FMaterial *tex, int mode); void BindVBO(); + int FaceStart(int i) + { + if (i >= 0 && i < 7) return mFaceStart[i]; + else return mSideStart; + } }; diff --git a/src/gl/scene/gl_skydome.cpp b/src/gl/scene/gl_skydome.cpp index 33c73d82c..6e379117a 100644 --- a/src/gl/scene/gl_skydome.cpp +++ b/src/gl/scene/gl_skydome.cpp @@ -215,6 +215,72 @@ void FSkyVertexBuffer::CreateDome() CreateSkyHemisphere(SKYHEMI_UPPER); CreateSkyHemisphere(SKYHEMI_LOWER); mPrimStart.Push(mVertices.Size()); + + mSideStart = mVertices.Size(); + mFaceStart[0] = mSideStart + 10; + mFaceStart[1] = mFaceStart[0] + 4; + mFaceStart[2] = mFaceStart[1] + 4; + mFaceStart[3] = mFaceStart[2] + 4; + mFaceStart[4] = mFaceStart[3] + 4; + mFaceStart[5] = mFaceStart[4] + 4; + mFaceStart[6] = mFaceStart[5] + 4; + mVertices.Reserve(10 + 7*4); + FSkyVertex *ptr = &mVertices[mSideStart]; + + // all sides + ptr[0].Set(128.f, 128.f, -128.f, 0, 0); + ptr[1].Set(128.f, -128.f, -128.f, 0, 1); + ptr[2].Set(-128.f, 128.f, -128.f, 0.25f, 0); + ptr[3].Set(-128.f, -128.f, -128.f, 0.25f, 1); + ptr[4].Set(-128.f, 128.f, 128.f, 0.5f, 0); + ptr[5].Set(-128.f, -128.f, 128.f, 0.5f, 1); + ptr[6].Set(128.f, 128.f, 128.f, 0.75f, 0); + ptr[7].Set(128.f, -128.f, 128.f, 0.75f, 1); + ptr[8].Set(128.f, 128.f, -128.f, 1, 0); + ptr[9].Set(128.f, -128.f, -128.f, 1, 1); + + // north face + ptr[10].Set(128.f, 128.f, -128.f, 0, 0); + ptr[11].Set(-128.f, 128.f, -128.f, 1, 0); + ptr[12].Set(128.f, -128.f, -128.f, 0, 1); + ptr[13].Set(-128.f, -128.f, -128.f, 1, 1); + + // east face + ptr[14].Set(-128.f, 128.f, -128.f, 0, 0); + ptr[15].Set(-128.f, 128.f, 128.f, 1, 0); + ptr[16].Set(-128.f, -128.f, -128.f, 0, 1); + ptr[17].Set(-128.f, -128.f, 128.f, 1, 1); + + // south face + ptr[18].Set(-128.f, 128.f, 128.f, 0, 0); + ptr[19].Set(128.f, 128.f, 128.f, 1, 0); + ptr[20].Set(-128.f, -128.f, 128.f, 0, 1); + ptr[21].Set(128.f, -128.f, 128.f, 1, 1); + + // west face + ptr[22].Set(128.f, 128.f, 128.f, 0, 0); + ptr[23].Set(128.f, 128.f, -128.f, 1, 0); + ptr[24].Set(128.f, -128.f, 128.f, 0, 1); + ptr[25].Set(128.f, -128.f, -128.f, 1, 1); + + // bottom face + ptr[26].Set(128.f, -128.f, -128.f, 0, 0); + ptr[27].Set(-128.f, -128.f, -128.f, 1, 0); + ptr[28].Set(128.f, -128.f, 128.f, 0, 1); + ptr[29].Set(-128.f, -128.f, 128.f, 1, 1); + + // top face + ptr[30].Set(128.f, 128.f, -128.f, 0, 0); + ptr[31].Set(-128.f, 128.f, -128.f, 1, 0); + ptr[32].Set(128.f, 128.f, 128.f, 0, 1); + ptr[33].Set(-128.f, 128.f, 128.f, 1, 1); + + // top face flipped + ptr[34].Set(128.f, 128.f, -128.f, 0, 1); + ptr[35].Set(-128.f, 128.f, -128.f, 1, 1); + ptr[36].Set(128.f, 128.f, 128.f, 0, 0); + ptr[37].Set(-128.f, 128.f, 128.f, 1, 0); + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glBufferData(GL_ARRAY_BUFFER, mVertices.Size() * sizeof(FSkyVertex), &mVertices[0], GL_STATIC_DRAW); } @@ -327,7 +393,6 @@ void RenderDome(FMaterial * tex, float x_offset, float y_offset, bool mirror, in GLRenderer->mSkyVBO->RenderDome(tex, mode); gl_RenderState.EnableTextureMatrix(false); - gl_RenderState.EnableModelMatrix(false); } @@ -351,7 +416,6 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool else gl_RenderState.mModelMatrix.rotate(-180.0f+x_offset, glset.skyrotatevector2.X, glset.skyrotatevector2.Z, glset.skyrotatevector2.Y); - FFlatVertex *ptr; if (sb->faces[5]) { faces=4; @@ -360,65 +424,25 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool tex = FMaterial::ValidateTexture(sb->faces[0], false); gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false); gl_RenderState.Apply(); - - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(128.f, 128.f, -128.f, 0, 0); - ptr++; - ptr->Set(-128.f, 128.f, -128.f, 1, 0); - ptr++; - ptr->Set(128.f, -128.f, -128.f, 0, 1); - ptr++; - ptr->Set(-128.f, -128.f, -128.f, 1, 1); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(0), 4); // east tex = FMaterial::ValidateTexture(sb->faces[1], false); gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false); gl_RenderState.Apply(); - - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(-128.f, 128.f, -128.f, 0, 0); - ptr++; - ptr->Set(-128.f, 128.f, 128.f, 1, 0); - ptr++; - ptr->Set(-128.f, -128.f, -128.f, 0, 1); - ptr++; - ptr->Set(-128.f, -128.f, 128.f, 1, 1); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(1), 4); // south tex = FMaterial::ValidateTexture(sb->faces[2], false); gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false); gl_RenderState.Apply(); - - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(-128.f, 128.f, 128.f, 0, 0); - ptr++; - ptr->Set(128.f, 128.f, 128.f, 1, 0); - ptr++; - ptr->Set(-128.f, -128.f, 128.f, 0, 1); - ptr++; - ptr->Set(128.f, -128.f, 128.f, 1, 1); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(2), 4); // west tex = FMaterial::ValidateTexture(sb->faces[3], false); gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false); gl_RenderState.Apply(); - - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(128.f, 128.f, 128.f, 0, 0); - ptr++; - ptr->Set(128.f, 128.f, -128.f, 1, 0); - ptr++; - ptr->Set(128.f, -128.f, 128.f, 0, 1); - ptr++; - ptr->Set(128.f, -128.f, -128.f, 1, 1); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(3), 4); } else { @@ -426,62 +450,21 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool tex = FMaterial::ValidateTexture(sb->faces[0], false); gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false); gl_RenderState.Apply(); - - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(128.f, 128.f, -128.f, 0, 0); - ptr++; - ptr->Set(128.f, -128.f, -128.f, 0, 1); - ptr++; - ptr->Set(-128.f, 128.f, -128.f, 0.25f, 0); - ptr++; - ptr->Set(-128.f, -128.f, -128.f, 0.25f, 1); - ptr++; - ptr->Set(-128.f, 128.f, 128.f, 0.5f, 0); - ptr++; - ptr->Set(-128.f, -128.f, 128.f, 0.5f, 1); - ptr++; - ptr->Set(128.f, 128.f, 128.f, 0.75f, 0); - ptr++; - ptr->Set(128.f, -128.f, 128.f, 0.75f, 1); - ptr++; - ptr->Set(128.f, 128.f, -128.f, 1, 0); - ptr++; - ptr->Set(128.f, -128.f, -128.f, 1, 1); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(-1), 10); } // top tex = FMaterial::ValidateTexture(sb->faces[faces], false); gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false); gl_RenderState.Apply(); - - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(128.f, 128.f, -128.f, 0, sb->fliptop); - ptr++; - ptr->Set(-128.f, 128.f, -128.f, 1, sb->fliptop); - ptr++; - ptr->Set(128.f, 128.f, 128.f, 0, !sb->fliptop); - ptr++; - ptr->Set(-128.f, 128.f, 128.f, 1, !sb->fliptop); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(sb->fliptop? 6:5), 4); // bottom tex = FMaterial::ValidateTexture(sb->faces[faces+1], false); gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false); gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(4), 4); - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(128.f, -128.f, -128.f, 0, 0); - ptr++; - ptr->Set(-128.f, -128.f, -128.f, 1, 0); - ptr++; - ptr->Set(128.f, -128.f, 128.f, 0, 1); - ptr++; - ptr->Set(-128.f, -128.f, 128.f, 1, 1); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); gl_RenderState.EnableModelMatrix(false); } @@ -512,13 +495,13 @@ void GLSkyPortal::DrawContents() gl_MatrixStack.Push(gl_RenderState.mViewMatrix); GLRenderer->SetupView(0, 0, 0, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); + gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO); if (origin->texture[0] && origin->texture[0]->tex->gl_info.bSkybox) { RenderBox(origin->skytexno1, origin->texture[0], origin->x_offset[0], origin->sky2); } else { - gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO); if (origin->texture[0]==origin->texture[1] && origin->doublesky) origin->doublesky=false; if (origin->texture[0]) @@ -547,11 +530,12 @@ void GLSkyPortal::DrawContents() gl_RenderState.EnableTexture(true); gl_RenderState.SetObjectColor(0xffffffff); } - gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); } + gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); gl_MatrixStack.Pop(gl_RenderState.mViewMatrix); gl_RenderState.ApplyMatrices(); glset.lightmode = oldlightmode; gl_RenderState.SetDepthClamp(oldClamp); + gl_RenderState.EnableModelMatrix(false); } From 63ad7d99d1d4ce7d0db48ed707e6542d50b0fcf6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 4 Aug 2016 12:55:21 +0200 Subject: [PATCH 06/53] - fixed: The dynamic light buffer's behavior needs to obey the gl.lightmethod variable, and not depend on presence of persistently mapped buffers. Since there is a command line switch to revert to the lower behavior it can well be that they do not match. --- src/gl/dynlights/gl_lightbuffer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gl/dynlights/gl_lightbuffer.cpp b/src/gl/dynlights/gl_lightbuffer.cpp index 4fd3b985a..604b6f9a2 100644 --- a/src/gl/dynlights/gl_lightbuffer.cpp +++ b/src/gl/dynlights/gl_lightbuffer.cpp @@ -71,7 +71,7 @@ FLightBuffer::FLightBuffer() glGenBuffers(1, &mBufferId); glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, mBufferId); glBindBuffer(mBufferType, mBufferId); // Note: Some older AMD drivers don't do that in glBindBufferBase, as they should. - if (gl.flags & RFL_BUFFER_STORAGE) + if (gl.lightmethod == LM_DIRECT) { glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); @@ -151,7 +151,7 @@ int FLightBuffer::UploadLights(FDynLightData &data) // create the new buffer's storage (twice as large as the old one) mBufferSize *= 2; mByteSize *= 2; - if (gl.flags & RFL_BUFFER_STORAGE) + if (gl.lightmethod == LM_DIRECT) { glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); @@ -190,7 +190,7 @@ int FLightBuffer::UploadLights(FDynLightData &data) void FLightBuffer::Begin() { - if (!(gl.flags & RFL_BUFFER_STORAGE)) + if (gl.lightmethod == LM_DEFERRED) { glBindBuffer(mBufferType, mBufferId); mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT); @@ -199,7 +199,7 @@ void FLightBuffer::Begin() void FLightBuffer::Finish() { - if (!(gl.flags & RFL_BUFFER_STORAGE)) + if (gl.lightmethod == LM_DEFERRED) { glBindBuffer(mBufferType, mBufferId); glUnmapBuffer(mBufferType); From 21536781a93688b40556c5f3a29d70d8026fc843 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 4 Aug 2016 13:01:42 +0200 Subject: [PATCH 07/53] - forgot to save this. --- src/gl/scene/gl_walls_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index 20d170977..67f40dd6d 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -387,7 +387,7 @@ void GLWall::RenderTranslucentWall() { if (gltexture) { - if (gl_fixedcolormap == CM_DEFAULT && gl_lights && (gl.flags & RFL_BUFFER_STORAGE)) + if (gl_fixedcolormap == CM_DEFAULT && gl_lights && gl.lightmethod == LM_DIRECT) { SetupLights(); } From 6fc7596d52710a0c92338806e2777cbd4e49f592 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 4 Aug 2016 15:47:15 +0200 Subject: [PATCH 08/53] Fix aspect ratio and texture clipping in lens shader --- src/gl/renderer/gl_postprocess.cpp | 18 +++++++++++++++--- src/gl/shaders/gl_lensshader.cpp | 2 ++ src/gl/shaders/gl_lensshader.h | 2 ++ wadsrc/static/shaders/glsl/lensdistortion.fp | 15 +++++++++------ 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 373f7c635..b934720b3 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -98,9 +98,9 @@ CUSTOM_CVAR(Int, gl_bloom_kernel_size, 7, 0) CVAR(Bool, gl_lens, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Float, gl_lens_k, -0.15f, 0) -CVAR(Float, gl_lens_kcube, 0.15f, 0) -CVAR(Float, gl_lens_chromatic, 1.2f, 0) +CVAR(Float, gl_lens_k, -0.12f, 0) +CVAR(Float, gl_lens_kcube, 0.1f, 0) +CVAR(Float, gl_lens_chromatic, 1.12f, 0) EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) @@ -310,12 +310,24 @@ void FGLRenderer::LensDistortScene() 0.0f }; + float aspect = mOutputViewport.width / mOutputViewport.height; + + // Scale factor to keep sampling within the input texture + float r2 = aspect * aspect * 0.25 + 0.25f; + float sqrt_r2 = sqrt(r2); + float f0 = 1.0f + MAX(r2 * (k[0] + kcube[0] * sqrt_r2), 0.0f); + float f2 = 1.0f + MAX(r2 * (k[2] + kcube[2] * sqrt_r2), 0.0f); + float f = MAX(f0, f2); + float scale = 1.0f / f; + mBuffers->BindHudFB(); mBuffers->BindSceneTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mLensShader->Bind(); mLensShader->InputTexture.Set(0); + mLensShader->AspectRatio.Set(aspect); + mLensShader->Scale.Set(scale); mLensShader->LensDistortionCoefficient.Set(k); mLensShader->CubicDistortionValue.Set(kcube); mVBO->BindVBO(); diff --git a/src/gl/shaders/gl_lensshader.cpp b/src/gl/shaders/gl_lensshader.cpp index 9181d260d..39f5042e7 100644 --- a/src/gl/shaders/gl_lensshader.cpp +++ b/src/gl/shaders/gl_lensshader.cpp @@ -59,6 +59,8 @@ void FLensShader::Bind() mShader.Link("shaders/glsl/lensdistortion"); mShader.SetAttribLocation(0, "PositionInProjection"); InputTexture.Init(mShader, "InputTexture"); + AspectRatio.Init(mShader, "Aspect"); + Scale.Init(mShader, "Scale"); LensDistortionCoefficient.Init(mShader, "k"); CubicDistortionValue.Init(mShader, "kcube"); } diff --git a/src/gl/shaders/gl_lensshader.h b/src/gl/shaders/gl_lensshader.h index a83532161..ef0810e4e 100644 --- a/src/gl/shaders/gl_lensshader.h +++ b/src/gl/shaders/gl_lensshader.h @@ -9,6 +9,8 @@ public: void Bind(); FBufferedUniform1i InputTexture; + FBufferedUniform1f AspectRatio; + FBufferedUniform1f Scale; FBufferedUniform4f LensDistortionCoefficient; FBufferedUniform4f CubicDistortionValue; diff --git a/wadsrc/static/shaders/glsl/lensdistortion.fp b/wadsrc/static/shaders/glsl/lensdistortion.fp index 9d6fd1a26..7facf5a80 100644 --- a/wadsrc/static/shaders/glsl/lensdistortion.fp +++ b/wadsrc/static/shaders/glsl/lensdistortion.fp @@ -33,18 +33,21 @@ in vec2 TexCoord; out vec4 FragColor; uniform sampler2D InputTexture; -uniform vec4 k; // lens distortion coefficient -uniform vec4 kcube; // cubic distortion value +uniform float Aspect; // image width/height +uniform float Scale; // 1/max(f) +uniform vec4 k; // lens distortion coefficient +uniform vec4 kcube; // cubic distortion value void main() { - vec2 position = TexCoord - vec2(0.5); + vec2 position = (TexCoord - vec2(0.5)); - float r2 = dot(position, position); + vec2 p = vec2(position.x * Aspect, position.y); + float r2 = dot(p, p); vec3 f = vec3(1.0) + r2 * (k.rgb + kcube.rgb * sqrt(r2)); - vec3 x = f * position.x + 0.5; - vec3 y = f * position.y + 0.5; + vec3 x = f * position.x * Scale + 0.5; + vec3 y = f * position.y * Scale + 0.5; vec3 c; c.r = texture(InputTexture, vec2(x.r, y.r)).r; From 1d434add503894c63f3e8bf1496d591b09854fb0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 4 Aug 2016 17:14:31 +0200 Subject: [PATCH 09/53] - fixed: monsters which were made friendly by the MBF map flag lost their friendliness when being revived with Thing_Raise. --- src/p_mobj.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 94df4c3bf..8971efe25 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6404,6 +6404,7 @@ void AActor::Revive() flags5 = info->flags5; flags6 = info->flags6; flags7 = info->flags7; + if (SpawnFlags & MTF_FRIENDLY) flags |= MF_FRIENDLY; DamageType = info->DamageType; health = SpawnHealth(); target = NULL; From 976a78429e174ebfbc218546763467b5a23d2fb2 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 4 Aug 2016 17:16:49 +0200 Subject: [PATCH 10/53] Simplify post process buffer handling --- src/gl/renderer/gl_postprocess.cpp | 16 ++-- src/gl/renderer/gl_renderbuffers.cpp | 106 +++++++++++++-------------- src/gl/renderer/gl_renderbuffers.h | 31 +++++--- src/gl/renderer/gl_renderer.cpp | 2 +- src/gl/system/gl_wipe.cpp | 6 +- 5 files changed, 85 insertions(+), 76 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index b934720b3..155321de4 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -150,7 +150,7 @@ void FGLRenderer::BloomScene() // Extract blooming pixels from scene texture: glBindFramebuffer(GL_FRAMEBUFFER, level0.VFramebuffer); glViewport(0, 0, level0.Width, level0.Height); - mBuffers->BindSceneTexture(0); + mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mBloomExtractShader->Bind(); @@ -195,7 +195,7 @@ void FGLRenderer::BloomScene() mBlurShader->BlurVertical(mVBO, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height); // Add bloom back to scene texture: - mBuffers->BindSceneTextureFB(); + mBuffers->BindCurrentFB(); glViewport(mOutputViewport.left, mOutputViewport.top, mOutputViewport.width, mOutputViewport.height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); @@ -249,13 +249,14 @@ void FGLRenderer::TonemapScene() glDisable(GL_BLEND); glDisable(GL_SCISSOR_TEST); - mBuffers->BindHudFB(); - mBuffers->BindSceneTexture(0); + mBuffers->BindNextFB(); + mBuffers->BindCurrentTexture(0); mTonemapShader->Bind(); mTonemapShader->SceneTexture.Set(0); mTonemapShader->Exposure.Set(mCameraExposure); mVBO->BindVBO(); mVBO->RenderScreenQuad(); + mBuffers->NextTexture(); if (blendEnabled) glEnable(GL_BLEND); @@ -320,8 +321,8 @@ void FGLRenderer::LensDistortScene() float f = MAX(f0, f2); float scale = 1.0f / f; - mBuffers->BindHudFB(); - mBuffers->BindSceneTexture(0); + mBuffers->BindNextFB(); + mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mLensShader->Bind(); @@ -332,6 +333,7 @@ void FGLRenderer::LensDistortScene() mLensShader->CubicDistortionValue.Set(kcube); mVBO->BindVBO(); mVBO->RenderScreenQuad(); + mBuffers->NextTexture(); if (blendEnabled) glEnable(GL_BLEND); @@ -439,7 +441,7 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) mPresentShader->Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); mPresentShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); } - mBuffers->BindHudTexture(0); + mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mVBO->BindVBO(); diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index d9a8823cd..490d73ed0 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -76,25 +76,26 @@ FGLRenderBuffers::FGLRenderBuffers() FGLRenderBuffers::~FGLRenderBuffers() { ClearScene(); - ClearHud(); + ClearPipeline(); ClearBloom(); } void FGLRenderBuffers::ClearScene() { DeleteFrameBuffer(mSceneFB); - DeleteFrameBuffer(mSceneTextureFB); DeleteRenderBuffer(mSceneMultisample); DeleteRenderBuffer(mSceneDepthStencil); DeleteRenderBuffer(mSceneDepth); DeleteRenderBuffer(mSceneStencil); - DeleteTexture(mSceneTexture); } -void FGLRenderBuffers::ClearHud() +void FGLRenderBuffers::ClearPipeline() { - DeleteFrameBuffer(mHudFB); - DeleteTexture(mHudTexture); + for (int i = 0; i < NumPipelineTextures; i++) + { + DeleteFrameBuffer(mPipelineFB[i]); + DeleteTexture(mPipelineTexture[i]); + } } void FGLRenderBuffers::ClearBloom() @@ -149,8 +150,8 @@ void FGLRenderBuffers::Setup(int width, int height) } else if (width > mWidth || height > mHeight) { + CreatePipeline(width, height); CreateScene(width, height, samples); - CreateHud(width, height); CreateBloom(width, height); mWidth = width; mHeight = height; @@ -173,9 +174,6 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples) { ClearScene(); - mSceneTexture = Create2DTexture(GetHdrFormat(), width, height); - mSceneTextureFB = CreateFrameBuffer(mSceneTexture); - if (samples > 1) mSceneMultisample = CreateRenderBuffer(GetHdrFormat(), samples, width, height); @@ -183,26 +181,30 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples) { mSceneDepth = CreateRenderBuffer(GL_DEPTH_COMPONENT24, samples, width, height); mSceneStencil = CreateRenderBuffer(GL_STENCIL_INDEX8, samples, width, height); - mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mSceneTexture, mSceneDepth, mSceneStencil, samples > 1); + mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepth, mSceneStencil, samples > 1); } else { mSceneDepthStencil = CreateRenderBuffer(GL_DEPTH24_STENCIL8, samples, width, height); - mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mSceneTexture, mSceneDepthStencil, samples > 1); + mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1); } } //========================================================================== // -// Creates the post-tonemapping-step buffers +// Creates the buffers needed for post processing steps // //========================================================================== -void FGLRenderBuffers::CreateHud(int width, int height) +void FGLRenderBuffers::CreatePipeline(int width, int height) { - ClearHud(); - mHudTexture = Create2DTexture(GetHdrFormat(), width, height); - mHudFB = CreateFrameBuffer(mHudTexture); + ClearPipeline(); + + for (int i = 0; i < NumPipelineTextures; i++) + { + mPipelineTexture[i] = Create2DTexture(GetHdrFormat(), width, height); + mPipelineFB[i] = CreateFrameBuffer(mPipelineTexture[i]); + } } //========================================================================== @@ -392,11 +394,13 @@ void FGLRenderBuffers::CheckFrameBufferCompleteness() void FGLRenderBuffers::BlitSceneToTexture() { + mCurrentPipelineTexture = 0; + if (mSamples <= 1) return; glBindFramebuffer(GL_READ_FRAMEBUFFER, mSceneFB); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mSceneTextureFB); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture]); glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); @@ -415,27 +419,48 @@ void FGLRenderBuffers::BindSceneFB() //========================================================================== // -// Makes the scene texture frame buffer active (final 2D texture only) +// Binds the current scene/effect/hud texture to the specified texture unit // //========================================================================== -void FGLRenderBuffers::BindSceneTextureFB() +void FGLRenderBuffers::BindCurrentTexture(int index) { - glBindFramebuffer(GL_FRAMEBUFFER, mSceneTextureFB); + glActiveTexture(GL_TEXTURE0 + index); + glBindTexture(GL_TEXTURE_2D, mPipelineFB[mCurrentPipelineTexture]); } //========================================================================== // -// Makes the 2D/HUD frame buffer active +// Makes the frame buffer for the current texture active // //========================================================================== -void FGLRenderBuffers::BindHudFB() +void FGLRenderBuffers::BindCurrentFB() { - if (gl_tonemap != 0 || gl_lens) - glBindFramebuffer(GL_FRAMEBUFFER, mHudFB); - else - glBindFramebuffer(GL_FRAMEBUFFER, mSceneTextureFB); + glBindFramebuffer(GL_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture]); +} + +//========================================================================== +// +// Makes the frame buffer for the next texture active +// +//========================================================================== + +void FGLRenderBuffers::BindNextFB() +{ + int out = (mCurrentPipelineTexture + 1) % NumPipelineTextures; + glBindFramebuffer(GL_FRAMEBUFFER, mPipelineFB[out]); +} + +//========================================================================== +// +// Next pipeline texture now contains the output +// +//========================================================================== + +void FGLRenderBuffers::NextTexture() +{ + mCurrentPipelineTexture = (mCurrentPipelineTexture + 1) % NumPipelineTextures; } //========================================================================== @@ -449,33 +474,6 @@ void FGLRenderBuffers::BindOutputFB() glBindFramebuffer(GL_FRAMEBUFFER, mOutputFB); } -//========================================================================== -// -// Binds the scene frame buffer texture to the specified texture unit -// -//========================================================================== - -void FGLRenderBuffers::BindSceneTexture(int index) -{ - glActiveTexture(GL_TEXTURE0 + index); - glBindTexture(GL_TEXTURE_2D, mSceneTexture); -} - -//========================================================================== -// -// Binds the 2D/HUD frame buffer texture to the specified texture unit -// -//========================================================================== - -void FGLRenderBuffers::BindHudTexture(int index) -{ - glActiveTexture(GL_TEXTURE0 + index); - if (gl_tonemap != 0 || gl_lens) - glBindTexture(GL_TEXTURE_2D, mHudTexture); - else - glBindTexture(GL_TEXTURE_2D, mSceneTexture); -} - //========================================================================== // // Returns true if render buffers are supported and should be used diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 37bbdc2e5..8b3001c96 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -21,13 +21,16 @@ public: ~FGLRenderBuffers(); void Setup(int width, int height); - void BlitSceneToTexture(); + void BindSceneFB(); - void BindSceneTextureFB(); - void BindHudFB(); + void BlitSceneToTexture(); + + void BindCurrentTexture(int index); + void BindCurrentFB(); + void BindNextFB(); + void NextTexture(); + void BindOutputFB(); - void BindSceneTexture(int index); - void BindHudTexture(int index); enum { NumBloomLevels = 4 }; FGLBloomTextureLevel BloomLevels[NumBloomLevels]; @@ -39,10 +42,10 @@ public: private: void ClearScene(); - void ClearHud(); + void ClearPipeline(); void ClearBloom(); void CreateScene(int width, int height, int samples); - void CreateHud(int width, int height); + void CreatePipeline(int width, int height); void CreateBloom(int width, int height); GLuint Create2DTexture(GLuint format, int width, int height); GLuint CreateRenderBuffer(GLuint format, int width, int height); @@ -62,15 +65,21 @@ private: int mHeight = 0; int mSamples = 0; - GLuint mSceneTexture = 0; + static const int NumPipelineTextures = 2; + int mCurrentPipelineTexture = 0; + + // Buffers for the scene GLuint mSceneMultisample = 0; GLuint mSceneDepthStencil = 0; GLuint mSceneDepth = 0; GLuint mSceneStencil = 0; GLuint mSceneFB = 0; - GLuint mSceneTextureFB = 0; - GLuint mHudTexture = 0; - GLuint mHudFB = 0; + + // Effect/HUD buffers + GLuint mPipelineTexture[NumPipelineTextures]; + GLuint mPipelineFB[NumPipelineTextures]; + + // Back buffer frame buffer GLuint mOutputFB = 0; }; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 5fa52ec6b..9105c08c7 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -251,7 +251,7 @@ void FGLRenderer::Begin2D() if (mDrawingScene2D) mBuffers->BindSceneFB(); else - mBuffers->BindHudFB(); + mBuffers->BindCurrentFB(); } glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index 781194ca4..0d1973131 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -158,7 +158,7 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type) if (FGLRenderBuffers::IsEnabled()) { - GLRenderer->mBuffers->BindHudFB(); + GLRenderer->mBuffers->BindCurrentFB(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); } else @@ -193,7 +193,7 @@ void OpenGLFrameBuffer::WipeEndScreen() wipeendscreen->Bind(0, false, false); if (FGLRenderBuffers::IsEnabled()) - GLRenderer->mBuffers->BindHudFB(); + GLRenderer->mBuffers->BindCurrentFB(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -232,7 +232,7 @@ bool OpenGLFrameBuffer::WipeDo(int ticks) if (FGLRenderBuffers::IsEnabled()) { - GLRenderer->mBuffers->BindHudFB(); + GLRenderer->mBuffers->BindCurrentFB(); const auto &bounds = GLRenderer->mScreenViewport; glViewport(bounds.left, bounds.top, bounds.width, bounds.height); } From 0457fee9c02a18093ba760b121cb81b3f7f5b2ba Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 4 Aug 2016 17:22:05 +0200 Subject: [PATCH 11/53] Added lens distortion effect to menus --- wadsrc/static/language.enu | 1 + wadsrc/static/menudef.z | 1 + 2 files changed, 2 insertions(+) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 21aab53a6..8050079e8 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2621,6 +2621,7 @@ GLPREFMNU_VRQUADSTEREO = "Enable Quad Stereo"; GLPREFMNU_MULTISAMPLE = "Multisample"; GLPREFMNU_TONEMAP = "Tonemap Mode"; GLPREFMNU_BLOOM = "Bloom effect"; +GLPREFMNU_LENS = "Lens distortion effect"; // Option Values OPTVAL_SMART = "Smart"; diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index bcee4ca01..bd458f376 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -220,4 +220,5 @@ OptionMenu "GLPrefOptions" Option "$GLPREFMNU_MULTISAMPLE", gl_multisample, "Multisample" Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes" Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff" + Option "$GLPREFMNU_LENS", gl_lens, "OnOff" } From 9229146eeb1dfaf867e3e5e6f053f8718a81f864 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Aug 2016 12:13:47 +0200 Subject: [PATCH 12/53] - fixed: DFloor set the 'gap' for one wrong movement type. --- src/p_floor.cpp | 10 ++++------ src/p_lnspec.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 10bcf6d7e..ccb1c82e9 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -349,16 +349,14 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, break; case DFloor::floorRaiseAndCrushDoom: + height = 8; case DFloor::floorRaiseToLowestCeiling: floor->m_Direction = 1; - newheight = sec->FindLowestCeilingSurrounding(&spot); - if (floortype == DFloor::floorRaiseAndCrushDoom) - newheight -= 8; + newheight = sec->FindLowestCeilingSurrounding(&spot) - height; ceilingheight = sec->FindLowestCeilingPoint(&spot2); floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); if (sec->floorplane.ZatPointDist(spot2, floor->m_FloorDestDist) > ceilingheight) - floor->m_FloorDestDist = sec->floorplane.PointToDist(spot2, - floortype == DFloor::floorRaiseAndCrushDoom ? ceilingheight - 8 : ceilingheight); + floor->m_FloorDestDist = sec->floorplane.PointToDist(spot2, floortype == ceilingheight - height); break; case DFloor::floorRaiseToHighest: @@ -393,7 +391,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, case DFloor::floorLowerToLowestCeiling: floor->m_Direction = -1; - newheight = sec->FindLowestCeilingSurrounding(&spot) - height; + newheight = sec->FindLowestCeilingSurrounding(&spot); floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight); break; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index dc6170c24..d0a56ee87 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -260,7 +260,13 @@ FUNC(LS_Door_Raise) FUNC(LS_Door_LockedRaise) // Door_LockedRaise (tag, speed, delay, lock, lighttag) { +#if 0 + // In Hexen this originally created a thinker running for nearly 4 years. + // Let's not do this unless it becomes necessary because this can hang tagwait. + return EV_DoDoor (arg2 || (level.flags2 & LEVEL2_HEXENHACK) ? DDoor::doorRaise : DDoor::doorOpen, ln, it, +#else return EV_DoDoor (arg2 ? DDoor::doorRaise : DDoor::doorOpen, ln, it, +#endif arg0, SPEED(arg1), TICS(arg2), arg3, arg4); } From 4a859393fe1ddac1c023f47a094c2b77da6a9f98 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Thu, 4 Aug 2016 19:45:24 +0200 Subject: [PATCH 13/53] Fixed: the game could crash while parsing expressions in some places --- src/thingdef/thingdef_exp.cpp | 2 +- src/thingdef/thingdef_expression.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 35932e0be..6a756d9b5 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -392,7 +392,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) return ParseAtan2(sc, identifier, cls); default: args = new FArgumentList; - func = dyn_cast(cls->Symbols.FindSymbol(identifier, true)); + func = (cls == nullptr) ? nullptr : dyn_cast(cls->Symbols.FindSymbol(identifier, true)); try { // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index acb26d05b..fee31a6e9 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -4410,6 +4410,8 @@ ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build) FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); + ABORT(ctx.Class); + if (ctx.Class->NumOwnedStates == 0) { // This can't really happen @@ -4464,6 +4466,8 @@ FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPositi FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); + ABORT(ctx.Class); + if (names[0] == NAME_None) { scope = NULL; From 73d0ed78fef46438581882c32014209d32ef4c0f Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Thu, 4 Aug 2016 19:58:57 +0200 Subject: [PATCH 14/53] Fixed: the game could crash while resolving expressions in some places --- src/thingdef/thingdef.cpp | 24 ++++++++++++++---------- src/thingdef/thingdef_parse.cpp | 33 ++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4bb247f94..04ac21890 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -361,16 +361,20 @@ static void FinishThingdef() if (sfunc == NULL) { FCompileContext ctx(ti); - dmg->Resolve(ctx); - VMFunctionBuilder buildit; - buildit.Registers[REGT_POINTER].Get(1); // The self pointer - dmg->Emit(&buildit); - sfunc = buildit.MakeFunction(); - sfunc->NumArgs = 1; - sfunc->Proto = NULL; ///FIXME: Need a proper prototype here - // Save this function in case this damage value was reused - // (which happens quite easily with inheritance). - dmg->SetFunction(sfunc); + dmg = static_cast(dmg->Resolve(ctx)); + + if (dmg != nullptr) + { + VMFunctionBuilder buildit; + buildit.Registers[REGT_POINTER].Get(1); // The self pointer + dmg->Emit(&buildit); + sfunc = buildit.MakeFunction(); + sfunc->NumArgs = 1; + sfunc->Proto = NULL; ///FIXME: Need a proper prototype here + // Save this function in case this damage value was reused + // (which happens quite easily with inheritance). + dmg->SetFunction(sfunc); + } } def->Damage = sfunc; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index f4bad69bb..566643b8e 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -191,7 +191,12 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls) FxExpression *expr = ParseExpression (sc, cls, true); sc.MustGetToken(';'); - if (!expr->isConstant()) + if (expr == nullptr) + { + sc.ScriptMessage("Error while resolving constant definition"); + FScriptPosition::ErrorCounter++; + } + else if (!expr->isConstant()) { sc.ScriptMessage("Constant definition is not a constant"); FScriptPosition::ErrorCounter++; @@ -247,16 +252,24 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls) if (sc.CheckToken('=')) { FxExpression *expr = ParseExpression (sc, cls, true); - if (!expr->isConstant()) + if (expr != nullptr) { - sc.ScriptMessage("'%s' must be constant", symname.GetChars()); - FScriptPosition::ErrorCounter++; + if (!expr->isConstant()) + { + sc.ScriptMessage("'%s' must be constant", symname.GetChars()); + FScriptPosition::ErrorCounter++; + } + else + { + currvalue = static_cast(expr)->GetValue().GetInt(); + } + delete expr; } else { - currvalue = static_cast(expr)->GetValue().GetInt(); + sc.ScriptMessage("Error while resolving expression of '%s'", symname.GetChars()); + FScriptPosition::ErrorCounter++; } - delete expr; } PSymbolConstNumeric *sym = new PSymbolConstNumeric(symname, TypeSInt32); sym->Value = currvalue; @@ -568,7 +581,13 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl if (sc.CheckToken('[')) { FxExpression *expr = ParseExpression(sc, cls, true); - if (!expr->isConstant()) + if (expr == nullptr) + { + sc.ScriptMessage("Error while resolving array size"); + FScriptPosition::ErrorCounter++; + maxelems = 1; + } + else if (!expr->isConstant()) { sc.ScriptMessage("Array size must be a constant"); FScriptPosition::ErrorCounter++; From 01fb2eaecc567818c798951b02e6425084a35ced Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Wed, 3 Aug 2016 19:37:19 +0200 Subject: [PATCH 15/53] Fixed a typo in FxBoolCast::Emit --- src/thingdef/thingdef_expression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index fee31a6e9..b57618575 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -414,7 +414,7 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) { build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.)); } - else if (from.RegNum == REGT_POINTER) + else if (from.RegType == REGT_POINTER) { build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); } From a893013dbbfd68895f9a44476a4b67368420f2c8 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 5 Aug 2016 01:43:56 +0200 Subject: [PATCH 16/53] Adds HUD quadruple scale and a scale slider for the crosshair --- src/c_console.cpp | 28 +++++++++++++++-- src/ct_chat.cpp | 24 +++++++++++++-- src/g_shared/hudmessages.cpp | 58 ++++++++++++++++++++++++++++++++++-- src/g_shared/shared_hud.cpp | 28 +++++++++++++++-- src/g_shared/shared_sbar.cpp | 20 +++++++++++-- wadsrc/static/language.enu | 2 ++ wadsrc/static/menudef.txt | 4 ++- 7 files changed, 150 insertions(+), 14 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index 2f221e319..9a9274aa1 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -162,7 +162,7 @@ CVAR (Bool, con_centernotify, false, CVAR_ARCHIVE) CUSTOM_CVAR (Int, con_scaletext, 0, CVAR_ARCHIVE) // Scale notify text at high resolutions? { if (self < 0) self = 0; - if (self > 2) self = 2; + if (self > 3) self = 3; } CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE) @@ -493,7 +493,14 @@ void C_AddNotifyString (int printlevel, const char *source) return; } - width = con_scaletext > 1 ? DisplayWidth/2 : con_scaletext == 1 ? DisplayWidth / CleanXfac : DisplayWidth; + switch (con_scaletext) + { + default: + case 0: width = DisplayWidth; break; + case 1: width = DisplayWidth / CleanXfac; break; + case 2: width = DisplayWidth / 2; break; + case 3: width = DisplayWidth / 4; break; + } if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].PrintLevel == printlevel) { @@ -770,6 +777,23 @@ static void C_DrawNotifyText () line, NotifyStrings[i].Text, DTA_AlphaF, alpha, TAG_DONE); } + else if (con_scaletext == 3) + { + if (!center) + screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text, + DTA_VirtualWidth, screen->GetWidth() / 4, + DTA_VirtualHeight, screen->GetHeight() / 4, + DTA_KeepRatio, true, + DTA_AlphaF, alpha, TAG_DONE); + else + screen->DrawText (SmallFont, color, (screen->GetWidth() / 4 - + SmallFont->StringWidth (NotifyStrings[i].Text))/4, + line, NotifyStrings[i].Text, + DTA_VirtualWidth, screen->GetWidth() / 4, + DTA_VirtualHeight, screen->GetHeight() / 4, + DTA_KeepRatio, true, + DTA_AlphaF, alpha, TAG_DONE); + } else { if (!center) diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index d814717c9..b053d8bd8 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -234,9 +234,27 @@ void CT_Drawer (void) scalex = 1; } - int screen_width = con_scaletext > 1? SCREENWIDTH/2 : SCREENWIDTH; - int screen_height = con_scaletext > 1? SCREENHEIGHT/2 : SCREENHEIGHT; - int st_y = con_scaletext > 1? ST_Y/2 : ST_Y; + int screen_width, screen_height, st_y; + switch (con_scaletext) + { + default: + case 0: + case 1: + screen_width = SCREENWIDTH; + screen_height = SCREENHEIGHT; + st_y = ST_Y; + break; + case 2: + screen_width = SCREENWIDTH / 2; + screen_height = SCREENHEIGHT / 2; + st_y = ST_Y / 2; + break; + case 3: + screen_width = SCREENWIDTH / 4; + screen_height = SCREENHEIGHT / 4; + st_y = ST_Y / 4; + break; + } y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y; diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp index 0ee61f942..9f13d3d9e 100644 --- a/src/g_shared/hudmessages.cpp +++ b/src/g_shared/hudmessages.cpp @@ -260,7 +260,14 @@ void DHUDMessage::ResetText (const char *text) } else { - width = con_scaletext >= 2 ? SCREENWIDTH/2 : (con_scaletext ? SCREENWIDTH / CleanXfac : SCREENWIDTH); + switch (con_scaletext) + { + default: + case 0: width = SCREENWIDTH; break; + case 1: width = SCREENWIDTH / CleanXfac; break; + case 2: width = SCREENWIDTH / 2; break; + case 3: width = SCREENWIDTH / 4; break; + } } if (Lines != NULL) @@ -334,12 +341,18 @@ void DHUDMessage::Draw (int bottom, int visibility) else { xscale = yscale = 1; - if (HUDWidth==0 && con_scaletext>1) + if (HUDWidth==0 && con_scaletext==2) { screen_width/=2; screen_height/=2; bottom/=2; } + else if (HUDWidth==0 && con_scaletext==3) + { + screen_width/=4; + screen_height/=4; + bottom/=4; + } } if (HUDWidth == 0) @@ -448,6 +461,16 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight) DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_AlphaF, Alpha, + DTA_RenderStyle, Style, + DTA_KeepRatio, true, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, @@ -551,6 +574,16 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_AlphaF, trans, + DTA_RenderStyle, Style, + DTA_KeepRatio, true, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, @@ -651,6 +684,16 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_AlphaF, trans, + DTA_RenderStyle, Style, + DTA_KeepRatio, true, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, @@ -830,6 +873,17 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in DTA_RenderStyle, Style, TAG_DONE); } + else if (con_scaletext == 3) + { + screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, + DTA_VirtualWidth, SCREENWIDTH/4, + DTA_VirtualHeight, SCREENHEIGHT/4, + DTA_KeepRatio, true, + DTA_TextLen, LineVisible, + DTA_AlphaF, Alpha, + DTA_RenderStyle, Style, + TAG_DONE); + } else { screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text, diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 3a8dc388c..c9e87d642 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -885,8 +885,25 @@ static void DrawCoordinates(player_t * CPlayer) pos = DVector3(apos, z); } - int vwidth = con_scaletext==0? SCREENWIDTH : SCREENWIDTH/2; - int vheight = con_scaletext==0? SCREENHEIGHT : SCREENHEIGHT/2; + int vwidth, vheight; + switch (con_scaletext) + { + default: + case 0: + vwidth = SCREENWIDTH; + vheight = SCREENWIDTH; + break; + case 1: + case 2: + vwidth = SCREENWIDTH/2; + vheight = SCREENWIDTH/2; + break; + case 3: + vwidth = SCREENWIDTH/4; + vheight = SCREENWIDTH/4; + break; + } + int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; int ypos = 18; @@ -1073,7 +1090,12 @@ void DrawHUD() if (hud_althudscale && SCREENWIDTH>640) { hudwidth=SCREENWIDTH/2; - if (hud_althudscale == 2) + if (hud_althudscale == 3) + { + hudwidth = SCREENWIDTH / 4; + hudheight = SCREENHEIGHT / 4; + } + else if (hud_althudscale == 2) { // Optionally just double the pixels to reduce scaling artifacts. hudheight=SCREENHEIGHT/2; diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index b48c04893..c3b1fd262 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -108,7 +108,7 @@ CVAR (Int, crosshair, 0, CVAR_ARCHIVE) CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE) CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE); CVAR (Bool, crosshairhealth, true, CVAR_ARCHIVE); -CVAR (Bool, crosshairscale, false, CVAR_ARCHIVE); +CVAR (Float, crosshairscale, 1.0, CVAR_ARCHIVE); CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE); CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE) { @@ -1106,9 +1106,9 @@ void DBaseStatusBar::DrawCrosshair () return; } - if (crosshairscale) + if (crosshairscale > 0.0f) { - size = SCREENHEIGHT / 200.; + size = SCREENHEIGHT * crosshairscale / 200.; } else { @@ -1247,6 +1247,13 @@ void DBaseStatusBar::Draw (EHudState state) xpos = vwidth - 80; y = ::ST_Y - height; } + else if (con_scaletext == 3) + { + vwidth = SCREENWIDTH/4; + vheight = SCREENHEIGHT/4; + xpos = vwidth - SmallFont->StringWidth("X: -00000")-6; + y = ::ST_Y/4 - height; + } else { vwidth = SCREENWIDTH/2; @@ -1259,6 +1266,8 @@ void DBaseStatusBar::Draw (EHudState state) { if (con_scaletext == 0) y -= height * 4; + else if (con_scaletext == 3) + y -= height; else y -= height * 2; } @@ -1407,6 +1416,11 @@ void DBaseStatusBar::DrawLog () hudwidth = SCREENWIDTH / 2; hudheight = SCREENHEIGHT / 2; break; + + case 3: + hudwidth = SCREENWIDTH / 4; + hudheight = SCREENHEIGHT / 4; + break; } int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560; diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index cef67aca9..03a3ffb1a 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2197,6 +2197,7 @@ OPTVAL_PLAYER = "Player"; OPTVAL_MAP = "Map"; OPTVAL_SCALETO640X400 = "Scale to 640x400"; OPTVAL_PIXELDOUBLE = "Pixel double"; +OPTVAL_PIXELQUADRUPLE = "Pixel quadruple"; OPTVAL_CURRENTWEAPON = "Current weapon"; OPTVAL_AVAILABLEWEAPONS = "Available weapons"; OPTVAL_ALLWEAPONS = "All weapons"; @@ -2231,6 +2232,7 @@ OPTVAL_ANIMATED = "Animated"; OPTVAL_ROTATED = "Rotated"; OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colors only"; OPTVAL_DOUBLE = "Double"; +OPTVAL_QUADRUPLE = "Quadruple"; OPTVAL_ITEMPICKUP = "Item Pickup"; OPTVAL_OBITUARIES = "Obituaries"; OPTVAL_CRITICALMESSAGES = "Critical Messages"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 2a59c4103..ca36c1975 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -760,7 +760,7 @@ OptionMenu "HUDOptions" Option "$HUDMNU_GROWCROSSHAIR", "crosshairgrow", "OnOff" ColorPicker "$HUDMNU_CROSSHAIRCOLOR", "crosshaircolor" Option "$HUDMNU_CROSSHAIRHEALTH", "crosshairhealth", "OnOff" - Option "$HUDMNU_CROSSHAIRSCALE", "crosshairscale", "OnOff" + Slider "$HUDMNU_CROSSHAIRSCALE", "crosshairscale", 0.0, 2.0, 0.05, 2 StaticText " " Option "$HUDMNU_NAMETAGS", "displaynametags", "DisplayTagsTypes" Option "$HUDMNU_NAMETAGCOLOR", "nametagcolor", "TextColors", "displaynametags" @@ -791,6 +791,7 @@ OptionValue "AltHUDScale" 0, "$OPTVAL_OFF" 1, "$OPTVAL_SCALETO640X400" 2, "$OPTVAL_PIXELDOUBLE" + 3, "$OPTVAL_PIXELQUADRUPLE" } OptionValue "AltHUDAmmo" @@ -1107,6 +1108,7 @@ OptionValue ScaleValues 0, "$OPTVAL_OFF" 1, "$OPTVAL_ON" 2, "$OPTVAL_DOUBLE" + 3, "$OPTVAL_QUADRUPLE" } OptionValue MessageLevels From 5b201287fa9b332dcc83ef6f4156a1bdb80cc0b4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 5 Aug 2016 15:27:35 +0200 Subject: [PATCH 17/53] - fixed bad #pragma pack combination in hqnx_asm_Image.h --- src/gl/hqnx_asm/hqnx_asm_Image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/hqnx_asm/hqnx_asm_Image.h b/src/gl/hqnx_asm/hqnx_asm_Image.h index e4157a7b5..38f0f1d6a 100644 --- a/src/gl/hqnx_asm/hqnx_asm_Image.h +++ b/src/gl/hqnx_asm/hqnx_asm_Image.h @@ -147,6 +147,6 @@ class CImage char m_cBuf[32768]; }; -#pragma pack(8) +#pragma pack() } \ No newline at end of file From 13a2bf57e535ac4b051fc82d0cfe6218b448fe47 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Aug 2016 11:47:03 +0200 Subject: [PATCH 18/53] - fixed vertex coordinate ordering for the sky cubemap. This was done differently for FFlatVertex and FSkyVertex which caused a switch of the y and z coordinates for the skybox image. --- src/gl/data/gl_vertexbuffer.h | 10 +++++ src/gl/scene/gl_skydome.cpp | 76 +++++++++++++++++------------------ 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index f7a48a3e3..6420e8fc8 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -146,6 +146,16 @@ struct FSkyVertex color = col; } + void SetXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0, PalEntry col = 0xffffffff) + { + x = xx; + y = yy; + z = zz; + u = uu; + v = vv; + color = col; + } + }; class FSkyVertexBuffer : public FVertexBuffer diff --git a/src/gl/scene/gl_skydome.cpp b/src/gl/scene/gl_skydome.cpp index 6e379117a..52dfa064f 100644 --- a/src/gl/scene/gl_skydome.cpp +++ b/src/gl/scene/gl_skydome.cpp @@ -228,58 +228,58 @@ void FSkyVertexBuffer::CreateDome() FSkyVertex *ptr = &mVertices[mSideStart]; // all sides - ptr[0].Set(128.f, 128.f, -128.f, 0, 0); - ptr[1].Set(128.f, -128.f, -128.f, 0, 1); - ptr[2].Set(-128.f, 128.f, -128.f, 0.25f, 0); - ptr[3].Set(-128.f, -128.f, -128.f, 0.25f, 1); - ptr[4].Set(-128.f, 128.f, 128.f, 0.5f, 0); - ptr[5].Set(-128.f, -128.f, 128.f, 0.5f, 1); - ptr[6].Set(128.f, 128.f, 128.f, 0.75f, 0); - ptr[7].Set(128.f, -128.f, 128.f, 0.75f, 1); - ptr[8].Set(128.f, 128.f, -128.f, 1, 0); - ptr[9].Set(128.f, -128.f, -128.f, 1, 1); + ptr[0].SetXYZ(128.f, 128.f, -128.f, 0, 0); + ptr[1].SetXYZ(128.f, -128.f, -128.f, 0, 1); + ptr[2].SetXYZ(-128.f, 128.f, -128.f, 0.25f, 0); + ptr[3].SetXYZ(-128.f, -128.f, -128.f, 0.25f, 1); + ptr[4].SetXYZ(-128.f, 128.f, 128.f, 0.5f, 0); + ptr[5].SetXYZ(-128.f, -128.f, 128.f, 0.5f, 1); + ptr[6].SetXYZ(128.f, 128.f, 128.f, 0.75f, 0); + ptr[7].SetXYZ(128.f, -128.f, 128.f, 0.75f, 1); + ptr[8].SetXYZ(128.f, 128.f, -128.f, 1, 0); + ptr[9].SetXYZ(128.f, -128.f, -128.f, 1, 1); // north face - ptr[10].Set(128.f, 128.f, -128.f, 0, 0); - ptr[11].Set(-128.f, 128.f, -128.f, 1, 0); - ptr[12].Set(128.f, -128.f, -128.f, 0, 1); - ptr[13].Set(-128.f, -128.f, -128.f, 1, 1); + ptr[10].SetXYZ(128.f, 128.f, -128.f, 0, 0); + ptr[11].SetXYZ(-128.f, 128.f, -128.f, 1, 0); + ptr[12].SetXYZ(128.f, -128.f, -128.f, 0, 1); + ptr[13].SetXYZ(-128.f, -128.f, -128.f, 1, 1); // east face - ptr[14].Set(-128.f, 128.f, -128.f, 0, 0); - ptr[15].Set(-128.f, 128.f, 128.f, 1, 0); - ptr[16].Set(-128.f, -128.f, -128.f, 0, 1); - ptr[17].Set(-128.f, -128.f, 128.f, 1, 1); + ptr[14].SetXYZ(-128.f, 128.f, -128.f, 0, 0); + ptr[15].SetXYZ(-128.f, 128.f, 128.f, 1, 0); + ptr[16].SetXYZ(-128.f, -128.f, -128.f, 0, 1); + ptr[17].SetXYZ(-128.f, -128.f, 128.f, 1, 1); // south face - ptr[18].Set(-128.f, 128.f, 128.f, 0, 0); - ptr[19].Set(128.f, 128.f, 128.f, 1, 0); - ptr[20].Set(-128.f, -128.f, 128.f, 0, 1); - ptr[21].Set(128.f, -128.f, 128.f, 1, 1); + ptr[18].SetXYZ(-128.f, 128.f, 128.f, 0, 0); + ptr[19].SetXYZ(128.f, 128.f, 128.f, 1, 0); + ptr[20].SetXYZ(-128.f, -128.f, 128.f, 0, 1); + ptr[21].SetXYZ(128.f, -128.f, 128.f, 1, 1); // west face - ptr[22].Set(128.f, 128.f, 128.f, 0, 0); - ptr[23].Set(128.f, 128.f, -128.f, 1, 0); - ptr[24].Set(128.f, -128.f, 128.f, 0, 1); - ptr[25].Set(128.f, -128.f, -128.f, 1, 1); + ptr[22].SetXYZ(128.f, 128.f, 128.f, 0, 0); + ptr[23].SetXYZ(128.f, 128.f, -128.f, 1, 0); + ptr[24].SetXYZ(128.f, -128.f, 128.f, 0, 1); + ptr[25].SetXYZ(128.f, -128.f, -128.f, 1, 1); // bottom face - ptr[26].Set(128.f, -128.f, -128.f, 0, 0); - ptr[27].Set(-128.f, -128.f, -128.f, 1, 0); - ptr[28].Set(128.f, -128.f, 128.f, 0, 1); - ptr[29].Set(-128.f, -128.f, 128.f, 1, 1); + ptr[26].SetXYZ(128.f, -128.f, -128.f, 0, 0); + ptr[27].SetXYZ(-128.f, -128.f, -128.f, 1, 0); + ptr[28].SetXYZ(128.f, -128.f, 128.f, 0, 1); + ptr[29].SetXYZ(-128.f, -128.f, 128.f, 1, 1); // top face - ptr[30].Set(128.f, 128.f, -128.f, 0, 0); - ptr[31].Set(-128.f, 128.f, -128.f, 1, 0); - ptr[32].Set(128.f, 128.f, 128.f, 0, 1); - ptr[33].Set(-128.f, 128.f, 128.f, 1, 1); + ptr[30].SetXYZ(128.f, 128.f, -128.f, 0, 0); + ptr[31].SetXYZ(-128.f, 128.f, -128.f, 1, 0); + ptr[32].SetXYZ(128.f, 128.f, 128.f, 0, 1); + ptr[33].SetXYZ(-128.f, 128.f, 128.f, 1, 1); // top face flipped - ptr[34].Set(128.f, 128.f, -128.f, 0, 1); - ptr[35].Set(-128.f, 128.f, -128.f, 1, 1); - ptr[36].Set(128.f, 128.f, 128.f, 0, 0); - ptr[37].Set(-128.f, 128.f, 128.f, 1, 0); + ptr[34].SetXYZ(128.f, 128.f, -128.f, 0, 1); + ptr[35].SetXYZ(-128.f, 128.f, -128.f, 1, 1); + ptr[36].SetXYZ(128.f, 128.f, 128.f, 0, 0); + ptr[37].SetXYZ(-128.f, 128.f, 128.f, 1, 0); glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glBufferData(GL_ARRAY_BUFFER, mVertices.Size() * sizeof(FSkyVertex), &mVertices[0], GL_STATIC_DRAW); From 346badf25f10c4597215f89187d665bebaec7300 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 5 Aug 2016 17:12:00 +0200 Subject: [PATCH 19/53] Moved state to FGLPostProcessState and merged vertex shaders --- src/CMakeLists.txt | 1 + src/gl/renderer/gl_postprocess.cpp | 122 ++--------------- src/gl/renderer/gl_postprocessstate.cpp | 124 ++++++++++++++++++ src/gl/renderer/gl_postprocessstate.h | 37 ++++++ src/gl/shaders/gl_bloomshader.cpp | 4 +- src/gl/shaders/gl_lensshader.cpp | 2 +- src/gl/shaders/gl_presentshader.cpp | 2 +- src/gl/shaders/gl_tonemapshader.cpp | 2 +- wadsrc/static/shaders/glsl/bloomcombine.vp | 9 -- wadsrc/static/shaders/glsl/bloomextract.vp | 9 -- wadsrc/static/shaders/glsl/lensdistortion.vp | 9 -- .../glsl/{present.vp => screenquad.vp} | 0 wadsrc/static/shaders/glsl/tonemap.vp | 9 -- 13 files changed, 176 insertions(+), 154 deletions(-) create mode 100644 src/gl/renderer/gl_postprocessstate.cpp create mode 100644 src/gl/renderer/gl_postprocessstate.h delete mode 100644 wadsrc/static/shaders/glsl/bloomcombine.vp delete mode 100644 wadsrc/static/shaders/glsl/bloomextract.vp delete mode 100644 wadsrc/static/shaders/glsl/lensdistortion.vp rename wadsrc/static/shaders/glsl/{present.vp => screenquad.vp} (100%) delete mode 100644 wadsrc/static/shaders/glsl/tonemap.vp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5317c277a..b5dd8739c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1063,6 +1063,7 @@ set( FASTMATH_SOURCES gl/renderer/gl_renderbuffers.cpp gl/renderer/gl_lightdata.cpp gl/renderer/gl_postprocess.cpp + gl/renderer/gl_postprocessstate.cpp gl/hqnx/init.cpp gl/hqnx/hq2x.cpp gl/hqnx/hq3x.cpp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 155321de4..da7031afe 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -63,6 +63,7 @@ #include "gl/renderer/gl_renderstate.h" #include "gl/renderer/gl_renderbuffers.h" #include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_postprocessstate.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/shaders/gl_bloomshader.h" @@ -117,34 +118,11 @@ void FGLRenderer::BloomScene() if (!gl_bloom || !FGLRenderBuffers::IsEnabled() || gl_fixedcolormap != CM_DEFAULT) return; + FGLPostProcessState savedState; + const float blurAmount = gl_bloom_amount; int sampleCount = gl_bloom_kernel_size; - // TBD: Maybe need a better way to share state with other parts of the pipeline - GLint activeTex, textureBinding, samplerBinding; - glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); - glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - { - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding); - glBindSampler(0, 0); - } - GLboolean blendEnabled, scissorEnabled; - GLint currentProgram, blendEquationRgb, blendEquationAlpha, blendSrcRgb, blendSrcAlpha, blendDestRgb, blendDestAlpha; - glGetBooleanv(GL_BLEND, &blendEnabled); - glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); - glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); - glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRgb); - glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha); - glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRgb); - glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha); - glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRgb); - glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha); - - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - const auto &level0 = mBuffers->BloomLevels[0]; // Extract blooming pixels from scene texture: @@ -207,18 +185,6 @@ void FGLRenderer::BloomScene() mBloomCombineShader->Bind(); mBloomCombineShader->BloomTexture.Set(0); mVBO->RenderScreenQuad(); - - if (blendEnabled) - glEnable(GL_BLEND); - if (scissorEnabled) - glEnable(GL_SCISSOR_TEST); - glBlendEquationSeparate(blendEquationRgb, blendEquationAlpha); - glBlendFuncSeparate(blendSrcRgb, blendDestRgb, blendSrcAlpha, blendDestAlpha); - glUseProgram(currentProgram); - glBindTexture(GL_TEXTURE_2D, textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - glBindSampler(0, samplerBinding); - glActiveTexture(activeTex); } //----------------------------------------------------------------------------- @@ -232,22 +198,7 @@ void FGLRenderer::TonemapScene() if (gl_tonemap == 0) return; - GLint activeTex, textureBinding, samplerBinding; - glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); - glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - { - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding); - glBindSampler(0, 0); - } - - GLboolean blendEnabled, scissorEnabled; - glGetBooleanv(GL_BLEND, &blendEnabled); - glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); - - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); + FGLPostProcessState savedState; mBuffers->BindNextFB(); mBuffers->BindCurrentTexture(0); @@ -257,15 +208,6 @@ void FGLRenderer::TonemapScene() mVBO->BindVBO(); mVBO->RenderScreenQuad(); mBuffers->NextTexture(); - - if (blendEnabled) - glEnable(GL_BLEND); - if (scissorEnabled) - glEnable(GL_SCISSOR_TEST); - glBindTexture(GL_TEXTURE_2D, textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - glBindSampler(0, samplerBinding); - glActiveTexture(activeTex); } //----------------------------------------------------------------------------- @@ -279,23 +221,6 @@ void FGLRenderer::LensDistortScene() if (gl_lens == 0) return; - GLint activeTex, textureBinding, samplerBinding; - glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); - glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - { - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding); - glBindSampler(0, 0); - } - - GLboolean blendEnabled, scissorEnabled; - glGetBooleanv(GL_BLEND, &blendEnabled); - glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); - - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - float k[4] = { gl_lens_k, @@ -321,6 +246,8 @@ void FGLRenderer::LensDistortScene() float f = MAX(f0, f2); float scale = 1.0f / f; + FGLPostProcessState savedState; + mBuffers->BindNextFB(); mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -333,16 +260,9 @@ void FGLRenderer::LensDistortScene() mLensShader->CubicDistortionValue.Set(kcube); mVBO->BindVBO(); mVBO->RenderScreenQuad(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mBuffers->NextTexture(); - - if (blendEnabled) - glEnable(GL_BLEND); - if (scissorEnabled) - glEnable(GL_SCISSOR_TEST); - glBindTexture(GL_TEXTURE_2D, textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - glBindSampler(0, samplerBinding); - glActiveTexture(activeTex); } //----------------------------------------------------------------------------- @@ -355,23 +275,7 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) { if (FGLRenderBuffers::IsEnabled()) { - glDisable(GL_MULTISAMPLE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_STENCIL_TEST); - - GLboolean blendEnabled; - GLint currentProgram; - GLint activeTex, textureBinding, samplerBinding; - glGetBooleanv(GL_BLEND, &blendEnabled); - glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); - glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); - glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - { - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding); - glBindSampler(0, 0); - } + FGLPostProcessState savedState; mBuffers->BindOutputFB(); @@ -446,13 +350,5 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mVBO->BindVBO(); mVBO->RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); - - if (blendEnabled) - glEnable(GL_BLEND); - glUseProgram(currentProgram); - glBindTexture(GL_TEXTURE_2D, textureBinding); - if (gl.flags & RFL_SAMPLER_OBJECTS) - glBindSampler(0, samplerBinding); - glActiveTexture(activeTex); } } diff --git a/src/gl/renderer/gl_postprocessstate.cpp b/src/gl/renderer/gl_postprocessstate.cpp new file mode 100644 index 000000000..7e34a1149 --- /dev/null +++ b/src/gl/renderer/gl_postprocessstate.cpp @@ -0,0 +1,124 @@ +/* +** gl_postprocessstate.cpp +** Render state maintenance +** +**--------------------------------------------------------------------------- +** Copyright 2016 Magnus Norddahl +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 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 "templates.h" +#include "gl/system/gl_system.h" +#include "gl/system/gl_interface.h" +#include "gl/data/gl_data.h" +#include "gl/data/gl_vertexbuffer.h" +#include "gl/system/gl_cvars.h" +#include "gl/shaders/gl_shader.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_postprocessstate.h" + +//----------------------------------------------------------------------------- +// +// Saves state modified by post processing shaders +// +//----------------------------------------------------------------------------- + +FGLPostProcessState::FGLPostProcessState() +{ + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); + glActiveTexture(GL_TEXTURE0); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + if (gl.flags & RFL_SAMPLER_OBJECTS) + { + glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding); + glBindSampler(0, 0); + } + + glGetBooleanv(GL_BLEND, &blendEnabled); + glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); + glGetBooleanv(GL_DEPTH_TEST, &depthEnabled); + glGetBooleanv(GL_MULTISAMPLE, &multisampleEnabled); + glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); + glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRgb); + glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha); + glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRgb); + glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha); + glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRgb); + glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha); + + glDisable(GL_MULTISAMPLE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); +} + +//----------------------------------------------------------------------------- +// +// Restores state at the end of post processing +// +//----------------------------------------------------------------------------- + +FGLPostProcessState::~FGLPostProcessState() +{ + if (blendEnabled) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + + if (scissorEnabled) + glEnable(GL_SCISSOR_TEST); + else + glDisable(GL_SCISSOR_TEST); + + if (depthEnabled) + glEnable(GL_DEPTH_TEST); + else + glDisable(GL_DEPTH_TEST); + + if (multisampleEnabled) + glEnable(GL_MULTISAMPLE); + else + glDisable(GL_MULTISAMPLE); + + glBlendEquationSeparate(blendEquationRgb, blendEquationAlpha); + glBlendFuncSeparate(blendSrcRgb, blendDestRgb, blendSrcAlpha, blendDestAlpha); + + glUseProgram(currentProgram); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureBinding); + if (gl.flags & RFL_SAMPLER_OBJECTS) + glBindSampler(0, samplerBinding); + glActiveTexture(activeTex); +} diff --git a/src/gl/renderer/gl_postprocessstate.h b/src/gl/renderer/gl_postprocessstate.h new file mode 100644 index 000000000..5cba73674 --- /dev/null +++ b/src/gl/renderer/gl_postprocessstate.h @@ -0,0 +1,37 @@ +#ifndef __GL_POSTPROCESSSTATE_H +#define __GL_POSTPROCESSSTATE_H + +#include +#include "gl/system/gl_interface.h" +#include "gl/data/gl_data.h" +#include "gl/data/gl_matrix.h" +#include "c_cvars.h" +#include "r_defs.h" + +class FGLPostProcessState +{ +public: + FGLPostProcessState(); + ~FGLPostProcessState(); + +private: + FGLPostProcessState(const FGLPostProcessState &) = delete; + FGLPostProcessState &operator=(const FGLPostProcessState &) = delete; + + GLint activeTex; + GLint textureBinding; + GLint samplerBinding; + GLboolean blendEnabled; + GLboolean scissorEnabled; + GLboolean depthEnabled; + GLboolean multisampleEnabled; + GLint currentProgram; + GLint blendEquationRgb; + GLint blendEquationAlpha; + GLint blendSrcRgb; + GLint blendSrcAlpha; + GLint blendDestRgb; + GLint blendDestAlpha; +}; + +#endif diff --git a/src/gl/shaders/gl_bloomshader.cpp b/src/gl/shaders/gl_bloomshader.cpp index c7191884f..f9e38e0c3 100644 --- a/src/gl/shaders/gl_bloomshader.cpp +++ b/src/gl/shaders/gl_bloomshader.cpp @@ -53,7 +53,7 @@ void FBloomExtractShader::Bind() { if (!mShader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/bloomextract.vp", "", 330); + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/bloomextract.fp", "", 330); mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/bloomextract"); @@ -68,7 +68,7 @@ void FBloomCombineShader::Bind() { if (!mShader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/bloomcombine.vp", "", 330); + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/bloomcombine.fp", "", 330); mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/bloomcombine"); diff --git a/src/gl/shaders/gl_lensshader.cpp b/src/gl/shaders/gl_lensshader.cpp index 39f5042e7..4dc23f14d 100644 --- a/src/gl/shaders/gl_lensshader.cpp +++ b/src/gl/shaders/gl_lensshader.cpp @@ -53,7 +53,7 @@ void FLensShader::Bind() { if (!mShader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/lensdistortion.vp", "", 330); + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/lensdistortion.fp", "", 330); mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/lensdistortion"); diff --git a/src/gl/shaders/gl_presentshader.cpp b/src/gl/shaders/gl_presentshader.cpp index 2f9642458..9998fda36 100644 --- a/src/gl/shaders/gl_presentshader.cpp +++ b/src/gl/shaders/gl_presentshader.cpp @@ -53,7 +53,7 @@ void FPresentShader::Bind() { if (!mShader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/present.vp", "", 330); + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present.fp", "", 330); mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/present"); diff --git a/src/gl/shaders/gl_tonemapshader.cpp b/src/gl/shaders/gl_tonemapshader.cpp index c26e8d1af..8e1f3a844 100644 --- a/src/gl/shaders/gl_tonemapshader.cpp +++ b/src/gl/shaders/gl_tonemapshader.cpp @@ -54,7 +54,7 @@ void FTonemapShader::Bind() auto &shader = mShader[gl_tonemap]; if (!shader) { - shader.Compile(FShaderProgram::Vertex, "shaders/glsl/tonemap.vp", "", 330); + shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); shader.Compile(FShaderProgram::Fragment, "shaders/glsl/tonemap.fp", GetDefines(gl_tonemap), 330); shader.SetFragDataLocation(0, "FragColor"); shader.Link("shaders/glsl/tonemap"); diff --git a/wadsrc/static/shaders/glsl/bloomcombine.vp b/wadsrc/static/shaders/glsl/bloomcombine.vp deleted file mode 100644 index 5990669a5..000000000 --- a/wadsrc/static/shaders/glsl/bloomcombine.vp +++ /dev/null @@ -1,9 +0,0 @@ - -in vec4 PositionInProjection; -out vec2 TexCoord; - -void main() -{ - gl_Position = PositionInProjection; - TexCoord = PositionInProjection.xy * 0.5 + 0.5; -} diff --git a/wadsrc/static/shaders/glsl/bloomextract.vp b/wadsrc/static/shaders/glsl/bloomextract.vp deleted file mode 100644 index 5990669a5..000000000 --- a/wadsrc/static/shaders/glsl/bloomextract.vp +++ /dev/null @@ -1,9 +0,0 @@ - -in vec4 PositionInProjection; -out vec2 TexCoord; - -void main() -{ - gl_Position = PositionInProjection; - TexCoord = PositionInProjection.xy * 0.5 + 0.5; -} diff --git a/wadsrc/static/shaders/glsl/lensdistortion.vp b/wadsrc/static/shaders/glsl/lensdistortion.vp deleted file mode 100644 index 5990669a5..000000000 --- a/wadsrc/static/shaders/glsl/lensdistortion.vp +++ /dev/null @@ -1,9 +0,0 @@ - -in vec4 PositionInProjection; -out vec2 TexCoord; - -void main() -{ - gl_Position = PositionInProjection; - TexCoord = PositionInProjection.xy * 0.5 + 0.5; -} diff --git a/wadsrc/static/shaders/glsl/present.vp b/wadsrc/static/shaders/glsl/screenquad.vp similarity index 100% rename from wadsrc/static/shaders/glsl/present.vp rename to wadsrc/static/shaders/glsl/screenquad.vp diff --git a/wadsrc/static/shaders/glsl/tonemap.vp b/wadsrc/static/shaders/glsl/tonemap.vp deleted file mode 100644 index 5990669a5..000000000 --- a/wadsrc/static/shaders/glsl/tonemap.vp +++ /dev/null @@ -1,9 +0,0 @@ - -in vec4 PositionInProjection; -out vec2 TexCoord; - -void main() -{ - gl_Position = PositionInProjection; - TexCoord = PositionInProjection.xy * 0.5 + 0.5; -} From 2e555e6dabf18891ca82deef827fbfd427ad4373 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Aug 2016 12:03:16 +0200 Subject: [PATCH 20/53] - use client arrays on compatibility profiles instead of calling glBegin/glEnd. This eliminates most behavioral differences for FFlatVertexBuffer between both operating modes, now the only difference is where the buffer is located. --- src/gl/data/gl_vertexbuffer.cpp | 57 +++++++++++++-------------------- src/gl/data/gl_vertexbuffer.h | 9 +----- src/gl/system/gl_interface.cpp | 13 ++++++++ src/gl/system/gl_interface.h | 9 ++++++ 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 96343b284..dd3854596 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -78,9 +78,9 @@ FVertexBuffer::~FVertexBuffer() //========================================================================== FFlatVertexBuffer::FFlatVertexBuffer() -: FVertexBuffer(!!(gl.flags & RFL_BUFFER_STORAGE)) +: FVertexBuffer(gl.buffermethod == BM_PERSISTENT) { - if (gl.flags & RFL_BUFFER_STORAGE) + if (gl.buffermethod == BM_PERSISTENT) { unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex); glBindBuffer(GL_ARRAY_BUFFER, vbo_id); @@ -91,19 +91,24 @@ FFlatVertexBuffer::FFlatVertexBuffer() { // The fallback path uses immediate mode rendering and does not set up an actual vertex buffer vbo_shadowdata.Reserve(BUFFER_SIZE); - map = &vbo_shadowdata[0]; + map = new FFlatVertex[BUFFER_SIZE]; } mNumReserved = mIndex = mCurIndex = 0; } FFlatVertexBuffer::~FFlatVertexBuffer() { - if (gl.flags & RFL_BUFFER_STORAGE) + if (vbo_id != 0) { glBindBuffer(GL_ARRAY_BUFFER, vbo_id); glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); } + else + { + delete[] map; + } + map = nullptr; } @@ -116,14 +121,15 @@ void FFlatVertexBuffer::BindVBO() { glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u); - glEnableVertexAttribArray(VATTR_VERTEX); - glEnableVertexAttribArray(VATTR_TEXCOORD); } else { - glDisableVertexAttribArray(VATTR_VERTEX); - glDisableVertexAttribArray(VATTR_TEXCOORD); + // If we cannot use a hardware buffer, use an old-style client array. + glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &map->x); + glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &map->u); } + glEnableVertexAttribArray(VATTR_VERTEX); + glEnableVertexAttribArray(VATTR_TEXCOORD); glDisableVertexAttribArray(VATTR_COLOR); glDisableVertexAttribArray(VATTR_VERTEX2); } @@ -346,24 +352,10 @@ void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) void FFlatVertexBuffer::CreateVBO() { - if (gl.flags & RFL_BUFFER_STORAGE) - { - vbo_shadowdata.Resize(mNumReserved); - CreateFlatVBO(); - mCurIndex = mIndex = vbo_shadowdata.Size(); - memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex)); - } - else if (sectors) - { - // set all VBO info to invalid values so that we can save some checks in the rendering code - for(int i=0;iGetHeightSec(); - if (hs != NULL) CheckPlanes(hs); - for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++) - CheckPlanes(sector->e->XFloor.ffloors[i]->model); - } + CheckPlanes(sector); + sector_t *hs = sector->GetHeightSec(); + if (hs != NULL) CheckPlanes(hs); + for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++) + CheckPlanes(sector->e->XFloor.ffloors[i]->model); } \ No newline at end of file diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 6420e8fc8..c82ea707b 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -85,14 +85,7 @@ public: void RenderArray(unsigned int primtype, unsigned int offset, unsigned int count) { drawcalls.Clock(); - if (gl.flags & RFL_BUFFER_STORAGE) - { - glDrawArrays(primtype, offset, count); - } - else - { - ImmRenderBuffer(primtype, offset, count); - } + glDrawArrays(primtype, offset, count); drawcalls.Unclock(); } diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index ced1b8b4a..beb636d9c 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -167,6 +167,7 @@ void gl_LoadExtensions() gl.vendorstring = (char*)glGetString(GL_VENDOR); gl.lightmethod = LM_SOFTWARE; + gl.buffermethod = BM_CLIENTARRAY; if ((gl.version >= 3.3f || CheckExtension("GL_ARB_sampler_objects")) && !Args->CheckParm("-nosampler")) { @@ -177,6 +178,10 @@ void gl_LoadExtensions() if (gl.version > 3.0f && (gl.version >= 3.3f || CheckExtension("GL_ARB_uniform_buffer_object"))) { gl.lightmethod = LM_DEFERRED; + // Only Apple requires the core profile for GL 3.x+. + // #ifdef __APPLE__ + // gl.buffermethod = BM_DEFERRED; + // #endif } if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION; @@ -222,6 +227,7 @@ void gl_LoadExtensions() } gl.flags |= RFL_BUFFER_STORAGE; gl.lightmethod = LM_DIRECT; + gl.buffermethod = BM_PERSISTENT; } else { @@ -236,6 +242,13 @@ void gl_LoadExtensions() if (!stricmp(lm, "textured")) gl.lightmethod = LM_SOFTWARE; } + lm = Args->CheckValue("-buffermethod"); + if (lm != NULL) + { + //if (!stricmp(lm, "deferred") && gl.buffermethod == BM_PERSISTENT) gl.buffermethod = BM_DEFERRED; + if (!stricmp(lm, "clientarray")) gl.buffermethod = BM_CLIENTARRAY; + } + int v; if (gl.lightmethod != LM_SOFTWARE && !(gl.flags & RFL_SHADER_STORAGE_BUFFER)) diff --git a/src/gl/system/gl_interface.h b/src/gl/system/gl_interface.h index 1813e2c7f..d43252ebc 100644 --- a/src/gl/system/gl_interface.h +++ b/src/gl/system/gl_interface.h @@ -44,6 +44,14 @@ enum ELightMethod LM_DIRECT = 2, // calculate lights on the fly along with the render data }; +enum EBufferMethod +{ + BM_CLIENTARRAY = 0, // use a client array instead of a hardware buffer + BM_DEFERRED = 1, // use a temporarily mapped buffer (only necessary on GL 3.x core profile, i.e. Apple) + BM_PERSISTENT = 2 // use a persistently mapped buffer +}; + + struct RenderContext { unsigned int flags; @@ -51,6 +59,7 @@ struct RenderContext unsigned int maxuniformblock; unsigned int uniformblockalignment; int lightmethod; + int buffermethod; float version; float glslversion; int max_texturesize; From 7576e85cef145ca38607d560841d01a72f6d771f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Aug 2016 13:06:55 +0200 Subject: [PATCH 21/53] - force use of shaders on all hardware, unless -noshader is specified. Right it's only for easy testing, so only the code that does the feature checking has been disabled. --- src/gl/system/gl_interface.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index beb636d9c..bf926cd93 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -187,7 +187,7 @@ void gl_LoadExtensions() if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION; if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags |= RFL_TEXTURE_COMPRESSION_S3TC; - if (Args->CheckParm("-noshader") || gl.glslversion < 1.2f) + if (Args->CheckParm("-noshader")/* || gl.glslversion < 1.2f*/) { gl.version = 2.11f; gl.glslversion = 0; @@ -195,8 +195,9 @@ void gl_LoadExtensions() } else if (gl.version < 3.0f) { - if (CheckExtension("GL_NV_GPU_shader4") || CheckExtension("GL_EXT_GPU_shader4")) gl.glslversion = 1.21f; // for pre-3.0 drivers that support capable hardware. Needed for Apple. - else gl.glslversion = 0; + //if (CheckExtension("GL_NV_GPU_shader4") || CheckExtension("GL_EXT_GPU_shader4")) gl.glslversion = 1.21f; // for pre-3.0 drivers that support capable hardware. Needed for Apple. + //else gl.glslversion = 0; + gl.glslversion = 1.21f; if (!CheckExtension("GL_EXT_packed_float")) gl.flags |= RFL_NO_RGBA16F; if (!CheckExtension("GL_EXT_packed_depth_stencil")) gl.flags |= RFL_NO_DEPTHSTENCIL; From 6a66d0255db59e0b72dfb95d05b8640c4e57858d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Aug 2016 14:12:40 +0200 Subject: [PATCH 22/53] - use a dedicated vertex buffer for rendering the wipes. - fixed: The postprocessing shaders clobbered the render state's vertex buffer info by bypassing and not notifying it of the change. --- src/gl/data/gl_vertexbuffer.h | 10 -- src/gl/renderer/gl_postprocess.cpp | 29 +++-- src/gl/renderer/gl_renderer.h | 1 + src/gl/system/gl_framebuffer.h | 8 ++ src/gl/system/gl_interface.cpp | 1 - src/gl/system/gl_wipe.cpp | 203 +++++++++++++++++++---------- 6 files changed, 160 insertions(+), 92 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index c82ea707b..edb38733a 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -98,16 +98,6 @@ public: if (pcount) *pcount = count; } - void RenderScreenQuad(float maxU = 1.0f, float maxV = 1.0f) - { - FFlatVertex *ptr = GetBuffer(); - ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; - ptr->Set(-1.0f, 1.0f, 0, 0.0f, maxV); ptr++; - ptr->Set(1.0f, -1.0f, 0, maxU, 0.0f); ptr++; - ptr->Set(1.0f, 1.0f, 0, maxU, maxV); ptr++; - RenderCurrent(ptr, GL_TRIANGLE_STRIP); - } - #endif void Reset() { diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index da7031afe..a997f5b47 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -106,6 +106,19 @@ CVAR(Float, gl_lens_chromatic, 1.12f, 0) EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) + +void FGLRenderer::RenderScreenQuad(float maxU, float maxV) +{ + FFlatVertex *ptr = mVBO->GetBuffer(); + mVBO->BindVBO(); + gl_RenderState.ResetVertexBuffer(); + ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; + ptr->Set(-1.0f, 1.0f, 0, 0.0f, maxV); ptr++; + ptr->Set(1.0f, -1.0f, 0, maxU, 0.0f); ptr++; + ptr->Set(1.0f, 1.0f, 0, maxU, maxV); ptr++; + mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); +} + //----------------------------------------------------------------------------- // // Adds bloom contribution to scene texture @@ -134,8 +147,7 @@ void FGLRenderer::BloomScene() mBloomExtractShader->Bind(); mBloomExtractShader->SceneTexture.Set(0); mBloomExtractShader->Exposure.Set(mCameraExposure); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -166,7 +178,7 @@ void FGLRenderer::BloomScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mBloomCombineShader->Bind(); mBloomCombineShader->BloomTexture.Set(0); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); } mBlurShader->BlurHorizontal(mVBO, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height); @@ -184,7 +196,7 @@ void FGLRenderer::BloomScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mBloomCombineShader->Bind(); mBloomCombineShader->BloomTexture.Set(0); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); } //----------------------------------------------------------------------------- @@ -205,8 +217,7 @@ void FGLRenderer::TonemapScene() mTonemapShader->Bind(); mTonemapShader->SceneTexture.Set(0); mTonemapShader->Exposure.Set(mCameraExposure); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); mBuffers->NextTexture(); } @@ -258,8 +269,7 @@ void FGLRenderer::LensDistortScene() mLensShader->Scale.Set(scale); mLensShader->LensDistortionCoefficient.Set(k); mLensShader->CubicDistortionValue.Set(kcube); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(); + RenderScreenQuad(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mBuffers->NextTexture(); @@ -348,7 +358,6 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - mVBO->BindVBO(); - mVBO->RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); + RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); } } diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 9be66bbfb..9caace177 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -157,6 +157,7 @@ public: unsigned char *GetTextureBuffer(FTexture *tex, int &w, int &h); void SetupLevel(); + void RenderScreenQuad(float maxU = 1.0f, float maxV = 1.0f); void SetFixedColormap (player_t *player); void WriteSavePic (player_t *player, FILE *file, int width, int height); void EndDrawScene(sector_t * viewsector); diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 3da60fac4..2ba90ff5b 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -94,7 +94,15 @@ private: class Wiper { + class WipeVertexBuffer; + + protected: + WipeVertexBuffer *mVertexBuf; + + void MakeVBO(OpenGLFrameBuffer *fb); + public: + Wiper(); virtual ~Wiper(); virtual bool Run(int ticks, OpenGLFrameBuffer *fb) = 0; }; diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index bf926cd93..6b1105ee4 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -197,7 +197,6 @@ void gl_LoadExtensions() { //if (CheckExtension("GL_NV_GPU_shader4") || CheckExtension("GL_EXT_GPU_shader4")) gl.glslversion = 1.21f; // for pre-3.0 drivers that support capable hardware. Needed for Apple. //else gl.glslversion = 0; - gl.glslversion = 1.21f; if (!CheckExtension("GL_EXT_packed_float")) gl.flags |= RFL_NO_RGBA16F; if (!CheckExtension("GL_EXT_packed_depth_stencil")) gl.flags |= RFL_NO_DEPTHSTENCIL; diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index 0d1973131..bc1708061 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -97,6 +97,7 @@ class OpenGLFrameBuffer::Wiper_Melt : public OpenGLFrameBuffer::Wiper { public: Wiper_Melt(); + int MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done); bool Run(int ticks, OpenGLFrameBuffer *fb); private: @@ -217,29 +218,28 @@ void OpenGLFrameBuffer::WipeEndScreen() bool OpenGLFrameBuffer::WipeDo(int ticks) { + bool done = true; // Sanity checks. - if (wipestartscreen == NULL || wipeendscreen == NULL) + if (wipestartscreen != nullptr && wipeendscreen != nullptr) { - return true; + Lock(true); + + gl_RenderState.EnableTexture(true); + gl_RenderState.EnableFog(false); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + + if (FGLRenderBuffers::IsEnabled()) + { + GLRenderer->mBuffers->BindCurrentFB(); + const auto &bounds = GLRenderer->mScreenViewport; + glViewport(bounds.left, bounds.top, bounds.width, bounds.height); + } + + done = ScreenWipe->Run(ticks, this); + glDepthMask(true); } - - Lock(true); - - gl_RenderState.EnableTexture(true); - gl_RenderState.EnableFog(false); - glDisable(GL_DEPTH_TEST); - glDepthMask(false); - - if (FGLRenderBuffers::IsEnabled()) - { - GLRenderer->mBuffers->BindCurrentFB(); - const auto &bounds = GLRenderer->mScreenViewport; - glViewport(bounds.left, bounds.top, bounds.width, bounds.height); - } - - bool done = ScreenWipe->Run(ticks, this); - glDepthMask(true); - //DrawLetterbox(); + gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); return done; } @@ -273,12 +273,80 @@ void OpenGLFrameBuffer::WipeCleanup() //========================================================================== // -// OpenGLFrameBuffer :: Wiper Constructor +// The wiper vertex buffer +// +// Note that this will recreate the buffer each frame, although +// only for melt its contents will change. +// +// But since this is no time critical code, ease of implementation +// was chosen over maximum efficiency. // //========================================================================== +class OpenGLFrameBuffer::Wiper::WipeVertexBuffer : public FVertexBuffer +{ +public: + WipeVertexBuffer() + { + } + void BindVBO() + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + if (gl.glslversion > 0) + { + glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); + glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u); + glDisableVertexAttribArray(VATTR_COLOR); + glDisableVertexAttribArray(VATTR_VERTEX2); + } + else + { + glVertexPointer(3, GL_FLOAT, sizeof(FFlatVertex), &VTO->x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FFlatVertex), &VTO->u); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } + } + void set(FFlatVertex *verts, int count) + { + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + gl_RenderState.SetVertexBuffer(this); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(*verts), verts, GL_STREAM_DRAW); + } +}; + +//========================================================================== +// +// OpenGLFrameBuffer :: Wiper Constructor +// +//========================================================================== +OpenGLFrameBuffer::Wiper::Wiper() +{ + mVertexBuf = new WipeVertexBuffer; +} + OpenGLFrameBuffer::Wiper::~Wiper() { + delete mVertexBuf; +} + +void OpenGLFrameBuffer::Wiper::MakeVBO(OpenGLFrameBuffer *fb) +{ + FFlatVertex make[4]; + FFlatVertex *ptr = make; + + float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); + float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); + + ptr->Set(0, 0, 0, 0, vb); + ptr++; + ptr->Set(0, fb->Height, 0, 0, 0); + ptr++; + ptr->Set(fb->Width, 0, 0, ur, vb); + ptr++; + ptr->Set(fb->Width, fb->Height, 0, ur, 0); + mVertexBuf->set(make, 4); } // WIPE: CROSSFADE --------------------------------------------------------- @@ -306,32 +374,21 @@ bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb) { Clock += ticks; - float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); - float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); + MakeVBO(fb); gl_RenderState.SetTextureMode(TM_OPAQUE); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); gl_RenderState.ResetColor(); gl_RenderState.Apply(); fb->wipestartscreen->Bind(0, 0, false); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - FFlatVertex *ptr; - unsigned int offset, count; - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(0, 0, 0, 0, vb); - ptr++; - ptr->Set(0, fb->Height, 0, 0, 0); - ptr++; - ptr->Set(fb->Width, 0, 0, ur, vb); - ptr++; - ptr->Set(fb->Width, fb->Height, 0, ur, 0); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count); - - fb->wipeendscreen->Bind(0, 0, false); - gl_RenderState.SetColorAlpha(0xffffff, clamp(Clock/32.f, 0.f, 1.f)); + float a = clamp(Clock / 32.f, 0.f, 1.f); + Printf("%f\n", a); + gl_RenderState.SetColorAlpha(0xffffff, a); gl_RenderState.Apply(); - GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count); + fb->wipeendscreen->Bind(0, 0, false); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f); gl_RenderState.SetTextureMode(TM_MODULATE); @@ -366,18 +423,15 @@ OpenGLFrameBuffer::Wiper_Melt::Wiper_Melt() // //========================================================================== -bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) +int OpenGLFrameBuffer::Wiper_Melt::MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done) { + FFlatVertex *make = new FFlatVertex[321*4]; + FFlatVertex *ptr = make; + int dy; + float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); - // Draw the new screen on the bottom. - gl_RenderState.SetTextureMode(TM_OPAQUE); - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - fb->wipeendscreen->Bind(0, 0, false); - FFlatVertex *ptr; - ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(0, 0, 0, 0, vb); ptr++; ptr->Set(0, fb->Height, 0, 0, 0); @@ -386,31 +440,26 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) ptr++; ptr->Set(fb->Width, fb->Height, 0, ur, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - int i, dy; - bool done = false; - - fb->wipestartscreen->Bind(0, 0, false); // Copy the old screen in vertical strips on top of the new one. while (ticks--) { done = true; - for (i = 0; i < WIDTH; i++) + for (int i = 0; i < WIDTH; i++) { if (y[i] < 0) { y[i]++; done = false; - } + } else if (y[i] < HEIGHT) { - dy = (y[i] < 16) ? y[i]+1 : 8; + dy = (y[i] < 16) ? y[i] + 1 : 8; y[i] = MIN(y[i] + dy, HEIGHT); done = false; } if (ticks == 0) - { + { // Only draw for the final tick. // No need for optimization. Wipes won't ever be drawn with anything else. RECT rect; @@ -429,7 +478,6 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) rect.bottom = fb->Height - rect.bottom; rect.top = fb->Height - rect.top; - ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(rect.left, rect.bottom, 0, rect.left / tw, rect.top / th); ptr++; ptr->Set(rect.left, rect.top, 0, rect.left / tw, rect.bottom / th); @@ -438,12 +486,34 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) ptr++; ptr->Set(rect.right, rect.top, 0, rect.right / tw, rect.bottom / th); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); } } } } + int numverts = int(ptr - make); + mVertexBuf->set(make, numverts); + delete[] make; + return numverts; +} + +bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb) +{ + bool done = false; + int maxvert = MakeVBO(ticks, fb, done); + + // Draw the new screen on the bottom. + gl_RenderState.SetTextureMode(TM_OPAQUE); + gl_RenderState.ResetColor(); + gl_RenderState.Apply(); + fb->wipeendscreen->Bind(0, 0, false); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + fb->wipestartscreen->Bind(0, 0, false); gl_RenderState.SetTextureMode(TM_MODULATE); + for (int i = 4; i < maxvert; i += 4) + { + glDrawArrays(GL_TRIANGLE_STRIP, i, 4); + } return done; } @@ -486,6 +556,8 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) { bool done; + MakeVBO(fb); + BurnTime += ticks; ticks *= 2; @@ -524,18 +596,7 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) gl_RenderState.ResetColor(); gl_RenderState.Apply(); fb->wipestartscreen->Bind(0, 0, false); - FFlatVertex *ptr; - unsigned int offset, count; - ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(0, 0, 0, 0, vb); - ptr++; - ptr->Set(0, fb->Height, 0, 0, 0); - ptr++; - ptr->Set(fb->Width, 0, 0, ur, vb); - ptr++; - ptr->Set(fb->Width, fb->Height, 0, ur, 0); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.SetEffect(EFF_BURN); @@ -547,7 +608,7 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0); - GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); gl_RenderState.SetEffect(EFF_NONE); // The fire may not always stabilize, so the wipe is forced to end From 8f0629932d4849550253d248473ca9c68189723b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Aug 2016 14:29:21 +0200 Subject: [PATCH 23/53] - ImmRenderBuffer is not needed anymore. --- src/gl/data/gl_vertexbuffer.cpp | 34 --------------------------------- src/gl/data/gl_vertexbuffer.h | 2 -- 2 files changed, 36 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index dd3854596..fc17f7ff8 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -141,40 +141,6 @@ void FFlatVertexBuffer::BindVBO() } } -//========================================================================== -// -// immediate mode fallback for drivers without GL_ARB_buffer_storage -// -// No single core method is performant enough to handle this adequately -// so we have to resort to immediate mode instead... -// -//========================================================================== - -void FFlatVertexBuffer::ImmRenderBuffer(unsigned int primtype, unsigned int offset, unsigned int count) -{ - // this will only get called if we can't acquire a persistently mapped buffer. -#ifndef CORE_PROFILE - glBegin(primtype); - if (gl.glslversion > 0) - { - for (unsigned int i = 0; i < count; i++) - { - glVertexAttrib2fv(VATTR_TEXCOORD, &map[offset + i].u); - glVertexAttrib3fv(VATTR_VERTEX, &map[offset + i].x); - } - } - else // no shader means no vertex attributes, so use the old stuff instead. - { - for (unsigned int i = 0; i < count; i++) - { - glTexCoord2fv(&map[offset + i].u); - glVertex3fv(&map[offset + i].x); - } - } - glEnd(); -#endif -} - //========================================================================== // // Initialize a single vertex diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index edb38733a..0223c5791 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -54,8 +54,6 @@ class FFlatVertexBuffer : public FVertexBuffer static const unsigned int BUFFER_SIZE = 2000000; static const unsigned int BUFFER_SIZE_TO_USE = 1999500; - void ImmRenderBuffer(unsigned int primtype, unsigned int offset, unsigned int count); - public: TArray vbo_shadowdata; // this is kept around for updating the actual (non-readable) buffer and as stand-in for pre GL 4.x From fd7b833ad568386086d2101f7f8403dda405d919 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Aug 2016 19:20:41 +0200 Subject: [PATCH 24/53] - added some helper code mainly designed to help GZDoom maintain the vertex buffer for the textured automap. --- src/am_map.cpp | 2 ++ src/v_draw.cpp | 13 +++++++++++++ src/v_video.h | 3 +++ 3 files changed, 18 insertions(+) diff --git a/src/am_map.cpp b/src/am_map.cpp index 3a4e0aaa1..7e346843b 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1897,6 +1897,7 @@ void AM_drawSubsectors() FDynamicColormap *colormap; mpoint_t originpt; + screen->StartSimplePolys(); for (int i = 0; i < numsubsectors; ++i) { if (subsectors[i].flags & SSECF_POLYORG) @@ -2049,6 +2050,7 @@ void AM_drawSubsectors() ); } } + screen->FinishSimplePolys(); } //============================================================================= diff --git a/src/v_draw.cpp b/src/v_draw.cpp index c7b62b0a6..89023d4bd 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1244,6 +1244,19 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin } } +//========================================================================== +// +// no-ops. This is so that renderer backends can better manage the +// processing of the subsector drawing in the automap +// +//========================================================================== + +void DCanvas::StartSimplePolys() +{} + +void DCanvas::FinishSimplePolys() +{} + //========================================================================== // // DCanvas :: FillSimplePoly diff --git a/src/v_video.h b/src/v_video.h index fa1ce83df..7091c518d 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -216,6 +216,9 @@ public: // Fill an area with a texture virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false); + virtual void StartSimplePolys(); + virtual void FinishSimplePolys(); + // Fill a simple polygon with a texture virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, From 04c59b434bc722147fbaab75bbd621174b38c796 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Aug 2016 00:40:31 +0200 Subject: [PATCH 25/53] - renamed WipeVertexBuffer to FSimpleVertexBuffer because this will be useful elsewhere, too. --- src/gl/data/gl_vertexbuffer.cpp | 28 ++++++++++++++++++++ src/gl/data/gl_vertexbuffer.h | 10 +++++++ src/gl/system/gl_framebuffer.h | 4 +-- src/gl/system/gl_wipe.cpp | 47 +-------------------------------- 4 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index fc17f7ff8..2f38a720e 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -71,6 +71,34 @@ FVertexBuffer::~FVertexBuffer() } } + +void FSimpleVertexBuffer::BindVBO() +{ + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + if (gl.glslversion > 0) + { + glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); + glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u); + glDisableVertexAttribArray(VATTR_COLOR); + glDisableVertexAttribArray(VATTR_VERTEX2); + } + else + { + glVertexPointer(3, GL_FLOAT, sizeof(FFlatVertex), &VTO->x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FFlatVertex), &VTO->u); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } +} + +void FSimpleVertexBuffer::set(FFlatVertex *verts, int count) +{ + glBindBuffer(GL_ARRAY_BUFFER, vbo_id); + gl_RenderState.SetVertexBuffer(this); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(*verts), verts, GL_STREAM_DRAW); +} + //========================================================================== // // diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 0223c5791..4d39a7f58 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -41,6 +41,16 @@ struct FFlatVertex #define VTO ((FFlatVertex*)NULL) +class FSimpleVertexBuffer : public FVertexBuffer +{ + TArray mBuffer; +public: + FSimpleVertexBuffer() + { + } + void BindVBO(); + void set(FFlatVertex *verts, int count); +}; class FFlatVertexBuffer : public FVertexBuffer { diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 2ba90ff5b..d648da30c 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -7,6 +7,7 @@ #endif class FHardwareTexture; +class FSimpleVertexBuffer; extern long gl_frameMS; extern long gl_frameCount; @@ -94,10 +95,9 @@ private: class Wiper { - class WipeVertexBuffer; protected: - WipeVertexBuffer *mVertexBuf; + FSimpleVertexBuffer *mVertexBuf; void MakeVBO(OpenGLFrameBuffer *fb); diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index bc1708061..2978dd55d 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -271,51 +271,6 @@ void OpenGLFrameBuffer::WipeCleanup() FMaterial::ClearLastTexture(); } -//========================================================================== -// -// The wiper vertex buffer -// -// Note that this will recreate the buffer each frame, although -// only for melt its contents will change. -// -// But since this is no time critical code, ease of implementation -// was chosen over maximum efficiency. -// -//========================================================================== - -class OpenGLFrameBuffer::Wiper::WipeVertexBuffer : public FVertexBuffer -{ -public: - WipeVertexBuffer() - { - } - void BindVBO() - { - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - if (gl.glslversion > 0) - { - glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); - glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u); - glDisableVertexAttribArray(VATTR_COLOR); - glDisableVertexAttribArray(VATTR_VERTEX2); - } - else - { - glVertexPointer(3, GL_FLOAT, sizeof(FFlatVertex), &VTO->x); - glTexCoordPointer(2, GL_FLOAT, sizeof(FFlatVertex), &VTO->u); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - } - } - void set(FFlatVertex *verts, int count) - { - glBindBuffer(GL_ARRAY_BUFFER, vbo_id); - gl_RenderState.SetVertexBuffer(this); - glBufferData(GL_ARRAY_BUFFER, count * sizeof(*verts), verts, GL_STREAM_DRAW); - } -}; - //========================================================================== // // OpenGLFrameBuffer :: Wiper Constructor @@ -323,7 +278,7 @@ public: //========================================================================== OpenGLFrameBuffer::Wiper::Wiper() { - mVertexBuf = new WipeVertexBuffer; + mVertexBuf = new FSimpleVertexBuffer; } OpenGLFrameBuffer::Wiper::~Wiper() From d4615861aef3655156ae11142765ff8ec311ae1b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 6 Aug 2016 23:42:37 +0200 Subject: [PATCH 26/53] Fix missing FGLRenderBuffers::IsEnabled checks --- src/gl/renderer/gl_postprocess.cpp | 4 ++-- src/gl/renderer/gl_renderbuffers.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index a997f5b47..f249aa1cc 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -207,7 +207,7 @@ void FGLRenderer::BloomScene() void FGLRenderer::TonemapScene() { - if (gl_tonemap == 0) + if (gl_tonemap == 0 || !FGLRenderBuffers::IsEnabled()) return; FGLPostProcessState savedState; @@ -229,7 +229,7 @@ void FGLRenderer::TonemapScene() void FGLRenderer::LensDistortScene() { - if (gl_lens == 0) + if (gl_lens == 0 || !FGLRenderBuffers::IsEnabled()) return; float k[4] = diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 490d73ed0..3b402d801 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -141,6 +141,9 @@ void FGLRenderBuffers::DeleteFrameBuffer(GLuint &handle) void FGLRenderBuffers::Setup(int width, int height) { + if (!IsEnabled()) + return; + int samples = GetCvarSamples(); if (width == mWidth && height == mHeight && mSamples != samples) From 5b079dd40bbbd83617e62b66c62a04c26dd57023 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 6 Aug 2016 17:47:33 +0300 Subject: [PATCH 27/53] Fixed wrong height of player coordinates text --- src/g_shared/shared_hud.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index c9e87d642..cddc86ee4 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -891,16 +891,16 @@ static void DrawCoordinates(player_t * CPlayer) default: case 0: vwidth = SCREENWIDTH; - vheight = SCREENWIDTH; + vheight = SCREENHEIGHT; break; case 1: case 2: vwidth = SCREENWIDTH/2; - vheight = SCREENWIDTH/2; + vheight = SCREENHEIGHT/2; break; case 3: vwidth = SCREENWIDTH/4; - vheight = SCREENWIDTH/4; + vheight = SCREENHEIGHT/4; break; } From 5a66fdf9be3f2dfac07d80b7761b82a8802ef76d Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Sun, 7 Aug 2016 20:55:16 +0200 Subject: [PATCH 28/53] - Hide Clang -Winconsistent-missing-override warnings in non-Apple targets, too. --- src/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5fe947ef8..f6caa2f5d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -484,8 +484,10 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" ) endif() - if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" ) + if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) + if( APPLE OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.6" ) + set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" ) + endif() endif() set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" ) From ab837b608d2ad3dba4f9be2a1749a53f8048d0c9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Aug 2016 22:03:36 +0200 Subject: [PATCH 29/53] - compatibility optioned triggering sector actions by indirectly initiated teleports There's several old maps depending on this not happening. - Set the option for Hell's Twisted Influence Part 1. --- src/compatibility.cpp | 1 + src/d_main.cpp | 3 ++- src/doomdef.h | 1 + src/g_mapinfo.cpp | 1 + src/p_map.cpp | 3 ++- wadsrc/static/compatibility.txt | 5 +++++ 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index ae3b905d0..870d2ede6 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -147,6 +147,7 @@ static FCompatOption Options[] = { "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 }, { "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 }, { "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 }, + { "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 }, { NULL, 0, 0 } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index d6d53dd77..4e360a38e 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -574,7 +574,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) case 4: // Old ZDoom compat mode v = COMPATF_SOUNDTARGET | COMPATF_LIGHT; - w = COMPATF2_MULTIEXIT; + w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT; break; case 5: // MBF compat mode @@ -630,6 +630,7 @@ CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE); CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF); CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE); CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT); +CVAR (Flag, compat_teleport, compatflags2, COMPATF2_TELEPORT); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index 56b69fe7c..9ebe45cf7 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -342,6 +342,7 @@ enum : unsigned int COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat() COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script) + COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions }; // Emulate old bugs for select maps. These are not exposed by a cvar diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 78ba9142b..7d3df69e0 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1341,6 +1341,7 @@ MapFlagHandlers[] = { "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF }, { "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE }, { "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT }, + { "compat_teleport", MITYPE_COMPATFLAG, 0, COMPATF2_TELEPORT }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/p_map.cpp b/src/p_map.cpp index 110ae5235..e7aceba78 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -434,7 +434,8 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi // If this teleport was caused by a move, P_TryMove() will handle the // sector transition messages better than we can here. - if (!(thing->flags6 & MF6_INTRYMOVE)) + // This needs to be compatibility optioned because some older maps exploited this missing feature. + if (!(thing->flags6 & MF6_INTRYMOVE) && !(i_compatflags2 & COMPATF2_TELEPORT)) { thing->CheckSectorTransition(oldsec); } diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index a2c3794ae..25395dad6 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -430,6 +430,11 @@ C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07 maskedmidtex } +7B82B12A6990E09553B12FDB4E3824A0 // hti.wad map01 +{ + teleport +} + D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update { From 078881a941958b92d76e10d87370fdc00971801d Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:07:51 +0200 Subject: [PATCH 30/53] Parse statements as expressions in sequences This will be needed for assignment operators to work --- src/thingdef/thingdef_states.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index ecc62bf29..652bdf9e9 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -539,7 +539,8 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B sc.MustGetString(); if (!sc.Compare(";")) { - init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now. + sc.UnGet(); + init = ParseExpression(sc, bag.Info); sc.MustGetStringName(";"); } sc.MustGetString(); @@ -552,7 +553,8 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B sc.MustGetString(); if (!sc.Compare(")")) { - iter = ParseAction(sc, state, statestring, bag); + sc.UnGet(); + iter = ParseExpression(sc, bag.Info); sc.MustGetStringName(")"); } @@ -641,8 +643,9 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg sc.MustGetString(); } else - { // Handle a regular action function call - add = ParseAction(sc, state, statestring, bag); + { // Handle a regular expression + sc.UnGet(); + add = ParseExpression(sc, bag.Info); sc.MustGetStringName(";"); sc.MustGetString(); } From a4142ad9fba4fb26eea2b60277012d6f78dc7766 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Thu, 4 Aug 2016 02:39:00 +0200 Subject: [PATCH 31/53] Re-allow action function calls with no argument list in sequences --- src/thingdef/thingdef_exp.cpp | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 6a756d9b5..b83796860 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -374,6 +374,29 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) case NAME_Random2: return ParseRandom2(sc, cls); default: + if (cls != nullptr) + { + func = dyn_cast(cls->Symbols.FindSymbol(identifier, true)); + + // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. + if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult) + { + args = new FArgumentList; + if (sc.CheckToken('(')) + { + sc.UnGet(); + ParseFunctionParameters(sc, cls, *args, func, "", nullptr); + } + if (args->Size() == 0) + { + delete args; + args = nullptr; + } + + return new FxVMFunctionCall(func, args, sc); + } + } + break; } if (sc.CheckToken('(')) @@ -392,17 +415,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) return ParseAtan2(sc, identifier, cls); default: args = new FArgumentList; - func = (cls == nullptr) ? nullptr : dyn_cast(cls->Symbols.FindSymbol(identifier, true)); try { - // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. - if (func != NULL && identifier != NAME_ACS_NamedExecuteWithResult) - { - sc.UnGet(); - ParseFunctionParameters(sc, cls, *args, func, "", NULL); - return new FxVMFunctionCall(func, args, sc); - } - else if (!sc.CheckToken(')')) + if (!sc.CheckToken(')')) { do { From db9f4c13857f785b589bfdb01684c38557611a79 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:26:33 +0200 Subject: [PATCH 32/53] Re-allow indexes as state parameter in sequences --- src/namedef.h | 1 + src/thingdef/thingdef_exp.h | 18 ++++++ src/thingdef/thingdef_expression.cpp | 83 ++++++++++++++++++++++++++++ src/thingdef/thingdef_parse.cpp | 29 ++++++---- 4 files changed, 120 insertions(+), 11 deletions(-) diff --git a/src/namedef.h b/src/namedef.h index cd0d5615b..e5b6c452a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -654,6 +654,7 @@ xx(DecoCallLineSpecial) xx(DecoNameToClass) xx(DecoFindMultiNameState) xx(DecoFindSingleNameState) +xx(DecoHandleRuntimeState) xx(Damage) // basic type names diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index b878e50f1..c1e8863e8 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -1058,6 +1058,24 @@ public: FxExpression *Resolve(FCompileContext&); }; +//========================================================================== +// +// Same as above except for expressions which means it will have to be +// evaluated at runtime +// +//========================================================================== + +class FxRuntimeStateIndex : public FxExpression +{ + FxExpression *Index; + +public: + FxRuntimeStateIndex(FxExpression *index); + ~FxRuntimeStateIndex(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index b57618575..d40b7605c 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -4428,7 +4428,90 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) delete this; return x; } + +//========================================================================== +// +// +// +//========================================================================== + +FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) +: FxExpression(index->ScriptPosition), Index(index) +{ + ValueType = TypeState; +} + +FxRuntimeStateIndex::~FxRuntimeStateIndex() +{ + SAFE_DELETE(Index); +} + +FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Index, ctx); + + if (!Index->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Index->ValueType->GetRegType() != REGT_INT) + { // Float. + Index = new FxIntCast(Index); + SAFE_RESOLVE(Index, ctx); + } + + return this; +} + +static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(stateowner, AActor); + PARAM_POINTER(stateinfo, FStateParamInfo); + PARAM_INT(index); + + if (index == 0 || !stateowner->GetClass()->OwnsState(stateinfo->mCallingState + index)) + { + // Null is returned if the location was invalid which means that no jump will be performed + // if used as return value + // 0 always meant the same thing so we handle it here for compatibility + ret->SetPointer(nullptr, ATAG_STATE); + } + else + { + ret->SetPointer(stateinfo->mCallingState + index, ATAG_STATE); + } + + return 1; +} + +ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) +{ + assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + + ExpEmit out(build, REGT_POINTER); + + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // stateowner + build->Emit(OP_PARAM, 0, REGT_POINTER, 2); // stateinfo + ExpEmit id = Index->Emit(build); + build->Emit(OP_PARAM, 0, REGT_INT | (id.Konst ? REGT_KONST : 0), id.RegNum); // index + + VMFunction *callfunc; + PSymbol *sym; + sym = FindDecorateBuiltinFunction(NAME_DecoHandleRuntimeState, DecoHandleRuntimeState); + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); + + return out; +} //========================================================================== // diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 566643b8e..b99f1a384 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -138,23 +138,30 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c else if (type == TypeState) { // This forces quotation marks around the state name. - sc.MustGetToken(TK_StringConst); - if (sc.String[0] == 0 || sc.Compare("None")) + if (sc.CheckToken(TK_StringConst)) { - x = new FxConstant((FState*)NULL, sc); - } - else if (sc.Compare("*")) - { - if (constant) + if (sc.String[0] == 0 || sc.Compare("None")) { - x = new FxConstant((FState*)(intptr_t)-1, sc); + x = new FxConstant((FState*)NULL, sc); + } + else if (sc.Compare("*")) + { + if (constant) + { + x = new FxConstant((FState*)(intptr_t)-1, sc); + } + else sc.ScriptError("Invalid state name '*'"); + } + else + { + x = new FxMultiNameState(sc.String, sc); } - else sc.ScriptError("Invalid state name '*'"); } - else + else if (!constant) { - x = new FxMultiNameState(sc.String, sc); + x = new FxRuntimeStateIndex(ParseExpression(sc, cls)); } + else sc.MustGetToken(TK_StringConst); // This is for the error. } else if (type->GetClass() == RUNTIME_CLASS(PClassPointer)) { // Actor name From 2ef51d0d501dccf4d2151f0a2cc85802e7758153 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:32:01 +0200 Subject: [PATCH 33/53] Re-allow casts in sequences --- src/thingdef/thingdef_exp.cpp | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index b83796860..265917175 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -357,6 +357,49 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) // a cheap way to get them working when people use "name" instead of 'name'. return new FxConstant(FName(sc.String), scpos); } + else if (sc.CheckToken(TK_Bool)) + { + sc.MustGetToken('('); + FxExpression *exp = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + return new FxBoolCast(exp); + } + else if (sc.CheckToken(TK_Int)) + { + sc.MustGetToken('('); + FxExpression *exp = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + return new FxIntCast(exp); + } + else if (sc.CheckToken(TK_Float)) + { + sc.MustGetToken('('); + FxExpression *exp = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + return new FxFloatCast(exp); + } + else if (sc.CheckToken(TK_State)) + { + sc.MustGetToken('('); + FxExpression *exp; + if (sc.CheckToken(TK_StringConst)) + { + if (sc.String[0] == 0 || sc.Compare("None")) + { + exp = new FxConstant((FState*)nullptr, sc); + } + else + { + exp = new FxMultiNameState(sc.String, sc); + } + } + else + { + exp = new FxRuntimeStateIndex(ParseExpressionM(sc, cls)); + } + sc.MustGetToken(')'); + return exp; + } else if (sc.CheckToken(TK_Identifier)) { FName identifier = FName(sc.String); From 8437313e7c2d5d8c2db8419da8c00cf4b0759cdf Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Fri, 5 Aug 2016 17:33:29 +0200 Subject: [PATCH 34/53] Added post/pre increment/decrement operators to DECORATE --- src/dobjtype.h | 1 + src/thingdef/thingdef_data.cpp | 68 ++++---- src/thingdef/thingdef_exp.cpp | 15 +- src/thingdef/thingdef_exp.h | 48 +++++- src/thingdef/thingdef_expression.cpp | 240 ++++++++++++++++++++++++--- 5 files changed, 306 insertions(+), 66 deletions(-) diff --git a/src/dobjtype.h b/src/dobjtype.h index 7edf8ca6a..d0ccee746 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -18,6 +18,7 @@ typedef std::pair FTypeAndOffset; #define VARF_Method (1<<1) // func has an implied self parameter #define VARF_Action (1<<2) // func has implied owner and state parameters #define VARF_Native (1<<3) // func is native code/don't auto serialize field +#define VARF_ReadOnly (1<<4) // field is read only, do not write to it // Symbol information ------------------------------------------------------- diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 3b114fbee..8fceca8ee 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -631,38 +631,38 @@ void InitThingdef() // Define some member variables we feel like exposing to the user PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; PType *array5 = NewArray(TypeSInt32, 5); - symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor,Alpha))); - symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Yaw))); - symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args))); - symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz))); - symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz))); - symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health))); - symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass))); - symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Pitch))); - symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Roll))); - symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special))); - symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); - symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); - symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); - symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.X))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Y))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Z))); // must remain read-only! - symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X))); - symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X))); - symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); - symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); - symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score))); - symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy))); - symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina))); - symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor,Height))); - symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius))); - symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime))); - symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor,meleerange))); - symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor,Speed))); - symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native, myoffsetof(AActor,threshold))); - symt.AddSymbol(new PField(NAME_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold))); + symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha))); + symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw))); + symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args))); + symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz))); + symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz))); + symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health))); + symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass))); + symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch))); + symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll))); + symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special))); + symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid))); + symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate))); + symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel))); + symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only! + symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); + symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); + symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score))); + symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy))); + symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina))); + symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height))); + symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius))); + symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime))); + symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange))); + symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed))); + symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold))); + symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold))); } diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 265917175..12dd5957e 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -63,6 +63,7 @@ static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls); // // ParseExpression // [GRB] Parses an expression and stores it into Expression array +// It's worth mentioning that this is using C++ operator precedence // static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls); @@ -257,6 +258,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls) case '+': return new FxPlusSign(ParseExpressionA (sc, cls)); + case TK_Incr: + case TK_Decr: + return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType); + default: sc.UnGet(); return ParseExpressionA (sc, cls); @@ -312,6 +317,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls) sc.MustGetToken(']'); base_expr = new FxArrayElement(base_expr, index); } + else if (sc.CheckToken(TK_Incr)) + { + return new FxPostIncrDecr(base_expr, TK_Incr); + } + else if (sc.CheckToken(TK_Decr)) + { + return new FxPostIncrDecr(base_expr, TK_Decr); + } else break; } @@ -478,7 +491,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) } break; } - } + } else { return new FxIdentifier(identifier, sc); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index c1e8863e8..25c4b3afb 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -201,7 +201,7 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); virtual bool isConstant() const; - virtual void RequestAddress(); + virtual bool RequestAddress(); virtual VMFunction *GetDirectFunction(); bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } @@ -469,6 +469,45 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxPreIncrDecr +// +//========================================================================== + +class FxPreIncrDecr : public FxExpression +{ + int Token; + FxExpression *Base; + bool AddressRequested; + bool AddressWritable; + +public: + FxPreIncrDecr(FxExpression *base, int token); + ~FxPreIncrDecr(); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxPostIncrDecr +// +//========================================================================== + +class FxPostIncrDecr : public FxExpression +{ + int Token; + FxExpression *Base; + +public: + FxPostIncrDecr(FxExpression *base, int token); + ~FxPostIncrDecr(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxBinary @@ -753,7 +792,7 @@ public: FxClassMember(FxExpression*, PField*, const FScriptPosition&); ~FxClassMember(); FxExpression *Resolve(FCompileContext&); - void RequestAddress(); + bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -796,12 +835,13 @@ class FxArrayElement : public FxExpression public: FxExpression *Array; FxExpression *index; - //bool AddressRequested; + bool AddressRequested; + bool AddressWritable; FxArrayElement(FxExpression*, FxExpression*); ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); - //void RequestAddress(); + bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d40b7605c..63b6be9ca 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -218,13 +218,14 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx) //========================================================================== // -// +// Returns true if we can write to the address. // //========================================================================== -void FxExpression::RequestAddress() +bool FxExpression::RequestAddress() { ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); + return false; } //========================================================================== @@ -887,6 +888,166 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) return from; } +//========================================================================== +// +// FxPreIncrDecr +// +//========================================================================== + +FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token) +: FxExpression(base->ScriptPosition), Base(base), Token(token) +{ + AddressRequested = false; + AddressWritable = false; +} + +FxPreIncrDecr::~FxPreIncrDecr() +{ + SAFE_DELETE(Base); +} + +bool FxPreIncrDecr::RequestAddress() +{ + AddressRequested = true; + return AddressWritable; +} + +FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!(AddressWritable = Base->RequestAddress())) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + + ExpEmit value(build, regtype); + build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero); + + if (regtype == REGT_INT) + { + build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, value.RegNum, value.RegNum, build->GetConstantInt(1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, value.RegNum, value.RegNum, build->GetConstantFloat(1.)); + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero); + + if (AddressRequested) + { + value.Free(build); + return pointer; + } + + pointer.Free(build); + return value; +} + +//========================================================================== +// +// FxPostIncrDecr +// +//========================================================================== + +FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token) +: FxExpression(base->ScriptPosition), Base(base), Token(token) +{ +} + +FxPostIncrDecr::~FxPostIncrDecr() +{ + SAFE_DELETE(Base); +} + +FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!Base->RequestAddress()) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + + ExpEmit out(build, regtype); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero); + + ExpEmit assign(build, regtype); + if (regtype == REGT_INT) + { + build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.)); + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero); + + pointer.Free(build); + assign.Free(build); + return out; +} + //========================================================================== // // @@ -2995,9 +3156,10 @@ FxClassMember::~FxClassMember() // //========================================================================== -void FxClassMember::RequestAddress() +bool FxClassMember::RequestAddress() { AddressRequested = true; + return !!(~membervar->Flags & VARF_ReadOnly); } //========================================================================== @@ -3027,6 +3189,17 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) ExpEmit obj = classx->Emit(build); assert(obj.RegType == REGT_POINTER); + if (obj.Konst) + { + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; + } + if (AddressRequested) { if (membervar->Offset == 0) @@ -3040,20 +3213,8 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) } int offsetreg = build->GetConstantInt((int)membervar->Offset); - ExpEmit loc, tmp; + ExpEmit loc(build, membervar->Type->GetRegType()); - if (obj.Konst) - { - // If the situation where we are dereferencing a constant - // pointer is common, then it would probably be worthwhile - // to add new opcodes for those. But as of right now, I - // don't expect it to be a particularly common case. - ExpEmit newobj(build, REGT_POINTER); - build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); - obj = newobj; - } - - loc = ExpEmit(build, membervar->Type->GetRegType()); build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); obj.Free(build); return loc; @@ -3071,7 +3232,8 @@ FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) { Array=base; index = _index; - //AddressRequested = false; + AddressRequested = false; + AddressWritable = false; } //========================================================================== @@ -3092,12 +3254,11 @@ FxArrayElement::~FxArrayElement() // //========================================================================== -/* -void FxArrayElement::RequestAddress() +bool FxArrayElement::RequestAddress() { AddressRequested = true; + return AddressWritable; } -*/ //========================================================================== // @@ -3145,7 +3306,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return NULL; } - Array->RequestAddress(); + AddressWritable = Array->RequestAddress(); return this; } @@ -3159,13 +3320,13 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit start = Array->Emit(build); PArray *const arraytype = static_cast(Array->ValueType); - PType *const elementtype = arraytype->ElementType; - ExpEmit dest(build, elementtype->GetRegType()); + ExpEmit dest(build, arraytype->ElementType->GetRegType()); if (start.Konst) { ExpEmit tmpstart(build, REGT_POINTER); build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); + start.Free(build); start = tmpstart; } if (index->isConstant()) @@ -3176,8 +3337,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) I_Error("Array index out of bounds"); } indexval *= arraytype->ElementSize; - build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, - start.RegNum, build->GetConstantInt(indexval)); + + if (AddressRequested) + { + if (indexval != 0) + { + build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); + } + } + else + { + build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, + start.RegNum, build->GetConstantInt(indexval)); + } } else { @@ -3193,10 +3365,24 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits); } - build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that - dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register + + if (AddressRequested) + { + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum); + } + else + { + build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that + dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register + } indexv.Free(build); } + if (AddressRequested) + { + dest.Free(build); + return start; + } + start.Free(build); return dest; } From 90cc79a902002c68f5a910dccee1b9e018024459 Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Mon, 1 Aug 2016 00:32:02 +0200 Subject: [PATCH 35/53] Added the direct assignment operator to DECORATE --- src/thingdef/thingdef_exp.cpp | 11 +++- src/thingdef/thingdef_exp.h | 21 +++++++ src/thingdef/thingdef_expression.cpp | 94 ++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 12dd5957e..ffe7bf11a 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -96,18 +96,23 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve) static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) { - FxExpression *condition = ParseExpressionL (sc, cls); + FxExpression *base = ParseExpressionL (sc, cls); if (sc.CheckToken('?')) { FxExpression *truex = ParseExpressionM (sc, cls); sc.MustGetToken(':'); FxExpression *falsex = ParseExpressionM (sc, cls); - return new FxConditional(condition, truex, falsex); + return new FxConditional(base, truex, falsex); + } + else if (sc.CheckToken('=')) + { + FxExpression *right = ParseExpressionM(sc, cls); + return new FxAssign(base, right); } else { - return condition; + return base; } } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 25c4b3afb..1284f364d 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -508,6 +508,27 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxAssign +// +//========================================================================== + +class FxAssign : public FxExpression +{ + FxExpression *Base; + FxExpression *Right; + bool AddressRequested; + bool AddressWritable; + +public: + FxAssign(FxExpression *base, FxExpression *right); + ~FxAssign(); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxBinary diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 63b6be9ca..34a2c0f95 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1048,6 +1048,100 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) return out; } +//========================================================================== +// +// FxAssign +// +//========================================================================== + +FxAssign::FxAssign(FxExpression *base, FxExpression *right) +: FxExpression(base->ScriptPosition), Base(base), Right(right) +{ + AddressRequested = false; + AddressWritable = false; +} + +FxAssign::~FxAssign() +{ + SAFE_DELETE(Base); + SAFE_DELETE(Right); +} + +bool FxAssign::RequestAddress() +{ + AddressRequested = true; + return AddressWritable; +} + +FxExpression *FxAssign::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + SAFE_RESOLVE(Right, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric() || !Right->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + if (!(AddressWritable = Base->RequestAddress())) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + if (Right->ValueType != ValueType) + { + if (ValueType == TypeBool) + { + Right = new FxBoolCast(Right); + } + else if (ValueType->GetRegType() == REGT_INT) + { + Right = new FxIntCast(Right); + } + else + { + Right = new FxFloatCast(Right); + } + SAFE_RESOLVE(Right, ctx); + } + + return this; +} + +ExpEmit FxAssign::Emit(VMFunctionBuilder *build) +{ + assert(ValueType == Base->ValueType && IsNumeric()); + assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); + + ExpEmit pointer = Base->Emit(build); + ExpEmit result = Right->Emit(build); + + if (result.Konst) + { + ExpEmit temp(build, result.RegType); + build->Emit(result.RegType == REGT_FLOAT ? OP_LKF : OP_LK, temp.RegNum, result.RegNum); + result.Free(build); + result = temp; + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + + if (AddressRequested) + { + result.Free(build); + return pointer; + } + + pointer.Free(build); + return result; +} + //========================================================================== // // From e79c0225ed7a635870f1d22e31cc9ad45be5fb2f Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Mon, 1 Aug 2016 03:32:02 +0200 Subject: [PATCH 36/53] Added all compound assignment operators to DECORATE --- src/thingdef/thingdef_exp.cpp | 62 +++++++++++++++++++++++++++- src/thingdef/thingdef_exp.h | 18 ++++++++ src/thingdef/thingdef_expression.cpp | 40 +++++++++++++++++- 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index ffe7bf11a..991e9b947 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -112,7 +112,67 @@ static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls) } else { - return base; + FxBinary *exp; + FxAssignSelf *left = new FxAssignSelf(sc); + + sc.GetToken(); + switch (sc.TokenType) + { + case TK_AddEq: + exp = new FxAddSub('+', left, nullptr); + break; + + case TK_SubEq: + exp = new FxAddSub('-', left, nullptr); + break; + + case TK_MulEq: + exp = new FxMulDiv('*', left, nullptr); + break; + + case TK_DivEq: + exp = new FxMulDiv('/', left, nullptr); + break; + + case TK_ModEq: + exp = new FxMulDiv('%', left, nullptr); + break; + + case TK_LShiftEq: + exp = new FxBinaryInt(TK_LShift, left, nullptr); + break; + + case TK_RShiftEq: + exp = new FxBinaryInt(TK_RShift, left, nullptr); + break; + + case TK_URShiftEq: + exp = new FxBinaryInt(TK_URShift, left, nullptr); + break; + + case TK_AndEq: + exp = new FxBinaryInt('&', left, nullptr); + break; + + case TK_XorEq: + exp = new FxBinaryInt('^', left, nullptr); + break; + + case TK_OrEq: + exp = new FxBinaryInt('|', left, nullptr); + break; + + default: + sc.UnGet(); + delete left; + return base; + } + + exp->right = ParseExpressionM(sc, cls); + + FxAssign *ret = new FxAssign(base, exp); + left->Assignment = ret; + return ret; } } diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 1284f364d..7ec542772 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -527,6 +527,24 @@ public: FxExpression *Resolve(FCompileContext&); bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); + + ExpEmit Address; +}; + +//========================================================================== +// +// FxAssignSelf +// +//========================================================================== + +class FxAssignSelf : public FxExpression +{ +public: + FxAssign *Assignment; + + FxAssignSelf(const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); }; //========================================================================== diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 34a2c0f95..07f4d9fdf 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1077,10 +1077,11 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); SAFE_RESOLVE(Base, ctx); - SAFE_RESOLVE(Right, ctx); ValueType = Base->ValueType; + SAFE_RESOLVE(Right, ctx); + if (!Base->IsNumeric() || !Right->IsNumeric()) { ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); @@ -1120,8 +1121,10 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); ExpEmit pointer = Base->Emit(build); - ExpEmit result = Right->Emit(build); + Address = pointer; + ExpEmit result = Right->Emit(build); + if (result.Konst) { ExpEmit temp(build, result.RegType); @@ -1142,6 +1145,39 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) return result; } +//========================================================================== +// +// FxAssignSelf +// +//========================================================================== + +FxAssignSelf::FxAssignSelf(const FScriptPosition &pos) +: FxExpression(pos) +{ + Assignment = nullptr; +} + +FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + // This should never happen if FxAssignSelf is used correctly + assert(Assignment != nullptr); + + ValueType = Assignment->ValueType; + + return this; +} + +ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) +{ + assert(ValueType = Assignment->ValueType); + ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it + ExpEmit out(build, ValueType->GetRegType()); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + return out; +} + //========================================================================== // // From b97024b710ff796391f0c7dda9606b38d8e4608b Mon Sep 17 00:00:00 2001 From: Leonard2 Date: Tue, 2 Aug 2016 18:50:34 +0200 Subject: [PATCH 37/53] The return statement now accepts any expression as its return value So something like 'return ++user_x;' is now possible Admittedly this needed quite a bit of refactoring mainly due to the fact that return types now have to be checked after resolving the function rather than before --- src/thingdef/thingdef.cpp | 41 ++-- src/thingdef/thingdef.h | 4 +- src/thingdef/thingdef_exp.h | 37 ++-- src/thingdef/thingdef_expression.cpp | 314 ++++++++++++++++++++++----- src/thingdef/thingdef_states.cpp | 152 ++----------- 5 files changed, 327 insertions(+), 221 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 04ac21890..4878adfdf 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -270,23 +270,28 @@ static void FinishThingdef() for (i = 0; i < StateTempCalls.Size(); ++i) { FStateTempCall *tcall = StateTempCalls[i]; - VMFunction *func; + VMFunction *func = nullptr; assert(tcall->Code != NULL); - // Can we call this function directly without wrapping it in an - // anonymous function? e.g. Are we passing any parameters to it? - func = tcall->Code->GetDirectFunction(); - if (func == NULL) - { - FCompileContext ctx(tcall->ActorClass); - tcall->Code = tcall->Code->Resolve(ctx); + // We don't know the return type in advance for anonymous functions. + FCompileContext ctx(tcall->ActorClass, nullptr); + tcall->Code = tcall->Code->Resolve(ctx); + tcall->Proto = ctx.ReturnProto; - // Make sure resolving it didn't obliterate it. - if (tcall->Code != NULL) + // Make sure resolving it didn't obliterate it. + if (tcall->Code != nullptr) + { + // Can we call this function directly without wrapping it in an + // anonymous function? e.g. Are we passing any parameters to it? + func = tcall->Code->GetDirectFunction(); + + if (func == nullptr) { VMFunctionBuilder buildit; + assert(tcall->Proto != nullptr); + // Allocate registers used to pass parameters in. // self, stateowner, state (all are pointers) buildit.Registers[REGT_POINTER].Get(3); @@ -300,15 +305,7 @@ static void FinishThingdef() // Generate prototype for this anonymous function TArray args(3); SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action); - if (tcall->Proto != NULL) - { - sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args); - } - else - { - TArray norets(0); - sfunc->Proto = NewPrototype(norets, args); - } + sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args); func = sfunc; @@ -321,11 +318,9 @@ static void FinishThingdef() codesize += sfunc->CodeSize; } } - } - if (tcall->Code != NULL) - { + delete tcall->Code; - tcall->Code = NULL; + tcall->Code = nullptr; for (int k = 0; k < tcall->NumStates; ++k) { tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 8ad28f098..296383a3d 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -190,10 +190,9 @@ AFuncDesc *FindFunction(const char * string); void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag); void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray &out_params, PFunction *afd, FString statestring, FStateDefinitions *statedef); -FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&proto, bool &endswithret); +FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret); class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag); FName CheckCastKludges(FName in); -void AddImplicitReturn(class FxSequence *code, const PPrototype *proto, FScanner &sc); void SetImplicitArgs(TArray *args, TArray *argflags, PClassActor *cls, DWORD funcflags); PFunction *FindGlobalActionFunction(const char *name); @@ -356,6 +355,7 @@ int MatchString (const char *in, const char **strings); #define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0) +#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0) #define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0) #define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v) diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 7ec542772..2f06e085e 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -62,14 +62,16 @@ class FxJumpStatement; struct FCompileContext { TArray Jumps; + PPrototype *ReturnProto; PClassActor *Class; - FCompileContext(PClassActor *cls = nullptr); + FCompileContext(PClassActor *cls = nullptr, PPrototype *ret = nullptr); PSymbol *FindInClass(FName identifier); PSymbol *FindGlobal(FName identifier); void HandleJumps(int token, FxExpression *handler); + void CheckReturn(PPrototype *proto, FScriptPosition &pos); }; //========================================================================== @@ -170,14 +172,14 @@ struct ExpVal struct ExpEmit { - ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false) {} - ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false) {} - ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false) {} + ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false) {} + ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false), Final(false) {} + ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false), Final(false) {} ExpEmit(VMFunctionBuilder *build, int type); void Free(VMFunctionBuilder *build); void Reuse(VMFunctionBuilder *build); - BYTE RegNum, RegType, Konst:1, Fixed:1; + BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1; }; //========================================================================== @@ -202,6 +204,7 @@ public: virtual bool isConstant() const; virtual bool RequestAddress(); + virtual PPrototype *ReturnProto(); virtual VMFunction *GetDirectFunction(); bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } @@ -748,6 +751,7 @@ public: class FxRandom : public FxExpression { protected: + bool EmitTail; FRandom *rng; FxExpression *min, *max; @@ -756,7 +760,7 @@ public: FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); ~FxRandom(); FxExpression *Resolve(FCompileContext&); - + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -802,6 +806,7 @@ public: class FxRandom2 : public FxExpression { + bool EmitTail; FRandom * rng; FxExpression *mask; @@ -810,7 +815,7 @@ public: FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos); ~FxRandom2(); FxExpression *Resolve(FCompileContext&); - + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -915,8 +920,9 @@ public: class FxActionSpecialCall : public FxExpression { - FxExpression *Self; int Special; + bool EmitTail; + FxExpression *Self; FArgumentList *ArgList; public: @@ -924,6 +930,7 @@ public: FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos); ~FxActionSpecialCall(); FxExpression *Resolve(FCompileContext&); + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -954,6 +961,7 @@ public: class FxVMFunctionCall : public FxExpression { + bool EmitTail; PFunction *Function; FArgumentList *ArgList; @@ -961,13 +969,10 @@ public: FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos); ~FxVMFunctionCall(); FxExpression *Resolve(FCompileContext&); + PPrototype *ReturnProto(); + VMFunction *GetDirectFunction(); ExpEmit Emit(VMFunctionBuilder *build); - ExpEmit Emit(VMFunctionBuilder *build, bool tailcall); bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®); - unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); } - PFunction *GetFunction() const { return Function; } - VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; } - bool IsDirectFunction(); }; //========================================================================== @@ -1089,10 +1094,10 @@ public: class FxReturnStatement : public FxExpression { - FxVMFunctionCall *Call; + FxExpression *Value; public: - FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos); + FxReturnStatement(FxExpression *value, const FScriptPosition &pos); ~FxReturnStatement(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); @@ -1146,12 +1151,14 @@ public: class FxRuntimeStateIndex : public FxExpression { + bool EmitTail; FxExpression *Index; public: FxRuntimeStateIndex(FxExpression *index); ~FxRuntimeStateIndex(); FxExpression *Resolve(FCompileContext&); + PPrototype *ReturnProto(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 07f4d9fdf..4af9e33c9 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -91,7 +91,7 @@ static const FLOP FxFlops[] = // //========================================================================== -FCompileContext::FCompileContext(PClassActor *cls) : Class(cls) +FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : Class(cls), ReturnProto(ret) { } @@ -118,6 +118,50 @@ void FCompileContext::HandleJumps(int token, FxExpression *handler) } } +void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) +{ + assert(proto != nullptr); + bool fail = false; + + if (ReturnProto == nullptr) + { + ReturnProto = proto; + return; + } + + // A prototype that defines fewer return types can be compatible with + // one that defines more if the shorter one matches the initial types + // for the longer one. + if (ReturnProto->ReturnTypes.Size() < proto->ReturnTypes.Size()) + { // Make proto the shorter one to avoid code duplication below. + swapvalues(proto, ReturnProto); + } + // If one prototype returns nothing, they both must. + if (proto->ReturnTypes.Size() == 0) + { + if (ReturnProto->ReturnTypes.Size() != 0) + { + fail = true; + } + } + else + { + for (unsigned i = 0; i < proto->ReturnTypes.Size(); i++) + { + if (ReturnProto->ReturnTypes[i] != proto->ReturnTypes[i]) + { // Incompatible + fail = true; + break; + } + } + } + + if (fail) + { + pos.Message(MSG_ERROR, "All return expressions must deduce to the same type"); + } +} + //========================================================================== // // ExpEmit @@ -125,7 +169,7 @@ void FCompileContext::HandleJumps(int token, FxExpression *handler) //========================================================================== ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) -: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) +: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false), Final(false) { } @@ -228,6 +272,26 @@ bool FxExpression::RequestAddress() return false; } +//========================================================================== +// +// Called by return statements. +// +//========================================================================== + +PPrototype *FxExpression::ReturnProto() +{ + assert(ValueType != nullptr); + + TArray ret(0); + TArray none(0); + if (ValueType != TypeVoid) + { + ret.Push(ValueType); + } + + return NewPrototype(ret, none); +} + //========================================================================== // // @@ -2651,6 +2715,7 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build) FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) : FxExpression(pos) { + EmitTail = false; if (mi != NULL && ma != NULL) { min = new FxIntCast(mi); @@ -2679,6 +2744,18 @@ FxRandom::~FxRandom() // //========================================================================== +PPrototype *FxRandom::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + FxExpression *FxRandom::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -2706,12 +2783,12 @@ int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FRandom *rng = reinterpret_cast(param[0].a); if (numparam == 1) { - ret->SetInt((*rng)()); + ACTION_RETURN_INT((*rng)()); } else if (numparam == 2) { int maskval = param[1].i; - ret->SetInt(rng->Random2(maskval)); + ACTION_RETURN_INT(rng->Random2(maskval)); } else if (numparam == 3) { @@ -2720,9 +2797,11 @@ int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, { swapvalues(max, min); } - ret->SetInt((*rng)(max - min + 1) + min); + ACTION_RETURN_INT((*rng)(max - min + 1) + min); } - return 1; + + // Shouldn't happen + return 0; } ExpEmit FxRandom::Emit(VMFunctionBuilder *build) @@ -2735,17 +2814,27 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { EmitParameter(build, min, ScriptPosition); EmitParameter(build, max, ScriptPosition); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else { - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); } + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); return out; @@ -2952,13 +3041,12 @@ int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret { swapvalues(max, min); } - ret->SetFloat(frandom * (max - min) + min); + ACTION_RETURN_FLOAT(frandom * (max - min) + min); } else { - ret->SetFloat(frandom); + ACTION_RETURN_FLOAT(frandom); } - return 1; } ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) @@ -2971,17 +3059,27 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); if (min != NULL && max != NULL) { EmitParameter(build, min, ScriptPosition); EmitParameter(build, max, ScriptPosition); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); } else { - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1); } + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit out(build, REGT_FLOAT); build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum); return out; @@ -2996,6 +3094,7 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build) FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos) : FxExpression(pos) { + EmitTail = false; rng = r; if (m) mask = new FxIntCast(m); else mask = new FxConstant(-1, pos); @@ -3019,6 +3118,18 @@ FxRandom2::~FxRandom2() // //========================================================================== +PPrototype *FxRandom2::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + FxExpression *FxRandom2::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -3042,9 +3153,19 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); EmitParameter(build, mask, ScriptPosition); - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); + + if (EmitTail) + { + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit out(build, REGT_INT); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); return out; @@ -3623,6 +3744,7 @@ FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgum Self = self; Special = special; ArgList = args; + EmitTail = false; } //========================================================================== @@ -3643,6 +3765,18 @@ FxActionSpecialCall::~FxActionSpecialCall() // //========================================================================== +PPrototype *FxActionSpecialCall::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + +//========================================================================== +// +// +// +//========================================================================== + FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); @@ -3695,7 +3829,6 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx) int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { assert(numparam > 2 && numparam < 8); - assert(numret == 1); assert(param[0].Type == REGT_INT); assert(param[1].Type == REGT_POINTER); int v[5] = { 0 }; @@ -3704,8 +3837,7 @@ int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMRet { v[i - 2] = param[i].i; } - ret->SetInt(P_ExecuteSpecial(param[0].i, NULL, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); - return 1; + ACTION_RETURN_INT(P_ExecuteSpecial(param[0].i, NULL, reinterpret_cast(param[1].a), false, v[0], v[1], v[2], v[3], v[4])); } ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) @@ -3750,6 +3882,14 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != NULL); callfunc = ((PSymbolVMFunction *)sym)->Function; + if (EmitTail) + { + build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 0); + ExpEmit call; + call.Final = true; + return call; + } + ExpEmit dest(build, REGT_INT); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 1); build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum); @@ -3767,6 +3907,7 @@ FxVMFunctionCall::FxVMFunctionCall(PFunction *func, FArgumentList *args, const F { Function = func; ArgList = args; + EmitTail = false; } //========================================================================== @@ -3780,6 +3921,38 @@ FxVMFunctionCall::~FxVMFunctionCall() SAFE_DELETE(ArgList); } +//========================================================================== +// +// +// +//========================================================================== + +PPrototype *FxVMFunctionCall::ReturnProto() +{ + EmitTail = true; + return Function->Variants[0].Implementation->Proto; +} + +//========================================================================== +// +// +// +//========================================================================== + +VMFunction *FxVMFunctionCall::GetDirectFunction() +{ + // If this return statement calls a function with no arguments, + // then it can be a "direct" function. That is, the DECORATE + // definition can call that function directly without wrapping + // it inside VM code. + if (EmitTail && (ArgList ? ArgList->Size() : 0) == 0 && (Function->Flags & VARF_Action)) + { + return Function->Variants[0].Implementation; + } + + return nullptr; +} + //========================================================================== // // FxVMFunctionCall :: Resolve @@ -3809,6 +3982,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { ValueType = rets[0]; } + else + { + ValueType = TypeVoid; + } + return this; } @@ -3821,19 +3999,14 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) //========================================================================== ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) -{ - return Emit(build, false); -} - -ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) { assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); - int count = GetArgCount(); + int count = (ArgList ? ArgList->Size() : 0); if (count == 1) { ExpEmit reg; - if (CheckEmitCast(build, tailcall, reg)) + if (CheckEmitCast(build, EmitTail, reg)) { return reg; } @@ -3862,10 +4035,12 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall) VMFunction *vmfunc = Function->Variants[0].Implementation; int funcaddr = build->GetConstantAddress(vmfunc, ATAG_OBJECT); // Emit the call - if (tailcall) + if (EmitTail) { // Tail call build->Emit(OP_TAIL_K, funcaddr, count, 0); - return ExpEmit(); + ExpEmit call; + call.Final = true; + return call; } else if (vmfunc->Proto->ReturnTypes.Size() > 0) { // Call, expecting one result @@ -3913,6 +4088,7 @@ bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, Ex where.Free(build); } reg = ExpEmit(); + reg.Final = true; } else { @@ -4540,54 +4716,77 @@ ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build) // //========================================================================== -FxReturnStatement::FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos) -: FxExpression(pos), Call(call) +FxReturnStatement::FxReturnStatement(FxExpression *value, const FScriptPosition &pos) +: FxExpression(pos), Value(value) { + ValueType = TypeVoid; } FxReturnStatement::~FxReturnStatement() { - SAFE_DELETE(Call); + SAFE_DELETE(Value); } FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); - if (Call != NULL) + SAFE_RESOLVE_OPT(Value, ctx); + + PPrototype *retproto; + if (Value == nullptr) { - Call = static_cast(Call->Resolve(ctx)); - ABORT(Call); + TArray none(0); + retproto = NewPrototype(none, none); } + else + { + retproto = Value->ReturnProto(); + } + + ctx.CheckReturn(retproto, ScriptPosition); + return this; } ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build) { - // If we return nothing, use a regular RET opcode. If we return - // something, use TAIL to call the function. Our return type - // should be compatible with the called function's return type. - if (Call == NULL) + // If we return nothing, use a regular RET opcode. + // Otherwise just return the value we're given. + if (Value == nullptr) { build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); } else { - Call->Emit(build, true); + ExpEmit ret = Value->Emit(build); + + // Check if it is a function call that simplified itself + // into a tail call in which case we don't emit anything. + if (!ret.Final) + { + if (Value->ValueType == TypeVoid) + { // Nothing is returned. + build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0); + } + else + { + build->Emit(OP_RET, RET_FINAL, ret.RegType | (ret.Konst ? REGT_KONST : 0), ret.RegNum); + } + } } - return ExpEmit(); + + ExpEmit out; + out.Final = true; + return out; } VMFunction *FxReturnStatement::GetDirectFunction() { - // If this return statement calls a function with no arguments, - // then it can be a "direct" function. That is, the DECORATE - // definition can call that function directly without wrapping - // it inside VM code. - if (Call != NULL && Call->GetArgCount() == 0 && (Call->GetFunction()->Flags & VARF_Action)) + if (Value != nullptr) { - return Call->GetVMFunction(); + return Value->GetDirectFunction(); } - return NULL; + return nullptr; } //========================================================================== @@ -4754,6 +4953,7 @@ FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx) FxRuntimeStateIndex::FxRuntimeStateIndex(FxExpression *index) : FxExpression(index->ScriptPosition), Index(index) { + EmitTail = false; ValueType = TypeState; } @@ -4762,6 +4962,12 @@ FxRuntimeStateIndex::~FxRuntimeStateIndex() SAFE_DELETE(Index); } +PPrototype *FxRuntimeStateIndex::ReturnProto() +{ + EmitTail = true; + return FxExpression::ReturnProto(); +} + FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); @@ -4794,14 +5000,12 @@ static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numpa // Null is returned if the location was invalid which means that no jump will be performed // if used as return value // 0 always meant the same thing so we handle it here for compatibility - ret->SetPointer(nullptr, ATAG_STATE); + ACTION_RETURN_STATE(nullptr); } else { - ret->SetPointer(stateinfo->mCallingState + index, ATAG_STATE); + ACTION_RETURN_STATE(stateinfo->mCallingState + index); } - - return 1; } ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) @@ -4823,8 +5027,16 @@ ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); - build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); + if (EmitTail) + { + build->Emit(OP_TAIL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + out.Final = true; + } + else + { + build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); + build->Emit(OP_RESULT, 0, REGT_POINTER, out.RegNum); + } return out; } diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 652bdf9e9..707de3045 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -315,10 +315,10 @@ do_stop: } bool hasfinalret; - tcall->Code = ParseActions(sc, state, statestring, bag, tcall->Proto, hasfinalret); - if (!hasfinalret) + tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret); + if (!hasfinalret && tcall->Code != nullptr) { - AddImplicitReturn(static_cast(tcall->Code), tcall->Proto, sc); + static_cast(tcall->Code)->Add(new FxReturnStatement(nullptr, sc)); } goto endofstate; } @@ -351,125 +351,37 @@ endofstate: sc.SetEscape(true); // re-enable escape sequences } -//========================================================================== -// -// AddImplicitReturn -// -// Adds an implied return; statement to the end of a code sequence. -// -//========================================================================== - -void AddImplicitReturn(FxSequence *code, const PPrototype *proto, FScanner &sc) -{ - if (code == NULL) - { - return; - } - if (proto == NULL || proto->ReturnTypes.Size() == 0) - { // Returns nothing. Good. We can safely add an implied return. - code->Add(new FxReturnStatement(NULL, sc)); - } - else - { // Something was returned earlier in the sequence. Make it an error - // instead of adding an implicit one. - sc.ScriptError("Not all paths return a value"); - } -} - -//========================================================================== -// -// ReturnCheck -// -// If proto1 is NULL, returns proto2. If proto2 is NULL, returns proto1. -// If neither is null, checks if both prototypes define the same return -// types. If not, an error is flagged. -// -//========================================================================== - -static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner &sc) -{ - if (proto1 == NULL) - { - return proto2; - } - if (proto2 == NULL) - { - return proto1; - } - // A prototype that defines fewer return types can be compatible with - // one that defines more if the shorter one matches the initial types - // for the longer one. - if (proto2->ReturnTypes.Size() < proto1->ReturnTypes.Size()) - { // Make proto1 the shorter one to avoid code duplication below. - swapvalues(proto1, proto2); - } - // If one prototype returns nothing, they both must. - if (proto1->ReturnTypes.Size() == 0) - { - if (proto2->ReturnTypes.Size() == 0) - { - return proto1; - } - proto1 = NULL; - } - else - { - for (unsigned i = 0; i < proto1->ReturnTypes.Size(); ++i) - { - if (proto1->ReturnTypes[i] != proto2->ReturnTypes[i]) - { // Incompatible - proto1 = NULL; - break; - } - } - } - if (proto1 == NULL) - { - sc.ScriptError("Return types are incompatible"); - } - return proto1; -} - //========================================================================== // // ParseActions // -// If this action block contains any return statements, the prototype for -// one of them will be returned. This is used for deducing the return type -// of anonymous functions. All called functions passed to return must have -// matching return types. -// //========================================================================== -static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *add, *cond; - FxExpression *true_part, *false_part = NULL; - PPrototype *true_proto, *false_proto = NULL; + FxExpression *true_part, *false_part = nullptr; bool true_ret, false_ret = false; sc.MustGetStringName("("); cond = ParseExpression(sc, bag.Info); sc.MustGetStringName(")"); sc.MustGetStringName("{"); // braces are mandatory - true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret); + true_part = ParseActions(sc, state, statestring, bag, true_ret); sc.MustGetString(); if (sc.Compare("else")) { if (sc.CheckString("if")) { - false_part = ParseIf(sc, state, statestring, bag, false_proto, false_ret); + false_part = ParseIf(sc, state, statestring, bag, false_ret); } else { sc.MustGetStringName("{"); // braces are still mandatory - false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret); + false_part = ParseActions(sc, state, statestring, bag, false_ret); sc.MustGetString(); } } add = new FxIfStatement(cond, true_part, false_part, sc); - retproto = ReturnCheck(retproto, true_proto, sc); - retproto = ReturnCheck(retproto, false_proto, sc); // If one side does not end with a return, we don't consider the if statement // to end with a return. If the else case is missing, it can never be considered // as ending with a return. @@ -480,11 +392,9 @@ static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Ba return add; } -static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *cond, *code; - PPrototype *proto; bool ret; sc.MustGetStringName("("); @@ -492,24 +402,21 @@ static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, sc.MustGetStringName(")"); sc.MustGetStringName("{"); // Enforce braces like for if statements. - code = ParseActions(sc, state, statestring, bag, proto, ret); + code = ParseActions(sc, state, statestring, bag, ret); sc.MustGetString(); - retproto = ReturnCheck(retproto, proto, sc); lastwasret = false; // A while loop always jumps back. return new FxWhileLoop(cond, code, sc); } -static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *cond, *code; - PPrototype *proto; bool ret; sc.MustGetStringName("{"); // Enforce braces like for if statements. - code = ParseActions(sc, state, statestring, bag, proto, ret); + code = ParseActions(sc, state, statestring, bag, ret); sc.MustGetStringName("while"); sc.MustGetStringName("("); @@ -518,20 +425,17 @@ static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestrin sc.MustGetStringName(";"); sc.MustGetString(); - retproto = ReturnCheck(retproto, proto, sc); lastwasret = false; return new FxDoWhileLoop(cond, code, sc); } -static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &lastwasret) +static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret) { FxExpression *init = nullptr; FxExpression *cond = nullptr; FxExpression *iter = nullptr; FxExpression *code = nullptr; - PPrototype *proto; bool ret; // Parse the statements. @@ -560,24 +464,21 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B // Now parse the loop's content. sc.MustGetStringName("{"); // Enforce braces like for if statements. - code = ParseActions(sc, state, statestring, bag, proto, ret); + code = ParseActions(sc, state, statestring, bag, ret); sc.MustGetString(); - retproto = ReturnCheck(retproto, proto, sc); lastwasret = false; return new FxForLoop(init, cond, iter, code, sc); } -FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, - PPrototype *&retproto, bool &endswithret) +FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret) { // If it's not a '{', then it should be a single action. // Otherwise, it's a sequence of actions. if (!sc.Compare("{")) { FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag); - retproto = call->GetVMFunction()->Proto; endswithret = true; return new FxReturnStatement(call, sc); } @@ -585,7 +486,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg const FScriptPosition pos(sc); FxSequence *seq = NULL; - PPrototype *proto = NULL; bool lastwasret = false; sc.MustGetString(); @@ -595,38 +495,31 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg lastwasret = false; if (sc.Compare("if")) { // Handle an if statement - add = ParseIf(sc, state, statestring, bag, proto, lastwasret); + add = ParseIf(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("while")) { // Handle a while loop - add = ParseWhile(sc, state, statestring, bag, proto, lastwasret); + add = ParseWhile(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("do")) { // Handle a do-while loop - add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret); + add = ParseDoWhile(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("for")) { // Handle a for loop - add = ParseFor(sc, state, statestring, bag, proto, lastwasret); + add = ParseFor(sc, state, statestring, bag, lastwasret); } else if (sc.Compare("return")) { // Handle a return statement lastwasret = true; - FxVMFunctionCall *retexp = NULL; - PPrototype *retproto; + FxExpression *retexp = nullptr; sc.MustGetString(); if (!sc.Compare(";")) { - retexp = ParseAction(sc, state, statestring, bag); + sc.UnGet(); + retexp = ParseExpression(sc, bag.Info); sc.MustGetStringName(";"); - retproto = retexp->GetVMFunction()->Proto; } - else - { // Returning nothing; we still need a prototype for that. - TArray notypes(0); - retproto = NewPrototype(notypes, notypes); - } - proto = ReturnCheck(proto, retproto, sc); sc.MustGetString(); add = new FxReturnStatement(retexp, sc); } @@ -660,7 +553,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg } } endswithret = lastwasret; - retproto = proto; return seq; } From def3ad7533693978b9a546967219e0c900af94c4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 12:13:09 +0200 Subject: [PATCH 38/53] - refactored all 2D drawing to use its own vertex buffer which does not need to be mapped permanently. --- src/CMakeLists.txt | 1 + src/gl/data/gl_vertexbuffer.cpp | 18 +- src/gl/data/gl_vertexbuffer.h | 23 +- src/gl/renderer/gl_2ddrawer.cpp | 488 +++++++++++++++++++++++++++++ src/gl/renderer/gl_2ddrawer.h | 73 +++++ src/gl/renderer/gl_postprocess.cpp | 2 + src/gl/renderer/gl_renderer.cpp | 371 +--------------------- src/gl/renderer/gl_renderer.h | 11 +- src/gl/system/gl_framebuffer.cpp | 29 +- src/gl/system/gl_wipe.cpp | 10 +- 10 files changed, 632 insertions(+), 394 deletions(-) create mode 100644 src/gl/renderer/gl_2ddrawer.cpp create mode 100644 src/gl/renderer/gl_2ddrawer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 170737fa5..e002fc66f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1060,6 +1060,7 @@ set( FASTMATH_SOURCES gl/utility/gl_clock.cpp gl/utility/gl_cycler.cpp gl/utility/gl_geometric.cpp + gl/renderer/gl_2ddrawer.cpp gl/renderer/gl_renderer.cpp gl/renderer/gl_renderstate.cpp gl/renderer/gl_renderbuffers.cpp diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 2f38a720e..1d69c2547 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -77,22 +77,26 @@ void FSimpleVertexBuffer::BindVBO() glBindBuffer(GL_ARRAY_BUFFER, vbo_id); if (gl.glslversion > 0) { - glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); - glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u); - glDisableVertexAttribArray(VATTR_COLOR); + glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FSimpleVertex), &VSiO->x); + glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FSimpleVertex), &VSiO->u); + glVertexAttribPointer(VATTR_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(FSimpleVertex), &VSiO->color); + glEnableVertexAttribArray(VATTR_VERTEX); + glEnableVertexAttribArray(VATTR_TEXCOORD); + glEnableVertexAttribArray(VATTR_COLOR); glDisableVertexAttribArray(VATTR_VERTEX2); } else { - glVertexPointer(3, GL_FLOAT, sizeof(FFlatVertex), &VTO->x); - glTexCoordPointer(2, GL_FLOAT, sizeof(FFlatVertex), &VTO->u); + glVertexPointer(3, GL_FLOAT, sizeof(FSimpleVertex), &VSiO->x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FSimpleVertex), &VSiO->u); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(FSimpleVertex), &VSiO->color); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); } } -void FSimpleVertexBuffer::set(FFlatVertex *verts, int count) +void FSimpleVertexBuffer::set(FSimpleVertex *verts, int count) { glBindBuffer(GL_ARRAY_BUFFER, vbo_id); gl_RenderState.SetVertexBuffer(this); diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 4d39a7f58..ce598965f 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -36,20 +36,37 @@ struct FFlatVertex u = uu; v = vv; } - void BindVBO(); +}; + +struct FSimpleVertex +{ + float x, z, y; // world position + float u, v; // texture coordinates + PalEntry color; + + void Set(float xx, float zz, float yy, float uu = 0, float vv = 0, PalEntry col = 0xffffffff) + { + x = xx; + z = zz; + y = yy; + u = uu; + v = vv; + color = col; + } }; #define VTO ((FFlatVertex*)NULL) +#define VSiO ((FSimpleVertex*)NULL) class FSimpleVertexBuffer : public FVertexBuffer { - TArray mBuffer; + TArray mBuffer; public: FSimpleVertexBuffer() { } void BindVBO(); - void set(FFlatVertex *verts, int count); + void set(FSimpleVertex *verts, int count); }; class FFlatVertexBuffer : public FVertexBuffer diff --git a/src/gl/renderer/gl_2ddrawer.cpp b/src/gl/renderer/gl_2ddrawer.cpp new file mode 100644 index 000000000..75f76bbe6 --- /dev/null +++ b/src/gl/renderer/gl_2ddrawer.cpp @@ -0,0 +1,488 @@ +/* +** gl_2ddrawer.h +** Container class for drawing 2d graphics with a vertex buffer +** +**--------------------------------------------------------------------------- +** Copyright 2016 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 "gl/system/gl_framebuffer.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_2ddrawer.h" +#include "gl/textures/gl_material.h" +#include "gl/renderer/gl_renderstate.h" +#include "gl/renderer/gl_lightdata.h" +#include "gl/scene/gl_drawinfo.h" +#include "gl/textures/gl_translate.h" +#include "vectors.h" + +//========================================================================== +// +// +// +//========================================================================== + +int F2DDrawer::AddData(const F2DDrawer::DataGeneric *data) +{ + int addr = mData.Reserve(data->mLen); + memcpy(&mData[addr], data, data->mLen); + mLastLineCmd = -1; + return addr; +} + +//========================================================================== +// +// Draws a texture +// +//========================================================================== + +void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms) +{ + double xscale = parms.destwidth / parms.texwidth; + double yscale = parms.destheight / parms.texheight; + double x = parms.x - parms.left * xscale; + double y = parms.y - parms.top * yscale; + double w = parms.destwidth; + double h = parms.destheight; + float u1, v1, u2, v2; + int light = 255; + + FMaterial * gltex = FMaterial::ValidateTexture(img, false); + if (gltex == nullptr) return; + + DataTexture dg; + + dg.mType = DrawTypeTexture; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 4; + dg.mRenderStyle = parms.style; + dg.mMasked = !!parms.masked; + dg.mTexture = gltex; + + if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0) + { + // handle black overlays as reduced light. + light = 255 - APART(parms.colorOverlay); + parms.colorOverlay = 0; + } + dg.mVertIndex = (int)mVertices.Reserve(parms.colorOverlay == 0? 4 : 8); + dg.mColorOverlay = parms.colorOverlay; + dg.mTranslation = 0; + + if (!img->bHasCanvas) + { + if (!parms.alphaChannel) + { + if (parms.remap != NULL && !parms.remap->Inactive) + { + GLTranslationPalette * pal = static_cast(parms.remap->GetNative()); + if (pal) dg.mTranslation = -pal->GetIndex(); + } + } + dg.mAlphaTexture = !!(parms.style.Flags & STYLEF_RedIsAlpha); + u1 = gltex->GetUL(); + v1 = gltex->GetVT(); + u2 = gltex->GetUR(); + v2 = gltex->GetVB(); + + } + else + { + dg.mAlphaTexture = false; + u1 = 0.f; + v1 = 1.f; + u2 = 1.f; + v2 = 0.f; + } + + if (parms.flipX) + std::swap(u1, u2); + + + if (parms.windowleft > 0 || parms.windowright < parms.texwidth) + { + double wi = MIN(parms.windowright, parms.texwidth); + x += parms.windowleft * xscale; + w -= (parms.texwidth - wi + parms.windowleft) * xscale; + + u1 = float(u1 + parms.windowleft / parms.texwidth); + u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); + } + + PalEntry color; + if (parms.style.Flags & STYLEF_ColorIsFixed) + { + color = parms.fillcolor; + std::swap(color.r, color.b); + } + else + { + color = PalEntry(light, light, light); + } + color.a = (BYTE)(parms.Alpha * 255); + + // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates + int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; + btm = SCREENHEIGHT - btm; + + int space = (static_cast(screen)->GetTrueHeight() - screen->GetHeight()) / 2; + dg.mScissor[0] = parms.lclip; + dg.mScissor[1] = btm - parms.dclip + space; + dg.mScissor[2] = parms.rclip - parms.lclip; + dg.mScissor[3] = parms.dclip - parms.uclip; + + FSimpleVertex *ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x, y, 0, u1, v1, color); ptr++; + ptr->Set(x, y + h, 0, u1, v2, color); ptr++; + ptr->Set(x + w, y, 0, u2, v1, color); ptr++; + ptr->Set(x + w, y + h, 0, u2, v2, color); ptr++; + if (parms.colorOverlay != 0) + { + color = parms.colorOverlay; + std::swap(color.r, color.b); + ptr->Set(x, y, 0, u1, v1, color); ptr++; + ptr->Set(x, y + h, 0, u1, v2, color); ptr++; + ptr->Set(x + w, y, 0, u2, v1, color); ptr++; + ptr->Set(x + w, y + h, 0, u2, v2, color); ptr++; + } + AddData(&dg); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + DAngle rotation, FDynamicColormap *colormap, int lightlevel) +{ + FMaterial *gltexture = FMaterial::ValidateTexture(texture, false); + + if (gltexture == nullptr) + { + return; + } + DataSimplePoly poly; + + poly.mType = DrawTypePoly; + poly.mLen = (sizeof(poly) + 7) & ~7; + poly.mTexture = gltexture; + poly.mColormap = colormap; + poly.mLightLevel = lightlevel; + poly.mVertCount = npoints; + poly.mVertIndex = (int)mVertices.Reserve(npoints); + + bool dorotate = rotation != 0; + + float cosrot = cos(rotation.Radians()); + float sinrot = sin(rotation.Radians()); + + float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); + float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); + if (texture->bHasCanvas) + { + vscale = 0 - vscale; + } + float ox = float(originx); + float oy = float(originy); + + for (int i = 0; i < npoints; ++i) + { + float u = points[i].X - 0.5f - ox; + float v = points[i].Y - 0.5f - oy; + if (dorotate) + { + float t = u; + u = t * cosrot - v * sinrot; + v = v * cosrot + t * sinrot; + } + mVertices[poly.mVertIndex+i].Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale); + } + AddData(&poly); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void F2DDrawer::AddDim(PalEntry color, float damount, int x1, int y1, int w, int h) +{ + color.a = uint8_t(damount * 255); + std::swap(color.r, color.b); + + DataGeneric dg; + + dg.mType = DrawTypeDim; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + FSimpleVertex *ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x1, y1, 0, 0, 0, color); ptr++; + ptr->Set(x1, y1 + h, 0, 0, 0, color); ptr++; + ptr->Set(x1 + w, y1 + h, 0, 0, 0, color); ptr++; + ptr->Set(x1 + w, y1, 0, 0, 0, color); ptr++; + AddData(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddClear(int left, int top, int right, int bottom, int palcolor, uint32 color) +{ + PalEntry p = palcolor == -1 || color != 0 ? (PalEntry)color : GPalette.BaseColors[palcolor]; + AddDim(p, 1.f, left, top, right - left, bottom - top); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) +{ + float fU1, fU2, fV1, fV2; + + FMaterial *gltexture = FMaterial::ValidateTexture(src, false); + + if (!gltexture) return; + + DataFlatFill dg; + + dg.mType = DrawTypeFlatFill; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + dg.mTexture = gltexture; + + // scaling is not used here. + if (!local_origin) + { + fU1 = float(left) / src->GetWidth(); + fV1 = float(top) / src->GetHeight(); + fU2 = float(right) / src->GetWidth(); + fV2 = float(bottom) / src->GetHeight(); + } + else + { + fU1 = 0; + fV1 = 0; + fU2 = float(right - left) / src->GetWidth(); + fV2 = float(bottom - top) / src->GetHeight(); + } + FSimpleVertex *ptr = &mVertices[dg.mVertIndex]; + ptr->Set(left, top, 0, fU1, fV1); ptr++; + ptr->Set(left, bottom, 0, fU1, fV2); ptr++; + ptr->Set(right, top, 0, fU2, fV1); ptr++; + ptr->Set(right, bottom, 0, fU2, fV2); ptr++; + AddData(&dg); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color) +{ + PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor]; + p.a = 255; + std::swap(p.r, p.b); + + DataGeneric dg; + + dg.mType = DrawTypeLine; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 2; + dg.mVertIndex = (int)mVertices.Reserve(2); + mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p); + mVertices[dg.mVertIndex+1].Set(x2, y2, 0, 0, 0, p); + + // Test if we can batch multiple line commands + if (mLastLineCmd == -1) + { + mLastLineCmd = AddData(&dg); + } + else + { + DataGeneric *dg = (DataGeneric *)&mData[mLastLineCmd]; + dg->mVertCount += 2; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddPixel(int x1, int y1, int palcolor, uint32 color) +{ + PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor]; + p.a = 255; + std::swap(p.r, p.b); + + DataGeneric dg; + + dg.mType = DrawTypePixel; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 2; + dg.mVertIndex = (int)mVertices.Reserve(1); + mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p); + AddData(&dg); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::Flush() +{ + if (mData.Size() == 0) return; + SBYTE savedlightmode = glset.lightmode; + // lightmode is only relevant for automap subsectors, + // but We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering. + if (glset.lightmode == 8) glset.lightmode = 0; + + set(&mVertices[0], mVertices.Size()); + for (unsigned i = 0; i < mData.Size();) + { + DataGeneric *dg = (DataGeneric *)&mData[i]; + switch (dg->mType) + { + default: + break; + + case DrawTypeTexture: + { + DataTexture *dt = static_cast(dg); + + gl_SetRenderStyle(dt->mRenderStyle, !dt->mMasked, false); + gl_RenderState.SetMaterial(dt->mTexture, CLAMP_XY_NOMIP, dt->mTranslation, -1, dt->mAlphaTexture); + if (dt->mTexture->tex->bHasCanvas) gl_RenderState.SetTextureMode(TM_OPAQUE); + + glEnable(GL_SCISSOR_TEST); + glScissor(dt->mScissor[0], dt->mScissor[1], dt->mScissor[2], dt->mScissor[3]); + + gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); + gl_RenderState.Apply(); + + glDrawArrays(GL_TRIANGLE_STRIP, dt->mVertIndex, 4); + + gl_RenderState.BlendEquation(GL_FUNC_ADD); + if (dt->mVertCount > 4) + { + gl_RenderState.SetTextureMode(TM_MASK); + gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_STRIP, dt->mVertIndex + 4, 4); + } + + glScissor(0, 0, screen->GetWidth(), screen->GetHeight()); + glDisable(GL_SCISSOR_TEST); + gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_RenderState.SetTextureMode(TM_MODULATE); + break; + } + + case DrawTypePoly: + { + DataSimplePoly *dsp = static_cast(dg); + + FColormap cm; + cm = dsp->mColormap; + gl_SetColor(dsp->mLightLevel, 0, cm, 1.f); + gl_RenderState.SetMaterial(dsp->mTexture, CLAMP_NONE, 0, -1, false); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_FAN, dsp->mVertIndex, dsp->mVertCount); + break; + } + + case DrawTypeFlatFill: + { + DataFlatFill *dff = static_cast(dg); + gl_RenderState.SetMaterial(dff->mTexture, CLAMP_NONE, 0, -1, false); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_STRIP, dg->mVertIndex, dg->mVertCount); + break; + } + + case DrawTypeDim: + gl_RenderState.EnableTexture(false); + gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_RenderState.AlphaFunc(GL_GREATER, 0); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_FAN, dg->mVertIndex, dg->mVertCount); + gl_RenderState.EnableTexture(true); + break; + + case DrawTypeLine: + gl_RenderState.EnableTexture(false); + gl_RenderState.Apply(); + glDrawArrays(GL_LINES, dg->mVertIndex, dg->mVertCount); + gl_RenderState.EnableTexture(true); + break; + + case DrawTypePixel: + gl_RenderState.EnableTexture(false); + gl_RenderState.Apply(); + glDrawArrays(GL_POINTS, dg->mVertIndex, dg->mVertCount); + gl_RenderState.EnableTexture(true); + break; + + } + i += dg->mLen; + } + mVertices.Clear(); + mData.Clear(); + gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); + glset.lightmode = savedlightmode; +} + + diff --git a/src/gl/renderer/gl_2ddrawer.h b/src/gl/renderer/gl_2ddrawer.h new file mode 100644 index 000000000..32d2ad1f5 --- /dev/null +++ b/src/gl/renderer/gl_2ddrawer.h @@ -0,0 +1,73 @@ +#ifndef __2DDRAWER_H +#define __2DDRAWER_H + +#include "tarray.h" +#include "gl/data/gl_vertexbuffer.h" + +class F2DDrawer : public FSimpleVertexBuffer +{ + enum EDrawType + { + DrawTypeTexture, + DrawTypeDim, + DrawTypeFlatFill, + DrawTypePoly, + DrawTypeLine, + DrawTypePixel + }; + + struct DataGeneric + { + EDrawType mType; + uint32_t mLen; + int mVertIndex; + int mVertCount; + }; + + struct DataTexture : public DataGeneric + { + FMaterial *mTexture; + int mScissor[4]; + uint32_t mColorOverlay; + int mTranslation; + FRenderStyle mRenderStyle; + bool mMasked; + bool mAlphaTexture; + }; + + struct DataFlatFill : public DataGeneric + { + FMaterial *mTexture; + }; + + struct DataSimplePoly : public DataGeneric + { + FMaterial *mTexture; + int mLightLevel; + FDynamicColormap *mColormap; + }; + + TArray mVertices; + TArray mData; + int mLastLineCmd = -1; // consecutive lines can be batched into a single draw call so keep this info around. + + int AddData(const DataGeneric *data); + +public: + void AddTexture(FTexture *img, DrawParms &parms); + void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h); + void AddClear(int left, int top, int right, int bottom, int palcolor, uint32 color); + void AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin); + + void AddPoly(FTexture *texture, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + DAngle rotation, FDynamicColormap *colormap, int lightlevel); + + void AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color); + void AddPixel(int x1, int y1, int palcolor, uint32 color); + + void Flush(); +}; + + +#endif diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index f249aa1cc..79bd31860 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -71,6 +71,7 @@ #include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_presentshader.h" +#include "gl/renderer/gl_2ddrawer.h" //========================================================================== // @@ -283,6 +284,7 @@ void FGLRenderer::LensDistortScene() void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) { + m2DDrawer->Flush(); // draw all pending 2D stuff before copying the buffer if (FGLRenderBuffers::IsEnabled()) { FGLPostProcessState savedState; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 9105c08c7..2716c6a2c 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -58,6 +58,7 @@ #include "gl/renderer/gl_lightdata.h" #include "gl/renderer/gl_renderstate.h" #include "gl/renderer/gl_renderbuffers.h" +#include "gl/renderer/gl_2ddrawer.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/scene/gl_drawinfo.h" @@ -106,6 +107,7 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mShaderManager = NULL; gllight = glpart2 = glpart = mirrortexture = NULL; mLights = NULL; + m2DDrawer = nullptr; } void gl_LoadModels(); @@ -120,6 +122,7 @@ void FGLRenderer::Initialize() mTonemapShader = new FTonemapShader(); mLensShader = new FLensShader(); mPresentShader = new FPresentShader(); + m2DDrawer = new F2DDrawer; // Only needed for the core profile, because someone decided it was a good idea to remove the default VAO. if (gl.version >= 4.0) @@ -153,6 +156,7 @@ FGLRenderer::~FGLRenderer() gl_FlushModels(); gl_DeleteAllAttachedLights(); FMaterial::FlushAll(); + if (m2DDrawer != nullptr) delete m2DDrawer; if (mShaderManager != NULL) delete mShaderManager; if (mSamplerManager != NULL) delete mSamplerManager; if (mVBO != NULL) delete mVBO; @@ -378,366 +382,13 @@ void FGLRenderer::ClearBorders() int borderHeight = (trueHeight - height) / 2; glViewport(0, 0, width, trueHeight); - gl_RenderState.mProjectionMatrix.loadIdentity(); - gl_RenderState.mProjectionMatrix.ortho(0.0f, width * 1.0f, 0.0f, trueHeight, -1.0f, 1.0f); - gl_RenderState.SetColor(0.f ,0.f ,0.f ,1.f); - gl_RenderState.Set2DMode(true); - gl_RenderState.EnableTexture(false); - gl_RenderState.Apply(); - gl_RenderState.ApplyMatrices(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(0, borderHeight, 0, 0, 0); ptr++; - ptr->Set(0, 0, 0, 0, 0); ptr++; - ptr->Set(width, 0, 0, 0, 0); ptr++; - ptr->Set(width, borderHeight, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - ptr->Set(0, trueHeight, 0, 0, 0); ptr++; - ptr->Set(0, trueHeight - borderHeight, 0, 0, 0); ptr++; - ptr->Set(width, trueHeight - borderHeight, 0, 0, 0); ptr++; - ptr->Set(width, trueHeight, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - gl_RenderState.EnableTexture(true); - + glClearColor(0, 0, 0, 1); + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, width, borderHeight); + glClear(GL_COLOR_BUFFER_BIT); + glScissor(0, trueHeight-borderHeight, width, borderHeight); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); glViewport(0, (trueHeight - height) / 2, width, height); } -//========================================================================== -// -// Draws a texture -// -//========================================================================== - -void FGLRenderer::DrawTexture(FTexture *img, DrawParms &parms) -{ - double xscale = parms.destwidth / parms.texwidth; - double yscale = parms.destheight / parms.texheight; - double x = parms.x - parms.left * xscale; - double y = parms.y - parms.top * yscale; - double w = parms.destwidth; - double h = parms.destheight; - float u1, v1, u2, v2; - int light = 255; - - FMaterial * gltex = FMaterial::ValidateTexture(img, false); - - if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0) - { - // Right now there's only black. Should be implemented properly later - light = 255 - APART(parms.colorOverlay); - parms.colorOverlay = 0; - } - - gl_SetRenderStyle(parms.style, !parms.masked, false); - if (!img->bHasCanvas) - { - int translation = 0; - if (!parms.alphaChannel) - { - if (parms.remap != NULL && !parms.remap->Inactive) - { - GLTranslationPalette * pal = static_cast(parms.remap->GetNative()); - if (pal) translation = -pal->GetIndex(); - } - } - gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, translation, -1, !!(parms.style.Flags & STYLEF_RedIsAlpha)); - - u1 = gltex->GetUL(); - v1 = gltex->GetVT(); - u2 = gltex->GetUR(); - v2 = gltex->GetVB(); - - } - else - { - gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, 0, -1, false); - u1 = 0.f; - v1 = 1.f; - u2 = 1.f; - v2 = 0.f; - gl_RenderState.SetTextureMode(TM_OPAQUE); - } - - if (parms.flipX) - { - float temp = u1; - u1 = u2; - u2 = temp; - } - - - if (parms.windowleft > 0 || parms.windowright < parms.texwidth) - { - double wi = MIN(parms.windowright, parms.texwidth); - x += parms.windowleft * xscale; - w -= (parms.texwidth - wi + parms.windowleft) * xscale; - - u1 = float(u1 + parms.windowleft / parms.texwidth); - u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); - } - - PalEntry color; - if (parms.style.Flags & STYLEF_ColorIsFixed) - { - color = parms.fillcolor; - } - else - { - color = PalEntry(light, light, light); - } - color.a = (BYTE)(parms.Alpha * 255); - - // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates - int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; - btm = SCREENHEIGHT - btm; - - glEnable(GL_SCISSOR_TEST); - int space = (static_cast(screen)->GetTrueHeight()-screen->GetHeight())/2; - glScissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip); - - gl_RenderState.SetColor(color); - gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x, y, 0, u1, v1); ptr++; - ptr->Set(x, y + h, 0, u1, v2); ptr++; - ptr->Set(x + w, y, 0, u2, v1); ptr++; - ptr->Set(x + w, y + h, 0, u2, v2); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - - if (parms.colorOverlay) - { - gl_RenderState.SetTextureMode(TM_MASK); - gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_RenderState.BlendEquation(GL_FUNC_ADD); - gl_RenderState.SetColor(PalEntry(parms.colorOverlay)); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x, y, 0, u1, v1); ptr++; - ptr->Set(x, y + h, 0, u1, v2); ptr++; - ptr->Set(x + w, y, 0, u2, v1); ptr++; - ptr->Set(x + w, y + h, 0, u2, v2); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - } - - glScissor(0, 0, screen->GetWidth(), screen->GetHeight()); - glDisable(GL_SCISSOR_TEST); - gl_RenderState.SetTextureMode(TM_MODULATE); - gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_RenderState.BlendEquation(GL_FUNC_ADD); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color) -{ - PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor]; - gl_RenderState.EnableTexture(false); - gl_RenderState.SetColorAlpha(p, 1.f); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x1, y1, 0, 0, 0); ptr++; - ptr->Set(x2, y2, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_LINES); - - gl_RenderState.EnableTexture(true); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::DrawPixel(int x1, int y1, int palcolor, uint32 color) -{ - PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor]; - gl_RenderState.EnableTexture(false); - gl_RenderState.SetColorAlpha(p, 1.f); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x1, y1, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_POINTS); - - gl_RenderState.EnableTexture(true); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLRenderer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h) -{ - gl_RenderState.EnableTexture(false); - gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_RenderState.AlphaFunc(GL_GREATER,0); - gl_RenderState.SetColorAlpha(color, damount); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x1, y1, 0, 0, 0); ptr++; - ptr->Set(x1, y1+h, 0, 0, 0); ptr++; - ptr->Set(x1+w, y1+h, 0, 0, 0); ptr++; - ptr->Set(x1+w, y1, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); - - gl_RenderState.EnableTexture(true); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin) -{ - float fU1,fU2,fV1,fV2; - - FMaterial *gltexture=FMaterial::ValidateTexture(src, false); - - if (!gltexture) return; - - gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false); - - // scaling is not used here. - if (!local_origin) - { - fU1 = float(left) / src->GetWidth(); - fV1 = float(top) / src->GetHeight(); - fU2 = float(right) / src->GetWidth(); - fV2 = float(bottom) / src->GetHeight(); - } - else - { - fU1 = 0; - fV1 = 0; - fU2 = float(right-left) / src->GetWidth(); - fV2 = float(bottom-top) / src->GetHeight(); - } - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(left, top, 0, fU1, fV1); ptr++; - ptr->Set(left, bottom, 0, fU1, fV2); ptr++; - ptr->Set(right, top, 0, fU2, fV1); ptr++; - ptr->Set(right, bottom, 0, fU2, fV2); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color) -{ - int rt; - int offY = 0; - PalEntry p = palcolor==-1 || color != 0? (PalEntry)color : GPalette.BaseColors[palcolor]; - int width = right-left; - int height= bottom-top; - - - rt = screen->GetHeight() - top; - - int space = (static_cast(screen)->GetTrueHeight()-screen->GetHeight())/2; // ugh... - rt += space; - /* - if (!m_windowed && (m_trueHeight != m_height)) - { - offY = (m_trueHeight - m_height) / 2; - rt += offY; - } - */ - - glEnable(GL_SCISSOR_TEST); - glScissor(left, rt - height, width, height); - - glClearColor(p.r/255.0f, p.g/255.0f, p.b/255.0f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.f, 0.f, 0.f, 0.f); - - glDisable(GL_SCISSOR_TEST); -} - -//========================================================================== -// -// D3DFB :: FillSimplePoly -// -// Here, "simple" means that a simple triangle fan can draw it. -// -//========================================================================== - -void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, - double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel) -{ - if (npoints < 3) - { // This is no polygon. - return; - } - - FMaterial *gltexture = FMaterial::ValidateTexture(texture, false); - - if (gltexture == NULL) - { - return; - } - - FColormap cm; - cm = colormap; - - // We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering. - SBYTE savedlightmode = glset.lightmode; - if (glset.lightmode == 8) glset.lightmode = 0; - - gl_SetColor(lightlevel, 0, cm, 1.f); - - glset.lightmode = savedlightmode; - - gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false); - - int i; - bool dorotate = rotation != 0; - - float cosrot = cos(rotation.Radians()); - float sinrot = sin(rotation.Radians()); - - //float yoffs = GatheringWipeScreen ? 0 : LBOffset; - float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); - float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); - if (gltexture->tex->bHasCanvas) - { - vscale = 0 - vscale; - } - float ox = float(originx); - float oy = float(originy); - - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - for (i = 0; i < npoints; ++i) - { - float u = points[i].X - 0.5f - ox; - float v = points[i].Y - 0.5f - oy; - if (dorotate) - { - float t = u; - u = t * cosrot - v * sinrot; - v = v * cosrot + t * sinrot; - } - ptr->Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale); - ptr++; - } - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); -} - diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 9caace177..8a00e6ce4 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -25,6 +25,7 @@ class FBlurShader; class FTonemapShader; class FLensShader; class FPresentShader; +class F2DDrawer; inline float DEG2RAD(float deg) { @@ -107,6 +108,7 @@ public: FFlatVertexBuffer *mVBO; FSkyVertexBuffer *mSkyVBO; FLightBuffer *mLights; + F2DDrawer *m2DDrawer; GL_IRECT mScreenViewport; GL_IRECT mOutputViewportLB; @@ -142,12 +144,6 @@ public: void Begin2D(); void ClearBorders(); - void DrawTexture(FTexture *img, DrawParms &parms); - void DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color); - void DrawPixel(int x1, int y1, int palcolor, uint32 color); - void Dim(PalEntry color, float damount, int x1, int y1, int w, int h); - void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin); - void Clear(int left, int top, int right, int bottom, int palcolor, uint32 color); void ProcessLowerMiniseg(seg_t *seg, sector_t * frontsector, sector_t * backsector); void ProcessSprite(AActor *thing, sector_t *sector, bool thruportal); @@ -175,6 +171,9 @@ public: bool StartOffscreen(); void EndOffscreen(); + void StartSimplePolys(); + void FinishSimplePolys(); + void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel); diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 1b3a880b2..d5bb578e5 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -64,6 +64,7 @@ #include "gl/utility/gl_clock.h" #include "gl/utility/gl_templates.h" #include "gl/gl_functions.h" +#include "gl/renderer/gl_2ddrawer.h" IMPLEMENT_CLASS(OpenGLFrameBuffer) EXTERN_CVAR (Float, vid_brightness) @@ -386,7 +387,8 @@ bool OpenGLFrameBuffer::Begin2D(bool) void OpenGLFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) { - if (GLRenderer != NULL) GLRenderer->DrawTexture(img, parms); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddTexture(img, parms); } //========================================================================== @@ -396,8 +398,8 @@ void OpenGLFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) //========================================================================== void OpenGLFrameBuffer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color) { - if (GLRenderer != NULL) - GLRenderer->DrawLine(x1, y1, x2, y2, palcolor, color); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddLine(x1, y1, x2, y2, palcolor, color); } //========================================================================== @@ -407,8 +409,8 @@ void OpenGLFrameBuffer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, u //========================================================================== void OpenGLFrameBuffer::DrawPixel(int x1, int y1, int palcolor, uint32 color) { - if (GLRenderer != NULL) - GLRenderer->DrawPixel(x1, y1, palcolor, color); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddPixel(x1, y1, palcolor, color); } //========================================================================== @@ -425,8 +427,8 @@ void OpenGLFrameBuffer::Dim(PalEntry) void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h) { - if (GLRenderer != NULL) - GLRenderer->Dim(color, damount, x1, y1, w, h); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddDim(color, damount, x1, y1, w, h); } //========================================================================== @@ -437,8 +439,8 @@ void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin) { - if (GLRenderer != NULL) - GLRenderer->FlatFill(left, top, right, bottom, src, local_origin); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddFlatFill(left, top, right, bottom, src, local_origin); } //========================================================================== @@ -448,8 +450,8 @@ void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTex //========================================================================== void OpenGLFrameBuffer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color) { - if (GLRenderer != NULL) - GLRenderer->Clear(left, top, right, bottom, palcolor, color); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddClear(left, top, right, bottom, palcolor, color); } //========================================================================== @@ -464,10 +466,9 @@ void OpenGLFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, int double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel) { - if (GLRenderer != NULL) + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr && npoints >= 3) { - GLRenderer->FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, - rotation, colormap, lightlevel); + GLRenderer->m2DDrawer->AddPoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel); } } diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index 2978dd55d..bd03ca96e 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -61,6 +61,7 @@ #include "gl/textures/gl_samplers.h" #include "gl/utility/gl_templates.h" #include "gl/data/gl_vertexbuffer.h" +#include "gl/renderer/gl_2ddrawer.h" #ifndef _WIN32 struct POINT { @@ -187,6 +188,7 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type) void OpenGLFrameBuffer::WipeEndScreen() { + GLRenderer->m2DDrawer->Flush(); wipeendscreen = new FHardwareTexture(Width, Height, true); wipeendscreen->CreateTexture(NULL, Width, Height, 0, false, 0); GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1); @@ -288,8 +290,8 @@ OpenGLFrameBuffer::Wiper::~Wiper() void OpenGLFrameBuffer::Wiper::MakeVBO(OpenGLFrameBuffer *fb) { - FFlatVertex make[4]; - FFlatVertex *ptr = make; + FSimpleVertex make[4]; + FSimpleVertex *ptr = make; float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); @@ -380,8 +382,8 @@ OpenGLFrameBuffer::Wiper_Melt::Wiper_Melt() int OpenGLFrameBuffer::Wiper_Melt::MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done) { - FFlatVertex *make = new FFlatVertex[321*4]; - FFlatVertex *ptr = make; + FSimpleVertex *make = new FSimpleVertex[321*4]; + FSimpleVertex *ptr = make; int dy; float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); From 9ab9548723e1c258cfa713799b9c6cf12ccc927d Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 7 Aug 2016 14:50:48 +0300 Subject: [PATCH 39/53] Additional fix for splitting of complex wall in compatibility renderer warp 2720 -200 -32 on Extreme Terror https://www.doomworld.com/idgames/levels/doom2/Ports/d-f/exterror --- src/gl/scene/gl_wall.h | 2 +- src/gl/scene/gl_walls.cpp | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index fdeb99ed0..674d7fffd 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -187,7 +187,7 @@ private: void RenderLightsCompat(int pass); void Put3DWall(lightlist_t * lightlist, bool translucent); - void SplitWallComplex(sector_t * frontsector, bool translucent, float maplightbottomleft, float maplightbottomright); + bool SplitWallComplex(sector_t * frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright); void SplitWall(sector_t * frontsector, bool translucent); void SetupLights(); diff --git a/src/gl/scene/gl_walls.cpp b/src/gl/scene/gl_walls.cpp index a688a036b..6f1f02d86 100644 --- a/src/gl/scene/gl_walls.cpp +++ b/src/gl/scene/gl_walls.cpp @@ -264,7 +264,7 @@ void GLWall::Put3DWall(lightlist_t * lightlist, bool translucent) // //========================================================================== -void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float maplightbottomleft, float maplightbottomright) +bool GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright) { GLWall copyWall1, copyWall2; @@ -304,7 +304,7 @@ void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float ma copyWall1.SplitWall(frontsector, translucent); copyWall2.SplitWall(frontsector, translucent); - return; + return true; } } @@ -345,9 +345,11 @@ void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float ma copyWall1.SplitWall(frontsector, translucent); copyWall2.SplitWall(frontsector, translucent); - return; + return true; } } + + return false; } void GLWall::SplitWall(sector_t * frontsector, bool translucent) @@ -406,14 +408,14 @@ void GLWall::SplitWall(sector_t * frontsector, bool translucent) // Use hardware clipping if this cannot be done cleanly. this->lightlist = &lightlist; PutWall(translucent); - } - else - { - // crappy fallback if no clip planes available - SplitWallComplex(frontsector, translucent, maplightbottomleft, maplightbottomright); - } - goto out; + goto out; + } + // crappy fallback if no clip planes available + else if (SplitWallComplex(frontsector, translucent, maplightbottomleft, maplightbottomright)) + { + goto out; + } } // 3D floor is completely within this light From 2ac91f0c5a8d7076c45ad050017fa3d4769f1a40 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 8 Aug 2016 01:11:43 +0200 Subject: [PATCH 40/53] Fix Nvidia driver ignoring wglSwapIntervalEXT --- src/gl/system/gl_framebuffer.cpp | 5 ++++- src/win32/win32gliface.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index d5bb578e5..151683d56 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -94,6 +94,10 @@ CUSTOM_CVAR(Int, vid_hwgamma, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITC OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) : Super(hMonitor, width, height, bits, refreshHz, fullscreen) { + // SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver. + // If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed! + SetVSync(vid_vsync); + GLRenderer = new FGLRenderer(this); memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256); UpdatePalette (); @@ -107,7 +111,6 @@ OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int needsetgamma = true; swapped = false; Accel2D = true; - SetVSync(vid_vsync); } OpenGLFrameBuffer::~OpenGLFrameBuffer() diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index 2e61ae3a6..4f8c4d49b 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -1141,7 +1141,7 @@ void Win32GLFrameBuffer::ReleaseResources () void Win32GLFrameBuffer::SetVSync (bool vsync) { - if (vsyncfunc != NULL) vsyncfunc(vsync); + if (vsyncfunc != NULL) vsyncfunc(vsync ? 1 : 0); } void Win32GLFrameBuffer::SwapBuffers() From 9c9edbffdb0c7a5460433683e5bde0700c846d8a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 12:55:09 +0200 Subject: [PATCH 41/53] - on older ATI drivers where the clip planes are broken, only disable the clip planes themselves, but not OpenGL 3.x so that dynamic lights still work as intended. - only disable clip planes on Windows, but not on Linux or macOS. - If a driver reports full OpenGL 4.5 support, assume that all features are working properly. --- src/gl/renderer/gl_renderstate.cpp | 4 ++-- src/gl/renderer/gl_renderstate.h | 4 ++-- src/gl/scene/gl_sprite.cpp | 2 +- src/gl/scene/gl_walls.cpp | 2 +- src/gl/shaders/gl_shader.cpp | 6 ++++++ src/gl/system/gl_interface.cpp | 17 +++++++++++++---- src/gl/system/gl_interface.h | 3 ++- 7 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 865053b41..84badd07b 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -344,12 +344,12 @@ void FRenderState::SetClipHeight(float height, float direction) mClipHeightDirection = direction; #if 1 // This still doesn't work... :( - if (gl.glslversion < 1.3f) return; + if (gl.flags & RFL_NO_CLIP_PLANES) return; #endif if (direction != 0.f) { /* - if (gl.glslversion < 1.3f) + if (gl.flags & RFL_NO_CLIP_PLANES) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 2ad611ab2..12671c2a6 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -237,7 +237,7 @@ public: void EnableSplit(bool on) { - if (gl.glslversion >= 1.3f) + if (!(gl.flags & RFL_NO_CLIP_PLANES)) { mSplitEnabled = on; if (on) @@ -260,7 +260,7 @@ public: void EnableClipLine(bool on) { - if (gl.glslversion >= 1.3f) + if (!(gl.flags & RFL_NO_CLIP_PLANES)) { mClipLineEnabled = on; if (on) diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 98e0fb8d5..76796adf9 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -972,7 +972,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) if (thing->Sector->e->XFloor.lightlist.Size() != 0 && gl_fixedcolormap == CM_DEFAULT && !fullbright && RenderStyle.BlendOp != STYLEOP_Shadow && RenderStyle.BlendOp != STYLEOP_RevSub) { - if (gl.glslversion < 1.3) // on old hardware we are rather limited... + if (gl.flags & RFL_NO_CLIP_PLANES) // on old hardware we are rather limited... { lightlist = NULL; if (!drawWithXYBillboard && !modelframe) diff --git a/src/gl/scene/gl_walls.cpp b/src/gl/scene/gl_walls.cpp index 6f1f02d86..d8cef9771 100644 --- a/src/gl/scene/gl_walls.cpp +++ b/src/gl/scene/gl_walls.cpp @@ -403,7 +403,7 @@ void GLWall::SplitWall(sector_t * frontsector, bool translucent) (maplightbottomleftzbottom[1]) || (maplightbottomleft > zbottom[0] && maplightbottomright < zbottom[1])) { - if (gl.glslversion >= 1.3f) + if (!(gl.flags & RFL_NO_CLIP_PLANES)) { // Use hardware clipping if this cannot be done cleanly. this->lightlist = &lightlist; diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index f2b4c7ebd..cce8c6563 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -169,6 +169,12 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * FShaderProgram::PatchVertShader(vp_comb); FShaderProgram::PatchFragShader(fp_comb); } + else if (gl.flags & RFL_NO_CLIP_PLANES) + { + // On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken. + // This will cause some glitches and regressions but is the only way to avoid total display garbage. + vp_comb.Substitute("gl_ClipDistance", "//"); + } hVertProg = glCreateShader(GL_VERTEX_SHADER); hFragProg = glCreateShader(GL_FRAGMENT_SHADER); diff --git a/src/gl/system/gl_interface.cpp b/src/gl/system/gl_interface.cpp index 6b1105ee4..6176a2be9 100644 --- a/src/gl/system/gl_interface.cpp +++ b/src/gl/system/gl_interface.cpp @@ -192,6 +192,7 @@ void gl_LoadExtensions() gl.version = 2.11f; gl.glslversion = 0; gl.lightmethod = LM_SOFTWARE; + gl.flags |= RFL_NO_CLIP_PLANES; } else if (gl.version < 3.0f) { @@ -200,17 +201,18 @@ void gl_LoadExtensions() if (!CheckExtension("GL_EXT_packed_float")) gl.flags |= RFL_NO_RGBA16F; if (!CheckExtension("GL_EXT_packed_depth_stencil")) gl.flags |= RFL_NO_DEPTHSTENCIL; + gl.flags |= RFL_NO_CLIP_PLANES; } else if (gl.version < 4.f) { +#ifdef _WIN32 if (strstr(gl.vendorstring, "ATI Tech")) { - gl.version = 2.11f; - gl.glslversion = 1.21f; - gl.lightmethod = LM_SOFTWARE; // do not use uniform buffers with the fallback shader, it may cause problems. + gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows. } +#endif } - else + else if (gl.version < 4.5f) { // don't use GL 4.x features when running in GL 3 emulation mode. if (CheckExtension("GL_ARB_buffer_storage")) @@ -234,6 +236,13 @@ void gl_LoadExtensions() gl.version = 3.3f; } } + else + { + // Assume that everything works without problems on GL 4.5 drivers where these things are core features. + gl.flags |= RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE; + gl.lightmethod = LM_DIRECT; + gl.buffermethod = BM_PERSISTENT; + } const char *lm = Args->CheckValue("-lightmethod"); if (lm != NULL) diff --git a/src/gl/system/gl_interface.h b/src/gl/system/gl_interface.h index d43252ebc..fbe4e09c8 100644 --- a/src/gl/system/gl_interface.h +++ b/src/gl/system/gl_interface.h @@ -22,7 +22,8 @@ enum RenderFlags RFL_SAMPLER_OBJECTS = 16, RFL_NO_RGBA16F = 32, - RFL_NO_DEPTHSTENCIL = 64 + RFL_NO_DEPTHSTENCIL = 64, + RFL_NO_CLIP_PLANES = 128 }; enum TexMode From d62d345a7bbe3baa583a034e1e2af90760ff92f2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 13:06:29 +0200 Subject: [PATCH 42/53] =?UTF-8?q?-=20fixed:=20The=20cosine=20of=200=C2=B0?= =?UTF-8?q?=20is=201,=20not=200,=20as=20the=20portal=20code=20assumed=20fo?= =?UTF-8?q?r=20linked=20portals.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/portal.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/portal.cpp b/src/portal.cpp index bf919f09a..d7dad220e 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -294,7 +294,8 @@ static void SetRotation(FLinePortal *port) else { // Linked portals have no angular difference. - port->mSinRot = port->mCosRot = 0.; + port->mSinRot = 0.; + port->mCosRot = 1.; port->mAngleDiff = 0.; } } From 8daaf61160c526817b49c0acbaa660243f400c54 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 14:24:48 +0200 Subject: [PATCH 43/53] - predefine the vertex data for the blend overlay which will never change throughout the lifetime of the GLRenderer object. --- src/gl/data/gl_vertexbuffer.cpp | 20 +++++++++++++++++--- src/gl/data/gl_vertexbuffer.h | 2 +- src/gl/renderer/gl_renderer.cpp | 4 ++-- src/gl/renderer/gl_renderer.h | 2 +- src/gl/scene/gl_scene.cpp | 12 ++---------- src/gl/system/gl_framebuffer.cpp | 2 +- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 1d69c2547..4cb0efd6a 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -109,7 +109,7 @@ void FSimpleVertexBuffer::set(FSimpleVertex *verts, int count) // //========================================================================== -FFlatVertexBuffer::FFlatVertexBuffer() +FFlatVertexBuffer::FFlatVertexBuffer(int width, int height) : FVertexBuffer(gl.buffermethod == BM_PERSISTENT) { if (gl.buffermethod == BM_PERSISTENT) @@ -125,7 +125,22 @@ FFlatVertexBuffer::FFlatVertexBuffer() vbo_shadowdata.Reserve(BUFFER_SIZE); map = new FFlatVertex[BUFFER_SIZE]; } - mNumReserved = mIndex = mCurIndex = 0; + mIndex = mCurIndex = 0; + mNumReserved = 8; + vbo_shadowdata.Resize(mNumReserved); + + // the first quad is reserved for handling coordinates through uniforms. + vbo_shadowdata[0].Set(1, 0, 0, 0, 0); + vbo_shadowdata[1].Set(2, 0, 0, 0, 0); + vbo_shadowdata[2].Set(3, 0, 0, 0, 0); + vbo_shadowdata[3].Set(4, 0, 0, 0, 0); + + // and the second one for the fullscreen quad used for blend overlays. + vbo_shadowdata[4].Set(0, 0, 0, 0, 0); + vbo_shadowdata[5].Set(0, (float)height, 0, 0, 0); + vbo_shadowdata[6].Set((float)width, 0, 0, 0, 0); + vbo_shadowdata[7].Set((float)width, (float)height, 0, 0, 0); + } FFlatVertexBuffer::~FFlatVertexBuffer() @@ -350,7 +365,6 @@ void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) void FFlatVertexBuffer::CreateVBO() { - vbo_shadowdata.Resize(mNumReserved); CreateFlatVBO(); mCurIndex = mIndex = vbo_shadowdata.Size(); memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex)); diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index ce598965f..31251653d 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -84,7 +84,7 @@ class FFlatVertexBuffer : public FVertexBuffer public: TArray vbo_shadowdata; // this is kept around for updating the actual (non-readable) buffer and as stand-in for pre GL 4.x - FFlatVertexBuffer(); + FFlatVertexBuffer(int width, int height); ~FFlatVertexBuffer(); void BindVBO(); diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 2716c6a2c..b00396e21 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -113,7 +113,7 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) void gl_LoadModels(); void gl_FlushModels(); -void FGLRenderer::Initialize() +void FGLRenderer::Initialize(int width, int height) { mBuffers = new FGLRenderBuffers(); mBloomExtractShader = new FBloomExtractShader(); @@ -137,7 +137,7 @@ void FGLRenderer::Initialize() glpart = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart.png"), FTexture::TEX_MiscPatch); mirrortexture = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/mirror.png"), FTexture::TEX_MiscPatch); - mVBO = new FFlatVertexBuffer; + mVBO = new FFlatVertexBuffer(width, height); mSkyVBO = new FSkyVertexBuffer; if (gl.lightmethod != LM_SOFTWARE) mLights = new FLightBuffer(); else mLights = NULL; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 8a00e6ce4..0fe91dae2 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -129,7 +129,7 @@ public: void SetViewAngle(DAngle viewangle); void SetupView(float viewx, float viewy, float viewz, DAngle viewangle, bool mirror, bool planemirror); - void Initialize(); + void Initialize(int width, int height); void CreateScene(); void RenderMultipassStuff(); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 16bb6cd34..44118087d 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -525,16 +525,8 @@ void gl_FillScreen() gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); gl_RenderState.EnableTexture(false); gl_RenderState.Apply(); - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(0, 0, 0, 0, 0); - ptr++; - ptr->Set(0, (float)SCREENHEIGHT, 0, 0, 0); - ptr++; - ptr->Set((float)SCREENWIDTH, 0, 0, 0, 0); - ptr++; - ptr->Set((float)SCREENWIDTH, (float)SCREENHEIGHT, 0, 0, 0); - ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + // The fullscreen quad is stored at index 4 in the main vertex buffer. + glDrawArrays(GL_TRIANGLE_STRIP, 4, 4); } //========================================================================== diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 151683d56..495df07e8 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -164,7 +164,7 @@ void OpenGLFrameBuffer::InitializeState() //int h = GetHeight(); //glViewport(0, (trueH - h)/2, GetWidth(), GetHeight()); - GLRenderer->Initialize(); + GLRenderer->Initialize(GetWidth(), GetHeight()); GLRenderer->SetOutputViewport(nullptr); Begin2D(false); } From 675822004de6c698576cc2724b520673ca26d354 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 16:06:02 +0200 Subject: [PATCH 44/53] - use static buffer data and a uniform to handle the texture positioning of the present shader. That's again one less write access to the buffer. The uniform method was chosen because this way a buffer update can be completely avoided, and setting a single uniform is a lot cheaper and simpler to handle. --- src/gl/data/gl_vertexbuffer.cpp | 8 +++++++- src/gl/renderer/gl_postprocess.cpp | 12 ++++-------- src/gl/renderer/gl_renderer.h | 2 +- src/gl/shaders/gl_presentshader.cpp | 3 ++- src/gl/shaders/gl_presentshader.h | 1 + src/gl/shaders/gl_shader.h | 11 +++++++++++ wadsrc/static/shaders/glsl/screenquadscale.vp | 11 +++++++++++ 7 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 wadsrc/static/shaders/glsl/screenquadscale.vp diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 4cb0efd6a..8e27c34fe 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -126,7 +126,7 @@ FFlatVertexBuffer::FFlatVertexBuffer(int width, int height) map = new FFlatVertex[BUFFER_SIZE]; } mIndex = mCurIndex = 0; - mNumReserved = 8; + mNumReserved = 12; vbo_shadowdata.Resize(mNumReserved); // the first quad is reserved for handling coordinates through uniforms. @@ -141,6 +141,12 @@ FFlatVertexBuffer::FFlatVertexBuffer(int width, int height) vbo_shadowdata[6].Set((float)width, 0, 0, 0, 0); vbo_shadowdata[7].Set((float)width, (float)height, 0, 0, 0); + // and this is for the postprocessing copy operation + vbo_shadowdata[8].Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); + vbo_shadowdata[9].Set(-1.0f, 1.0f, 0, 0.0f, 1.f); + vbo_shadowdata[10].Set(1.0f, -1.0f, 0, 1.f, 0.0f); + vbo_shadowdata[11].Set(1.0f, 1.0f, 0, 1.f, 1.f); + } FFlatVertexBuffer::~FFlatVertexBuffer() diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 79bd31860..dd4cc71aa 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -108,16 +108,11 @@ EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) -void FGLRenderer::RenderScreenQuad(float maxU, float maxV) +void FGLRenderer::RenderScreenQuad() { - FFlatVertex *ptr = mVBO->GetBuffer(); mVBO->BindVBO(); gl_RenderState.ResetVertexBuffer(); - ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; - ptr->Set(-1.0f, 1.0f, 0, 0.0f, maxV); ptr++; - ptr->Set(1.0f, -1.0f, 0, maxU, 0.0f); ptr++; - ptr->Set(1.0f, 1.0f, 0, maxU, maxV); ptr++; - mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + glDrawArrays(GL_TRIANGLE_STRIP, 8, 4); } //----------------------------------------------------------------------------- @@ -357,9 +352,10 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) mPresentShader->Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); mPresentShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); } + mPresentShader->Scale.Set(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight()); + RenderScreenQuad(); } } diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 0fe91dae2..1a8883b3f 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -153,7 +153,7 @@ public: unsigned char *GetTextureBuffer(FTexture *tex, int &w, int &h); void SetupLevel(); - void RenderScreenQuad(float maxU = 1.0f, float maxV = 1.0f); + void RenderScreenQuad(); void SetFixedColormap (player_t *player); void WriteSavePic (player_t *player, FILE *file, int width, int height); void EndDrawScene(sector_t * viewsector); diff --git a/src/gl/shaders/gl_presentshader.cpp b/src/gl/shaders/gl_presentshader.cpp index 9998fda36..e40aa7a2c 100644 --- a/src/gl/shaders/gl_presentshader.cpp +++ b/src/gl/shaders/gl_presentshader.cpp @@ -53,7 +53,7 @@ void FPresentShader::Bind() { if (!mShader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330); mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present.fp", "", 330); mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/present"); @@ -63,6 +63,7 @@ void FPresentShader::Bind() Gamma.Init(mShader, "Gamma"); Contrast.Init(mShader, "Contrast"); Brightness.Init(mShader, "Brightness"); + Scale.Init(mShader, "UVScale"); } mShader.Bind(); } diff --git a/src/gl/shaders/gl_presentshader.h b/src/gl/shaders/gl_presentshader.h index 6bec79625..513af41cc 100644 --- a/src/gl/shaders/gl_presentshader.h +++ b/src/gl/shaders/gl_presentshader.h @@ -12,6 +12,7 @@ public: FBufferedUniform1f Gamma; FBufferedUniform1f Contrast; FBufferedUniform1f Brightness; + FBufferedUniform2f Scale; private: FShaderProgram mShader; diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index ca534c31d..a0b01d20d 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -123,6 +123,17 @@ public: glUniform2fv(mIndex, 1, newvalue); } } + + void Set(float f1, float f2) + { + if (mBuffer[0] != f1 || mBuffer[1] != f2) + { + mBuffer[0] = f1; + mBuffer[1] = f2; + glUniform2fv(mIndex, 1, mBuffer); + } + } + }; class FBufferedUniform4f diff --git a/wadsrc/static/shaders/glsl/screenquadscale.vp b/wadsrc/static/shaders/glsl/screenquadscale.vp new file mode 100644 index 000000000..2d7f505b4 --- /dev/null +++ b/wadsrc/static/shaders/glsl/screenquadscale.vp @@ -0,0 +1,11 @@ + +in vec4 PositionInProjection; +in vec2 UV; +uniform vec2 UVScale; +out vec2 TexCoord; + +void main() +{ + gl_Position = PositionInProjection; + TexCoord = UV * UVScale; +} From e5f88a9883adfe5316458e7db81c0f252ed14f26 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 16:18:07 +0200 Subject: [PATCH 45/53] - fixed: The textured automap was not using correct light levels. In order for the externally passed vertex attribute to work the buffer's color attrib array needs to be disabled for these. --- src/gl/data/gl_vertexbuffer.cpp | 27 +++++++++++++++++++++++++++ src/gl/data/gl_vertexbuffer.h | 1 + src/gl/renderer/gl_2ddrawer.cpp | 13 +++++++++++++ 3 files changed, 41 insertions(+) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 8e27c34fe..2faae2990 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -96,6 +96,33 @@ void FSimpleVertexBuffer::BindVBO() } } +void FSimpleVertexBuffer::EnableColorArray(bool on) +{ + if (on) + { + if (gl.glslversion > 0) + { + glEnableVertexAttribArray(VATTR_COLOR); + } + else + { + glEnableClientState(GL_COLOR_ARRAY); + } + } + else + { + if (gl.glslversion > 0) + { + glDisableVertexAttribArray(VATTR_COLOR); + } + else + { + glDisableClientState(GL_COLOR_ARRAY); + } + } +} + + void FSimpleVertexBuffer::set(FSimpleVertex *verts, int count) { glBindBuffer(GL_ARRAY_BUFFER, vbo_id); diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 31251653d..4d2252fe0 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -67,6 +67,7 @@ public: } void BindVBO(); void set(FSimpleVertex *verts, int count); + void EnableColorArray(bool on); }; class FFlatVertexBuffer : public FVertexBuffer diff --git a/src/gl/renderer/gl_2ddrawer.cpp b/src/gl/renderer/gl_2ddrawer.cpp index 75f76bbe6..67cb5f2f4 100644 --- a/src/gl/renderer/gl_2ddrawer.cpp +++ b/src/gl/renderer/gl_2ddrawer.cpp @@ -384,6 +384,8 @@ void F2DDrawer::AddPixel(int x1, int y1, int palcolor, uint32 color) void F2DDrawer::Flush() { + F2DDrawer::EDrawType lasttype = DrawTypeTexture; + if (mData.Size() == 0) return; SBYTE savedlightmode = glset.lightmode; // lightmode is only relevant for automap subsectors, @@ -394,6 +396,17 @@ void F2DDrawer::Flush() for (unsigned i = 0; i < mData.Size();) { DataGeneric *dg = (DataGeneric *)&mData[i]; + // DrawTypePoly may not use the color part of the vertex buffer because it needs to use gl_SetColor to produce proper output. + if (lasttype == DrawTypePoly && dg->mType != DrawTypePoly) + { + EnableColorArray(true); + } + else if (lasttype != DrawTypePoly && dg->mType == DrawTypePoly) + { + EnableColorArray(false); + } + lasttype = dg->mType; + switch (dg->mType) { default: From 56a60ebe8587d27cc000c449b0b3590a0f9f036b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 20:47:54 +0200 Subject: [PATCH 46/53] - restored a line that got accidentally deleted. --- src/gl/data/gl_vertexbuffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 2faae2990..77623b3ca 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -398,6 +398,7 @@ void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) void FFlatVertexBuffer::CreateVBO() { + vbo_shadowdata.Reserve(mNumReserved); CreateFlatVBO(); mCurIndex = mIndex = vbo_shadowdata.Size(); memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex)); From 19b65195eaf1216750c7252012b99c20d86c8de0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 10:07:06 +0200 Subject: [PATCH 47/53] - added an internal compatibility option to disable setting the line ID for the Plane_Align special. There have been reports for some Skulltag maps a few years back and I just ran across an old beta version of a map that got completely broken by this. --- src/compatibility.cpp | 1 + src/doomdef.h | 1 + src/p_setup.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 870d2ede6..ca5d8293c 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -111,6 +111,7 @@ static FCompatOption Options[] = { "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT }, { "disablepushwindowcheck", BCOMPATF_NOWINDOWCHECK, SLOT_BCOMPAT }, { "floatbob", BCOMPATF_FLOATBOB, SLOT_BCOMPAT }, + { "noslopeid", BCOMPATF_NOSLOPEID, SLOT_BCOMPAT }, // list copied from g_mapinfo.cpp { "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT }, diff --git a/src/doomdef.h b/src/doomdef.h index 9ebe45cf7..a36a7a1c2 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -358,6 +358,7 @@ enum BCOMPATF_LINKFROZENPROPS = 1 << 6, // Clearing PROP_TOTALLYFROZEN or PROP_FROZEN also clears the other BCOMPATF_NOWINDOWCHECK = 1 << 7, // Disable the window check in CheckForPushSpecial() BCOMPATF_FLOATBOB = 1 << 8, // Use Hexen's original method of preventing floatbobbing items from falling down + BCOMPATF_NOSLOPEID = 1 << 9, // disable line IDs on slopes. }; // phares 3/20/98: diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 8a69c2de2..92636fb0c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1959,7 +1959,7 @@ void P_SetLineID (int i, line_t *ld) break; case Plane_Align: - setid = ld->args[2]; + if (!(ib_compatflags & BCOMPATF_NOSLOPEID)) setid = ld->args[2]; break; case Static_Init: From b2a6512981b98840c4068588a13c421699931f52 Mon Sep 17 00:00:00 2001 From: yqco Date: Tue, 9 Aug 2016 02:11:13 -0600 Subject: [PATCH 48/53] Fix partial initialization in ACS PickActor function --- src/p_map.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_map.cpp b/src/p_map.cpp index e7aceba78..ec9fea20a 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4439,6 +4439,9 @@ AActor *P_LinePickActor(AActor *t1, DAngle angle, double distance, DAngle pitch, TData.Caller = t1; TData.hitGhosts = true; + TData.MThruSpecies = false; + TData.ThruActors = false; + TData.ThruSpecies = false; if (Trace(t1->PosAtZ(shootz), t1->Sector, direction, distance, actorMask, wallMask, t1, trace, TRACE_NoSky | TRACE_PortalRestrict, CheckForActor, &TData)) From 6b27d0c3ba5ae3cdb24ab621ef2b7c97d6e9418e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 15:11:11 +0200 Subject: [PATCH 49/53] - fixed: FPolyObj::RecalcActorFloorCeil altered the floorz of all actors in the same blockmap block as the polyobject, even when they were nowhere near its bounding box. This fix is still incomplete, it should really discard everything outside the polyobject, not outside its bounding box, but at least it eliminates the most severe occurences of dislocated items. --- src/po_man.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/po_man.cpp b/src/po_man.cpp index 001f308f1..e449e0d67 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1327,6 +1327,17 @@ void FPolyObj::RecalcActorFloorCeil(FBoundingBox bounds) const while ((actor = it.Next()) != NULL) { + // skip everything outside the bounding box. + if (actor->X() + actor->radius <= bounds.Left() || + actor->X() - actor->radius >= bounds.Right() || + actor->Y() + actor->radius <= bounds.Bottom() || + actor->Y() - actor->radius >= bounds.Top()) + { + continue; + } + // Todo: Be a little more thorough with what gets altered here + // because this can dislocate a lot of items that were spawned on + // the lower side of a sector boundary. P_FindFloorCeiling(actor); } } From 7104b011931b0dd936ed57304649f93c7814a149 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 17:09:12 +0200 Subject: [PATCH 50/53] - added Hexen compatible handling to specials that stop perpetual sector movement. This uses the same logic as Eternity. --- src/actionspecials.h | 4 ++-- src/p_ceiling.cpp | 20 +++++++++++++++----- src/p_lnspec.cpp | 34 ++++++++++++++++++++++++++++++---- src/p_plats.cpp | 12 +++++++++--- src/p_spec.h | 8 ++++---- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 4ab222b2c..9b9c38cb9 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -42,7 +42,7 @@ DEFINE_SPECIAL(Ceiling_LowerByValue, 40, 3, 5, 5) DEFINE_SPECIAL(Ceiling_RaiseByValue, 41, 3, 4, 4) DEFINE_SPECIAL(Ceiling_CrushAndRaise, 42, 3, 4, 4) DEFINE_SPECIAL(Ceiling_LowerAndCrush, 43, 3, 4, 4) -DEFINE_SPECIAL(Ceiling_CrushStop, 44, 1, 1, 1) +DEFINE_SPECIAL(Ceiling_CrushStop, 44, 1, 2, 2) DEFINE_SPECIAL(Ceiling_CrushRaiseAndStay, 45, 3, 4, 4) DEFINE_SPECIAL(Floor_CrushStop, 46, 1, 1, 1) DEFINE_SPECIAL(Ceiling_MoveToValue, 47, 3, 5, 5) @@ -59,7 +59,7 @@ DEFINE_SPECIAL(Sector_SetPortal, 57, -1, -1, 5) DEFINE_SPECIAL(Sector_CopyScroller, 58, -1, -1, 2) DEFINE_SPECIAL(Polyobj_OR_MoveToSpot, 59, 3, 3, 3) DEFINE_SPECIAL(Plat_PerpetualRaise, 60, 3, 3, 3) -DEFINE_SPECIAL(Plat_Stop, 61, 1, 1, 1) +DEFINE_SPECIAL(Plat_Stop, 61, 1, 2, 2) DEFINE_SPECIAL(Plat_DownWaitUpStay, 62, 3, 3, 3) DEFINE_SPECIAL(Plat_DownByValue, 63, 4, 4, 4) DEFINE_SPECIAL(Plat_UpWaitDownStay, 64, 3, 3, 3) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index c635d9743..888b67b6c 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -552,21 +552,31 @@ void P_ActivateInStasisCeiling (int tag) // //============================================================================ -bool EV_CeilingCrushStop (int tag) +bool EV_CeilingCrushStop (int tag, bool remove) { bool rtn = false; DCeiling *scan; TThinkerIterator iterator; - while ( (scan = iterator.Next ()) ) + scan = iterator.Next(); + while (scan != nullptr) { + DCeiling *next = iterator.Next(); if (scan->m_Tag == tag && scan->m_Direction != 0) { - SN_StopSequence (scan->m_Sector, CHAN_CEILING); - scan->m_OldDirection = scan->m_Direction; - scan->m_Direction = 0; // in-stasis; + if (!remove) + { + SN_StopSequence(scan->m_Sector, CHAN_CEILING); + scan->m_OldDirection = scan->m_Direction; + scan->m_Direction = 0; // in-stasis; + } + else + { + scan->Destroy(); + } rtn = true; } + scan = next; } return rtn; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index d0a56ee87..c8c7db74d 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -686,9 +686,22 @@ FUNC(LS_Ceiling_LowerAndCrushDist) } FUNC(LS_Ceiling_CrushStop) -// Ceiling_CrushStop (tag) +// Ceiling_CrushStop (tag, remove) { - return EV_CeilingCrushStop (arg0); + bool remove; + switch (arg3) + { + case 1: + remove = false; + break; + case 2: + remove = true; + break; + default: + remove = gameinfo.gametype == GAME_Hexen; + break; + } + return EV_CeilingCrushStop (arg0, remove); } FUNC(LS_Ceiling_CrushRaiseAndStay) @@ -890,9 +903,22 @@ FUNC(LS_Plat_PerpetualRaiseLip) } FUNC(LS_Plat_Stop) -// Plat_Stop (tag) +// Plat_Stop (tag, remove?) { - EV_StopPlat (arg0); + bool remove; + switch (arg3) + { + case 1: + remove = false; + break; + case 2: + remove = true; + break; + default: + remove = gameinfo.gametype == GAME_Hexen; + break; + } + EV_StopPlat(arg0, remove); return true; } diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 55ba39fe5..96fec71c1 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -429,15 +429,21 @@ void DPlat::Stop () m_Status = in_stasis; } -void EV_StopPlat (int tag) +void EV_StopPlat (int tag, bool remove) { DPlat *scan; TThinkerIterator iterator; - while ( (scan = iterator.Next ()) ) + scan = iterator.Next(); + while (scan != nullptr) { + DPlat *next = iterator.Next(); if (scan->m_Status != DPlat::in_stasis && scan->m_Tag == tag) - scan->Stop (); + { + if (!remove) scan->Stop(); + else scan->Destroy(); + } + scan = next; } } diff --git a/src/p_spec.h b/src/p_spec.h index 125b2374e..d7abd4b42 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -212,13 +212,13 @@ private: friend bool EV_DoPlat (int tag, line_t *line, EPlatType type, double height, double speed, int delay, int lip, int change); - friend void EV_StopPlat (int tag); + friend void EV_StopPlat (int tag, bool remove); friend void P_ActivateInStasis (int tag); }; bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, double height, double speed, int delay, int lip, int change); -void EV_StopPlat (int tag); +void EV_StopPlat (int tag, bool remove); void P_ActivateInStasis (int tag); // @@ -434,14 +434,14 @@ private: DCeiling (); friend bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush); - friend bool EV_CeilingCrushStop (int tag); + friend bool EV_CeilingCrushStop (int tag, bool remove); friend void P_ActivateInStasisCeiling (int tag); }; bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush); bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom); -bool EV_CeilingCrushStop (int tag); +bool EV_CeilingCrushStop (int tag, bool remove); void P_ActivateInStasisCeiling (int tag); From b4e712ab019f13a33f718c95b7d1afcc5fb54acf Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 9 Aug 2016 20:15:13 +0200 Subject: [PATCH 51/53] - made disabling the push window check a real compatibility option. No idea why this was a hidden one, this one definitely needs to be in the menu. - set some required compatibility options for Super Sonic Doom. --- src/compatibility.cpp | 2 +- src/d_main.cpp | 3 ++- src/doomdef.h | 4 ++-- src/g_mapinfo.cpp | 1 + src/p_map.cpp | 2 +- wadsrc/static/compatibility.txt | 12 ++++++++++++ wadsrc/static/language.enu | 2 ++ wadsrc/static/menudef.txt | 2 ++ 8 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/compatibility.cpp b/src/compatibility.cpp index ca5d8293c..5bb51129a 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -109,7 +109,6 @@ static FCompatOption Options[] = { "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT }, { "rebuildnodes", BCOMPATF_REBUILDNODES, SLOT_BCOMPAT }, { "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT }, - { "disablepushwindowcheck", BCOMPATF_NOWINDOWCHECK, SLOT_BCOMPAT }, { "floatbob", BCOMPATF_FLOATBOB, SLOT_BCOMPAT }, { "noslopeid", BCOMPATF_NOSLOPEID, SLOT_BCOMPAT }, @@ -149,6 +148,7 @@ static FCompatOption Options[] = { "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 }, { "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 }, { "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 }, + { "disablepushwindowcheck", COMPATF2_PUSHWINDOW, SLOT_COMPAT2 }, { NULL, 0, 0 } }; diff --git a/src/d_main.cpp b/src/d_main.cpp index 4e360a38e..9f4568614 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -574,7 +574,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL) case 4: // Old ZDoom compat mode v = COMPATF_SOUNDTARGET | COMPATF_LIGHT; - w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT; + w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT | COMPATF2_PUSHWINDOW; break; case 5: // MBF compat mode @@ -631,6 +631,7 @@ CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF); CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE); CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT); CVAR (Flag, compat_teleport, compatflags2, COMPATF2_TELEPORT); +CVAR (Flag, compat_pushwindow, compatflags2, COMPATF2_PUSHWINDOW); //========================================================================== // diff --git a/src/doomdef.h b/src/doomdef.h index a36a7a1c2..5a1d1f95f 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -342,7 +342,8 @@ enum : unsigned int COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat() COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script) - COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions + COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions + COMPATF2_PUSHWINDOW = 1 << 6, // Disable the window check in CheckForPushSpecial() }; // Emulate old bugs for select maps. These are not exposed by a cvar @@ -356,7 +357,6 @@ enum BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior BCOMPATF_REBUILDNODES = 1 << 5, // Force node rebuild BCOMPATF_LINKFROZENPROPS = 1 << 6, // Clearing PROP_TOTALLYFROZEN or PROP_FROZEN also clears the other - BCOMPATF_NOWINDOWCHECK = 1 << 7, // Disable the window check in CheckForPushSpecial() BCOMPATF_FLOATBOB = 1 << 8, // Use Hexen's original method of preventing floatbobbing items from falling down BCOMPATF_NOSLOPEID = 1 << 9, // disable line IDs on slopes. }; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 7d3df69e0..ac1552b99 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1342,6 +1342,7 @@ MapFlagHandlers[] = { "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE }, { "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT }, { "compat_teleport", MITYPE_COMPATFLAG, 0, COMPATF2_TELEPORT }, + { "compat_pushwindow", MITYPE_COMPATFLAG, 0, COMPATF2_PUSHWINDOW }, { "cd_start_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end1_track", MITYPE_EATNEXT, 0, 0 }, { "cd_end2_track", MITYPE_EATNEXT, 0, 0 }, diff --git a/src/p_map.cpp b/src/p_map.cpp index ec9fea20a..278249a64 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1912,7 +1912,7 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 * { if (line->special && !(mobj->flags6 & MF6_NOTRIGGER)) { - if (posforwindowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL) + if (posforwindowcheck && !(i_compatflags2 & COMPATF2_PUSHWINDOW) && line->backsector != NULL) { // Make sure this line actually blocks us and is not a window // or similar construct we are standing inside of. DVector3 pos = mobj->PosRelative(line); diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 25395dad6..d964cbf75 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -397,6 +397,7 @@ D62DCA9EC226DE49108D5DD9271F7631 // Cheogsh 2 map04 E89CCC7E155F1032F693359CC219BE6C // hexen.wad map30 B9DFF13207EACAC675C71D82624D0007 // XtheaterIII map01 +6941BDC2F80C0FEBE34EFA23D5FB72B7 // sonic.wad map10 { DisablePushWindowCheck } @@ -435,6 +436,17 @@ C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07 teleport } +8570AA0D6737C0A19DB66767764F157F // sonic.wad map04 +{ + noslopeid +} + +05AA32F1D2220A462DCDA245ED22B94B // sonic.wad map09 +{ + polyobj +} + + D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9 19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update { diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 03a3ffb1a..03212768e 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2069,6 +2069,8 @@ CMPTMNU_SILENTINSTANTFLOORS = "Inst. moving floors are not silent"; CMPTMNU_SECTORSOUNDS = "Sector sounds use center as source"; CMPTMNU_SOUNDCUTOFF = "Sounds stop when actor vanishes"; CMPTMNU_SOUNDTARGET = "Use original sound target handling"; +CMPTMNU_TELEPORT = "Scripted teleports don't trigger sector actions"; +CMPTMNU_PUSHWINDOW = "Non-blocking lines can be pushed"; // Sound Options SNDMNU_TITLE = "SOUND OPTIONS"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index ca36c1975..077dc0608 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1320,6 +1320,8 @@ OptionMenu "CompatibilityOptions" Option "$CMPTMNU_FLOORMOVE", "compat_floormove", "YesNo" Option "$CMPTMNU_POINTONLINE", "compat_pointonline", "YesNo" Option "$CMPTMNU_MULTIEXIT", "compat_multiexit", "YesNo" + Option "$CMPTMNU_TELEPORT", "compat_teleport", "YesNo" + Option "$CMPTMNU_PUSHWINDOW", "compat_pushwindow", "YesNo" StaticText " " StaticText "$CMPTMNU_PHYSICSBEHAVIOR",1 From 0e5a3ebe50354c222586cba00ae0bde5360581db Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 10 Aug 2016 00:35:42 +0200 Subject: [PATCH 52/53] - fixed bad function call in vertex buffer init code. --- src/gl/data/gl_vertexbuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 77623b3ca..637de85aa 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -398,7 +398,7 @@ void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane) void FFlatVertexBuffer::CreateVBO() { - vbo_shadowdata.Reserve(mNumReserved); + vbo_shadowdata.Resize(mNumReserved); CreateFlatVBO(); mCurIndex = mIndex = vbo_shadowdata.Size(); memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex)); From 0fdd80eae719545255d487bbe5880ad11fe418d2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 10 Aug 2016 16:32:31 +0200 Subject: [PATCH 53/53] - removed debug Printf. --- src/gl/system/gl_wipe.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index bd03ca96e..59adc7e9e 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -341,7 +341,6 @@ bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); float a = clamp(Clock / 32.f, 0.f, 1.f); - Printf("%f\n", a); gl_RenderState.SetColorAlpha(0xffffff, a); gl_RenderState.Apply(); fb->wipeendscreen->Bind(0, 0, false);