diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index baef29c21..34e0e72d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1070,6 +1070,7 @@ set( FASTMATH_PCH_SOURCES r_swrenderer.cpp r_poly.cpp r_poly_cull.cpp + r_poly_decal.cpp r_poly_particle.cpp r_poly_plane.cpp r_poly_playersprite.cpp diff --git a/src/r_poly_decal.cpp b/src/r_poly_decal.cpp new file mode 100644 index 000000000..af9c53a89 --- /dev/null +++ b/src/r_poly_decal.cpp @@ -0,0 +1,159 @@ +/* +** Handling drawing a decal +** Copyright (c) 2016 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include +#include "templates.h" +#include "doomdef.h" +#include "sbar.h" +#include "r_data/r_translate.h" +#include "r_poly_decal.h" +#include "r_poly.h" +#include "a_sharedglobal.h" + +void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const seg_t *line, uint32_t subsectorDepth) +{ + for (DBaseDecal *decal = line->sidedef->AttachedDecals; decal != nullptr; decal = decal->WallNext) + { + RenderPolyDecal render; + render.Render(worldToClip, decal, line, subsectorDepth); + } +} + +void RenderPolyDecal::Render(const TriMatrix &worldToClip, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth) +{ + if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid()) + return; + + FTexture *tex = TexMan(decal->PicNum, true); + if (tex == nullptr || tex->UseType == FTexture::TEX_Null) + return; + + double edge_right = tex->GetWidth(); + double edge_left = tex->LeftOffset; + edge_right = (edge_right - edge_left) * decal->ScaleX; + edge_left *= decal->ScaleX; + + double dcx, dcy; + decal->GetXY(line->sidedef, dcx, dcy); + DVector2 decal_pos = { dcx, dcy }; + + DVector2 angvec = (line->v2->fPos() - line->v1->fPos()).Unit(); + DVector2 decal_left = decal_pos - edge_left * angvec; + DVector2 decal_right = decal_pos + edge_right * angvec; + + // Determine actor z + double zpos = decal->Z; + sector_t *front = line->frontsector; + sector_t *back = (line->backsector != nullptr) ? line->backsector : line->frontsector; + switch (decal->RenderFlags & RF_RELMASK) + { + default: + zpos = decal->Z; + break; + case RF_RELUPPER: + if (line->linedef->flags & ML_DONTPEGTOP) + zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); + else + zpos = decal->Z + back->GetPlaneTexZ(sector_t::ceiling); + break; + case RF_RELLOWER: + if (line->linedef->flags & ML_DONTPEGBOTTOM) + zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); + else + zpos = decal->Z + back->GetPlaneTexZ(sector_t::floor); + break; + case RF_RELMID: + if (line->linedef->flags & ML_DONTPEGBOTTOM) + zpos = decal->Z + front->GetPlaneTexZ(sector_t::floor); + else + zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); + } + + DVector2 spriteScale = { decal->ScaleX, decal->ScaleY }; + double thingxscalemul = spriteScale.X / tex->Scale.X; + double thingyscalemul = spriteScale.Y / tex->Scale.Y; + double spriteHeight = thingyscalemul * tex->GetHeight(); + + bool flipTextureX = (decal->RenderFlags & RF_XFLIP) == RF_XFLIP; + + DVector2 points[2] = { decal_left, decal_right }; + + TriVertex *vertices = PolyVertexBuffer::GetVertices(4); + if (!vertices) + return; + + bool foggy = false; + int actualextralight = foggy ? 0 : extralight << 4; + + std::pair offsets[4] = + { + { 0.0f, 1.0f }, + { 1.0f, 1.0f }, + { 1.0f, 0.0f }, + { 0.0f, 0.0f }, + }; + + for (int i = 0; i < 4; i++) + { + auto &p = (i == 0 || i == 3) ? points[0] : points[1]; + + vertices[i].x = (float)p.X; + vertices[i].y = (float)p.Y; + vertices[i].z = (float)(zpos + spriteHeight * offsets[i].second); + vertices[i].w = 1.0f; + vertices[i].varying[0] = (float)(offsets[i].first * tex->Scale.X); + vertices[i].varying[1] = (float)((1.0f - offsets[i].second) * tex->Scale.Y); + if (flipTextureX) + vertices[i].varying[0] = 1.0f - vertices[i].varying[0]; + } + + bool fullbrightSprite = (decal->RenderFlags & RF_FULLBRIGHT) == RF_FULLBRIGHT; + + TriUniforms uniforms; + uniforms.objectToClip = worldToClip; + if (fullbrightSprite || fixedlightlev >= 0 || fixedcolormap) + { + uniforms.light = 256; + uniforms.flags = TriUniforms::fixed_light; + } + else + { + uniforms.light = (uint32_t)((front->lightlevel + actualextralight) / 255.0f * 256.0f); + uniforms.flags = 0; + } + uniforms.subsectorDepth = subsectorDepth; + + PolyDrawArgs args; + args.uniforms = uniforms; + args.vinput = vertices; + args.vcount = 4; + args.mode = TriangleDrawMode::Fan; + args.ccw = true; + args.clipleft = 0; + args.cliptop = 0; + args.clipright = viewwidth; + args.clipbottom = viewheight; + args.stenciltestvalue = 0; + args.stencilwritevalue = 1; + args.SetTexture(tex); + PolyTriangleDrawer::draw(args, TriDrawVariant::DrawSubsector); +} diff --git a/src/r_poly_decal.h b/src/r_poly_decal.h new file mode 100644 index 000000000..39b250abb --- /dev/null +++ b/src/r_poly_decal.h @@ -0,0 +1,34 @@ +/* +** Handling drawing a decal +** Copyright (c) 2016 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#pragma once + +#include "r_triangle.h" + +class RenderPolyDecal +{ +public: + static void RenderWallDecals(const TriMatrix &worldToClip, const seg_t *line, uint32_t subsectorDepth); + +private: + void Render(const TriMatrix &worldToClip, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth); +}; diff --git a/src/r_poly_wall.cpp b/src/r_poly_wall.cpp index 6921b1a33..2ed225cf2 100644 --- a/src/r_poly_wall.cpp +++ b/src/r_poly_wall.cpp @@ -26,6 +26,7 @@ #include "sbar.h" #include "r_data/r_translate.h" #include "r_poly_wall.h" +#include "r_poly_decal.h" #include "r_poly.h" #include "r_sky.h" // for skyflatnum @@ -203,6 +204,8 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip) { PolyTriangleDrawer::draw(args, TriDrawVariant::DrawSubsector); } + + RenderPolyDecal::RenderWallDecals(worldToClip, Line, SubsectorDepth); } void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2) diff --git a/src/r_poly_wallsprite.cpp b/src/r_poly_wallsprite.cpp index 63472e297..c6b3a6569 100644 --- a/src/r_poly_wallsprite.cpp +++ b/src/r_poly_wallsprite.cpp @@ -65,7 +65,7 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, AActor *thing, s //gzt = pos.Z + scale.Y * scaled_to; //gzb = pos.Z + scale.Y * scaled_bo; - DVector2 points[2] = { right, left }; + DVector2 points[2] = { left, right }; TriVertex *vertices = PolyVertexBuffer::GetVertices(4); if (!vertices)