diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 3ae8ba1c3..2163a08bb 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -783,6 +783,7 @@ set (PCH_SOURCES common/textures/bitmap.cpp common/textures/m_png.cpp common/textures/texture.cpp + common/textures/gametexture.cpp common/textures/image.cpp common/textures/imagetexture.cpp common/textures/texturemanager.cpp @@ -1018,6 +1019,7 @@ include_directories( common/textures common/textures/formats common/textures/hires + common/textures common/filesystem common/utility common/console diff --git a/source/build/include/build.h b/source/build/include/build.h index d1cf94582..2ed1521a4 100644 --- a/source/build/include/build.h +++ b/source/build/include/build.h @@ -856,7 +856,7 @@ void videoClearScreen(int32_t dacol); void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang); void rotatesprite_(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat, uint8_t daalpha, uint8_t dablend, - int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2, FTexture *pic = nullptr, int basepal = 0); + int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2, FGameTexture *pic = nullptr, int basepal = 0); void renderDrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint8_t col); void drawlinergb(int32_t x1, int32_t y1, int32_t x2, int32_t y2, palette_t p); void drawlinergb(int32_t x1, int32_t y1, int32_t x2, int32_t y2, PalEntry p); @@ -864,13 +864,13 @@ void drawlinergb(int32_t x1, int32_t y1, int32_t x2, int32_t y2, PalEntry p); ////////// specialized rotatesprite wrappers for (very) often used cases ////////// static FORCE_INLINE void rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat, - int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2, FTexture* pic = nullptr, int basepal = 0) + int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2, FGameTexture* pic = nullptr, int basepal = 0) { rotatesprite_(sx, sy, z, a, picnum, dashade, dapalnum, dastat, 0, 0, cx1, cy1, cx2, cy2, pic, basepal); } // Don't clip at all, i.e. the whole screen real estate is available: static FORCE_INLINE void rotatesprite_fs(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, - int8_t dashade, uint8_t dapalnum, int32_t dastat, FTexture* pic = nullptr, int basepal = 0) + int8_t dashade, uint8_t dapalnum, int32_t dastat, FGameTexture* pic = nullptr, int basepal = 0) { rotatesprite_(sx, sy, z, a, picnum, dashade, dapalnum, dastat, 0, 0, 0,0,xdim-1,ydim-1, pic, basepal); } diff --git a/source/build/include/mdsprite.h b/source/build/include/mdsprite.h index 40bd5a6ce..7b6c8e9e6 100644 --- a/source/build/include/mdsprite.h +++ b/source/build/include/mdsprite.h @@ -14,14 +14,14 @@ #define IDP2_MAGIC 0x32504449 #define IDP3_MAGIC 0x33504449 -class FTexture; +class FGameTexture; class FHardwareTexture; struct mdmodel_t { int32_t mdnum, shadeoff; float scale, bscale, zadd, yoffset; - FTexture *texture; + FGameTexture *texture; int32_t flags; }; @@ -200,7 +200,7 @@ struct voxmodel_t : public mdmodel_t EXTERN mdmodel_t **models; -FTexture* mdloadskin(idmodel_t* m, int32_t number, int32_t pal, int32_t surf, bool* exact); +FGameTexture* mdloadskin(idmodel_t* m, int32_t number, int32_t pal, int32_t surf, bool* exact); void mdinit(void); void freeallmodels(void); int32_t polymost_mddraw(tspriteptr_t tspr); diff --git a/source/build/src/animvpx.cpp b/source/build/src/animvpx.cpp index 4b25e4df4..077a0d051 100644 --- a/source/build/src/animvpx.cpp +++ b/source/build/src/animvpx.cpp @@ -50,7 +50,7 @@ void VPXTexture::SetFrame(const void *data_, int width, int height) Width = width; Height = height; data = data_; - SystemTextures.Clean(true, true); + SystemTextures.Clean(); } //=========================================================================== @@ -412,27 +412,27 @@ read_ivf_frame: /////////////// DRAWING! /////////////// static int sampler; -static VPXTexture* vpxtex[2]; +static FGameTexture* vpxtex[2]; static int which; void animvpx_setup_glstate(int32_t animvpx_flags) { ////////// GL STATE ////////// - vpxtex[0] = new VPXTexture; - vpxtex[1] = new VPXTexture; + vpxtex[0] = MakeGameTexture(new VPXTexture, nullptr, ETextureType::Special); + vpxtex[1] = MakeGameTexture(new VPXTexture, nullptr, ETextureType::Special); if ((animvpx_flags & CUTSCENE_TEXTUREFILTER && hw_texfilter == TEXFILTER_ON) || animvpx_flags & CUTSCENE_FORCEFILTER || - (!(animvpx_flags & CUTSCENE_TEXTUREFILTER) && !(animvpx_flags & CUTSCENE_FORCENOFILTER))) // if no flags, then use filter for IVFs + (!(animvpx_flags & CUTSCENE_TEXTUREFILTER) && !(animvpx_flags & CUTSCENE_FORCENOFILTER))) // if no flags, then use filter for IVFs { - sampler = SamplerClampXY; + sampler = CLAMP_XY; } else { - sampler = SamplerNoFilterClampXY; + sampler = CLAMP_XY; } - GLInterface.ClearScreen(0, true); + GLInterface.ClearScreen(0, true); } void animvpx_restore_glstate(void) @@ -454,7 +454,8 @@ int32_t animvpx_render_frame(animvpx_codec_ctx *codec, double animvpx_aspect) return 2; // shouldn't happen which ^= 1; - vpxtex[which]->SetFrame(codec->pic, codec->width, codec->height); + static_cast(vpxtex[which]->GetTexture())->SetFrame(codec->pic, codec->width, codec->height); + vpxtex[which]->CleanHardwareData(); float vid_wbyh = ((float)codec->width)/codec->height; if (animvpx_aspect > 0) diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index b367d0024..626208047 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -3083,7 +3083,7 @@ static int32_t dorotspr_handle_bit2(int32_t* sxptr, int32_t* syptr, int32_t* z, void twod_rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat, uint8_t daalpha, uint8_t dablend, - int32_t clipx1, int32_t clipy1, int32_t clipx2, int32_t clipy2, FTexture* pic, int basepal) + int32_t clipx1, int32_t clipy1, int32_t clipx2, int32_t clipy2, FGameTexture* pic, int basepal) { F2DDrawer::RenderCommand dg = {}; int method = 0; @@ -3122,7 +3122,7 @@ void twod_rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t pic int light = clamp(scale((numshades - dashade), 255, numshades), 0, 255); auto p = PalEntry((uint8_t)(alpha * 255), light, light, light); - vec2_t const siz = { dg.mTexture->GetDisplayWidth(), dg.mTexture->GetDisplayHeight() }; + vec2_t const siz = { (int)dg.mTexture->GetDisplayWidth(), (int)dg.mTexture->GetDisplayHeight() }; vec2_16_t ofs = { 0, 0 }; if (!(dastat & RS_TOPLEFT)) @@ -5327,7 +5327,7 @@ void renderSetAspect(int32_t daxrange, int32_t daaspect) // void rotatesprite_(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat, uint8_t daalpha, uint8_t dablend, - int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2, FTexture *tex, int basepal) + int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2, FGameTexture *tex, int basepal) { if (!tex && (unsigned)picnum >= MAXTILES) return; diff --git a/source/build/src/mdsprite.cpp b/source/build/src/mdsprite.cpp index cd483d7d9..ed252b86a 100644 --- a/source/build/src/mdsprite.cpp +++ b/source/build/src/mdsprite.cpp @@ -463,7 +463,7 @@ int32_t md_undefinemodel(int32_t modelid) //Note: even though it says md2model, it works for both md2model&md3model -FTexture *mdloadskin(idmodel_t *m, int32_t number, int32_t pal, int32_t surf, bool *exact) +FGameTexture *mdloadskin(idmodel_t *m, int32_t number, int32_t pal, int32_t surf, bool *exact) { int32_t i; mdskinmap_t *sk, *skzero = NULL; @@ -482,7 +482,7 @@ FTexture *mdloadskin(idmodel_t *m, int32_t number, int32_t pal, int32_t surf, bo { if (exact) *exact = true; //Printf("Using exact match skin (pal=%d,skinnum=%d,surfnum=%d) %s\n",pal,number,surf,skinfile); - return TexMan.GetTexture(sk->texture); + return TexMan.GetGameTexture(sk->texture); } //If no match, give highest priority to number, then pal.. (Parkar's request, 02/27/2005) else if ((sk->palette == 0) && (sk->skinnum == number) && (sk->surfnum == surf) && (i < 5)) { i = 5; skzero = sk; } @@ -501,7 +501,7 @@ FTexture *mdloadskin(idmodel_t *m, int32_t number, int32_t pal, int32_t surf, bo { //Printf("Using def skin 0,0 as fallback, pal=%d\n", pal); if (exact) *exact = false; - return TexMan.GetTexture(skzero->texture); + return TexMan.GetGameTexture(skzero->texture); } else return nullptr; @@ -1711,7 +1711,7 @@ static int32_t polymost_md3draw(md3model_t *m, tspriteptr_t tspr) if (!tex) continue; - FTexture *det = nullptr, *glow = nullptr; + FGameTexture *det = nullptr, *glow = nullptr; float detscale = 1.f; // The data lookup here is one incredible mess. Thanks to whoever cooked this up... :( diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp index 04aadeae1..c97ff5643 100644 --- a/source/build/src/polymost.cpp +++ b/source/build/src/polymost.cpp @@ -502,7 +502,7 @@ static void polymost_drawpoly(vec2f_t const * const dpxy, int32_t const n, int32 { float const r = 1.f / dd[i]; - if (tileGetTexture(globalpicnum)->isCanvas()) + if (tileGetTexture(globalpicnum)->GetTexture()->isHardwareCanvas()) { //update texcoords, canvas textures are upside down! vt->SetTexCoord( diff --git a/source/common/2d/v_2ddrawer.cpp b/source/common/2d/v_2ddrawer.cpp index 39398b800..704d2e1cf 100644 --- a/source/common/2d/v_2ddrawer.cpp +++ b/source/common/2d/v_2ddrawer.cpp @@ -234,7 +234,7 @@ void F2DDrawer::AddIndices(int firstvert, TArray &v) // //========================================================================== -bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor, RenderCommand &quad) +bool F2DDrawer::SetStyle(FGameTexture *tex, DrawParms &parms, PalEntry &vertexcolor, RenderCommand &quad) { FRenderStyle style = parms.style; float alpha; @@ -390,7 +390,7 @@ void F2DDrawer::SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcol // //========================================================================== -void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms) +void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms) { if (parms.style.BlendOp == STYLEOP_None) return; // not supposed to be drawn. @@ -472,7 +472,7 @@ void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms) // //========================================================================== -void F2DDrawer::AddShape( FTexture *img, DShape2D *shape, DrawParms &parms ) +void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms) { // [MK] bail out if vertex/coord array sizes are mismatched if ( shape->mVertices.Size() != shape->mCoords.Size() ) @@ -550,12 +550,11 @@ void F2DDrawer::AddShape( FTexture *img, DShape2D *shape, DrawParms &parms ) // //========================================================================== -void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, +void F2DDrawer::AddPoly(FGameTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double fadelevel, uint32_t *indices, size_t indexcount) { - RenderCommand poly; poly.mType = DrawTypeTriangles; @@ -630,7 +629,7 @@ void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, // //========================================================================== -void F2DDrawer::AddPoly(FTexture* img, FVector4* vt, size_t vtcount, unsigned int* ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2) +void F2DDrawer::AddPoly(FGameTexture* img, FVector4* vt, size_t vtcount, unsigned int* ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2) { RenderCommand dg = {}; int method = 0; @@ -677,7 +676,7 @@ void F2DDrawer::AddPoly(FTexture* img, FVector4* vt, size_t vtcount, unsigned in // //========================================================================== -void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) +void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, bool local_origin) { float fU1, fU2, fV1, fV2; @@ -693,17 +692,17 @@ void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture * // scaling is not used here. if (!local_origin) { - fU1 = float(left) / src->GetDisplayWidth(); - fV1 = float(top) / src->GetDisplayHeight(); - fU2 = float(right) / src->GetDisplayWidth(); - fV2 = float(bottom) / src->GetDisplayHeight(); + fU1 = float(left) / (float)src->GetDisplayWidth(); + fV1 = float(top) / (float)src->GetDisplayHeight(); + fU2 = float(right) / (float)src->GetDisplayWidth(); + fV2 = float(bottom) / (float)src->GetDisplayHeight(); } else { fU1 = 0; fV1 = 0; - fU2 = float(right - left) / src->GetDisplayWidth(); - fV2 = float(bottom - top) / src->GetDisplayHeight(); + fU2 = float(right - left) / (float)src->GetDisplayWidth(); + fV2 = float(bottom - top) / (float)src->GetDisplayHeight(); } dg.mVertIndex = (int)mVertices.Reserve(4); auto ptr = &mVertices[dg.mVertIndex]; @@ -755,7 +754,7 @@ void F2DDrawer::ClearScreen(PalEntry color) // //========================================================================== -void F2DDrawer::AddLine(float x1, float y1, float x2, float y2, int clipx1, int clipy1, int clipx2, int clipy2, uint32_t color, uint8_t alpha) +void F2DDrawer::AddLine(double x1, double y1, double x2, double y2, int clipx1, int clipy1, int clipx2, int clipy2, uint32_t color, uint8_t alpha) { PalEntry p = (PalEntry)color; p.a = alpha; diff --git a/source/common/2d/v_2ddrawer.h b/source/common/2d/v_2ddrawer.h index a7abb6c5b..7e410a11e 100644 --- a/source/common/2d/v_2ddrawer.h +++ b/source/common/2d/v_2ddrawer.h @@ -124,7 +124,7 @@ public: int mIndexIndex; int mIndexCount; - FTexture *mTexture; + FGameTexture *mTexture; int mTranslationId; PalEntry mSpecialColormap[2]; int mScissor[4]; @@ -170,19 +170,19 @@ public: void AddIndices(int firstvert, int count, ...); private: void AddIndices(int firstvert, TArray &v); - bool SetStyle(FTexture *tex, DrawParms &parms, PalEntry &color0, RenderCommand &quad); + bool SetStyle(FGameTexture *tex, DrawParms &parms, PalEntry &color0, RenderCommand &quad); void SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor); public: - void AddTexture(FTexture *img, DrawParms &parms); - void AddShape(FTexture *img, DShape2D *shape, DrawParms &parms); - void AddPoly(FTexture *texture, FVector2 *points, int npoints, + void AddTexture(FGameTexture* img, DrawParms& parms); + void AddShape(FGameTexture *img, DShape2D *shape, DrawParms &parms); + void AddPoly(FGameTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount); - void AddPoly(FTexture* img, FVector4 *vt, size_t vtcount, unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2); + void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2); void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int picnum, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex, int clipx1, int clipy1, int clipx2, int clipy2); - void AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin = false); + void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, bool local_origin = false); void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr); void ClearScreen(PalEntry color = 0xff000000); @@ -190,7 +190,7 @@ public: void AddClear(int left, int top, int right, int bottom, int palcolor, uint32_t color); - void AddLine(float x1, float y1, float x2, float y2, int cx, int cy, int cx2, int cy2, uint32_t color, uint8_t alpha = 255); + void AddLine(double x1, double y1, double x2, double y2, int cx, int cy, int cx2, int cy2, uint32_t color, uint8_t alpha = 255); void AddThickLine(int x1, int y1, int x2, int y2, double thickness, uint32_t color, uint8_t alpha = 255); void AddPixel(int x1, int y1, uint32_t color); diff --git a/source/common/2d/v_draw.cpp b/source/common/2d/v_draw.cpp index a70d47e5f..a85f1ac8a 100644 --- a/source/common/2d/v_draw.cpp +++ b/source/common/2d/v_draw.cpp @@ -180,7 +180,7 @@ int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; // //========================================================================== -void DrawTexture(F2DDrawer *drawer, FTexture* img, double x, double y, int tags_first, ...) +void DrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, ...) { Va_List tags; va_start(tags.list, tags_first); @@ -203,7 +203,7 @@ void DrawTexture(F2DDrawer *drawer, FTexture* img, double x, double y, int tags_ int ListGetInt(VMVa_List &tags); -static void DrawTexture(F2DDrawer *drawer, FTexture *img, double x, double y, VMVa_List &args) +static void DrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y, VMVa_List &args) { DrawParms parms; uint32_t tag = ListGetInt(args); @@ -224,7 +224,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - FTexture *tex = TexMan.ByIndex(texid, animate); + auto tex = TexMan.GameByIndex(texid, animate); VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 }; DrawTexture(twod, tex, x, y, args); return 0; @@ -236,7 +236,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) // //========================================================================== -void DrawShape(F2DDrawer *drawer, FTexture *img, DShape2D *shape, int tags_first, ...) +void DrawShape(F2DDrawer *drawer, FGameTexture *img, DShape2D *shape, int tags_first, ...) { Va_List tags; va_start(tags.list, tags_first); @@ -248,7 +248,7 @@ void DrawShape(F2DDrawer *drawer, FTexture *img, DShape2D *shape, int tags_first drawer->AddShape(img, shape, parms); } -void DrawShape(F2DDrawer *drawer, FTexture *img, DShape2D *shape, VMVa_List &args) +void DrawShape(F2DDrawer *drawer, FGameTexture *img, DShape2D *shape, VMVa_List &args) { DrawParms parms; uint32_t tag = ListGetInt(args); @@ -269,7 +269,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawShape) if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - FTexture *tex = TexMan.ByIndex(texid, animate); + auto tex = TexMan.GameByIndex(texid, animate); VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 }; DrawShape(twod, tex, shape, args); @@ -334,7 +334,7 @@ DEFINE_ACTION_FUNCTION(_Screen, GetClipRect) // //========================================================================== -bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FTexture *img, double xx, double yy) +bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, double xx, double yy) { auto GetWidth = [=]() { return drawer->GetWidth(); }; auto GetHeight = [=]() {return drawer->GetHeight(); }; @@ -342,8 +342,8 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FTexture *img, double { parms->x = xx; parms->y = yy; - parms->texwidth = img->GetDisplayWidthDouble(); - parms->texheight = img->GetDisplayHeightDouble(); + parms->texwidth = img->GetDisplayWidth(); + parms->texheight = img->GetDisplayHeight(); if (parms->top == INT_MAX || parms->fortext) { parms->top = img->GetDisplayTopOffset(); @@ -354,11 +354,11 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FTexture *img, double } if (parms->destwidth == INT_MAX || parms->fortext) { - parms->destwidth = img->GetDisplayWidthDouble(); + parms->destwidth = img->GetDisplayWidth(); } if (parms->destheight == INT_MAX || parms->fortext) { - parms->destheight = img->GetDisplayHeightDouble(); + parms->destheight = img->GetDisplayHeight(); } switch (parms->cleanmode) @@ -387,10 +387,12 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FTexture *img, double case DTA_FullscreenEx: { double aspect; - double srcwidth = img->GetDisplayWidthDouble(); - double srcheight = img->GetDisplayHeightDouble(); + double srcwidth = img->GetDisplayWidth(); + double srcheight = img->GetDisplayHeight(); int autoaspect = parms->fsscalemode; - aspect = autoaspect == 0 || (srcwidth == 320 && srcheight == 200) || (srcwidth == 640 && srcheight == 400)? 1.333 : srcwidth / srcheight; + if (srcheight == 200) aspect = srcwidth / 240.; + else if (srcheight == 400) aspect = srcwidth / 480; + else aspect = srcwidth / srcheight; parms->x = parms->y = 0; parms->keepratio = true; auto screenratio = ActiveRatio(GetWidth(), GetHeight()); @@ -531,7 +533,7 @@ static inline FSpecialColormap * ListGetSpecialColormap(VMVa_List &tags) //========================================================================== template -bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y, uint32_t tag, T& tags, DrawParms *parms, bool fortext) +bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double y, uint32_t tag, T& tags, DrawParms *parms, bool fortext) { INTBOOL boolval; int intval; @@ -724,8 +726,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y, if (img == NULL) return false; parms->cleanmode = DTA_Fullscreen; parms->fsscalemode = (uint8_t)twod->fullscreenautoaspect; - parms->virtWidth = img->GetDisplayWidthDouble(); - parms->virtHeight = img->GetDisplayHeightDouble(); + parms->virtWidth = img->GetDisplayWidth(); + parms->virtHeight = img->GetDisplayHeight(); } break; @@ -738,8 +740,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y, if (img == NULL) return false; parms->cleanmode = DTA_Fullscreen; parms->fsscalemode = (uint8_t)intval; - parms->virtWidth = img->GetDisplayWidthDouble(); - parms->virtHeight = img->GetDisplayHeightDouble(); + parms->virtWidth = img->GetDisplayWidth(); + parms->virtHeight = img->GetDisplayHeight(); } break; @@ -785,19 +787,19 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y, break; case DTA_SrcX: - parms->srcx = ListGetDouble(tags) / img->GetDisplayWidthDouble(); + parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth(); break; case DTA_SrcY: - parms->srcy = ListGetDouble(tags) / img->GetDisplayHeightDouble(); + parms->srcy = ListGetDouble(tags) / img->GetDisplayHeight(); break; case DTA_SrcWidth: - parms->srcwidth = ListGetDouble(tags) / img->GetDisplayWidthDouble(); + parms->srcwidth = ListGetDouble(tags) / img->GetDisplayWidth(); break; case DTA_SrcHeight: - parms->srcheight = ListGetDouble(tags) / img->GetDisplayHeightDouble(); + parms->srcheight = ListGetDouble(tags) / img->GetDisplayHeight(); break; case DTA_TopOffset: @@ -829,8 +831,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y, if (fortext) return false; if (ListGetInt(tags)) { - parms->left = img->GetDisplayWidthDouble() * 0.5; - parms->top = img->GetDisplayHeightDouble() * 0.5; + parms->left = img->GetDisplayWidth() * 0.5; + parms->top = img->GetDisplayHeight() * 0.5; } break; @@ -839,8 +841,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y, if (fortext) return false; if (ListGetInt(tags)) { - parms->left = img->GetDisplayWidthDouble() * 0.5; - parms->top = img->GetDisplayHeightDouble(); + parms->left = img->GetDisplayWidth() * 0.5; + parms->top = img->GetDisplayHeight(); } break; @@ -1038,8 +1040,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y, } // explicitly instantiate both versions for v_text.cpp. -template bool ParseDrawTextureTags(F2DDrawer* drawer, FTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext); -template bool ParseDrawTextureTags(F2DDrawer* drawer, FTexture *img, double x, double y, uint32_t tag, VMVa_List& tags, DrawParms *parms, bool fortext); +template bool ParseDrawTextureTags(F2DDrawer* drawer, FGameTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext); +template bool ParseDrawTextureTags(F2DDrawer* drawer, FGameTexture *img, double x, double y, uint32_t tag, VMVa_List& tags, DrawParms *parms, bool fortext); //========================================================================== // @@ -1131,7 +1133,7 @@ void VirtualToRealCoordsInt(F2DDrawer *drawer, int &x, int &y, int &w, int &h, // //========================================================================== -void FillBorder (F2DDrawer *drawer, FTexture *img) +void FillBorder (F2DDrawer *drawer, FGameTexture *img) { auto Width = drawer->GetWidth(); auto Height = drawer->GetHeight(); @@ -1351,7 +1353,7 @@ void DrawBorder (F2DDrawer *drawer, FTextureID picnum, int x1, int y1, int x2, i { if (picnum.isValid()) { - drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetTexture(picnum, false)); + drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetGameTexture(picnum, false)); } else { diff --git a/source/common/2d/v_draw.h b/source/common/2d/v_draw.h index a3e6b747c..e42b6f306 100644 --- a/source/common/2d/v_draw.h +++ b/source/common/2d/v_draw.h @@ -203,20 +203,21 @@ inline int active_con_scale(F2DDrawer *drawer) #endif template -bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture* img, double x, double y, uint32_t tag, T& tags, DrawParms* parms, bool fortext); +bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture* img, double x, double y, uint32_t tag, T& tags, DrawParms* parms, bool fortext); template void DrawTextCommon(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double y, const T* string, DrawParms& parms); -bool SetTextureParms(F2DDrawer *drawer, DrawParms* parms, FTexture* img, double x, double y); +bool SetTextureParms(F2DDrawer *drawer, DrawParms* parms, FGameTexture* img, double x, double y); void DrawText(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, const char* string, int tag_first, ...); void DrawText(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, const char32_t* string, int tag_first, ...); void DrawChar(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, int character, int tag_first, ...); -void DrawTexture(F2DDrawer* drawer, FTexture* img, double x, double y, int tags_first, ...); + +void DrawTexture(F2DDrawer* drawer, FGameTexture* img, double x, double y, int tags_first, ...); void DoDim(F2DDrawer* drawer, PalEntry color, float amount, int x1, int y1, int w, int h, FRenderStyle* style = nullptr); void Dim(F2DDrawer* drawer, PalEntry color, float damount, int x1, int y1, int w, int h, FRenderStyle* style = nullptr); -void FillBorder(F2DDrawer *drawer, FTexture* img); // Fills the border around a 4:3 part of the screen on non-4:3 displays +void FillBorder(F2DDrawer *drawer, FGameTexture* img); // Fills the border around a 4:3 part of the screen on non-4:3 displays void DrawFrame(F2DDrawer* drawer, int left, int top, int width, int height); void DrawBorder(F2DDrawer* drawer, FTextureID, int x1, int y1, int x2, int y2); diff --git a/source/common/2d/v_drawtext.cpp b/source/common/2d/v_drawtext.cpp index a475e9e9a..ac99e3178 100644 --- a/source/common/2d/v_drawtext.cpp +++ b/source/common/2d/v_drawtext.cpp @@ -53,7 +53,7 @@ int ListGetInt(VMVa_List &tags); // //========================================================================== #if 0 -FTexture * BuildTextTexture(FFont *font, const char *string, int textcolor) +FGameTexture * BuildTextTexture(FFont *font, const char *string, int textcolor) { int w; const uint8_t *ch; @@ -61,7 +61,7 @@ FTexture * BuildTextTexture(FFont *font, const char *string, int textcolor) int cy; int trans = -1; int kerning; - FTexture *pic; + FGameTexture *pic; kerning = font->GetDefaultKerning(); @@ -170,7 +170,7 @@ void DrawChar(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double if (normalcolor >= NumTextColors) normalcolor = CR_UNTRANSLATED; - FTexture* pic; + FGameTexture* pic; int dummy; bool redirected; @@ -200,7 +200,7 @@ void DrawChar(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double if (normalcolor >= NumTextColors) normalcolor = CR_UNTRANSLATED; - FTexture *pic; + FGameTexture *pic; int dummy; bool redirected; @@ -256,7 +256,7 @@ void DrawTextCommon(F2DDrawer *drawer, FFont *font, int normalcolor, double x, d int boldcolor; int trans = -1; int kerning; - FTexture *pic; + FGameTexture *pic; if (parms.celly == 0) parms.celly = font->GetHeight() + 1; parms.celly *= parms.scaley; diff --git a/source/common/engine/serializer.cpp b/source/common/engine/serializer.cpp index 9270e4629..c2ea80a47 100644 --- a/source/common/engine/serializer.cpp +++ b/source/common/engine/serializer.cpp @@ -1082,16 +1082,17 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe } FTextureID chk = value; if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull(); - FTexture *pic = TexMan.GetTexture(chk); + auto pic = TexMan.GetGameTexture(chk); const char *name; + auto lump = pic->GetSourceLump(); - if (fileSystem.GetLinkedTexture(pic->SourceLump) == pic) + if (fileSystem.GetLinkedTexture(lump) == pic) { - name = fileSystem.GetFileFullName(pic->SourceLump); + name = fileSystem.GetFileFullName(lump); } else { - name = pic->Name; + name = pic->GetName(); } arc.WriteKey(key); arc.w->StartArray(); diff --git a/source/common/filesystem/filesystem.cpp b/source/common/filesystem/filesystem.cpp index 2bced8429..12b1d197a 100644 --- a/source/common/filesystem/filesystem.cpp +++ b/source/common/filesystem/filesystem.cpp @@ -57,7 +57,7 @@ extern FILE* hashfile; struct FileSystem::LumpRecord { FResourceLump *lump; - FTexture* linkedTexture; + FGameTexture* linkedTexture; LumpShortName shortName; FString longName; int rfnum; @@ -725,7 +725,7 @@ int FileSystem::GetResource (int resid, const char *type, int filenum) const // //========================================================================== -void FileSystem::SetLinkedTexture(int lump, FTexture *tex) +void FileSystem::SetLinkedTexture(int lump, FGameTexture *tex) { if ((size_t)lump < NumEntries) { @@ -739,7 +739,7 @@ void FileSystem::SetLinkedTexture(int lump, FTexture *tex) // //========================================================================== -FTexture *FileSystem::GetLinkedTexture(int lump) +FGameTexture *FileSystem::GetLinkedTexture(int lump) { if ((size_t)lump < NumEntries) { diff --git a/source/common/filesystem/filesystem.h b/source/common/filesystem/filesystem.h index f71aefb85..a7c38683f 100644 --- a/source/common/filesystem/filesystem.h +++ b/source/common/filesystem/filesystem.h @@ -16,7 +16,7 @@ class FResourceFile; struct FResourceLump; -class FTexture; +class FGameTexture; union LumpShortName { @@ -38,7 +38,7 @@ public: ~FileData (); void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); } size_t GetSize () { return Block.Len(); } - FString GetString () { return Block; } + const FString &GetString () const { return Block; } private: FileData (const FString &source); @@ -124,8 +124,8 @@ public: inline int CheckNumForFullName (const FString &name, int wadfile) { return CheckNumForFullName(name.GetChars(), wadfile); } inline int GetNumForFullName (const FString &name) { return GetNumForFullName(name.GetChars()); } - void SetLinkedTexture(int lump, FTexture *tex); - FTexture *GetLinkedTexture(int lump); + void SetLinkedTexture(int lump, FGameTexture *tex); + FGameTexture *GetLinkedTexture(int lump); void ReadFile (int lump, void *dest); diff --git a/source/common/filesystem/resourcefile.h b/source/common/filesystem/resourcefile.h index 82ba8c7a5..4d90f3e2f 100644 --- a/source/common/filesystem/resourcefile.h +++ b/source/common/filesystem/resourcefile.h @@ -3,6 +3,8 @@ #ifndef __RESFILE_H #define __RESFILE_H +#include + #include "files.h" struct LumpFilterInfo @@ -17,7 +19,6 @@ struct LumpFilterInfo }; class FResourceFile; -class FTexture; // [RH] Namespaces from BOOM. // These are needed here in the low level part so that WAD files can be properly set up. diff --git a/source/common/fonts/font.cpp b/source/common/fonts/font.cpp index d45e7a157..985ba4981 100644 --- a/source/common/fonts/font.cpp +++ b/source/common/fonts/font.cpp @@ -73,7 +73,6 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla int i; FTextureID lump; char buffer[12]; - int maxyoffs; DVector2 Scale = { 1, 1 }; noTranslate = notranslate; @@ -91,9 +90,7 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla translateUntranslated = false; int FixedWidth = 0; - maxyoffs = 0; - - TMap charMap; + TMap charMap; int minchar = INT_MAX; int maxchar = INT_MIN; @@ -231,13 +228,13 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla Type = Multilump; if (position < minchar) minchar = position; if (position > maxchar) maxchar = position; - charMap.Insert(position, TexMan.GetTexture(lump)); + charMap.Insert(position, TexMan.GetGameTexture(lump)); } } } else { - FTexture *texs[256] = {}; + FGameTexture *texs[256] = {}; if (lcount > 256 - start) lcount = 256 - start; for (i = 0; i < lcount; i++) { @@ -247,8 +244,8 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla TexMan.ListTextures(buffer, array, true); for (auto entry : array) { - FTexture *tex = TexMan.GetTexture(entry, false); - if (tex && tex->GetSourceLump() >= 0 && fileSystem.GetFileContainer(tex->GetSourceLump()) <= fileSystem.GetMaxIwadNum() && tex->GetUseType() == ETextureType::MiscPatch) + auto tex = TexMan.GetGameTexture(entry, false); + if (tex && !tex->isUserContent() && tex->GetUseType() == ETextureType::MiscPatch) { texs[i] = tex; } @@ -292,8 +289,8 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla { if ((int)position < minchar) minchar = (int)position; if ((int)position > maxchar) maxchar = (int)position; - auto tex = TexMan.GetTexture(lump); - tex->SetScale(Scale); + auto tex = TexMan.GetGameTexture(lump); + tex->SetScale((float)Scale.X, (float)Scale.Y); charMap.Insert((int)position, tex); Type = Folder; } @@ -312,17 +309,13 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla auto lump = charMap.CheckKey(FirstChar + i); if (lump != nullptr) { - FTexture *pic = *lump; + auto pic = *lump; if (pic != nullptr) { - int height = pic->GetDisplayHeight(); - int yoffs = pic->GetDisplayTopOffset(); + double fheight = pic->GetDisplayHeight(); + double yoffs = pic->GetDisplayTopOffset(); - if (yoffs > maxyoffs) - { - maxyoffs = yoffs; - } - height += abs(yoffs); + int height = int(fheight + abs(yoffs) + 0.5); if (height > fontheight) { fontheight = height; @@ -333,24 +326,24 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla } } - Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); - Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); - Chars[i].OriginalPic->CopySize(pic); - TexMan.AddTexture(Chars[i].OriginalPic); + auto orig = pic->GetTexture(); + auto tex = MakeGameTexture(orig, nullptr, ETextureType::FontChar); + tex->CopySize(pic); + TexMan.AddGameTexture(tex); + Chars[i].OriginalPic = tex; if (!noTranslate) { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); + Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar1(orig->GetImage())), nullptr, ETextureType::FontChar); Chars[i].TranslatedPic->CopySize(pic); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].TranslatedPic); + TexMan.AddGameTexture(Chars[i].TranslatedPic); } else { - Chars[i].TranslatedPic = Chars[i].OriginalPic; + Chars[i].TranslatedPic = tex; } - Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); + Chars[i].XMove = (int)Chars[i].TranslatedPic->GetDisplayWidth(); } else { @@ -388,8 +381,8 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla void FFont::ReadSheetFont(TArray &folderdata, int width, int height, const DVector2 &Scale) { // all valid lumps must be named with a hex number that represents the Unicode character index for its first character, - TArray part(1, true); - TMap charMap; + TArray part(1, true); + TMap charMap; int minchar = INT_MAX; int maxchar = INT_MIN; for (auto &entry : folderdata) @@ -402,7 +395,7 @@ void FFont::ReadSheetFont(TArray &folderdata, int width, int height auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); if (lump.isValid()) { - auto tex = TexMan.GetTexture(lump); + auto tex = TexMan.GetGameTexture(lump); int numtex_x = tex->GetTexelWidth() / width; int numtex_y = tex->GetTexelHeight() / height; int maxinsheet = int(position) + numtex_x * numtex_y - 1; @@ -415,25 +408,16 @@ void FFont::ReadSheetFont(TArray &folderdata, int width, int height { part[0].OriginX = -width * x; part[0].OriginY = -height * y; - part[0].Image = tex->GetImage(); + part[0].TexImage = static_cast(tex->GetTexture()); FMultiPatchTexture *image = new FMultiPatchTexture(width, height, part, false, false); - FImageTexture *tex = new FImageTexture(image, ""); - tex->SetUseType(ETextureType::FontChar); - tex->bMultiPatch = true; - tex->Width = width; - tex->Height = height; - tex->_LeftOffset[0] = - tex->_LeftOffset[1] = - tex->_TopOffset[0] = - tex->_TopOffset[1] = 0; - tex->Scale = Scale; - tex->bMasked = true; - tex->bTranslucent = -1; - tex->bWorldPanning = true; - tex->bNoDecals = false; - tex->SourceLump = -1; // We do not really care. - TexMan.AddTexture(tex); - charMap.Insert(int(position) + x + y * numtex_x, tex); + FImageTexture *tex = new FImageTexture(image); + auto gtex = MakeGameTexture(tex, nullptr, ETextureType::FontChar); + gtex->SetWorldPanning(true); + gtex->SetOffsets(0, 0, 0); + gtex->SetOffsets(1, 0, 0); + gtex->SetScale((float)Scale.X, (float)Scale.Y); + TexMan.AddGameTexture(gtex); + charMap.Insert(int(position) + x + y * numtex_x, gtex); } } } @@ -458,18 +442,18 @@ void FFont::ReadSheetFont(TArray &folderdata, int width, int height auto lump = charMap.CheckKey(FirstChar + i); if (lump != nullptr) { - FTexture *pic = *lump; + auto pic = (*lump)->GetTexture(); auto b = pic->Get8BitPixels(false); - Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); + Chars[i].OriginalPic = MakeGameTexture(pic, nullptr, ETextureType::FontChar); Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); - Chars[i].OriginalPic->CopySize(pic); - Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); - Chars[i].TranslatedPic->CopySize(pic); + Chars[i].OriginalPic->CopySize(*lump); + Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar1(pic->GetImage())), nullptr, ETextureType::FontChar); + Chars[i].TranslatedPic->CopySize(*lump); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].OriginalPic); - TexMan.AddTexture(Chars[i].TranslatedPic); + TexMan.AddGameTexture(Chars[i].OriginalPic); + TexMan.AddGameTexture(Chars[i].TranslatedPic); } Chars[i].XMove = width; } @@ -619,7 +603,7 @@ void FFont::RecordAllTextureColors(uint32_t *usedcolors) { if (Chars[i].TranslatedPic) { - FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetTexture()->GetImage()); if (pic) { // The remap must be temporarily reset here because this can be called on an initialized font. @@ -982,7 +966,7 @@ int FFont::GetCharCode(int code, bool needpic) const // //========================================================================== -FTexture *FFont::GetChar (int code, int translation, int *const width, bool *redirected) const +FGameTexture *FFont::GetChar (int code, int translation, int *const width, bool *redirected) const { code = GetCharCode(code, true); int xmove = SpaceWidth; @@ -1037,11 +1021,11 @@ int FFont::GetCharWidth (int code) const double GetBottomAlignOffset(FFont *font, int c) { int w; - FTexture *tex_zero = font->GetChar('0', CR_UNDEFINED, &w); - FTexture *texc = font->GetChar(c, CR_UNDEFINED, &w); + auto tex_zero = font->GetChar('0', CR_UNDEFINED, &w); + auto texc = font->GetChar(c, CR_UNDEFINED, &w); double offset = 0; - if (texc) offset += texc->GetDisplayTopOffsetDouble(); - if (tex_zero) offset += -tex_zero->GetDisplayTopOffsetDouble() + tex_zero->GetDisplayHeightDouble(); + if (texc) offset += texc->GetDisplayTopOffset(); + if (tex_zero) offset += -tex_zero->GetDisplayTopOffset() + tex_zero->GetDisplayHeight(); return offset; } @@ -1093,7 +1077,7 @@ bool FFont::CanPrint(const uint8_t *string) const // //========================================================================== -int FFont::StringWidth(const uint8_t *string) const +int FFont::StringWidth(const uint8_t *string, int spacing) const { int w = 0; int maxw = 0; @@ -1123,13 +1107,17 @@ int FFont::StringWidth(const uint8_t *string) const maxw = w; w = 0; } + else if (spacing >= 0) + { + w += GetCharWidth(chr) + GlobalKerning + spacing; + } else { - w += GetCharWidth(chr) + GlobalKerning; + w -= spacing; } } - return MAX(maxw, w); + return std::max(maxw, w); } //========================================================================== @@ -1196,7 +1184,7 @@ void FFont::LoadTranslations() { if (Chars[i].TranslatedPic) { - FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetTexture()->GetImage()); if (pic) { pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture @@ -1210,7 +1198,7 @@ void FFont::LoadTranslations() for (unsigned int i = 0; i < count; i++) { if(Chars[i].TranslatedPic) - static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); + static_cast(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap); } BuildTranslations (Luminosity.Data(), identity, &TranslationParms[TranslationType][0], ActiveColors, nullptr); @@ -1286,7 +1274,7 @@ void FFont::FixXMoves() } if (Chars[i].OriginalPic) { - int ofs = Chars[i].OriginalPic->GetDisplayTopOffset(); + int ofs = (int)Chars[i].OriginalPic->GetDisplayTopOffset(); if (ofs > Displacement) Displacement = ofs; } } diff --git a/source/common/fonts/hexfont.cpp b/source/common/fonts/hexfont.cpp index 1b3bca2e4..812973bba 100644 --- a/source/common/fonts/hexfont.cpp +++ b/source/common/fonts/hexfont.cpp @@ -289,10 +289,9 @@ public: { auto offset = hexdata.glyphmap[i]; int size = hexdata.glyphdata[offset] / 16; - Chars[i - FirstChar].TranslatedPic = new FImageTexture(new FHexFontChar (&hexdata.glyphdata[offset+1], size, size * 9, 16)); - Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar); + Chars[i - FirstChar].TranslatedPic = MakeGameTexture(new FImageTexture(new FHexFontChar (&hexdata.glyphdata[offset+1], size, size * 9, 16)), nullptr, ETextureType::FontChar); Chars[i - FirstChar].XMove = size * spacing; - TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic); + TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic); } else Chars[i - FirstChar].XMove = spacing; @@ -362,10 +361,9 @@ public: { auto offset = hexdata.glyphmap[i]; int size = hexdata.glyphdata[offset] / 16; - Chars[i - FirstChar].TranslatedPic = new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)); - Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar); + Chars[i - FirstChar].TranslatedPic = MakeGameTexture(new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)), nullptr, ETextureType::FontChar); Chars[i - FirstChar].XMove = size * spacing; - TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic); + TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic); } else Chars[i - FirstChar].XMove = spacing; diff --git a/source/common/fonts/singlelumpfont.cpp b/source/common/fonts/singlelumpfont.cpp index 4b4fc3d9a..ed69aea80 100644 --- a/source/common/fonts/singlelumpfont.cpp +++ b/source/common/fonts/singlelumpfont.cpp @@ -167,10 +167,10 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump) void FSingleLumpFont::CreateFontFromPic (FTextureID picnum) { - FTexture *pic = TexMan.GetTexture(picnum); + auto pic = TexMan.GetGameTexture(picnum); - FontHeight = pic->GetDisplayHeight (); - SpaceWidth = pic->GetDisplayWidth (); + FontHeight = (int)pic->GetDisplayHeight (); + SpaceWidth = (int)pic->GetDisplayWidth (); GlobalKerning = 0; FirstChar = LastChar = 'A'; @@ -222,7 +222,7 @@ void FSingleLumpFont::LoadTranslations() for(unsigned int i = 0;i < count;++i) { if(Chars[i].TranslatedPic) - static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); + static_cast(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap); } BuildTranslations (luminosity, useidentity ? identity : nullptr, ranges, ActiveColors, usepalette ? local_palette : nullptr); @@ -353,9 +353,8 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) } else { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].TranslatedPic); + Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)), nullptr, ETextureType::FontChar); + TexMan.AddGameTexture(Chars[i].TranslatedPic); do { int8_t code = *data_p++; @@ -483,15 +482,14 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) { // Empty character: skip it. continue; } - auto tex = new FImageTexture(new FFontChar2(lump, int(chardata + chari + 6 - data), + auto tex = MakeGameTexture(new FImageTexture(new FFontChar2(lump, int(chardata + chari + 6 - data), chardata[chari+1], // width chardata[chari+2], // height -(int8_t)chardata[chari+3], // x offset -(int8_t)chardata[chari+4] // y offset - )); - tex->SetUseType(ETextureType::FontChar); + )), nullptr, ETextureType::FontChar); Chars[chardata[chari] - FirstChar].TranslatedPic = tex; - TexMan.AddTexture(tex); + TexMan.AddGameTexture(tex); } // If the font did not define a space character, determine a suitable space width now. @@ -556,10 +554,9 @@ void FSingleLumpFont::CheckFON1Chars (double *luminosity) if(!Chars[i].TranslatedPic) { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); + Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)), nullptr, ETextureType::FontChar); Chars[i].XMove = SpaceWidth; - TexMan.AddTexture(Chars[i].TranslatedPic); + TexMan.AddGameTexture(Chars[i].TranslatedPic); } // Advance to next char's data and count the used colors. diff --git a/source/common/fonts/singlepicfont.cpp b/source/common/fonts/singlepicfont.cpp index 8d289944d..46a723bd1 100644 --- a/source/common/fonts/singlepicfont.cpp +++ b/source/common/fonts/singlepicfont.cpp @@ -45,7 +45,7 @@ public: FSinglePicFont(const char *picname); // FFont interface - FTexture *GetChar(int code, int translation, int *const width, bool *redirected = nullptr) const override; + FGameTexture *GetChar(int code, int translation, int *const width, bool *redirected = nullptr) const override; int GetCharWidth (int code) const; protected: @@ -72,11 +72,11 @@ FSinglePicFont::FSinglePicFont(const char *picname) : I_FatalError ("%s is not a font or texture", picname); } - FTexture *pic = TexMan.GetTexture(picnum); + auto pic = TexMan.GetGameTexture(picnum); FontName = picname; - FontHeight = pic->GetDisplayHeight(); - SpaceWidth = pic->GetDisplayWidth(); + FontHeight = (int)pic->GetDisplayHeight(); + SpaceWidth = (int)pic->GetDisplayWidth(); GlobalKerning = 0; FirstChar = LastChar = 'A'; ActiveColors = 0; @@ -94,13 +94,13 @@ FSinglePicFont::FSinglePicFont(const char *picname) : // //========================================================================== -FTexture *FSinglePicFont::GetChar (int code, int translation, int *const width, bool *redirected) const +FGameTexture *FSinglePicFont::GetChar (int code, int translation, int *const width, bool *redirected) const { *width = SpaceWidth; if (redirected) *redirected = false; if (code == 'a' || code == 'A') { - return TexMan.GetPalettedTexture(PicNum, true); + return TexMan.GetGameTexture(PicNum, true); } else { diff --git a/source/common/fonts/specialfont.cpp b/source/common/fonts/specialfont.cpp index 519ccf8dd..6bd544c9e 100644 --- a/source/common/fonts/specialfont.cpp +++ b/source/common/fonts/specialfont.cpp @@ -45,7 +45,7 @@ class FSpecialFont : public FFont { public: - FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); + FSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); void LoadTranslations(); @@ -60,13 +60,13 @@ protected: // //========================================================================== -FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) +FSpecialFont::FSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) : FFont(lump) { int i; - TArray charlumps(count, true); + TArray charlumps(count, true); int maxyoffs; - FTexture *pic; + FGameTexture *pic; memcpy(this->notranslate, notranslate, 256*sizeof(bool)); @@ -87,8 +87,8 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l pic = charlumps[i] = lumplist[i]; if (pic != nullptr) { - int height = pic->GetDisplayHeight(); - int yoffs = pic->GetDisplayTopOffset(); + int height = (int)pic->GetDisplayHeight(); + int yoffs = (int)pic->GetDisplayTopOffset(); if (yoffs > maxyoffs) { @@ -104,20 +104,18 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l if (charlumps[i] != nullptr) { auto pic = charlumps[i]; - Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); - Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); + Chars[i].OriginalPic = MakeGameTexture(pic->GetTexture(), nullptr, ETextureType::FontChar); Chars[i].OriginalPic->CopySize(pic); - TexMan.AddTexture(Chars[i].OriginalPic); + TexMan.AddGameTexture(Chars[i].OriginalPic); if (!noTranslate) { - Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (charlumps[i]->GetImage()), ""); + Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar1 (charlumps[i]->GetTexture()->GetImage())), nullptr, ETextureType::FontChar); Chars[i].TranslatedPic->CopySize(charlumps[i]); - Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); - TexMan.AddTexture(Chars[i].TranslatedPic); + TexMan.AddGameTexture(Chars[i].TranslatedPic); } else Chars[i].TranslatedPic = Chars[i].OriginalPic; - Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); + Chars[i].XMove = (int)Chars[i].TranslatedPic->GetDisplayWidth(); } else { @@ -167,7 +165,7 @@ void FSpecialFont::LoadTranslations() { if (Chars[i].TranslatedPic) { - FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetTexture()->GetImage()); if (pic) { pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture @@ -197,7 +195,7 @@ void FSpecialFont::LoadTranslations() for (i = 0; i < count; i++) { if(Chars[i].TranslatedPic) - static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); + static_cast(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap); } BuildTranslations(Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr, [=](FRemapTable* remap) @@ -217,7 +215,7 @@ void FSpecialFont::LoadTranslations() ActiveColors = TotalColors; } -FFont *CreateSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) +FFont *CreateSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) { return new FSpecialFont(name, first, count, lumplist, notranslate, lump, donttranslate); } diff --git a/source/common/fonts/v_font.cpp b/source/common/fonts/v_font.cpp index 8fe004f7f..4057bc878 100644 --- a/source/common/fonts/v_font.cpp +++ b/source/common/fonts/v_font.cpp @@ -144,7 +144,7 @@ FFont *V_GetFont(const char *name, const char *fontlumpname) FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any); if (picnum.isValid()) { - FTexture *tex = TexMan.GetTexture(picnum); + auto tex = TexMan.GetGameTexture(picnum); if (tex && tex->GetSourceLump() >= folderfile) { FFont *CreateSinglePicFont(const char *name); @@ -170,7 +170,7 @@ FFont *V_GetFont(const char *name, const char *fontlumpname) void V_InitCustomFonts() { FScanner sc; - FTexture *lumplist[256]; + FGameTexture *lumplist[256]; bool notranslate[256]; bool donttranslate; FString namebuffer, templatebuf; @@ -266,12 +266,12 @@ void V_InitCustomFonts() else { if (format == 1) goto wrong; - FTexture **p = &lumplist[*(unsigned char*)sc.String]; + FGameTexture **p = &lumplist[*(unsigned char*)sc.String]; sc.MustGetString(); FTextureID texid = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); if (texid.Exists()) { - *p = TexMan.GetTexture(texid); + *p = TexMan.GetGameTexture(texid); } else if (fileSystem.GetFileContainer(sc.LumpNum) >= fileSystem.GetIwadNum()) { @@ -307,7 +307,7 @@ void V_InitCustomFonts() } if (count > 0) { - FFont *CreateSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); + FFont *CreateSpecialFont (const char *name, int first, int count, FGameTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); FFont *fnt = CreateSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump, donttranslate); fnt->SetCursor(cursor); fnt->SetKerning(kerning); diff --git a/source/common/fonts/v_font.h b/source/common/fonts/v_font.h index 41fabb096..4e78da08f 100644 --- a/source/common/fonts/v_font.h +++ b/source/common/fonts/v_font.h @@ -39,7 +39,7 @@ #include "name.h" class DCanvas; -class FTexture; +class FGameTexture; struct FRemapTable; enum EColorRange : int @@ -77,7 +77,7 @@ enum EColorRange : int extern int NumTextColors; -using GlyphSet = TMap; +using GlyphSet = TMap; class FFont { @@ -97,7 +97,7 @@ public: FFont (const char *fontname, const char *nametemplate, const char *filetemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false, bool iwadonly = false, bool doomtemplate = false, GlyphSet *baseGlpyphs = nullptr); virtual ~FFont (); - virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; + virtual FGameTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; virtual int GetCharWidth (int code) const; int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; int GetLump() const { return Lump; } @@ -113,9 +113,9 @@ public: static FFont *FindFont(FName fontname); // Return width of string in pixels (unscaled) - int StringWidth (const uint8_t *str) const; - inline int StringWidth (const char *str) const { return StringWidth ((const uint8_t *)str); } - inline int StringWidth (const FString &str) const { return StringWidth ((const uint8_t *)str.GetChars()); } + int StringWidth (const uint8_t *str, int spacing = 0) const; + inline int StringWidth (const char *str, int spacing = 0) const { return StringWidth ((const uint8_t *)str, spacing); } + inline int StringWidth (const FString &str, int spacing = 0) const { return StringWidth ((const uint8_t *)str.GetChars(), spacing); } // Checks if the font contains all characters to print this text. bool CanPrint(const uint8_t *str) const; @@ -161,8 +161,8 @@ protected: bool forceremap = false; struct CharData { - FTexture *TranslatedPic = nullptr; // Texture for use with font translations. - FTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization. + FGameTexture *TranslatedPic = nullptr; // Texture for use with font translations. + FGameTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization. int XMove = INT_MIN; }; TArray Chars; diff --git a/source/common/scripting/jit/jit_move.cpp b/source/common/scripting/jit/jit_move.cpp index cf4e71944..53644568c 100644 --- a/source/common/scripting/jit/jit_move.cpp +++ b/source/common/scripting/jit/jit_move.cpp @@ -54,7 +54,7 @@ static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %0 static int CastS2So(FString *b) { return FSoundID(*b); } static void CastSo2S(FString* a, int b) { *a = soundEngine->GetSoundName(b); } static void CastSID2S(FString* a, unsigned int b) { VM_CastSpriteIDToString(a, b); } -static void CastTID2S(FString *a, int b) { auto tex = TexMan.GetTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); } +static void CastTID2S(FString *a, int b) { auto tex = TexMan.GetGameTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); } void JitCompiler::EmitCAST() { diff --git a/source/common/scripting/vm/vmexec.h b/source/common/scripting/vm/vmexec.h index 72e0d0199..d88945a44 100644 --- a/source/common/scripting/vm/vmexec.h +++ b/source/common/scripting/vm/vmexec.h @@ -1848,7 +1848,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c case CAST_TID2S: { ASSERTS(a); ASSERTD(b); - auto tex = TexMan.GetTexture(*(FTextureID*)&(reg.d[b])); + auto tex = TexMan.GetGameTexture(*(FTextureID*)&(reg.d[b])); reg.s[a] = tex == nullptr ? "(null)" : tex->GetName().GetChars(); break; } diff --git a/source/common/textures/animtexture.cpp b/source/common/textures/animtexture.cpp index 4dbf2d111..2d06eccab 100644 --- a/source/common/textures/animtexture.cpp +++ b/source/common/textures/animtexture.cpp @@ -43,14 +43,14 @@ void AnimTexture::SetFrameSize(int width, int height) { FTexture::SetSize(width, height); - Image.Resize(width*height); + Image.Resize(width * height); } -void AnimTexture::SetFrame(const uint8_t *palette, const void *data_) +void AnimTexture::SetFrame(const uint8_t* palette, const void* data_) { - memcpy(Palette, palette, 768); - memcpy(Image.Data(), data_, Width * Height); - SystemTextures.Clean(true, true); + memcpy(Palette, palette, 768); + memcpy(Image.Data(), data_, Width * Height); + CleanHardwareTextures(); } //=========================================================================== @@ -70,10 +70,10 @@ FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans) for (int i = 0; i < Width * Height; i++) { int p = i * 4; - int index = spix[i]; - dpix[p + 0] = Palette[index*3+2]; - dpix[p + 1] = Palette[index*3+1]; - dpix[p + 2] = Palette[index*3]; + int index = spix[i]; + dpix[p + 0] = Palette[index * 3 + 2]; + dpix[p + 1] = Palette[index * 3 + 1]; + dpix[p + 2] = Palette[index * 3]; dpix[p + 3] = 255; } return bmp; @@ -87,30 +87,32 @@ FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans) AnimTextures::AnimTextures() { - active = 1; - tex[0] = new AnimTexture; - tex[1] = new AnimTexture; + active = 1; + tex[0] = MakeGameTexture(new AnimTexture, "", ETextureType::Special); + tex[1] = MakeGameTexture(new AnimTexture, "", ETextureType::Special); } AnimTextures::~AnimTextures() { - delete tex[0]; - delete tex[1]; + delete tex[0]; + delete tex[1]; } void AnimTextures::SetSize(int width, int height) { - tex[0]->SetFrameSize(width, height); - tex[1]->SetFrameSize(width, height); -} - -void AnimTextures::SetFrame(const uint8_t *palette, const void* data) -{ - active ^= 1; - tex[active]->SetFrame(palette, data); + static_cast(tex[0]->GetTexture())->SetFrameSize(width, height); + static_cast(tex[1]->GetTexture())->SetFrameSize(width, height); + tex[0]->SetSize(width, height); + tex[1]->SetSize(width, height); } -FTexture * AnimTextures::GetFrame() +void AnimTextures::SetFrame(const uint8_t* palette, const void* data) { - return tex[active]; + active ^= 1; + static_cast(tex[active]->GetTexture())->SetFrame(palette, data); +} + +FGameTexture* AnimTextures::GetFrame() +{ + return tex[active]; } diff --git a/source/common/textures/animtexture.h b/source/common/textures/animtexture.h index 668671a9d..2515253a7 100644 --- a/source/common/textures/animtexture.h +++ b/source/common/textures/animtexture.h @@ -8,21 +8,21 @@ class AnimTexture : public FTexture uint8_t Palette[768]; TArray Image; public: - AnimTexture() = default; + AnimTexture() = default; void SetFrameSize(int width, int height); - void SetFrame(const uint8_t *palette, const void* data); - virtual FBitmap GetBgraBitmap(const PalEntry* remap, int* trans) override; + void SetFrame(const uint8_t* palette, const void* data); + virtual FBitmap GetBgraBitmap(const PalEntry* remap, int* trans) override; }; class AnimTextures { int active; - AnimTexture *tex[2]; + FGameTexture* tex[2]; public: AnimTextures(); ~AnimTextures(); void SetSize(int width, int height); - void SetFrame(const uint8_t *palette, const void* data); - FTexture *GetFrame(); + void SetFrame(const uint8_t* palette, const void* data); + FGameTexture* GetFrame(); }; diff --git a/source/common/textures/formats/emptytexture.cpp b/source/common/textures/formats/emptytexture.cpp index ab4703e4e..bcbd682e0 100644 --- a/source/common/textures/formats/emptytexture.cpp +++ b/source/common/textures/formats/emptytexture.cpp @@ -69,6 +69,11 @@ FImageSource *EmptyImage_TryCreate(FileReader & file, int lumpnum) return new FEmptyTexture(lumpnum); } +FImageSource* CreateEmptyTexture() +{ + return new FEmptyTexture(0); +} + //========================================================================== // // diff --git a/source/common/textures/formats/multipatchtexture.cpp b/source/common/textures/formats/multipatchtexture.cpp index 86c9f8d77..e131b9024 100644 --- a/source/common/textures/formats/multipatchtexture.cpp +++ b/source/common/textures/formats/multipatchtexture.cpp @@ -46,15 +46,19 @@ // //========================================================================== -FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual) +FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual) { Width = w; Height = h; bComplex = complex; - bTextual = textual; + bTextual = textual; Parts = (TexPart*)ImageArena.Alloc(sizeof(TexPart) * parts.Size()); NumParts = parts.Size(); memcpy(Parts, parts.Data(), sizeof(TexPart) * parts.Size()); + for (unsigned i = 0; i < parts.Size(); i++) + { + Parts[i].Image = parts[i].TexImage->GetImage(); + } bUseGamePalette = false; if (!bComplex) @@ -67,6 +71,27 @@ FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &part } } +//========================================================================== +// +// sky remapping will only happen if +// - the texture was defined through a TEXTUREx lump (this implies only trivial copies) +// - all patches use the base palette. +// - all patches are in a format that allows the remap. +// All other cases would not be able to properly deal with this special case. +// For textual definitions this hack isn't necessary. +// +//========================================================================== + +bool FMultiPatchTexture::SupportRemap0() +{ + if (bTextual || UseGamePalette()) return false; + for (int i = 0; i < NumParts; i++) + { + if (!Parts[i].Image->SupportRemap0()) return false; + } + return true; +} + //========================================================================== // // GetBlendMap @@ -203,11 +228,6 @@ TArray FMultiPatchTexture::CreatePalettedPixels(int conversion) } if (conversion == noremap0) { - // sky remapping will only happen if - // - the texture was defined through a TEXTUREx lump (this implies only trivial copies) - // - all patches use the base palette. - // All other cases would not be able to properly deal with this special case. - // For textual definitions this hack isn't necessary. if (bTextual || !UseGamePalette()) conversion = normal; } diff --git a/source/common/textures/formats/multipatchtexture.h b/source/common/textures/formats/multipatchtexture.h index f9f5913e1..51f36abf5 100644 --- a/source/common/textures/formats/multipatchtexture.h +++ b/source/common/textures/formats/multipatchtexture.h @@ -5,8 +5,11 @@ #include "vectors.h" #include "bitmap.h" #include "image.h" +#include "textures.h" class FImageTexture; +class FTextureManager; + //========================================================================== // // TexPart is the data that will get passed to the final texture. @@ -25,6 +28,18 @@ struct TexPart uint8_t op = OP_COPY; }; +struct TexPartBuild +{ + FRemapTable* Translation = nullptr; + FImageTexture *TexImage = nullptr; + PalEntry Blend = 0; + blend_t Alpha = FRACUNIT; + int16_t OriginX = 0; + int16_t OriginY = 0; + uint8_t Rotate = 0; + uint8_t op = OP_COPY; +}; + //========================================================================== @@ -36,8 +51,21 @@ struct TexPart class FMultiPatchTexture : public FImageSource { friend class FTexture; + friend class FGameTexture; public: - FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual); + FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual); + int GetNumParts() const { return NumParts; } + // Query some needed info for texture hack support. + bool SupportRemap0() override; + bool IsRawCompatible() override + { + return NumParts != 1 || Parts[0].OriginY == 0 || bTextual; + } + FImageSource* GetImageForPart(int num) + { + if (num >= 0 && num < NumParts) return Parts[num].Image; + return nullptr; + } protected: int NumParts; @@ -64,7 +92,7 @@ struct TexInit { FString TexName; ETextureType UseType = ETextureType::Null; - FTexture *Texture = nullptr; + FImageTexture *Texture = nullptr; bool Silent = false; bool HasLine = false; bool UseOffsets = false; @@ -82,7 +110,7 @@ struct FPatchLookup; struct BuildInfo { FString Name; - TArray Parts; + TArray Parts; TArray Inits; int Width = 0; int Height = 0; @@ -94,7 +122,7 @@ struct BuildInfo bool bNoDecals = false; int LeftOffset[2] = {}; int TopOffset[2] = {}; - FImageTexture *tex = nullptr; + FGameTexture *texture = nullptr; void swap(BuildInfo &other) { @@ -113,7 +141,7 @@ struct BuildInfo std::swap(LeftOffset[1], other.LeftOffset[1]); std::swap(TopOffset[0], other.TopOffset[0]); std::swap(TopOffset[1], other.TopOffset[1]); - std::swap(tex, other.tex); + std::swap(texture, other.texture); } }; @@ -123,15 +151,17 @@ class FMultipatchTextureBuilder { FTextureManager &TexMan; TArray BuiltTextures; + TMap complex; void(*progressFunc)(); void(*checkForHacks)(BuildInfo&); void MakeTexture(BuildInfo &buildinfo, ETextureType usetype); + void AddImageToTexture(FImageTexture* tex, BuildInfo& buildinfo); void BuildTexture(const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum, ETextureType usetyoe); void AddTexturesLump(const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1); - void ParsePatch(FScanner &sc, BuildInfo &info, TexPart &part, TexInit &init); + void ParsePatch(FScanner &sc, BuildInfo &info, TexPartBuild &part, TexInit &init); void ResolvePatches(BuildInfo &buildinfo); public: diff --git a/source/common/textures/formats/patchtexture.cpp b/source/common/textures/formats/patchtexture.cpp index 960994b5c..0a93adf50 100644 --- a/source/common/textures/formats/patchtexture.cpp +++ b/source/common/textures/formats/patchtexture.cpp @@ -63,6 +63,7 @@ public: FPatchTexture (int lumpnum, int w, int h, int lo, int to, bool isalphatex); TArray CreatePalettedPixels(int conversion) override; int CopyPixels(FBitmap *bmp, int conversion) override; + bool SupportRemap0() override { return !badflag; } void DetectBadPatches(); }; diff --git a/source/common/textures/formats/pngtexture.cpp b/source/common/textures/formats/pngtexture.cpp index 16b4805da..34fab85fa 100644 --- a/source/common/textures/formats/pngtexture.cpp +++ b/source/common/textures/formats/pngtexture.cpp @@ -41,8 +41,8 @@ #include "imagehelpers.h" #include "image.h" #include "printf.h" +#include "texturemanager.h" #include "filesystem.h" -#include "colormatcher.h" //========================================================================== // @@ -591,7 +591,7 @@ protected: // //========================================================================== -FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) +FGameTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) { if (M_FindPNGChunk(png, MAKE_ID('I','H','D','R')) == 0) { @@ -610,7 +610,7 @@ FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) // Reject anything that cannot be put into a savegame picture by GZDoom itself. if (compression != 0 || filter != 0 || interlace > 0 || bitdepth != 8 || (colortype != 2 && colortype != 3)) return nullptr; - else return new FPNGFileTexture (png->File, width, height, colortype); + else return MakeGameTexture(new FPNGFileTexture (png->File, width, height, colortype), nullptr, ETextureType::Override); } //========================================================================== @@ -624,6 +624,8 @@ FPNGFileTexture::FPNGFileTexture (FileReader &lump, int width, int height, uint8 { Width = width; Height = height; + Masked = false; + bTranslucent = false; fr = std::move(lump); } diff --git a/source/common/textures/formats/shadertexture.cpp b/source/common/textures/formats/shadertexture.cpp index d07f30706..6bde2b677 100644 --- a/source/common/textures/formats/shadertexture.cpp +++ b/source/common/textures/formats/shadertexture.cpp @@ -38,6 +38,7 @@ #include "bitmap.h" #include "imagehelpers.h" #include "image.h" +#include "textures.h" class FBarShader : public FImageSource @@ -128,9 +129,9 @@ private: }; -FTexture *CreateShaderTexture(bool vertical, bool reverse) +FGameTexture *CreateShaderTexture(bool vertical, bool reverse) { FStringf name("BarShader%c%c", vertical ? 'v' : 'h', reverse ? 'r' : 'f'); - return CreateImageTexture(new FBarShader(vertical, reverse), name.GetChars()); + return MakeGameTexture(CreateImageTexture(new FBarShader(vertical, reverse)), name.GetChars(), ETextureType::Override); } diff --git a/source/common/textures/gametexture.cpp b/source/common/textures/gametexture.cpp new file mode 100644 index 000000000..1ec6a6062 --- /dev/null +++ b/source/common/textures/gametexture.cpp @@ -0,0 +1,512 @@ +/* +** gametexture.cpp +** The game-facing texture class. +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2020 Christoph Oelckers +** 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 "printf.h" +#include "files.h" +#include "filesystem.h" +#include "templates.h" +#include "textures.h" +#include "bitmap.h" +#include "colormatcher.h" +#include "c_dispatch.h" +#include "m_fixed.h" +#include "imagehelpers.h" +#include "image.h" +#include "formats/multipatchtexture.h" +#include "texturemanager.h" +#include "c_cvars.h" +#include "hw_material.h" + +FTexture *CreateBrightmapTexture(FImageSource*); + + +FGameTexture::FGameTexture(FTexture* wrap, const char* name) : Name(name) +{ + if (wrap) Setup(wrap); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FGameTexture::Setup(FTexture *wrap) +{ + Base = wrap; + id.SetInvalid(); + TexelWidth = Base->GetWidth(); + DisplayWidth = (float)TexelWidth; + TexelHeight = Base->GetHeight(); + DisplayHeight = (float)TexelHeight; + auto img = Base->GetImage(); + if (img) + { + auto ofs = img->GetOffsets(); + LeftOffset[0] = LeftOffset[1] = ofs.first; + TopOffset[0] = TopOffset[1] = ofs.second; + } + else + { + LeftOffset[0] = LeftOffset[1] = + TopOffset[0] = TopOffset[1] = 0; + + } + ScaleX = ScaleY = 1.f; +} + +//========================================================================== +// +// +// +//========================================================================== + +FGameTexture::~FGameTexture() +{ + FGameTexture* link = fileSystem.GetLinkedTexture(GetSourceLump()); + if (link == this) fileSystem.SetLinkedTexture(GetSourceLump(), nullptr); + if (SoftwareTexture != nullptr) + { + delete SoftwareTexture; + SoftwareTexture = nullptr; + } + for (auto &mat : Material) + { + if (mat != nullptr) delete mat; + mat = nullptr; + } + +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FGameTexture::isUserContent() const +{ + int filenum = fileSystem.GetFileContainer(Base->GetSourceLump()); + return (filenum > fileSystem.GetMaxIwadNum()); +} + + +//========================================================================== +// +// Search auto paths for extra material textures +// +//========================================================================== + +void FGameTexture::AddAutoMaterials() +{ + struct AutoTextureSearchPath + { + const char* path; + RefCountedPtr FGameTexture::* pointer; + }; + + static AutoTextureSearchPath autosearchpaths[] = + { + { "brightmaps/", &FGameTexture::Brightmap }, // For backwards compatibility, only for short names + { "materials/brightmaps/", &FGameTexture::Brightmap }, + { "materials/normalmaps/", &FGameTexture::Normal }, + { "materials/specular/", &FGameTexture::Specular }, + { "materials/metallic/", &FGameTexture::Metallic }, + { "materials/roughness/", &FGameTexture::Roughness }, + { "materials/ao/", &FGameTexture::AmbientOcclusion } + }; + + + bool fullname = !!(flags & GTexf_FullNameTexture); + FString searchname = GetName(); + + if (fullname) + { + auto dot = searchname.LastIndexOf('.'); + auto slash = searchname.LastIndexOf('/'); + if (dot > slash) searchname.Truncate(dot); + } + + for (size_t i = 0; i < countof(autosearchpaths); i++) + { + auto& layer = autosearchpaths[i]; + if (this->*(layer.pointer) == nullptr) // only if no explicit assignment had been done. + { + FStringf lookup("%s%s%s", layer.path, fullname ? "" : "auto/", searchname.GetChars()); + auto lump = fileSystem.CheckNumForFullName(lookup, false, ns_global, true); + if (lump != -1) + { + auto bmtex = TexMan.FindGameTexture(fileSystem.GetFileFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny); + if (bmtex != nullptr) + { + this->*(layer.pointer) = bmtex->GetTexture(); + } + } + } + } +} + +//=========================================================================== +// +// Checks if the texture has a default brightmap and creates it if so +// +//=========================================================================== +void FGameTexture::CreateDefaultBrightmap() +{ + auto tex = GetTexture(); + if (flags & GTexf_BrightmapChecked) + { + flags |= GTexf_BrightmapChecked; + // Check for brightmaps + if (tex->GetImage() && tex->GetImage()->UseGamePalette() && GPalette.HasGlobalBrightmap && + GetUseType() != ETextureType::Decal && GetUseType() != ETextureType::MiscPatch && GetUseType() != ETextureType::FontChar && + Brightmap == nullptr) + { + // May have one - let's check when we use this texture + auto texbuf = tex->Get8BitPixels(false); + const int white = ColorMatcher.Pick(255, 255, 255); + + int size = tex->GetWidth() * tex->GetHeight(); + for (int i = 0; i < size; i++) + { + if (GPalette.GlobalBrightmap.Remap[texbuf[i]] == white) + { + // Create a brightmap + DPrintf(DMSG_NOTIFY, "brightmap created for texture '%s'\n", GetName().GetChars()); + Brightmap = CreateBrightmapTexture(tex->GetImage()); + return; + } + } + // No bright pixels found + DPrintf(DMSG_SPAMMY, "No bright pixels found in texture '%s'\n", GetName().GetChars()); + } + } +} + + +//========================================================================== +// +// Calculates glow color for a texture +// +//========================================================================== + +void FGameTexture::GetGlowColor(float* data) +{ + if (isGlowing() && GlowColor == 0) + { + auto buffer = Base->GetBgraBitmap(nullptr); + GlowColor = averageColor((uint32_t*)buffer.GetPixels(), buffer.GetWidth() * buffer.GetHeight(), 153); + + // Black glow equals nothing so switch glowing off + if (GlowColor == 0) flags &= ~GTexf_Glowing; + } + data[0] = GlowColor.r * (1 / 255.0f); + data[1] = GlowColor.g * (1 / 255.0f); + data[2] = GlowColor.b * (1 / 255.0f); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +int FGameTexture::GetAreas(FloatRect** pAreas) const +{ + if (shaderindex == SHADER_Default) // texture splitting can only be done if there's no attached effects + { + *pAreas = Base->areas; + return Base->areacount; + } + else + { + return 0; + } +} + +//=========================================================================== +// +// Checks if a sprite may be expanded with an empty frame +// +//=========================================================================== + +bool FGameTexture::ShouldExpandSprite() +{ + if (expandSprite != -1) return expandSprite; + // Only applicable to image textures with no shader effect. + if (GetShaderIndex() != SHADER_Default || !dynamic_cast(Base.get())) + { + expandSprite = false; + return false; + } + if (Brightmap != NULL && (Base->GetWidth() != Brightmap->GetWidth() || Base->GetHeight() != Brightmap->GetHeight())) + { + // do not expand if the brightmap's physical size differs from the base. + expandSprite = false; + return false; + } + if (Glowmap != NULL && (Base->GetWidth() != Glowmap->GetWidth() || Base->GetHeight() != Glowmap->GetHeight())) + { + // same restriction for the glow map + expandSprite = false; + return false; + } + expandSprite = true; + return true; +} + +//=========================================================================== +// +// Sets up the sprite positioning data for this texture +// +//=========================================================================== + +void FGameTexture::SetupSpriteData() +{ + // Since this is only needed for real sprites it gets allocated on demand. + // It also allocates from the image memory arena because it has the same lifetime and to reduce maintenance. + if (spi == nullptr) spi = (SpritePositioningInfo*)ImageArena.Alloc(2 * sizeof(SpritePositioningInfo)); + for (int i = 0; i < 2; i++) + { + auto& spi = this->spi[i]; + spi.mSpriteU[0] = spi.mSpriteV[0] = 0.f; + spi.mSpriteU[1] = spi.mSpriteV[1] = 1.f; + spi.spriteWidth = GetTexelWidth(); + spi.spriteHeight = GetTexelHeight(); + + if (i == 1 && ShouldExpandSprite()) + { + spi.mTrimResult = Base->TrimBorders(spi.trim); // get the trim size before adding the empty frame + spi.spriteWidth += 2; + spi.spriteHeight += 2; + } + } + SetSpriteRect(); +} + +//=========================================================================== +// +// Set the sprite rectangle. This is separate because it may be called by a CVAR, too. +// +//=========================================================================== + +void FGameTexture::SetSpriteRect() +{ + + if (!spi) return; + auto leftOffset = GetTexelLeftOffset(r_spriteadjustHW); + auto topOffset = GetTexelTopOffset(r_spriteadjustHW); + + float fxScale = GetScaleX(); + float fyScale = GetScaleY(); + + for (int i = 0; i < 2; i++) + { + auto& spi = this->spi[i]; + + // mSpriteRect is for positioning the sprite in the scene. + spi.mSpriteRect.left = -leftOffset / fxScale; + spi.mSpriteRect.top = -topOffset / fyScale; + spi.mSpriteRect.width = spi.spriteWidth / fxScale; + spi.mSpriteRect.height = spi.spriteHeight / fyScale; + + if (i == 1 && ShouldExpandSprite()) + { + // a little adjustment to make sprites look better with texture filtering: + // create a 1 pixel wide empty frame around them. + + int oldwidth = spi.spriteWidth - 2; + int oldheight = spi.spriteHeight - 2; + + leftOffset += 1; + topOffset += 1; + + // Reposition the sprite with the frame considered + spi.mSpriteRect.left = -(float)leftOffset / fxScale; + spi.mSpriteRect.top = -(float)topOffset / fyScale; + spi.mSpriteRect.width = (float)spi.spriteWidth / fxScale; + spi.mSpriteRect.height = (float)spi.spriteHeight / fyScale; + + if (spi.mTrimResult > 0) + { + spi.mSpriteRect.left += (float)spi.trim[0] / fxScale; + spi.mSpriteRect.top += (float)spi.trim[1] / fyScale; + + spi.mSpriteRect.width -= float(oldwidth - spi.trim[2]) / fxScale; + spi.mSpriteRect.height -= float(oldheight - spi.trim[3]) / fyScale; + + spi.mSpriteU[0] = (float)spi.trim[0] / (float)spi.spriteWidth; + spi.mSpriteV[0] = (float)spi.trim[1] / (float)spi.spriteHeight; + spi.mSpriteU[1] -= float(oldwidth - spi.trim[0] - spi.trim[2]) / (float)spi.spriteWidth; + spi.mSpriteV[1] -= float(oldheight - spi.trim[1] - spi.trim[3]) / (float)spi.spriteHeight; + } + } + } +} + +//=========================================================================== +// +// Cleans the attached hardware resources. +// This should only be used on textures which alter their content at run time +//or when the engine shuts down. +// +//=========================================================================== + +void FGameTexture::CleanHardwareData(bool full) +{ + Base->CleanHardwareTextures(); + for (auto mat : Material) if (mat) mat->DeleteDescriptors(); +} + + +//----------------------------------------------------------------------------- +// +// Make sprite offset adjustment user-configurable per renderer. +// +//----------------------------------------------------------------------------- + +CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + r_spriteadjustHW = !!(self & 2); + r_spriteadjustSW = !!(self & 1); + for (int i = 0; i < TexMan.NumTextures(); i++) + { + auto tex = TexMan.GetGameTexture(FSetTextureID(i)); + if (tex->GetTexelLeftOffset(0) != tex->GetTexelLeftOffset(1) || tex->GetTexelTopOffset(0) != tex->GetTexelTopOffset(1)) + { + tex->SetSpriteRect(); + } + } +} + +//=========================================================================== +// +// Coordinate helper. +// The only reason this is even needed is that many years ago someone +// was convinced that having per-texel panning on walls was a good idea. +// If it wasn't for this relatively useless feature the entire positioning +// code for wall textures could be a lot simpler. +// +//=========================================================================== + +//=========================================================================== +// +// +// +//=========================================================================== + +float FTexCoordInfo::RowOffset(float rowoffset) const +{ + float scale = fabs(mScale.Y); + if (scale == 1.f || mWorldPanning) return rowoffset; + else return rowoffset / scale; +} + +//=========================================================================== +// +// +// +//=========================================================================== + +float FTexCoordInfo::TextureOffset(float textureoffset) const +{ + float scale = fabs(mScale.X); + if (scale == 1.f || mWorldPanning) return textureoffset; + else return textureoffset / scale; +} + +//=========================================================================== +// +// Returns the size for which texture offset coordinates are used. +// +//=========================================================================== + +float FTexCoordInfo::TextureAdjustWidth() const +{ + if (mWorldPanning) + { + float tscale = fabs(mTempScale.X); + if (tscale == 1.f) return (float)mRenderWidth; + else return mWidth / fabs(tscale); + } + else return (float)mWidth; +} + + +//=========================================================================== +// +// Retrieve texture coordinate info for per-wall scaling +// +//=========================================================================== + +void FTexCoordInfo::GetFromTexture(FGameTexture *tex, float x, float y, bool forceworldpanning) +{ + if (x == 1.f) + { + mRenderWidth = xs_RoundToInt(tex->GetDisplayWidth()); + mScale.X = tex->GetScaleX(); + mTempScale.X = 1.f; + } + else + { + float scale_x = x * tex->GetScaleX(); + mRenderWidth = xs_CeilToInt(tex->GetTexelWidth() / scale_x); + mScale.X = scale_x; + mTempScale.X = x; + } + + if (y == 1.f) + { + mRenderHeight = xs_RoundToInt(tex->GetDisplayHeight()); + mScale.Y = tex->GetScaleY(); + mTempScale.Y = 1.f; + } + else + { + float scale_y = y * tex->GetScaleY(); + mRenderHeight = xs_CeilToInt(tex->GetTexelHeight() / scale_y); + mScale.Y = scale_y; + mTempScale.Y = y; + } + if (tex->isHardwareCanvas()) + { + mScale.Y = -mScale.Y; + mRenderHeight = -mRenderHeight; + } + mWorldPanning = tex->useWorldPanning() || forceworldpanning; + mWidth = tex->GetTexelWidth(); +} + diff --git a/source/common/textures/gametexture.h b/source/common/textures/gametexture.h new file mode 100644 index 000000000..1f0c26d9d --- /dev/null +++ b/source/common/textures/gametexture.h @@ -0,0 +1,339 @@ +#pragma once +#include +#include "vectors.h" +#include "floatrect.h" +#include "refcounted.h" +#include "xs_Float.h" +#include "palentry.h" +#include "zstring.h" +#include "textureid.h" + +// 15 because 0th texture is our texture +#define MAX_CUSTOM_HW_SHADER_TEXTURES 15 +class FTexture; +class ISoftwareTexture; +class FMaterial; + +struct SpritePositioningInfo +{ + uint16_t trim[4]; + int spriteWidth, spriteHeight; + float mSpriteU[2], mSpriteV[2]; + FloatRect mSpriteRect; + uint8_t mTrimResult; + + float GetSpriteUL() const { return mSpriteU[0]; } + float GetSpriteVT() const { return mSpriteV[0]; } + float GetSpriteUR() const { return mSpriteU[1]; } + float GetSpriteVB() const { return mSpriteV[1]; } + + const FloatRect &GetSpriteRect() const + { + return mSpriteRect; + } + +}; + +struct MaterialLayers +{ + float Glossiness; + float SpecularLevel; + FGameTexture* Brightmap; + FGameTexture* Normal; + FGameTexture* Specular; + FGameTexture* Metallic; + FGameTexture* Roughness; + FGameTexture* AmbientOcclusion; + FGameTexture* CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; +}; + +enum EGameTexFlags +{ + GTexf_NoDecals = 1, // Decals should not stick to texture + GTexf_WorldPanning = 2, // Texture is panned in world units rather than texels + GTexf_FullNameTexture = 4, // Name is taken from the file system. + GTexf_Glowing = 8, // Texture emits a glow + GTexf_AutoGlowing = 16, // Glow info is determined from texture image. + GTexf_RenderFullbright = 32, // always draw fullbright + GTexf_DisableFullbrightSprites = 64, // This texture will not be displayed as fullbright sprite + GTexf_BrightmapChecked = 128, // Check for a colormap-based brightmap was already done. +}; + +// Refactoring helper to allow piece by piece adjustment of the API +class FGameTexture +{ + friend class FMaterial; + + // Material layers. These are shared so reference counting is used. + RefCountedPtr Base; + RefCountedPtr Brightmap; + RefCountedPtr Detailmap; + RefCountedPtr Glowmap; + RefCountedPtr Normal; // Normal map texture + RefCountedPtr Specular; // Specular light texture for the diffuse+normal+specular light model + RefCountedPtr Metallic; // Metalness texture for the physically based rendering (PBR) light model + RefCountedPtr Roughness; // Roughness texture for PBR + RefCountedPtr AmbientOcclusion; // Ambient occlusion texture for PBR + RefCountedPtr CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; // Custom texture maps for custom hardware shaders + + FString Name; + FTextureID id; + + uint16_t TexelWidth, TexelHeight; + int16_t LeftOffset[2], TopOffset[2]; + float DisplayWidth, DisplayHeight; + float ScaleX, ScaleY; + + int8_t shouldUpscaleFlag = 0; // Without explicit setup, scaling is disabled for a texture. + ETextureType UseType = ETextureType::Wall; // This texture's primary purpose + SpritePositioningInfo* spi = nullptr; + + ISoftwareTexture* SoftwareTexture = nullptr; + FMaterial* Material[4] = { }; + + // Material properties + float Glossiness = 10.f; + float SpecularLevel = 0.1f; + float shaderspeed = 1.f; + int shaderindex = 0; + + int flags = 0; + uint8_t warped = 0; + int8_t expandSprite = -1; + uint16_t GlowHeight; + PalEntry GlowColor = 0; + + int16_t SkyOffset = 0; + uint16_t Rotations = 0xffff; + + +public: + float alphaThreshold = 0.5f; + + FGameTexture(FTexture* wrap, const char *name); + ~FGameTexture(); + void Setup(FTexture* wrap); + FTextureID GetID() const { return id; } + void SetID(FTextureID newid) { id = newid; } // should only be called by the texture manager + const FString& GetName() const { return Name; } + void SetName(const char* name) { Name = name; } // should only be called by setup code. + + float GetScaleX() { return ScaleX; } + float GetScaleY() { return ScaleY; } + float GetDisplayWidth() const { return DisplayWidth; } + float GetDisplayHeight() const { return DisplayHeight; } + int GetTexelWidth() const { return TexelWidth; } + int GetTexelHeight() const { return TexelHeight; } + + void CreateDefaultBrightmap(); + void AddAutoMaterials(); + bool ShouldExpandSprite(); + void SetupSpriteData(); + void SetSpriteRect(); + + ETextureType GetUseType() const { return UseType; } + void SetUpscaleFlag(int what) { shouldUpscaleFlag = what; } + int GetUpscaleFlag() { return shouldUpscaleFlag; } + + FTexture* GetTexture() { return Base.get(); } + int GetSourceLump() const { return Base->GetSourceLump(); } + void SetBrightmap(FGameTexture* tex) { Brightmap = tex->GetTexture(); } + + int GetTexelLeftOffset(int adjusted = 0) const { return LeftOffset[adjusted]; } + int GetTexelTopOffset(int adjusted = 0) const { return TopOffset[adjusted]; } + float GetDisplayLeftOffset(int adjusted = 0) const { return LeftOffset[adjusted] / ScaleX; } + float GetDisplayTopOffset(int adjusted = 0) const { return TopOffset[adjusted] / ScaleY; } + + bool isMiscPatch() const { return GetUseType() == ETextureType::MiscPatch; } // only used by the intermission screen to decide whether to tile the background image or not. + bool isFullbrightDisabled() const { return !!(flags & GTexf_DisableFullbrightSprites); } + bool isFullbright() const { return !!(flags & GTexf_RenderFullbright); } + bool isFullNameTexture() const { return !!(flags & GTexf_FullNameTexture); } + bool expandSprites() { return expandSprite == -1? ShouldExpandSprite() : !!expandSprite; } + bool useWorldPanning() const { return !!(flags & GTexf_WorldPanning); } + void SetWorldPanning(bool on) { if (on) flags |= GTexf_WorldPanning; else flags &= ~GTexf_WorldPanning; } + bool allowNoDecals() const { return !!(flags & GTexf_NoDecals); } + void SetNoDecals(bool on) { if (on) flags |= GTexf_NoDecals; else flags &= ~GTexf_NoDecals; } + + bool isValid() const { return UseType != ETextureType::Null; } + int isWarped() { return warped; } + void SetWarpStyle(int style) { warped = style; } + bool isMasked() { return Base->Masked; } + bool isHardwareCanvas() const { return Base->isHardwareCanvas(); } // There's two here so that this can deal with software canvases in the hardware renderer later. + bool isSoftwareCanvas() const { return Base->isCanvas(); } + + void SetTranslucent(bool on) { Base->bTranslucent = on; } + void SetUseType(ETextureType type) { UseType = type; } + int GetRotations() const { return Rotations; } + void SetRotations(int rot) { Rotations = int16_t(rot); } + void SetSkyOffset(int offs) { SkyOffset = offs; } + int GetSkyOffset() const { return SkyOffset; } + + ISoftwareTexture* GetSoftwareTexture() + { + return SoftwareTexture; + } + void SetSoftwareTexture(ISoftwareTexture* swtex) + { + SoftwareTexture = swtex; + } + + FMaterial* GetMaterial(int num) + { + return Material[num]; + } + + int GetShaderIndex() const { return shaderindex; } + float GetShaderSpeed() const { return shaderspeed; } + void SetShaderSpeed(float speed) { shaderspeed = speed; } + void SetShaderIndex(int index) { shaderindex = index; } + void SetShaderLayers(MaterialLayers& lay) + { + // Only update layers that have something defind. + if (lay.Glossiness > -1000) Glossiness = lay.Glossiness; + if (lay.SpecularLevel > -1000) SpecularLevel = lay.SpecularLevel; + if (lay.Brightmap) Brightmap = lay.Brightmap->GetTexture(); + if (lay.Normal) Normal = lay.Normal->GetTexture(); + if (lay.Specular) Specular = lay.Specular->GetTexture(); + if (lay.Metallic) Metallic = lay.Metallic->GetTexture(); + if (lay.Roughness) Roughness = lay.Roughness->GetTexture(); + if (lay.AmbientOcclusion) AmbientOcclusion = lay.AmbientOcclusion->GetTexture(); + for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++) + { + if (lay.CustomShaderTextures[i]) CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture(); + } + } + float GetGlossiness() const { return Glossiness; } + float GetSpecularLevel() const { return SpecularLevel; } + + void CopySize(FGameTexture* BaseTexture) + { + Base->CopySize(BaseTexture->Base.get()); + } + + // Glowing is a pure material property that should not filter down to the actual texture objects. + void GetGlowColor(float* data); + bool isGlowing() const { return !!(flags & GTexf_Glowing); } + bool isAutoGlowing() const { return !!(flags & GTexf_AutoGlowing); } + int GetGlowHeight() const { return GlowHeight; } + void SetAutoGlowing() { flags |= (GTexf_AutoGlowing | GTexf_Glowing | GTexf_RenderFullbright); } + void SetGlowHeight(int v) { GlowHeight = v; } + void SetFullbright() { flags |= GTexf_RenderFullbright; } + void SetDisableFullbright(bool on) { if (on) flags |= GTexf_DisableFullbrightSprites; else flags &= ~GTexf_DisableFullbrightSprites; } + void SetGlowing(PalEntry color) { flags = (flags & ~GTexf_AutoGlowing) | GTexf_Glowing; GlowColor = color; } + + bool isUserContent() const; + int CheckRealHeight() { return xs_RoundToInt(Base->CheckRealHeight() / ScaleY); } + void SetSize(int x, int y) + { + TexelWidth = x; + TexelHeight = y; + SetDisplaySize(float(x), float(y)); + } + void SetDisplaySize(float w, float h) + { + DisplayWidth = w; + DisplayHeight = h; + ScaleX = TexelWidth / w; + ScaleY = TexelHeight / h; + + // compensate for roundoff errors + if (int(ScaleX * w) != TexelWidth) ScaleX += (1 / 65536.); + if (int(ScaleY * h) != TexelHeight) ScaleY += (1 / 65536.); + + } + void SetOffsets(int which, int x, int y) + { + LeftOffset[which] = x; + TopOffset[which] = y; + } + void SetOffsets(int x, int y) + { + LeftOffset[0] = x; + TopOffset[0] = y; + LeftOffset[1] = x; + TopOffset[1] = y; + } + void SetScale(float x, float y) + { + ScaleX = x; + ScaleY = y; + DisplayWidth = x * TexelWidth; + DisplayHeight = y * TexelHeight; + } + + const SpritePositioningInfo& GetSpritePositioning(int which) { if (spi == nullptr) SetupSpriteData(); return spi[which]; } + int GetAreas(FloatRect** pAreas) const; + + bool GetTranslucency() + { + return Base->GetTranslucency(); + } + + int GetClampMode(int clampmode) + { + if (GetUseType() == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; + else if (isHardwareCanvas()) clampmode = CLAMP_CAMTEX; + else if ((isWarped() || shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; + return clampmode; + } + + void CleanHardwareData(bool full = true); + + void GetLayers(TArray& layers) + { + layers.Clear(); + for (auto tex : { Base.get(), Brightmap.get(), Detailmap.get(), Glowmap.get(), Normal.get(), Specular.get(), Metallic.get(), Roughness.get(), AmbientOcclusion.get() }) + { + if (tex != nullptr) layers.Push(tex); + } + for (auto& tex : CustomShaderTextures) + { + if (tex != nullptr) layers.Push(tex.get()); + } + } + +}; + +inline FGameTexture* MakeGameTexture(FTexture* tex, const char *name, ETextureType useType) +{ + if (!tex) return nullptr; + auto t = new FGameTexture(tex, name); + t->SetUseType(useType); + return t; +} + +enum EUpscaleFlags +{ + UF_None = 0, + UF_Texture = 1, + UF_Sprite = 2, + UF_Font = 4 +}; + +extern int upscalemask; +void UpdateUpscaleMask(); + +int calcShouldUpscale(FGameTexture* tex); +inline int shouldUpscale(FGameTexture* tex, EUpscaleFlags UseType) +{ + // This only checks the global scale mask and the texture's validation for upscaling. Everything else has been done up front elsewhere. + if (!(upscalemask & UseType)) return 0; + return tex->GetUpscaleFlag(); +} + +struct FTexCoordInfo +{ + int mRenderWidth; + int mRenderHeight; + int mWidth; + FVector2 mScale; + FVector2 mTempScale; + bool mWorldPanning; + + float FloatToTexU(float v) const { return v / mRenderWidth; } + float FloatToTexV(float v) const { return v / mRenderHeight; } + float RowOffset(float ofs) const; + float TextureOffset(float ofs) const; + float TextureAdjustWidth() const; + void GetFromTexture(FGameTexture* tex, float x, float y, bool forceworldpanning); +}; diff --git a/source/common/textures/hires/hqresize.cpp b/source/common/textures/hires/hqresize.cpp index e04be8262..2e7b2fb06 100644 --- a/source/common/textures/hires/hqresize.cpp +++ b/source/common/textures/hires/hqresize.cpp @@ -46,6 +46,8 @@ #include "texturemanager.h" #include "printf.h" +int upscalemask; + EXTERN_CVAR(Int, gl_texture_hqresizemult) CUSTOM_CVAR(Int, gl_texture_hqresizemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { @@ -54,6 +56,7 @@ CUSTOM_CVAR(Int, gl_texture_hqresizemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | if ((gl_texture_hqresizemult > 4) && (self < 4) && (self > 0)) gl_texture_hqresizemult = 4; TexMan.FlushAll(); + UpdateUpscaleMask(); } CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) @@ -63,6 +66,7 @@ CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | if ((self > 4) && (gl_texture_hqresizemode < 4) && (gl_texture_hqresizemode > 0)) self = 4; TexMan.FlushAll(); + UpdateUpscaleMask(); } CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) @@ -74,6 +78,7 @@ CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOB CUSTOM_CVAR(Int, gl_texture_hqresize_targets, 7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { TexMan.FlushAll(); + UpdateUpscaleMask(); } CVAR (Flag, gl_texture_hqresize_textures, gl_texture_hqresize_targets, 1); @@ -96,6 +101,13 @@ CUSTOM_CVAR(Int, gl_texture_hqresize_mt_height, 4, CVAR_ARCHIVE | CVAR_GLOBALCON CVAR(Int, xbrz_colorformat, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +void UpdateUpscaleMask() +{ + if (!gl_texture_hqresizemode || gl_texture_hqresizemult == 1) upscalemask = 0; + else upscalemask = gl_texture_hqresize_targets; +} + + static void xbrzApplyOptions() { if (gl_texture_hqresizemult != 0 && (gl_texture_hqresizemode == 4 || gl_texture_hqresizemode == 5)) @@ -405,42 +417,15 @@ static void xbrzOldScale(size_t factor, const uint32_t* src, uint32_t* trg, int // the upsampled buffer. // //=========================================================================== + void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly) { // [BB] Make sure that inWidth and inHeight denote the size of // the returned buffer even if we don't upsample the input buffer. + int inWidth = texbuffer.mWidth; int inHeight = texbuffer.mHeight; - // [BB] Don't resample if width * height of the input texture is bigger than gl_texture_hqresize_maxinputsize squared. - const int maxInputSize = gl_texture_hqresize_maxinputsize; - if (inWidth * inHeight > maxInputSize * maxInputSize) - return; - - // [BB] Don't try to upsample textures based off FCanvasTexture. (This should never get here in the first place!) - if (bHasCanvas) - return; - - // already scaled? - if (Scale.X >= 2 && Scale.Y >= 2) - return; - - switch (UseType) - { - case ETextureType::Sprite: - case ETextureType::SkinSprite: - if (!(gl_texture_hqresize_targets & 2)) return; - break; - - case ETextureType::FontChar: - if (!(gl_texture_hqresize_targets & 4)) return; - break; - - default: - if (!(gl_texture_hqresize_targets & 1)) return; - break; - } - int type = gl_texture_hqresizemode; int mult = gl_texture_hqresizemult; #ifdef HAVE_MMX @@ -509,3 +494,28 @@ void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasA contentId.scalefactor = mult; texbuffer.mContentId = contentId.id; } + +//=========================================================================== +// +// This was pulled out of the above function to allow running these +// checks before the texture is passed to the render state. +// +//=========================================================================== + +int calcShouldUpscale(FGameTexture *tex) +{ + // [BB] Don't resample if width * height of the input texture is bigger than gl_texture_hqresize_maxinputsize squared. + const int maxInputSize = gl_texture_hqresize_maxinputsize; + if (tex->GetTexelWidth() * tex->GetTexelHeight() > maxInputSize * maxInputSize) + return 0; + + // [BB] Don't try to upsample textures based off FCanvasTexture. (This should never get here in the first place!) + if (tex->isHardwareCanvas()) + return 0; + + // already scaled? + if (tex->GetDisplayWidth() >= 2* tex->GetTexelWidth() || tex->GetDisplayHeight() >= 2*tex->GetTexelHeight()) + return 0; + + return CTF_Upscale; +} \ No newline at end of file diff --git a/source/common/textures/hw_ihwtexture.h b/source/common/textures/hw_ihwtexture.h index 24b92c926..b207dceb4 100644 --- a/source/common/textures/hw_ihwtexture.h +++ b/source/common/textures/hw_ihwtexture.h @@ -14,10 +14,8 @@ public: MAX_TEXTURES = 16 }; - IHardwareTexture() {} - virtual ~IHardwareTexture() {} - - virtual void DeleteDescriptors() { } + IHardwareTexture() = default; + virtual ~IHardwareTexture() = default; virtual void AllocateBuffer(int w, int h, int texelsize) = 0; virtual uint8_t *MapBuffer() = 0; diff --git a/source/common/textures/hw_material.cpp b/source/common/textures/hw_material.cpp index 33406ccd9..574b5f10b 100644 --- a/source/common/textures/hw_material.cpp +++ b/source/common/textures/hw_material.cpp @@ -27,8 +27,8 @@ #include "hw_material.h" #include "texturemanager.h" #include "c_cvars.h" +#include "v_video.h" -EXTERN_CVAR(Bool, gl_texture_usehires) IHardwareTexture* CreateHardwareTexture(); //=========================================================================== @@ -37,99 +37,100 @@ IHardwareTexture* CreateHardwareTexture(); // //=========================================================================== -FMaterial::FMaterial(FTexture * tx, bool expanded) +FMaterial::FMaterial(FGameTexture * tx, int scaleflags) { mShaderIndex = SHADER_Default; - sourcetex = tex = tx; + sourcetex = tx; + auto imgtex = tx->GetTexture(); + mTextureLayers.Push({ imgtex, scaleflags }); - if (tx->UseType == ETextureType::SWCanvas && static_cast(tx)->GetColorFormat() == 0) + if (tx->GetUseType() == ETextureType::SWCanvas && static_cast(imgtex)->GetColorFormat() == 0) { mShaderIndex = SHADER_Paletted; } - else if (tx->isWarped()) - { - mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 - } else if (tx->isHardwareCanvas()) { - if (tx->shaderindex >= FIRST_USER_SHADER) + if (tx->GetShaderIndex() >= FIRST_USER_SHADER) { - mShaderIndex = tx->shaderindex; + mShaderIndex = tx->GetShaderIndex(); } // no brightmap for cameratexture } else { - if (tx->Normal && tx->Specular) + if (tx->isWarped()) { - for (auto &texture : { tx->Normal, tx->Specular }) + mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 + } + // Note that the material takes no ownership of the texture! + else if (tx->Normal.get() && tx->Specular.get()) + { + for (auto &texture : { tx->Normal.get(), tx->Specular.get() }) { - mTextureLayers.Push(texture); + mTextureLayers.Push({ texture, 0 }); } mShaderIndex = SHADER_Specular; } - else if (tx->Normal && tx->Metallic && tx->Roughness && tx->AmbientOcclusion) + else if (tx->Normal.get() && tx->Metallic.get() && tx->Roughness.get() && tx->AmbientOcclusion.get()) { - for (auto &texture : { tx->Normal, tx->Metallic, tx->Roughness, tx->AmbientOcclusion }) + for (auto &texture : { tx->Normal.get(), tx->Metallic.get(), tx->Roughness.get(), tx->AmbientOcclusion.get() }) { - mTextureLayers.Push(texture); + mTextureLayers.Push({ texture, 0 }); } mShaderIndex = SHADER_PBR; } + // Note that these layers must present a valid texture even if not used, because empty TMUs in the shader are an undefined condition. tx->CreateDefaultBrightmap(); - if (tx->Brightmap) + auto placeholder = TexMan.GameByIndex(1); + if (tx->Brightmap.get()) { - mTextureLayers.Push(tx->Brightmap); - if (mShaderIndex == SHADER_Specular) - mShaderIndex = SHADER_SpecularBrightmap; - else if (mShaderIndex == SHADER_PBR) - mShaderIndex = SHADER_PBRBrightmap; - else - mShaderIndex = SHADER_Brightmap; + mTextureLayers.Push({ tx->Brightmap.get(), scaleflags }); + mLayerFlags |= TEXF_Brightmap; + } + else + { + mTextureLayers.Push({ placeholder->GetTexture(), 0 }); + } + if (tx->Detailmap.get()) + { + mTextureLayers.Push({ tx->Detailmap.get(), 0 }); + mLayerFlags |= TEXF_Detailmap; + } + else + { + mTextureLayers.Push({ placeholder->GetTexture(), 0 }); + } + if (tx->Glowmap.get()) + { + mTextureLayers.Push({ tx->Glowmap.get(), scaleflags }); + mLayerFlags |= TEXF_Glowmap; + } + else + { + mTextureLayers.Push({ placeholder->GetTexture(), 0 }); } - if (tx->shaderindex >= FIRST_USER_SHADER) + auto index = tx->GetShaderIndex(); + if (index >= FIRST_USER_SHADER) { - const UserShaderDesc &usershader = usershaders[tx->shaderindex - FIRST_USER_SHADER]; + const UserShaderDesc &usershader = usershaders[index - FIRST_USER_SHADER]; if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material { for (auto &texture : tx->CustomShaderTextures) { if (texture == nullptr) continue; - mTextureLayers.Push(texture); + mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable. } - mShaderIndex = tx->shaderindex; + mShaderIndex = index; } } } - mWidth = tx->GetTexelWidth(); - mHeight = tx->GetTexelHeight(); - mLeftOffset = tx->GetLeftOffset(0); // These only get used by decals and decals should not use renderer-specific offsets. - mTopOffset = tx->GetTopOffset(0); - mRenderWidth = tx->GetScaledWidth(); - mRenderHeight = tx->GetScaledHeight(); - mSpriteU[0] = mSpriteV[0] = 0.f; - mSpriteU[1] = mSpriteV[1] = 1.f; - - mExpanded = expanded; - if (expanded) - { - int oldwidth = mWidth; - int oldheight = mHeight; - - mTrimResult = TrimBorders(trim); // get the trim size before adding the empty frame - mWidth += 2; - mHeight += 2; - mRenderWidth = mRenderWidth * mWidth / oldwidth; - mRenderHeight = mRenderHeight * mHeight / oldheight; - - } - SetSpriteRect(); + mScaleFlags = scaleflags; mTextureLayers.ShrinkToFit(); - tx->Material[expanded] = this; - if (tx->isHardwareCanvas()) tx->bTranslucent = 0; + tx->Material[scaleflags] = this; + if (tx->isHardwareCanvas()) tx->SetTranslucent(false); } //=========================================================================== @@ -142,193 +143,22 @@ FMaterial::~FMaterial() { } + //=========================================================================== // -// Set the sprite rectangle +// // //=========================================================================== -void FMaterial::SetSpriteRect() +IHardwareTexture *FMaterial::GetLayer(int i, int translation, MaterialLayerInfo **pLayer) const { - auto leftOffset = tex->GetLeftOffsetHW(); - auto topOffset = tex->GetTopOffsetHW(); - - float fxScale = (float)tex->Scale.X; - float fyScale = (float)tex->Scale.Y; - - // mSpriteRect is for positioning the sprite in the scene. - mSpriteRect.left = -leftOffset / fxScale; - mSpriteRect.top = -topOffset / fyScale; - mSpriteRect.width = mWidth / fxScale; - mSpriteRect.height = mHeight / fyScale; - - if (mExpanded) - { - // a little adjustment to make sprites look better with texture filtering: - // create a 1 pixel wide empty frame around them. - - int oldwidth = mWidth - 2; - int oldheight = mHeight - 2; - - leftOffset += 1; - topOffset += 1; - - // Reposition the sprite with the frame considered - mSpriteRect.left = -leftOffset / fxScale; - mSpriteRect.top = -topOffset / fyScale; - mSpriteRect.width = mWidth / fxScale; - mSpriteRect.height = mHeight / fyScale; - - if (mTrimResult) - { - mSpriteRect.left += trim[0] / fxScale; - mSpriteRect.top += trim[1] / fyScale; - - mSpriteRect.width -= (oldwidth - trim[2]) / fxScale; - mSpriteRect.height -= (oldheight - trim[3]) / fyScale; - - mSpriteU[0] = trim[0] / (float)mWidth; - mSpriteV[0] = trim[1] / (float)mHeight; - mSpriteU[1] -= (oldwidth - trim[0] - trim[2]) / (float)mWidth; - mSpriteV[1] -= (oldheight - trim[1] - trim[3]) / (float)mHeight; - } - } -} - - -//=========================================================================== -// -// Finds empty space around the texture. -// Used for sprites that got placed into a huge empty frame. -// -//=========================================================================== - -bool FMaterial::TrimBorders(uint16_t *rect) -{ - - auto texbuffer = sourcetex->CreateTexBuffer(0); - int w = texbuffer.mWidth; - int h = texbuffer.mHeight; - auto Buffer = texbuffer.mBuffer; - - if (texbuffer.mBuffer == nullptr) - { - return false; - } - if (w != mWidth || h != mHeight) - { - // external Hires replacements cannot be trimmed. - return false; - } - - int size = w*h; - if (size == 1) - { - // nothing to be done here. - rect[0] = 0; - rect[1] = 0; - rect[2] = 1; - rect[3] = 1; - return true; - } - int first, last; - - for(first = 0; first < size; first++) - { - if (Buffer[first*4+3] != 0) break; - } - if (first >= size) - { - // completely empty - rect[0] = 0; - rect[1] = 0; - rect[2] = 1; - rect[3] = 1; - return true; - } - - for(last = size-1; last >= first; last--) - { - if (Buffer[last*4+3] != 0) break; - } - - rect[1] = first / w; - rect[3] = 1 + last/w - rect[1]; - - rect[0] = 0; - rect[2] = w; - - unsigned char *bufferoff = Buffer + (rect[1] * w * 4); - h = rect[3]; - - for(int x = 0; x < w; x++) - { - for(int y = 0; y < h; y++) - { - if (bufferoff[(x+y*w)*4+3] != 0) goto outl; - } - rect[0]++; - } -outl: - rect[2] -= rect[0]; - - for(int x = w-1; rect[2] > 1; x--) - { - for(int y = 0; y < h; y++) - { - if (bufferoff[(x+y*w)*4+3] != 0) - { - return true; - } - } - rect[2]--; - } - return true; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -IHardwareTexture *FMaterial::GetLayer(int i, int translation, FTexture **pLayer) -{ - FTexture *layer = i == 0 ? tex : mTextureLayers[i - 1]; - if (pLayer) *pLayer = layer; + auto &layer = mTextureLayers[i]; + if (pLayer) *pLayer = &layer; - if (layer && layer->UseType!=ETextureType::Null) - { - IHardwareTexture *hwtex = layer->SystemTextures.GetHardwareTexture(translation, mExpanded); - if (hwtex == nullptr) - { - hwtex = CreateHardwareTexture(); - layer->SystemTextures.AddHardwareTexture(translation, mExpanded, hwtex); - } - return hwtex; - } + if (layer.layerTexture) return layer.layerTexture->GetHardwareTexture(translation, layer.scaleFlags); return nullptr; } -//=========================================================================== -// -// -// -//=========================================================================== - -int FMaterial::GetAreas(FloatRect **pAreas) const -{ - if (mShaderIndex == SHADER_Default) // texture splitting can only be done if there's no attached effects - { - *pAreas = sourcetex->areas; - return sourcetex->areacount; - } - else - { - return 0; - } -} - //========================================================================== // // Gets a texture from the texture manager and checks its validity for @@ -336,75 +166,27 @@ int FMaterial::GetAreas(FloatRect **pAreas) const // //========================================================================== -FMaterial * FMaterial::ValidateTexture(FTexture * tex, bool expand, bool create) +FMaterial * FMaterial::ValidateTexture(FGameTexture * gtex, int scaleflags, bool create) { -again: - if (tex && tex->isValid()) +#if 0 + if (gtex && gtex->isValid()) { - if (tex->bNoExpand) expand = false; + if (!gtex->expandSprites()) scaleflags &= ~CTF_Expand; - FMaterial *hwtex = tex->Material[expand]; + FMaterial *hwtex = gtex->Material[scaleflags]; if (hwtex == NULL && create) { - if (expand) - { - if (tex->isWarped() || tex->isHardwareCanvas() || tex->shaderindex >= FIRST_USER_SHADER || (tex->shaderindex >= SHADER_Specular && tex->shaderindex <= SHADER_PBRBrightmap)) - { - tex->bNoExpand = true; - goto again; - } - if (tex->Brightmap != NULL && - (tex->GetTexelWidth() != tex->Brightmap->GetTexelWidth() || - tex->GetTexelHeight() != tex->Brightmap->GetTexelHeight()) - ) - { - // do not expand if the brightmap's size differs. - tex->bNoExpand = true; - goto again; - } - } - hwtex = new FMaterial(tex, expand); + hwtex = screen->CreateMaterial(gtex, scaleflags); } return hwtex; } +#endif return NULL; } -FMaterial * FMaterial::ValidateTexture(FTextureID no, bool expand, bool translate, bool create) -{ - return ValidateTexture(TexMan.GetTexture(no, translate), expand, create); -} - - void DeleteMaterial(FMaterial* mat) { delete mat; } -//----------------------------------------------------------------------------- -// -// Make sprite offset adjustment user-configurable per renderer. -// -//----------------------------------------------------------------------------- - -extern int r_spriteadjustSW, r_spriteadjustHW; - -CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - r_spriteadjustHW = !!(self & 2); - r_spriteadjustSW = !!(self & 1); - for (int i = 0; i < TexMan.NumTextures(); i++) - { - auto tex = TexMan.GetTexture(FSetTextureID(i)); - if (tex->GetTexelLeftOffset(0) != tex->GetTexelLeftOffset(1) || tex->GetTexelTopOffset(0) != tex->GetTexelTopOffset(1)) - { - for (int i = 0; i < 2; i++) - { - auto mat = tex->GetMaterial(i); - if (mat != nullptr) mat->SetSpriteRect(); - } - } - - } -} diff --git a/source/common/textures/hw_material.h b/source/common/textures/hw_material.h index f6311c962..d7509cc94 100644 --- a/source/common/textures/hw_material.h +++ b/source/common/textures/hw_material.h @@ -8,18 +8,12 @@ struct FRemapTable; class IHardwareTexture; -enum +struct MaterialLayerInfo { - CLAMP_NONE = 0, - CLAMP_X = 1, - CLAMP_Y = 2, - CLAMP_XY = 3, - CLAMP_XY_NOMIP = 4, - CLAMP_NOFILTER = 5, - CLAMP_CAMTEX = 6, + FTexture* layerTexture; + int scaleFlags; }; - //=========================================================================== // // this is the material class for OpenGL. @@ -28,108 +22,42 @@ enum class FMaterial { - TArray mTextureLayers; + private: + TArray mTextureLayers; // the only layers allowed to scale are the brightmap and the glowmap. int mShaderIndex; - - short mLeftOffset; - short mTopOffset; - short mWidth; - short mHeight; - short mRenderWidth; - short mRenderHeight; - bool mExpanded; - bool mTrimResult; - uint16_t trim[4]; - - float mSpriteU[2], mSpriteV[2]; - FloatRect mSpriteRect; - - bool TrimBorders(uint16_t *rect); + int mLayerFlags = 0; + int mScaleFlags; public: - FTexture *tex; - FTexture *sourcetex; // in case of redirection this is different from tex. - - FMaterial(FTexture *tex, bool forceexpand); - ~FMaterial(); - void SetSpriteRect(); + FGameTexture *sourcetex; // the owning texture. + + FMaterial(FGameTexture *tex, int scaleflags); + virtual ~FMaterial(); + int GetLayerFlags() const { return mLayerFlags; } int GetShaderIndex() const { return mShaderIndex; } - void AddTextureLayer(FTexture *tex) + int GetScaleFlags() const { return mScaleFlags; } + virtual void DeleteDescriptors() { } + + FGameTexture* Source() const { - ValidateTexture(tex, false); - mTextureLayers.Push(tex); - } - bool isMasked() const - { - return sourcetex->bMasked; - } - bool isExpanded() const - { - return mExpanded; + return sourcetex; } - int GetLayers() const + void AddTextureLayer(FTexture *tex, bool allowscale) { - return mTextureLayers.Size() + 1; - } - - bool hasCanvas() - { - return tex->isHardwareCanvas(); + mTextureLayers.Push({ tex, allowscale }); } - IHardwareTexture *GetLayer(int i, int translation, FTexture **pLayer = nullptr); - - // Patch drawing utilities - - void GetSpriteRect(FloatRect * r) const + int NumLayers() const { - *r = mSpriteRect; + return mTextureLayers.Size(); } - // This is scaled size in integer units as needed by walls and flats - int TextureHeight() const { return mRenderHeight; } - int TextureWidth() const { return mRenderWidth; } - - int GetAreas(FloatRect **pAreas) const; - - int GetWidth() const - { - return mWidth; - } - - int GetHeight() const - { - return mHeight; - } - - int GetLeftOffset() const - { - return mLeftOffset; - } - - int GetTopOffset() const - { - return mTopOffset; - } - - // Get right/bottom UV coordinates for patch drawing - float GetUL() const { return 0; } - float GetVT() const { return 0; } - float GetUR() const { return 1; } - float GetVB() const { return 1; } - float GetU(float upix) const { return upix/(float)mWidth; } - float GetV(float vpix) const { return vpix/(float)mHeight; } - - float GetSpriteUL() const { return mSpriteU[0]; } - float GetSpriteVT() const { return mSpriteV[0]; } - float GetSpriteUR() const { return mSpriteU[1]; } - float GetSpriteVB() const { return mSpriteV[1]; } + IHardwareTexture *GetLayer(int i, int translation, MaterialLayerInfo **pLayer = nullptr) const; - static FMaterial *ValidateTexture(FTexture * tex, bool expand, bool create = true); - static FMaterial *ValidateTexture(FTextureID no, bool expand, bool trans, bool create = true); - const TArray &GetLayerArray() const + static FMaterial *ValidateTexture(FGameTexture * tex, int scaleflags, bool create = true); + const TArray &GetLayerArray() const { return mTextureLayers; } diff --git a/source/common/textures/hw_texcontainer.h b/source/common/textures/hw_texcontainer.h index 9292fb7dd..c75d42278 100644 --- a/source/common/textures/hw_texcontainer.h +++ b/source/common/textures/hw_texcontainer.h @@ -7,6 +7,15 @@ struct FTextureBuffer; class IHardwareTexture; +enum ECreateTexBufferFlags +{ + CTF_Expand = 1, // create buffer with a one-pixel wide border + CTF_Upscale = 2, // Upscale the texture + CTF_CreateMask = 3, // Flags that are relevant for hardware texture creation. + CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture. + CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures. +}; + class FHardwareTextureContainer { public: @@ -20,6 +29,7 @@ private: { IHardwareTexture *hwTexture = nullptr; int translation = 0; + bool precacheMarker; // This is used to check whether a texture has been hit by the precacher, so that the cleanup code can delete the unneeded ones. void Delete() { @@ -27,23 +37,28 @@ private: hwTexture = nullptr; } - void DeleteDescriptors() - { - if (hwTexture) hwTexture->DeleteDescriptors(); - } - ~TranslatedTexture() { Delete(); } + + void MarkForPrecache(bool on) + { + precacheMarker = on; + } + + bool isMarkedForPreache() const + { + return precacheMarker; + } }; private: - TranslatedTexture hwDefTex[2]; + TranslatedTexture hwDefTex[4]; TArray hwTex_Translated; - TranslatedTexture * GetTexID(int translation, bool expanded) + TranslatedTexture * GetTexID(int translation, int scaleflags) { // Allow negative indices to pass through unchanged. // This is needed for allowing the client to allocate slots that aren't matched to a palette, e.g. Build's indexed variants. @@ -54,12 +69,12 @@ private: } else translation &= ~0x7fffffff; - if (translation == 0) + if (translation == 0 && !(scaleflags & CTF_Upscale)) { - return &hwDefTex[expanded]; + return &hwDefTex[scaleflags]; } - if (expanded) translation = -translation; + translation |= (scaleflags << 24); // normally there aren't more than very few different // translations here so this isn't performance critical. unsigned index = hwTex_Translated.FindEx([=](auto &element) @@ -78,32 +93,22 @@ private: } public: - - void Clean(bool cleannormal, bool cleanexpanded) + void Clean() { - if (cleannormal) hwDefTex[0].Delete(); - if (cleanexpanded) hwDefTex[1].Delete(); - hwDefTex[0].DeleteDescriptors(); - hwDefTex[1].DeleteDescriptors(); - for (int i = hwTex_Translated.Size() - 1; i >= 0; i--) - { - if (cleannormal && hwTex_Translated[i].translation > 0) hwTex_Translated.Delete(i); - else if (cleanexpanded && hwTex_Translated[i].translation < 0) hwTex_Translated.Delete(i); - - for (unsigned int j = 0; j < hwTex_Translated.Size(); j++) - hwTex_Translated[j].DeleteDescriptors(); - } + hwDefTex[0].Delete(); + hwDefTex[1].Delete(); + hwTex_Translated.Clear(); } - IHardwareTexture * GetHardwareTexture(int translation, bool expanded) + IHardwareTexture * GetHardwareTexture(int translation, int scaleflags) { - auto tt = GetTexID(translation, expanded); + auto tt = GetTexID(translation, scaleflags); return tt->hwTexture; } - void AddHardwareTexture(int translation, bool expanded, IHardwareTexture *tex) + void AddHardwareTexture(int translation, int scaleflags, IHardwareTexture *tex) { - auto tt = GetTexID(translation, expanded); + auto tt = GetTexID(translation, scaleflags); tt->Delete(); tt->hwTexture =tex; } @@ -111,26 +116,44 @@ public: //=========================================================================== // // Deletes all allocated resources and considers translations - // This will only be called for sprites // //=========================================================================== - void CleanUnused(SpriteHits &usedtranslations, bool expanded) + void CleanUnused() { - if (usedtranslations.CheckKey(0) == nullptr) + for (auto& tt : hwDefTex) { - hwDefTex[expanded].Delete(); + if (!tt.isMarkedForPreache()) tt.Delete(); } - int fac = expanded ? -1 : 1; for (int i = hwTex_Translated.Size()-1; i>= 0; i--) { - if (usedtranslations.CheckKey(hwTex_Translated[i].translation * fac) == nullptr) + auto& tt = hwTex_Translated[i]; + if (!tt.isMarkedForPreache()) { hwTex_Translated.Delete(i); } } } - + + void UnmarkAll() + { + for (auto& tt : hwDefTex) + { + if (!tt.isMarkedForPreache()) tt.MarkForPrecache(false); + } + for (auto& tt : hwTex_Translated) + { + if (!tt.isMarkedForPreache()) tt.MarkForPrecache(false); + } + } + + void MarkForPrecache(int translation, int scaleflags) + { + auto tt = GetTexID(translation, scaleflags); + tt->MarkForPrecache(true); + } + + template void Iterate(T callback) { diff --git a/source/common/textures/image.cpp b/source/common/textures/image.cpp index ef40efd19..d68db329d 100644 --- a/source/common/textures/image.cpp +++ b/source/common/textures/image.cpp @@ -41,7 +41,7 @@ #include "cmdlib.h" #include "palettecontainer.h" -FMemArena FImageSource::ImageArena(32768); +FMemArena ImageArena(32768); TArrayFImageSource::ImageForLump; int FImageSource::NextID; static PrecacheInfo precacheInfo; diff --git a/source/common/textures/image.h b/source/common/textures/image.h index 1f6fcb5fa..6ddd34bc2 100644 --- a/source/common/textures/image.h +++ b/source/common/textures/image.h @@ -7,6 +7,7 @@ class FImageSource; using PrecacheInfo = TMap>; +extern FMemArena ImageArena; // Doom patch format header struct patch_t @@ -38,7 +39,6 @@ class FImageSource friend class FBrightmapTexture; protected: - static FMemArena ImageArena; static TArrayImageForLump; static int NextID; @@ -57,6 +57,8 @@ protected: public: + virtual bool SupportRemap0() { return false; } // Unfortunate hackery that's needed for Hexen's skies. Only the image can know about the needed parameters + virtual bool IsRawCompatible() { return true; } // Same thing for mid texture compatibility handling. Can only be determined by looking at the composition data which is private to the image. void CopySize(FImageSource &other) { @@ -169,4 +171,4 @@ protected: class FTexture; -FTexture* CreateImageTexture(FImageSource* img, const char *name = nullptr) noexcept; +FTexture* CreateImageTexture(FImageSource* img) noexcept; diff --git a/source/common/textures/imagetexture.cpp b/source/common/textures/imagetexture.cpp index 805cb64ca..2efc943ae 100644 --- a/source/common/textures/imagetexture.cpp +++ b/source/common/textures/imagetexture.cpp @@ -47,25 +47,25 @@ // //========================================================================== -FImageTexture::FImageTexture(FImageSource* img, const char* name) noexcept - : FTexture(name, img ? img->LumpNum() : 0) +FImageTexture::FImageTexture(FImageSource *img) noexcept +: FTexture(img? img->LumpNum() : 0) { mImage = img; if (img != nullptr) { - if (name == nullptr) fileSystem.GetFileShortName(Name, img->LumpNum()); - Width = img->GetWidth(); - Height = img->GetHeight(); - - auto offsets = img->GetOffsets(); - _LeftOffset[1] = _LeftOffset[0] = offsets.first; - _TopOffset[1] = _TopOffset[0] = offsets.second; - - bMasked = img->bMasked; - bTranslucent = img->bTranslucent; + SetFromImage(); } } +void FImageTexture::SetFromImage() +{ + auto img = mImage; + Width = img->GetWidth(); + Height = img->GetHeight(); + + Masked = img->bMasked; + bTranslucent = img->bTranslucent; +} //=========================================================================== // // @@ -108,8 +108,8 @@ bool FImageTexture::DetermineTranslucency() } -FTexture* CreateImageTexture(FImageSource* img, const char* name) noexcept +FTexture* CreateImageTexture(FImageSource* img) noexcept { - return new FImageTexture(img, name); + return new FImageTexture(img); } diff --git a/source/common/textures/m_png.h b/source/common/textures/m_png.h index 12e6d5adf..2f52a1fcf 100644 --- a/source/common/textures/m_png.h +++ b/source/common/textures/m_png.h @@ -119,8 +119,8 @@ bool M_ReadIDAT (FileReader &file, uint8_t *buffer, int width, int height, int p uint8_t bitdepth, uint8_t colortype, uint8_t interlace, unsigned int idatlen); -class FTexture; +class FGameTexture; -FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename); +FGameTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename); #endif diff --git a/source/common/textures/multipatchtexturebuilder.cpp b/source/common/textures/multipatchtexturebuilder.cpp index 3380968b0..d95c681dc 100644 --- a/source/common/textures/multipatchtexturebuilder.cpp +++ b/source/common/textures/multipatchtexturebuilder.cpp @@ -57,7 +57,6 @@ #endif - //-------------------------------------------------------------------------- // // Data structures for the TEXTUREx lumps @@ -85,7 +84,7 @@ struct mappatch_t struct maptexture_t { uint8_t name[8]; - uint16_t Flags; // [RH] Was unused + uint16_t Flags; // [RH] Was unused uint8_t ScaleX; // [RH] Scaling (8 is normal) uint8_t ScaleY; // [RH] Same as above int16_t width; @@ -113,7 +112,7 @@ struct strifemappatch_t struct strifemaptexture_t { uint8_t name[8]; - uint16_t Flags; // [RH] Was unused + uint16_t Flags; // [RH] Was unused uint8_t ScaleX; // [RH] Scaling (8 is normal) uint8_t ScaleY; // [RH] Same as above int16_t width; @@ -137,25 +136,23 @@ struct FPatchLookup void FMultipatchTextureBuilder::MakeTexture(BuildInfo &buildinfo, ETextureType usetype) { - FImageTexture *tex = new FImageTexture(nullptr, buildinfo.Name); - tex->SetUseType(usetype); - tex->bMultiPatch = true; - tex->Width = buildinfo.Width; - tex->Height = buildinfo.Height; - tex->_LeftOffset[0] = buildinfo.LeftOffset[0]; - tex->_LeftOffset[1] = buildinfo.LeftOffset[1]; - tex->_TopOffset[0] = buildinfo.TopOffset[0]; - tex->_TopOffset[1] = buildinfo.TopOffset[1]; - tex->Scale = buildinfo.Scale; - tex->bMasked = true; // we do not really know yet. - tex->bTranslucent = -1; - tex->bWorldPanning = buildinfo.bWorldPanning; - tex->bNoDecals = buildinfo.bNoDecals; - tex->SourceLump = buildinfo.DefinitionLump; - buildinfo.tex = tex; - TexMan.AddTexture(tex); + buildinfo.texture = new FGameTexture(nullptr, buildinfo.Name); + buildinfo.texture->SetUseType(usetype); + TexMan.AddGameTexture(buildinfo.texture); } +void FMultipatchTextureBuilder::AddImageToTexture(FImageTexture *tex, BuildInfo& buildinfo) +{ + buildinfo.texture->Setup(tex); + buildinfo.texture->SetOffsets(0, buildinfo.LeftOffset[0], buildinfo.TopOffset[0]); + buildinfo.texture->SetOffsets(1, buildinfo.LeftOffset[1], buildinfo.TopOffset[1]); + buildinfo.texture->SetScale((float)buildinfo.Scale.X, (float)buildinfo.Scale.X); + buildinfo.texture->SetWorldPanning(buildinfo.bWorldPanning); + buildinfo.texture->SetNoDecals(buildinfo.bNoDecals); + calcShouldUpscale(buildinfo.texture); // calculate this once at insertion +} + + //========================================================================== // // The reader for TEXTUREx @@ -238,7 +235,7 @@ void FMultipatchTextureBuilder::BuildTexture(const void *texdef, FPatchLookup *p } buildinfo.Parts[i].OriginX = LittleShort(mpatch.d->originx); buildinfo.Parts[i].OriginY = LittleShort(mpatch.d->originy); - buildinfo.Parts[i].Image = nullptr; + buildinfo.Parts[i].TexImage = nullptr; buildinfo.Inits[i].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name; buildinfo.Inits[i].UseType = ETextureType::WallPatch; if (strife) @@ -356,7 +353,7 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi // It still needs to be created in case someone uses it by name. offset = LittleLong(directory[1]); const maptexture_t *tex = (const maptexture_t *)((const uint8_t *)maptex + offset); - FTexture *tex0 = TexMan.ByIndex(0); + auto tex0 = TexMan.GameByIndex(0); tex0->SetSize(SAFESHORT(tex->width), SAFESHORT(tex->height)); } @@ -373,7 +370,7 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi int j; for (j = (int)TexMan.NumTextures() - 1; j >= firstdup; --j) { - if (strnicmp(TexMan.ByIndex(j)->GetName(), (const char *)maptex + offset, 8) == 0) + if (strnicmp(TexMan.GameByIndex(j)->GetName(), (const char *)maptex + offset, 8) == 0) break; } if (j + 1 == firstdup) @@ -420,7 +417,7 @@ void FMultipatchTextureBuilder::AddTexturesLumps(int lump1, int lump2, int patch // //========================================================================== -void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPart & part, TexInit &init) +void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPartBuild & part, TexInit &init) { FString patchname; int Mirror = 0; @@ -672,7 +669,7 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) } else if (sc.Compare("Patch")) { - TexPart part; + TexPartBuild part; TexInit init; ParsePatch(sc, buildinfo, part, init); if (init.TexName.IsNotEmpty()) @@ -684,12 +681,12 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) init.sc = sc; buildinfo.Inits.Push(init); } - part.Image = nullptr; + part.TexImage = nullptr; part.Translation = nullptr; } else if (sc.Compare("Sprite")) { - TexPart part; + TexPartBuild part; TexInit init; ParsePatch(sc, buildinfo, part, init); if (init.TexName.IsNotEmpty()) @@ -701,12 +698,12 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) init.sc = sc; buildinfo.Inits.Push(init); } - part.Image = nullptr; + part.TexImage = nullptr; part.Translation = nullptr; } else if (sc.Compare("Graphic")) { - TexPart part; + TexPartBuild part; TexInit init; ParsePatch(sc, buildinfo, part, init); if (init.TexName.IsNotEmpty()) @@ -718,7 +715,7 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) init.sc = sc; buildinfo.Inits.Push(init); } - part.Image = nullptr; + part.TexImage = nullptr; part.Translation = nullptr; } else if (sc.Compare("Offset")) @@ -774,19 +771,23 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo) for (unsigned i = 0; i < buildinfo.Inits.Size(); i++) { FTextureID texno = TexMan.CheckForTexture(buildinfo.Inits[i].TexName, buildinfo.Inits[i].UseType); - if (texno == buildinfo.tex->id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. + if (texno == buildinfo.texture->GetID()) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. { TArray list; TexMan.ListTextures(buildinfo.Inits[i].TexName, list, true); for (int i = list.Size() - 1; i >= 0; i--) { - if (list[i] != buildinfo.tex->id && !TexMan.GetTexture(list[i])->bMultiPatch) + if (list[i] != buildinfo.texture->GetID()) { - texno = list[i]; + auto gtex = TexMan.GetGameTexture(list[i]); + if (gtex && !dynamic_cast(gtex->GetTexture())) + { + texno = list[i]; + } break; } } - if (texno == buildinfo.tex->id) + if (texno == buildinfo.texture->GetID()) { if (buildinfo.Inits[i].HasLine) buildinfo.Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", buildinfo.Inits[i].TexName.GetChars()); else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", buildinfo.Inits[i].TexName.GetChars()); @@ -809,18 +810,19 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo) } else { - FTexture *tex = TexMan.GetTexture(texno); + FGameTexture *tex = TexMan.GetGameTexture(texno); - if (tex != nullptr && tex->isValid()) + if (tex != nullptr && tex->isValid() && dynamic_cast(tex->GetTexture())) { //We cannot set the image source yet. First all textures need to be resolved. - buildinfo.Inits[i].Texture = tex; - buildinfo.tex->bComplex |= tex->bComplex; - buildinfo.bComplex |= tex->bComplex; + buildinfo.Inits[i].Texture = static_cast(tex->GetTexture()); + bool iscomplex = !!complex.CheckKey(tex); + if (iscomplex) complex.Insert(buildinfo.texture, true); + buildinfo.bComplex |= iscomplex; if (buildinfo.Inits[i].UseOffsets) { - buildinfo.Parts[i].OriginX -= tex->GetLeftOffset(0); - buildinfo.Parts[i].OriginY -= tex->GetTopOffset(0); + buildinfo.Parts[i].OriginX -= tex->GetTexelLeftOffset(0); + buildinfo.Parts[i].OriginY -= tex->GetTexelTopOffset(0); } } else @@ -841,8 +843,6 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo) i--; } } - - checkForHacks(buildinfo); } void FMultipatchTextureBuilder::ResolveAllPatches() @@ -874,12 +874,12 @@ void FMultipatchTextureBuilder::ResolveAllPatches() for (unsigned j = 0; j < buildinfo.Inits.Size(); j++) { - if (buildinfo.Parts[j].Image == nullptr) + if (buildinfo.Parts[j].TexImage == nullptr) { - auto image = buildinfo.Inits[j].Texture->GetImage(); - if (image != nullptr) + auto image = buildinfo.Inits[j].Texture; + if (image->GetImage() != nullptr) { - buildinfo.Parts[j].Image = image; + buildinfo.Parts[j].TexImage = image; donesomething = true; } else hasEmpty = true; @@ -889,26 +889,28 @@ void FMultipatchTextureBuilder::ResolveAllPatches() { // If this texture is just a wrapper around a single patch, we can simply // use that patch's image directly here. + checkForHacks(buildinfo); bool done = false; if (buildinfo.Parts.Size() == 1) { if (buildinfo.Parts[0].OriginX == 0 && buildinfo.Parts[0].OriginY == 0 && - buildinfo.Parts[0].Image->GetWidth() == buildinfo.Width && - buildinfo.Parts[0].Image->GetHeight() == buildinfo.Height && + buildinfo.Parts[0].TexImage->GetWidth() == buildinfo.Width && + buildinfo.Parts[0].TexImage->GetHeight() == buildinfo.Height && buildinfo.Parts[0].Rotate == 0 && !buildinfo.bComplex) { - buildinfo.tex->SetImage(buildinfo.Parts[0].Image); + AddImageToTexture(buildinfo.Parts[0].TexImage, buildinfo); + buildinfo.texture->Setup(buildinfo.Parts[0].TexImage); done = true; } } if (!done) { auto img = new FMultiPatchTexture(buildinfo.Width, buildinfo.Height, buildinfo.Parts, buildinfo.bComplex, buildinfo.textual); - buildinfo.tex->SetImage(img); + auto itex = new FImageTexture(img); + AddImageToTexture(itex, buildinfo); } - BuiltTextures.Delete(i); donesomething = true; } @@ -919,7 +921,7 @@ void FMultipatchTextureBuilder::ResolveAllPatches() for (auto &b : BuiltTextures) { Printf("%s\n", b.Name.GetChars()); - b.tex->SetUseType(ETextureType::Null); + b.texture->SetUseType(ETextureType::Null); } break; } diff --git a/source/common/textures/skyboxtexture.cpp b/source/common/textures/skyboxtexture.cpp index a1df3a9b1..486bd1a4d 100644 --- a/source/common/textures/skyboxtexture.cpp +++ b/source/common/textures/skyboxtexture.cpp @@ -47,18 +47,15 @@ //----------------------------------------------------------------------------- FSkyBox::FSkyBox(const char *name) -: FTexture(name) + : FImageTexture(nullptr) { FTextureID texid = TexMan.CheckForTexture(name, ETextureType::Wall); - previous = nullptr; if (texid.isValid()) { - previous = TexMan.GetTexture(texid); - CopySize(previous); + previous = TexMan.GetGameTexture(texid); } + else previous = nullptr; faces[0]=faces[1]=faces[2]=faces[3]=faces[4]=faces[5] = nullptr; - UseType = ETextureType::Override; - bSkybox = true; fliptop = false; } @@ -68,29 +65,11 @@ FSkyBox::FSkyBox(const char *name) // //----------------------------------------------------------------------------- -TArray FSkyBox::Get8BitPixels(bool alphatex) +void FSkyBox::SetSize() { - return previous->Get8BitPixels(alphatex); -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -FBitmap FSkyBox::GetBgraBitmap(const PalEntry *p, int *trans) -{ - return previous->GetBgraBitmap(p, trans); -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -FImageSource *FSkyBox::GetImage() const -{ - return previous->GetImage(); + if (!previous && faces[0]) previous = faces[0]; + if (previous && previous->GetTexture()->GetImage()) + { + SetImage(previous->GetTexture()->GetImage()); + } } diff --git a/source/common/textures/skyboxtexture.h b/source/common/textures/skyboxtexture.h index 07a75f1e8..645e54b93 100644 --- a/source/common/textures/skyboxtexture.h +++ b/source/common/textures/skyboxtexture.h @@ -1,35 +1,24 @@ #pragma once #include "textures.h" + //----------------------------------------------------------------------------- // -// This is not a real texture but will be added to the texture manager -// so that it can be handled like any other sky. +// Todo: Get rid of this +// The faces can easily be stored in the material layer array // //----------------------------------------------------------------------------- -class FSkyBox : public FTexture +class FSkyBox : public FImageTexture { public: - FTexture *previous; - FTexture * faces[6]; + FGameTexture* previous; + FGameTexture* faces[6]; // the faces need to be full materials as they can have all supported effects. bool fliptop; - FSkyBox(const char *name); - TArray Get8BitPixels(bool alphatex); - FBitmap GetBgraBitmap(const PalEntry *, int *trans) override; - FImageSource *GetImage() const override; - - - void SetSize() - { - if (!previous && faces[0]) previous = faces[0]; - if (previous) - { - CopySize(previous); - } - } + FSkyBox(const char* name); + void SetSize(); bool Is3Face() const { @@ -40,4 +29,14 @@ public: { return fliptop; } + + FGameTexture* GetSkyFace(int num) const + { + return faces[num]; + } + + bool GetSkyFlip() const + { + return fliptop; + } }; diff --git a/source/common/textures/texture.cpp b/source/common/textures/texture.cpp index 37dd68da7..016ac4fec 100644 --- a/source/common/textures/texture.cpp +++ b/source/common/textures/texture.cpp @@ -47,123 +47,24 @@ #include "image.h" #include "formats/multipatchtexture.h" #include "texturemanager.h" +#include "c_cvars.h" // Wrappers to keep the definitions of these classes out of here. -void DeleteMaterial(FMaterial* mat); -void DeleteSoftwareTexture(FSoftwareTexture* swtex); IHardwareTexture* CreateHardwareTexture(); - -FTexture* CreateBrightmapTexture(FImageSource*); - // Make sprite offset adjustment user-configurable per renderer. int r_spriteadjustSW, r_spriteadjustHW; -//========================================================================== -// -// -// -//========================================================================== - - -// Examines the lump contents to decide what type of texture to create, -// and creates the texture. -FTexture* FTexture::CreateTexture(const char* name, int lumpnum, ETextureType usetype) -{ - if (lumpnum == -1) return nullptr; - - auto image = FImageSource::GetImage(lumpnum, usetype == ETextureType::Flat); - if (image != nullptr) - { - FTexture* tex = new FImageTexture(image); - if (tex != nullptr) - { - tex->UseType = usetype; - if (usetype == ETextureType::Flat) - { - int w = tex->GetTexelWidth(); - int h = tex->GetTexelHeight(); - - // Auto-scale flats with dimensions 128x128 and 256x256. - // In hindsight, a bad idea, but RandomLag made it sound better than it really is. - // Now we're stuck with this stupid behaviour. - if (w == 128 && h == 128) - { - tex->Scale.X = tex->Scale.Y = 2; - tex->bWorldPanning = true; - } - else if (w == 256 && h == 256) - { - tex->Scale.X = tex->Scale.Y = 4; - tex->bWorldPanning = true; - } - } - tex->Name = name; - tex->Name.ToUpper(); - return tex; - } - } - return nullptr; -} - //========================================================================== // // // //========================================================================== -FTexture::FTexture(const char* name, int lumpnum) - : - Scale(1, 1), SourceLump(lumpnum), - UseType(ETextureType::Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false), - bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bFullNameTexture(false), - Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0) +FTexture::FTexture (int lumpnum) + : SourceLump(lumpnum), bHasCanvas(false) { - bBrightmapChecked = false; - bGlowing = false; - bAutoGlowing = false; - bFullbright = false; - bDisableFullbright = false; - bSkybox = false; - bNoCompress = false; - bNoExpand = false; bTranslucent = -1; - - - _LeftOffset[0] = _LeftOffset[1] = _TopOffset[0] = _TopOffset[1] = 0; - id.SetInvalid(); - if (name != NULL) - { - Name = name; - Name.ToUpper(); - } - else if (lumpnum < 0) - { - Name = FString(); - } - else - { - fileSystem.GetFileShortName(Name, lumpnum); - } -} - -FTexture::~FTexture() -{ - FTexture* link = fileSystem.GetLinkedTexture(SourceLump); - if (link == this) fileSystem.SetLinkedTexture(SourceLump, nullptr); - if (areas != nullptr) delete[] areas; - areas = nullptr; - - for (int i = 0; i < 2; i++) - { - if (Material[i] != nullptr) DeleteMaterial(Material[i]); - Material[i] = nullptr; - } - if (SoftwareTexture != nullptr) - { - DeleteSoftwareTexture(SoftwareTexture); - SoftwareTexture = nullptr; - } } //=========================================================================== @@ -182,111 +83,6 @@ FBitmap FTexture::GetBgraBitmap(const PalEntry* remap, int* ptrans) return bmp; } -//========================================================================== -// -// -// -//========================================================================== - -FTexture* FTexture::GetRawTexture() -{ - if (OffsetLess) return OffsetLess; - // Reject anything that cannot have been a single-patch multipatch texture in vanilla. - auto image = static_cast(GetImage()); - if (bMultiPatch != 1 || UseType != ETextureType::Wall || Scale.X != 1 || Scale.Y != 1 || bWorldPanning || image == nullptr || image->NumParts != 1 || _TopOffset[0] == 0) - { - OffsetLess = this; - return this; - } - // Set up a new texture that directly references the underlying patch. - // From here we cannot retrieve the original texture made for it, so just create a new one. - FImageSource* source = image->Parts[0].Image; - - // Size must match for this to work as intended - if (source->GetWidth() != Width || source->GetHeight() != Height) - { - OffsetLess = this; - return this; - } - - - OffsetLess = new FImageTexture(source, ""); - TexMan.AddTexture(OffsetLess); - return OffsetLess; -} - -void FTexture::SetDisplaySize(int fitwidth, int fitheight) -{ - Scale.X = double(Width) / fitwidth; - Scale.Y = double(Height) / fitheight; - // compensate for roundoff errors - if (int(Scale.X * fitwidth) != Width) Scale.X += (1 / 65536.); - if (int(Scale.Y * fitheight) != Height) Scale.Y += (1 / 65536.); -} - -//=========================================================================== -// -// Gets the average color of a texture for use as a sky cap color -// -//=========================================================================== - -PalEntry FTexture::averageColor(const uint32_t* data, int size, int maxout) -{ - int i; - unsigned int r, g, b; - - // First clear them. - r = g = b = 0; - if (size == 0) - { - return PalEntry(255, 255, 255); - } - for (i = 0; i < size; i++) - { - b += BPART(data[i]); - g += GPART(data[i]); - r += RPART(data[i]); - } - - r = r / size; - g = g / size; - b = b / size; - - int maxv = MAX(MAX(r, g), b); - - if (maxv && maxout) - { - r = ::Scale(r, maxout, maxv); - g = ::Scale(g, maxout, maxv); - b = ::Scale(b, maxout, maxv); - } - return PalEntry(255, r, g, b); -} - -PalEntry FTexture::GetSkyCapColor(bool bottom) -{ - if (!bSWSkyColorDone) - { - bSWSkyColorDone = true; - - FBitmap bitmap = GetBgraBitmap(nullptr); - int w = bitmap.GetWidth(); - int h = bitmap.GetHeight(); - - const uint32_t* buffer = (const uint32_t*)bitmap.GetPixels(); - if (buffer) - { - CeilingSkyColor = averageColor((uint32_t*)buffer, w * MIN(30, h), 0); - if (h > 30) - { - FloorSkyColor = averageColor(((uint32_t*)buffer) + (h - 30) * w, w * 30, 0); - } - else FloorSkyColor = CeilingSkyColor; - } - } - return bottom ? FloorSkyColor : CeilingSkyColor; -} - //==================================================================== // // CheckRealHeight @@ -299,16 +95,13 @@ PalEntry FTexture::GetSkyCapColor(bool bottom) int FTexture::CheckRealHeight() { auto pixels = Get8BitPixels(false); - - for (int h = GetTexelHeight() - 1; h >= 0; h--) + + for(int h = GetHeight()-1; h>= 0; h--) { - for (int w = 0; w < GetTexelWidth(); w++) + for(int w = 0; w < GetWidth(); w++) { - if (pixels[h + w * GetTexelHeight()] != 0) + if (pixels[h + w * GetHeight()] != 0) { - // Scale maxy before returning it - h = int((h * 2) / Scale.Y); - h = (h >> 1) + (h & 1); return h; } } @@ -316,127 +109,6 @@ int FTexture::CheckRealHeight() return 0; } -//========================================================================== -// -// Search auto paths for extra material textures -// -//========================================================================== - -void FTexture::AddAutoMaterials() -{ - struct AutoTextureSearchPath - { - const char* path; - FTexture* FTexture::* pointer; - }; - - static AutoTextureSearchPath autosearchpaths[] = - { - { "brightmaps/", &FTexture::Brightmap }, // For backwards compatibility, only for short names - { "materials/brightmaps/", &FTexture::Brightmap }, - { "materials/normalmaps/", &FTexture::Normal }, - { "materials/specular/", &FTexture::Specular }, - { "materials/metallic/", &FTexture::Metallic }, - { "materials/roughness/", &FTexture::Roughness }, - { "materials/ao/", &FTexture::AmbientOcclusion } - }; - - - int startindex = bFullNameTexture ? 1 : 0; - FString searchname = Name; - - if (bFullNameTexture) - { - auto dot = searchname.LastIndexOf('.'); - auto slash = searchname.LastIndexOf('/'); - if (dot > slash) searchname.Truncate(dot); - } - - for (size_t i = 0; i < countof(autosearchpaths); i++) - { - auto& layer = autosearchpaths[i]; - if (this->*(layer.pointer) == nullptr) // only if no explicit assignment had been done. - { - FStringf lookup("%s%s%s", layer.path, bFullNameTexture ? "" : "auto/", searchname.GetChars()); - auto lump = fileSystem.CheckNumForFullName(lookup, false, ns_global, true); - if (lump != -1) - { - auto bmtex = TexMan.FindTexture(fileSystem.GetFileFullName(lump), ETextureType::Any, FTextureManager::TEXMAN_TryAny); - if (bmtex != nullptr) - { - bmtex->bMasked = false; - this->*(layer.pointer) = bmtex; - } - } - } - } -} - -//=========================================================================== -// -// Checks if the texture has a default brightmap and creates it if so -// -//=========================================================================== -void FTexture::CreateDefaultBrightmap() -{ - if (!bBrightmapChecked) - { - // Check for brightmaps - if (GetImage() && GetImage()->UseGamePalette() && GPalette.HasGlobalBrightmap && - UseType != ETextureType::Decal && UseType != ETextureType::MiscPatch && UseType != ETextureType::FontChar && - Brightmap == NULL && bWarped == 0) - { - // May have one - let's check when we use this texture - auto texbuf = Get8BitPixels(false); - const int white = ColorMatcher.Pick(255, 255, 255); - - int size = GetTexelWidth() * GetTexelHeight(); - for (int i = 0; i < size; i++) - { - if (GPalette.GlobalBrightmap.Remap[texbuf[i]] == white) - { - // Create a brightmap - DPrintf(DMSG_NOTIFY, "brightmap created for texture '%s'\n", Name.GetChars()); - Brightmap = CreateBrightmapTexture(static_cast(this)->GetImage()); - bBrightmapChecked = true; - TexMan.AddTexture(Brightmap); - return; - } - } - // No bright pixels found - DPrintf(DMSG_SPAMMY, "No bright pixels found in texture '%s'\n", Name.GetChars()); - bBrightmapChecked = true; - } - else - { - // does not have one so set the flag to 'done' - bBrightmapChecked = true; - } - } -} - - -//========================================================================== -// -// Calculates glow color for a texture -// -//========================================================================== - -void FTexture::GetGlowColor(float* data) -{ - if (bGlowing && GlowColor == 0) - { - auto buffer = GetBgraBitmap(nullptr); - GlowColor = averageColor((uint32_t*)buffer.GetPixels(), buffer.GetWidth() * buffer.GetHeight(), 153); - - // Black glow equals nothing so switch glowing off - if (GlowColor == 0) bGlowing = false; - } - data[0] = GlowColor.r / 255.0f; - data[1] = GlowColor.g / 255.0f; - data[2] = GlowColor.b / 255.0f; -} - //=========================================================================== // // Finds gaps in the texture which can be skipped by the renderer @@ -455,11 +127,10 @@ bool FTexture::FindHoles(const unsigned char* buffer, int w, int h) // already done! if (areacount) return false; - if (UseType == ETextureType::Flat) return false; // flats don't have transparent parts areacount = -1; //whatever happens next, it shouldn't be done twice! - // large textures are excluded for performance reasons - if (h > 512) return false; + // large textures and non-images are excluded for performance reasons + if (h>512 || !GetImage()) return false; startdraw = -1; lendraw = 0; @@ -510,7 +181,7 @@ bool FTexture::FindHoles(const unsigned char* buffer, int w, int h) if (gapc > 0) { - FloatRect* rcs = new FloatRect[gapc]; + FloatRect* rcs = (FloatRect*)ImageArena.Alloc(gapc * sizeof(FloatRect)); // allocate this on the image arena for (x = 0; x < gapc; x++) { @@ -635,10 +306,10 @@ bool FTexture::SmoothEdges(unsigned char* buffer, int w, int h) bool FTexture::ProcessData(unsigned char* buffer, int w, int h, bool ispatch) { - if (bMasked) + if (Masked) { - bMasked = SmoothEdges(buffer, w, h); - if (bMasked && !ispatch) FindHoles(buffer, w, h); + Masked = SmoothEdges(buffer, w, h); + if (Masked && !ispatch) FindHoles(buffer, w, h); } return true; } @@ -660,8 +331,8 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) int exx = !!(flags & CTF_Expand); - W = GetTexelWidth() + 2 * exx; - H = GetTexelHeight() + 2 * exx; + W = GetWidth() + 2 * exx; + H = GetHeight() + 2 * exx; if (!checkonly) { @@ -669,6 +340,7 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) memset(buffer, 0, W * (H + 1) * 4); auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation); + if (remap) translation = remap->Index; FBitmap bmp(buffer, W * 4, W, H); int trans; @@ -705,10 +377,8 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) // Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.) if (GetImage() && flags & CTF_ProcessData) { -#pragma message("Activate me") -#if 0 - CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly); -#endif + if (flags & CTF_Upscale) CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly); + if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false); } @@ -723,15 +393,8 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) bool FTexture::DetermineTranslucency() { - if (!bHasCanvas) - { // This will calculate all we need, so just discard the result. CreateTexBuffer(0); - } - else - { - bTranslucent = 0; - } return !!bTranslucent; } @@ -749,101 +412,114 @@ TArray FTexture::Get8BitPixels(bool alphatex) } //=========================================================================== -// -// Coordinate helper. -// The only reason this is even needed is that many years ago someone -// was convinced that having per-texel panning on walls was a good idea. -// If it wasn't for this relatively useless feature the entire positioning -// code for wall textures could be a lot simpler. -// -//=========================================================================== - -//=========================================================================== -// // +// Finds empty space around the texture. +// Used for sprites that got placed into a huge empty frame. // //=========================================================================== -float FTexCoordInfo::RowOffset(float rowoffset) const +bool FTexture::TrimBorders(uint16_t* rect) { - float scale = fabs(mScale.Y); - if (scale == 1.f || mWorldPanning) return rowoffset; - else return rowoffset / scale; + + auto texbuffer = CreateTexBuffer(0); + int w = texbuffer.mWidth; + int h = texbuffer.mHeight; + auto Buffer = texbuffer.mBuffer; + + if (texbuffer.mBuffer == nullptr) + { + return false; + } + if (w != Width || h != Height) + { + // external Hires replacements cannot be trimmed. + return false; + } + + int size = w * h; + if (size == 1) + { + // nothing to be done here. + rect[0] = 0; + rect[1] = 0; + rect[2] = 1; + rect[3] = 1; + return true; + } + int first, last; + + for (first = 0; first < size; first++) + { + if (Buffer[first * 4 + 3] != 0) break; + } + if (first >= size) + { + // completely empty + rect[0] = 0; + rect[1] = 0; + rect[2] = 1; + rect[3] = 1; + return true; + } + + for (last = size - 1; last >= first; last--) + { + if (Buffer[last * 4 + 3] != 0) break; + } + + rect[1] = first / w; + rect[3] = 1 + last / w - rect[1]; + + rect[0] = 0; + rect[2] = w; + + unsigned char* bufferoff = Buffer + (rect[1] * w * 4); + h = rect[3]; + + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + if (bufferoff[(x + y * w) * 4 + 3] != 0) goto outl; + } + rect[0]++; + } +outl: + rect[2] -= rect[0]; + + for (int x = w - 1; rect[2] > 1; x--) + { + for (int y = 0; y < h; y++) + { + if (bufferoff[(x + y * w) * 4 + 3] != 0) + { + return true; + } + } + rect[2]--; + } + return true; } //=========================================================================== // -// +// Create a hardware texture for this texture image. // //=========================================================================== -float FTexCoordInfo::TextureOffset(float textureoffset) const +IHardwareTexture* FTexture::GetHardwareTexture(int translation, int scaleflags) { - float scale = fabs(mScale.X); - if (scale == 1.f || mWorldPanning) return textureoffset; - else return textureoffset / scale; -} - -//=========================================================================== -// -// Returns the size for which texture offset coordinates are used. -// -//=========================================================================== - -float FTexCoordInfo::TextureAdjustWidth() const -{ - if (mWorldPanning) + //if (UseType != ETextureType::Null) { - float tscale = fabs(mTempScale.X); - if (tscale == 1.f) return (float)mRenderWidth; - else return mWidth / fabs(tscale); - } - else return (float)mWidth; -} - - -//=========================================================================== -// -// Retrieve texture coordinate info for per-wall scaling -// -//=========================================================================== - -void FTexCoordInfo::GetFromTexture(FTexture* tex, float x, float y, bool forceworldpanning) -{ - if (x == 1.f) + IHardwareTexture* hwtex = SystemTextures.GetHardwareTexture(translation, scaleflags); + if (hwtex == nullptr) { - mRenderWidth = tex->GetScaledWidth(); - mScale.X = (float)tex->Scale.X; - mTempScale.X = 1.f; + hwtex = CreateHardwareTexture(); + SystemTextures.AddHardwareTexture(translation, scaleflags, hwtex); } - else - { - float scale_x = x * (float)tex->Scale.X; - mRenderWidth = xs_CeilToInt(tex->GetTexelWidth() / scale_x); - mScale.X = scale_x; - mTempScale.X = x; + return hwtex; } - - if (y == 1.f) - { - mRenderHeight = tex->GetScaledHeight(); - mScale.Y = (float)tex->Scale.Y; - mTempScale.Y = 1.f; - } - else - { - float scale_y = y * (float)tex->Scale.Y; - mRenderHeight = xs_CeilToInt(tex->GetTexelHeight() / scale_y); - mScale.Y = scale_y; - mTempScale.Y = y; - } - if (tex->bHasCanvas) - { - mScale.Y = -mScale.Y; - mRenderHeight = -mRenderHeight; - } - mWorldPanning = tex->bWorldPanning || forceworldpanning; - mWidth = tex->GetTexelWidth(); + return nullptr; } @@ -858,8 +534,7 @@ FWrapperTexture::FWrapperTexture(int w, int h, int bits) Width = w; Height = h; Format = bits; - UseType = ETextureType::SWCanvas; - bNoCompress = true; + //bNoCompress = true; auto hwtex = CreateHardwareTexture(); // todo: Initialize here. SystemTextures.AddHardwareTexture(0, false, hwtex); diff --git a/source/common/textures/textureid.h b/source/common/textures/textureid.h index ce41b9058..5d2b7d726 100644 --- a/source/common/textures/textureid.h +++ b/source/common/textures/textureid.h @@ -17,7 +17,7 @@ enum class ETextureType : uint8_t SkinGraphic, Null, FirstDefined, - Canvas, + Special, SWCanvas, }; diff --git a/source/common/textures/texturemanager.cpp b/source/common/textures/texturemanager.cpp index 66a196a31..a94a1592a 100644 --- a/source/common/textures/texturemanager.cpp +++ b/source/common/textures/texturemanager.cpp @@ -103,15 +103,14 @@ void FTextureManager::DeleteAll() //========================================================================== // // Flushes all hardware dependent data. -// Thia must not, under any circumstances, delete the wipe textures, because +// This must not, under any circumstances, delete the wipe textures, because // all CCMDs triggering a flush can be executed while a wipe is in progress // // This now also deletes the software textures because having the software -// renderer use the texture scalers is a planned feature and that is the +// renderer can also use the texture scalers and that is the // main reason to call this outside of the destruction code. // //========================================================================== -void DeleteSoftwareTexture(FSoftwareTexture* swtex); void FTextureManager::FlushAll() { @@ -119,13 +118,33 @@ void FTextureManager::FlushAll() { for (int j = 0; j < 2; j++) { - Textures[i].Texture->SystemTextures.Clean(true, true); - DeleteSoftwareTexture(Textures[i].Texture->SoftwareTexture); - Textures[i].Texture->SoftwareTexture = nullptr; + Textures[i].Texture->CleanHardwareData(); + delete Textures[i].Texture->GetSoftwareTexture(); + Textures[i].Texture->SetSoftwareTexture(nullptr); + calcShouldUpscale(Textures[i].Texture); } } } +//========================================================================== +// +// Examines the lump contents to decide what type of texture to create, +// and creates the texture. +// +//========================================================================== + +static FTexture* CreateTextureFromLump(int lumpnum, bool allowflats = false) +{ + if (lumpnum == -1) return nullptr; + + auto image = FImageSource::GetImage(lumpnum, allowflats); + if (image != nullptr) + { + return new FImageTexture(image); + } + return nullptr; +} + //========================================================================== // // FTextureManager :: CheckForTexture @@ -152,38 +171,39 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset for(i = HashFirst[MakeKey(name) % HASH_SIZE]; i != HASH_END; i = Textures[i].HashNext) { - const FTexture *tex = Textures[i].Texture; + auto tex = Textures[i].Texture; - if (stricmp (tex->Name, name) == 0 ) + if (stricmp (tex->GetName(), name) == 0 ) { // If we look for short names, we must ignore any long name texture. - if ((flags & TEXMAN_ShortNameOnly) && tex->bFullNameTexture) + if ((flags & TEXMAN_ShortNameOnly) && tex->isFullNameTexture()) { continue; } + auto texUseType = tex->GetUseType(); // The name matches, so check the texture type if (usetype == ETextureType::Any) { // All NULL textures should actually return 0 - if (tex->UseType == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0; - if (tex->UseType == ETextureType::SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0; - return FTextureID(tex->UseType==ETextureType::Null ? 0 : i); + if (texUseType == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0; + if (texUseType == ETextureType::SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0; + return FTextureID(texUseType==ETextureType::Null ? 0 : i); } - else if ((flags & TEXMAN_Overridable) && tex->UseType == ETextureType::Override) + else if ((flags & TEXMAN_Overridable) && texUseType == ETextureType::Override) { return FTextureID(i); } - else if (tex->UseType == usetype) + else if (texUseType == usetype) { return FTextureID(i); } - else if (tex->UseType == ETextureType::FirstDefined && usetype == ETextureType::Wall) + else if (texUseType == ETextureType::FirstDefined && usetype == ETextureType::Wall) { if (!(flags & TEXMAN_ReturnFirst)) return FTextureID(0); else return FTextureID(i); } - else if (tex->UseType == ETextureType::Null && usetype == ETextureType::Wall) + else if (texUseType == ETextureType::Null && usetype == ETextureType::Wall) { // We found a NULL texture on a wall -> return 0 return FTextureID(0); @@ -192,12 +212,12 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset { if (firsttype == ETextureType::Null || (firsttype == ETextureType::MiscPatch && - tex->UseType != firsttype && - tex->UseType != ETextureType::Null) + texUseType != firsttype && + texUseType != ETextureType::Null) ) { firstfound = i; - firsttype = tex->UseType; + firsttype = texUseType; } } } @@ -221,20 +241,20 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset // Any graphic being placed in the zip's root directory can not be found by this. if (strchr(name, '/')) { - FTexture *const NO_TEXTURE = (FTexture*)-1; + FGameTexture *const NO_TEXTURE = (FGameTexture*)-1; int lump = fileSystem.CheckNumForFullName(name); if (lump >= 0) { - FTexture *tex = fileSystem.GetLinkedTexture(lump); + FGameTexture *tex = fileSystem.GetLinkedTexture(lump); if (tex == NO_TEXTURE) return FTextureID(-1); - if (tex != NULL) return tex->id; + if (tex != NULL) return tex->GetID(); if (flags & TEXMAN_DontCreate) return FTextureID(-1); // we only want to check, there's no need to create a texture if we don't have one yet. - tex = FTexture::CreateTexture("", lump, ETextureType::Override); + tex = MakeGameTexture(CreateTextureFromLump(lump), nullptr, ETextureType::Override); if (tex != NULL) { tex->AddAutoMaterials(); fileSystem.SetLinkedTexture(lump, tex); - return AddTexture(tex); + return AddGameTexture(tex); } else { @@ -273,12 +293,13 @@ int FTextureManager::ListTextures (const char *name, TArray &list, b while (i != HASH_END) { - const FTexture *tex = Textures[i].Texture; + auto tex = Textures[i].Texture; - if (stricmp (tex->Name, name) == 0) + if (stricmp (tex->GetName(), name) == 0) { + auto texUseType = tex->GetUseType(); // NULL textures must be ignored. - if (tex->UseType!=ETextureType::Null) + if (texUseType!=ETextureType::Null) { unsigned int j = list.Size(); if (!listall) @@ -286,7 +307,7 @@ int FTextureManager::ListTextures (const char *name, TArray &list, b for (j = 0; j < list.Size(); j++) { // Check for overriding definitions from newer WADs - if (Textures[list[j].GetIndex()].Texture->UseType == tex->UseType) break; + if (Textures[list[j].GetIndex()].Texture->GetUseType() == texUseType) break; } } if (j==list.Size()) list.Push(FTextureID(i)); @@ -331,10 +352,10 @@ FTextureID FTextureManager::GetTextureID (const char *name, ETextureType usetype // //========================================================================== -FTexture *FTextureManager::FindTexture(const char *texname, ETextureType usetype, BITFIELD flags) +FGameTexture *FTextureManager::FindGameTexture(const char *texname, ETextureType usetype, BITFIELD flags) { FTextureID texnum = CheckForTexture (texname, usetype, flags); - return GetTexture(texnum.GetIndex()); + return GetGameTexture(texnum.GetIndex()); } //========================================================================== @@ -362,7 +383,7 @@ bool FTextureManager::OkForLocalization(FTextureID texnum, const char *substitut if (locmode == 2) return false; // Mode 3 must also reject substitutions for non-IWAD content. - int file = fileSystem.GetFileContainer(Textures[texnum.GetIndex()].Texture->SourceLump); + int file = fileSystem.GetFileContainer(Textures[texnum.GetIndex()].Texture->GetSourceLump()); if (file > fileSystem.GetMaxIwadNum()) return true; return false; @@ -374,19 +395,23 @@ bool FTextureManager::OkForLocalization(FTextureID texnum, const char *substitut // //========================================================================== -FTextureID FTextureManager::AddTexture (FTexture *texture) +FTextureID FTextureManager::AddGameTexture (FGameTexture *texture, bool addtohash) { int bucket; int hash; if (texture == NULL) return FTextureID(-1); - // Later textures take precedence over earlier ones + if (texture->GetTexture()) + { + // Later textures take precedence over earlier ones + calcShouldUpscale(texture); // calculate this once at insertion + } // Textures without name can't be looked for - if (texture->Name[0] != '\0') + if (addtohash && texture->GetName().IsNotEmpty()) { - bucket = int(MakeKey (texture->Name) % HASH_SIZE); + bucket = int(MakeKey (texture->GetName()) % HASH_SIZE); hash = HashFirst[bucket]; } else @@ -395,11 +420,13 @@ FTextureID FTextureManager::AddTexture (FTexture *texture) hash = -1; } - TextureHash hasher = { texture, hash }; + TextureHash hasher = { texture, -1, -1, -1, hash }; int trans = Textures.Push (hasher); Translation.Push (trans); if (bucket >= 0) HashFirst[bucket] = trans; - return (texture->id = FTextureID(trans)); + auto id = FTextureID(trans); + texture->SetID(id); + return id; } //========================================================================== @@ -416,9 +443,32 @@ FTextureID FTextureManager::CreateTexture (int lumpnum, ETextureType usetype) { FString str; fileSystem.GetFileShortName(str, lumpnum); - FTexture *out = FTexture::CreateTexture(str, lumpnum, usetype); + auto out = MakeGameTexture(CreateTextureFromLump(lumpnum, usetype == ETextureType::Flat), str, usetype); - if (out != NULL) return AddTexture (out); + if (out != NULL) + { + if (usetype == ETextureType::Flat) + { + int w = out->GetTexelWidth(); + int h = out->GetTexelHeight(); + + // Auto-scale flats with dimensions 128x128 and 256x256. + // In hindsight, a bad idea, but RandomLag made it sound better than it really is. + // Now we're stuck with this stupid behaviour. + if (w == 128 && h == 128) + { + out->SetScale(2, 2); + out->SetWorldPanning(true); + } + else if (w == 256 && h == 256) + { + out->SetScale(4, 4); + out->SetWorldPanning(true); + } + } + + return AddGameTexture(out); + } else { Printf (TEXTCOLOR_ORANGE "Invalid data encountered for texture %s\n", fileSystem.GetFileFullPath(lumpnum).GetChars()); @@ -434,20 +484,20 @@ FTextureID FTextureManager::CreateTexture (int lumpnum, ETextureType usetype) // //========================================================================== -void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, bool free) +void FTextureManager::ReplaceTexture (FTextureID picnum, FGameTexture *newtexture, bool free) { int index = picnum.GetIndex(); if (unsigned(index) >= Textures.Size()) return; - FTexture *oldtexture = Textures[index].Texture; + auto oldtexture = Textures[index].Texture; - newtexture->Name = oldtexture->Name; - newtexture->UseType = oldtexture->UseType; + newtexture->SetName(oldtexture->GetName()); + newtexture->SetUseType(oldtexture->GetUseType()); Textures[index].Texture = newtexture; - newtexture->id = oldtexture->id; - oldtexture->Name = ""; - AddTexture(oldtexture); + newtexture->SetID(oldtexture->GetID()); + oldtexture->SetName(""); + AddGameTexture(oldtexture); } //========================================================================== @@ -465,11 +515,11 @@ bool FTextureManager::AreTexturesCompatible (FTextureID picnum1, FTextureID picn if (unsigned(index1) >= Textures.Size() || unsigned(index2) >= Textures.Size()) return false; - FTexture *texture1 = Textures[index1].Texture; - FTexture *texture2 = Textures[index2].Texture; + auto texture1 = Textures[index1].Texture; + auto texture2 = Textures[index2].Texture; // both textures must be the same type. - if (texture1 == NULL || texture2 == NULL || texture1->UseType != texture2->UseType) + if (texture1 == NULL || texture2 == NULL || texture1->GetUseType() != texture2->GetUseType()) return false; // both textures must be from the same file @@ -556,30 +606,28 @@ void FTextureManager::AddHiresTextures (int wadnum) if (amount == 0) { // A texture with this name does not yet exist - FTexture * newtex = FTexture::CreateTexture (Name, firsttx, ETextureType::Any); + auto newtex = MakeGameTexture(CreateTextureFromLump(firsttx), Name, ETextureType::Override); if (newtex != NULL) { - newtex->UseType=ETextureType::Override; - AddTexture(newtex); + AddGameTexture(newtex); } } else { for(unsigned int i = 0; i < tlist.Size(); i++) { - FTexture * newtex = FTexture::CreateTexture ("", firsttx, ETextureType::Any); + FTexture * newtex = CreateTextureFromLump(firsttx); if (newtex != NULL) { - FTexture * oldtex = Textures[tlist[i].GetIndex()].Texture; + auto oldtex = Textures[tlist[i].GetIndex()].Texture; // Replace the entire texture and adjust the scaling and offset factors. - newtex->bWorldPanning = true; - newtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); - newtex->_LeftOffset[0] = int(oldtex->GetScaledLeftOffset(0) * newtex->Scale.X); - newtex->_LeftOffset[1] = int(oldtex->GetScaledLeftOffset(1) * newtex->Scale.X); - newtex->_TopOffset[0] = int(oldtex->GetScaledTopOffset(0) * newtex->Scale.Y); - newtex->_TopOffset[1] = int(oldtex->GetScaledTopOffset(1) * newtex->Scale.Y); - ReplaceTexture(tlist[i], newtex, true); + auto gtex = MakeGameTexture(newtex, nullptr, ETextureType::Override); + gtex->SetWorldPanning(true); + gtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); + gtex->SetOffsets(0, xs_RoundToInt(oldtex->GetDisplayLeftOffset(0) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(0) * gtex->GetScaleY())); + gtex->SetOffsets(1, xs_RoundToInt(oldtex->GetDisplayLeftOffset(1) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(1) * gtex->GetScaleY())); + ReplaceTexture(tlist[i], gtex, true); } } } @@ -655,28 +703,27 @@ void FTextureManager::ParseTextureDef(int lump, FMultipatchTextureBuilder &build { for(unsigned int i = 0; i < tlist.Size(); i++) { - FTexture * oldtex = Textures[tlist[i].GetIndex()].Texture; + auto oldtex = Textures[tlist[i].GetIndex()].Texture; int sl; // only replace matching types. For sprites also replace any MiscPatches // based on the same lump. These can be created for icons. - if (oldtex->UseType == type || type == ETextureType::Any || - (mode == TEXMAN_Overridable && oldtex->UseType == ETextureType::Override) || - (type == ETextureType::Sprite && oldtex->UseType == ETextureType::MiscPatch && + if (oldtex->GetUseType() == type || type == ETextureType::Any || + (mode == TEXMAN_Overridable && oldtex->GetUseType() == ETextureType::Override) || + (type == ETextureType::Sprite && oldtex->GetUseType() == ETextureType::MiscPatch && (sl=oldtex->GetSourceLump()) >= 0 && fileSystem.GetFileNamespace(sl) == ns_sprites) ) { - FTexture * newtex = FTexture::CreateTexture ("", lumpnum, ETextureType::Any); + FTexture * newtex = CreateTextureFromLump(lumpnum); if (newtex != NULL) { // Replace the entire texture and adjust the scaling and offset factors. - newtex->bWorldPanning = true; - newtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); - newtex->_LeftOffset[0] = int(oldtex->GetScaledLeftOffset(0) * newtex->Scale.X); - newtex->_LeftOffset[1] = int(oldtex->GetScaledLeftOffset(1) * newtex->Scale.X); - newtex->_TopOffset[0] = int(oldtex->GetScaledTopOffset(0) * newtex->Scale.Y); - newtex->_TopOffset[1] = int(oldtex->GetScaledTopOffset(1) * newtex->Scale.Y); - ReplaceTexture(tlist[i], newtex, true); + auto gtex = MakeGameTexture(newtex, nullptr, ETextureType::Override); + gtex->SetWorldPanning(true); + gtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); + gtex->SetOffsets(0, xs_RoundToInt(oldtex->GetDisplayLeftOffset(0) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(0) * gtex->GetScaleY())); + gtex->SetOffsets(1, xs_RoundToInt(oldtex->GetDisplayLeftOffset(1) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(1) * gtex->GetScaleY())); + ReplaceTexture(tlist[i], gtex, true); } } } @@ -705,21 +752,21 @@ void FTextureManager::ParseTextureDef(int lump, FMultipatchTextureBuilder &build if (lumpnum>=0) { - FTexture *newtex = FTexture::CreateTexture(src, lumpnum, ETextureType::Override); + auto newtex = MakeGameTexture(CreateTextureFromLump(lumpnum), src, ETextureType::Override); if (newtex != NULL) { // Replace the entire texture and adjust the scaling and offset factors. - newtex->bWorldPanning = true; - newtex->SetDisplaySize(width, height); + newtex->SetWorldPanning(true); + newtex->SetDisplaySize((float)width, (float)height); FTextureID oldtex = TexMan.CheckForTexture(src, ETextureType::MiscPatch); if (oldtex.isValid()) { ReplaceTexture(oldtex, newtex, true); - newtex->UseType = ETextureType::Override; + newtex->SetUseType(ETextureType::Override); } - else AddTexture(newtex); + else AddGameTexture(newtex); } } } @@ -925,11 +972,11 @@ void FTextureManager::AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &b // Try to create a texture from this lump and add it. // Unfortunately we have to look at everything that comes through here... - FTexture *out = FTexture::CreateTexture(Name, i, skin ? ETextureType::SkinGraphic : ETextureType::MiscPatch); + auto out = MakeGameTexture(CreateTextureFromLump(i), Name, skin ? ETextureType::SkinGraphic : ETextureType::MiscPatch); if (out != NULL) { - AddTexture (out); + AddGameTexture (out); } } @@ -953,7 +1000,7 @@ void FTextureManager::AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &b void FTextureManager::SortTexturesByType(int start, int end) { - TArray newtextures; + TArray newtextures; // First unlink all newly added textures from the hash chain for (int i = 0; i < HASH_SIZE; i++) @@ -981,9 +1028,9 @@ void FTextureManager::SortTexturesByType(int start, int end) { for(unsigned j = 0; jUseType == texturetypes[i]) + if (newtextures[j] != NULL && newtextures[j]->GetUseType() == texturetypes[i]) { - AddTexture(newtextures[j]); + AddGameTexture(newtextures[j]); newtextures[j] = NULL; } } @@ -993,8 +1040,8 @@ void FTextureManager::SortTexturesByType(int start, int end) { if (newtextures[j] != NULL) { - Printf("Texture %s has unknown type!\n", newtextures[j]->Name.GetChars()); - AddTexture(newtextures[j]); + Printf("Texture %s has unknown type!\n", newtextures[j]->GetName().GetChars()); + AddGameTexture(newtextures[j]); } } } @@ -1032,8 +1079,8 @@ void FTextureManager::AddLocalizedVariants() FTextureID tex = CheckForTexture(entry.name, ETextureType::MiscPatch); if (tex.isValid()) { - FTexture *otex = GetTexture(origTex); - FTexture *ntex = GetTexture(tex); + auto otex = GetGameTexture(origTex); + auto ntex = GetGameTexture(tex); if (otex->GetDisplayWidth() != ntex->GetDisplayWidth() || otex->GetDisplayHeight() != ntex->GetDisplayHeight()) { Printf("Localized texture %s must be the same size as the one it replaces\n", entry.name); @@ -1081,8 +1128,9 @@ void FTextureManager::AddLocalizedVariants() // FTextureManager :: Init // //========================================================================== -FTexture *CreateShaderTexture(bool, bool); +FGameTexture *CreateShaderTexture(bool, bool); void InitBuildTiles(); +FImageSource* CreateEmptyTexture(); void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo&)) { @@ -1090,15 +1138,18 @@ void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildI DeleteAll(); //if (BuildTileFiles.Size() == 0) CountBuildTiles (); - // Texture 0 is a dummy texture used to indicate "no texture" - auto nulltex = new FImageTexture(nullptr, ""); - nulltex->SetUseType(ETextureType::Null); - AddTexture (nulltex); + auto nulltex = MakeGameTexture(new FImageTexture(CreateEmptyTexture()), nullptr, ETextureType::Null); + AddGameTexture(nulltex); + + // This is for binding to unused texture units, because accessing an unbound texture unit is undefined. It's a one pixel empty texture. + auto emptytex = MakeGameTexture(new FImageTexture(CreateEmptyTexture()), nullptr, ETextureType::Override); + emptytex->SetSize(1, 1); + AddGameTexture(emptytex); // some special textures used in the game. - AddTexture(CreateShaderTexture(false, false)); - AddTexture(CreateShaderTexture(false, true)); - AddTexture(CreateShaderTexture(true, false)); - AddTexture(CreateShaderTexture(true, true)); + AddGameTexture(CreateShaderTexture(false, false)); + AddGameTexture(CreateShaderTexture(false, true)); + AddGameTexture(CreateShaderTexture(true, false)); + AddGameTexture(CreateShaderTexture(true, true)); int wadcnt = fileSystem.GetNumWads(); @@ -1133,6 +1184,13 @@ void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildI glPart = TexMan.CheckForTexture("glstuff/glpart.png", ETextureType::MiscPatch); mirrorTexture = TexMan.CheckForTexture("glstuff/mirror.png", ETextureType::MiscPatch); AddLocalizedVariants(); + + // Make sure all ID's are correct by resetting them here to the proper index. + for (unsigned int i = 0, count = Textures.Size(); i < count; ++i) + { + Textures[i].Texture->SetID(i); + } + } //========================================================================== @@ -1160,19 +1218,95 @@ void FTextureManager::InitPalettedVersions() FTextureID pic2 = CheckForTexture(sc.String, ETextureType::Any); if (!pic2.isValid()) { - sc.ScriptMessage("Unknown texture %s to use as replacement", sc.String); + sc.ScriptMessage("Unknown texture %s to use as paletted replacement", sc.String); } if (pic1.isValid() && pic2.isValid()) { - FTexture *owner = GetTexture(pic1); - FTexture *owned = GetTexture(pic2); - - if (owner && owned) owner->PalVersion = owned; + Textures[pic1.GetIndex()].Paletted = pic2.GetIndex(); } } } } +//========================================================================== +// +// +// +//========================================================================== + +FTextureID FTextureManager::GetRawTexture(FTextureID texid) +{ + int texidx = texid.GetIndex(); + if ((unsigned)texidx >= Textures.Size()) return texid; + if (Textures[texidx].FrontSkyLayer != -1) return FSetTextureID(Textures[texidx].FrontSkyLayer); + + // Reject anything that cannot have been a front layer for the sky in original Hexen, i.e. it needs to be an unscaled wall texture only using Doom patches. + auto tex = Textures[texidx].Texture; + auto ttex = tex->GetTexture(); + auto image = ttex->GetImage(); + // Reject anything that cannot have been a single-patch multipatch texture in vanilla. + if (image == nullptr || image->IsRawCompatible() || tex->GetUseType() != ETextureType::Wall || ttex->GetWidth() != tex->GetDisplayWidth() || + ttex->GetHeight() != tex->GetDisplayHeight()) + { + Textures[texidx].RawTexture = texidx; + return texid; + } + + // Let the hackery begin + auto mptimage = static_cast(image); + auto source = mptimage->GetImageForPart(0); + + // Size must match for this to work as intended + if (source->GetWidth() != ttex->GetWidth() || source->GetHeight() != ttex->GetHeight()) + { + Textures[texidx].RawTexture = texidx; + return texid; + } + + // Todo: later this can just link to the already existing texture for this source graphic, once it can be retrieved through the image's SourceLump index + auto RawTexture = MakeGameTexture(new FImageTexture(source), nullptr, ETextureType::Wall); + texid = TexMan.AddGameTexture(RawTexture); + Textures[texidx].RawTexture = texid.GetIndex(); + Textures[texid.GetIndex()].RawTexture = texid.GetIndex(); + return texid; +} + + +//========================================================================== +// +// Same shit for a different hack, this time Hexen's front sky layers. +// +//========================================================================== + +FTextureID FTextureManager::GetFrontSkyLayer(FTextureID texid) +{ + int texidx = texid.GetIndex(); + if ((unsigned)texidx >= Textures.Size()) return texid; + if (Textures[texidx].FrontSkyLayer != -1) return FSetTextureID(Textures[texidx].FrontSkyLayer); + + // Reject anything that cannot have been a front layer for the sky in original Hexen, i.e. it needs to be an unscaled wall texture only using Doom patches. + auto tex = Textures[texidx].Texture; + auto ttex = tex->GetTexture(); + auto image = ttex->GetImage(); + if (image == nullptr || !image->SupportRemap0() || tex->GetUseType() != ETextureType::Wall || tex->useWorldPanning() || tex->GetTexelTopOffset() != 0 || + ttex->GetWidth() != tex->GetDisplayWidth() || ttex->GetHeight() != tex->GetDisplayHeight()) + { + Textures[texidx].FrontSkyLayer = texidx; + return texid; + } + + // Set this up so that it serializes to the same info as the base texture - this is needed to restore it on load. + // But do not link the new texture into the hash chain! + auto itex = new FImageTexture(image); + itex->SetNoRemap0(); + auto FrontSkyLayer = MakeGameTexture(itex, tex->GetName(), ETextureType::Wall); + FrontSkyLayer->SetUseType(tex->GetUseType()); + texid = TexMan.AddGameTexture(FrontSkyLayer, false); + Textures[texidx].FrontSkyLayer = texid.GetIndex(); + Textures[texid.GetIndex()].FrontSkyLayer = texid.GetIndex(); // also let it refer to itself as its front sky layer, in case for repeated InitSkyMap calls. + return texid; +} + //========================================================================== // // @@ -1314,7 +1448,7 @@ void FTextureManager::AdjustSpriteOffsets() fileSystem.GetFileShortName(str, i); str[8] = 0; FTextureID texid = TexMan.CheckForTexture(str, ETextureType::Sprite, 0); - if (texid.isValid() && fileSystem.GetFileContainer(GetTexture(texid)->SourceLump) > fileSystem.GetMaxIwadNum()) + if (texid.isValid() && fileSystem.GetFileContainer(GetGameTexture(texid)->GetSourceLump()) > fileSystem.GetMaxIwadNum()) { // This texture has been replaced by some PWAD. memcpy(&sprid, str, 4); @@ -1349,7 +1483,7 @@ void FTextureManager::AdjustSpriteOffsets() } if (texno.isValid()) { - FTexture * tex = GetTexture(texno); + auto tex = GetGameTexture(texno); int lumpnum = tex->GetSourceLump(); // We only want to change texture offsets for sprites in the IWAD or the file this lump originated from. @@ -1360,11 +1494,10 @@ void FTextureManager::AdjustSpriteOffsets() { if (wadno >= fileSystem.GetIwadNum() && wadno <= fileSystem.GetMaxIwadNum() && !forced && iwadonly) { - memcpy(&sprid, &tex->Name[0], 4); + memcpy(&sprid, tex->GetName().GetChars(), 4); if (donotprocess.CheckKey(sprid)) continue; // do not alter sprites that only get partially replaced. } - tex->_LeftOffset[1] = x; - tex->_TopOffset[1] = y; + tex->SetOffsets(1, x, y); } } } diff --git a/source/common/textures/texturemanager.h b/source/common/textures/texturemanager.h index ef56ded53..fcece60d5 100644 --- a/source/common/textures/texturemanager.h +++ b/source/common/textures/texturemanager.h @@ -9,8 +9,8 @@ #include "name.h" class FxAddSub; -class FTexture; struct BuildInfo; +class FMultipatchTextureBuilder; int PalCheck(int tex); // Texture manager @@ -25,42 +25,59 @@ public: private: int ResolveLocalizedTexture(int texnum); - FTexture *InternalGetTexture(int texnum, bool animate, bool localize, bool palettesubst) + int ResolveTextureIndex(int texnum, bool animate, bool localize) { - if ((unsigned)texnum >= Textures.Size()) return nullptr; + if ((unsigned)texnum >= Textures.Size()) return -1; if (animate) texnum = Translation[texnum]; if (localize && Textures[texnum].HasLocalization) texnum = ResolveLocalizedTexture(texnum); - if (palettesubst) texnum = PalCheck(texnum); + return texnum; + } + + FGameTexture *InternalGetTexture(int texnum, bool animate, bool localize) + { + texnum = ResolveTextureIndex(texnum, animate, localize); + if (texnum == -1) return nullptr; return Textures[texnum].Texture; } + public: + FTextureID ResolveTextureIndex(FTextureID texid, bool animate, bool localize) + { + return FSetTextureID(ResolveTextureIndex(texid.GetIndex(), animate, localize)); + } + // This only gets used in UI code so we do not need PALVERS handling. - FTexture *GetTextureByName(const char *name, bool animate = false) + FGameTexture* GetGameTextureByName(const char *name, bool animate = false) { - FTextureID texnum = GetTextureID (name, ETextureType::MiscPatch); - return InternalGetTexture(texnum.GetIndex(), animate, true, false); + FTextureID texnum = GetTextureID(name, ETextureType::MiscPatch); + return InternalGetTexture(texnum.GetIndex(), animate, true); + } + + FGameTexture* GetGameTexture(FTextureID texnum, bool animate = false) + { + return InternalGetTexture(texnum.GetIndex(), animate, true); } - FTexture *GetTexture(FTextureID texnum, bool animate = false) + FGameTexture* GetPalettedTexture(FTextureID texnum, bool animate = false, bool allowsubstitute = true) { - return InternalGetTexture(texnum.GetIndex(), animate, true, false); + auto texid = ResolveTextureIndex(texnum.GetIndex(), animate, true); + if (texid == -1) return nullptr; + if (allowsubstitute && Textures[texid].Paletted > 0) texid = Textures[texid].Paletted; + return Textures[texid].Texture; } - - // This is the only access function that should be used inside the software renderer. - FTexture *GetPalettedTexture(FTextureID texnum, bool animate) + + FGameTexture* GameByIndex(int i, bool animate = false) { - return InternalGetTexture(texnum.GetIndex(), animate, true, true); + return InternalGetTexture(i, animate, true); } - - FTexture *ByIndex(int i, bool animate = false) - { - return InternalGetTexture(i, animate, true, false); - } - - FTexture *FindTexture(const char *texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny); + + FGameTexture* FindGameTexture(const char* texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny); + bool OkForLocalization(FTextureID texnum, const char *substitute, int locnum); void FlushAll(); + FTextureID GetFrontSkyLayer(FTextureID); + FTextureID GetRawTexture(FTextureID); enum @@ -99,7 +116,7 @@ public: void AddLocalizedVariants(); FTextureID CreateTexture (int lumpnum, ETextureType usetype=ETextureType::Any); // Also calls AddTexture - FTextureID AddTexture (FTexture *texture); + FTextureID AddGameTexture(FGameTexture* texture, bool addtohash = true); FTextureID GetDefaultTexture() const { return DefaultTexture; } void LoadTextureX(int wadnum, FMultipatchTextureBuilder &build); @@ -107,7 +124,7 @@ public: void Init(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo &)); void DeleteAll(); - void ReplaceTexture (FTextureID picnum, FTexture *newtexture, bool free); + void ReplaceTexture (FTextureID picnum, FGameTexture *newtexture, bool free); int NumTextures () const { return (int)Textures.Size(); } @@ -144,7 +161,7 @@ public: return BuildTileData.Last(); } - FTexture* Texture(FTextureID id) { return Textures[id.GetIndex()].Texture; } + FGameTexture* GameTexture(FTextureID id) { return Textures[id.GetIndex()].Texture; } void SetTranslation(FTextureID fromtexnum, FTextureID totexnum); private: @@ -155,7 +172,10 @@ private: struct TextureHash { - FTexture *Texture; + FGameTexture* Texture; + int Paletted; // redirection to paletted variant + int FrontSkyLayer; // and front sky layer, + int RawTexture; int HashNext; bool HasLocalization; }; @@ -185,3 +205,4 @@ public: }; extern FTextureManager TexMan; + diff --git a/source/common/textures/textures.h b/source/common/textures/textures.h index 0c1747d65..5c8468061 100644 --- a/source/common/textures/textures.h +++ b/source/common/textures/textures.h @@ -42,23 +42,33 @@ #include "textureid.h" #include #include "hw_texcontainer.h" - -// 15 because 0th texture is our texture -#define MAX_CUSTOM_HW_SHADER_TEXTURES 15 +#include "floatrect.h" +#include "refcounted.h" typedef TMap SpriteHits; class FImageSource; +class FGameTexture; +class IHardwareTexture; + + +enum +{ + CLAMP_NONE = 0, + CLAMP_X = 1, + CLAMP_Y = 2, + CLAMP_XY = 3, + CLAMP_XY_NOMIP = 4, + CLAMP_NOFILTER = 5, + CLAMP_CAMTEX = 6, +}; enum MaterialShaderIndex { SHADER_Default, SHADER_Warp1, SHADER_Warp2, - SHADER_Brightmap, SHADER_Specular, - SHADER_SpecularBrightmap, SHADER_PBR, - SHADER_PBRBrightmap, SHADER_Paletted, SHADER_NoTexture, SHADER_BasicFuzz, @@ -72,46 +82,34 @@ enum MaterialShaderIndex FIRST_USER_SHADER }; +enum texflags +{ + // These get Or'ed into uTextureMode because it only uses its 3 lowermost bits. + TEXF_Brightmap = 0x10000, + TEXF_Detailmap = 0x20000, + TEXF_Glowmap = 0x40000, +}; + + + +enum +{ + SFlag_Brightmap = 1, + SFlag_Detailmap = 2, + SFlag_Glowmap = 4, +}; + struct UserShaderDesc { FString shader; MaterialShaderIndex shaderType; FString defines; bool disablealphatest = false; + uint8_t shaderFlags = 0; }; extern TArray usershaders; - -struct FloatRect -{ - float left,top; - float width,height; - - - void Offset(float xofs,float yofs) - { - left+=xofs; - top+=yofs; - } - void Scale(float xfac,float yfac) - { - left*=xfac; - width*=xfac; - top*=yfac; - height*=yfac; - } -}; - -enum ECreateTexBufferFlags -{ - CTF_Expand = 2, // create buffer with a one-pixel wide border - CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture. - CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures. -}; - - - class FBitmap; struct FRemapTable; struct FCopyInfo; @@ -141,7 +139,12 @@ enum FTextureFormat : uint32_t TEX_Count }; -class FSoftwareTexture; +class ISoftwareTexture +{ +public: + virtual ~ISoftwareTexture() = default; +}; + class FGLRenderState; struct spriteframewithrotate; @@ -202,115 +205,62 @@ struct FTextureBuffer }; // Base texture class -class FTexture +class FTexture : public RefCountedBase { - friend class GLDefsParser; - friend class FMultipatchTextureBuilder; - - // The serializer also needs access to more specific info that shouldn't be accessible through the interface. - friend FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); + friend class FGameTexture; // only for the porting work - // 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 - friend class VkRenderState; - friend class PolyRenderState; - friend struct FTexCoordInfo; - friend class OpenGLRenderer::FHardwareTexture; - friend class VkHardwareTexture; - friend class PolyHardwareTexture; - friend class FMultiPatchTexture; - friend class FSkyBox; - friend class FBrightmapTexture; - friend class FFont; +public: + FHardwareTextureContainer SystemTextures; +protected: + FloatRect* areas = nullptr; + int SourceLump; + uint16_t Width = 0, Height = 0; + + bool Masked = false; // Texture (might) have holes + bool bHasCanvas = false; + int8_t bTranslucent = -1; + int8_t areacount = 0; // this is capped at 4 sections. public: - static FTexture *CreateTexture(const char *name, int lumpnum, ETextureType usetype); - virtual ~FTexture (); + + IHardwareTexture* GetHardwareTexture(int translation, int scaleflags); virtual FImageSource *GetImage() const { return nullptr; } - void AddAutoMaterials(); void CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly); - // These are mainly meant for 2D code which only needs logical information about the texture to position it properly. - int GetDisplayWidth() { int foo = int((Width * 2) / Scale.X); return (foo >> 1) + (foo & 1); } - int GetDisplayHeight() { int foo = int((Height * 2) / Scale.Y); return (foo >> 1) + (foo & 1); } - double GetDisplayWidthDouble() { return Width / Scale.X; } - double GetDisplayHeightDouble() { return Height / Scale.Y; } - int GetDisplayLeftOffset() { return GetScaledLeftOffset(0); } - int GetDisplayTopOffset() { return GetScaledTopOffset(0); } - double GetDisplayLeftOffsetDouble() { return GetScaledLeftOffsetDouble(0); } - double GetDisplayTopOffsetDouble() { return GetScaledTopOffsetDouble(0); } - void SetOffsets(int l, int t) + void CleanHardwareTextures() { - _LeftOffset[0] = _LeftOffset[1] = l; - _TopOffset[0] = _TopOffset[1] = t; + SystemTextures.Clean(); } - - int GetTexelWidth() { return Width; } - int GetTexelHeight() { return Height; } - int GetTexelLeftOffset(int adjusted) { return _LeftOffset[adjusted]; } - int GetTexelTopOffset(int adjusted) { return _TopOffset[adjusted]; } + void CleanPrecacheMarker() + { + SystemTextures.UnmarkAll(); + } + + void MarkForPrecache(int translation, int scaleflags) + { + SystemTextures.MarkForPrecache(translation, scaleflags); + } + + void CleanUnused() + { + SystemTextures.CleanUnused(); + } + + int GetWidth() { return Width; } + int GetHeight() { return Height; } - bool isValid() const { return UseType != ETextureType::Null; } - bool isSWCanvas() const { return UseType == ETextureType::SWCanvas; } - bool isSkybox() const { return bSkybox; } - bool isFullbrightDisabled() const { return bDisableFullbright; } bool isHardwareCanvas() const { return bHasCanvas; } // There's two here so that this can deal with software canvases in the hardware renderer later. bool isCanvas() const { return bHasCanvas; } - 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; } - void SetRotations(int rot) { Rotations = int16_t(rot); } - bool isSprite() const { return UseType == ETextureType::Sprite || UseType == ETextureType::SkinSprite || UseType == ETextureType::Decal; } - const FString &GetName() const { return Name; } - void SetNoDecals(bool on) { bNoDecals = on; } - void SetWarpStyle(int style) { bWarped = style; } - bool allowNoDecals() const { return bNoDecals; } - bool isScaled() const { return Scale.X != 1 || Scale.Y != 1; } - bool isMasked() const { return bMasked; } - void SetSkyOffset(int offs) { SkyOffset = offs; } - int GetSkyOffset() const { return SkyOffset; } - FTextureID GetID() const { return id; } - PalEntry GetSkyCapColor(bool bottom); - FTexture *GetRawTexture(); - virtual int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method. - void GetGlowColor(float *data); - bool isGlowing() const { return bGlowing; } - bool isAutoGlowing() const { return bAutoGlowing; } - int GetGlowHeight() const { return GlowHeight; } - bool isFullbright() const { return bFullbright; } - void CreateDefaultBrightmap(); + int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method. bool FindHoles(const unsigned char * buffer, int w, int h); - void SetUseType(ETextureType type) { UseType = type; } - int GetSourceLump() const { return SourceLump; } - ETextureType GetUseType() const { return UseType; } - void SetSpeed(float fac) { shaderspeed = fac; } - void SetWorldPanning(bool on) { bWorldPanning = on; } - void SetDisplaySize(int fitwidth, int fitheight); - void SetFrontSkyLayer(bool on = true) { bNoRemap0 = on; } - bool IsFrontSkyLayer() { return bNoRemap0; } - - FTexture* GetBrightmap() - { - if (!bBrightmapChecked) - CreateDefaultBrightmap(); - return Brightmap; - } void CopySize(FTexture* BaseTexture) { - Width = BaseTexture->GetTexelWidth(); - Height = BaseTexture->GetTexelHeight(); - _TopOffset[0] = BaseTexture->_TopOffset[0]; - _TopOffset[1] = BaseTexture->_TopOffset[1]; - _LeftOffset[0] = BaseTexture->_LeftOffset[0]; - _LeftOffset[1] = BaseTexture->_LeftOffset[1]; - Scale = BaseTexture->Scale; + Width = BaseTexture->GetWidth(); + Height = BaseTexture->GetHeight(); } // This is only used for the null texture and for Heretic's skies. @@ -320,119 +270,20 @@ public: Height = h; } + bool TrimBorders(uint16_t* rect); + int GetAreas(FloatRect** pAreas) const; // Returns the whole texture, stored in column-major order virtual TArray Get8BitPixels(bool alphatex); virtual FBitmap GetBgraBitmap(const PalEntry *remap, int *trans = nullptr); static bool SmoothEdges(unsigned char * buffer,int w, int h); - static PalEntry averageColor(const uint32_t *data, int size, int maxout); - - FSoftwareTexture *GetSoftwareTexture(); - -protected: - - DVector2 Scale; - - int SourceLump; - FTextureID id; - - FMaterial *Material[2] = { nullptr, nullptr }; -public: - FHardwareTextureContainer SystemTextures; - int alphaThreshold = 0.5; - FixedBitArray<256> NoBrightmapFlag = false; -protected: - FSoftwareTexture *SoftwareTexture = nullptr; - - // None of the following pointers are owned by this texture, they are all controlled by the texture manager. - - // Offset-less version for COMPATF_MASKEDMIDTEX - FTexture *OffsetLess = nullptr; - // Paletted variant - FTexture *PalVersion = nullptr; - // Material layers - FTexture *Brightmap = nullptr; - FTexture *Normal = nullptr; // Normal map texture - FTexture *Specular = nullptr; // Specular light texture for the diffuse+normal+specular light model - FTexture *Metallic = nullptr; // Metalness texture for the physically based rendering (PBR) light model - FTexture *Roughness = nullptr; // Roughness texture for PBR - FTexture *AmbientOcclusion = nullptr; // Ambient occlusion texture for PBR - - FTexture *CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES] = { nullptr }; // Custom texture maps for custom hardware shaders - - FString Name; - ETextureType UseType; // This texture's primary purpose - - uint8_t bNoDecals:1; // Decals should not stick to texture - uint8_t bNoRemap0:1; // Do not remap color 0 (used by front layer of parallax skies) - uint8_t bWorldPanning:1; // Texture is panned in world units rather than texels - uint8_t bMasked:1; // Texture (might) have holes - uint8_t bAlphaTexture:1; // Texture is an alpha channel without color information - uint8_t bHasCanvas:1; // Texture is based off FCanvasTexture - uint8_t bWarped:2; // This is a warped texture. Used to avoid multiple warps on one texture - uint8_t bComplex:1; // Will be used to mark extended MultipatchTextures that have to be - // fully composited before subjected to any kind of postprocessing instead of - // doing it per patch. - uint8_t bMultiPatch:2; // This is a multipatch texture (we really could use real type info for textures...) - uint8_t bFullNameTexture : 1; - uint8_t bBrightmapChecked : 1; // Set to 1 if brightmap has been checked - uint8_t bGlowing : 1; // Texture glow color - uint8_t bAutoGlowing : 1; // Glow info is determined from texture image. - uint8_t bFullbright : 1; // always draw fullbright - uint8_t bDisableFullbright : 1; // This texture will not be displayed as fullbright sprite - uint8_t bSkybox : 1; // is a cubic skybox - uint8_t bNoCompress : 1; - uint8_t bNoExpand : 1; - int8_t bTranslucent : 2; - bool bHiresHasColorKey = false; // Support for old color-keyed Doomsday textures - - uint16_t Rotations; - int16_t SkyOffset; - FloatRect *areas = nullptr; - int areacount = 0; - int GlowHeight = 128; - PalEntry GlowColor = 0; - int HiresLump = -1; // For external hires textures. - float Glossiness = 10.f; - float SpecularLevel = 0.1f; - float shaderspeed = 1.f; - int shaderindex = 0; - - int GetScaledWidth () { int foo = int((Width * 2) / Scale.X); return (foo >> 1) + (foo & 1); } - int GetScaledHeight () { int foo = int((Height * 2) / Scale.Y); return (foo >> 1) + (foo & 1); } - double GetScaledWidthDouble () { return Width / Scale.X; } - double GetScaledHeightDouble () { return Height / Scale.Y; } - double GetScaleY() const { return Scale.Y; } - - // Now with improved offset adjustment. - int GetLeftOffset(int adjusted) { return _LeftOffset[adjusted]; } - int GetTopOffset(int adjusted) { return _TopOffset[adjusted]; } - int GetScaledLeftOffset (int adjusted) { int foo = int((_LeftOffset[adjusted] * 2) / Scale.X); return (foo >> 1) + (foo & 1); } - int GetScaledTopOffset (int adjusted) { int foo = int((_TopOffset[adjusted] * 2) / Scale.Y); return (foo >> 1) + (foo & 1); } - double GetScaledLeftOffsetDouble(int adjusted) { return _LeftOffset[adjusted] / Scale.X; } - double GetScaledTopOffsetDouble(int adjusted) { return _TopOffset[adjusted] / Scale.Y; } - - // 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. - - // For the hardware renderer. The software renderer's have been offloaded to FSoftwareTexture - int GetLeftOffsetHW() { return _LeftOffset[r_spriteadjustHW]; } - int GetTopOffsetHW() { return _TopOffset[r_spriteadjustHW]; } virtual void ResolvePatches() {} - void SetScale(const DVector2 &scale) - { - Scale = scale; - } -protected: - uint16_t Width, Height; - int16_t _LeftOffset[2], _TopOffset[2]; - - FTexture (const char *name = NULL, int lumpnum = -1); + FTexture (int lumpnum = -1); public: FTextureBuffer CreateTexBuffer(int translation, int flags = 0); @@ -442,27 +293,6 @@ public: { return bTranslucent != -1 ? bTranslucent : DetermineTranslucency(); } - FMaterial* GetMaterial(int num) - { - return Material[num]; - } - FTexture* GetPalVersion() - { - return PalVersion; - } - - void DeleteHardwareTextures() - { - SystemTextures.Clean(true, true); - } - -private: - int CheckDDPK3(); - int CheckExternalFile(bool & hascolorkey); - - bool bSWSkyColorDone = false; - PalEntry FloorSkyColor; - PalEntry CeilingSkyColor; public: @@ -479,17 +309,13 @@ public: class FCanvasTexture : public FTexture { public: - FCanvasTexture(const char* name, int width, int height) + FCanvasTexture(int width, int height) { - Name = name; Width = width; Height = height; - bMasked = false; bHasCanvas = true; - bTranslucent = false; - bNoExpand = true; - UseType = ETextureType::Wall; + aspectRatio = (float)width / height; } void NeedUpdate() { bNeedsUpdate = true; } @@ -501,6 +327,7 @@ protected: bool bNeedsUpdate = true; public: bool bFirstUpdate = true; + float aspectRatio; friend struct FCanvasTextureInfo; }; @@ -514,7 +341,7 @@ public: FWrapperTexture(int w, int h, int bits = 1); IHardwareTexture *GetSystemTexture() { - return SystemTextures.GetHardwareTexture(0, false); + return SystemTextures.GetHardwareTexture(0, 0); } int GetColorFormat() const @@ -527,14 +354,19 @@ public: class FImageTexture : public FTexture { FImageSource* mImage; + bool bNoRemap0 = false; +protected: + void SetFromImage(); public: - FImageTexture(FImageSource* image, const char* name = nullptr) noexcept; + FImageTexture(FImageSource* image) noexcept; virtual TArray Get8BitPixels(bool alphatex); - void SetImage(FImageSource* img) // This is only for the multipatch texture builder! + void SetImage(FImageSource* img) { mImage = img; + SetFromImage(); } + void SetNoRemap0() { bNoRemap0 = true; } FImageSource* GetImage() const override { return mImage; } FBitmap GetBgraBitmap(const PalEntry* p, int* trans) override; @@ -542,24 +374,8 @@ public: }; -struct FTexCoordInfo -{ - int mRenderWidth; - int mRenderHeight; - int mWidth; - FVector2 mScale; - FVector2 mTempScale; - bool mWorldPanning; - - float FloatToTexU(float v) const { return v / mRenderWidth; } - float FloatToTexV(float v) const { return v / mRenderHeight; } - float RowOffset(float ofs) const; - float TextureOffset(float ofs) const; - float TextureAdjustWidth() const; - void GetFromTexture(FTexture *tex, float x, float y, bool forceworldpanning); -}; - +#include "gametexture.h" #endif diff --git a/source/core/console/c_console.cpp b/source/core/console/c_console.cpp index e37382076..258d7bf72 100644 --- a/source/core/console/c_console.cpp +++ b/source/core/console/c_console.cpp @@ -86,7 +86,7 @@ static bool TabbedList; // True if tab list was shown CVAR(Bool, con_notablist, false, CVAR_ARCHIVE) -static FTexture* conback; +static FGameTexture* conback; static uint32_t conshade; static bool conline; diff --git a/source/core/menu/listmenu.cpp b/source/core/menu/listmenu.cpp index aa23b676d..7f0d97926 100644 --- a/source/core/menu/listmenu.cpp +++ b/source/core/menu/listmenu.cpp @@ -316,7 +316,7 @@ bool FListMenuItem::Selectable() return false; } -void FListMenuItem::DrawSelector(int xofs, int yofs, FTexture *tex) +void FListMenuItem::DrawSelector(int xofs, int yofs, FGameTexture *tex) { if (!tex) { @@ -399,7 +399,7 @@ int FListMenuItem::GetWidth() // //============================================================================= -FListMenuItemStaticPatch::FListMenuItemStaticPatch(int x, int y, FTexture *patch, bool centered) +FListMenuItemStaticPatch::FListMenuItemStaticPatch(int x, int y, FGameTexture *patch, bool centered) : FListMenuItem(x, y) { mTexture = patch; @@ -414,7 +414,7 @@ void FListMenuItemStaticPatch::Drawer(DListMenu* menu, const DVector2& origin, b } int x = mXpos; - FTexture *tex = mTexture; + FGameTexture *tex = mTexture; if (mYpos >= 0) { if (mCentered) x -= tex->GetDisplayWidth()/2; @@ -631,7 +631,7 @@ int FListMenuItemNativeText::GetWidth() // //============================================================================= -FListMenuItemPatch::FListMenuItemPatch(int x, int y, int height, int hotkey, FTexture *patch, FName child, int param) +FListMenuItemPatch::FListMenuItemPatch(int x, int y, int height, int hotkey, FGameTexture *patch, FName child, int param) : FListMenuItemSelectable(x, y, height, child, param) { mHotkey = hotkey; diff --git a/source/core/menu/menu.cpp b/source/core/menu/menu.cpp index b0e6123be..165dc881e 100644 --- a/source/core/menu/menu.cpp +++ b/source/core/menu/menu.cpp @@ -270,7 +270,7 @@ bool DMenu::MouseEventBack(int type, int x, int y) auto texid = TexMan.CheckForTexture("engine/graphics/m_back.png", ETextureType::Any); if (texid.isValid()) { - auto tex = TexMan.GetTexture(texid); + auto tex = TexMan.GetGameTexture(texid); if (m_show_backbutton&1) x -= screen->GetWidth() - tex->GetDisplayWidth() * CleanXfac; if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetDisplayHeight() * CleanYfac; mBackbuttonSelected = ( x >= 0 && x < tex->GetDisplayWidth() * CleanXfac && @@ -327,7 +327,7 @@ void DMenu::Drawer () auto texid = TexMan.CheckForTexture("engine/graphics/m_back.png", ETextureType::Any); if (texid.isValid()) { - auto tex = TexMan.GetTexture(texid); + auto tex = TexMan.GetGameTexture(texid); int w = tex->GetDisplayWidth() * CleanXfac; int h = tex->GetDisplayHeight() * CleanYfac; int x = (!(m_show_backbutton & 1)) ? 0 : screen->GetWidth() - w; diff --git a/source/core/menu/menu.h b/source/core/menu/menu.h index 2d9621c38..8542bd7c3 100644 --- a/source/core/menu/menu.h +++ b/source/core/menu/menu.h @@ -107,7 +107,7 @@ enum EMenuSounds : int EXTERN_CVAR(Bool, menu_sounds) struct event_t; -class FTexture; +class FGameTexture; class FFont; enum EColorRange : int; class FPlayerClass; @@ -196,7 +196,7 @@ struct FListMenuDescriptor : public FMenuDescriptor int mSelectedItem; int mSelectOfsX; int mSelectOfsY; - FTexture *mSelector; + FGameTexture *mSelector; int mDisplayTop; int mXpos, mYpos, mYbotton; int mWLeft, mWRight; @@ -401,7 +401,7 @@ public: virtual bool MouseEvent(int type, int x, int y); virtual bool CheckHotkey(int c); virtual int GetWidth(); - virtual void DrawSelector(int xofs, int yofs, FTexture *tex); + virtual void DrawSelector(int xofs, int yofs, FGameTexture *tex); void OffsetPositionY(int ydelta) { mYpos += ydelta; } int GetY() { return mYpos; } int GetX() { return mXpos; } @@ -414,11 +414,11 @@ public: class FListMenuItemStaticPatch : public FListMenuItem { protected: - FTexture *mTexture; + FGameTexture *mTexture; bool mCentered; public: - FListMenuItemStaticPatch(int x, int y, FTexture *patch, bool centered); + FListMenuItemStaticPatch(int x, int y, FGameTexture *patch, bool centered); void Drawer(DListMenu* menu, const DVector2& origin, bool selected); }; @@ -496,15 +496,15 @@ public: ~FListMenuItemNativeText(); void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override; int GetWidth() override; - void DrawSelector(int xofs, int yofs, FTexture* tex) override { } // The text drawer handles this itself. + void DrawSelector(int xofs, int yofs, FGameTexture* tex) override { } // The text drawer handles this itself. }; class FListMenuItemPatch : public FListMenuItemSelectable { - FTexture* mTexture; + FGameTexture* mTexture; public: - FListMenuItemPatch(int x, int y, int height, int hotkey, FTexture* patch, FName child, int param = 0); + FListMenuItemPatch(int x, int y, int height, int hotkey, FGameTexture* patch, FName child, int param = 0); void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override; int GetWidth() override; }; @@ -806,7 +806,7 @@ private: int LastSaved = -1; int LastAccessed = -1; TArray SavePicData; - FTexture *SavePic = nullptr; + FGameTexture *SavePic = nullptr; public: int WindowSize = 0; diff --git a/source/core/menu/menudef.cpp b/source/core/menu/menudef.cpp index 32774d9d2..64feeae19 100644 --- a/source/core/menu/menudef.cpp +++ b/source/core/menu/menudef.cpp @@ -104,7 +104,7 @@ void M_DeinitMenus() DefaultListMenuSettings.mItems.Clear(); } -static FTexture* GetMenuTexture(const char* const name) +static FGameTexture* GetMenuTexture(const char* const name) { auto texid = TexMan.CheckForTexture(name, ETextureType::Any); if (!texid.isValid()) @@ -112,7 +112,7 @@ static FTexture* GetMenuTexture(const char* const name) Printf("Missing menu texture: \"%s\"\n", name); } - return TexMan.GetTexture(texid); + return TexMan.GetGameTexture(texid); } //============================================================================= @@ -370,7 +370,7 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) int y = sc.Number; sc.MustGetStringName(","); sc.MustGetString(); - FTexture* tex = GetMenuTexture(sc.String); + auto tex = GetMenuTexture(sc.String); FListMenuItem *it = new FListMenuItemStaticPatch(x, y, tex, centered); desc->mItems.Push(it); @@ -401,7 +401,7 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc) else if (sc.Compare("PatchItem")) { sc.MustGetString(); - FTexture* tex = GetMenuTexture(sc.String); + auto tex = GetMenuTexture(sc.String); sc.MustGetStringName(","); sc.MustGetString(); int hotkey = sc.String[0]; diff --git a/source/core/menu/menuinput.cpp b/source/core/menu/menuinput.cpp index d04e0f130..f3da36bcf 100644 --- a/source/core/menu/menuinput.cpp +++ b/source/core/menu/menuinput.cpp @@ -330,7 +330,7 @@ void DTextEnterMenu::Drawer () int width; const int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2; const int ch = InputGridChars[y * INPUTGRID_WIDTH + x]; - FTexture *pic = displayFont->GetChar(ch, CR_DARKGRAY, &width); + auto pic = displayFont->GetChar(ch, CR_DARKGRAY, &width); EColorRange color; int remap; diff --git a/source/core/rendering/gl/renderer/gl_renderer.cpp b/source/core/rendering/gl/renderer/gl_renderer.cpp index a8b6d4e76..6b93fbd28 100644 --- a/source/core/rendering/gl/renderer/gl_renderer.cpp +++ b/source/core/rendering/gl/renderer/gl_renderer.cpp @@ -169,9 +169,9 @@ void FGLRenderer::EndOffscreen() // //=========================================================================== -void FGLRenderer::BindToFrameBuffer(FTexture *mat) +void FGLRenderer::BindToFrameBuffer(FGameTexture *mat) { - auto pBaseLayer = mat->SystemTextures.GetHardwareTexture(0, false); + auto pBaseLayer = mat->GetTexture()->SystemTextures.GetHardwareTexture(0, false); auto BaseLayer = pBaseLayer ? (::FHardwareTexture*)pBaseLayer : nullptr; if (BaseLayer == nullptr) @@ -179,7 +179,7 @@ void FGLRenderer::BindToFrameBuffer(FTexture *mat) // must create the hardware texture first BaseLayer = new ::FHardwareTexture; BaseLayer->CreateTexture(mat->GetTexelWidth()*4, mat->GetTexelHeight()*4, ::FHardwareTexture::TrueColor, false); - mat->SystemTextures.AddHardwareTexture(0, false, BaseLayer); + mat->GetTexture()->SystemTextures.AddHardwareTexture(0, false, BaseLayer); } BaseLayer->BindToFrameBuffer(mat->GetTexelWidth()*4, mat->GetTexelHeight()*4); } diff --git a/source/core/rendering/gl/renderer/gl_renderer.h b/source/core/rendering/gl/renderer/gl_renderer.h index b3a2ec6b6..89a0aeb2e 100644 --- a/source/core/rendering/gl/renderer/gl_renderer.h +++ b/source/core/rendering/gl/renderer/gl_renderer.h @@ -88,7 +88,7 @@ public: bool StartOffscreen(); void EndOffscreen(); - void BindToFrameBuffer(FTexture* tex); + void BindToFrameBuffer(FGameTexture* tex); private: diff --git a/source/core/textures/buildtiles.cpp b/source/core/textures/buildtiles.cpp index cbee3730e..29d92ca73 100644 --- a/source/core/textures/buildtiles.cpp +++ b/source/core/textures/buildtiles.cpp @@ -108,7 +108,7 @@ TArray FTileTexture::CreatePalettedPixels(int conversion) // //========================================================================== -static FTexture* GetTileTexture(const char* name, const TArray& backingstore, uint32_t offset, int width, int height) +static FGameTexture* GetTileTexture(const char* name, const TArray& backingstore, uint32_t offset, int width, int height) { auto tex = new FArtTile(backingstore, offset, width, height); auto p = &backingstore[offset]; @@ -122,7 +122,7 @@ static FTexture* GetTileTexture(const char* name, const TArray& backing if (tex) { - return new FImageTexture(tex, name); + return MakeGameTexture(new FImageTexture(tex), name, ETextureType::Any); } return nullptr; } @@ -130,7 +130,7 @@ static FTexture* GetTileTexture(const char* name, const TArray& backing void BuildTiles::Init() { - Placeholder = TexMan.ByIndex(0); + Placeholder = TexMan.GameByIndex(0); for (auto& tile : tiledata) { tile.texture = Placeholder; @@ -138,6 +138,7 @@ void BuildTiles::Init() tile.picanm = {}; tile.RotTile = { -1,-1 }; tile.replacement = ReplacementType::Art; + tile.NoBrightmapFlag.Zero(); } } @@ -147,10 +148,10 @@ void BuildTiles::Init() // //========================================================================== -void BuildTiles::AddTile(int tilenum, FTexture* tex, bool permap) +void BuildTiles::AddTile(int tilenum, FGameTexture* tex, bool permap) { assert(!tex->GetID().isValid()); // must not be added yet. - TexMan.AddTexture(tex); + TexMan.AddGameTexture(tex); tiledata[tilenum].texture = tex; if (!permap) tiledata[tilenum].backup = tex; } @@ -300,12 +301,12 @@ void BuildTiles::InvalidateTile(int num) if ((unsigned) num < MAXTILES) { auto tex = tiledata[num].texture; - tex->SystemTextures.Clean(true, true); + tex->GetTexture()->SystemTextures.Clean(); for (auto &rep : tiledata[num].Hightiles) { for (auto &reptex : rep.faces) { - if (reptex) reptex->SystemTextures.Clean(true, true); + if (reptex) reptex->GetTexture()->SystemTextures.Clean(); } } tiledata[num].rawCache.data.Clear(); @@ -404,7 +405,7 @@ void BuildTiles::LoadArtSet(const char* filename) // //========================================================================== -FTexture* BuildTiles::ValidateCustomTile(int tilenum, ReplacementType type) +FGameTexture* BuildTiles::ValidateCustomTile(int tilenum, ReplacementType type) { if (tilenum < 0 || tilenum >= MAXTILES) return nullptr; auto &td = tiledata[tilenum]; @@ -435,15 +436,16 @@ FTexture* BuildTiles::ValidateCustomTile(int tilenum, ReplacementType type) // All of these effects should probably be redone without actual texture hacking... if (tile->GetTexelWidth() == 0 || tile->GetTexelHeight() == 0) return nullptr; // The base must have a size for this to work. // todo: invalidate hardware textures for tile. - replacement = new FImageTexture(new FRestorableTile(tile->GetImage())); + replacement = new FImageTexture(new FRestorableTile(tile->GetTexture()->GetImage())); } else if (type == ReplacementType::Canvas) { - replacement = new FCanvasTexture("camera", 0, 0); + replacement = new FCanvasTexture(0, 0); } else return nullptr; - AddTile(tilenum, replacement); - return replacement; + auto reptex = MakeGameTexture(replacement, "", ETextureType::Any); + AddTile(tilenum, reptex); + return reptex; } //========================================================================== @@ -470,7 +472,7 @@ uint8_t* BuildTiles::tileCreate(int tilenum, int width, int height) if (width <= 0 || height <= 0) return nullptr; auto tex = ValidateCustomTile(tilenum, ReplacementType::Writable); if (tex == nullptr) return nullptr; - auto wtex = static_cast(tex->GetImage()); + auto wtex = static_cast(tex->GetTexture()->GetImage()); if (!wtex->ResizeImage(width, height)) return nullptr; tex->SetSize(width, height); return wtex->GetRawData(); @@ -486,7 +488,7 @@ uint8_t* BuildTiles::tileCreate(int tilenum, int width, int height) uint8_t* BuildTiles::tileMakeWritable(int num) { auto tex = ValidateCustomTile(num, ReplacementType::Restorable); - auto wtex = static_cast(tex->GetImage()); + auto wtex = static_cast(tex->GetTexture()->GetImage()); return wtex ? wtex->GetRawData() : nullptr; } @@ -499,7 +501,7 @@ uint8_t* BuildTiles::tileMakeWritable(int num) int32_t tileGetCRC32(int tileNum) { if ((unsigned)tileNum >= (unsigned)MAXTILES) return 0; - auto tile = dynamic_cast(TileFiles.tiledata[tileNum].texture->GetImage()); // only consider original ART tiles. + auto tile = dynamic_cast(TileFiles.tiledata[tileNum].texture->GetTexture()->GetImage()); // only consider original ART tiles. if (!tile) return 0; auto pixels = tile->GetRawData(); if (!pixels) return 0; @@ -541,7 +543,7 @@ int tileImportFromTexture(const char* fn, int tilenum, int alphacut, int istextu { FTextureID texid = TexMan.CheckForTexture(fn, ETextureType::Any); if (!texid.isValid()) return -1; - auto tex = TexMan.GetTexture(texid); + auto tex = TexMan.GetGameTexture(texid); //tex->alphaThreshold = 255 - alphacut; int32_t xsiz = tex->GetTexelWidth(), ysiz = tex->GetTexelHeight(); @@ -573,7 +575,7 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags picanm_t* picanm = nullptr; picanm_t* sourceanm = nullptr; int srcxo, srcyo; - FTexture* tex; + FGameTexture* tex; if (pal == -1 && tile == source) { @@ -594,7 +596,7 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags srcxo = tex->GetTexelLeftOffset(0); srcyo = tex->GetTexelTopOffset(0); - TArray buffer = tex->Get8BitPixels(false); + TArray buffer = tex->GetTexture()->Get8BitPixels(false); if (pal != -1) { @@ -604,7 +606,7 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags pixel = remap[pixel]; } } - tex = new FImageTexture(new FLooseTile(buffer, tex->GetTexelWidth(), tex->GetTexelHeight())); + tex = MakeGameTexture(new FImageTexture(new FLooseTile(buffer, tex->GetTexelWidth(), tex->GetTexelHeight())), "", ETextureType::Any); picanm = &TileFiles.tiledata[tile].picanm; TileFiles.AddTile(tile, tex); } @@ -656,7 +658,7 @@ void artSetupMapArt(const char* filename) auto texid = TexMan.CheckForTexture(name, ETextureType::Any); if (texid.isValid()) { - TileFiles.tiledata[i].texture = TexMan.GetTexture(texid); + TileFiles.tiledata[i].texture = TexMan.GetGameTexture(texid); } } return; @@ -691,7 +693,7 @@ void artSetupMapArt(const char* filename) void tileDelete(int tile) { TileFiles.TextureToTile.Remove(tileGetTexture(tile)); - TileFiles.tiledata[tile].texture = TileFiles.tiledata[tile].backup = TexMan.ByIndex(0); + TileFiles.tiledata[tile].texture = TileFiles.tiledata[tile].backup = TexMan.GameByIndex(0); vox_undefine(tile); md_undefinetile(tile); tileRemoveReplacement(tile); @@ -723,7 +725,7 @@ void tileSetDummy(int tile, int width, int height) } else if (width > 0 && height > 0) { - auto dtile = new FImageTexture(new FDummyTile(width, height)); + auto dtile = MakeGameTexture(new FImageTexture(new FDummyTile(width, height)), "", ETextureType::Any); TileFiles.AddTile(tile, dtile); } } @@ -760,7 +762,7 @@ int BuildTiles::tileCreateRotated(int tileNum) if ((unsigned)tileNum >= MAXTILES) return tileNum; auto tex = tileGetTexture(tileNum); if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return tileNum; - TArray buffer = tex->Get8BitPixels(false); + TArray buffer = tex->GetTexture()->Get8BitPixels(false); TArray dbuffer(tex->GetTexelWidth() * tex->GetTexelHeight(), true); auto src = buffer.Data(); @@ -777,7 +779,7 @@ int BuildTiles::tileCreateRotated(int tileNum) *(dst + y * width + xofs) = *(src + y + yofs); } - auto dtex = new FImageTexture(new FLooseTile(dbuffer, tex->GetTexelHeight(), tex->GetTexelWidth())); + auto dtex = MakeGameTexture(new FImageTexture(new FLooseTile(dbuffer, tex->GetTexelHeight(), tex->GetTexelWidth())), "", ETextureType::Any); int index = findUnusedTile(); bool mapart = TileFiles.tiledata[tileNum].texture != TileFiles.tiledata[tileNum].backup; TileFiles.AddTile(index, dtex, mapart); @@ -821,7 +823,7 @@ int tileSetHightileReplacement(int picnum, int palnum, const char* filename, flo return -1; } - replace.faces[0] = TexMan.GetTexture(texid); + replace.faces[0] = TexMan.GetGameTexture(texid); if (replace.faces[0] == nullptr) replace.alphacut = min(alphacut,1.f); replace.scale = { xscale, yscale }; @@ -861,7 +863,7 @@ int tileSetSkybox(int picnum, int palnum, const char **facenames, int flags ) Printf("%s: Skybox image for tile %d does not exist or is invalid\n", *facenames, picnum); return -1; } - face = TexMan.GetTexture(texid); + face = TexMan.GetGameTexture(texid); } replace.flags = flags; replace.palnum = (uint16_t)palnum; diff --git a/source/core/textures/buildtiles.h b/source/core/textures/buildtiles.h index d4bd5e831..6e1bfbc6b 100644 --- a/source/core/textures/buildtiles.h +++ b/source/core/textures/buildtiles.h @@ -62,7 +62,7 @@ struct rottile_t struct HightileReplacement { - FTexture* faces[6]; // only one gets used by a texture, the other 5 are for skyboxes only + FGameTexture* faces[6]; // only one gets used by a texture, the other 5 are for skyboxes only vec2f_t scale; float alphacut, specpower, specfactor; uint16_t palnum, flags; @@ -257,23 +257,24 @@ struct RawCacheNode struct TileDesc { - FTexture* texture; // the currently active tile - FTexture* backup; // original backup for map tiles + FGameTexture* texture; // the currently active tile + FGameTexture* backup; // original backup for map tiles RawCacheNode rawCache; // this is needed for hitscan testing to avoid reloading the texture each time. picanm_t picanm; // animation descriptor picanm_t picanmbackup; // animation descriptor backup when using map tiles rottile_t RotTile;// = { -1,-1 }; TArray Hightiles; ReplacementType replacement; + FixedBitArray<256> NoBrightmapFlag; }; struct BuildTiles { - FTexture* Placeholder; + FGameTexture* Placeholder; TDeletingArray ArtFiles; TileDesc tiledata[MAXTILES]; TArray addedArt; - TMap TextureToTile; + TMap TextureToTile; TArray maptilesadded; void Init(); // This cannot be a constructor because it needs the texture manager running. @@ -284,7 +285,7 @@ struct BuildTiles void CloseAll(); - void AddTile(int tilenum, FTexture* tex, bool permap = false); + void AddTile(int tilenum, FGameTexture* tex, bool permap = false); void AddTiles(int firsttile, TArray& store, const char* mapname); @@ -302,7 +303,7 @@ struct BuildTiles { addedArt = std::move(art); } - int GetTileIndex(FTexture* tex) + int GetTileIndex(FGameTexture* tex) { auto p = TextureToTile.CheckKey(tex); return p ? *p : -1; @@ -317,14 +318,12 @@ struct BuildTiles } } - FTexture* ValidateCustomTile(int tilenum, ReplacementType type); + FGameTexture* ValidateCustomTile(int tilenum, ReplacementType type); int32_t artLoadFiles(const char* filename); uint8_t* tileMakeWritable(int num); uint8_t* tileCreate(int tilenum, int width, int height); - void tileSetExternal(int tilenum, int width, int height, uint8_t* data); int findUnusedTile(void); int tileCreateRotated(int owner); - void ClearTextureCache(bool artonly = false); void InvalidateTile(int num); void MakeCanvas(int tilenum, int width, int height); HightileReplacement* FindReplacement(int picnum, int palnum, bool skybox = false); @@ -367,7 +366,7 @@ inline const uint8_t* tilePtr(int num) { auto tex = TileFiles.tiledata[num].texture; if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return nullptr; - TileFiles.tiledata[num].rawCache.data = std::move(tex->Get8BitPixels(false)); + TileFiles.tiledata[num].rawCache.data = std::move(tex->GetTexture()->Get8BitPixels(false)); } TileFiles.tiledata[num].rawCache.lastUseTime = I_nsTime(); return TileFiles.tiledata[num].rawCache.data.Data(); @@ -381,7 +380,7 @@ inline bool tileLoad(int tileNum) inline uint8_t* tileData(int num) { auto tex = TileFiles.tiledata[num].texture; - auto p = dynamic_cast(tex); + auto p = dynamic_cast(tex->GetTexture()); return p ? p->GetRawData() : nullptr; } @@ -464,7 +463,7 @@ inline void tileInvalidate(int tilenume, int32_t, int32_t) TileFiles.InvalidateTile(tilenume); } -inline FTexture* tileGetTexture(int tile) +inline FGameTexture* tileGetTexture(int tile) { assert(tile < MAXTILES); return TileFiles.tiledata[tile].texture; diff --git a/source/glbackend/gl_texture.cpp b/source/glbackend/gl_texture.cpp index 75654eb0b..cd6cba48b 100644 --- a/source/glbackend/gl_texture.cpp +++ b/source/glbackend/gl_texture.cpp @@ -66,11 +66,11 @@ void FlipNonSquareBlock(T* dst, const T* src, int x, int y, int srcpitch) // //=========================================================================== -FHardwareTexture* GLInstance::CreateIndexedTexture(FTexture* tex) +FHardwareTexture* GLInstance::CreateIndexedTexture(FGameTexture* tex) { vec2_t siz = { tex->GetTexelWidth(), tex->GetTexelHeight() }; - auto store = tex->Get8BitPixels(false); + auto store = tex->GetTexture()->Get8BitPixels(false); const uint8_t* p = store.Data(); auto glpic = GLInterface.NewTexture(); @@ -88,9 +88,9 @@ FHardwareTexture* GLInstance::CreateIndexedTexture(FTexture* tex) // //=========================================================================== -FHardwareTexture* GLInstance::CreateTrueColorTexture(FTexture* tex, int palid, bool checkfulltransparency, bool rgb8bit) +FHardwareTexture* GLInstance::CreateTrueColorTexture(FGameTexture* tex, int palid, bool checkfulltransparency, bool rgb8bit) { - auto texbuffer = tex->CreateTexBuffer(palid, checkfulltransparency? 0: CTF_ProcessData); + auto texbuffer = tex->GetTexture()->CreateTexBuffer(palid, checkfulltransparency? 0: CTF_ProcessData); // Check if the texture is fully transparent. When creating a brightmap such textures can be discarded. if (checkfulltransparency) { @@ -122,21 +122,21 @@ FHardwareTexture* GLInstance::CreateTrueColorTexture(FTexture* tex, int palid, b // //=========================================================================== -FHardwareTexture* GLInstance::LoadTexture(FTexture* tex, int textype, int palid) +FHardwareTexture* GLInstance::LoadTexture(FGameTexture* tex, int textype, int palid) { if (textype == TT_INDEXED) palid = -1; - auto phwtex = tex->SystemTextures.GetHardwareTexture(palid, false); + auto phwtex = tex->GetTexture()->SystemTextures.GetHardwareTexture(palid, false); if (phwtex) return (FHardwareTexture*)phwtex; FHardwareTexture *hwtex = nullptr; if (textype == TT_INDEXED) hwtex = CreateIndexedTexture(tex); - else if (tex->GetUseType() != ETextureType::Canvas) + else if (!tex->GetTexture()->isHardwareCanvas()) hwtex = CreateTrueColorTexture(tex, textype == TT_HICREPLACE? -1 : palid, textype == TT_BRIGHTMAP, textype == TT_BRIGHTMAP); else hwtex = nullptr; - if (hwtex) tex->SystemTextures.AddHardwareTexture(palid, false, hwtex); + if (hwtex) tex->GetTexture()->SystemTextures.AddHardwareTexture(palid, false, hwtex); return hwtex; } @@ -148,7 +148,7 @@ FHardwareTexture* GLInstance::LoadTexture(FTexture* tex, int textype, int palid) struct TexturePick { - FTexture* texture; // which texture to use + FGameTexture* texture; // which texture to use int translation; // which translation table to use int tintFlags; // which shader tinting options to use PalEntry tintColor; // Tint color @@ -165,7 +165,7 @@ TexturePick PickTexture(int tilenum, int basepal, int palette) auto tex = TileFiles.tiles[tilenum]; auto rep = (hw_hightile && !(h.f & HICTINT_ALWAYSUSEART)) ? TileFiles.FindReplacement(tilenum, usepalswap) : nullptr; // Canvas textures must be treated like hightile replacements in the following code. - bool truecolor = rep || tex->GetUseType() == FTexture::Canvas; + bool truecolor = rep || tex->GetUseType() == FGameTexture::Canvas; bool applytint = false; if (truecolor) { @@ -203,7 +203,7 @@ TexturePick PickTexture(int tilenum, int basepal, int palette) } #endif -bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int method, int sampleroverride, FTexture *det, float detscale, FTexture *glow) +bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int palette, int method, int sampleroverride, FGameTexture *det, float detscale, FGameTexture *glow) { if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false; int usepalette = fixpalette >= 0 ? fixpalette : curbasepal; @@ -225,7 +225,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int // Canvas textures must be treated like hightile replacements in the following code. if (picnum < 0) picnum = TileFiles.GetTileIndex(tex); // Allow getting replacements also when the texture is not passed by its tile number. auto rep = (picnum >= 0 && hw_hightile && !(h.f & HICTINT_ALWAYSUSEART)) ? TileFiles.FindReplacement(picnum, palette) : nullptr; - if (rep || tex->GetUseType() == ETextureType::Canvas) + if (rep || tex->GetTexture()->isHardwareCanvas()) { if (usepalette != 0) { @@ -338,7 +338,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int } } #if 1 - if (picnum > -1 && !(TileFiles.tiledata[picnum].picanm.sf & PICANM_NOFULLBRIGHT_BIT) && !(globalflags & GLOBAL_NO_GL_FULLBRIGHT) && !tex->NoBrightmapFlag[usepalswap]) + if (picnum > -1 && !(TileFiles.tiledata[picnum].picanm.sf & PICANM_NOFULLBRIGHT_BIT) && !(globalflags & GLOBAL_NO_GL_FULLBRIGHT) && !TileFiles.tiledata[picnum].NoBrightmapFlag[usepalswap]) { if (TextureType == TT_HICREPLACE) { @@ -364,7 +364,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int if (htex == nullptr) { // Flag the texture as not being brightmapped for the given palette - tex->NoBrightmapFlag.Set(usepalswap); + TileFiles.tiledata[picnum].NoBrightmapFlag.Set(usepalswap); } else { @@ -400,7 +400,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int // //=========================================================================== -bool GLInstance::SetNamedTexture(FTexture* tex, int palette, int sampler) +bool GLInstance::SetNamedTexture(FGameTexture* tex, int palette, int sampler) { auto mtex = LoadTexture(tex, palette>= 0? TT_TRUECOLOR : TT_HICREPLACE, palette); if (!mtex) return false; @@ -417,11 +417,6 @@ int PalCheck(int tex) return tex; } -void DeleteSoftwareTexture(FSoftwareTexture *) -{ - -} - void InitBuildTiles() { diff --git a/source/glbackend/glbackend.h b/source/glbackend/glbackend.h index ea24ec832..cb462d9c8 100644 --- a/source/glbackend/glbackend.h +++ b/source/glbackend/glbackend.h @@ -14,7 +14,7 @@ class FSamplerManager; class FShader; class PolymostShader; class SurfaceShader; -class FTexture; +class FGameTexture; class GLInstance; class F2DDrawer; struct palette_t; @@ -115,7 +115,7 @@ class GLInstance PaletteManager palmanager; int lastPalswapIndex = -1; FHardwareTexture* texv; - FTexture* currentTexture = nullptr; + FGameTexture* currentTexture = nullptr; int TextureType; int MatrixChange = 0; @@ -474,19 +474,19 @@ public: renderState.AlphaThreshold = al; } - FHardwareTexture* CreateIndexedTexture(FTexture* tex); - FHardwareTexture* CreateTrueColorTexture(FTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false); - FHardwareTexture *LoadTexture(FTexture* tex, int texturetype, int palid); - bool SetTextureInternal(int globalpicnum, FTexture* tex, int palette, int method, int sampleroverride, FTexture *det, float detscale, FTexture *glow); + FHardwareTexture* CreateIndexedTexture(FGameTexture* tex); + FHardwareTexture* CreateTrueColorTexture(FGameTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false); + FHardwareTexture *LoadTexture(FGameTexture* tex, int texturetype, int palid); + bool SetTextureInternal(int globalpicnum, FGameTexture* tex, int palette, int method, int sampleroverride, FGameTexture *det, float detscale, FGameTexture *glow); - bool SetNamedTexture(FTexture* tex, int palette, int sampleroverride); + bool SetNamedTexture(FGameTexture* tex, int palette, int sampleroverride); - bool SetTexture(int globalpicnum, FTexture* tex, int palette, int method, int sampleroverride) + bool SetTexture(int globalpicnum, FGameTexture* tex, int palette, int method, int sampleroverride) { return SetTextureInternal(globalpicnum, tex, palette, method, sampleroverride, nullptr, 1, nullptr); } - bool SetModelTexture(FTexture *tex, int palette, FTexture *det, float detscale, FTexture *glow) + bool SetModelTexture(FGameTexture *tex, int palette, FGameTexture *det, float detscale, FGameTexture *glow) { return SetTextureInternal(-1, tex, palette, 8/*DAMETH_MODEL*/, -1, det, detscale, glow); } diff --git a/source/platform/posix/i_system.h b/source/platform/posix/i_system.h index 8d1e6db16..ad8fa8806 100644 --- a/source/platform/posix/i_system.h +++ b/source/platform/posix/i_system.h @@ -63,8 +63,8 @@ TArray I_GetGogPaths(); // The ini could not be saved at exit bool I_WriteIniFailed (); -class FTexture; -bool I_SetCursor(FTexture *); +class FGameTexture; +bool I_SetCursor(FGameTexture *); static inline char *strlwr(char *str) { diff --git a/source/platform/posix/sdl/i_gui.cpp b/source/platform/posix/sdl/i_gui.cpp index f7388d49d..cd3ffb3b8 100644 --- a/source/platform/posix/sdl/i_gui.cpp +++ b/source/platform/posix/sdl/i_gui.cpp @@ -38,14 +38,14 @@ #include "bitmap.h" #include "textures.h" -bool I_SetCursor(FTexture *cursorpic) +bool I_SetCursor(FGameTexture *cursorpic) { static SDL_Cursor *cursor; static SDL_Surface *cursorSurface; if (cursorpic != NULL) { - auto src = cursorpic->GetBgraBitmap(nullptr); + auto src = cursorpic->GetTexture()->GetBgraBitmap(nullptr); // Must be no larger than 32x32. if (src.GetWidth() > 32 || src.GetHeight() > 32) { diff --git a/source/platform/win32/i_system.cpp b/source/platform/win32/i_system.cpp index 44b883df0..a6ddbb4d3 100644 --- a/source/platform/win32/i_system.cpp +++ b/source/platform/win32/i_system.cpp @@ -646,13 +646,13 @@ int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad) // //========================================================================== -bool I_SetCursor(FTexture *cursorpic) +bool I_SetCursor(FGameTexture *cursorpic) { HCURSOR cursor; if (cursorpic != NULL) { - auto image = cursorpic->GetBgraBitmap(nullptr); + auto image = cursorpic->GetTexture()->GetBgraBitmap(nullptr); // Must be no larger than 32x32. (is this still necessary? if (image.GetWidth() > 32 || image.GetHeight() > 32) { diff --git a/source/platform/win32/i_system.h b/source/platform/win32/i_system.h index a59b6c532..071b25a93 100644 --- a/source/platform/win32/i_system.h +++ b/source/platform/win32/i_system.h @@ -62,8 +62,8 @@ void I_Quit (void); void I_Tactile (int on, int off, int total); // Set the mouse cursor. The texture must be 32x32. -class FTexture; -bool I_SetCursor(FTexture *cursor); +class FGameTexture; +bool I_SetCursor(FGameTexture *cursor); // Repaint the pre-game console void I_PaintConsole (void);