- another backend update, pulling in the sky renderer.

This commit is contained in:
Christoph Oelckers 2020-05-31 10:24:04 +02:00
parent efa1cd3048
commit 1d15fe63a6
19 changed files with 1197 additions and 126 deletions

View file

@ -883,6 +883,7 @@ set (PCH_SOURCES
common/rendering/hwrenderer/data/hw_vrmodes.cpp common/rendering/hwrenderer/data/hw_vrmodes.cpp
common/rendering/hwrenderer/data/hw_lightbuffer.cpp common/rendering/hwrenderer/data/hw_lightbuffer.cpp
common/rendering/hwrenderer/data/hw_aabbtree.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_shadowmap.cpp
common/rendering/hwrenderer/data/hw_shaderpatcher.cpp common/rendering/hwrenderer/data/hw_shaderpatcher.cpp
common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp
@ -938,6 +939,7 @@ set (PCH_SOURCES
core/input/m_joy.cpp core/input/m_joy.cpp
core/rendering/gl/renderer/gl_renderer.cpp core/rendering/gl/renderer/gl_renderer.cpp
core/rendering/gl/renderer/gl_stereo3d.cpp
core/rendering/gl/system/gl_framebuffer.cpp core/rendering/gl/system/gl_framebuffer.cpp
) )

View file

@ -17,6 +17,7 @@
#include "v_video.h" #include "v_video.h"
#include "flatvertices.h" #include "flatvertices.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "hw_renderstate.h"
#include "../../glbackend/glbackend.h" #include "../../glbackend/glbackend.h"
static int32_t curextra=MAXTILES; 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); 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 #ifndef USE_GLEXT
UNREFERENCED_PARAMETER(texunits); UNREFERENCED_PARAMETER(texunits);

View file

@ -20,7 +20,7 @@ Ken Silverman's official web site: http://www.advsys.net/ken
#include "flatvertices.h" #include "flatvertices.h"
#include "palettecontainer.h" #include "palettecontainer.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "gamecontrol.h" #include "hw_renderstate.h"
CVAR(Bool, hw_detailmapping, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, hw_detailmapping, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, hw_glowmapping, 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)); 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.SetTinting(-1, 0xffffff, 0xffffff);
GLInterface.UseDetailMapping(false); 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; vec3d_t const bxtex = xtex, bytex = ytex, botex = otex;
xtex = xtex2, ytex = ytex2, otex = otex2; xtex = xtex2, ytex = ytex2, otex = otex2;
GLInterface.SetColorMask(false); GLInterface.SetColorMask(false);
GLInterface.Draw(DT_TRIANGLE_FAN, data.second, npoints); GLInterface.Draw(DT_TriangleFan, data.second, npoints);
GLInterface.SetColorMask(true); GLInterface.SetColorMask(true);
xtex = bxtex, ytex = bytex, otex = botex; xtex = bxtex, ytex = bytex, otex = botex;
} }

View file

@ -11,6 +11,7 @@
#include "mdsprite.h" #include "mdsprite.h"
#include "v_video.h" #include "v_video.h"
#include "flatvertices.h" #include "flatvertices.h"
#include "hw_renderstate.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "palette.h" #include "palette.h"
@ -1174,7 +1175,7 @@ int32_t polymost_voxdraw(voxmodel_t *m, tspriteptr_t const tspr)
f = 1 /*clut[fi++]*/; f = 1 /*clut[fi++]*/;
if (qdone > 0) if (qdone > 0)
{ {
GLInterface.Draw(DT_TRIANGLES, qstart, qdone * 6); GLInterface.Draw(DT_Triangles, qstart, qdone * 6);
qstart += qdone * 6; qstart += qdone * 6;
qdone = 0; qdone = 0;
} }
@ -1205,7 +1206,7 @@ int32_t polymost_voxdraw(voxmodel_t *m, tspriteptr_t const tspr)
qdone++; qdone++;
} }
GLInterface.Draw(DT_TRIANGLES, qstart, qdone * 6); GLInterface.Draw(DT_Triangles, qstart, qdone * 6);
GLInterface.SetClamp(prevClamp); GLInterface.SetClamp(prevClamp);
//------------ //------------
GLInterface.SetCull(Cull_None); GLInterface.SetCull(Cull_None);

View file

@ -1,4 +1,4 @@
#pragma once
#include "renderstyle.h" #include "renderstyle.h"
#include "matrix.h" #include "matrix.h"
#include "model.h" #include "model.h"

View file

@ -87,7 +87,7 @@ struct FStateVec4
struct FMaterialState struct FMaterialState
{ {
FMaterial *mMaterial; FMaterial *mMaterial = nullptr;
int mClampMode; int mClampMode;
int mTranslation; int mTranslation;
int mOverrideShader; int mOverrideShader;

View file

@ -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<PalEntry, PalEntry> Colors;
};
static TArray<SkyColor> SkyColors;
std::pair<PalEntry, PalEntry>& 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);
}

View file

@ -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<FSkyVertex> mVertices;
TArray<unsigned int> 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<IVertexBuffer *, IIndexBuffer *> 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);
};

View file

@ -39,15 +39,10 @@
#include "filesystem.h" #include "filesystem.h"
#include "i_time.h" #include "i_time.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "m_png.h"
#include "version.h" #include "version.h"
#include "texturemanager.h" #include "gl_interface.h"
#include "model.h"
//#include "hwrenderer/utility/hw_clock.h"
#include "gl_load/gl_interface.h"
#include "gl/system/gl_framebuffer.h" #include "gl/system/gl_framebuffer.h"
#include "gamecvars.h" #include "hw_cvars.h"
#include "gl_debug.h" #include "gl_debug.h"
#include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderer.h"
#include "gl_renderstate.h" #include "gl_renderstate.h"
@ -56,18 +51,14 @@
#include "flatvertices.h" #include "flatvertices.h"
#include "gl_samplers.h" #include "gl_samplers.h"
#include "hw_lightbuffer.h" #include "hw_lightbuffer.h"
//#include "hwrenderer/data/hw_viewpointbuffer.h"
#include "r_videoscale.h" #include "r_videoscale.h"
//#include "r_data/models/models.h" #include "model.h"
#include "gl_postprocessstate.h" #include "gl_postprocessstate.h"
#include "gl_buffers.h" #include "gl_buffers.h"
#include "gl_hwtexture.h" #include "gl_hwtexture.h"
#include "build.h" #include "texturemanager.h"
EXTERN_CVAR(Int, screenblocks) EXTERN_CVAR(Int, screenblocks)
EXTERN_CVAR(Bool, cl_capfps)
extern bool NoInterpolateView;
namespace OpenGLRenderer namespace OpenGLRenderer
{ {
@ -195,9 +186,4 @@ void FGLRenderer::BeginFrame()
mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT); mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT);
} }
void FGLRenderer::PresentStereo()
{
}
} }

View file

@ -78,7 +78,6 @@ public:
void CopyToBackbuffer(const IntRect *bounds, bool applyGamma); void CopyToBackbuffer(const IntRect *bounds, bool applyGamma);
void DrawPresentTexture(const IntRect &box, bool applyGamma); void DrawPresentTexture(const IntRect &box, bool applyGamma);
void Flush(); void Flush();
//void Draw2D(F2DDrawer *data);
void BeginFrame(); void BeginFrame();
bool StartOffscreen(); bool StartOffscreen();

View file

@ -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<float>(vid_gamma, 0.1f, 4.f);
shader.Uniforms->Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
shader.Uniforms->Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
shader.Uniforms->Saturation = clamp<float>(vid_saturation, -15.0f, 15.0f);
shader.Uniforms->GrayFormula = static_cast<int>(gl_satformula);
}
shader.Uniforms->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<GLDataBuffer*>(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<GLDataBuffer*>(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<GLDataBuffer*>(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<GLDataBuffer*>(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;
}
}
}

View file

@ -41,28 +41,24 @@
#include "templates.h" #include "templates.h"
#include "palette.h" #include "palette.h"
#include "build.h" #include "build.h"
#include "hw_viewpointbuffer.h"
#include "glbackend/glbackend.h" #include "glbackend/glbackend.h"
#include "gl_load/gl_interface.h" #include "gl_load/gl_interface.h"
#include "gl/system/gl_framebuffer.h" #include "gl/system/gl_framebuffer.h"
#include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderer.h"
#include "gl_renderstate.h"
#include "gl_renderbuffers.h" #include "gl_renderbuffers.h"
#include "flatvertices.h" #include "flatvertices.h"
#include "hw_lightbuffer.h" #include "hw_lightbuffer.h"
/* #include "hw_vrmodes.h"
#include "gl/textures/gl_samplers.h" #include "hwrenderer/postprocessing/hw_postprocess.h"
#include "hwrenderer/utility/hw_clock.h" #include "gl_postprocessstate.h"
#include "hwrenderer/utility/hw_vrmodes.h" #include "hw_skydome.h"
#include "hwrenderer/models/hw_models.h" #include "gl_shaderprogram.h"
#include "hwrenderer/scene/hw_skydome.h" #include "hw_cvars.h"
#include "hwrenderer/data/hw_viewpointbuffer.h"
#include "gl/shaders/gl_shaderprogram.h"
*/
#include "gl_debug.h" #include "gl_debug.h"
#include "r_videoscale.h" #include "r_videoscale.h"
//#include "gl_buffers.h"
//#include "hwrenderer/data/flatvertices.h"
EXTERN_CVAR (Bool, vid_vsync) EXTERN_CVAR (Bool, vid_vsync)
EXTERN_CVAR(Bool, r_drawvoxels) EXTERN_CVAR(Bool, r_drawvoxels)
@ -97,11 +93,9 @@ OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, bool fullscreen) :
Super::SetVSync(vid_vsync); Super::SetVSync(vid_vsync);
FHardwareTexture::InitGlobalState(); FHardwareTexture::InitGlobalState();
#ifdef IMPLEMENT_IT
// Make sure all global variables tracking OpenGL context state are reset.. // Make sure all global variables tracking OpenGL context state are reset..
gl_RenderState.Reset(); gl_RenderState.Reset();
#endif
GLRenderer = nullptr; GLRenderer = nullptr;
} }
@ -111,10 +105,8 @@ OpenGLFrameBuffer::~OpenGLFrameBuffer()
PPResource::ResetAll(); PPResource::ResetAll();
if (mVertexData != nullptr) delete mVertexData; if (mVertexData != nullptr) delete mVertexData;
#ifdef IMPLEMENT_IT
if (mSkyData != nullptr) delete mSkyData; if (mSkyData != nullptr) delete mSkyData;
if (mViewpoints != nullptr) delete mViewpoints; if (mViewpoints != nullptr) delete mViewpoints;
#endif
if (mLights != nullptr) delete mLights; if (mLights != nullptr) delete mLights;
mShadowMap.Reset(); mShadowMap.Reset();
@ -177,10 +169,8 @@ void OpenGLFrameBuffer::InitializeState()
SetViewportRects(nullptr); SetViewportRects(nullptr);
mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight()); mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight());
#ifdef IMPLEMENT_IT
mSkyData = new FSkyVertexBuffer; mSkyData = new FSkyVertexBuffer;
mViewpoints = new HWViewpointBuffer; mViewpoints = new HWViewpointBuffer;
#endif
mLights = new FLightBuffer(); mLights = new FLightBuffer();
GLRenderer = new FGLRenderer(this); GLRenderer = new FGLRenderer(this);
GLRenderer->Initialize(GetWidth(), GetHeight()); GLRenderer->Initialize(GetWidth(), GetHeight());
@ -212,12 +202,50 @@ void OpenGLFrameBuffer::Update()
screen->mVertexData->Reset(); 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<void(IntRect &)> 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<OpenGLFrameBuffer*>(screen)->camtexcount++;
#endif
}
//===========================================================================
//
//
//
//===========================================================================
const char* OpenGLFrameBuffer::DeviceName() const const char* OpenGLFrameBuffer::DeviceName() const
{ {
@ -283,38 +311,28 @@ void OpenGLFrameBuffer::SetTextureFilterMode()
if (GLRenderer != nullptr && GLRenderer->mSamplerManager != nullptr) GLRenderer->mSamplerManager->SetTextureFilterMode(); if (GLRenderer != nullptr && GLRenderer->mSamplerManager != nullptr) GLRenderer->mSamplerManager->SetTextureFilterMode();
} }
#ifdef IMPLEMENT_IT
void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
{ {
auto tex = mat->tex; if (mat->Source()->GetUseType() == ETextureType::SWCanvas) return;
if (tex->isSWCanvas()) return;
// Textures that are already scaled in the texture lump will not get replaced by hires textures. int flags = mat->GetScaleFlags();
int flags = mat->isExpanded() ? CTF_Expand : (!tex->isScaled()) ? CTF_CheckHires : 0; int numLayers = mat->NumLayers();
int numLayers = mat->GetLayers(); MaterialLayerInfo* layer;
auto base = static_cast<FHardwareTexture*>(mat->GetLayer(0, translation)); auto base = static_cast<FHardwareTexture*>(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++) for (int i = 1; i < numLayers; i++)
{ {
FTexture *layer;
auto systex = static_cast<FHardwareTexture*>(mat->GetLayer(i, 0, &layer)); auto systex = static_cast<FHardwareTexture*>(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. // unbind everything.
FHardwareTexture::UnbindAll(); FHardwareTexture::UnbindAll();
} }
FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli)
{
return new FHWModelRenderer(nullptr, gl_RenderState, mli);
}
#endif
IVertexBuffer *OpenGLFrameBuffer::CreateVertexBuffer() IVertexBuffer *OpenGLFrameBuffer::CreateVertexBuffer()
{ {
return new GLVertexBuffer; return new GLVertexBuffer;
@ -335,13 +353,95 @@ void OpenGLFrameBuffer::BlurScene(float amount)
GLRenderer->BlurScene(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() void OpenGLFrameBuffer::UpdatePalette()
{ {
if (GLRenderer) if (GLRenderer)
GLRenderer->ClearTonemapPalette(); 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<GLDataBuffer*>(screen->mShadowMap.mLightList)->BindBase();
static_cast<GLDataBuffer*>(screen->mShadowMap.mNodesBuffer)->BindBase();
static_cast<GLDataBuffer*>(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<GLDataBuffer*>(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<uint8_t> OpenGLFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &colo
// Screenshot should not use gamma correction if it was already applied to rendered image // Screenshot should not use gamma correction if it was already applied to rendered image
gamma = 1; gamma = 1;
if (vid_hdr_active && vid_fullscreen)
gamma *= 2.2f;
return ScreenshotBuffer; return ScreenshotBuffer;
} }
@ -428,6 +530,49 @@ void OpenGLFrameBuffer::PostProcessScene(bool swscene, int fixedcm, const std::f
GLRenderer->PostProcessScene(fixedcm, afterBloomDrawEndScene2D); 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<FHardwareTexture*>(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<FHardwareTexture*>(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;
}
}

View file

@ -28,10 +28,6 @@ public:
IHardwareTexture *CreateHardwareTexture(int numchannels) override; IHardwareTexture *CreateHardwareTexture(int numchannels) override;
void SetTextureFilterMode() override; void SetTextureFilterMode() override;
#ifdef IMPLEMENT_IT
void PrecacheMaterial(FMaterial *mat, int translation) override;
FModelRenderer *CreateModelRenderer(int mli) override;
#endif
void BeginFrame() override; void BeginFrame() override;
//void SetViewportRects(IntRect *bounds) override; //void SetViewportRects(IntRect *bounds) override;
void BlurScene(float amount) override; void BlurScene(float amount) override;
@ -49,6 +45,24 @@ public:
void SetVSync(bool vsync) override; 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<void(IntRect&)> renderFunc) override;
void PrecacheMaterial(FMaterial* mat, int translation) override;
FRenderState* RenderState() override;
FTexture* WipeStartScreen() override;
FTexture* WipeEndScreen() override;
//void Draw2D() override; //void Draw2D() override;
void PostProcessScene(bool swscene, int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D) override; void PostProcessScene(bool swscene, int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D) override;

View file

@ -125,3 +125,8 @@ void InitBuildTiles()
} }
TArray<UserShaderDesc> usershaders; TArray<UserShaderDesc> usershaders;
void UpdateVRModes(bool considerQuadBuffered = true)
{
// should update the menu.
}

View file

@ -184,13 +184,7 @@ void GLInstance::ClearBufferState()
} }
static GLint primtypes[] = static GLint primtypes[] ={ GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP };
{
GL_TRIANGLES,
GL_TRIANGLE_STRIP,
GL_TRIANGLE_FAN,
GL_LINES
};
void GLInstance::Draw(EDrawType type, size_t start, size_t count) 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. 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); 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))); glDrawElements(primtypes[type], count, GL_UNSIGNED_INT, (void*)(intptr_t)(start * sizeof(uint32_t)));
} }

View file

@ -5,11 +5,12 @@
#include <map> #include <map>
#include "gl_samplers.h" #include "gl_samplers.h"
#include "gl_hwtexture.h" #include "gl_hwtexture.h"
#include "gl_renderstate.h"
#include "matrix.h" #include "matrix.h"
#include "palentry.h" #include "palentry.h"
#include "renderstyle.h" #include "renderstyle.h"
#include "hw_material.h" #include "hw_material.h"
#include "hw_renderstate.h"
#include "pm_renderstate.h"
class FShader; class FShader;
class PolymostShader; class PolymostShader;
@ -66,22 +67,13 @@ struct glinfo_t {
float maxanisotropy; float maxanisotropy;
}; };
enum EDrawType enum ECullSide
{ {
DT_TRIANGLES,
DT_TRIANGLE_STRIP,
DT_TRIANGLE_FAN,
DT_LINES
};
enum ECull
{
Cull_None,
Cull_Front, Cull_Front,
Cull_Back Cull_Back
}; };
enum EDepthFunc enum EDepthFunct
{ {
Depth_Always, Depth_Always,
Depth_Less, Depth_Less,

View file

@ -43,6 +43,7 @@
#include "flatvertices.h" #include "flatvertices.h"
#include "build.h" #include "build.h"
#include "v_video.h" #include "v_video.h"
#include "hw_renderstate.h"
extern int16_t numshades; extern int16_t numshades;
extern TArray<VSMatrix> matrixArray; extern TArray<VSMatrix> matrixArray;
@ -182,11 +183,11 @@ void GLInstance::Draw2D(F2DDrawer *drawer)
switch (cmd.mType) switch (cmd.mType)
{ {
case F2DDrawer::DrawTypeTriangles: case F2DDrawer::DrawTypeTriangles:
DrawElement(DT_TRIANGLES, cmd.mIndexIndex, cmd.mIndexCount, renderState); DrawElement(DT_Triangles, cmd.mIndexIndex, cmd.mIndexCount, renderState);
break; break;
case F2DDrawer::DrawTypeLines: case F2DDrawer::DrawTypeLines:
DrawElement(DT_LINES, cmd.mVertIndex, cmd.mVertCount, renderState); DrawElement(DT_Lines, cmd.mVertIndex, cmd.mVertCount, renderState);
break; break;
case F2DDrawer::DrawTypePoints: case F2DDrawer::DrawTypePoints:
@ -241,18 +242,18 @@ void DrawFullscreenBlends()
// Todo: reroute to the 2D drawer // Todo: reroute to the 2D drawer
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]); GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]);
GLInterface.SetColorub(palfadergb.r, palfadergb.g, palfadergb.b, palfadergb.a); 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) if (tint_blood_r | tint_blood_g | tint_blood_b)
{ {
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Add]); GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Add]);
GLInterface.SetColorub(max(tint_blood_r, 0), max(tint_blood_g, 0), max(tint_blood_b, 0), 255); 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.SetRenderStyle(LegacyRenderStyles[STYLE_Subtract]);
GLInterface.SetColorub(max(-tint_blood_r, 0), max(-tint_blood_g, 0), max(-tint_blood_b, 0), 255); 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.SetColorub(255, 255, 255, 255);
GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]); GLInterface.SetRenderStyle(LegacyRenderStyles[STYLE_Translucent]);

View file

@ -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 struct PolymostRenderState
{ {
int vindex, vcount, primtype; int vindex, vcount, primtype;

View file

@ -29,6 +29,9 @@ CRC
RRRA_CRC 0x958018C6 RRRA_CRC 0x958018C6
RRDEER_CRC 0xA6BE8B16 RRDEER_CRC 0xA6BE8B16
BLOOD10_CRC 0xB291418f
BLOOD11_CRC 0xC3A99936
BLOOD_CRC 0xA8FDDA84
BLOOD_CRC 0xA8FDDA84 BLOOD_CRC 0xA8FDDA84
SWREG12_CRC 0x7545319F SWREG12_CRC 0x7545319F
SWWD_CRC 0xA9AAA7B7 SWWD_CRC 0xA9AAA7B7