From 9593cb56aebbf61393e866b6bbd7db3cfe2741c6 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 14 Apr 2020 00:42:13 +0200 Subject: [PATCH] - decoupled the software renderer entirely from FTexture - it will only look at FSoftwareTexture now, all access to the texture manager has been wrapped. --- src/common/textures/texture.cpp | 3 +- src/common/textures/texturemanager.cpp | 3 +- src/common/textures/texturemanager.h | 7 ++- src/common/textures/textures.h | 37 +++++++++++-- src/rendering/swrenderer/line/r_line.cpp | 24 ++++----- .../swrenderer/line/r_renderdrawsegment.cpp | 42 +++++---------- src/rendering/swrenderer/line/r_walldraw.cpp | 2 +- src/rendering/swrenderer/plane/r_skyplane.cpp | 19 +++---- .../swrenderer/plane/r_visibleplane.cpp | 8 +-- src/rendering/swrenderer/r_swrenderer.cpp | 18 +++---- src/rendering/swrenderer/r_swrenderer.h | 4 +- .../swrenderer/scene/r_opaque_pass.cpp | 17 +++--- .../swrenderer/scene/r_opaque_pass.h | 2 +- .../swrenderer/textures/r_swtexture.cpp | 54 ++++++++++++------- .../swrenderer/textures/r_swtexture.h | 51 +++++++++--------- .../swrenderer/textures/swcanvastexture.cpp | 6 +-- .../swrenderer/textures/warptexture.cpp | 6 +-- src/rendering/swrenderer/things/r_decal.cpp | 6 +-- .../swrenderer/things/r_playersprite.cpp | 8 +-- src/rendering/swrenderer/things/r_sprite.cpp | 8 ++- src/rendering/swrenderer/things/r_sprite.h | 2 +- .../swrenderer/things/r_wallsprite.cpp | 3 +- .../swrenderer/things/r_wallsprite.h | 2 +- 23 files changed, 170 insertions(+), 162 deletions(-) diff --git a/src/common/textures/texture.cpp b/src/common/textures/texture.cpp index a2f02e3eb..05ae74221 100644 --- a/src/common/textures/texture.cpp +++ b/src/common/textures/texture.cpp @@ -50,7 +50,6 @@ // Wrappers to keep the definitions of these classes out of here. void DeleteMaterial(FMaterial* mat); -void DeleteSoftwareTexture(FSoftwareTexture *swtex); IHardwareTexture* CreateHardwareTexture(); @@ -161,7 +160,7 @@ FTexture::~FTexture () } if (SoftwareTexture != nullptr) { - DeleteSoftwareTexture(SoftwareTexture); + delete SoftwareTexture; SoftwareTexture = nullptr; } } diff --git a/src/common/textures/texturemanager.cpp b/src/common/textures/texturemanager.cpp index 4e87a893e..834f9de48 100644 --- a/src/common/textures/texturemanager.cpp +++ b/src/common/textures/texturemanager.cpp @@ -111,7 +111,6 @@ void FTextureManager::DeleteAll() // main reason to call this outside of the destruction code. // //========================================================================== -void DeleteSoftwareTexture(FSoftwareTexture* swtex); void FTextureManager::FlushAll() { @@ -120,7 +119,7 @@ void FTextureManager::FlushAll() for (int j = 0; j < 2; j++) { Textures[i].Texture->CleanHardwareTextures(true, true); - DeleteSoftwareTexture(Textures[i].Texture->SoftwareTexture); + delete Textures[i].Texture->SoftwareTexture; Textures[i].Texture->SoftwareTexture = nullptr; } } diff --git a/src/common/textures/texturemanager.h b/src/common/textures/texturemanager.h index ed239c8ba..b5a7aa4e7 100644 --- a/src/common/textures/texturemanager.h +++ b/src/common/textures/texturemanager.h @@ -60,7 +60,12 @@ public: { return InternalGetTexture(i, animate, true, false); } - + + FGameTexture* GameByIndex(int i, bool animate = false) + { + return reinterpret_cast(ByIndex(i, animate)); + } + FTexture *FindTexture(const char *texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny); bool OkForLocalization(FTextureID texnum, const char *substitute, int locnum); diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h index 74d3bed19..839607cd3 100644 --- a/src/common/textures/textures.h +++ b/src/common/textures/textures.h @@ -156,7 +156,12 @@ enum FTextureFormat : uint32_t TEX_Count }; -class FSoftwareTexture; +class ISoftwareTexture +{ +public: + virtual ~ISoftwareTexture() = default; +}; + class FGLRenderState; struct spriteframewithrotate; @@ -226,7 +231,6 @@ class FTexture friend FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); // For now only give access to classes which cannot be reworked yet. None of these should remain here when all is done. - friend class FSoftwareTexture; friend class FWarpTexture; friend class FMaterial; friend class OpenGLRenderer::FGLRenderState; // For now this needs access to some fields in ApplyMaterial. This should be rerouted through the Material class @@ -275,6 +279,7 @@ public: bool isMiscPatch() const { return UseType == ETextureType::MiscPatch; } // only used by the intermission screen to decide whether to tile the background image or not. int isWarped() const { return bWarped; } int GetRotations() const { return Rotations; } + float GetShaderSpeed() const { return shaderspeed; } void SetRotations(int rot) { Rotations = int16_t(rot); } bool isSprite() const { return UseType == ETextureType::Sprite || UseType == ETextureType::SkinSprite || UseType == ETextureType::Decal; } @@ -301,6 +306,7 @@ public: int GetSourceLump() const { return SourceLump; } ETextureType GetUseType() const { return UseType; } void SetSpeed(float fac) { shaderspeed = fac; } + bool UseWorldPanning() const { return bWorldPanning; } void SetWorldPanning(bool on) { bWorldPanning = on; } void SetDisplaySize(int fitwidth, int fitheight); void SetFrontSkyLayer(bool on = true) { bNoRemap0 = on; } @@ -334,7 +340,14 @@ public: static PalEntry averageColor(const uint32_t *data, int size, int maxout); - FSoftwareTexture *GetSoftwareTexture(); + ISoftwareTexture* GetSoftwareTexture() + { + return SoftwareTexture; + } + void SetSoftwareTextue(ISoftwareTexture* swtex) + { + SoftwareTexture = swtex; + } protected: @@ -347,7 +360,7 @@ protected: public: FHardwareTextureContainer SystemTextures; protected: - FSoftwareTexture *SoftwareTexture = nullptr; + ISoftwareTexture *SoftwareTexture = nullptr; // None of the following pointers are owned by this texture, they are all controlled by the texture manager. @@ -568,9 +581,23 @@ public: int GetDisplayWidth() /*const*/ { return wrapped.GetDisplayWidth(); } int GetDisplayHeight() /*const*/ { return wrapped.GetDisplayHeight(); } + int GetTexelWidth() /*const*/ { return wrapped.GetTexelWidth(); } + int GetTexelHeight() /*const*/ { return wrapped.GetTexelHeight(); } + int GetTexelLeftOffset(int adjusted) /*const*/ { return wrapped.GetTexelLeftOffset(adjusted); } + int GetTexelTopOffset(int adjusted) /*const*/ { return wrapped.GetTexelTopOffset(adjusted); } + double GetDisplayLeftOffset(int adjusted) /*const*/ { return wrapped.GetDisplayLeftOffsetDouble(adjusted); } + double GetDisplayTopOffset(int adjusted) /*const*/ { return wrapped.GetDisplayTopOffsetDouble(adjusted); } bool isValid() { return wrapped.isValid(); } - uint16_t GetRotations() { return wrapped.GetRotations(); } + bool isWarped() { return wrapped.isWarped(); } + bool useWorldPanning() { return wrapped.UseWorldPanning(); } + float GetShaderSpeed() const { return wrapped.GetShaderSpeed(); } + uint16_t GetRotations() const { return wrapped.GetRotations(); } + int GetSkyOffset() const { return wrapped.GetSkyOffset(); } + FTextureID GetID() const { return wrapped.GetID(); } + ISoftwareTexture* GetSoftwareTexture() { return wrapped.GetSoftwareTexture(); } + void SetSoftwareTexture(ISoftwareTexture* swtex) { wrapped.SetSoftwareTextue(swtex); } + }; diff --git a/src/rendering/swrenderer/line/r_line.cpp b/src/rendering/swrenderer/line/r_line.cpp index d18c2d9a5..d6fb81321 100644 --- a/src/rendering/swrenderer/line/r_line.cpp +++ b/src/rendering/swrenderer/line/r_line.cpp @@ -389,8 +389,7 @@ namespace swrenderer if (mLineSegment->linedef->alpha > 0.0f && sidedef->GetTexture(side_t::mid).isValid()) { - FTexture* tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); - FSoftwareTexture* pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; + auto pic = GetPalettedSWTexture(sidedef->GetTexture(side_t::mid), true); if (pic) { draw_segment->SetHasTranslucentMidTexture(); @@ -687,10 +686,9 @@ namespace swrenderer // No top texture for skyhack lines if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum) return; - FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::top), true); - if (!tex || !tex->isValid()) return; - - mTopTexture = tex->GetSoftwareTexture(); + auto tex = GetPalettedSWTexture(sidedef->GetTexture(side_t::top), true); + if (!tex) return; + mTopTexture = tex; } void SWRenderLine::SetMiddleTexture() @@ -702,10 +700,9 @@ namespace swrenderer if (linedef->isVisualPortal()) return; if (linedef->special == Line_Horizon) return; - auto tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); - if (!tex || !tex->isValid()) return; - - mMiddleTexture = tex->GetSoftwareTexture(); + auto tex = GetPalettedSWTexture(sidedef->GetTexture(side_t::mid), true); + if (!tex) return; + mMiddleTexture = tex; } void SWRenderLine::SetBottomTexture() @@ -713,10 +710,9 @@ namespace swrenderer side_t *sidedef = mLineSegment->sidedef; line_t *linedef = mLineSegment->linedef; - FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::bottom), true); - if (!tex || !tex->isValid()) return; - - mBottomTexture = tex->GetSoftwareTexture(); + auto tex = GetPalettedSWTexture(sidedef->GetTexture(side_t::bottom), true); + if (!tex) return; + mBottomTexture = tex; } bool SWRenderLine::IsFogBoundary(sector_t *front, sector_t *back) const diff --git a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp index fc5a2cbb0..4d203ec4a 100644 --- a/src/rendering/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/rendering/swrenderer/line/r_renderdrawsegment.cpp @@ -91,13 +91,7 @@ namespace swrenderer auto viewport = Thread->Viewport.get(); Clip3DFloors *clip3d = Thread->Clip3D.get(); - FTexture *ttex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::mid), true); - if (curline->GetLevel()->i_compatflags & COMPATF_MASKEDMIDTEX) - { - ttex = ttex->GetRawTexture(); - } - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); - + auto tex = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::mid), true, curline->GetLevel()); const short *mfloorclip = ds->drawsegclip.sprbottomclip; const short *mceilingclip = ds->drawsegclip.sprtopclip; @@ -333,20 +327,18 @@ namespace swrenderer } else { - FTexture *rw_tex = nullptr; if (fover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (fover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } } else if (frontsector->e->XFloor.ffloors.Size()) @@ -395,20 +387,18 @@ namespace swrenderer if (!rw_pic && !swimmable_found) { fover = nullptr; - FTexture *rw_tex; if (rover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (rover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } if (rw_pic && !swimmable_found) @@ -487,20 +477,18 @@ namespace swrenderer } else { - FTexture *rw_tex; if (fover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (fover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } } else if (frontsector->e->XFloor.ffloors.Size()) @@ -546,20 +534,18 @@ namespace swrenderer if (!rw_pic && !swimmable_found) { fover = nullptr; - FTexture *rw_tex; if (rover->flags & FF_UPPERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (rover->flags & FF_LOWERTEXTURE) { - rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + rw_pic = GetPalettedSWTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_tex = TexMan.GetPalettedTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_pic = GetPalettedSWTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); } - rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } if (rw_pic && !swimmable_found) @@ -643,7 +629,7 @@ namespace swrenderer void RenderDrawSegment::GetNoWrapMidTextureZ(DrawSegment* ds, FSoftwareTexture* tex, double& ceilZ, double& floorZ) { - double texheight = tex->GetScaledHeightDouble() / fabs(curline->sidedef->GetTextureYScale(side_t::mid)); + double texheight = tex->GetScaledHeight() / fabs(curline->sidedef->GetTextureYScale(side_t::mid)); double texturemid; if (curline->linedef->flags & ML_DONTPEGBOTTOM) texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight; diff --git a/src/rendering/swrenderer/line/r_walldraw.cpp b/src/rendering/swrenderer/line/r_walldraw.cpp index 022854ddd..35f340360 100644 --- a/src/rendering/swrenderer/line/r_walldraw.cpp +++ b/src/rendering/swrenderer/line/r_walldraw.cpp @@ -130,7 +130,7 @@ namespace swrenderer WallDrawerArgs drawerargs; // Textures that aren't masked can use the faster opaque drawer - if (!pic->GetTexture()->isMasked() && mask && alpha >= OPAQUE && !additive) + if (!pic->isMasked() && mask && alpha >= OPAQUE && !additive) { drawerargs.SetStyle(true, false, OPAQUE, light_list); } diff --git a/src/rendering/swrenderer/plane/r_skyplane.cpp b/src/rendering/swrenderer/plane/r_skyplane.cpp index 13361e397..5b9b60c4c 100644 --- a/src/rendering/swrenderer/plane/r_skyplane.cpp +++ b/src/rendering/swrenderer/plane/r_skyplane.cpp @@ -63,10 +63,7 @@ namespace swrenderer { static FSoftwareTexture *GetSWTex(FTextureID texid, bool allownull = true) { - auto tex = TexMan.GetPalettedTexture(texid, true); - if (tex == nullptr) return nullptr; - if (!allownull && !tex->isValid()) return nullptr; - return tex->GetSoftwareTexture(); + return GetPalettedSWTexture(texid, true, nullptr, true); } RenderSkyPlane::RenderSkyPlane(RenderThread *thread) @@ -74,16 +71,14 @@ namespace swrenderer Thread = thread; auto Level = Thread->Viewport->Level(); - auto skytex1 = TexMan.GetPalettedTexture(Level->skytexture1, true); - auto skytex2 = TexMan.GetPalettedTexture(Level->skytexture2, true); + auto sskytex1 = GetPalettedSWTexture(Level->skytexture1, true, nullptr, true); + auto sskytex2 = GetPalettedSWTexture(Level->skytexture2, true, nullptr, true); - if (skytex1 == nullptr) + if (sskytex1 == nullptr) return; - FSoftwareTexture *sskytex1 = skytex1->GetSoftwareTexture(); - FSoftwareTexture *sskytex2 = skytex2->GetSoftwareTexture(); skytexturemid = 0; - int skyheight = skytex1->GetDisplayHeight(); + int skyheight = sskytex1->GetScaledHeight(); skyoffset = cl_oldfreelooklimit? 0 : skyheight == 256? 166 : skyheight >= 240? 150 : skyheight >= 200? 110 : 138; if (skyheight >= 128 && skyheight < 200) { @@ -91,7 +86,7 @@ namespace swrenderer } else if (skyheight >= 200) { - skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)) ? skytex1->GetSkyOffset() : 0); + skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)) ? sskytex1->GetSkyOffset() : 0); } if (viewwidth != 0 && viewheight != 0) @@ -207,7 +202,7 @@ namespace swrenderer frontcyl = MAX(frontskytex->GetWidth(), frontxscale); if (Level->skystretch) { - skymid = skymid * frontskytex->GetScaledHeightDouble() / (SKYSTRETCH_HEIGHT + skyoffset); + skymid = skymid * frontskytex->GetScaledHeight() / (SKYSTRETCH_HEIGHT + skyoffset); } } } diff --git a/src/rendering/swrenderer/plane/r_visibleplane.cpp b/src/rendering/swrenderer/plane/r_visibleplane.cpp index 00f76a8f3..889d2f0be 100644 --- a/src/rendering/swrenderer/plane/r_visibleplane.cpp +++ b/src/rendering/swrenderer/plane/r_visibleplane.cpp @@ -114,13 +114,7 @@ namespace swrenderer } else // regular flat { - FTexture *ttex = TexMan.GetPalettedTexture(picnum, true); - - if (!ttex->isValid()) - { - return; - } - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); + auto tex = GetPalettedSWTexture(picnum, true); if (!masked && !additive) { // If we're not supposed to see through this plane, draw it opaque. diff --git a/src/rendering/swrenderer/r_swrenderer.cpp b/src/rendering/swrenderer/r_swrenderer.cpp index c099b4b16..4f91447ce 100644 --- a/src/rendering/swrenderer/r_swrenderer.cpp +++ b/src/rendering/swrenderer/r_swrenderer.cpp @@ -82,13 +82,13 @@ FRenderer *CreateSWRenderer() return new FSoftwareRenderer; } -void FSoftwareRenderer::PreparePrecache(FTexture *ttex, int cache) +void FSoftwareRenderer::PreparePrecache(FGameTexture *ttex, int cache) { bool isbgra = V_IsTrueColor(); - if (ttex != nullptr && ttex->isValid() && !ttex->isCanvas()) + if (ttex != nullptr && ttex->isValid() && !ttex->GetTexture()->isCanvas()) { - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); + FSoftwareTexture *tex = GetSoftwareTexture(ttex); if (tex->CheckPixels()) { @@ -96,18 +96,18 @@ void FSoftwareRenderer::PreparePrecache(FTexture *ttex, int cache) } else if (cache != 0) { - FImageSource::RegisterForPrecache(ttex->GetImage(), V_IsTrueColor()); + FImageSource::RegisterForPrecache(ttex->GetTexture()->GetImage(), V_IsTrueColor()); } } } -void FSoftwareRenderer::PrecacheTexture(FTexture *ttex, int cache) +void FSoftwareRenderer::PrecacheTexture(FGameTexture *ttex, int cache) { bool isbgra = V_IsTrueColor(); - if (ttex != nullptr && ttex->isValid() && !ttex->isCanvas()) + if (ttex != nullptr && ttex->isValid() && !ttex->GetTexture()->isCanvas()) { - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); + FSoftwareTexture *tex = GetSoftwareTexture(ttex); if (cache & FTextureManager::HIT_Columnmode) { const FSoftwareTextureSpan *spanp; @@ -173,12 +173,12 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap & FImageSource::BeginPrecaching(); for (int i = cnt - 1; i >= 0; i--) { - PreparePrecache(TexMan.ByIndex(i), texhitlist[i]); + PreparePrecache(TexMan.GameByIndex(i), texhitlist[i]); } for (int i = cnt - 1; i >= 0; i--) { - PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]); + PrecacheTexture(TexMan.GameByIndex(i), texhitlist[i]); } FImageSource::EndPrecaching(); } diff --git a/src/rendering/swrenderer/r_swrenderer.h b/src/rendering/swrenderer/r_swrenderer.h index 7ab3c0508..1e26a6a06 100644 --- a/src/rendering/swrenderer/r_swrenderer.h +++ b/src/rendering/swrenderer/r_swrenderer.h @@ -27,8 +27,8 @@ struct FSoftwareRenderer : public FRenderer void Init() override; private: - void PreparePrecache(FTexture *tex, int cache); - void PrecacheTexture(FTexture *tex, int cache); + void PreparePrecache(FGameTexture *tex, int cache); + void PrecacheTexture(FGameTexture *tex, int cache); swrenderer::RenderScene mScene; }; diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.cpp b/src/rendering/swrenderer/scene/r_opaque_pass.cpp index c8158e8cf..6f6ef6bd1 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.cpp +++ b/src/rendering/swrenderer/scene/r_opaque_pass.cpp @@ -951,7 +951,8 @@ namespace swrenderer { thinglightlevel = thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight(); auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING); - thingColormap = GetSpriteColorTable(thing->Sector->Colormap, thing->Sector->SpecialColors[sector_t::sprites], nc); } + thingColormap = GetSpriteColorTable(thing->Sector->Colormap, thing->Sector->SpecialColors[sector_t::sprites], nc); + } if ((sprite.renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) { @@ -1021,11 +1022,8 @@ namespace swrenderer { sprite.picnum = thing->picnum; - sprite.tex = TexMan.GetPalettedTexture(sprite.picnum, true); - if (!sprite.tex->isValid()) - { - return false; - } + sprite.tex = GetPalettedSWTexture(sprite.picnum, true); + if (!sprite.tex) return false; if (sprite.tex->GetRotations() != 0xFFFF) { @@ -1052,7 +1050,8 @@ namespace swrenderer { sprite.renderflags ^= RF_XFLIP; } - sprite.tex = TexMan.GetPalettedTexture(sprite.picnum, false); // Do not animate the rotation + sprite.tex = GetPalettedSWTexture(sprite.picnum, false); // Do not animate the rotation + if (!sprite.tex) return false; } } else @@ -1082,7 +1081,7 @@ namespace swrenderer { sprite.renderflags ^= RF_XFLIP; } - sprite.tex = TexMan.GetPalettedTexture(tex, false); // Do not animate the rotation + sprite.tex = GetPalettedSWTexture(tex, false); // Do not animate the rotation } if (r_drawvoxels) @@ -1094,7 +1093,7 @@ namespace swrenderer return false; } - if (sprite.voxel == nullptr && (sprite.tex == nullptr || !sprite.tex->isValid())) + if (sprite.voxel == nullptr && sprite.tex == nullptr) { return false; } diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.h b/src/rendering/swrenderer/scene/r_opaque_pass.h index d834327d5..d9d20c972 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.h +++ b/src/rendering/swrenderer/scene/r_opaque_pass.h @@ -51,7 +51,7 @@ namespace swrenderer { DVector3 pos; int spritenum; - FTexture *tex; + FSoftwareTexture *tex; FVoxelDef *voxel; FTextureID picnum; DVector2 spriteScale; diff --git a/src/rendering/swrenderer/textures/r_swtexture.cpp b/src/rendering/swrenderer/textures/r_swtexture.cpp index 37695fa7d..676ed7313 100644 --- a/src/rendering/swrenderer/textures/r_swtexture.cpp +++ b/src/rendering/swrenderer/textures/r_swtexture.cpp @@ -38,18 +38,9 @@ #include "bitmap.h" #include "m_alloc.h" #include "imagehelpers.h" +#include "texturemanager.h" -FSoftwareTexture *FTexture::GetSoftwareTexture() -{ - if (!SoftwareTexture) - { - if (bHasCanvas) SoftwareTexture = new FSWCanvasTexture(this); - else if (bWarped) SoftwareTexture = new FWarpTexture(this, bWarped); - else SoftwareTexture = new FSoftwareTexture(this); - } - return SoftwareTexture; -} //========================================================================== // @@ -57,16 +48,19 @@ FSoftwareTexture *FTexture::GetSoftwareTexture() // //========================================================================== -FSoftwareTexture::FSoftwareTexture(FTexture *tex) +FSoftwareTexture::FSoftwareTexture(FGameTexture *tex) { mTexture = tex; - mSource = tex; + mSource = tex->GetTexture(); mBufferFlags = CTF_ProcessData; - auto info = tex->CreateTexBuffer(0, CTF_CheckOnly| mBufferFlags); + // calculate the real size after running the scaler. + auto info = mSource->CreateTexBuffer(0, CTF_CheckOnly| mBufferFlags); mPhysicalWidth = info.mWidth; mPhysicalHeight = info.mHeight; - mPhysicalScale = tex->Width > 0? mPhysicalWidth / tex->Width : mPhysicalWidth; + mPhysicalScale = tex->GetTexelWidth() > 0 ? mPhysicalWidth / tex->GetTexelWidth() : mPhysicalWidth; + Scale.X = (double)tex->GetTexelWidth() / tex->GetDisplayWidth(); + Scale.Y = (double)tex->GetTexelHeight() / tex->GetDisplayHeight(); CalcBitSize(); } @@ -119,7 +113,7 @@ const uint8_t *FSoftwareTexture::GetPixels(int style) } else { - auto tempbuffer = mTexture->CreateTexBuffer(0, mBufferFlags); + auto tempbuffer = mSource->CreateTexBuffer(0, mBufferFlags); Pixels.Resize(GetPhysicalWidth()*GetPhysicalHeight()); PalEntry *pe = (PalEntry*)tempbuffer.mBuffer; if (!style) @@ -159,12 +153,12 @@ const uint32_t *FSoftwareTexture::GetPixelsBgra() { if (mPhysicalScale == 1) { - FBitmap bitmap = mTexture->GetBgraBitmap(nullptr); + FBitmap bitmap = mSource->GetBgraBitmap(nullptr); GenerateBgraFromBitmap(bitmap); } else { - auto tempbuffer = mTexture->CreateTexBuffer(0, mBufferFlags); + auto tempbuffer = mSource->CreateTexBuffer(0, mBufferFlags); CreatePixelsBgraWithMipmaps(); PalEntry *pe = (PalEntry*)tempbuffer.mBuffer; for (int y = 0; y < GetPhysicalHeight(); y++) @@ -263,7 +257,7 @@ FSoftwareTextureSpan **FSoftwareTexture::CreateSpans (const T *pixels) { FSoftwareTextureSpan **spans, *span; - if (!mTexture->isMasked()) + if (!mSource->isMasked()) { // Texture does not have holes, so it can use a simpler span structure spans = (FSoftwareTextureSpan **)M_Malloc (sizeof(FSoftwareTextureSpan*)*GetPhysicalWidth() + sizeof(FSoftwareTextureSpan)*2); span = (FSoftwareTextureSpan *)&spans[GetPhysicalWidth()]; @@ -598,8 +592,28 @@ void FSoftwareTexture::FreeAllSpans() } } -void DeleteSoftwareTexture(FSoftwareTexture* swtex) +FSoftwareTexture* GetSoftwareTexture(FGameTexture* tex) { - delete swtex; + FSoftwareTexture* SoftwareTexture = static_cast(tex->GetSoftwareTexture()); + if (!SoftwareTexture) + { + auto source = tex->GetTexture(); + if (source->isCanvas()) SoftwareTexture = new FSWCanvasTexture(tex); + else if (tex->isWarped()) SoftwareTexture = new FWarpTexture(tex, tex->isWarped()); + else SoftwareTexture = new FSoftwareTexture(tex); + tex->SetSoftwareTexture(SoftwareTexture); + } + return SoftwareTexture; +} + +FSoftwareTexture* GetPalettedSWTexture(FTextureID texid, bool animate, FLevelLocals *checkcompat, bool allownull) +{ + auto tex = TexMan.GetPalettedTexture(texid, true); + if (checkcompat && tex && tex->isValid() && checkcompat->i_compatflags & COMPATF_MASKEDMIDTEX) + { + tex = tex->GetRawTexture(); + } + FSoftwareTexture* pic = tex && (allownull || tex->isValid()) ? GetSoftwareTexture(reinterpret_cast(tex)) : nullptr; + return pic; } diff --git a/src/rendering/swrenderer/textures/r_swtexture.h b/src/rendering/swrenderer/textures/r_swtexture.h index ce6438aaf..a6b89c8c9 100644 --- a/src/rendering/swrenderer/textures/r_swtexture.h +++ b/src/rendering/swrenderer/textures/r_swtexture.h @@ -12,14 +12,15 @@ struct FSoftwareTextureSpan // For now this is just a minimal wrapper around FTexture. Once the software renderer no longer accesses FTexture directly, it is time for cleaning up. -class FSoftwareTexture +class FSoftwareTexture : public ISoftwareTexture { protected: - FTexture *mTexture; + FGameTexture *mTexture; FTexture *mSource; TArray Pixels; TArray PixelsBgra; FSoftwareTextureSpan **Spandata[3] = { }; + DVector2 Scale; uint8_t WidthBits = 0, HeightBits = 0; uint16_t WidthMask = 0; int mPhysicalWidth, mPhysicalHeight; @@ -32,14 +33,14 @@ protected: void CalcBitSize(); public: - FSoftwareTexture(FTexture *tex); + FSoftwareTexture(FGameTexture *tex); virtual ~FSoftwareTexture() { FreeAllSpans(); } - FTexture *GetTexture() const + FGameTexture *GetTexture() const { return mTexture; } @@ -47,32 +48,33 @@ public: // The feature from hell... :( bool useWorldPanning(FLevelLocals *Level) const { - return mTexture->bWorldPanning || (Level->flags3 & LEVEL3_FORCEWORLDPANNING); + return mTexture->useWorldPanning() || (Level->flags3 & LEVEL3_FORCEWORLDPANNING); } bool isMasked() { - return mTexture->bMasked; + return mSource->isMasked(); + } + + uint16_t GetRotations() const + { + return mTexture->GetRotations(); } int GetSkyOffset() const { return mTexture->GetSkyOffset(); } - PalEntry GetSkyCapColor(bool bottom) const { return mTexture->GetSkyCapColor(bottom); } + PalEntry GetSkyCapColor(bool bottom) const { return mSource->GetSkyCapColor(bottom); } int GetWidth () { return mTexture->GetTexelWidth(); } int GetHeight () { return mTexture->GetTexelHeight(); } int GetWidthBits() { return WidthBits; } int GetHeightBits() { return HeightBits; } - int GetScaledWidth () { return mTexture->GetScaledWidth(); } - int GetScaledHeight () { return mTexture->GetScaledHeight(); } - double GetScaledWidthDouble () { return mTexture->GetScaledWidthDouble(); } - double GetScaledHeightDouble () { return mTexture->GetScaledHeightDouble(); } + int GetScaledWidth () { return mTexture->GetDisplayWidth(); } + int GetScaledHeight () { return mTexture->GetDisplayHeight(); } // Now with improved offset adjustment. - int GetLeftOffset(int adjusted) { return mTexture->GetLeftOffset(adjusted); } - int GetTopOffset(int adjusted) { return mTexture->GetTopOffset(adjusted); } - int GetScaledLeftOffset (int adjusted) { return mTexture->GetScaledLeftOffset(adjusted); } - int GetScaledTopOffset (int adjusted) { return mTexture->GetScaledTopOffset(adjusted); } + int GetLeftOffset(int adjusted) { return mTexture->GetTexelLeftOffset(adjusted); } + int GetTopOffset(int adjusted) { return mTexture->GetTexelTopOffset(adjusted); } // Interfaces for the different renderers. Everything that needs to check renderer-dependent offsets // should use these, so that if changes are needed, this is the only place to edit. @@ -80,16 +82,10 @@ public: // For the original software renderer int GetLeftOffsetSW() { return GetLeftOffset(r_spriteadjustSW); } int GetTopOffsetSW() { return GetTopOffset(r_spriteadjustSW); } - int GetScaledLeftOffsetSW() { return GetScaledLeftOffset(r_spriteadjustSW); } - int GetScaledTopOffsetSW() { return GetScaledTopOffset(r_spriteadjustSW); } + double GetScaledLeftOffsetSW() { return mTexture->GetDisplayLeftOffset(r_spriteadjustSW); } + double GetScaledTopOffsetSW() { return mTexture->GetDisplayTopOffset(r_spriteadjustSW); } - // For the softpoly renderer, in case it wants adjustment - int GetLeftOffsetPo() { return GetLeftOffset(r_spriteadjustSW); } - int GetTopOffsetPo() { return GetTopOffset(r_spriteadjustSW); } - int GetScaledLeftOffsetPo() { return GetScaledLeftOffset(r_spriteadjustSW); } - int GetScaledTopOffsetPo() { return GetScaledTopOffset(r_spriteadjustSW); } - - DVector2 GetScale() const { return mTexture->Scale; } + DVector2 GetScale() const { return Scale; } int GetPhysicalWidth() { return mPhysicalWidth; } int GetPhysicalHeight() { return mPhysicalHeight; } int GetPhysicalScale() const { return mPhysicalScale; } @@ -157,7 +153,7 @@ class FWarpTexture : public FSoftwareTexture int WidthOffsetMultiplier, HeightOffsetMultiplier; // [mxd] public: - FWarpTexture (FTexture *source, int warptype); + FWarpTexture (FGameTexture *source, int warptype); const uint32_t *GetPixelsBgra() override; const uint8_t *GetPixels(int style) override; @@ -180,7 +176,7 @@ class FSWCanvasTexture : public FSoftwareTexture public: - FSWCanvasTexture(FTexture *source) : FSoftwareTexture(source) {} + FSWCanvasTexture(FGameTexture *source) : FSoftwareTexture(source) {} ~FSWCanvasTexture(); // Returns the whole texture, stored in column-major order @@ -195,3 +191,6 @@ public: bool Mipmapped() override { return false; } }; + +FSoftwareTexture* GetSoftwareTexture(FGameTexture* tex); +FSoftwareTexture* GetPalettedSWTexture(FTextureID texid, bool animate, FLevelLocals *checkcompat = nullptr, bool allownull = false); diff --git a/src/rendering/swrenderer/textures/swcanvastexture.cpp b/src/rendering/swrenderer/textures/swcanvastexture.cpp index c3d12e33e..a9a946fce 100644 --- a/src/rendering/swrenderer/textures/swcanvastexture.cpp +++ b/src/rendering/swrenderer/textures/swcanvastexture.cpp @@ -64,7 +64,7 @@ FSWCanvasTexture::~FSWCanvasTexture() const uint8_t *FSWCanvasTexture::GetPixels(int style) { - static_cast(mTexture)->NeedUpdate(); + static_cast(mSource)->NeedUpdate(); if (Canvas == nullptr) { MakeTexture(); @@ -81,7 +81,7 @@ const uint8_t *FSWCanvasTexture::GetPixels(int style) const uint32_t *FSWCanvasTexture::GetPixelsBgra() { - static_cast(mTexture)->NeedUpdate(); + static_cast(mSource)->NeedUpdate(); if (CanvasBgra == nullptr) { MakeTextureBgra(); @@ -181,5 +181,5 @@ void FSWCanvasTexture::UpdatePixels(bool truecolor) ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Canvas->GetPixels(), GetWidth(), GetHeight(), Canvas->GetPitch(), GPalette.Remap); } - static_cast(mTexture)->SetUpdated(false); + static_cast(mSource)->SetUpdated(false); } \ No newline at end of file diff --git a/src/rendering/swrenderer/textures/warptexture.cpp b/src/rendering/swrenderer/textures/warptexture.cpp index 23a15529a..49869f8d6 100644 --- a/src/rendering/swrenderer/textures/warptexture.cpp +++ b/src/rendering/swrenderer/textures/warptexture.cpp @@ -44,7 +44,7 @@ EXTERN_CVAR(Int, gl_texture_hqresizemult) EXTERN_CVAR(Int, gl_texture_hqresizemode) EXTERN_CVAR(Int, gl_texture_hqresize_targets) -FWarpTexture::FWarpTexture (FTexture *source, int warptype) +FWarpTexture::FWarpTexture (FGameTexture *source, int warptype) : FSoftwareTexture (source) { if (warptype == 2) SetupMultipliers(256, 128); @@ -69,7 +69,7 @@ const uint32_t *FWarpTexture::GetPixelsBgra() auto otherpix = FSoftwareTexture::GetPixelsBgra(); WarpedPixelsRgba.Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult * 4 / 3 + 1)); - WarpBuffer(WarpedPixelsRgba.Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped); + WarpBuffer(WarpedPixelsRgba.Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->GetShaderSpeed(), bWarped); GenerateBgraMipmapsFast(); FreeAllSpans(); GenTime[2] = time; @@ -90,7 +90,7 @@ const uint8_t *FWarpTexture::GetPixels(int index) const uint8_t *otherpix = FSoftwareTexture::GetPixels(index); WarpedPixels[index].Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult)); - WarpBuffer(WarpedPixels[index].Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped); + WarpBuffer(WarpedPixels[index].Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->GetShaderSpeed(), bWarped); FreeAllSpans(); GenTime[index] = time; } diff --git a/src/rendering/swrenderer/things/r_decal.cpp b/src/rendering/swrenderer/things/r_decal.cpp index 7ede9a574..fcc3055f4 100644 --- a/src/rendering/swrenderer/things/r_decal.cpp +++ b/src/rendering/swrenderer/things/r_decal.cpp @@ -123,13 +123,11 @@ namespace swrenderer } } - FTexture *tex = TexMan.GetPalettedTexture(decal->PicNum, true); - - if (tex == NULL || !tex->isValid()) + FSoftwareTexture *WallSpriteTile = GetPalettedSWTexture(decal->PicNum, true); + if (WallSpriteTile == NULL) { return; } - FSoftwareTexture *WallSpriteTile = tex->GetSoftwareTexture(); // Determine left and right edges of sprite. Since this sprite is bound // to a wall, we use the wall's angle instead of the decal's. This is diff --git a/src/rendering/swrenderer/things/r_playersprite.cpp b/src/rendering/swrenderer/things/r_playersprite.cpp index d4459c880..d59f0a64c 100644 --- a/src/rendering/swrenderer/things/r_playersprite.cpp +++ b/src/rendering/swrenderer/things/r_playersprite.cpp @@ -208,7 +208,7 @@ namespace swrenderer spriteframe_t* sprframe; FTextureID picnum; uint16_t flip; - FTexture* tex; + FGameTexture* tex; bool noaccel; double alpha = owner->Alpha; @@ -228,7 +228,7 @@ namespace swrenderer picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan.GetTexture(picnum); + tex = TexMan.GetGameTexture(picnum); if (!tex->isValid()) return; @@ -267,7 +267,7 @@ namespace swrenderer double pspriteyscale = pspritexscale * viewport->BaseYaspectMul * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio; double pspritexiscale = 1 / pspritexscale; - int tleft = tex->GetDisplayLeftOffset(); + int tleft = tex->GetDisplayLeftOffset(0); int twidth = tex->GetDisplayWidth(); // calculate edges of the shape @@ -290,7 +290,7 @@ namespace swrenderer vis.renderflags = owner->renderflags; - FSoftwareTexture *stex = tex->GetSoftwareTexture(); + FSoftwareTexture* stex = GetSoftwareTexture(tex); vis.texturemid = (BASEYCENTER - sy) * stex->GetScale().Y + stex->GetTopOffset(0); // Force it to use software rendering when drawing to a canvas texture. diff --git a/src/rendering/swrenderer/things/r_sprite.cpp b/src/rendering/swrenderer/things/r_sprite.cpp index 348cc1bf4..c0ebeae75 100644 --- a/src/rendering/swrenderer/things/r_sprite.cpp +++ b/src/rendering/swrenderer/things/r_sprite.cpp @@ -74,10 +74,8 @@ EXTERN_CVAR(Int, gl_texture_hqresize_targets) namespace swrenderer { - void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ttex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap) + void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap) { - FSoftwareTexture *tex = ttex->GetSoftwareTexture(); - auto viewport = thread->Viewport.get(); const double thingxscalemul = spriteScale.X / tex->GetScale().X; @@ -92,8 +90,8 @@ namespace swrenderer return; // [RH] Added scaling - int scaled_to = tex->GetScaledTopOffsetSW(); - int scaled_bo = scaled_to - tex->GetScaledHeight(); + double scaled_to = tex->GetScaledTopOffsetSW(); + double scaled_bo = scaled_to - tex->GetScaledHeight(); double gzt = pos.Z + spriteScale.Y * scaled_to; double gzb = pos.Z + spriteScale.Y * scaled_bo; diff --git a/src/rendering/swrenderer/things/r_sprite.h b/src/rendering/swrenderer/things/r_sprite.h index 0e7d97bcb..d41504fc8 100644 --- a/src/rendering/swrenderer/things/r_sprite.h +++ b/src/rendering/swrenderer/things/r_sprite.h @@ -7,7 +7,7 @@ namespace swrenderer class RenderSprite : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap); protected: void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override; diff --git a/src/rendering/swrenderer/things/r_wallsprite.cpp b/src/rendering/swrenderer/things/r_wallsprite.cpp index 4663f6f36..909c72395 100644 --- a/src/rendering/swrenderer/things/r_wallsprite.cpp +++ b/src/rendering/swrenderer/things/r_wallsprite.cpp @@ -69,9 +69,8 @@ namespace swrenderer { - void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ppic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap) + void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *pic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap) { - FSoftwareTexture *pic = ppic->GetSoftwareTexture(); FWallCoords wallc; double x1, x2; DVector2 left, right; diff --git a/src/rendering/swrenderer/things/r_wallsprite.h b/src/rendering/swrenderer/things/r_wallsprite.h index 2851ec2b5..b512ec960 100644 --- a/src/rendering/swrenderer/things/r_wallsprite.h +++ b/src/rendering/swrenderer/things/r_wallsprite.h @@ -10,7 +10,7 @@ namespace swrenderer class RenderWallSprite : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *pic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *pic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap); protected: bool IsWallSprite() const override { return true; }