mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
- draw decals in hardware independent code.
This commit is contained in:
parent
1768508c80
commit
a97d71a3c3
9 changed files with 183 additions and 179 deletions
|
@ -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()
|
||||
{
|
||||
FRenderState::Reset();
|
||||
mSplitEnabled = false;
|
||||
mSrcBlend = GL_SRC_ALPHA;
|
||||
mDstBlend = GL_ONE_MINUS_SRC_ALPHA;
|
||||
mBlendEquation = GL_FUNC_ADD;
|
||||
mVertexBuffer = mCurrentVertexBuffer = NULL;
|
||||
mVertexBuffer = mCurrentVertexBuffer = nullptr;
|
||||
mGlossiness = 0.0f;
|
||||
mSpecularLevel = 0.0f;
|
||||
mShaderTimer = 0.0f;
|
||||
ClearClipSplit();
|
||||
|
||||
stRenderStyle = DefaultRenderStyle();
|
||||
stSrcBlend = stDstBlend = -1;
|
||||
stBlendEquation = -1;
|
||||
stAlphaTest = 0;
|
||||
|
@ -216,6 +217,21 @@ void FGLRenderState::Apply()
|
|||
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)
|
||||
{
|
||||
ApplyMaterial(mMaterial.mMaterial, mMaterial.mClampMode, mMaterial.mTranslation, mMaterial.mOverrideShader);
|
||||
|
|
|
@ -49,7 +49,6 @@ enum EPassType
|
|||
|
||||
class FGLRenderState : public FRenderState
|
||||
{
|
||||
uint8_t mSplitEnabled : 1;
|
||||
uint8_t mLastDepthClamp : 1;
|
||||
|
||||
int mSrcBlend, mDstBlend;
|
||||
|
@ -68,6 +67,7 @@ class FGLRenderState : public FRenderState
|
|||
FRenderStyle stRenderStyle;
|
||||
int stSrcBlend, stDstBlend;
|
||||
bool stAlphaTest;
|
||||
bool stSplitEnabled;
|
||||
int stBlendEquation;
|
||||
|
||||
FShader *activeShader;
|
||||
|
@ -115,25 +115,6 @@ public:
|
|||
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)
|
||||
{
|
||||
mGlossiness = glossiness;
|
||||
|
|
|
@ -57,16 +57,7 @@ struct FDrawInfo : public HWDrawInfo
|
|||
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 DrawDecal(GLDecal *gldecal, FRenderState &state);
|
||||
void DrawDecals(FRenderState &state);
|
||||
void DrawDecalsForMirror(GLWall *wall, FRenderState &state);
|
||||
|
||||
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
|
||||
void RenderWall(GLWall *wall, int textured);
|
||||
|
|
|
@ -203,14 +203,9 @@ void FDrawInfo::RenderScene(int recursion)
|
|||
|
||||
// Part 4: Draw decals (not a real pass)
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
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);
|
||||
RenderAll.Unclock();
|
||||
}
|
||||
|
|
|
@ -122,14 +122,9 @@ void FDrawInfo::RenderMirrorSurface(GLWall *wall)
|
|||
// because the depth buffer won't get set by translucent items.
|
||||
if (wall->seg->sidedef->AttachedDecals)
|
||||
{
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
glDepthMask(false);
|
||||
DrawDecalsForMirror(wall, gl_RenderState);
|
||||
wall->DrawDecalsForMirror(this, gl_RenderState, decals[1]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -440,138 +435,3 @@ void FDrawInfo::AddPortal(GLWall *wall, int ptype)
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,153 @@
|
|||
#include "hwrenderer/scene/hw_drawstructs.h"
|
||||
#include "hwrenderer/scene/hw_drawinfo.h"
|
||||
#include "hwrenderer/utility/hw_lighting.h"
|
||||
#include "hwrenderer/utility/hw_clock.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)
|
||||
{
|
||||
|
@ -271,6 +417,7 @@ void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor
|
|||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void GLWall::ProcessDecals(HWDrawInfo *di)
|
||||
{
|
||||
if (seg->sidedef != nullptr)
|
||||
|
|
|
@ -284,6 +284,8 @@ public:
|
|||
void SetupView(float vx, float vy, float vz, bool mirror, bool planemirror);
|
||||
angle_t FrustumAngle();
|
||||
|
||||
void DrawDecals(FRenderState &state, TArray<GLDecal *> &decals);
|
||||
|
||||
virtual void DrawWall(GLWall *wall, int pass) = 0;
|
||||
virtual void DrawSprite(GLSprite *sprite, int pass) = 0;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ class VSMatrix;
|
|||
struct FSpriteModelFrame;
|
||||
struct particle_t;
|
||||
class FRenderState;
|
||||
struct GLDecal;
|
||||
enum area_t : int;
|
||||
|
||||
enum HWRenderStyle
|
||||
|
@ -284,6 +285,8 @@ public:
|
|||
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;
|
||||
FVector3 Normal;
|
||||
|
||||
void DrawDecal(HWDrawInfo *di, FRenderState &state);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ protected:
|
|||
uint8_t mBrightmapEnabled : 1;
|
||||
uint8_t mModelMatrixEnabled : 1;
|
||||
uint8_t mTextureMatrixEnabled : 1;
|
||||
uint8_t mSplitEnabled : 1;
|
||||
|
||||
int mLightIndex;
|
||||
int mSpecialEffect;
|
||||
|
@ -154,6 +155,7 @@ public:
|
|||
mAlphaThreshold = 0.5f;
|
||||
mModelMatrixEnabled = false;
|
||||
mTextureMatrixEnabled = false;
|
||||
mSplitEnabled = false;
|
||||
mObjectColor = 0xffffffff;
|
||||
mObjectColor2 = 0;
|
||||
mSoftLight = 0;
|
||||
|
@ -264,6 +266,11 @@ public:
|
|||
mBrightmapEnabled = on;
|
||||
}
|
||||
|
||||
void EnableSplit(bool on)
|
||||
{
|
||||
mSplitEnabled = on;
|
||||
}
|
||||
|
||||
void EnableModelMatrix(bool on)
|
||||
{
|
||||
mModelMatrixEnabled = on;
|
||||
|
|
Loading…
Reference in a new issue