From 1d15fe63a698a95a66dbb69cb1c60f16e09ac333 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 31 May 2020 10:24:04 +0200 Subject: [PATCH] - another backend update, pulling in the sky renderer. --- source/CMakeLists.txt | 2 + source/build/src/mdsprite.cpp | 3 +- source/build/src/polymost.cpp | 6 +- source/build/src/voxmodel.cpp | 5 +- source/common/models/modelrenderer.h | 2 +- .../hwrenderer/data/hw_renderstate.h | 2 +- .../rendering/hwrenderer/data/hw_skydome.cpp | 482 ++++++++++++++++++ .../rendering/hwrenderer/data/hw_skydome.h | 90 ++++ .../rendering/gl/renderer/gl_renderer.cpp | 22 +- .../core/rendering/gl/renderer/gl_renderer.h | 1 - .../rendering/gl/renderer/gl_stereo3d.cpp | 388 ++++++++++++++ .../rendering/gl/system/gl_framebuffer.cpp | 221 ++++++-- .../core/rendering/gl/system/gl_framebuffer.h | 22 +- source/glbackend/gl_texture.cpp | 5 + source/glbackend/glbackend.cpp | 10 +- source/glbackend/glbackend.h | 16 +- source/glbackend/hw_draw2d.cpp | 11 +- .../{gl_renderstate.h => pm_renderstate.h} | 32 -- wadsrc/static/engine/grpinfo.txt | 3 + 19 files changed, 1197 insertions(+), 126 deletions(-) create mode 100644 source/common/rendering/hwrenderer/data/hw_skydome.cpp create mode 100644 source/common/rendering/hwrenderer/data/hw_skydome.h create mode 100644 source/core/rendering/gl/renderer/gl_stereo3d.cpp rename source/glbackend/{gl_renderstate.h => pm_renderstate.h} (84%) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index a325aa021..29ad7147f 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -883,6 +883,7 @@ set (PCH_SOURCES common/rendering/hwrenderer/data/hw_vrmodes.cpp common/rendering/hwrenderer/data/hw_lightbuffer.cpp common/rendering/hwrenderer/data/hw_aabbtree.cpp + common/rendering/hwrenderer/data/hw_skydome.cpp common/rendering/hwrenderer/data/hw_shadowmap.cpp common/rendering/hwrenderer/data/hw_shaderpatcher.cpp common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp @@ -938,6 +939,7 @@ set (PCH_SOURCES core/input/m_joy.cpp core/rendering/gl/renderer/gl_renderer.cpp + core/rendering/gl/renderer/gl_stereo3d.cpp core/rendering/gl/system/gl_framebuffer.cpp ) diff --git a/source/build/src/mdsprite.cpp b/source/build/src/mdsprite.cpp index dccf0826e..ca25be004 100644 --- a/source/build/src/mdsprite.cpp +++ b/source/build/src/mdsprite.cpp @@ -17,6 +17,7 @@ #include "v_video.h" #include "flatvertices.h" #include "texturemanager.h" +#include "hw_renderstate.h" #include "../../glbackend/glbackend.h" static int32_t curextra=MAXTILES; @@ -1475,7 +1476,7 @@ static void md3draw_handle_triangles(const md3surf_t *s, uint16_t *indexhandle, vt->SetVertex(vertlist[k].x, vertlist[k].y); } } - GLInterface.Draw(DT_TRIANGLES, data.second, s->numtris *3); + GLInterface.Draw(DT_Triangles, data.second, s->numtris *3); #ifndef USE_GLEXT UNREFERENCED_PARAMETER(texunits); diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp index 935816f10..7542e49ed 100644 --- a/source/build/src/polymost.cpp +++ b/source/build/src/polymost.cpp @@ -20,7 +20,7 @@ Ken Silverman's official web site: http://www.advsys.net/ken #include "flatvertices.h" #include "palettecontainer.h" #include "texturemanager.h" -#include "gamecontrol.h" +#include "hw_renderstate.h" CVAR(Bool, hw_detailmapping, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, hw_glowmapping, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) @@ -479,7 +479,7 @@ static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32 r * (1.f / 1024.f)); } - GLInterface.Draw(DT_TRIANGLE_FAN, data.second, npoints); + GLInterface.Draw(DT_TriangleFan, data.second, npoints); GLInterface.SetTinting(-1, 0xffffff, 0xffffff); GLInterface.UseDetailMapping(false); @@ -491,7 +491,7 @@ static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32 vec3d_t const bxtex = xtex, bytex = ytex, botex = otex; xtex = xtex2, ytex = ytex2, otex = otex2; GLInterface.SetColorMask(false); - GLInterface.Draw(DT_TRIANGLE_FAN, data.second, npoints); + GLInterface.Draw(DT_TriangleFan, data.second, npoints); GLInterface.SetColorMask(true); xtex = bxtex, ytex = bytex, otex = botex; } diff --git a/source/build/src/voxmodel.cpp b/source/build/src/voxmodel.cpp index f136188bf..3b76c21ac 100644 --- a/source/build/src/voxmodel.cpp +++ b/source/build/src/voxmodel.cpp @@ -11,6 +11,7 @@ #include "mdsprite.h" #include "v_video.h" #include "flatvertices.h" +#include "hw_renderstate.h" #include "texturemanager.h" #include "palette.h" @@ -1174,7 +1175,7 @@ int32_t polymost_voxdraw(voxmodel_t *m, tspriteptr_t const tspr) f = 1 /*clut[fi++]*/; if (qdone > 0) { - GLInterface.Draw(DT_TRIANGLES, qstart, qdone * 6); + GLInterface.Draw(DT_Triangles, qstart, qdone * 6); qstart += qdone * 6; qdone = 0; } @@ -1205,7 +1206,7 @@ int32_t polymost_voxdraw(voxmodel_t *m, tspriteptr_t const tspr) qdone++; } - GLInterface.Draw(DT_TRIANGLES, qstart, qdone * 6); + GLInterface.Draw(DT_Triangles, qstart, qdone * 6); GLInterface.SetClamp(prevClamp); //------------ GLInterface.SetCull(Cull_None); diff --git a/source/common/models/modelrenderer.h b/source/common/models/modelrenderer.h index 1018d7ebb..38786afe6 100644 --- a/source/common/models/modelrenderer.h +++ b/source/common/models/modelrenderer.h @@ -1,4 +1,4 @@ - +#pragma once #include "renderstyle.h" #include "matrix.h" #include "model.h" diff --git a/source/common/rendering/hwrenderer/data/hw_renderstate.h b/source/common/rendering/hwrenderer/data/hw_renderstate.h index 5da24d209..fac9574f7 100644 --- a/source/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/source/common/rendering/hwrenderer/data/hw_renderstate.h @@ -87,7 +87,7 @@ struct FStateVec4 struct FMaterialState { - FMaterial *mMaterial; + FMaterial *mMaterial = nullptr; int mClampMode; int mTranslation; int mOverrideShader; diff --git a/source/common/rendering/hwrenderer/data/hw_skydome.cpp b/source/common/rendering/hwrenderer/data/hw_skydome.cpp new file mode 100644 index 000000000..45c813fc7 --- /dev/null +++ b/source/common/rendering/hwrenderer/data/hw_skydome.cpp @@ -0,0 +1,482 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2003-2018 Christoph Oelckers +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** +** Draws the sky. Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky. +** +** for FSkyVertexBuffer::SkyVertex only: +**--------------------------------------------------------------------------- +** Copyright 2003 Tim Stump +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ +#include "filesystem.h" +#include "cmdlib.h" +#include "bitmap.h" +#include "skyboxtexture.h" +#include "hw_material.h" +#include "hw_skydome.h" +#include "hw_renderstate.h" +#include "v_video.h" +#include "hwrenderer/data/buffers.h" + +// 57 world units roughly represent one sky texel for the glTranslate call. +enum +{ + skyoffsetfactor = 57 +}; + + +//----------------------------------------------------------------------------- +// +// Shamelessly lifted from Doomsday (written by Jaakko Keränen) +// also shamelessly lifted from ZDoomGL! ;) +// +//----------------------------------------------------------------------------- +CVAR(Float, skyoffset, 0, 0) // for testing + + +struct SkyColor +{ + FTextureID Texture; + std::pair Colors; +}; + +static TArray SkyColors; + +std::pair& R_GetSkyCapColor(FGameTexture* tex) +{ + for (auto& sky : SkyColors) + { + if (sky.Texture == tex->GetID()) return sky.Colors; + } + + auto itex = tex->GetTexture(); + SkyColor sky; + + FBitmap bitmap = itex->GetBgraBitmap(nullptr); + int w = bitmap.GetWidth(); + int h = bitmap.GetHeight(); + + const uint32_t* buffer = (const uint32_t*)bitmap.GetPixels(); + if (buffer) + { + sky.Colors.first = averageColor((uint32_t*)buffer, w * MIN(30, h), 0); + if (h > 30) + { + sky.Colors.second = averageColor(((uint32_t*)buffer) + (h - 30) * w, w * 30, 0); + } + else sky.Colors.second = sky.Colors.first; + } + sky.Texture = tex->GetID(); + SkyColors.Push(sky); + + return SkyColors.Last().Colors; +} + + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +FSkyVertexBuffer::FSkyVertexBuffer() +{ + CreateDome(); + mVertexBuffer = screen->CreateVertexBuffer(); + + static const FVertexBufferAttribute format[] = { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(FSkyVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(FSkyVertex, u) }, + { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(FSkyVertex, color) } + }; + mVertexBuffer->SetFormat(1, 3, sizeof(FSkyVertex), format); + mVertexBuffer->SetData(mVertices.Size() * sizeof(FSkyVertex), &mVertices[0], true); +} + +FSkyVertexBuffer::~FSkyVertexBuffer() +{ + delete mVertexBuffer; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::SkyVertex(int r, int c, bool zflip) +{ + static const FAngle maxSideAngle = 60.f; + static const float scale = 10000.; + + FAngle topAngle = (c / (float)mColumns * 360.f); + FAngle sideAngle = maxSideAngle * float(mRows - r) / float(mRows); + float height = sideAngle.Sin(); + float realRadius = scale * sideAngle.Cos(); + FVector2 pos = topAngle.ToVector(realRadius); + float z = (!zflip) ? scale * height : -scale * height; + + FSkyVertex vert; + + vert.color = r == 0 ? 0xffffff : 0xffffffff; + + // And the texture coordinates. + if (!zflip) // Flipped Y is for the lower hemisphere. + { + vert.u = (-c / (float)mColumns); + vert.v = (r / (float)mRows); + } + else + { + vert.u = (-c / (float)mColumns); + vert.v = 1.0f + ((mRows - r) / (float)mRows); + } + + if (r != 4) z += 300; + // And finally the vertex. + vert.x = -pos.X; // Doom mirrors the sky vertically! + vert.y = z - 1.f; + vert.z = pos.Y; + + mVertices.Push(vert); +} + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::CreateSkyHemisphere(int hemi) +{ + int r, c; + bool zflip = !!(hemi & SKYHEMI_LOWER); + + mPrimStart.Push(mVertices.Size()); + + for (c = 0; c < mColumns; c++) + { + SkyVertex(1, c, zflip); + } + + // The total number of triangles per hemisphere can be calculated + // as follows: rows * columns * 2 + 2 (for the top cap). + for (r = 0; r < mRows; r++) + { + mPrimStart.Push(mVertices.Size()); + for (c = 0; c <= mColumns; c++) + { + SkyVertex(r + zflip, c, zflip); + SkyVertex(r + 1 - zflip, c, zflip); + } + } +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::CreateDome() +{ + // the first thing we put into the buffer is the fog layer object which is just 4 triangles around the viewpoint. + + mVertices.Reserve(12); + mVertices[0].Set(1.0f, 1.0f, -1.0f); + mVertices[1].Set(1.0f, -1.0f, -1.0f); + mVertices[2].Set(-1.0f, 0.0f, -1.0f); + + mVertices[3].Set(1.0f, 1.0f, -1.0f); + mVertices[4].Set(1.0f, -1.0f, -1.0f); + mVertices[5].Set(0.0f, 0.0f, 1.0f); + + mVertices[6].Set(-1.0f, 0.0f, -1.0f); + mVertices[7].Set(1.0f, 1.0f, -1.0f); + mVertices[8].Set(0.0f, 0.0f, 1.0f); + + mVertices[9].Set(1.0f, -1.0f, -1.0f); + mVertices[10].Set(-1.0f, 0.0f, -1.0f); + mVertices[11].Set(0.0f, 0.0f, 1.0f); + + mColumns = 128; + mRows = 4; + 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].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].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].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].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].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].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].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].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); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelMatrix, VSMatrix &textureMatrix, bool tiled) +{ + float texw = tex->GetDisplayWidth(); + float texh = tex->GetDisplayHeight(); + + modelMatrix.loadIdentity(); + modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f); + + float xscale = texw < 1024.f ? floor(1024.f / float(texw)) : 1.f; + float yscale = 1.f; + auto texskyoffset = tex->GetSkyOffset() + skyoffset; + if (texh <= 128 && tiled) + { + modelMatrix.translate(0.f, (-40 + texskyoffset)*skyoffsetfactor, 0.f); + modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); + yscale = 240.f / texh; + } + else if (texh < 128) + { + // smaller sky textures must be tiled. We restrict it to 128 sky pixels, though + modelMatrix.translate(0.f, -1250.f, 0.f); + modelMatrix.scale(1.f, 128 / 230.f, 1.f); + yscale = float(128 / texh); // intentionally left as integer. + } + else if (texh < 200) + { + modelMatrix.translate(0.f, -1250.f, 0.f); + modelMatrix.scale(1.f, texh / 230.f, 1.f); + } + else if (texh <= 240) + { + modelMatrix.translate(0.f, (200 - texh + texskyoffset)*skyoffsetfactor, 0.f); + modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f); + } + else + { + modelMatrix.translate(0.f, (-40 + texskyoffset)*skyoffsetfactor, 0.f); + modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); + yscale = 240.f / texh; + } + textureMatrix.loadIdentity(); + textureMatrix.scale(mirror ? -xscale : xscale, yscale, 1.f); + textureMatrix.translate(1.f, y_offset / texh, 1.f); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::RenderRow(FRenderState& state, EDrawType prim, int row, bool apply) +{ + state.Draw(prim, mPrimStart[row], mPrimStart[row + 1] - mPrimStart[row]); +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled) +{ + if (tex) + { + state.SetMaterial(tex, UF_Texture, 0, CLAMP_NONE, 0, -1); + state.EnableModelMatrix(true); + state.EnableTextureMatrix(true); + + SetupMatrices(tex, x_offset, y_offset, mirror, mode, state.mModelMatrix, state.mTextureMatrix, tiled); + } + + int rc = mRows + 1; + + // The caps only get drawn for the main layer but not for the overlay. + if (mode == FSkyVertexBuffer::SKYMODE_MAINLAYER && tex != NULL) + { + auto& col = R_GetSkyCapColor(tex); + state.SetObjectColor(col.first); + state.EnableTexture(false); + RenderRow(state, DT_TriangleFan, 0); + + state.SetObjectColor(col.second); + RenderRow(state, DT_TriangleFan, rc); + state.EnableTexture(true); + } + state.SetObjectColor(0xffffffff); + for (int i = 1; i <= mRows; i++) + { + RenderRow(state, DT_TriangleStrip, i, i == 1); + RenderRow(state, DT_TriangleStrip, rc + i, false); + } + + state.EnableTextureMatrix(false); + state.EnableModelMatrix(false); +} + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void FSkyVertexBuffer::RenderBox(FRenderState& state, FTextureID texno, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2) +{ + int faces; + + state.EnableModelMatrix(true); + state.mModelMatrix.loadIdentity(); + state.mModelMatrix.scale(1, 1 / stretch, 1); // Undo the map's vertical scaling as skyboxes are true cubes. + + if (!sky2) + state.mModelMatrix.rotate(-180.0f + x_offset, skyrotatevector.X, skyrotatevector.Z, skyrotatevector.Y); + else + state.mModelMatrix.rotate(-180.0f + x_offset, skyrotatevector2.X, skyrotatevector2.Z, skyrotatevector2.Y); + + if (tex->GetSkyFace(5)) + { + faces = 4; + + // north + state.SetMaterial(tex->GetSkyFace(0), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(0), 4); + + // east + state.SetMaterial(tex->GetSkyFace(1), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(1), 4); + + // south + state.SetMaterial(tex->GetSkyFace(2), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(2), 4); + + // west + state.SetMaterial(tex->GetSkyFace(3), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(3), 4); + } + else + { + faces = 1; + state.SetMaterial(tex->GetSkyFace(0), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(-1), 10); + } + + // top + state.SetMaterial(tex->GetSkyFace(faces), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(tex->GetSkyFlip() ? 6 : 5), 4); + + // bottom + state.SetMaterial(tex->GetSkyFace(faces + 1), UF_Texture, 0, CLAMP_XY, 0, -1); + state.Draw(DT_TriangleStrip, FaceStart(4), 4); + + state.EnableModelMatrix(false); +} + diff --git a/source/common/rendering/hwrenderer/data/hw_skydome.h b/source/common/rendering/hwrenderer/data/hw_skydome.h new file mode 100644 index 000000000..7cbd37948 --- /dev/null +++ b/source/common/rendering/hwrenderer/data/hw_skydome.h @@ -0,0 +1,90 @@ +#pragma once + +#include "matrix.h" +#include "hwrenderer/data/buffers.h" +#include "hw_renderstate.h" +#include "skyboxtexture.h" + +class FGameTexture; +class FRenderState; +class IVertexBuffer; +struct HWSkyPortal; +struct HWDrawInfo; + +struct FSkyVertex +{ + float x, y, z, u, v; + 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; + } + + 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 +{ + friend struct HWSkyPortal; +public: + static const int SKYHEMI_UPPER = 1; + static const int SKYHEMI_LOWER = 2; + + enum + { + SKYMODE_MAINLAYER = 0, + SKYMODE_SECONDLAYER = 1, + SKYMODE_FOGLAYER = 2 + }; + + IVertexBuffer *mVertexBuffer; + + TArray mVertices; + TArray mPrimStart; + + 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(); + +public: + + FSkyVertexBuffer(); + ~FSkyVertexBuffer(); + void SetupMatrices(FGameTexture *tex, float x_offset, float y_offset, bool mirror, int mode, VSMatrix &modelmatrix, VSMatrix &textureMatrix, bool tiled); + std::pair GetBufferObjects() const + { + return std::make_pair(mVertexBuffer, nullptr); + } + + int FaceStart(int i) + { + if (i >= 0 && i < 7) return mFaceStart[i]; + else return mSideStart; + } + + void RenderRow(FRenderState& state, EDrawType prim, int row, bool apply = true); + void RenderDome(FRenderState& state, FGameTexture* tex, float x_offset, float y_offset, bool mirror, int mode, bool tiled); + void RenderBox(FRenderState& state, FTextureID texno, FSkyBox* tex, float x_offset, bool sky2, float stretch, const FVector3& skyrotatevector, const FVector3& skyrotatevector2); + +}; diff --git a/source/core/rendering/gl/renderer/gl_renderer.cpp b/source/core/rendering/gl/renderer/gl_renderer.cpp index 1b3ea328f..7735e9eb4 100644 --- a/source/core/rendering/gl/renderer/gl_renderer.cpp +++ b/source/core/rendering/gl/renderer/gl_renderer.cpp @@ -39,15 +39,10 @@ #include "filesystem.h" #include "i_time.h" #include "cmdlib.h" -#include "m_png.h" #include "version.h" -#include "texturemanager.h" -#include "model.h" -//#include "hwrenderer/utility/hw_clock.h" - -#include "gl_load/gl_interface.h" +#include "gl_interface.h" #include "gl/system/gl_framebuffer.h" -#include "gamecvars.h" +#include "hw_cvars.h" #include "gl_debug.h" #include "gl/renderer/gl_renderer.h" #include "gl_renderstate.h" @@ -56,18 +51,14 @@ #include "flatvertices.h" #include "gl_samplers.h" #include "hw_lightbuffer.h" -//#include "hwrenderer/data/hw_viewpointbuffer.h" #include "r_videoscale.h" -//#include "r_data/models/models.h" +#include "model.h" #include "gl_postprocessstate.h" #include "gl_buffers.h" #include "gl_hwtexture.h" -#include "build.h" +#include "texturemanager.h" EXTERN_CVAR(Int, screenblocks) -EXTERN_CVAR(Bool, cl_capfps) - -extern bool NoInterpolateView; namespace OpenGLRenderer { @@ -195,9 +186,4 @@ void FGLRenderer::BeginFrame() mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); } -void FGLRenderer::PresentStereo() -{ - -} - } diff --git a/source/core/rendering/gl/renderer/gl_renderer.h b/source/core/rendering/gl/renderer/gl_renderer.h index 125e5ea89..79df2afd7 100644 --- a/source/core/rendering/gl/renderer/gl_renderer.h +++ b/source/core/rendering/gl/renderer/gl_renderer.h @@ -78,7 +78,6 @@ public: void CopyToBackbuffer(const IntRect *bounds, bool applyGamma); void DrawPresentTexture(const IntRect &box, bool applyGamma); void Flush(); - //void Draw2D(F2DDrawer *data); void BeginFrame(); bool StartOffscreen(); diff --git a/source/core/rendering/gl/renderer/gl_stereo3d.cpp b/source/core/rendering/gl/renderer/gl_stereo3d.cpp new file mode 100644 index 000000000..edd64dd8c --- /dev/null +++ b/source/core/rendering/gl/renderer/gl_stereo3d.cpp @@ -0,0 +1,388 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2015 Christopher Bruns +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_stereo3d.cpp +** Stereoscopic 3D API +** +*/ + +#include "gl_system.h" +#include "gl/renderer/gl_renderer.h" +#include "gl_renderbuffers.h" +#include "hw_vrmodes.h" +#include "gl/system/gl_framebuffer.h" +#include "gl_postprocessstate.h" +#include "gl/system/gl_framebuffer.h" +#include "gl_shaderprogram.h" +#include "gl_buffers.h" +#include "templates.h" + +EXTERN_CVAR(Int, vr_mode) +EXTERN_CVAR(Float, vid_saturation) +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) +EXTERN_CVAR(Int, gl_satformula) +EXTERN_CVAR(Int, gl_dither_bpc) + +void UpdateVRModes(bool considerQuadBuffered = true); + +namespace OpenGLRenderer +{ + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentAnaglyph(bool r, bool g, bool b) +{ + mBuffers->BindOutputFB(); + ClearBorders(); + + glColorMask(r, g, b, 1); + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glColorMask(!r, !g, !b, 1); + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glColorMask(1, 1, 1, 1); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentSideBySide() +{ + mBuffers->BindOutputFB(); + ClearBorders(); + + // Compute screen regions to use for left and right eye views + int leftWidth = screen->mOutputLetterbox.width / 2; + int rightWidth = screen->mOutputLetterbox.width - leftWidth; + IntRect leftHalfScreen = screen->mOutputLetterbox; + leftHalfScreen.width = leftWidth; + IntRect rightHalfScreen = screen->mOutputLetterbox; + rightHalfScreen.width = rightWidth; + rightHalfScreen.left += leftWidth; + + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(leftHalfScreen, true); + + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(rightHalfScreen, true); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentTopBottom() +{ + mBuffers->BindOutputFB(); + ClearBorders(); + + // Compute screen regions to use for left and right eye views + int topHeight = screen->mOutputLetterbox.height / 2; + int bottomHeight = screen->mOutputLetterbox.height - topHeight; + IntRect topHalfScreen = screen->mOutputLetterbox; + topHalfScreen.height = topHeight; + topHalfScreen.top = topHeight; + IntRect bottomHalfScreen = screen->mOutputLetterbox; + bottomHalfScreen.height = bottomHeight; + bottomHalfScreen.top = 0; + + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(topHalfScreen, true); + + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(bottomHalfScreen, true); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::prepareInterleavedPresent(FPresentShaderBase& shader) +{ + mBuffers->BindOutputFB(); + ClearBorders(); + + + // Bind each eye texture, for composition in the shader + mBuffers->BindEyeTexture(0, 0); + mBuffers->BindEyeTexture(1, 1); + + glActiveTexture(GL_TEXTURE0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + const IntRect& box = screen->mOutputLetterbox; + glViewport(box.left, box.top, box.width, box.height); + + shader.Bind(); + + if (framebuffer->IsHWGammaActive()) + { + shader.Uniforms->InvGamma = 1.0f; + shader.Uniforms->Contrast = 1.0f; + shader.Uniforms->Brightness = 0.0f; + shader.Uniforms->Saturation = 1.0f; + } + else + { + shader.Uniforms->InvGamma = 1.0f / clamp(vid_gamma, 0.1f, 4.f); + shader.Uniforms->Contrast = clamp(vid_contrast, 0.1f, 3.f); + shader.Uniforms->Brightness = clamp(vid_brightness, -0.8f, 0.8f); + shader.Uniforms->Saturation = clamp(vid_saturation, -15.0f, 15.0f); + shader.Uniforms->GrayFormula = static_cast(gl_satformula); + } + shader.Uniforms->HdrMode = 0; + shader.Uniforms->ColorScale = (gl_dither_bpc == -1) ? 255.0f : (float)((1 << gl_dither_bpc) - 1); + shader.Uniforms->Scale = { + screen->mScreenViewport.width / (float)mBuffers->GetWidth(), + screen->mScreenViewport.height / (float)mBuffers->GetHeight() + }; + shader.Uniforms->Offset = { 0.0f, 0.0f }; + shader.Uniforms.SetData(); + static_cast(shader.Uniforms.GetBuffer())->BindBase(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentColumnInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*mPresent3dColumnShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + + // Todo: + //auto clientoffset = screen->GetClientOffset(); + //auto windowHOffset = clientoffset.X % 2; + int windowHOffset = 0; + + mPresent3dColumnShader->Uniforms->WindowPositionParity = windowHOffset; + mPresent3dColumnShader->Uniforms.SetData(); + static_cast(mPresent3dColumnShader->Uniforms.GetBuffer())->BindBase(); + + RenderScreenQuad(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentRowInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*mPresent3dRowShader); + + // Todo: + //auto clientoffset = screen->GetClientOffset(); + //auto windowVOffset = clientoffset.Y % 2; + int windowVOffset = 0; + + mPresent3dRowShader->Uniforms->WindowPositionParity = + (windowVOffset + + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2; + + mPresent3dRowShader->Uniforms.SetData(); + static_cast(mPresent3dRowShader->Uniforms.GetBuffer())->BindBase(); + RenderScreenQuad(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentCheckerInterleaved() +{ + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); + prepareInterleavedPresent(*mPresent3dCheckerShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + + //auto clientoffset = screen->GetClientOffset(); + //auto windowHOffset = clientoffset.X % 2; + //auto windowVOffset = clientoffset.Y % 2; + int windowHOffset = 0; + int windowVOffset = 0; + + mPresent3dCheckerShader->Uniforms->WindowPositionParity = + (windowVOffset + + windowHOffset + + screen->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2; // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset + + mPresent3dCheckerShader->Uniforms.SetData(); + static_cast(mPresent3dCheckerShader->Uniforms.GetBuffer())->BindBase(); + RenderScreenQuad(); +} + +//========================================================================== +// +// Sometimes the stereo render context is not ready immediately at start up +// +//========================================================================== + +bool FGLRenderer::QuadStereoCheckInitialRenderContextState() +{ + // Keep trying until we see at least one good OpenGL context to render to + bool bQuadStereoSupported = false; + bool bDecentContextWasFound = false; + int contextCheckCount = 0; + if ((!bDecentContextWasFound) && (contextCheckCount < 200)) + { + contextCheckCount += 1; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // This question is about the main screen display context + GLboolean supportsStereo, supportsBuffered; + glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered); + if (supportsBuffered) // Finally, a useful OpenGL context + { + // This block will be executed exactly ONCE during a game run + bDecentContextWasFound = true; // now we can stop checking every frame... + // Now check whether this context supports hardware stereo + glGetBooleanv(GL_STEREO, &supportsStereo); + bQuadStereoSupported = supportsStereo && supportsBuffered; + if (! bQuadStereoSupported) + UpdateVRModes(false); + } + } + return bQuadStereoSupported; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGLRenderer::PresentQuadStereo() +{ + if (QuadStereoCheckInitialRenderContextState()) + { + mBuffers->BindOutputFB(); + + glDrawBuffer(GL_BACK_LEFT); + ClearBorders(); + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glDrawBuffer(GL_BACK_RIGHT); + ClearBorders(); + mBuffers->BindEyeTexture(1, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + + glDrawBuffer(GL_BACK); + } + else + { + mBuffers->BindOutputFB(); + ClearBorders(); + mBuffers->BindEyeTexture(0, 0); + DrawPresentTexture(screen->mOutputLetterbox, true); + } +} + + +void FGLRenderer::PresentStereo() +{ + auto vrmode = VRMode::GetVRMode(true); + const int eyeCount = vrmode->mEyeCount; + // Don't invalidate the bound framebuffer (..., false) + if (eyeCount > 1) + mBuffers->BlitToEyeTexture(mBuffers->CurrentEye(), false); + + switch (vr_mode) + { + default: + return; + + case VR_GREENMAGENTA: + PresentAnaglyph(false, true, false); + break; + + case VR_REDCYAN: + PresentAnaglyph(true, false, false); + break; + + case VR_AMBERBLUE: + PresentAnaglyph(true, true, false); + break; + + case VR_SIDEBYSIDEFULL: + case VR_SIDEBYSIDESQUISHED: + PresentSideBySide(); + break; + + case VR_TOPBOTTOM: + PresentTopBottom(); + break; + + case VR_ROWINTERLEAVED: + PresentRowInterleaved(); + break; + + case VR_COLUMNINTERLEAVED: + PresentColumnInterleaved(); + break; + + case VR_CHECKERINTERLEAVED: + PresentCheckerInterleaved(); + break; + + case VR_QUADSTEREO: + PresentQuadStereo(); + break; + } +} + +} \ No newline at end of file diff --git a/source/core/rendering/gl/system/gl_framebuffer.cpp b/source/core/rendering/gl/system/gl_framebuffer.cpp index 6c1d307fd..ee9031a00 100644 --- a/source/core/rendering/gl/system/gl_framebuffer.cpp +++ b/source/core/rendering/gl/system/gl_framebuffer.cpp @@ -41,28 +41,24 @@ #include "templates.h" #include "palette.h" #include "build.h" +#include "hw_viewpointbuffer.h" #include "glbackend/glbackend.h" #include "gl_load/gl_interface.h" #include "gl/system/gl_framebuffer.h" #include "gl/renderer/gl_renderer.h" +#include "gl_renderstate.h" #include "gl_renderbuffers.h" #include "flatvertices.h" #include "hw_lightbuffer.h" -/* -#include "gl/textures/gl_samplers.h" -#include "hwrenderer/utility/hw_clock.h" -#include "hwrenderer/utility/hw_vrmodes.h" -#include "hwrenderer/models/hw_models.h" -#include "hwrenderer/scene/hw_skydome.h" -#include "hwrenderer/data/hw_viewpointbuffer.h" -#include "gl/shaders/gl_shaderprogram.h" -*/ +#include "hw_vrmodes.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "gl_postprocessstate.h" +#include "hw_skydome.h" +#include "gl_shaderprogram.h" +#include "hw_cvars.h" #include "gl_debug.h" #include "r_videoscale.h" -//#include "gl_buffers.h" - -//#include "hwrenderer/data/flatvertices.h" EXTERN_CVAR (Bool, vid_vsync) EXTERN_CVAR(Bool, r_drawvoxels) @@ -97,11 +93,9 @@ OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, bool fullscreen) : Super::SetVSync(vid_vsync); FHardwareTexture::InitGlobalState(); -#ifdef IMPLEMENT_IT // Make sure all global variables tracking OpenGL context state are reset.. gl_RenderState.Reset(); -#endif GLRenderer = nullptr; } @@ -111,10 +105,8 @@ OpenGLFrameBuffer::~OpenGLFrameBuffer() PPResource::ResetAll(); if (mVertexData != nullptr) delete mVertexData; -#ifdef IMPLEMENT_IT if (mSkyData != nullptr) delete mSkyData; if (mViewpoints != nullptr) delete mViewpoints; -#endif if (mLights != nullptr) delete mLights; mShadowMap.Reset(); @@ -177,10 +169,8 @@ void OpenGLFrameBuffer::InitializeState() SetViewportRects(nullptr); mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight()); -#ifdef IMPLEMENT_IT mSkyData = new FSkyVertexBuffer; mViewpoints = new HWViewpointBuffer; -#endif mLights = new FLightBuffer(); GLRenderer = new FGLRenderer(this); GLRenderer->Initialize(GetWidth(), GetHeight()); @@ -212,12 +202,50 @@ void OpenGLFrameBuffer::Update() screen->mVertexData->Reset(); } +void OpenGLFrameBuffer::CopyScreenToBuffer(int width, int height, uint8_t* scr) +{ + IntRect bounds; + bounds.left = 0; + bounds.top = 0; + bounds.width = width; + bounds.height = height; + GLRenderer->CopyToBackbuffer(&bounds, false); + + // strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers + glFinish(); + glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, scr); +} + //=========================================================================== // -// +// Camera texture rendering // //=========================================================================== +void OpenGLFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::function renderFunc) +{ +#if 0 + GLRenderer->StartOffscreen(); + GLRenderer->BindToFrameBuffer(tex); + + IntRect bounds; + bounds.left = bounds.top = 0; + bounds.width = FHardwareTexture::GetTexDimension(tex->GetWidth()); + bounds.height = FHardwareTexture::GetTexDimension(tex->GetHeight()); + + renderFunc(bounds); + GLRenderer->EndOffscreen(); + + tex->SetUpdated(true); + static_cast(screen)->camtexcount++; +#endif +} + +//=========================================================================== +// +// +// +//=========================================================================== const char* OpenGLFrameBuffer::DeviceName() const { @@ -283,38 +311,28 @@ void OpenGLFrameBuffer::SetTextureFilterMode() if (GLRenderer != nullptr && GLRenderer->mSamplerManager != nullptr) GLRenderer->mSamplerManager->SetTextureFilterMode(); } -#ifdef IMPLEMENT_IT - void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) { - auto tex = mat->tex; - if (tex->isSWCanvas()) return; + if (mat->Source()->GetUseType() == ETextureType::SWCanvas) return; - // Textures that are already scaled in the texture lump will not get replaced by hires textures. - int flags = mat->isExpanded() ? CTF_Expand : (!tex->isScaled()) ? CTF_CheckHires : 0; - int numLayers = mat->GetLayers(); - auto base = static_cast(mat->GetLayer(0, translation)); + int flags = mat->GetScaleFlags(); + int numLayers = mat->NumLayers(); + MaterialLayerInfo* layer; + auto base = static_cast(mat->GetLayer(0, translation, &layer)); - if (base->BindOrCreate(tex, 0, CLAMP_NONE, translation, flags)) + if (base->BindOrCreate(layer->layerTexture, 0, CLAMP_NONE, translation, layer->scaleFlags)) { for (int i = 1; i < numLayers; i++) { - FTexture *layer; auto systex = static_cast(mat->GetLayer(i, 0, &layer)); - systex->BindOrCreate(layer, i, CLAMP_NONE, 0, mat->isExpanded() ? CTF_Expand : 0); + systex->BindOrCreate(layer->layerTexture, i, CLAMP_NONE, 0, layer->scaleFlags); } } // unbind everything. FHardwareTexture::UnbindAll(); } -FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli) -{ - return new FHWModelRenderer(nullptr, gl_RenderState, mli); -} -#endif - IVertexBuffer *OpenGLFrameBuffer::CreateVertexBuffer() { return new GLVertexBuffer; @@ -335,13 +353,95 @@ void OpenGLFrameBuffer::BlurScene(float amount) GLRenderer->BlurScene(amount); } -#if 0 +void OpenGLFrameBuffer::SetViewportRects(IntRect *bounds) +{ + Super::SetViewportRects(bounds); + if (!bounds) + { + auto vrmode = VRMode::GetVRMode(true); + vrmode->AdjustViewport(this); + } +} + void OpenGLFrameBuffer::UpdatePalette() { if (GLRenderer) GLRenderer->ClearTonemapPalette(); } -#endif + +FRenderState* OpenGLFrameBuffer::RenderState() +{ + return &gl_RenderState; +} + +void OpenGLFrameBuffer::AmbientOccludeScene(float m5) +{ + gl_RenderState.EnableDrawBuffers(1); + GLRenderer->AmbientOccludeScene(m5); + glViewport(screen->mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); + GLRenderer->mBuffers->BindSceneFB(true); + gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); + gl_RenderState.Apply(); +} + +void OpenGLFrameBuffer::FirstEye() +{ + GLRenderer->mBuffers->CurrentEye() = 0; // always begin at zero, in case eye count changed +} + +void OpenGLFrameBuffer::NextEye(int eyecount) +{ + GLRenderer->mBuffers->NextEye(eyecount); +} + +void OpenGLFrameBuffer::SetSceneRenderTarget(bool useSSAO) +{ + GLRenderer->mBuffers->BindSceneFB(useSSAO); +} + +void OpenGLFrameBuffer::UpdateShadowMap() +{ + if (mShadowMap.PerformUpdate()) + { + FGLDebug::PushGroup("ShadowMap"); + + FGLPostProcessState savedState; + + static_cast(screen->mShadowMap.mLightList)->BindBase(); + static_cast(screen->mShadowMap.mNodesBuffer)->BindBase(); + static_cast(screen->mShadowMap.mLinesBuffer)->BindBase(); + + GLRenderer->mBuffers->BindShadowMapFB(); + + GLRenderer->mShadowMapShader->Bind(); + GLRenderer->mShadowMapShader->Uniforms->ShadowmapQuality = gl_shadowmap_quality; + GLRenderer->mShadowMapShader->Uniforms->NodesCount = screen->mShadowMap.NodesCount(); + GLRenderer->mShadowMapShader->Uniforms.SetData(); + static_cast(GLRenderer->mShadowMapShader->Uniforms.GetBuffer())->BindBase(); + + glViewport(0, 0, gl_shadowmap_quality, 1024); + GLRenderer->RenderScreenQuad(); + + const auto& viewport = screen->mScreenViewport; + glViewport(viewport.left, viewport.top, viewport.width, viewport.height); + + GLRenderer->mBuffers->BindShadowMapTexture(16); + FGLDebug::PopGroup(); + screen->mShadowMap.FinishUpdate(); + } +} + +void OpenGLFrameBuffer::WaitForCommands(bool finish) +{ + glFinish(); +} + +void OpenGLFrameBuffer::SetSaveBuffers(bool yes) +{ + if (!GLRenderer) return; + if (yes) GLRenderer->mBuffers = GLRenderer->mSaveBuffers; + else GLRenderer->mBuffers = GLRenderer->mScreenBuffers; +} //=========================================================================== // @@ -403,6 +503,8 @@ TArray OpenGLFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &colo // Screenshot should not use gamma correction if it was already applied to rendered image gamma = 1; + if (vid_hdr_active && vid_fullscreen) + gamma *= 2.2f; return ScreenshotBuffer; } @@ -428,6 +530,49 @@ void OpenGLFrameBuffer::PostProcessScene(bool swscene, int fixedcm, const std::f GLRenderer->PostProcessScene(fixedcm, afterBloomDrawEndScene2D); } +//========================================================================== +// +// OpenGLFrameBuffer :: WipeStartScreen +// +// Called before the current screen has started rendering. This needs to +// save what was drawn the previous frame so that it can be animated into +// what gets drawn this frame. +// +//========================================================================== +FTexture *OpenGLFrameBuffer::WipeStartScreen() +{ + const auto &viewport = screen->mScreenViewport; + + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + tex->GetSystemTexture()->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, "WipeStartScreen"); + glFinish(); + static_cast(tex->GetSystemTexture())->Bind(0, false); + + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; } +//========================================================================== +// +// OpenGLFrameBuffer :: WipeEndScreen +// +// The screen we want to animate to has just been drawn. +// +//========================================================================== + +FTexture *OpenGLFrameBuffer::WipeEndScreen() +{ + GLRenderer->Flush(); + const auto &viewport = screen->mScreenViewport; + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + tex->GetSystemTexture()->CreateTexture(NULL, viewport.width, viewport.height, 0, false, "WipeEndScreen"); + glFinish(); + static_cast(tex->GetSystemTexture())->Bind(0, false); + GLRenderer->mBuffers->BindCurrentFB(); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); + return tex; +} + +} diff --git a/source/core/rendering/gl/system/gl_framebuffer.h b/source/core/rendering/gl/system/gl_framebuffer.h index 9a5793abf..ee03b4b17 100644 --- a/source/core/rendering/gl/system/gl_framebuffer.h +++ b/source/core/rendering/gl/system/gl_framebuffer.h @@ -28,10 +28,6 @@ public: IHardwareTexture *CreateHardwareTexture(int numchannels) override; void SetTextureFilterMode() override; -#ifdef IMPLEMENT_IT - void PrecacheMaterial(FMaterial *mat, int translation) override; - FModelRenderer *CreateModelRenderer(int mli) override; -#endif void BeginFrame() override; //void SetViewportRects(IntRect *bounds) override; void BlurScene(float amount) override; @@ -49,6 +45,24 @@ public: void SetVSync(bool vsync) override; + void SetViewportRects(IntRect* bounds) override; + void UpdatePalette() override; + void AmbientOccludeScene(float m5) override; + void FirstEye() override; + void NextEye(int eyecount) override; + void SetSceneRenderTarget(bool useSSAO) override; + void UpdateShadowMap() override; + void WaitForCommands(bool finish) override; + void SetSaveBuffers(bool yes) override; + void CopyScreenToBuffer(int width, int height, uint8_t* buffer) override; + bool FlipSavePic() const override { return true; } + void RenderTextureView(FCanvasTexture* tex, std::function renderFunc) override; + void PrecacheMaterial(FMaterial* mat, int translation) override; + FRenderState* RenderState() override; + + FTexture* WipeStartScreen() override; + FTexture* WipeEndScreen() override; + //void Draw2D() override; void PostProcessScene(bool swscene, int fixedcm, const std::function &afterBloomDrawEndScene2D) override; diff --git a/source/glbackend/gl_texture.cpp b/source/glbackend/gl_texture.cpp index 288bac014..a54ae4e05 100644 --- a/source/glbackend/gl_texture.cpp +++ b/source/glbackend/gl_texture.cpp @@ -125,3 +125,8 @@ void InitBuildTiles() } TArray usershaders; + +void UpdateVRModes(bool considerQuadBuffered = true) +{ + // should update the menu. +} diff --git a/source/glbackend/glbackend.cpp b/source/glbackend/glbackend.cpp index 9d8758342..4e8f957d0 100644 --- a/source/glbackend/glbackend.cpp +++ b/source/glbackend/glbackend.cpp @@ -184,13 +184,7 @@ void GLInstance::ClearBufferState() } -static GLint primtypes[] = -{ - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN, - GL_LINES -}; +static GLint primtypes[] ={ GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP }; void GLInstance::Draw(EDrawType type, size_t start, size_t count) @@ -214,7 +208,7 @@ void GLInstance::DrawElement(EDrawType type, size_t start, size_t count, Polymos if (renderState.Color[3] != 1.f) renderState.Flags &= ~RF_Brightmapping; // The way the colormaps are set up means that brightmaps cannot be used on translucent content at all. renderState.Apply(polymostShader, lastState); } - if (type != DT_LINES) + if (type != DT_Lines) { glDrawElements(primtypes[type], count, GL_UNSIGNED_INT, (void*)(intptr_t)(start * sizeof(uint32_t))); } diff --git a/source/glbackend/glbackend.h b/source/glbackend/glbackend.h index cfc613280..a21f27458 100644 --- a/source/glbackend/glbackend.h +++ b/source/glbackend/glbackend.h @@ -5,11 +5,12 @@ #include #include "gl_samplers.h" #include "gl_hwtexture.h" -#include "gl_renderstate.h" #include "matrix.h" #include "palentry.h" #include "renderstyle.h" #include "hw_material.h" +#include "hw_renderstate.h" +#include "pm_renderstate.h" class FShader; class PolymostShader; @@ -66,22 +67,13 @@ struct glinfo_t { float maxanisotropy; }; -enum EDrawType +enum ECullSide { - DT_TRIANGLES, - DT_TRIANGLE_STRIP, - DT_TRIANGLE_FAN, - DT_LINES -}; - -enum ECull -{ - Cull_None, Cull_Front, Cull_Back }; -enum EDepthFunc +enum EDepthFunct { Depth_Always, Depth_Less, diff --git a/source/glbackend/hw_draw2d.cpp b/source/glbackend/hw_draw2d.cpp index a44f89dda..d54feaaa0 100644 --- a/source/glbackend/hw_draw2d.cpp +++ b/source/glbackend/hw_draw2d.cpp @@ -43,6 +43,7 @@ #include "flatvertices.h" #include "build.h" #include "v_video.h" +#include "hw_renderstate.h" extern int16_t numshades; extern TArray matrixArray; @@ -182,11 +183,11 @@ void GLInstance::Draw2D(F2DDrawer *drawer) switch (cmd.mType) { case F2DDrawer::DrawTypeTriangles: - DrawElement(DT_TRIANGLES, cmd.mIndexIndex, cmd.mIndexCount, renderState); + DrawElement(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount, renderState); break; case F2DDrawer::DrawTypeLines: - DrawElement(DT_LINES, cmd.mVertIndex, cmd.mVertCount, renderState); + DrawElement(DT_Lines, cmd.mVertIndex, cmd.mVertCount, renderState); break; case F2DDrawer::DrawTypePoints: @@ -241,18 +242,18 @@ void DrawFullscreenBlends() // Todo: reroute to the 2D drawer GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]); GLInterface.SetColorub(palfadergb.r, palfadergb.g, palfadergb.b, palfadergb.a); - GLInterface.Draw(DT_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); + GLInterface.Draw(DT_TriangleStrip, FFlatVertexBuffer::PRESENT_INDEX, 4); } if (tint_blood_r | tint_blood_g | tint_blood_b) { GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Add]); GLInterface.SetColorub(max(tint_blood_r, 0), max(tint_blood_g, 0), max(tint_blood_b, 0), 255); - GLInterface.Draw(DT_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); + GLInterface.Draw(DT_TriangleStrip, FFlatVertexBuffer::PRESENT_INDEX, 4); GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Subtract]); GLInterface.SetColorub(max(-tint_blood_r, 0), max(-tint_blood_g, 0), max(-tint_blood_b, 0), 255); - GLInterface.Draw(DT_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); + GLInterface.Draw(DT_TriangleStrip, FFlatVertexBuffer::PRESENT_INDEX, 4); GLInterface.SetColorub(255, 255, 255, 255); GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]); diff --git a/source/glbackend/gl_renderstate.h b/source/glbackend/pm_renderstate.h similarity index 84% rename from source/glbackend/gl_renderstate.h rename to source/glbackend/pm_renderstate.h index d1c3dd61d..7cbf798ca 100644 --- a/source/glbackend/gl_renderstate.h +++ b/source/glbackend/pm_renderstate.h @@ -57,38 +57,6 @@ enum PRSFlags }; -struct FDepthBiasState -{ - float mFactor; - float mUnits; - bool mChanged; - - void Reset() - { - mFactor = 0; - mUnits = 0; - mChanged = false; - } -}; - -struct FMaterialState -{ - FMaterial* mMaterial; - int mClampMode; - int mTranslation; - int mOverrideShader; - bool mChanged; - - void Reset() - { - mMaterial = nullptr; - mTranslation = 0; - mClampMode = 0/*CLAMP_NONE*/; - mOverrideShader = -1; - mChanged = false; - } -}; - struct PolymostRenderState { int vindex, vcount, primtype; diff --git a/wadsrc/static/engine/grpinfo.txt b/wadsrc/static/engine/grpinfo.txt index 7b4092a87..1ed10abd3 100644 --- a/wadsrc/static/engine/grpinfo.txt +++ b/wadsrc/static/engine/grpinfo.txt @@ -29,6 +29,9 @@ CRC RRRA_CRC 0x958018C6 RRDEER_CRC 0xA6BE8B16 + BLOOD10_CRC 0xB291418f + BLOOD11_CRC 0xC3A99936 + BLOOD_CRC 0xA8FDDA84 BLOOD_CRC 0xA8FDDA84 SWREG12_CRC 0x7545319F SWWD_CRC 0xA9AAA7B7