- draw decals in hardware independent code.

This commit is contained in:
Christoph Oelckers 2018-10-21 10:51:26 +02:00
parent 1768508c80
commit a97d71a3c3
9 changed files with 183 additions and 179 deletions

View file

@ -52,23 +52,24 @@ static void matrixToGL(const VSMatrix &mat, int loc)
//========================================================================== //==========================================================================
// //
// // This only gets called once upon setup.
// With OpenGL the state is persistent and cannot be cleared, once set up.
// //
//========================================================================== //==========================================================================
void FGLRenderState::Reset() void FGLRenderState::Reset()
{ {
FRenderState::Reset(); FRenderState::Reset();
mSplitEnabled = false;
mSrcBlend = GL_SRC_ALPHA; mSrcBlend = GL_SRC_ALPHA;
mDstBlend = GL_ONE_MINUS_SRC_ALPHA; mDstBlend = GL_ONE_MINUS_SRC_ALPHA;
mBlendEquation = GL_FUNC_ADD; mBlendEquation = GL_FUNC_ADD;
mVertexBuffer = mCurrentVertexBuffer = NULL; mVertexBuffer = mCurrentVertexBuffer = nullptr;
mGlossiness = 0.0f; mGlossiness = 0.0f;
mSpecularLevel = 0.0f; mSpecularLevel = 0.0f;
mShaderTimer = 0.0f; mShaderTimer = 0.0f;
ClearClipSplit(); ClearClipSplit();
stRenderStyle = DefaultRenderStyle();
stSrcBlend = stDstBlend = -1; stSrcBlend = stDstBlend = -1;
stBlendEquation = -1; stBlendEquation = -1;
stAlphaTest = 0; stAlphaTest = 0;
@ -216,6 +217,21 @@ void FGLRenderState::Apply()
stRenderStyle = mRenderStyle; stRenderStyle = mRenderStyle;
} }
if (mSplitEnabled != stSplitEnabled)
{
if (mSplitEnabled)
{
glEnable(GL_CLIP_DISTANCE3);
glEnable(GL_CLIP_DISTANCE4);
}
else
{
glDisable(GL_CLIP_DISTANCE3);
glDisable(GL_CLIP_DISTANCE4);
}
stSplitEnabled = mSplitEnabled;
}
if (mMaterial.mChanged) if (mMaterial.mChanged)
{ {
ApplyMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader); ApplyMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader);

View file

@ -49,7 +49,6 @@ enum EPassType
class FGLRenderState : public FRenderState class FGLRenderState : public FRenderState
{ {
uint8_t mSplitEnabled : 1;
uint8_t mLastDepthClamp : 1; uint8_t mLastDepthClamp : 1;
int mSrcBlend, mDstBlend; int mSrcBlend, mDstBlend;
@ -68,6 +67,7 @@ class FGLRenderState : public FRenderState
FRenderStyle stRenderStyle; FRenderStyle stRenderStyle;
int stSrcBlend, stDstBlend; int stSrcBlend, stDstBlend;
bool stAlphaTest; bool stAlphaTest;
bool stSplitEnabled;
int stBlendEquation; int stBlendEquation;
FShader *activeShader; FShader *activeShader;
@ -115,25 +115,6 @@ public:
mCurrentVertexBuffer = NULL; mCurrentVertexBuffer = NULL;
} }
void EnableSplit(bool on)
{
if (!(gl.flags & RFL_NO_CLIP_PLANES))
{
mSplitEnabled = on;
if (on)
{
glEnable(GL_CLIP_DISTANCE3);
glEnable(GL_CLIP_DISTANCE4);
}
else
{
glDisable(GL_CLIP_DISTANCE3);
glDisable(GL_CLIP_DISTANCE4);
}
}
}
void SetSpecular(float glossiness, float specularLevel) void SetSpecular(float glossiness, float specularLevel)
{ {
mGlossiness = glossiness; mGlossiness = glossiness;

View file

@ -57,16 +57,7 @@ struct FDrawInfo : public HWDrawInfo
void Draw(EDrawType dt, FRenderState &state, int index, int count, bool apply = true); void Draw(EDrawType dt, FRenderState &state, int index, int count, bool apply = true);
void DrawIndexed(EDrawType dt, FRenderState &state, int index, int count, bool apply = true); void DrawIndexed(EDrawType dt, FRenderState &state, int index, int count, bool apply = true);
void DrawDecal(GLDecal *gldecal, FRenderState &state);
void DrawDecals(FRenderState &state);
void DrawDecalsForMirror(GLWall *wall, FRenderState &state);
void StartScene(); void StartScene();
void SetupFloodStencil(int vindex);
void ClearFloodStencil(int vindex);
void DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling);
void FloodUpperGap(seg_t * seg);
void FloodLowerGap(seg_t * seg);
// Wall drawer // Wall drawer
void RenderWall(GLWall *wall, int textured); void RenderWall(GLWall *wall, int textured);

View file

@ -203,14 +203,9 @@ void FDrawInfo::RenderScene(int recursion)
// Part 4: Draw decals (not a real pass) // Part 4: Draw decals (not a real pass)
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -128.0f);
glDepthMask(false); glDepthMask(false);
DrawDecals(gl_RenderState); DrawDecals(gl_RenderState, decals[0]);
gl_RenderState.SetTextureMode(TM_NORMAL);
glPolygonOffset(0.0f, 0.0f);
glDisable(GL_POLYGON_OFFSET_FILL);
glDepthMask(true); glDepthMask(true);
RenderAll.Unclock(); RenderAll.Unclock();
} }

View file

@ -122,14 +122,9 @@ void FDrawInfo::RenderMirrorSurface(GLWall *wall)
// because the depth buffer won't get set by translucent items. // because the depth buffer won't get set by translucent items.
if (wall->seg->sidedef->AttachedDecals) if (wall->seg->sidedef->AttachedDecals)
{ {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -128.0f);
glDepthMask(false); glDepthMask(false);
DrawDecalsForMirror(wall, gl_RenderState); wall->DrawDecalsForMirror(this, gl_RenderState, decals[1]);
glDepthMask(true); glDepthMask(true);
glPolygonOffset(0.0f, 0.0f);
glDisable(GL_POLYGON_OFFSET_FILL);
gl_RenderState.SetTextureMode(TM_NORMAL);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} }
} }
@ -440,138 +435,3 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
wall->vertcount = 0; wall->vertcount = 0;
} }
//==========================================================================
//
//
//
//==========================================================================
void FDrawInfo::DrawDecal(GLDecal *gldecal, FRenderState &state)
{
auto decal = gldecal->decal;
auto tex = gldecal->gltexture;
// calculate dynamic light effect.
if (level.HasDynamicLights && !isFullbrightScene() && gl_light_sprites)
{
// Note: This should be replaced with proper shader based lighting.
double x, y;
float out[3];
decal->GetXY(decal->Side, x, y);
GetDynSpriteLight(nullptr, x, y, gldecal->zcenter, decal->Side->lighthead, decal->Side->sector->PortalGroup, out);
gl_RenderState.SetDynLight(out[0], out[1], out[2]);
}
// alpha color only has an effect when using an alpha texture.
if (decal->RenderStyle.Flags & (STYLEF_RedIsAlpha | STYLEF_ColorIsFixed))
{
gl_RenderState.SetObjectColor(decal->AlphaColor | 0xff000000);
}
gl_RenderState.SetTextureMode(decal->RenderStyle);
gl_RenderState.SetRenderStyle(decal->RenderStyle);
gl_RenderState.SetMaterial(tex, CLAMP_XY, decal->Translation, -1);
// If srcalpha is one it looks better with a higher alpha threshold
if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) gl_RenderState.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
else gl_RenderState.AlphaFunc(Alpha_Greater, 0.f);
SetColor(gldecal->lightlevel, gldecal->rellight, gldecal->Colormap, gldecal->alpha);
// for additively drawn decals we must temporarily set the fog color to black.
PalEntry fc = gl_RenderState.GetFogColor();
if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One)
{
gl_RenderState.SetFog(0, -1);
}
gl_RenderState.SetNormal(gldecal->Normal);
if (gldecal->lightlist == nullptr)
{
Draw(DT_TriangleFan, gl_RenderState, gldecal->vertindex, 4);
}
else
{
auto &lightlist = *gldecal->lightlist;
for (unsigned k = 0; k < lightlist.Size(); k++)
{
secplane_t &lowplane = k == lightlist.Size() - 1 ? gldecal->bottomplane : lightlist[k + 1].plane;
DecalVertex *dv = gldecal->dv;
float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y);
float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y);
if (low1 < dv[1].z || low2 < dv[2].z)
{
int thisll = lightlist[k].caster != nullptr ? hw_ClampLight(*lightlist[k].p_lightlevel) : gldecal->lightlevel;
FColormap thiscm;
thiscm.FadeColor = gldecal->Colormap.FadeColor;
thiscm.CopyFrom3DLight(&lightlist[k]);
SetColor(thisll, gldecal->rellight, thiscm, gldecal->alpha);
if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) thiscm.Decolorize();
SetFog(thisll, gldecal->rellight, &thiscm, false);
gl_RenderState.SetSplitPlanes(lightlist[k].plane, lowplane);
Draw(DT_TriangleFan, gl_RenderState, gldecal->vertindex, 4);
}
if (low1 <= dv[0].z && low2 <= dv[3].z) break;
}
}
rendered_decals++;
gl_RenderState.SetTextureMode(TM_NORMAL);
gl_RenderState.SetObjectColor(0xffffffff);
gl_RenderState.SetFog(fc, -1);
gl_RenderState.SetDynLight(0, 0, 0);
}
//==========================================================================
//
//
//
//==========================================================================
void FDrawInfo::DrawDecals(FRenderState &state)
{
side_t *wall = nullptr;
bool splitting = false;
for (auto gldecal : decals[0])
{
if (gldecal->decal->Side != wall)
{
wall = gldecal->decal->Side;
if (gldecal->lightlist != nullptr)
{
gl_RenderState.EnableSplit(true);
splitting = true;
}
else
{
gl_RenderState.EnableSplit(false);
splitting = false;
SetFog(gldecal->lightlevel, gldecal->rellight, &gldecal->Colormap, false);
}
}
DrawDecal(gldecal, state);
}
if (splitting) gl_RenderState.EnableSplit(false);
}
//==========================================================================
//
// This list will never get long, so this code should be ok.
//
//==========================================================================
void FDrawInfo::DrawDecalsForMirror(GLWall *wall, FRenderState &state)
{
SetFog(wall->lightlevel, wall->rellight + getExtraLight(), &wall->Colormap, false);
for (auto gldecal : decals[1])
{
if (gldecal->decal->Side == wall->seg->sidedef)
{
DrawDecal(gldecal, state);
}
}
}

View file

@ -34,7 +34,153 @@
#include "hwrenderer/scene/hw_drawstructs.h" #include "hwrenderer/scene/hw_drawstructs.h"
#include "hwrenderer/scene/hw_drawinfo.h" #include "hwrenderer/scene/hw_drawinfo.h"
#include "hwrenderer/utility/hw_lighting.h" #include "hwrenderer/utility/hw_lighting.h"
#include "hwrenderer/utility/hw_clock.h"
#include "hwrenderer/data/flatvertices.h" #include "hwrenderer/data/flatvertices.h"
#include "hw_renderstate.h"
//==========================================================================
//
//
//
//==========================================================================
void GLDecal::DrawDecal(HWDrawInfo *di, FRenderState &state)
{
auto tex = gltexture;
// calculate dynamic light effect.
if (level.HasDynamicLights && !di->isFullbrightScene() && gl_light_sprites)
{
// Note: This should be replaced with proper shader based lighting.
double x, y;
float out[3];
decal->GetXY(decal->Side, x, y);
di->GetDynSpriteLight(nullptr, x, y, zcenter, decal->Side->lighthead, decal->Side->sector->PortalGroup, out);
state.SetDynLight(out[0], out[1], out[2]);
}
// alpha color only has an effect when using an alpha texture.
if (decal->RenderStyle.Flags & (STYLEF_RedIsAlpha | STYLEF_ColorIsFixed))
{
state.SetObjectColor(decal->AlphaColor | 0xff000000);
}
state.SetTextureMode(decal->RenderStyle);
state.SetRenderStyle(decal->RenderStyle);
state.SetMaterial(tex, CLAMP_XY, decal->Translation, -1);
// If srcalpha is one it looks better with a higher alpha threshold
if (decal->RenderStyle.SrcAlpha == STYLEALPHA_One) state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
else state.AlphaFunc(Alpha_Greater, 0.f);
state.SetColor(lightlevel, rellight, di->isFullbrightScene(), Colormap, alpha);
// for additively drawn decals we must temporarily set the fog color to black.
PalEntry fc = state.GetFogColor();
if (decal->RenderStyle.BlendOp == STYLEOP_Add && decal->RenderStyle.DestAlpha == STYLEALPHA_One)
{
state.SetFog(0, -1);
}
state.SetNormal(Normal);
if (lightlist == nullptr)
{
di->Draw(DT_TriangleFan, state, vertindex, 4);
}
else
{
auto &lightlist = *this->lightlist;
for (unsigned k = 0; k < lightlist.Size(); k++)
{
secplane_t &lowplane = k == lightlist.Size() - 1 ? bottomplane : lightlist[k + 1].plane;
float low1 = lowplane.ZatPoint(dv[1].x, dv[1].y);
float low2 = lowplane.ZatPoint(dv[2].x, dv[2].y);
if (low1 < dv[1].z || low2 < dv[2].z)
{
int thisll = lightlist[k].caster != nullptr ? hw_ClampLight(*lightlist[k].p_lightlevel) : lightlevel;
FColormap thiscm;
thiscm.FadeColor = Colormap.FadeColor;
thiscm.CopyFrom3DLight(&lightlist[k]);
state.SetColor(thisll, rellight, di->isFullbrightScene(), thiscm, alpha);
if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) thiscm.Decolorize();
state.SetFog(thisll, rellight, di->isFullbrightScene(), &thiscm, false);
state.SetSplitPlanes(lightlist[k].plane, lowplane);
di->Draw(DT_TriangleFan, state, vertindex, 4);
}
if (low1 <= dv[0].z && low2 <= dv[3].z) break;
}
}
rendered_decals++;
state.SetTextureMode(TM_NORMAL);
state.SetObjectColor(0xffffffff);
state.SetFog(fc, -1);
state.SetDynLight(0, 0, 0);
}
//==========================================================================
//
//
//
//==========================================================================
void HWDrawInfo::DrawDecals(FRenderState &state, TArray<GLDecal *> &decals)
{
side_t *wall = nullptr;
state.SetDepthBias(-1, -128);
for (auto gldecal : decals)
{
if (gldecal->decal->Side != wall)
{
wall = gldecal->decal->Side;
if (gldecal->lightlist != nullptr)
{
state.EnableSplit(true);
}
else
{
state.EnableSplit(false);
state.SetFog(gldecal->lightlevel, gldecal->rellight, isFullbrightScene(), &gldecal->Colormap, false);
}
}
gldecal->DrawDecal(this, state);
}
state.EnableSplit(false);
state.ClearDepthBias();
state.SetTextureMode(TM_NORMAL);
}
//==========================================================================
//
// This list will never get long, so this code should be ok.
//
//==========================================================================
void GLWall::DrawDecalsForMirror(HWDrawInfo *di, FRenderState &state, TArray<GLDecal *> &decals)
{
state.SetDepthBias(-1, -128);
state.SetFog(lightlevel, rellight + getExtraLight(), di->isFullbrightScene(), &Colormap, false);
for (auto gldecal : decals)
{
if (gldecal->decal->Side == seg->sidedef)
{
gldecal->DrawDecal(di, state);
}
}
state.ClearDepthBias();
state.SetTextureMode(TM_NORMAL);
}
//==========================================================================
//
//
//
//==========================================================================
void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &normal) void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &normal)
{ {
@ -271,6 +417,7 @@ void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor
// //
// //
//========================================================================== //==========================================================================
void GLWall::ProcessDecals(HWDrawInfo *di) void GLWall::ProcessDecals(HWDrawInfo *di)
{ {
if (seg->sidedef != nullptr) if (seg->sidedef != nullptr)

View file

@ -284,6 +284,8 @@ public:
void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror); void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror);
angle_t FrustumAngle(); angle_t FrustumAngle();
void DrawDecals(FRenderState &state, TArray<GLDecal *> &decals);
virtual void DrawWall(GLWall *wall, int pass) = 0; virtual void DrawWall(GLWall *wall, int pass) = 0;
virtual void DrawSprite(GLSprite *sprite, int pass) = 0; virtual void DrawSprite(GLSprite *sprite, int pass) = 0;

View file

@ -26,6 +26,7 @@ class VSMatrix;
struct FSpriteModelFrame; struct FSpriteModelFrame;
struct particle_t; struct particle_t;
class FRenderState; class FRenderState;
struct GLDecal;
enum area_t : int; enum area_t : int;
enum HWRenderStyle enum HWRenderStyle
@ -284,6 +285,8 @@ public:
return -((y-glseg.y1)*(glseg.x2-glseg.x1)-(x-glseg.x1)*(glseg.y2-glseg.y1)); return -((y-glseg.y1)*(glseg.x2-glseg.x1)-(x-glseg.x1)*(glseg.y2-glseg.y1));
} }
void DrawDecalsForMirror(HWDrawInfo *di, FRenderState &state, TArray<GLDecal *> &decals);
}; };
//========================================================================== //==========================================================================
@ -436,6 +439,8 @@ struct GLDecal
secplane_t bottomplane; secplane_t bottomplane;
FVector3 Normal; FVector3 Normal;
void DrawDecal(HWDrawInfo *di, FRenderState &state);
}; };

View file

@ -111,6 +111,7 @@ protected:
uint8_t mBrightmapEnabled : 1; uint8_t mBrightmapEnabled : 1;
uint8_t mModelMatrixEnabled : 1; uint8_t mModelMatrixEnabled : 1;
uint8_t mTextureMatrixEnabled : 1; uint8_t mTextureMatrixEnabled : 1;
uint8_t mSplitEnabled : 1;
int mLightIndex; int mLightIndex;
int mSpecialEffect; int mSpecialEffect;
@ -154,6 +155,7 @@ public:
mAlphaThreshold = 0.5f; mAlphaThreshold = 0.5f;
mModelMatrixEnabled = false; mModelMatrixEnabled = false;
mTextureMatrixEnabled = false; mTextureMatrixEnabled = false;
mSplitEnabled = false;
mObjectColor = 0xffffffff; mObjectColor = 0xffffffff;
mObjectColor2 = 0; mObjectColor2 = 0;
mSoftLight = 0; mSoftLight = 0;
@ -264,6 +266,11 @@ public:
mBrightmapEnabled = on; mBrightmapEnabled = on;
} }
void EnableSplit(bool on)
{
mSplitEnabled = on;
}
void EnableModelMatrix(bool on) void EnableModelMatrix(bool on)
{ {
mModelMatrixEnabled = on; mModelMatrixEnabled = on;