- updated to GZDoom's new texture management system.

This commit is contained in:
Christoph Oelckers 2020-05-25 23:59:07 +02:00
parent 7a1fda2cc2
commit c4017de12f
68 changed files with 2046 additions and 1782 deletions

View file

@ -783,6 +783,7 @@ set (PCH_SOURCES
common/textures/bitmap.cpp common/textures/bitmap.cpp
common/textures/m_png.cpp common/textures/m_png.cpp
common/textures/texture.cpp common/textures/texture.cpp
common/textures/gametexture.cpp
common/textures/image.cpp common/textures/image.cpp
common/textures/imagetexture.cpp common/textures/imagetexture.cpp
common/textures/texturemanager.cpp common/textures/texturemanager.cpp
@ -1018,6 +1019,7 @@ include_directories(
common/textures common/textures
common/textures/formats common/textures/formats
common/textures/hires common/textures/hires
common/textures
common/filesystem common/filesystem
common/utility common/utility
common/console common/console

View file

@ -856,7 +856,7 @@ void videoClearScreen(int32_t dacol);
void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang); 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, 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, 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 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, palette_t p);
void drawlinergb(int32_t x1, int32_t y1, int32_t x2, int32_t y2, PalEntry 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 ////////// ////////// 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, 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, 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); 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: // 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, 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); rotatesprite_(sx, sy, z, a, picnum, dashade, dapalnum, dastat, 0, 0, 0,0,xdim-1,ydim-1, pic, basepal);
} }

View file

@ -14,14 +14,14 @@
#define IDP2_MAGIC 0x32504449 #define IDP2_MAGIC 0x32504449
#define IDP3_MAGIC 0x33504449 #define IDP3_MAGIC 0x33504449
class FTexture; class FGameTexture;
class FHardwareTexture; class FHardwareTexture;
struct mdmodel_t struct mdmodel_t
{ {
int32_t mdnum, shadeoff; int32_t mdnum, shadeoff;
float scale, bscale, zadd, yoffset; float scale, bscale, zadd, yoffset;
FTexture *texture; FGameTexture *texture;
int32_t flags; int32_t flags;
}; };
@ -200,7 +200,7 @@ struct voxmodel_t : public mdmodel_t
EXTERN mdmodel_t **models; 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 mdinit(void);
void freeallmodels(void); void freeallmodels(void);
int32_t polymost_mddraw(tspriteptr_t tspr); int32_t polymost_mddraw(tspriteptr_t tspr);

View file

@ -50,7 +50,7 @@ void VPXTexture::SetFrame(const void *data_, int width, int height)
Width = width; Width = width;
Height = height; Height = height;
data = data_; data = data_;
SystemTextures.Clean(true, true); SystemTextures.Clean();
} }
//=========================================================================== //===========================================================================
@ -412,27 +412,27 @@ read_ivf_frame:
/////////////// DRAWING! /////////////// /////////////// DRAWING! ///////////////
static int sampler; static int sampler;
static VPXTexture* vpxtex[2]; static FGameTexture* vpxtex[2];
static int which; static int which;
void animvpx_setup_glstate(int32_t animvpx_flags) void animvpx_setup_glstate(int32_t animvpx_flags)
{ {
////////// GL STATE ////////// ////////// GL STATE //////////
vpxtex[0] = new VPXTexture; vpxtex[0] = MakeGameTexture(new VPXTexture, nullptr, ETextureType::Special);
vpxtex[1] = new VPXTexture; vpxtex[1] = MakeGameTexture(new VPXTexture, nullptr, ETextureType::Special);
if ((animvpx_flags & CUTSCENE_TEXTUREFILTER && hw_texfilter == TEXFILTER_ON) || animvpx_flags & CUTSCENE_FORCEFILTER || 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 else
{ {
sampler = SamplerNoFilterClampXY; sampler = CLAMP_XY;
} }
GLInterface.ClearScreen(0, true); GLInterface.ClearScreen(0, true);
} }
void animvpx_restore_glstate(void) 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 return 2; // shouldn't happen
which ^= 1; which ^= 1;
vpxtex[which]->SetFrame(codec->pic, codec->width, codec->height); static_cast<VPXTexture*>(vpxtex[which]->GetTexture())->SetFrame(codec->pic, codec->width, codec->height);
vpxtex[which]->CleanHardwareData();
float vid_wbyh = ((float)codec->width)/codec->height; float vid_wbyh = ((float)codec->width)/codec->height;
if (animvpx_aspect > 0) if (animvpx_aspect > 0)

View file

@ -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, 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, 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 = {}; F2DDrawer::RenderCommand dg = {};
int method = 0; 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); int light = clamp(scale((numshades - dashade), 255, numshades), 0, 255);
auto p = PalEntry((uint8_t)(alpha * 255), light, light, light); 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 }; vec2_16_t ofs = { 0, 0 };
if (!(dastat & RS_TOPLEFT)) 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, 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, 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) if (!tex && (unsigned)picnum >= MAXTILES)
return; return;

View file

@ -463,7 +463,7 @@ int32_t md_undefinemodel(int32_t modelid)
//Note: even though it says md2model, it works for both md2model&md3model //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; int32_t i;
mdskinmap_t *sk, *skzero = NULL; 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; if (exact) *exact = true;
//Printf("Using exact match skin (pal=%d,skinnum=%d,surfnum=%d) %s\n",pal,number,surf,skinfile); //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) //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; } 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); //Printf("Using def skin 0,0 as fallback, pal=%d\n", pal);
if (exact) *exact = false; if (exact) *exact = false;
return TexMan.GetTexture(skzero->texture); return TexMan.GetGameTexture(skzero->texture);
} }
else else
return nullptr; return nullptr;
@ -1711,7 +1711,7 @@ static int32_t polymost_md3draw(md3model_t *m, tspriteptr_t tspr)
if (!tex) if (!tex)
continue; continue;
FTexture *det = nullptr, *glow = nullptr; FGameTexture *det = nullptr, *glow = nullptr;
float detscale = 1.f; float detscale = 1.f;
// The data lookup here is one incredible mess. Thanks to whoever cooked this up... :( // The data lookup here is one incredible mess. Thanks to whoever cooked this up... :(

View file

@ -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]; float const r = 1.f / dd[i];
if (tileGetTexture(globalpicnum)->isCanvas()) if (tileGetTexture(globalpicnum)->GetTexture()->isHardwareCanvas())
{ {
//update texcoords, canvas textures are upside down! //update texcoords, canvas textures are upside down!
vt->SetTexCoord( vt->SetTexCoord(

View file

@ -234,7 +234,7 @@ void F2DDrawer::AddIndices(int firstvert, TArray<int> &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; FRenderStyle style = parms.style;
float alpha; 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. 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 // [MK] bail out if vertex/coord array sizes are mismatched
if ( shape->mVertices.Size() != shape->mCoords.Size() ) 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, double originx, double originy, double scalex, double scaley,
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double fadelevel, DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double fadelevel,
uint32_t *indices, size_t indexcount) uint32_t *indices, size_t indexcount)
{ {
RenderCommand poly; RenderCommand poly;
poly.mType = DrawTypeTriangles; 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 = {}; RenderCommand dg = {};
int method = 0; 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; 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. // scaling is not used here.
if (!local_origin) if (!local_origin)
{ {
fU1 = float(left) / src->GetDisplayWidth(); fU1 = float(left) / (float)src->GetDisplayWidth();
fV1 = float(top) / src->GetDisplayHeight(); fV1 = float(top) / (float)src->GetDisplayHeight();
fU2 = float(right) / src->GetDisplayWidth(); fU2 = float(right) / (float)src->GetDisplayWidth();
fV2 = float(bottom) / src->GetDisplayHeight(); fV2 = float(bottom) / (float)src->GetDisplayHeight();
} }
else else
{ {
fU1 = 0; fU1 = 0;
fV1 = 0; fV1 = 0;
fU2 = float(right - left) / src->GetDisplayWidth(); fU2 = float(right - left) / (float)src->GetDisplayWidth();
fV2 = float(bottom - top) / src->GetDisplayHeight(); fV2 = float(bottom - top) / (float)src->GetDisplayHeight();
} }
dg.mVertIndex = (int)mVertices.Reserve(4); dg.mVertIndex = (int)mVertices.Reserve(4);
auto ptr = &mVertices[dg.mVertIndex]; 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; PalEntry p = (PalEntry)color;
p.a = alpha; p.a = alpha;

View file

@ -124,7 +124,7 @@ public:
int mIndexIndex; int mIndexIndex;
int mIndexCount; int mIndexCount;
FTexture *mTexture; FGameTexture *mTexture;
int mTranslationId; int mTranslationId;
PalEntry mSpecialColormap[2]; PalEntry mSpecialColormap[2];
int mScissor[4]; int mScissor[4];
@ -170,19 +170,19 @@ public:
void AddIndices(int firstvert, int count, ...); void AddIndices(int firstvert, int count, ...);
private: private:
void AddIndices(int firstvert, TArray<int> &v); void AddIndices(int firstvert, TArray<int> &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); void SetColorOverlay(PalEntry color, float alpha, PalEntry &vertexcolor, PalEntry &overlaycolor);
public: public:
void AddTexture(FTexture *img, DrawParms &parms); void AddTexture(FGameTexture* img, DrawParms& parms);
void AddShape(FTexture *img, DShape2D *shape, DrawParms &parms); void AddShape(FGameTexture *img, DShape2D *shape, DrawParms &parms);
void AddPoly(FTexture *texture, FVector2 *points, int npoints, void AddPoly(FGameTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, double originx, double originy, double scalex, double scaley,
DAngle rotation, const FColormap &colormap, PalEntry flatcolor, double lightlevel, uint32_t *indices, size_t indexcount); 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, 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); 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 AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr);
void ClearScreen(PalEntry color = 0xff000000); 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 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 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); void AddPixel(int x1, int y1, uint32_t color);

View file

@ -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_List tags;
va_start(tags.list, tags_first); 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); 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; DrawParms parms;
uint32_t tag = ListGetInt(args); 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"); 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 }; VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 };
DrawTexture(twod, tex, x, y, args); DrawTexture(twod, tex, x, y, args);
return 0; 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_List tags;
va_start(tags.list, tags_first); 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); 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; DrawParms parms;
uint32_t tag = ListGetInt(args); 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"); 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 }; VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 };
DrawShape(twod, tex, shape, args); 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 GetWidth = [=]() { return drawer->GetWidth(); };
auto GetHeight = [=]() {return drawer->GetHeight(); }; auto GetHeight = [=]() {return drawer->GetHeight(); };
@ -342,8 +342,8 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FTexture *img, double
{ {
parms->x = xx; parms->x = xx;
parms->y = yy; parms->y = yy;
parms->texwidth = img->GetDisplayWidthDouble(); parms->texwidth = img->GetDisplayWidth();
parms->texheight = img->GetDisplayHeightDouble(); parms->texheight = img->GetDisplayHeight();
if (parms->top == INT_MAX || parms->fortext) if (parms->top == INT_MAX || parms->fortext)
{ {
parms->top = img->GetDisplayTopOffset(); parms->top = img->GetDisplayTopOffset();
@ -354,11 +354,11 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FTexture *img, double
} }
if (parms->destwidth == INT_MAX || parms->fortext) if (parms->destwidth == INT_MAX || parms->fortext)
{ {
parms->destwidth = img->GetDisplayWidthDouble(); parms->destwidth = img->GetDisplayWidth();
} }
if (parms->destheight == INT_MAX || parms->fortext) if (parms->destheight == INT_MAX || parms->fortext)
{ {
parms->destheight = img->GetDisplayHeightDouble(); parms->destheight = img->GetDisplayHeight();
} }
switch (parms->cleanmode) switch (parms->cleanmode)
@ -387,10 +387,12 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FTexture *img, double
case DTA_FullscreenEx: case DTA_FullscreenEx:
{ {
double aspect; double aspect;
double srcwidth = img->GetDisplayWidthDouble(); double srcwidth = img->GetDisplayWidth();
double srcheight = img->GetDisplayHeightDouble(); double srcheight = img->GetDisplayHeight();
int autoaspect = parms->fsscalemode; 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->x = parms->y = 0;
parms->keepratio = true; parms->keepratio = true;
auto screenratio = ActiveRatio(GetWidth(), GetHeight()); auto screenratio = ActiveRatio(GetWidth(), GetHeight());
@ -531,7 +533,7 @@ static inline FSpecialColormap * ListGetSpecialColormap(VMVa_List &tags)
//========================================================================== //==========================================================================
template<class T> template<class T>
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; INTBOOL boolval;
int intval; int intval;
@ -724,8 +726,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y,
if (img == NULL) return false; if (img == NULL) return false;
parms->cleanmode = DTA_Fullscreen; parms->cleanmode = DTA_Fullscreen;
parms->fsscalemode = (uint8_t)twod->fullscreenautoaspect; parms->fsscalemode = (uint8_t)twod->fullscreenautoaspect;
parms->virtWidth = img->GetDisplayWidthDouble(); parms->virtWidth = img->GetDisplayWidth();
parms->virtHeight = img->GetDisplayHeightDouble(); parms->virtHeight = img->GetDisplayHeight();
} }
break; break;
@ -738,8 +740,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y,
if (img == NULL) return false; if (img == NULL) return false;
parms->cleanmode = DTA_Fullscreen; parms->cleanmode = DTA_Fullscreen;
parms->fsscalemode = (uint8_t)intval; parms->fsscalemode = (uint8_t)intval;
parms->virtWidth = img->GetDisplayWidthDouble(); parms->virtWidth = img->GetDisplayWidth();
parms->virtHeight = img->GetDisplayHeightDouble(); parms->virtHeight = img->GetDisplayHeight();
} }
break; break;
@ -785,19 +787,19 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y,
break; break;
case DTA_SrcX: case DTA_SrcX:
parms->srcx = ListGetDouble(tags) / img->GetDisplayWidthDouble(); parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth();
break; break;
case DTA_SrcY: case DTA_SrcY:
parms->srcy = ListGetDouble(tags) / img->GetDisplayHeightDouble(); parms->srcy = ListGetDouble(tags) / img->GetDisplayHeight();
break; break;
case DTA_SrcWidth: case DTA_SrcWidth:
parms->srcwidth = ListGetDouble(tags) / img->GetDisplayWidthDouble(); parms->srcwidth = ListGetDouble(tags) / img->GetDisplayWidth();
break; break;
case DTA_SrcHeight: case DTA_SrcHeight:
parms->srcheight = ListGetDouble(tags) / img->GetDisplayHeightDouble(); parms->srcheight = ListGetDouble(tags) / img->GetDisplayHeight();
break; break;
case DTA_TopOffset: case DTA_TopOffset:
@ -829,8 +831,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y,
if (fortext) return false; if (fortext) return false;
if (ListGetInt(tags)) if (ListGetInt(tags))
{ {
parms->left = img->GetDisplayWidthDouble() * 0.5; parms->left = img->GetDisplayWidth() * 0.5;
parms->top = img->GetDisplayHeightDouble() * 0.5; parms->top = img->GetDisplayHeight() * 0.5;
} }
break; break;
@ -839,8 +841,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y,
if (fortext) return false; if (fortext) return false;
if (ListGetInt(tags)) if (ListGetInt(tags))
{ {
parms->left = img->GetDisplayWidthDouble() * 0.5; parms->left = img->GetDisplayWidth() * 0.5;
parms->top = img->GetDisplayHeightDouble(); parms->top = img->GetDisplayHeight();
} }
break; break;
@ -1038,8 +1040,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FTexture *img, double x, double y,
} }
// explicitly instantiate both versions for v_text.cpp. // explicitly instantiate both versions for v_text.cpp.
template bool ParseDrawTextureTags<Va_List>(F2DDrawer* drawer, FTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext); template bool ParseDrawTextureTags<Va_List>(F2DDrawer* drawer, FGameTexture *img, double x, double y, uint32_t tag, Va_List& tags, DrawParms *parms, bool fortext);
template bool ParseDrawTextureTags<VMVa_List>(F2DDrawer* drawer, FTexture *img, double x, double y, uint32_t tag, VMVa_List& tags, DrawParms *parms, bool fortext); template bool ParseDrawTextureTags<VMVa_List>(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 Width = drawer->GetWidth();
auto Height = drawer->GetHeight(); auto Height = drawer->GetHeight();
@ -1351,7 +1353,7 @@ void DrawBorder (F2DDrawer *drawer, FTextureID picnum, int x1, int y1, int x2, i
{ {
if (picnum.isValid()) if (picnum.isValid())
{ {
drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetTexture(picnum, false)); drawer->AddFlatFill (x1, y1, x2, y2, TexMan.GetGameTexture(picnum, false));
} }
else else
{ {

View file

@ -203,20 +203,21 @@ inline int active_con_scale(F2DDrawer *drawer)
#endif #endif
template<class T> template<class T>
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<class T> template<class T>
void DrawTextCommon(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double y, const T* string, DrawParms& parms); 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 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 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 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 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 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 DrawFrame(F2DDrawer* drawer, int left, int top, int width, int height);
void DrawBorder(F2DDrawer* drawer, FTextureID, int x1, int y1, int x2, int y2); void DrawBorder(F2DDrawer* drawer, FTextureID, int x1, int y1, int x2, int y2);

View file

@ -53,7 +53,7 @@ int ListGetInt(VMVa_List &tags);
// //
//========================================================================== //==========================================================================
#if 0 #if 0
FTexture * BuildTextTexture(FFont *font, const char *string, int textcolor) FGameTexture * BuildTextTexture(FFont *font, const char *string, int textcolor)
{ {
int w; int w;
const uint8_t *ch; const uint8_t *ch;
@ -61,7 +61,7 @@ FTexture * BuildTextTexture(FFont *font, const char *string, int textcolor)
int cy; int cy;
int trans = -1; int trans = -1;
int kerning; int kerning;
FTexture *pic; FGameTexture *pic;
kerning = font->GetDefaultKerning(); kerning = font->GetDefaultKerning();
@ -170,7 +170,7 @@ void DrawChar(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double
if (normalcolor >= NumTextColors) if (normalcolor >= NumTextColors)
normalcolor = CR_UNTRANSLATED; normalcolor = CR_UNTRANSLATED;
FTexture* pic; FGameTexture* pic;
int dummy; int dummy;
bool redirected; bool redirected;
@ -200,7 +200,7 @@ void DrawChar(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double
if (normalcolor >= NumTextColors) if (normalcolor >= NumTextColors)
normalcolor = CR_UNTRANSLATED; normalcolor = CR_UNTRANSLATED;
FTexture *pic; FGameTexture *pic;
int dummy; int dummy;
bool redirected; bool redirected;
@ -256,7 +256,7 @@ void DrawTextCommon(F2DDrawer *drawer, FFont *font, int normalcolor, double x, d
int boldcolor; int boldcolor;
int trans = -1; int trans = -1;
int kerning; int kerning;
FTexture *pic; FGameTexture *pic;
if (parms.celly == 0) parms.celly = font->GetHeight() + 1; if (parms.celly == 0) parms.celly = font->GetHeight() + 1;
parms.celly *= parms.scaley; parms.celly *= parms.scaley;

View file

@ -1082,16 +1082,17 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
} }
FTextureID chk = value; FTextureID chk = value;
if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull(); if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull();
FTexture *pic = TexMan.GetTexture(chk); auto pic = TexMan.GetGameTexture(chk);
const char *name; 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 else
{ {
name = pic->Name; name = pic->GetName();
} }
arc.WriteKey(key); arc.WriteKey(key);
arc.w->StartArray(); arc.w->StartArray();

View file

@ -57,7 +57,7 @@ extern FILE* hashfile;
struct FileSystem::LumpRecord struct FileSystem::LumpRecord
{ {
FResourceLump *lump; FResourceLump *lump;
FTexture* linkedTexture; FGameTexture* linkedTexture;
LumpShortName shortName; LumpShortName shortName;
FString longName; FString longName;
int rfnum; 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) 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) if ((size_t)lump < NumEntries)
{ {

View file

@ -16,7 +16,7 @@
class FResourceFile; class FResourceFile;
struct FResourceLump; struct FResourceLump;
class FTexture; class FGameTexture;
union LumpShortName union LumpShortName
{ {
@ -38,7 +38,7 @@ public:
~FileData (); ~FileData ();
void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); } void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); }
size_t GetSize () { return Block.Len(); } size_t GetSize () { return Block.Len(); }
FString GetString () { return Block; } const FString &GetString () const { return Block; }
private: private:
FileData (const FString &source); FileData (const FString &source);
@ -124,8 +124,8 @@ public:
inline int CheckNumForFullName (const FString &name, int wadfile) { return CheckNumForFullName(name.GetChars(), wadfile); } inline int CheckNumForFullName (const FString &name, int wadfile) { return CheckNumForFullName(name.GetChars(), wadfile); }
inline int GetNumForFullName (const FString &name) { return GetNumForFullName(name.GetChars()); } inline int GetNumForFullName (const FString &name) { return GetNumForFullName(name.GetChars()); }
void SetLinkedTexture(int lump, FTexture *tex); void SetLinkedTexture(int lump, FGameTexture *tex);
FTexture *GetLinkedTexture(int lump); FGameTexture *GetLinkedTexture(int lump);
void ReadFile (int lump, void *dest); void ReadFile (int lump, void *dest);

View file

@ -3,6 +3,8 @@
#ifndef __RESFILE_H #ifndef __RESFILE_H
#define __RESFILE_H #define __RESFILE_H
#include <limits.h>
#include "files.h" #include "files.h"
struct LumpFilterInfo struct LumpFilterInfo
@ -17,7 +19,6 @@ struct LumpFilterInfo
}; };
class FResourceFile; class FResourceFile;
class FTexture;
// [RH] Namespaces from BOOM. // [RH] Namespaces from BOOM.
// These are needed here in the low level part so that WAD files can be properly set up. // These are needed here in the low level part so that WAD files can be properly set up.

View file

@ -73,7 +73,6 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
int i; int i;
FTextureID lump; FTextureID lump;
char buffer[12]; char buffer[12];
int maxyoffs;
DVector2 Scale = { 1, 1 }; DVector2 Scale = { 1, 1 };
noTranslate = notranslate; noTranslate = notranslate;
@ -91,9 +90,7 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
translateUntranslated = false; translateUntranslated = false;
int FixedWidth = 0; int FixedWidth = 0;
maxyoffs = 0; TMap<int, FGameTexture*> charMap;
TMap<int, FTexture*> charMap;
int minchar = INT_MAX; int minchar = INT_MAX;
int maxchar = INT_MIN; int maxchar = INT_MIN;
@ -231,13 +228,13 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
Type = Multilump; Type = Multilump;
if (position < minchar) minchar = position; if (position < minchar) minchar = position;
if (position > maxchar) maxchar = position; if (position > maxchar) maxchar = position;
charMap.Insert(position, TexMan.GetTexture(lump)); charMap.Insert(position, TexMan.GetGameTexture(lump));
} }
} }
} }
else else
{ {
FTexture *texs[256] = {}; FGameTexture *texs[256] = {};
if (lcount > 256 - start) lcount = 256 - start; if (lcount > 256 - start) lcount = 256 - start;
for (i = 0; i < lcount; i++) 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); TexMan.ListTextures(buffer, array, true);
for (auto entry : array) for (auto entry : array)
{ {
FTexture *tex = TexMan.GetTexture(entry, false); auto tex = TexMan.GetGameTexture(entry, false);
if (tex && tex->GetSourceLump() >= 0 && fileSystem.GetFileContainer(tex->GetSourceLump()) <= fileSystem.GetMaxIwadNum() && tex->GetUseType() == ETextureType::MiscPatch) if (tex && !tex->isUserContent() && tex->GetUseType() == ETextureType::MiscPatch)
{ {
texs[i] = tex; 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 < minchar) minchar = (int)position;
if ((int)position > maxchar) maxchar = (int)position; if ((int)position > maxchar) maxchar = (int)position;
auto tex = TexMan.GetTexture(lump); auto tex = TexMan.GetGameTexture(lump);
tex->SetScale(Scale); tex->SetScale((float)Scale.X, (float)Scale.Y);
charMap.Insert((int)position, tex); charMap.Insert((int)position, tex);
Type = Folder; Type = Folder;
} }
@ -312,17 +309,13 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
auto lump = charMap.CheckKey(FirstChar + i); auto lump = charMap.CheckKey(FirstChar + i);
if (lump != nullptr) if (lump != nullptr)
{ {
FTexture *pic = *lump; auto pic = *lump;
if (pic != nullptr) if (pic != nullptr)
{ {
int height = pic->GetDisplayHeight(); double fheight = pic->GetDisplayHeight();
int yoffs = pic->GetDisplayTopOffset(); double yoffs = pic->GetDisplayTopOffset();
if (yoffs > maxyoffs) int height = int(fheight + abs(yoffs) + 0.5);
{
maxyoffs = yoffs;
}
height += abs(yoffs);
if (height > fontheight) if (height > fontheight)
{ {
fontheight = height; fontheight = height;
@ -333,24 +326,24 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
} }
} }
Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); auto orig = pic->GetTexture();
Chars[i].OriginalPic->SetUseType(ETextureType::FontChar); auto tex = MakeGameTexture(orig, nullptr, ETextureType::FontChar);
Chars[i].OriginalPic->CopySize(pic); tex->CopySize(pic);
TexMan.AddTexture(Chars[i].OriginalPic); TexMan.AddGameTexture(tex);
Chars[i].OriginalPic = tex;
if (!noTranslate) 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->CopySize(pic);
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); TexMan.AddGameTexture(Chars[i].TranslatedPic);
TexMan.AddTexture(Chars[i].TranslatedPic);
} }
else 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 else
{ {
@ -388,8 +381,8 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height, const DVector2 &Scale) void FFont::ReadSheetFont(TArray<FolderEntry> &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, // all valid lumps must be named with a hex number that represents the Unicode character index for its first character,
TArray<TexPart> part(1, true); TArray<TexPartBuild> part(1, true);
TMap<int, FTexture*> charMap; TMap<int, FGameTexture*> charMap;
int minchar = INT_MAX; int minchar = INT_MAX;
int maxchar = INT_MIN; int maxchar = INT_MIN;
for (auto &entry : folderdata) for (auto &entry : folderdata)
@ -402,7 +395,7 @@ void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height
auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch); auto lump = TexMan.CheckForTexture(entry.name, ETextureType::MiscPatch);
if (lump.isValid()) if (lump.isValid())
{ {
auto tex = TexMan.GetTexture(lump); auto tex = TexMan.GetGameTexture(lump);
int numtex_x = tex->GetTexelWidth() / width; int numtex_x = tex->GetTexelWidth() / width;
int numtex_y = tex->GetTexelHeight() / height; int numtex_y = tex->GetTexelHeight() / height;
int maxinsheet = int(position) + numtex_x * numtex_y - 1; int maxinsheet = int(position) + numtex_x * numtex_y - 1;
@ -415,25 +408,16 @@ void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height
{ {
part[0].OriginX = -width * x; part[0].OriginX = -width * x;
part[0].OriginY = -height * y; part[0].OriginY = -height * y;
part[0].Image = tex->GetImage(); part[0].TexImage = static_cast<FImageTexture*>(tex->GetTexture());
FMultiPatchTexture *image = new FMultiPatchTexture(width, height, part, false, false); FMultiPatchTexture *image = new FMultiPatchTexture(width, height, part, false, false);
FImageTexture *tex = new FImageTexture(image, ""); FImageTexture *tex = new FImageTexture(image);
tex->SetUseType(ETextureType::FontChar); auto gtex = MakeGameTexture(tex, nullptr, ETextureType::FontChar);
tex->bMultiPatch = true; gtex->SetWorldPanning(true);
tex->Width = width; gtex->SetOffsets(0, 0, 0);
tex->Height = height; gtex->SetOffsets(1, 0, 0);
tex->_LeftOffset[0] = gtex->SetScale((float)Scale.X, (float)Scale.Y);
tex->_LeftOffset[1] = TexMan.AddGameTexture(gtex);
tex->_TopOffset[0] = charMap.Insert(int(position) + x + y * numtex_x, gtex);
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);
} }
} }
} }
@ -458,18 +442,18 @@ void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height
auto lump = charMap.CheckKey(FirstChar + i); auto lump = charMap.CheckKey(FirstChar + i);
if (lump != nullptr) if (lump != nullptr)
{ {
FTexture *pic = *lump; auto pic = (*lump)->GetTexture();
auto b = pic->Get8BitPixels(false); 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->SetUseType(ETextureType::FontChar);
Chars[i].OriginalPic->CopySize(pic); Chars[i].OriginalPic->CopySize(*lump);
Chars[i].TranslatedPic = new FImageTexture(new FFontChar1(pic->GetImage()), ""); Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar1(pic->GetImage())), nullptr, ETextureType::FontChar);
Chars[i].TranslatedPic->CopySize(pic); Chars[i].TranslatedPic->CopySize(*lump);
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
TexMan.AddTexture(Chars[i].OriginalPic); TexMan.AddGameTexture(Chars[i].OriginalPic);
TexMan.AddTexture(Chars[i].TranslatedPic); TexMan.AddGameTexture(Chars[i].TranslatedPic);
} }
Chars[i].XMove = width; Chars[i].XMove = width;
} }
@ -619,7 +603,7 @@ void FFont::RecordAllTextureColors(uint32_t *usedcolors)
{ {
if (Chars[i].TranslatedPic) if (Chars[i].TranslatedPic)
{ {
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetImage()); FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage());
if (pic) if (pic)
{ {
// The remap must be temporarily reset here because this can be called on an initialized font. // 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); code = GetCharCode(code, true);
int xmove = SpaceWidth; int xmove = SpaceWidth;
@ -1037,11 +1021,11 @@ int FFont::GetCharWidth (int code) const
double GetBottomAlignOffset(FFont *font, int c) double GetBottomAlignOffset(FFont *font, int c)
{ {
int w; int w;
FTexture *tex_zero = font->GetChar('0', CR_UNDEFINED, &w); auto tex_zero = font->GetChar('0', CR_UNDEFINED, &w);
FTexture *texc = font->GetChar(c, CR_UNDEFINED, &w); auto texc = font->GetChar(c, CR_UNDEFINED, &w);
double offset = 0; double offset = 0;
if (texc) offset += texc->GetDisplayTopOffsetDouble(); if (texc) offset += texc->GetDisplayTopOffset();
if (tex_zero) offset += -tex_zero->GetDisplayTopOffsetDouble() + tex_zero->GetDisplayHeightDouble(); if (tex_zero) offset += -tex_zero->GetDisplayTopOffset() + tex_zero->GetDisplayHeight();
return offset; 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 w = 0;
int maxw = 0; int maxw = 0;
@ -1123,13 +1107,17 @@ int FFont::StringWidth(const uint8_t *string) const
maxw = w; maxw = w;
w = 0; w = 0;
} }
else if (spacing >= 0)
{
w += GetCharWidth(chr) + GlobalKerning + spacing;
}
else 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) if (Chars[i].TranslatedPic)
{ {
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetImage()); FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage());
if (pic) if (pic)
{ {
pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture 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++) for (unsigned int i = 0; i < count; i++)
{ {
if(Chars[i].TranslatedPic) if(Chars[i].TranslatedPic)
static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
} }
BuildTranslations (Luminosity.Data(), identity, &TranslationParms[TranslationType][0], ActiveColors, nullptr); BuildTranslations (Luminosity.Data(), identity, &TranslationParms[TranslationType][0], ActiveColors, nullptr);
@ -1286,7 +1274,7 @@ void FFont::FixXMoves()
} }
if (Chars[i].OriginalPic) if (Chars[i].OriginalPic)
{ {
int ofs = Chars[i].OriginalPic->GetDisplayTopOffset(); int ofs = (int)Chars[i].OriginalPic->GetDisplayTopOffset();
if (ofs > Displacement) Displacement = ofs; if (ofs > Displacement) Displacement = ofs;
} }
} }

View file

@ -289,10 +289,9 @@ public:
{ {
auto offset = hexdata.glyphmap[i]; auto offset = hexdata.glyphmap[i];
int size = hexdata.glyphdata[offset] / 16; 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 = MakeGameTexture(new FImageTexture(new FHexFontChar (&hexdata.glyphdata[offset+1], size, size * 9, 16)), nullptr, ETextureType::FontChar);
Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar);
Chars[i - FirstChar].XMove = size * spacing; Chars[i - FirstChar].XMove = size * spacing;
TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic); TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic);
} }
else Chars[i - FirstChar].XMove = spacing; else Chars[i - FirstChar].XMove = spacing;
@ -362,10 +361,9 @@ public:
{ {
auto offset = hexdata.glyphmap[i]; auto offset = hexdata.glyphmap[i];
int size = hexdata.glyphdata[offset] / 16; 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 = MakeGameTexture(new FImageTexture(new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18)), nullptr, ETextureType::FontChar);
Chars[i - FirstChar].TranslatedPic->SetUseType(ETextureType::FontChar);
Chars[i - FirstChar].XMove = size * spacing; Chars[i - FirstChar].XMove = size * spacing;
TexMan.AddTexture(Chars[i - FirstChar].TranslatedPic); TexMan.AddGameTexture(Chars[i - FirstChar].TranslatedPic);
} }
else Chars[i - FirstChar].XMove = spacing; else Chars[i - FirstChar].XMove = spacing;

View file

@ -167,10 +167,10 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump)
void FSingleLumpFont::CreateFontFromPic (FTextureID picnum) void FSingleLumpFont::CreateFontFromPic (FTextureID picnum)
{ {
FTexture *pic = TexMan.GetTexture(picnum); auto pic = TexMan.GetGameTexture(picnum);
FontHeight = pic->GetDisplayHeight (); FontHeight = (int)pic->GetDisplayHeight ();
SpaceWidth = pic->GetDisplayWidth (); SpaceWidth = (int)pic->GetDisplayWidth ();
GlobalKerning = 0; GlobalKerning = 0;
FirstChar = LastChar = 'A'; FirstChar = LastChar = 'A';
@ -222,7 +222,7 @@ void FSingleLumpFont::LoadTranslations()
for(unsigned int i = 0;i < count;++i) for(unsigned int i = 0;i < count;++i)
{ {
if(Chars[i].TranslatedPic) if(Chars[i].TranslatedPic)
static_cast<FFontChar2*>(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); static_cast<FFontChar2*>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
} }
BuildTranslations (luminosity, useidentity ? identity : nullptr, ranges, ActiveColors, usepalette ? local_palette : nullptr); 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 else
{ {
Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)); Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)), nullptr, ETextureType::FontChar);
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); TexMan.AddGameTexture(Chars[i].TranslatedPic);
TexMan.AddTexture(Chars[i].TranslatedPic);
do do
{ {
int8_t code = *data_p++; int8_t code = *data_p++;
@ -483,15 +482,14 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
{ // Empty character: skip it. { // Empty character: skip it.
continue; 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+1], // width
chardata[chari+2], // height chardata[chari+2], // height
-(int8_t)chardata[chari+3], // x offset -(int8_t)chardata[chari+3], // x offset
-(int8_t)chardata[chari+4] // y offset -(int8_t)chardata[chari+4] // y offset
)); )), nullptr, ETextureType::FontChar);
tex->SetUseType(ETextureType::FontChar);
Chars[chardata[chari] - FirstChar].TranslatedPic = tex; 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. // 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) if(!Chars[i].TranslatedPic)
{ {
Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)); Chars[i].TranslatedPic = MakeGameTexture(new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)), nullptr, ETextureType::FontChar);
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar);
Chars[i].XMove = SpaceWidth; 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. // Advance to next char's data and count the used colors.

View file

@ -45,7 +45,7 @@ public:
FSinglePicFont(const char *picname); FSinglePicFont(const char *picname);
// FFont interface // 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; int GetCharWidth (int code) const;
protected: protected:
@ -72,11 +72,11 @@ FSinglePicFont::FSinglePicFont(const char *picname) :
I_FatalError ("%s is not a font or texture", picname); I_FatalError ("%s is not a font or texture", picname);
} }
FTexture *pic = TexMan.GetTexture(picnum); auto pic = TexMan.GetGameTexture(picnum);
FontName = picname; FontName = picname;
FontHeight = pic->GetDisplayHeight(); FontHeight = (int)pic->GetDisplayHeight();
SpaceWidth = pic->GetDisplayWidth(); SpaceWidth = (int)pic->GetDisplayWidth();
GlobalKerning = 0; GlobalKerning = 0;
FirstChar = LastChar = 'A'; FirstChar = LastChar = 'A';
ActiveColors = 0; 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; *width = SpaceWidth;
if (redirected) *redirected = false; if (redirected) *redirected = false;
if (code == 'a' || code == 'A') if (code == 'a' || code == 'A')
{ {
return TexMan.GetPalettedTexture(PicNum, true); return TexMan.GetGameTexture(PicNum, true);
} }
else else
{ {

View file

@ -45,7 +45,7 @@
class FSpecialFont : public FFont class FSpecialFont : public FFont
{ {
public: 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(); 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) : FFont(lump)
{ {
int i; int i;
TArray<FTexture *> charlumps(count, true); TArray<FGameTexture *> charlumps(count, true);
int maxyoffs; int maxyoffs;
FTexture *pic; FGameTexture *pic;
memcpy(this->notranslate, notranslate, 256*sizeof(bool)); 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]; pic = charlumps[i] = lumplist[i];
if (pic != nullptr) if (pic != nullptr)
{ {
int height = pic->GetDisplayHeight(); int height = (int)pic->GetDisplayHeight();
int yoffs = pic->GetDisplayTopOffset(); int yoffs = (int)pic->GetDisplayTopOffset();
if (yoffs > maxyoffs) if (yoffs > maxyoffs)
{ {
@ -104,20 +104,18 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l
if (charlumps[i] != nullptr) if (charlumps[i] != nullptr)
{ {
auto pic = charlumps[i]; auto pic = charlumps[i];
Chars[i].OriginalPic = new FImageTexture(pic->GetImage(), ""); Chars[i].OriginalPic = MakeGameTexture(pic->GetTexture(), nullptr, ETextureType::FontChar);
Chars[i].OriginalPic->SetUseType(ETextureType::FontChar);
Chars[i].OriginalPic->CopySize(pic); Chars[i].OriginalPic->CopySize(pic);
TexMan.AddTexture(Chars[i].OriginalPic); TexMan.AddGameTexture(Chars[i].OriginalPic);
if (!noTranslate) 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->CopySize(charlumps[i]);
Chars[i].TranslatedPic->SetUseType(ETextureType::FontChar); TexMan.AddGameTexture(Chars[i].TranslatedPic);
TexMan.AddTexture(Chars[i].TranslatedPic);
} }
else Chars[i].TranslatedPic = Chars[i].OriginalPic; else Chars[i].TranslatedPic = Chars[i].OriginalPic;
Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); Chars[i].XMove = (int)Chars[i].TranslatedPic->GetDisplayWidth();
} }
else else
{ {
@ -167,7 +165,7 @@ void FSpecialFont::LoadTranslations()
{ {
if (Chars[i].TranslatedPic) if (Chars[i].TranslatedPic)
{ {
FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetImage()); FFontChar1 *pic = static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage());
if (pic) if (pic)
{ {
pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture 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++) for (i = 0; i < count; i++)
{ {
if(Chars[i].TranslatedPic) if(Chars[i].TranslatedPic)
static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); static_cast<FFontChar1 *>(Chars[i].TranslatedPic->GetTexture()->GetImage())->SetSourceRemap(PatchRemap);
} }
BuildTranslations(Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr, [=](FRemapTable* remap) BuildTranslations(Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr, [=](FRemapTable* remap)
@ -217,7 +215,7 @@ void FSpecialFont::LoadTranslations()
ActiveColors = TotalColors; 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); return new FSpecialFont(name, first, count, lumplist, notranslate, lump, donttranslate);
} }

View file

@ -144,7 +144,7 @@ FFont *V_GetFont(const char *name, const char *fontlumpname)
FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any); FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any);
if (picnum.isValid()) if (picnum.isValid())
{ {
FTexture *tex = TexMan.GetTexture(picnum); auto tex = TexMan.GetGameTexture(picnum);
if (tex && tex->GetSourceLump() >= folderfile) if (tex && tex->GetSourceLump() >= folderfile)
{ {
FFont *CreateSinglePicFont(const char *name); FFont *CreateSinglePicFont(const char *name);
@ -170,7 +170,7 @@ FFont *V_GetFont(const char *name, const char *fontlumpname)
void V_InitCustomFonts() void V_InitCustomFonts()
{ {
FScanner sc; FScanner sc;
FTexture *lumplist[256]; FGameTexture *lumplist[256];
bool notranslate[256]; bool notranslate[256];
bool donttranslate; bool donttranslate;
FString namebuffer, templatebuf; FString namebuffer, templatebuf;
@ -266,12 +266,12 @@ void V_InitCustomFonts()
else else
{ {
if (format == 1) goto wrong; if (format == 1) goto wrong;
FTexture **p = &lumplist[*(unsigned char*)sc.String]; FGameTexture **p = &lumplist[*(unsigned char*)sc.String];
sc.MustGetString(); sc.MustGetString();
FTextureID texid = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); FTextureID texid = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch);
if (texid.Exists()) if (texid.Exists())
{ {
*p = TexMan.GetTexture(texid); *p = TexMan.GetGameTexture(texid);
} }
else if (fileSystem.GetFileContainer(sc.LumpNum) >= fileSystem.GetIwadNum()) else if (fileSystem.GetFileContainer(sc.LumpNum) >= fileSystem.GetIwadNum())
{ {
@ -307,7 +307,7 @@ void V_InitCustomFonts()
} }
if (count > 0) 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); FFont *fnt = CreateSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump, donttranslate);
fnt->SetCursor(cursor); fnt->SetCursor(cursor);
fnt->SetKerning(kerning); fnt->SetKerning(kerning);

View file

@ -39,7 +39,7 @@
#include "name.h" #include "name.h"
class DCanvas; class DCanvas;
class FTexture; class FGameTexture;
struct FRemapTable; struct FRemapTable;
enum EColorRange : int enum EColorRange : int
@ -77,7 +77,7 @@ enum EColorRange : int
extern int NumTextColors; extern int NumTextColors;
using GlyphSet = TMap<int, FTexture*>; using GlyphSet = TMap<int, FGameTexture*>;
class FFont 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); 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 ~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; virtual int GetCharWidth (int code) const;
int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const;
int GetLump() const { return Lump; } int GetLump() const { return Lump; }
@ -113,9 +113,9 @@ public:
static FFont *FindFont(FName fontname); static FFont *FindFont(FName fontname);
// Return width of string in pixels (unscaled) // Return width of string in pixels (unscaled)
int StringWidth (const uint8_t *str) const; int StringWidth (const uint8_t *str, int spacing = 0) const;
inline int StringWidth (const char *str) const { return StringWidth ((const uint8_t *)str); } inline int StringWidth (const char *str, int spacing = 0) const { return StringWidth ((const uint8_t *)str, spacing); }
inline int StringWidth (const FString &str) const { return StringWidth ((const uint8_t *)str.GetChars()); } 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. // Checks if the font contains all characters to print this text.
bool CanPrint(const uint8_t *str) const; bool CanPrint(const uint8_t *str) const;
@ -161,8 +161,8 @@ protected:
bool forceremap = false; bool forceremap = false;
struct CharData struct CharData
{ {
FTexture *TranslatedPic = nullptr; // Texture for use with font translations. FGameTexture *TranslatedPic = nullptr; // Texture for use with font translations.
FTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization. FGameTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization.
int XMove = INT_MIN; int XMove = INT_MIN;
}; };
TArray<CharData> Chars; TArray<CharData> Chars;

View file

@ -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 int CastS2So(FString *b) { return FSoundID(*b); }
static void CastSo2S(FString* a, int b) { *a = soundEngine->GetSoundName(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 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() void JitCompiler::EmitCAST()
{ {

View file

@ -1848,7 +1848,7 @@ static void DoCast(const VMRegisters &reg, const VMFrame *f, int a, int b, int c
case CAST_TID2S: case CAST_TID2S:
{ {
ASSERTS(a); ASSERTD(b); 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(); reg.s[a] = tex == nullptr ? "(null)" : tex->GetName().GetChars();
break; break;
} }

View file

@ -43,14 +43,14 @@
void AnimTexture::SetFrameSize(int width, int height) void AnimTexture::SetFrameSize(int width, int height)
{ {
FTexture::SetSize(width, 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(Palette, palette, 768);
memcpy(Image.Data(), data_, Width * Height); memcpy(Image.Data(), data_, Width * Height);
SystemTextures.Clean(true, true); CleanHardwareTextures();
} }
//=========================================================================== //===========================================================================
@ -70,10 +70,10 @@ FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans)
for (int i = 0; i < Width * Height; i++) for (int i = 0; i < Width * Height; i++)
{ {
int p = i * 4; int p = i * 4;
int index = spix[i]; int index = spix[i];
dpix[p + 0] = Palette[index*3+2]; dpix[p + 0] = Palette[index * 3 + 2];
dpix[p + 1] = Palette[index*3+1]; dpix[p + 1] = Palette[index * 3 + 1];
dpix[p + 2] = Palette[index*3]; dpix[p + 2] = Palette[index * 3];
dpix[p + 3] = 255; dpix[p + 3] = 255;
} }
return bmp; return bmp;
@ -87,30 +87,32 @@ FBitmap AnimTexture::GetBgraBitmap(const PalEntry* remap, int* trans)
AnimTextures::AnimTextures() AnimTextures::AnimTextures()
{ {
active = 1; active = 1;
tex[0] = new AnimTexture; tex[0] = MakeGameTexture(new AnimTexture, "", ETextureType::Special);
tex[1] = new AnimTexture; tex[1] = MakeGameTexture(new AnimTexture, "", ETextureType::Special);
} }
AnimTextures::~AnimTextures() AnimTextures::~AnimTextures()
{ {
delete tex[0]; delete tex[0];
delete tex[1]; delete tex[1];
} }
void AnimTextures::SetSize(int width, int height) void AnimTextures::SetSize(int width, int height)
{ {
tex[0]->SetFrameSize(width, height); static_cast<AnimTexture*>(tex[0]->GetTexture())->SetFrameSize(width, height);
tex[1]->SetFrameSize(width, height); static_cast<AnimTexture*>(tex[1]->GetTexture())->SetFrameSize(width, height);
} tex[0]->SetSize(width, height);
tex[1]->SetSize(width, height);
void AnimTextures::SetFrame(const uint8_t *palette, const void* data)
{
active ^= 1;
tex[active]->SetFrame(palette, data);
} }
FTexture * AnimTextures::GetFrame() void AnimTextures::SetFrame(const uint8_t* palette, const void* data)
{ {
return tex[active]; active ^= 1;
static_cast<AnimTexture*>(tex[active]->GetTexture())->SetFrame(palette, data);
}
FGameTexture* AnimTextures::GetFrame()
{
return tex[active];
} }

View file

@ -8,21 +8,21 @@ class AnimTexture : public FTexture
uint8_t Palette[768]; uint8_t Palette[768];
TArray<uint8_t> Image; TArray<uint8_t> Image;
public: public:
AnimTexture() = default; AnimTexture() = default;
void SetFrameSize(int width, int height); void SetFrameSize(int width, int height);
void SetFrame(const uint8_t *palette, const void* data); void SetFrame(const uint8_t* palette, const void* data);
virtual FBitmap GetBgraBitmap(const PalEntry* remap, int* trans) override; virtual FBitmap GetBgraBitmap(const PalEntry* remap, int* trans) override;
}; };
class AnimTextures class AnimTextures
{ {
int active; int active;
AnimTexture *tex[2]; FGameTexture* tex[2];
public: public:
AnimTextures(); AnimTextures();
~AnimTextures(); ~AnimTextures();
void SetSize(int width, int height); void SetSize(int width, int height);
void SetFrame(const uint8_t *palette, const void* data); void SetFrame(const uint8_t* palette, const void* data);
FTexture *GetFrame(); FGameTexture* GetFrame();
}; };

View file

@ -69,6 +69,11 @@ FImageSource *EmptyImage_TryCreate(FileReader & file, int lumpnum)
return new FEmptyTexture(lumpnum); return new FEmptyTexture(lumpnum);
} }
FImageSource* CreateEmptyTexture()
{
return new FEmptyTexture(0);
}
//========================================================================== //==========================================================================
// //
// //

View file

@ -46,15 +46,19 @@
// //
//========================================================================== //==========================================================================
FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray<TexPart> &parts, bool complex, bool textual) FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray<TexPartBuild> &parts, bool complex, bool textual)
{ {
Width = w; Width = w;
Height = h; Height = h;
bComplex = complex; bComplex = complex;
bTextual = textual; bTextual = textual;
Parts = (TexPart*)ImageArena.Alloc(sizeof(TexPart) * parts.Size()); Parts = (TexPart*)ImageArena.Alloc(sizeof(TexPart) * parts.Size());
NumParts = parts.Size(); NumParts = parts.Size();
memcpy(Parts, parts.Data(), sizeof(TexPart) * 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; bUseGamePalette = false;
if (!bComplex) if (!bComplex)
@ -67,6 +71,27 @@ FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray<TexPart> &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 // GetBlendMap
@ -203,11 +228,6 @@ TArray<uint8_t> FMultiPatchTexture::CreatePalettedPixels(int conversion)
} }
if (conversion == noremap0) 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; if (bTextual || !UseGamePalette()) conversion = normal;
} }

View file

@ -5,8 +5,11 @@
#include "vectors.h" #include "vectors.h"
#include "bitmap.h" #include "bitmap.h"
#include "image.h" #include "image.h"
#include "textures.h"
class FImageTexture; class FImageTexture;
class FTextureManager;
//========================================================================== //==========================================================================
// //
// TexPart is the data that will get passed to the final texture. // TexPart is the data that will get passed to the final texture.
@ -25,6 +28,18 @@ struct TexPart
uint8_t op = OP_COPY; 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 class FMultiPatchTexture : public FImageSource
{ {
friend class FTexture; friend class FTexture;
friend class FGameTexture;
public: public:
FMultiPatchTexture(int w, int h, const TArray<TexPart> &parts, bool complex, bool textual); FMultiPatchTexture(int w, int h, const TArray<TexPartBuild> &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: protected:
int NumParts; int NumParts;
@ -64,7 +92,7 @@ struct TexInit
{ {
FString TexName; FString TexName;
ETextureType UseType = ETextureType::Null; ETextureType UseType = ETextureType::Null;
FTexture *Texture = nullptr; FImageTexture *Texture = nullptr;
bool Silent = false; bool Silent = false;
bool HasLine = false; bool HasLine = false;
bool UseOffsets = false; bool UseOffsets = false;
@ -82,7 +110,7 @@ struct FPatchLookup;
struct BuildInfo struct BuildInfo
{ {
FString Name; FString Name;
TArray<TexPart> Parts; TArray<TexPartBuild> Parts;
TArray<TexInit> Inits; TArray<TexInit> Inits;
int Width = 0; int Width = 0;
int Height = 0; int Height = 0;
@ -94,7 +122,7 @@ struct BuildInfo
bool bNoDecals = false; bool bNoDecals = false;
int LeftOffset[2] = {}; int LeftOffset[2] = {};
int TopOffset[2] = {}; int TopOffset[2] = {};
FImageTexture *tex = nullptr; FGameTexture *texture = nullptr;
void swap(BuildInfo &other) void swap(BuildInfo &other)
{ {
@ -113,7 +141,7 @@ struct BuildInfo
std::swap(LeftOffset[1], other.LeftOffset[1]); std::swap(LeftOffset[1], other.LeftOffset[1]);
std::swap(TopOffset[0], other.TopOffset[0]); std::swap(TopOffset[0], other.TopOffset[0]);
std::swap(TopOffset[1], other.TopOffset[1]); 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; FTextureManager &TexMan;
TArray<BuildInfo> BuiltTextures; TArray<BuildInfo> BuiltTextures;
TMap<FGameTexture*, bool> complex;
void(*progressFunc)(); void(*progressFunc)();
void(*checkForHacks)(BuildInfo&); void(*checkForHacks)(BuildInfo&);
void MakeTexture(BuildInfo &buildinfo, ETextureType usetype); 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 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 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); void ResolvePatches(BuildInfo &buildinfo);
public: public:

View file

@ -63,6 +63,7 @@ public:
FPatchTexture (int lumpnum, int w, int h, int lo, int to, bool isalphatex); FPatchTexture (int lumpnum, int w, int h, int lo, int to, bool isalphatex);
TArray<uint8_t> CreatePalettedPixels(int conversion) override; TArray<uint8_t> CreatePalettedPixels(int conversion) override;
int CopyPixels(FBitmap *bmp, int conversion) override; int CopyPixels(FBitmap *bmp, int conversion) override;
bool SupportRemap0() override { return !badflag; }
void DetectBadPatches(); void DetectBadPatches();
}; };

View file

@ -41,8 +41,8 @@
#include "imagehelpers.h" #include "imagehelpers.h"
#include "image.h" #include "image.h"
#include "printf.h" #include "printf.h"
#include "texturemanager.h"
#include "filesystem.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) 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. // 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; 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; Width = width;
Height = height; Height = height;
Masked = false;
bTranslucent = false;
fr = std::move(lump); fr = std::move(lump);
} }

View file

@ -38,6 +38,7 @@
#include "bitmap.h" #include "bitmap.h"
#include "imagehelpers.h" #include "imagehelpers.h"
#include "image.h" #include "image.h"
#include "textures.h"
class FBarShader : public FImageSource 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'); 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);
} }

View file

@ -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<FTexture> 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<FImageTexture*>(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();
}

View file

@ -0,0 +1,339 @@
#pragma once
#include <stdint.h>
#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<FTexture> Base;
RefCountedPtr<FTexture> Brightmap;
RefCountedPtr<FTexture> Detailmap;
RefCountedPtr<FTexture> Glowmap;
RefCountedPtr<FTexture> Normal; // Normal map texture
RefCountedPtr<FTexture> Specular; // Specular light texture for the diffuse+normal+specular light model
RefCountedPtr<FTexture> Metallic; // Metalness texture for the physically based rendering (PBR) light model
RefCountedPtr<FTexture> Roughness; // Roughness texture for PBR
RefCountedPtr<FTexture> AmbientOcclusion; // Ambient occlusion texture for PBR
RefCountedPtr<FTexture> 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<FTexture*>& 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);
};

View file

@ -46,6 +46,8 @@
#include "texturemanager.h" #include "texturemanager.h"
#include "printf.h" #include "printf.h"
int upscalemask;
EXTERN_CVAR(Int, gl_texture_hqresizemult) EXTERN_CVAR(Int, gl_texture_hqresizemult)
CUSTOM_CVAR(Int, gl_texture_hqresizemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) 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)) if ((gl_texture_hqresizemult > 4) && (self < 4) && (self > 0))
gl_texture_hqresizemult = 4; gl_texture_hqresizemult = 4;
TexMan.FlushAll(); TexMan.FlushAll();
UpdateUpscaleMask();
} }
CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) 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)) if ((self > 4) && (gl_texture_hqresizemode < 4) && (gl_texture_hqresizemode > 0))
self = 4; self = 4;
TexMan.FlushAll(); TexMan.FlushAll();
UpdateUpscaleMask();
} }
CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) 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) CUSTOM_CVAR(Int, gl_texture_hqresize_targets, 7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{ {
TexMan.FlushAll(); TexMan.FlushAll();
UpdateUpscaleMask();
} }
CVAR (Flag, gl_texture_hqresize_textures, gl_texture_hqresize_targets, 1); 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) 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() static void xbrzApplyOptions()
{ {
if (gl_texture_hqresizemult != 0 && (gl_texture_hqresizemode == 4 || gl_texture_hqresizemode == 5)) 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. // the upsampled buffer.
// //
//=========================================================================== //===========================================================================
void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly) void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly)
{ {
// [BB] Make sure that inWidth and inHeight denote the size of // [BB] Make sure that inWidth and inHeight denote the size of
// the returned buffer even if we don't upsample the input buffer. // the returned buffer even if we don't upsample the input buffer.
int inWidth = texbuffer.mWidth; int inWidth = texbuffer.mWidth;
int inHeight = texbuffer.mHeight; 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 type = gl_texture_hqresizemode;
int mult = gl_texture_hqresizemult; int mult = gl_texture_hqresizemult;
#ifdef HAVE_MMX #ifdef HAVE_MMX
@ -509,3 +494,28 @@ void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasA
contentId.scalefactor = mult; contentId.scalefactor = mult;
texbuffer.mContentId = contentId.id; 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;
}

View file

@ -14,10 +14,8 @@ public:
MAX_TEXTURES = 16 MAX_TEXTURES = 16
}; };
IHardwareTexture() {} IHardwareTexture() = default;
virtual ~IHardwareTexture() {} virtual ~IHardwareTexture() = default;
virtual void DeleteDescriptors() { }
virtual void AllocateBuffer(int w, int h, int texelsize) = 0; virtual void AllocateBuffer(int w, int h, int texelsize) = 0;
virtual uint8_t *MapBuffer() = 0; virtual uint8_t *MapBuffer() = 0;

View file

@ -27,8 +27,8 @@
#include "hw_material.h" #include "hw_material.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "v_video.h"
EXTERN_CVAR(Bool, gl_texture_usehires)
IHardwareTexture* CreateHardwareTexture(); IHardwareTexture* CreateHardwareTexture();
//=========================================================================== //===========================================================================
@ -37,99 +37,100 @@ IHardwareTexture* CreateHardwareTexture();
// //
//=========================================================================== //===========================================================================
FMaterial::FMaterial(FTexture * tx, bool expanded) FMaterial::FMaterial(FGameTexture * tx, int scaleflags)
{ {
mShaderIndex = SHADER_Default; mShaderIndex = SHADER_Default;
sourcetex = tex = tx; sourcetex = tx;
auto imgtex = tx->GetTexture();
mTextureLayers.Push({ imgtex, scaleflags });
if (tx->UseType == ETextureType::SWCanvas && static_cast<FWrapperTexture*>(tx)->GetColorFormat() == 0) if (tx->GetUseType() == ETextureType::SWCanvas && static_cast<FWrapperTexture*>(imgtex)->GetColorFormat() == 0)
{ {
mShaderIndex = SHADER_Paletted; mShaderIndex = SHADER_Paletted;
} }
else if (tx->isWarped())
{
mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2
}
else if (tx->isHardwareCanvas()) 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 // no brightmap for cameratexture
} }
else 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; 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; 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(); tx->CreateDefaultBrightmap();
if (tx->Brightmap) auto placeholder = TexMan.GameByIndex(1);
if (tx->Brightmap.get())
{ {
mTextureLayers.Push(tx->Brightmap); mTextureLayers.Push({ tx->Brightmap.get(), scaleflags });
if (mShaderIndex == SHADER_Specular) mLayerFlags |= TEXF_Brightmap;
mShaderIndex = SHADER_SpecularBrightmap; }
else if (mShaderIndex == SHADER_PBR) else
mShaderIndex = SHADER_PBRBrightmap; {
else mTextureLayers.Push({ placeholder->GetTexture(), 0 });
mShaderIndex = SHADER_Brightmap; }
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 if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material
{ {
for (auto &texture : tx->CustomShaderTextures) for (auto &texture : tx->CustomShaderTextures)
{ {
if (texture == nullptr) continue; 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(); mScaleFlags = scaleflags;
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();
mTextureLayers.ShrinkToFit(); mTextureLayers.ShrinkToFit();
tx->Material[expanded] = this; tx->Material[scaleflags] = this;
if (tx->isHardwareCanvas()) tx->bTranslucent = 0; 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 &layer = mTextureLayers[i];
auto topOffset = tex->GetTopOffsetHW(); if (pLayer) *pLayer = &layer;
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;
if (layer && layer->UseType!=ETextureType::Null) if (layer.layerTexture) return layer.layerTexture->GetHardwareTexture(translation, layer.scaleFlags);
{
IHardwareTexture *hwtex = layer->SystemTextures.GetHardwareTexture(translation, mExpanded);
if (hwtex == nullptr)
{
hwtex = CreateHardwareTexture();
layer->SystemTextures.AddHardwareTexture(translation, mExpanded, hwtex);
}
return hwtex;
}
return nullptr; 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 // 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 0
if (tex && tex->isValid()) 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 (hwtex == NULL && create)
{ {
if (expand) hwtex = screen->CreateMaterial(gtex, scaleflags);
{
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);
} }
return hwtex; return hwtex;
} }
#endif
return NULL; 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) void DeleteMaterial(FMaterial* mat)
{ {
delete 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();
}
}
}
}

View file

@ -8,18 +8,12 @@
struct FRemapTable; struct FRemapTable;
class IHardwareTexture; class IHardwareTexture;
enum struct MaterialLayerInfo
{ {
CLAMP_NONE = 0, FTexture* layerTexture;
CLAMP_X = 1, int scaleFlags;
CLAMP_Y = 2,
CLAMP_XY = 3,
CLAMP_XY_NOMIP = 4,
CLAMP_NOFILTER = 5,
CLAMP_CAMTEX = 6,
}; };
//=========================================================================== //===========================================================================
// //
// this is the material class for OpenGL. // this is the material class for OpenGL.
@ -28,108 +22,42 @@ enum
class FMaterial class FMaterial
{ {
TArray<FTexture*> mTextureLayers; private:
TArray<MaterialLayerInfo> mTextureLayers; // the only layers allowed to scale are the brightmap and the glowmap.
int mShaderIndex; int mShaderIndex;
int mLayerFlags = 0;
short mLeftOffset; int mScaleFlags;
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);
public: public:
FTexture *tex; FGameTexture *sourcetex; // the owning texture.
FTexture *sourcetex; // in case of redirection this is different from tex.
FMaterial(FGameTexture *tex, int scaleflags);
FMaterial(FTexture *tex, bool forceexpand); virtual ~FMaterial();
~FMaterial(); int GetLayerFlags() const { return mLayerFlags; }
void SetSpriteRect();
int GetShaderIndex() const { return mShaderIndex; } int GetShaderIndex() const { return mShaderIndex; }
void AddTextureLayer(FTexture *tex) int GetScaleFlags() const { return mScaleFlags; }
virtual void DeleteDescriptors() { }
FGameTexture* Source() const
{ {
ValidateTexture(tex, false); return sourcetex;
mTextureLayers.Push(tex);
}
bool isMasked() const
{
return sourcetex->bMasked;
}
bool isExpanded() const
{
return mExpanded;
} }
int GetLayers() const void AddTextureLayer(FTexture *tex, bool allowscale)
{ {
return mTextureLayers.Size() + 1; mTextureLayers.Push({ tex, allowscale });
}
bool hasCanvas()
{
return tex->isHardwareCanvas();
} }
IHardwareTexture *GetLayer(int i, int translation, FTexture **pLayer = nullptr); int NumLayers() const
// Patch drawing utilities
void GetSpriteRect(FloatRect * r) const
{ {
*r = mSpriteRect; return mTextureLayers.Size();
} }
// This is scaled size in integer units as needed by walls and flats IHardwareTexture *GetLayer(int i, int translation, MaterialLayerInfo **pLayer = nullptr) const;
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]; }
static FMaterial *ValidateTexture(FTexture * tex, bool expand, bool create = true); static FMaterial *ValidateTexture(FGameTexture * tex, int scaleflags, bool create = true);
static FMaterial *ValidateTexture(FTextureID no, bool expand, bool trans, bool create = true); const TArray<MaterialLayerInfo> &GetLayerArray() const
const TArray<FTexture*> &GetLayerArray() const
{ {
return mTextureLayers; return mTextureLayers;
} }

View file

@ -7,6 +7,15 @@
struct FTextureBuffer; struct FTextureBuffer;
class IHardwareTexture; 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 class FHardwareTextureContainer
{ {
public: public:
@ -20,6 +29,7 @@ private:
{ {
IHardwareTexture *hwTexture = nullptr; IHardwareTexture *hwTexture = nullptr;
int translation = 0; 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() void Delete()
{ {
@ -27,23 +37,28 @@ private:
hwTexture = nullptr; hwTexture = nullptr;
} }
void DeleteDescriptors()
{
if (hwTexture) hwTexture->DeleteDescriptors();
}
~TranslatedTexture() ~TranslatedTexture()
{ {
Delete(); Delete();
} }
void MarkForPrecache(bool on)
{
precacheMarker = on;
}
bool isMarkedForPreache() const
{
return precacheMarker;
}
}; };
private: private:
TranslatedTexture hwDefTex[2]; TranslatedTexture hwDefTex[4];
TArray<TranslatedTexture> hwTex_Translated; TArray<TranslatedTexture> hwTex_Translated;
TranslatedTexture * GetTexID(int translation, bool expanded) TranslatedTexture * GetTexID(int translation, int scaleflags)
{ {
// Allow negative indices to pass through unchanged. // 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. // 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; 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 // normally there aren't more than very few different
// translations here so this isn't performance critical. // translations here so this isn't performance critical.
unsigned index = hwTex_Translated.FindEx([=](auto &element) unsigned index = hwTex_Translated.FindEx([=](auto &element)
@ -78,32 +93,22 @@ private:
} }
public: public:
void Clean()
void Clean(bool cleannormal, bool cleanexpanded)
{ {
if (cleannormal) hwDefTex[0].Delete(); hwDefTex[0].Delete();
if (cleanexpanded) hwDefTex[1].Delete(); hwDefTex[1].Delete();
hwDefTex[0].DeleteDescriptors(); hwTex_Translated.Clear();
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();
}
} }
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; 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->Delete();
tt->hwTexture =tex; tt->hwTexture =tex;
} }
@ -111,26 +116,44 @@ public:
//=========================================================================== //===========================================================================
// //
// Deletes all allocated resources and considers translations // 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--) 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); 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<class T> template<class T>
void Iterate(T callback) void Iterate(T callback)
{ {

View file

@ -41,7 +41,7 @@
#include "cmdlib.h" #include "cmdlib.h"
#include "palettecontainer.h" #include "palettecontainer.h"
FMemArena FImageSource::ImageArena(32768); FMemArena ImageArena(32768);
TArray<FImageSource *>FImageSource::ImageForLump; TArray<FImageSource *>FImageSource::ImageForLump;
int FImageSource::NextID; int FImageSource::NextID;
static PrecacheInfo precacheInfo; static PrecacheInfo precacheInfo;

View file

@ -7,6 +7,7 @@
class FImageSource; class FImageSource;
using PrecacheInfo = TMap<int, std::pair<int, int>>; using PrecacheInfo = TMap<int, std::pair<int, int>>;
extern FMemArena ImageArena;
// Doom patch format header // Doom patch format header
struct patch_t struct patch_t
@ -38,7 +39,6 @@ class FImageSource
friend class FBrightmapTexture; friend class FBrightmapTexture;
protected: protected:
static FMemArena ImageArena;
static TArray<FImageSource *>ImageForLump; static TArray<FImageSource *>ImageForLump;
static int NextID; static int NextID;
@ -57,6 +57,8 @@ protected:
public: 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) void CopySize(FImageSource &other)
{ {
@ -169,4 +171,4 @@ protected:
class FTexture; class FTexture;
FTexture* CreateImageTexture(FImageSource* img, const char *name = nullptr) noexcept; FTexture* CreateImageTexture(FImageSource* img) noexcept;

View file

@ -47,25 +47,25 @@
// //
//========================================================================== //==========================================================================
FImageTexture::FImageTexture(FImageSource* img, const char* name) noexcept FImageTexture::FImageTexture(FImageSource *img) noexcept
: FTexture(name, img ? img->LumpNum() : 0) : FTexture(img? img->LumpNum() : 0)
{ {
mImage = img; mImage = img;
if (img != nullptr) if (img != nullptr)
{ {
if (name == nullptr) fileSystem.GetFileShortName(Name, img->LumpNum()); SetFromImage();
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;
} }
} }
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);
} }

View file

@ -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); 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 #endif

View file

@ -57,7 +57,6 @@
#endif #endif
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// //
// Data structures for the TEXTUREx lumps // Data structures for the TEXTUREx lumps
@ -85,7 +84,7 @@ struct mappatch_t
struct maptexture_t struct maptexture_t
{ {
uint8_t name[8]; 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 ScaleX; // [RH] Scaling (8 is normal)
uint8_t ScaleY; // [RH] Same as above uint8_t ScaleY; // [RH] Same as above
int16_t width; int16_t width;
@ -113,7 +112,7 @@ struct strifemappatch_t
struct strifemaptexture_t struct strifemaptexture_t
{ {
uint8_t name[8]; 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 ScaleX; // [RH] Scaling (8 is normal)
uint8_t ScaleY; // [RH] Same as above uint8_t ScaleY; // [RH] Same as above
int16_t width; int16_t width;
@ -137,25 +136,23 @@ struct FPatchLookup
void FMultipatchTextureBuilder::MakeTexture(BuildInfo &buildinfo, ETextureType usetype) void FMultipatchTextureBuilder::MakeTexture(BuildInfo &buildinfo, ETextureType usetype)
{ {
FImageTexture *tex = new FImageTexture(nullptr, buildinfo.Name); buildinfo.texture = new FGameTexture(nullptr, buildinfo.Name);
tex->SetUseType(usetype); buildinfo.texture->SetUseType(usetype);
tex->bMultiPatch = true; TexMan.AddGameTexture(buildinfo.texture);
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);
} }
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 // 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].OriginX = LittleShort(mpatch.d->originx);
buildinfo.Parts[i].OriginY = LittleShort(mpatch.d->originy); 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].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name;
buildinfo.Inits[i].UseType = ETextureType::WallPatch; buildinfo.Inits[i].UseType = ETextureType::WallPatch;
if (strife) 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. // It still needs to be created in case someone uses it by name.
offset = LittleLong(directory[1]); offset = LittleLong(directory[1]);
const maptexture_t *tex = (const maptexture_t *)((const uint8_t *)maptex + offset); 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)); tex0->SetSize(SAFESHORT(tex->width), SAFESHORT(tex->height));
} }
@ -373,7 +370,7 @@ void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsi
int j; int j;
for (j = (int)TexMan.NumTextures() - 1; j >= firstdup; --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; break;
} }
if (j + 1 == firstdup) 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; FString patchname;
int Mirror = 0; int Mirror = 0;
@ -672,7 +669,7 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType)
} }
else if (sc.Compare("Patch")) else if (sc.Compare("Patch"))
{ {
TexPart part; TexPartBuild part;
TexInit init; TexInit init;
ParsePatch(sc, buildinfo, part, init); ParsePatch(sc, buildinfo, part, init);
if (init.TexName.IsNotEmpty()) if (init.TexName.IsNotEmpty())
@ -684,12 +681,12 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType)
init.sc = sc; init.sc = sc;
buildinfo.Inits.Push(init); buildinfo.Inits.Push(init);
} }
part.Image = nullptr; part.TexImage = nullptr;
part.Translation = nullptr; part.Translation = nullptr;
} }
else if (sc.Compare("Sprite")) else if (sc.Compare("Sprite"))
{ {
TexPart part; TexPartBuild part;
TexInit init; TexInit init;
ParsePatch(sc, buildinfo, part, init); ParsePatch(sc, buildinfo, part, init);
if (init.TexName.IsNotEmpty()) if (init.TexName.IsNotEmpty())
@ -701,12 +698,12 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType)
init.sc = sc; init.sc = sc;
buildinfo.Inits.Push(init); buildinfo.Inits.Push(init);
} }
part.Image = nullptr; part.TexImage = nullptr;
part.Translation = nullptr; part.Translation = nullptr;
} }
else if (sc.Compare("Graphic")) else if (sc.Compare("Graphic"))
{ {
TexPart part; TexPartBuild part;
TexInit init; TexInit init;
ParsePatch(sc, buildinfo, part, init); ParsePatch(sc, buildinfo, part, init);
if (init.TexName.IsNotEmpty()) if (init.TexName.IsNotEmpty())
@ -718,7 +715,7 @@ void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType)
init.sc = sc; init.sc = sc;
buildinfo.Inits.Push(init); buildinfo.Inits.Push(init);
} }
part.Image = nullptr; part.TexImage = nullptr;
part.Translation = nullptr; part.Translation = nullptr;
} }
else if (sc.Compare("Offset")) else if (sc.Compare("Offset"))
@ -774,19 +771,23 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo)
for (unsigned i = 0; i < buildinfo.Inits.Size(); i++) for (unsigned i = 0; i < buildinfo.Inits.Size(); i++)
{ {
FTextureID texno = TexMan.CheckForTexture(buildinfo.Inits[i].TexName, buildinfo.Inits[i].UseType); 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<FTextureID> list; TArray<FTextureID> list;
TexMan.ListTextures(buildinfo.Inits[i].TexName, list, true); TexMan.ListTextures(buildinfo.Inits[i].TexName, list, true);
for (int i = list.Size() - 1; i >= 0; i--) 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<FMultiPatchTexture*>(gtex->GetTexture()))
{
texno = list[i];
}
break; 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()); 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()); 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 else
{ {
FTexture *tex = TexMan.GetTexture(texno); FGameTexture *tex = TexMan.GetGameTexture(texno);
if (tex != nullptr && tex->isValid()) if (tex != nullptr && tex->isValid() && dynamic_cast<FImageTexture*>(tex->GetTexture()))
{ {
//We cannot set the image source yet. First all textures need to be resolved. //We cannot set the image source yet. First all textures need to be resolved.
buildinfo.Inits[i].Texture = tex; buildinfo.Inits[i].Texture = static_cast<FImageTexture*>(tex->GetTexture());
buildinfo.tex->bComplex |= tex->bComplex; bool iscomplex = !!complex.CheckKey(tex);
buildinfo.bComplex |= tex->bComplex; if (iscomplex) complex.Insert(buildinfo.texture, true);
buildinfo.bComplex |= iscomplex;
if (buildinfo.Inits[i].UseOffsets) if (buildinfo.Inits[i].UseOffsets)
{ {
buildinfo.Parts[i].OriginX -= tex->GetLeftOffset(0); buildinfo.Parts[i].OriginX -= tex->GetTexelLeftOffset(0);
buildinfo.Parts[i].OriginY -= tex->GetTopOffset(0); buildinfo.Parts[i].OriginY -= tex->GetTexelTopOffset(0);
} }
} }
else else
@ -841,8 +843,6 @@ void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo)
i--; i--;
} }
} }
checkForHacks(buildinfo);
} }
void FMultipatchTextureBuilder::ResolveAllPatches() void FMultipatchTextureBuilder::ResolveAllPatches()
@ -874,12 +874,12 @@ void FMultipatchTextureBuilder::ResolveAllPatches()
for (unsigned j = 0; j < buildinfo.Inits.Size(); j++) 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(); auto image = buildinfo.Inits[j].Texture;
if (image != nullptr) if (image->GetImage() != nullptr)
{ {
buildinfo.Parts[j].Image = image; buildinfo.Parts[j].TexImage = image;
donesomething = true; donesomething = true;
} }
else hasEmpty = 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 // If this texture is just a wrapper around a single patch, we can simply
// use that patch's image directly here. // use that patch's image directly here.
checkForHacks(buildinfo);
bool done = false; bool done = false;
if (buildinfo.Parts.Size() == 1) if (buildinfo.Parts.Size() == 1)
{ {
if (buildinfo.Parts[0].OriginX == 0 && buildinfo.Parts[0].OriginY == 0 && if (buildinfo.Parts[0].OriginX == 0 && buildinfo.Parts[0].OriginY == 0 &&
buildinfo.Parts[0].Image->GetWidth() == buildinfo.Width && buildinfo.Parts[0].TexImage->GetWidth() == buildinfo.Width &&
buildinfo.Parts[0].Image->GetHeight() == buildinfo.Height && buildinfo.Parts[0].TexImage->GetHeight() == buildinfo.Height &&
buildinfo.Parts[0].Rotate == 0 && buildinfo.Parts[0].Rotate == 0 &&
!buildinfo.bComplex) !buildinfo.bComplex)
{ {
buildinfo.tex->SetImage(buildinfo.Parts[0].Image); AddImageToTexture(buildinfo.Parts[0].TexImage, buildinfo);
buildinfo.texture->Setup(buildinfo.Parts[0].TexImage);
done = true; done = true;
} }
} }
if (!done) if (!done)
{ {
auto img = new FMultiPatchTexture(buildinfo.Width, buildinfo.Height, buildinfo.Parts, buildinfo.bComplex, buildinfo.textual); 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); BuiltTextures.Delete(i);
donesomething = true; donesomething = true;
} }
@ -919,7 +921,7 @@ void FMultipatchTextureBuilder::ResolveAllPatches()
for (auto &b : BuiltTextures) for (auto &b : BuiltTextures)
{ {
Printf("%s\n", b.Name.GetChars()); Printf("%s\n", b.Name.GetChars());
b.tex->SetUseType(ETextureType::Null); b.texture->SetUseType(ETextureType::Null);
} }
break; break;
} }

View file

@ -47,18 +47,15 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
FSkyBox::FSkyBox(const char *name) FSkyBox::FSkyBox(const char *name)
: FTexture(name) : FImageTexture(nullptr)
{ {
FTextureID texid = TexMan.CheckForTexture(name, ETextureType::Wall); FTextureID texid = TexMan.CheckForTexture(name, ETextureType::Wall);
previous = nullptr;
if (texid.isValid()) if (texid.isValid())
{ {
previous = TexMan.GetTexture(texid); previous = TexMan.GetGameTexture(texid);
CopySize(previous);
} }
else previous = nullptr;
faces[0]=faces[1]=faces[2]=faces[3]=faces[4]=faces[5] = nullptr; faces[0]=faces[1]=faces[2]=faces[3]=faces[4]=faces[5] = nullptr;
UseType = ETextureType::Override;
bSkybox = true;
fliptop = false; fliptop = false;
} }
@ -68,29 +65,11 @@ FSkyBox::FSkyBox(const char *name)
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
TArray<uint8_t> FSkyBox::Get8BitPixels(bool alphatex) void FSkyBox::SetSize()
{ {
return previous->Get8BitPixels(alphatex); if (!previous && faces[0]) previous = faces[0];
} if (previous && previous->GetTexture()->GetImage())
{
//----------------------------------------------------------------------------- SetImage(previous->GetTexture()->GetImage());
// }
//
//
//-----------------------------------------------------------------------------
FBitmap FSkyBox::GetBgraBitmap(const PalEntry *p, int *trans)
{
return previous->GetBgraBitmap(p, trans);
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
FImageSource *FSkyBox::GetImage() const
{
return previous->GetImage();
} }

View file

@ -1,35 +1,24 @@
#pragma once #pragma once
#include "textures.h" #include "textures.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
// This is not a real texture but will be added to the texture manager // Todo: Get rid of this
// so that it can be handled like any other sky. // The faces can easily be stored in the material layer array
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class FSkyBox : public FTexture class FSkyBox : public FImageTexture
{ {
public: public:
FTexture *previous; FGameTexture* previous;
FTexture * faces[6]; FGameTexture* faces[6]; // the faces need to be full materials as they can have all supported effects.
bool fliptop; bool fliptop;
FSkyBox(const char *name); FSkyBox(const char* name);
TArray<uint8_t> Get8BitPixels(bool alphatex); void SetSize();
FBitmap GetBgraBitmap(const PalEntry *, int *trans) override;
FImageSource *GetImage() const override;
void SetSize()
{
if (!previous && faces[0]) previous = faces[0];
if (previous)
{
CopySize(previous);
}
}
bool Is3Face() const bool Is3Face() const
{ {
@ -40,4 +29,14 @@ public:
{ {
return fliptop; return fliptop;
} }
FGameTexture* GetSkyFace(int num) const
{
return faces[num];
}
bool GetSkyFlip() const
{
return fliptop;
}
}; };

View file

@ -47,123 +47,24 @@
#include "image.h" #include "image.h"
#include "formats/multipatchtexture.h" #include "formats/multipatchtexture.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "c_cvars.h"
// Wrappers to keep the definitions of these classes out of here. // Wrappers to keep the definitions of these classes out of here.
void DeleteMaterial(FMaterial* mat);
void DeleteSoftwareTexture(FSoftwareTexture* swtex);
IHardwareTexture* CreateHardwareTexture(); IHardwareTexture* CreateHardwareTexture();
FTexture* CreateBrightmapTexture(FImageSource*);
// Make sprite offset adjustment user-configurable per renderer. // Make sprite offset adjustment user-configurable per renderer.
int r_spriteadjustSW, r_spriteadjustHW; 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) FTexture::FTexture (int lumpnum)
: : SourceLump(lumpnum), bHasCanvas(false)
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)
{ {
bBrightmapChecked = false;
bGlowing = false;
bAutoGlowing = false;
bFullbright = false;
bDisableFullbright = false;
bSkybox = false;
bNoCompress = false;
bNoExpand = false;
bTranslucent = -1; 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; 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<FMultiPatchTexture*>(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 // CheckRealHeight
@ -299,16 +95,13 @@ PalEntry FTexture::GetSkyCapColor(bool bottom)
int FTexture::CheckRealHeight() int FTexture::CheckRealHeight()
{ {
auto pixels = Get8BitPixels(false); 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; return h;
} }
} }
@ -316,127 +109,6 @@ int FTexture::CheckRealHeight()
return 0; 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<FImageTexture*>(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 // 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! // already done!
if (areacount) return false; 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! areacount = -1; //whatever happens next, it shouldn't be done twice!
// large textures are excluded for performance reasons // large textures and non-images are excluded for performance reasons
if (h > 512) return false; if (h>512 || !GetImage()) return false;
startdraw = -1; startdraw = -1;
lendraw = 0; lendraw = 0;
@ -510,7 +181,7 @@ bool FTexture::FindHoles(const unsigned char* buffer, int w, int h)
if (gapc > 0) 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++) 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) bool FTexture::ProcessData(unsigned char* buffer, int w, int h, bool ispatch)
{ {
if (bMasked) if (Masked)
{ {
bMasked = SmoothEdges(buffer, w, h); Masked = SmoothEdges(buffer, w, h);
if (bMasked && !ispatch) FindHoles(buffer, w, h); if (Masked && !ispatch) FindHoles(buffer, w, h);
} }
return true; return true;
} }
@ -660,8 +331,8 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
int exx = !!(flags & CTF_Expand); int exx = !!(flags & CTF_Expand);
W = GetTexelWidth() + 2 * exx; W = GetWidth() + 2 * exx;
H = GetTexelHeight() + 2 * exx; H = GetHeight() + 2 * exx;
if (!checkonly) if (!checkonly)
{ {
@ -669,6 +340,7 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
memset(buffer, 0, W * (H + 1) * 4); memset(buffer, 0, W * (H + 1) * 4);
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation); auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation);
if (remap) translation = remap->Index;
FBitmap bmp(buffer, W * 4, W, H); FBitmap bmp(buffer, W * 4, W, H);
int trans; 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.) // 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) if (GetImage() && flags & CTF_ProcessData)
{ {
#pragma message("Activate me") if (flags & CTF_Upscale) CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly);
#if 0
CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly);
#endif
if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false); if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false);
} }
@ -723,15 +393,8 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
bool FTexture::DetermineTranslucency() bool FTexture::DetermineTranslucency()
{ {
if (!bHasCanvas)
{
// This will calculate all we need, so just discard the result. // This will calculate all we need, so just discard the result.
CreateTexBuffer(0); CreateTexBuffer(0);
}
else
{
bTranslucent = 0;
}
return !!bTranslucent; return !!bTranslucent;
} }
@ -749,101 +412,114 @@ TArray<uint8_t> 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; auto texbuffer = CreateTexBuffer(0);
else return rowoffset / scale; 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 (UseType != ETextureType::Null)
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); IHardwareTexture* hwtex = SystemTextures.GetHardwareTexture(translation, scaleflags);
if (tscale == 1.f) return (float)mRenderWidth; if (hwtex == nullptr)
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)
{ {
mRenderWidth = tex->GetScaledWidth(); hwtex = CreateHardwareTexture();
mScale.X = (float)tex->Scale.X; SystemTextures.AddHardwareTexture(translation, scaleflags, hwtex);
mTempScale.X = 1.f;
} }
else return hwtex;
{
float scale_x = x * (float)tex->Scale.X;
mRenderWidth = xs_CeilToInt(tex->GetTexelWidth() / scale_x);
mScale.X = scale_x;
mTempScale.X = x;
} }
return nullptr;
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();
} }
@ -858,8 +534,7 @@ FWrapperTexture::FWrapperTexture(int w, int h, int bits)
Width = w; Width = w;
Height = h; Height = h;
Format = bits; Format = bits;
UseType = ETextureType::SWCanvas; //bNoCompress = true;
bNoCompress = true;
auto hwtex = CreateHardwareTexture(); auto hwtex = CreateHardwareTexture();
// todo: Initialize here. // todo: Initialize here.
SystemTextures.AddHardwareTexture(0, false, hwtex); SystemTextures.AddHardwareTexture(0, false, hwtex);

View file

@ -17,7 +17,7 @@ enum class ETextureType : uint8_t
SkinGraphic, SkinGraphic,
Null, Null,
FirstDefined, FirstDefined,
Canvas, Special,
SWCanvas, SWCanvas,
}; };

View file

@ -103,15 +103,14 @@ void FTextureManager::DeleteAll()
//========================================================================== //==========================================================================
// //
// Flushes all hardware dependent data. // 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 // 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 // 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. // main reason to call this outside of the destruction code.
// //
//========================================================================== //==========================================================================
void DeleteSoftwareTexture(FSoftwareTexture* swtex);
void FTextureManager::FlushAll() void FTextureManager::FlushAll()
{ {
@ -119,13 +118,33 @@ void FTextureManager::FlushAll()
{ {
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
Textures[i].Texture->SystemTextures.Clean(true, true); Textures[i].Texture->CleanHardwareData();
DeleteSoftwareTexture(Textures[i].Texture->SoftwareTexture); delete Textures[i].Texture->GetSoftwareTexture();
Textures[i].Texture->SoftwareTexture = nullptr; 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 // 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) 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 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; continue;
} }
auto texUseType = tex->GetUseType();
// The name matches, so check the texture type // The name matches, so check the texture type
if (usetype == ETextureType::Any) if (usetype == ETextureType::Any)
{ {
// All NULL textures should actually return 0 // All NULL textures should actually return 0
if (tex->UseType == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0; if (texUseType == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0;
if (tex->UseType == ETextureType::SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0; if (texUseType == ETextureType::SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0;
return FTextureID(tex->UseType==ETextureType::Null ? 0 : i); 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); return FTextureID(i);
} }
else if (tex->UseType == usetype) else if (texUseType == usetype)
{ {
return FTextureID(i); 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); if (!(flags & TEXMAN_ReturnFirst)) return FTextureID(0);
else return FTextureID(i); 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 // We found a NULL texture on a wall -> return 0
return FTextureID(0); return FTextureID(0);
@ -192,12 +212,12 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset
{ {
if (firsttype == ETextureType::Null || if (firsttype == ETextureType::Null ||
(firsttype == ETextureType::MiscPatch && (firsttype == ETextureType::MiscPatch &&
tex->UseType != firsttype && texUseType != firsttype &&
tex->UseType != ETextureType::Null) texUseType != ETextureType::Null)
) )
{ {
firstfound = i; 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. // Any graphic being placed in the zip's root directory can not be found by this.
if (strchr(name, '/')) if (strchr(name, '/'))
{ {
FTexture *const NO_TEXTURE = (FTexture*)-1; FGameTexture *const NO_TEXTURE = (FGameTexture*)-1;
int lump = fileSystem.CheckNumForFullName(name); int lump = fileSystem.CheckNumForFullName(name);
if (lump >= 0) if (lump >= 0)
{ {
FTexture *tex = fileSystem.GetLinkedTexture(lump); FGameTexture *tex = fileSystem.GetLinkedTexture(lump);
if (tex == NO_TEXTURE) return FTextureID(-1); 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. 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) if (tex != NULL)
{ {
tex->AddAutoMaterials(); tex->AddAutoMaterials();
fileSystem.SetLinkedTexture(lump, tex); fileSystem.SetLinkedTexture(lump, tex);
return AddTexture(tex); return AddGameTexture(tex);
} }
else else
{ {
@ -273,12 +293,13 @@ int FTextureManager::ListTextures (const char *name, TArray<FTextureID> &list, b
while (i != HASH_END) 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. // NULL textures must be ignored.
if (tex->UseType!=ETextureType::Null) if (texUseType!=ETextureType::Null)
{ {
unsigned int j = list.Size(); unsigned int j = list.Size();
if (!listall) if (!listall)
@ -286,7 +307,7 @@ int FTextureManager::ListTextures (const char *name, TArray<FTextureID> &list, b
for (j = 0; j < list.Size(); j++) for (j = 0; j < list.Size(); j++)
{ {
// Check for overriding definitions from newer WADs // 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)); 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); 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; if (locmode == 2) return false;
// Mode 3 must also reject substitutions for non-IWAD content. // 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; if (file > fileSystem.GetMaxIwadNum()) return true;
return false; 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 bucket;
int hash; int hash;
if (texture == NULL) return FTextureID(-1); 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 // 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]; hash = HashFirst[bucket];
} }
else else
@ -395,11 +420,13 @@ FTextureID FTextureManager::AddTexture (FTexture *texture)
hash = -1; hash = -1;
} }
TextureHash hasher = { texture, hash }; TextureHash hasher = { texture, -1, -1, -1, hash };
int trans = Textures.Push (hasher); int trans = Textures.Push (hasher);
Translation.Push (trans); Translation.Push (trans);
if (bucket >= 0) HashFirst[bucket] = 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; FString str;
fileSystem.GetFileShortName(str, lumpnum); 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 else
{ {
Printf (TEXTCOLOR_ORANGE "Invalid data encountered for texture %s\n", fileSystem.GetFileFullPath(lumpnum).GetChars()); 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(); int index = picnum.GetIndex();
if (unsigned(index) >= Textures.Size()) if (unsigned(index) >= Textures.Size())
return; return;
FTexture *oldtexture = Textures[index].Texture; auto oldtexture = Textures[index].Texture;
newtexture->Name = oldtexture->Name; newtexture->SetName(oldtexture->GetName());
newtexture->UseType = oldtexture->UseType; newtexture->SetUseType(oldtexture->GetUseType());
Textures[index].Texture = newtexture; Textures[index].Texture = newtexture;
newtexture->id = oldtexture->id; newtexture->SetID(oldtexture->GetID());
oldtexture->Name = ""; oldtexture->SetName("");
AddTexture(oldtexture); AddGameTexture(oldtexture);
} }
//========================================================================== //==========================================================================
@ -465,11 +515,11 @@ bool FTextureManager::AreTexturesCompatible (FTextureID picnum1, FTextureID picn
if (unsigned(index1) >= Textures.Size() || unsigned(index2) >= Textures.Size()) if (unsigned(index1) >= Textures.Size() || unsigned(index2) >= Textures.Size())
return false; return false;
FTexture *texture1 = Textures[index1].Texture; auto texture1 = Textures[index1].Texture;
FTexture *texture2 = Textures[index2].Texture; auto texture2 = Textures[index2].Texture;
// both textures must be the same type. // 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; return false;
// both textures must be from the same file // both textures must be from the same file
@ -556,30 +606,28 @@ void FTextureManager::AddHiresTextures (int wadnum)
if (amount == 0) if (amount == 0)
{ {
// A texture with this name does not yet exist // 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) if (newtex != NULL)
{ {
newtex->UseType=ETextureType::Override; AddGameTexture(newtex);
AddTexture(newtex);
} }
} }
else else
{ {
for(unsigned int i = 0; i < tlist.Size(); i++) for(unsigned int i = 0; i < tlist.Size(); i++)
{ {
FTexture * newtex = FTexture::CreateTexture ("", firsttx, ETextureType::Any); FTexture * newtex = CreateTextureFromLump(firsttx);
if (newtex != NULL) 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. // Replace the entire texture and adjust the scaling and offset factors.
newtex->bWorldPanning = true; auto gtex = MakeGameTexture(newtex, nullptr, ETextureType::Override);
newtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); gtex->SetWorldPanning(true);
newtex->_LeftOffset[0] = int(oldtex->GetScaledLeftOffset(0) * newtex->Scale.X); gtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight());
newtex->_LeftOffset[1] = int(oldtex->GetScaledLeftOffset(1) * newtex->Scale.X); gtex->SetOffsets(0, xs_RoundToInt(oldtex->GetDisplayLeftOffset(0) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(0) * gtex->GetScaleY()));
newtex->_TopOffset[0] = int(oldtex->GetScaledTopOffset(0) * newtex->Scale.Y); gtex->SetOffsets(1, xs_RoundToInt(oldtex->GetDisplayLeftOffset(1) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(1) * gtex->GetScaleY()));
newtex->_TopOffset[1] = int(oldtex->GetScaledTopOffset(1) * newtex->Scale.Y); ReplaceTexture(tlist[i], gtex, true);
ReplaceTexture(tlist[i], newtex, true);
} }
} }
} }
@ -655,28 +703,27 @@ void FTextureManager::ParseTextureDef(int lump, FMultipatchTextureBuilder &build
{ {
for(unsigned int i = 0; i < tlist.Size(); i++) 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; int sl;
// only replace matching types. For sprites also replace any MiscPatches // only replace matching types. For sprites also replace any MiscPatches
// based on the same lump. These can be created for icons. // based on the same lump. These can be created for icons.
if (oldtex->UseType == type || type == ETextureType::Any || if (oldtex->GetUseType() == type || type == ETextureType::Any ||
(mode == TEXMAN_Overridable && oldtex->UseType == ETextureType::Override) || (mode == TEXMAN_Overridable && oldtex->GetUseType() == ETextureType::Override) ||
(type == ETextureType::Sprite && oldtex->UseType == ETextureType::MiscPatch && (type == ETextureType::Sprite && oldtex->GetUseType() == ETextureType::MiscPatch &&
(sl=oldtex->GetSourceLump()) >= 0 && fileSystem.GetFileNamespace(sl) == ns_sprites) (sl=oldtex->GetSourceLump()) >= 0 && fileSystem.GetFileNamespace(sl) == ns_sprites)
) )
{ {
FTexture * newtex = FTexture::CreateTexture ("", lumpnum, ETextureType::Any); FTexture * newtex = CreateTextureFromLump(lumpnum);
if (newtex != NULL) if (newtex != NULL)
{ {
// Replace the entire texture and adjust the scaling and offset factors. // Replace the entire texture and adjust the scaling and offset factors.
newtex->bWorldPanning = true; auto gtex = MakeGameTexture(newtex, nullptr, ETextureType::Override);
newtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight()); gtex->SetWorldPanning(true);
newtex->_LeftOffset[0] = int(oldtex->GetScaledLeftOffset(0) * newtex->Scale.X); gtex->SetDisplaySize(oldtex->GetDisplayWidth(), oldtex->GetDisplayHeight());
newtex->_LeftOffset[1] = int(oldtex->GetScaledLeftOffset(1) * newtex->Scale.X); gtex->SetOffsets(0, xs_RoundToInt(oldtex->GetDisplayLeftOffset(0) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(0) * gtex->GetScaleY()));
newtex->_TopOffset[0] = int(oldtex->GetScaledTopOffset(0) * newtex->Scale.Y); gtex->SetOffsets(1, xs_RoundToInt(oldtex->GetDisplayLeftOffset(1) * gtex->GetScaleX()), xs_RoundToInt(oldtex->GetDisplayTopOffset(1) * gtex->GetScaleY()));
newtex->_TopOffset[1] = int(oldtex->GetScaledTopOffset(1) * newtex->Scale.Y); ReplaceTexture(tlist[i], gtex, true);
ReplaceTexture(tlist[i], newtex, true);
} }
} }
} }
@ -705,21 +752,21 @@ void FTextureManager::ParseTextureDef(int lump, FMultipatchTextureBuilder &build
if (lumpnum>=0) if (lumpnum>=0)
{ {
FTexture *newtex = FTexture::CreateTexture(src, lumpnum, ETextureType::Override); auto newtex = MakeGameTexture(CreateTextureFromLump(lumpnum), src, ETextureType::Override);
if (newtex != NULL) if (newtex != NULL)
{ {
// Replace the entire texture and adjust the scaling and offset factors. // Replace the entire texture and adjust the scaling and offset factors.
newtex->bWorldPanning = true; newtex->SetWorldPanning(true);
newtex->SetDisplaySize(width, height); newtex->SetDisplaySize((float)width, (float)height);
FTextureID oldtex = TexMan.CheckForTexture(src, ETextureType::MiscPatch); FTextureID oldtex = TexMan.CheckForTexture(src, ETextureType::MiscPatch);
if (oldtex.isValid()) if (oldtex.isValid())
{ {
ReplaceTexture(oldtex, newtex, true); 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. // Try to create a texture from this lump and add it.
// Unfortunately we have to look at everything that comes through here... // 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) 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) void FTextureManager::SortTexturesByType(int start, int end)
{ {
TArray<FTexture *> newtextures; TArray<FGameTexture *> newtextures;
// First unlink all newly added textures from the hash chain // First unlink all newly added textures from the hash chain
for (int i = 0; i < HASH_SIZE; i++) for (int i = 0; i < HASH_SIZE; i++)
@ -981,9 +1028,9 @@ void FTextureManager::SortTexturesByType(int start, int end)
{ {
for(unsigned j = 0; j<newtextures.Size(); j++) for(unsigned j = 0; j<newtextures.Size(); j++)
{ {
if (newtextures[j] != NULL && newtextures[j]->UseType == texturetypes[i]) if (newtextures[j] != NULL && newtextures[j]->GetUseType() == texturetypes[i])
{ {
AddTexture(newtextures[j]); AddGameTexture(newtextures[j]);
newtextures[j] = NULL; newtextures[j] = NULL;
} }
} }
@ -993,8 +1040,8 @@ void FTextureManager::SortTexturesByType(int start, int end)
{ {
if (newtextures[j] != NULL) if (newtextures[j] != NULL)
{ {
Printf("Texture %s has unknown type!\n", newtextures[j]->Name.GetChars()); Printf("Texture %s has unknown type!\n", newtextures[j]->GetName().GetChars());
AddTexture(newtextures[j]); AddGameTexture(newtextures[j]);
} }
} }
} }
@ -1032,8 +1079,8 @@ void FTextureManager::AddLocalizedVariants()
FTextureID tex = CheckForTexture(entry.name, ETextureType::MiscPatch); FTextureID tex = CheckForTexture(entry.name, ETextureType::MiscPatch);
if (tex.isValid()) if (tex.isValid())
{ {
FTexture *otex = GetTexture(origTex); auto otex = GetGameTexture(origTex);
FTexture *ntex = GetTexture(tex); auto ntex = GetGameTexture(tex);
if (otex->GetDisplayWidth() != ntex->GetDisplayWidth() || otex->GetDisplayHeight() != ntex->GetDisplayHeight()) 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); 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 // FTextureManager :: Init
// //
//========================================================================== //==========================================================================
FTexture *CreateShaderTexture(bool, bool); FGameTexture *CreateShaderTexture(bool, bool);
void InitBuildTiles(); void InitBuildTiles();
FImageSource* CreateEmptyTexture();
void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo&)) void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo&))
{ {
@ -1090,15 +1138,18 @@ void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildI
DeleteAll(); DeleteAll();
//if (BuildTileFiles.Size() == 0) CountBuildTiles (); //if (BuildTileFiles.Size() == 0) CountBuildTiles ();
// Texture 0 is a dummy texture used to indicate "no texture" auto nulltex = MakeGameTexture(new FImageTexture(CreateEmptyTexture()), nullptr, ETextureType::Null);
auto nulltex = new FImageTexture(nullptr, ""); AddGameTexture(nulltex);
nulltex->SetUseType(ETextureType::Null);
AddTexture (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. // some special textures used in the game.
AddTexture(CreateShaderTexture(false, false)); AddGameTexture(CreateShaderTexture(false, false));
AddTexture(CreateShaderTexture(false, true)); AddGameTexture(CreateShaderTexture(false, true));
AddTexture(CreateShaderTexture(true, false)); AddGameTexture(CreateShaderTexture(true, false));
AddTexture(CreateShaderTexture(true, true)); AddGameTexture(CreateShaderTexture(true, true));
int wadcnt = fileSystem.GetNumWads(); int wadcnt = fileSystem.GetNumWads();
@ -1133,6 +1184,13 @@ void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildI
glPart = TexMan.CheckForTexture("glstuff/glpart.png", ETextureType::MiscPatch); glPart = TexMan.CheckForTexture("glstuff/glpart.png", ETextureType::MiscPatch);
mirrorTexture = TexMan.CheckForTexture("glstuff/mirror.png", ETextureType::MiscPatch); mirrorTexture = TexMan.CheckForTexture("glstuff/mirror.png", ETextureType::MiscPatch);
AddLocalizedVariants(); 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); FTextureID pic2 = CheckForTexture(sc.String, ETextureType::Any);
if (!pic2.isValid()) 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()) if (pic1.isValid() && pic2.isValid())
{ {
FTexture *owner = GetTexture(pic1); Textures[pic1.GetIndex()].Paletted = pic2.GetIndex();
FTexture *owned = GetTexture(pic2);
if (owner && owned) owner->PalVersion = owned;
} }
} }
} }
} }
//==========================================================================
//
//
//
//==========================================================================
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<FMultiPatchTexture*>(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); fileSystem.GetFileShortName(str, i);
str[8] = 0; str[8] = 0;
FTextureID texid = TexMan.CheckForTexture(str, ETextureType::Sprite, 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. // This texture has been replaced by some PWAD.
memcpy(&sprid, str, 4); memcpy(&sprid, str, 4);
@ -1349,7 +1483,7 @@ void FTextureManager::AdjustSpriteOffsets()
} }
if (texno.isValid()) if (texno.isValid())
{ {
FTexture * tex = GetTexture(texno); auto tex = GetGameTexture(texno);
int lumpnum = tex->GetSourceLump(); int lumpnum = tex->GetSourceLump();
// We only want to change texture offsets for sprites in the IWAD or the file this lump originated from. // 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) 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. if (donotprocess.CheckKey(sprid)) continue; // do not alter sprites that only get partially replaced.
} }
tex->_LeftOffset[1] = x; tex->SetOffsets(1, x, y);
tex->_TopOffset[1] = y;
} }
} }
} }

View file

@ -9,8 +9,8 @@
#include "name.h" #include "name.h"
class FxAddSub; class FxAddSub;
class FTexture;
struct BuildInfo; struct BuildInfo;
class FMultipatchTextureBuilder;
int PalCheck(int tex); int PalCheck(int tex);
// Texture manager // Texture manager
@ -25,42 +25,59 @@ public:
private: private:
int ResolveLocalizedTexture(int texnum); 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 (animate) texnum = Translation[texnum];
if (localize && Textures[texnum].HasLocalization) texnum = ResolveLocalizedTexture(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; return Textures[texnum].Texture;
} }
public: 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. // 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); FTextureID texnum = GetTextureID(name, ETextureType::MiscPatch);
return InternalGetTexture(texnum.GetIndex(), animate, true, false); 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. FGameTexture* GameByIndex(int i, bool animate = false)
FTexture *GetPalettedTexture(FTextureID texnum, bool animate)
{ {
return InternalGetTexture(texnum.GetIndex(), animate, true, true); return InternalGetTexture(i, animate, true);
} }
FTexture *ByIndex(int i, bool animate = false) FGameTexture* FindGameTexture(const char* texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny);
{
return InternalGetTexture(i, animate, true, false);
}
FTexture *FindTexture(const char *texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny);
bool OkForLocalization(FTextureID texnum, const char *substitute, int locnum); bool OkForLocalization(FTextureID texnum, const char *substitute, int locnum);
void FlushAll(); void FlushAll();
FTextureID GetFrontSkyLayer(FTextureID);
FTextureID GetRawTexture(FTextureID);
enum enum
@ -99,7 +116,7 @@ public:
void AddLocalizedVariants(); void AddLocalizedVariants();
FTextureID CreateTexture (int lumpnum, ETextureType usetype=ETextureType::Any); // Also calls AddTexture 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; } FTextureID GetDefaultTexture() const { return DefaultTexture; }
void LoadTextureX(int wadnum, FMultipatchTextureBuilder &build); void LoadTextureX(int wadnum, FMultipatchTextureBuilder &build);
@ -107,7 +124,7 @@ public:
void Init(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo &)); void Init(void (*progressFunc_)(), void (*checkForHacks)(BuildInfo &));
void DeleteAll(); 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(); } int NumTextures () const { return (int)Textures.Size(); }
@ -144,7 +161,7 @@ public:
return BuildTileData.Last(); 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); void SetTranslation(FTextureID fromtexnum, FTextureID totexnum);
private: private:
@ -155,7 +172,10 @@ private:
struct TextureHash struct TextureHash
{ {
FTexture *Texture; FGameTexture* Texture;
int Paletted; // redirection to paletted variant
int FrontSkyLayer; // and front sky layer,
int RawTexture;
int HashNext; int HashNext;
bool HasLocalization; bool HasLocalization;
}; };
@ -185,3 +205,4 @@ public:
}; };
extern FTextureManager TexMan; extern FTextureManager TexMan;

View file

@ -42,23 +42,33 @@
#include "textureid.h" #include "textureid.h"
#include <vector> #include <vector>
#include "hw_texcontainer.h" #include "hw_texcontainer.h"
#include "floatrect.h"
// 15 because 0th texture is our texture #include "refcounted.h"
#define MAX_CUSTOM_HW_SHADER_TEXTURES 15
typedef TMap<int, bool> SpriteHits; typedef TMap<int, bool> SpriteHits;
class FImageSource; 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 enum MaterialShaderIndex
{ {
SHADER_Default, SHADER_Default,
SHADER_Warp1, SHADER_Warp1,
SHADER_Warp2, SHADER_Warp2,
SHADER_Brightmap,
SHADER_Specular, SHADER_Specular,
SHADER_SpecularBrightmap,
SHADER_PBR, SHADER_PBR,
SHADER_PBRBrightmap,
SHADER_Paletted, SHADER_Paletted,
SHADER_NoTexture, SHADER_NoTexture,
SHADER_BasicFuzz, SHADER_BasicFuzz,
@ -72,46 +82,34 @@ enum MaterialShaderIndex
FIRST_USER_SHADER 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 struct UserShaderDesc
{ {
FString shader; FString shader;
MaterialShaderIndex shaderType; MaterialShaderIndex shaderType;
FString defines; FString defines;
bool disablealphatest = false; bool disablealphatest = false;
uint8_t shaderFlags = 0;
}; };
extern TArray<UserShaderDesc> usershaders; extern TArray<UserShaderDesc> 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; class FBitmap;
struct FRemapTable; struct FRemapTable;
struct FCopyInfo; struct FCopyInfo;
@ -141,7 +139,12 @@ enum FTextureFormat : uint32_t
TEX_Count TEX_Count
}; };
class FSoftwareTexture; class ISoftwareTexture
{
public:
virtual ~ISoftwareTexture() = default;
};
class FGLRenderState; class FGLRenderState;
struct spriteframewithrotate; struct spriteframewithrotate;
@ -202,115 +205,62 @@ struct FTextureBuffer
}; };
// Base texture class // Base texture class
class FTexture class FTexture : public RefCountedBase
{ {
friend class GLDefsParser; friend class FGameTexture; // only for the porting work
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);
// For now only give access to classes which cannot be reworked yet. None of these should remain here when all is done. public:
friend class FSoftwareTexture; FHardwareTextureContainer SystemTextures;
friend class FWarpTexture; protected:
friend class FMaterial; FloatRect* areas = nullptr;
friend class OpenGLRenderer::FGLRenderState; // For now this needs access to some fields in ApplyMaterial. This should be rerouted through the Material class int SourceLump;
friend class VkRenderState; uint16_t Width = 0, Height = 0;
friend class PolyRenderState;
friend struct FTexCoordInfo; bool Masked = false; // Texture (might) have holes
friend class OpenGLRenderer::FHardwareTexture; bool bHasCanvas = false;
friend class VkHardwareTexture; int8_t bTranslucent = -1;
friend class PolyHardwareTexture; int8_t areacount = 0; // this is capped at 4 sections.
friend class FMultiPatchTexture;
friend class FSkyBox;
friend class FBrightmapTexture;
friend class FFont;
public: 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; } virtual FImageSource *GetImage() const { return nullptr; }
void AddAutoMaterials();
void CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly); 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. void CleanHardwareTextures()
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)
{ {
_LeftOffset[0] = _LeftOffset[1] = l; SystemTextures.Clean();
_TopOffset[0] = _TopOffset[1] = t;
} }
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 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 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; } int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method.
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();
bool FindHoles(const unsigned char * buffer, int w, int h); 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) void CopySize(FTexture* BaseTexture)
{ {
Width = BaseTexture->GetTexelWidth(); Width = BaseTexture->GetWidth();
Height = BaseTexture->GetTexelHeight(); Height = BaseTexture->GetHeight();
_TopOffset[0] = BaseTexture->_TopOffset[0];
_TopOffset[1] = BaseTexture->_TopOffset[1];
_LeftOffset[0] = BaseTexture->_LeftOffset[0];
_LeftOffset[1] = BaseTexture->_LeftOffset[1];
Scale = BaseTexture->Scale;
} }
// This is only used for the null texture and for Heretic's skies. // This is only used for the null texture and for Heretic's skies.
@ -320,119 +270,20 @@ public:
Height = h; Height = h;
} }
bool TrimBorders(uint16_t* rect);
int GetAreas(FloatRect** pAreas) const;
// Returns the whole texture, stored in column-major order // Returns the whole texture, stored in column-major order
virtual TArray<uint8_t> Get8BitPixels(bool alphatex); virtual TArray<uint8_t> Get8BitPixels(bool alphatex);
virtual FBitmap GetBgraBitmap(const PalEntry *remap, int *trans = nullptr); virtual FBitmap GetBgraBitmap(const PalEntry *remap, int *trans = nullptr);
static bool SmoothEdges(unsigned char * buffer,int w, int h); 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() {} virtual void ResolvePatches() {}
void SetScale(const DVector2 &scale)
{
Scale = scale;
}
protected: FTexture (int lumpnum = -1);
uint16_t Width, Height;
int16_t _LeftOffset[2], _TopOffset[2];
FTexture (const char *name = NULL, int lumpnum = -1);
public: public:
FTextureBuffer CreateTexBuffer(int translation, int flags = 0); FTextureBuffer CreateTexBuffer(int translation, int flags = 0);
@ -442,27 +293,6 @@ public:
{ {
return bTranslucent != -1 ? bTranslucent : DetermineTranslucency(); 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: public:
@ -479,17 +309,13 @@ public:
class FCanvasTexture : public FTexture class FCanvasTexture : public FTexture
{ {
public: public:
FCanvasTexture(const char* name, int width, int height) FCanvasTexture(int width, int height)
{ {
Name = name;
Width = width; Width = width;
Height = height; Height = height;
bMasked = false;
bHasCanvas = true; bHasCanvas = true;
bTranslucent = false; aspectRatio = (float)width / height;
bNoExpand = true;
UseType = ETextureType::Wall;
} }
void NeedUpdate() { bNeedsUpdate = true; } void NeedUpdate() { bNeedsUpdate = true; }
@ -501,6 +327,7 @@ protected:
bool bNeedsUpdate = true; bool bNeedsUpdate = true;
public: public:
bool bFirstUpdate = true; bool bFirstUpdate = true;
float aspectRatio;
friend struct FCanvasTextureInfo; friend struct FCanvasTextureInfo;
}; };
@ -514,7 +341,7 @@ public:
FWrapperTexture(int w, int h, int bits = 1); FWrapperTexture(int w, int h, int bits = 1);
IHardwareTexture *GetSystemTexture() IHardwareTexture *GetSystemTexture()
{ {
return SystemTextures.GetHardwareTexture(0, false); return SystemTextures.GetHardwareTexture(0, 0);
} }
int GetColorFormat() const int GetColorFormat() const
@ -527,14 +354,19 @@ public:
class FImageTexture : public FTexture class FImageTexture : public FTexture
{ {
FImageSource* mImage; FImageSource* mImage;
bool bNoRemap0 = false;
protected:
void SetFromImage();
public: public:
FImageTexture(FImageSource* image, const char* name = nullptr) noexcept; FImageTexture(FImageSource* image) noexcept;
virtual TArray<uint8_t> Get8BitPixels(bool alphatex); virtual TArray<uint8_t> Get8BitPixels(bool alphatex);
void SetImage(FImageSource* img) // This is only for the multipatch texture builder! void SetImage(FImageSource* img)
{ {
mImage = img; mImage = img;
SetFromImage();
} }
void SetNoRemap0() { bNoRemap0 = true; }
FImageSource* GetImage() const override { return mImage; } FImageSource* GetImage() const override { return mImage; }
FBitmap GetBgraBitmap(const PalEntry* p, int* trans) override; 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 #endif

View file

@ -86,7 +86,7 @@ static bool TabbedList; // True if tab list was shown
CVAR(Bool, con_notablist, false, CVAR_ARCHIVE) CVAR(Bool, con_notablist, false, CVAR_ARCHIVE)
static FTexture* conback; static FGameTexture* conback;
static uint32_t conshade; static uint32_t conshade;
static bool conline; static bool conline;

View file

@ -316,7 +316,7 @@ bool FListMenuItem::Selectable()
return false; return false;
} }
void FListMenuItem::DrawSelector(int xofs, int yofs, FTexture *tex) void FListMenuItem::DrawSelector(int xofs, int yofs, FGameTexture *tex)
{ {
if (!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) : FListMenuItem(x, y)
{ {
mTexture = patch; mTexture = patch;
@ -414,7 +414,7 @@ void FListMenuItemStaticPatch::Drawer(DListMenu* menu, const DVector2& origin, b
} }
int x = mXpos; int x = mXpos;
FTexture *tex = mTexture; FGameTexture *tex = mTexture;
if (mYpos >= 0) if (mYpos >= 0)
{ {
if (mCentered) x -= tex->GetDisplayWidth()/2; 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) : FListMenuItemSelectable(x, y, height, child, param)
{ {
mHotkey = hotkey; mHotkey = hotkey;

View file

@ -270,7 +270,7 @@ bool DMenu::MouseEventBack(int type, int x, int y)
auto texid = TexMan.CheckForTexture("engine/graphics/m_back.png", ETextureType::Any); auto texid = TexMan.CheckForTexture("engine/graphics/m_back.png", ETextureType::Any);
if (texid.isValid()) 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&1) x -= screen->GetWidth() - tex->GetDisplayWidth() * CleanXfac;
if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetDisplayHeight() * CleanYfac; if (m_show_backbutton&2) y -= screen->GetHeight() - tex->GetDisplayHeight() * CleanYfac;
mBackbuttonSelected = ( x >= 0 && x < tex->GetDisplayWidth() * CleanXfac && 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); auto texid = TexMan.CheckForTexture("engine/graphics/m_back.png", ETextureType::Any);
if (texid.isValid()) if (texid.isValid())
{ {
auto tex = TexMan.GetTexture(texid); auto tex = TexMan.GetGameTexture(texid);
int w = tex->GetDisplayWidth() * CleanXfac; int w = tex->GetDisplayWidth() * CleanXfac;
int h = tex->GetDisplayHeight() * CleanYfac; int h = tex->GetDisplayHeight() * CleanYfac;
int x = (!(m_show_backbutton & 1)) ? 0 : screen->GetWidth() - w; int x = (!(m_show_backbutton & 1)) ? 0 : screen->GetWidth() - w;

View file

@ -107,7 +107,7 @@ enum EMenuSounds : int
EXTERN_CVAR(Bool, menu_sounds) EXTERN_CVAR(Bool, menu_sounds)
struct event_t; struct event_t;
class FTexture; class FGameTexture;
class FFont; class FFont;
enum EColorRange : int; enum EColorRange : int;
class FPlayerClass; class FPlayerClass;
@ -196,7 +196,7 @@ struct FListMenuDescriptor : public FMenuDescriptor
int mSelectedItem; int mSelectedItem;
int mSelectOfsX; int mSelectOfsX;
int mSelectOfsY; int mSelectOfsY;
FTexture *mSelector; FGameTexture *mSelector;
int mDisplayTop; int mDisplayTop;
int mXpos, mYpos, mYbotton; int mXpos, mYpos, mYbotton;
int mWLeft, mWRight; int mWLeft, mWRight;
@ -401,7 +401,7 @@ public:
virtual bool MouseEvent(int type, int x, int y); virtual bool MouseEvent(int type, int x, int y);
virtual bool CheckHotkey(int c); virtual bool CheckHotkey(int c);
virtual int GetWidth(); 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; } void OffsetPositionY(int ydelta) { mYpos += ydelta; }
int GetY() { return mYpos; } int GetY() { return mYpos; }
int GetX() { return mXpos; } int GetX() { return mXpos; }
@ -414,11 +414,11 @@ public:
class FListMenuItemStaticPatch : public FListMenuItem class FListMenuItemStaticPatch : public FListMenuItem
{ {
protected: protected:
FTexture *mTexture; FGameTexture *mTexture;
bool mCentered; bool mCentered;
public: 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); void Drawer(DListMenu* menu, const DVector2& origin, bool selected);
}; };
@ -496,15 +496,15 @@ public:
~FListMenuItemNativeText(); ~FListMenuItemNativeText();
void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override; void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override;
int GetWidth() 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 class FListMenuItemPatch : public FListMenuItemSelectable
{ {
FTexture* mTexture; FGameTexture* mTexture;
public: 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; void Drawer(DListMenu* menu, const DVector2& origin, bool selected) override;
int GetWidth() override; int GetWidth() override;
}; };
@ -806,7 +806,7 @@ private:
int LastSaved = -1; int LastSaved = -1;
int LastAccessed = -1; int LastAccessed = -1;
TArray<char> SavePicData; TArray<char> SavePicData;
FTexture *SavePic = nullptr; FGameTexture *SavePic = nullptr;
public: public:
int WindowSize = 0; int WindowSize = 0;

View file

@ -104,7 +104,7 @@ void M_DeinitMenus()
DefaultListMenuSettings.mItems.Clear(); DefaultListMenuSettings.mItems.Clear();
} }
static FTexture* GetMenuTexture(const char* const name) static FGameTexture* GetMenuTexture(const char* const name)
{ {
auto texid = TexMan.CheckForTexture(name, ETextureType::Any); auto texid = TexMan.CheckForTexture(name, ETextureType::Any);
if (!texid.isValid()) if (!texid.isValid())
@ -112,7 +112,7 @@ static FTexture* GetMenuTexture(const char* const name)
Printf("Missing menu texture: \"%s\"\n", 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; int y = sc.Number;
sc.MustGetStringName(","); sc.MustGetStringName(",");
sc.MustGetString(); sc.MustGetString();
FTexture* tex = GetMenuTexture(sc.String); auto tex = GetMenuTexture(sc.String);
FListMenuItem *it = new FListMenuItemStaticPatch(x, y, tex, centered); FListMenuItem *it = new FListMenuItemStaticPatch(x, y, tex, centered);
desc->mItems.Push(it); desc->mItems.Push(it);
@ -401,7 +401,7 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc)
else if (sc.Compare("PatchItem")) else if (sc.Compare("PatchItem"))
{ {
sc.MustGetString(); sc.MustGetString();
FTexture* tex = GetMenuTexture(sc.String); auto tex = GetMenuTexture(sc.String);
sc.MustGetStringName(","); sc.MustGetStringName(",");
sc.MustGetString(); sc.MustGetString();
int hotkey = sc.String[0]; int hotkey = sc.String[0];

View file

@ -330,7 +330,7 @@ void DTextEnterMenu::Drawer ()
int width; int width;
const int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2; const int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2;
const int ch = InputGridChars[y * INPUTGRID_WIDTH + x]; 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; EColorRange color;
int remap; int remap;

View file

@ -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; auto BaseLayer = pBaseLayer ? (::FHardwareTexture*)pBaseLayer : nullptr;
if (BaseLayer == nullptr) if (BaseLayer == nullptr)
@ -179,7 +179,7 @@ void FGLRenderer::BindToFrameBuffer(FTexture *mat)
// must create the hardware texture first // must create the hardware texture first
BaseLayer = new ::FHardwareTexture; BaseLayer = new ::FHardwareTexture;
BaseLayer->CreateTexture(mat->GetTexelWidth()*4, mat->GetTexelHeight()*4, ::FHardwareTexture::TrueColor, false); 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); BaseLayer->BindToFrameBuffer(mat->GetTexelWidth()*4, mat->GetTexelHeight()*4);
} }

View file

@ -88,7 +88,7 @@ public:
bool StartOffscreen(); bool StartOffscreen();
void EndOffscreen(); void EndOffscreen();
void BindToFrameBuffer(FTexture* tex); void BindToFrameBuffer(FGameTexture* tex);
private: private:

View file

@ -108,7 +108,7 @@ TArray<uint8_t> FTileTexture::CreatePalettedPixels(int conversion)
// //
//========================================================================== //==========================================================================
static FTexture* GetTileTexture(const char* name, const TArray<uint8_t>& backingstore, uint32_t offset, int width, int height) static FGameTexture* GetTileTexture(const char* name, const TArray<uint8_t>& backingstore, uint32_t offset, int width, int height)
{ {
auto tex = new FArtTile(backingstore, offset, width, height); auto tex = new FArtTile(backingstore, offset, width, height);
auto p = &backingstore[offset]; auto p = &backingstore[offset];
@ -122,7 +122,7 @@ static FTexture* GetTileTexture(const char* name, const TArray<uint8_t>& backing
if (tex) if (tex)
{ {
return new FImageTexture(tex, name); return MakeGameTexture(new FImageTexture(tex), name, ETextureType::Any);
} }
return nullptr; return nullptr;
} }
@ -130,7 +130,7 @@ static FTexture* GetTileTexture(const char* name, const TArray<uint8_t>& backing
void BuildTiles::Init() void BuildTiles::Init()
{ {
Placeholder = TexMan.ByIndex(0); Placeholder = TexMan.GameByIndex(0);
for (auto& tile : tiledata) for (auto& tile : tiledata)
{ {
tile.texture = Placeholder; tile.texture = Placeholder;
@ -138,6 +138,7 @@ void BuildTiles::Init()
tile.picanm = {}; tile.picanm = {};
tile.RotTile = { -1,-1 }; tile.RotTile = { -1,-1 };
tile.replacement = ReplacementType::Art; 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. assert(!tex->GetID().isValid()); // must not be added yet.
TexMan.AddTexture(tex); TexMan.AddGameTexture(tex);
tiledata[tilenum].texture = tex; tiledata[tilenum].texture = tex;
if (!permap) tiledata[tilenum].backup = tex; if (!permap) tiledata[tilenum].backup = tex;
} }
@ -300,12 +301,12 @@ void BuildTiles::InvalidateTile(int num)
if ((unsigned) num < MAXTILES) if ((unsigned) num < MAXTILES)
{ {
auto tex = tiledata[num].texture; auto tex = tiledata[num].texture;
tex->SystemTextures.Clean(true, true); tex->GetTexture()->SystemTextures.Clean();
for (auto &rep : tiledata[num].Hightiles) for (auto &rep : tiledata[num].Hightiles)
{ {
for (auto &reptex : rep.faces) for (auto &reptex : rep.faces)
{ {
if (reptex) reptex->SystemTextures.Clean(true, true); if (reptex) reptex->GetTexture()->SystemTextures.Clean();
} }
} }
tiledata[num].rawCache.data.Clear(); 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; if (tilenum < 0 || tilenum >= MAXTILES) return nullptr;
auto &td = tiledata[tilenum]; 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... // 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. 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. // 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) else if (type == ReplacementType::Canvas)
{ {
replacement = new FCanvasTexture("camera", 0, 0); replacement = new FCanvasTexture(0, 0);
} }
else return nullptr; else return nullptr;
AddTile(tilenum, replacement); auto reptex = MakeGameTexture(replacement, "", ETextureType::Any);
return replacement; 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; if (width <= 0 || height <= 0) return nullptr;
auto tex = ValidateCustomTile(tilenum, ReplacementType::Writable); auto tex = ValidateCustomTile(tilenum, ReplacementType::Writable);
if (tex == nullptr) return nullptr; if (tex == nullptr) return nullptr;
auto wtex = static_cast<FWritableTile*>(tex->GetImage()); auto wtex = static_cast<FWritableTile*>(tex->GetTexture()->GetImage());
if (!wtex->ResizeImage(width, height)) return nullptr; if (!wtex->ResizeImage(width, height)) return nullptr;
tex->SetSize(width, height); tex->SetSize(width, height);
return wtex->GetRawData(); return wtex->GetRawData();
@ -486,7 +488,7 @@ uint8_t* BuildTiles::tileCreate(int tilenum, int width, int height)
uint8_t* BuildTiles::tileMakeWritable(int num) uint8_t* BuildTiles::tileMakeWritable(int num)
{ {
auto tex = ValidateCustomTile(num, ReplacementType::Restorable); auto tex = ValidateCustomTile(num, ReplacementType::Restorable);
auto wtex = static_cast<FWritableTile*>(tex->GetImage()); auto wtex = static_cast<FWritableTile*>(tex->GetTexture()->GetImage());
return wtex ? wtex->GetRawData() : nullptr; return wtex ? wtex->GetRawData() : nullptr;
} }
@ -499,7 +501,7 @@ uint8_t* BuildTiles::tileMakeWritable(int num)
int32_t tileGetCRC32(int tileNum) int32_t tileGetCRC32(int tileNum)
{ {
if ((unsigned)tileNum >= (unsigned)MAXTILES) return 0; if ((unsigned)tileNum >= (unsigned)MAXTILES) return 0;
auto tile = dynamic_cast<FArtTile*>(TileFiles.tiledata[tileNum].texture->GetImage()); // only consider original ART tiles. auto tile = dynamic_cast<FArtTile*>(TileFiles.tiledata[tileNum].texture->GetTexture()->GetImage()); // only consider original ART tiles.
if (!tile) return 0; if (!tile) return 0;
auto pixels = tile->GetRawData(); auto pixels = tile->GetRawData();
if (!pixels) return 0; 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); FTextureID texid = TexMan.CheckForTexture(fn, ETextureType::Any);
if (!texid.isValid()) return -1; if (!texid.isValid()) return -1;
auto tex = TexMan.GetTexture(texid); auto tex = TexMan.GetGameTexture(texid);
//tex->alphaThreshold = 255 - alphacut; //tex->alphaThreshold = 255 - alphacut;
int32_t xsiz = tex->GetTexelWidth(), ysiz = tex->GetTexelHeight(); 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* picanm = nullptr;
picanm_t* sourceanm = nullptr; picanm_t* sourceanm = nullptr;
int srcxo, srcyo; int srcxo, srcyo;
FTexture* tex; FGameTexture* tex;
if (pal == -1 && tile == source) 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); srcxo = tex->GetTexelLeftOffset(0);
srcyo = tex->GetTexelTopOffset(0); srcyo = tex->GetTexelTopOffset(0);
TArray<uint8_t> buffer = tex->Get8BitPixels(false); TArray<uint8_t> buffer = tex->GetTexture()->Get8BitPixels(false);
if (pal != -1) if (pal != -1)
{ {
@ -604,7 +606,7 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags
pixel = remap[pixel]; 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; picanm = &TileFiles.tiledata[tile].picanm;
TileFiles.AddTile(tile, tex); TileFiles.AddTile(tile, tex);
} }
@ -656,7 +658,7 @@ void artSetupMapArt(const char* filename)
auto texid = TexMan.CheckForTexture(name, ETextureType::Any); auto texid = TexMan.CheckForTexture(name, ETextureType::Any);
if (texid.isValid()) if (texid.isValid())
{ {
TileFiles.tiledata[i].texture = TexMan.GetTexture(texid); TileFiles.tiledata[i].texture = TexMan.GetGameTexture(texid);
} }
} }
return; return;
@ -691,7 +693,7 @@ void artSetupMapArt(const char* filename)
void tileDelete(int tile) void tileDelete(int tile)
{ {
TileFiles.TextureToTile.Remove(tileGetTexture(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); vox_undefine(tile);
md_undefinetile(tile); md_undefinetile(tile);
tileRemoveReplacement(tile); tileRemoveReplacement(tile);
@ -723,7 +725,7 @@ void tileSetDummy(int tile, int width, int height)
} }
else if (width > 0 && height > 0) 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); TileFiles.AddTile(tile, dtile);
} }
} }
@ -760,7 +762,7 @@ int BuildTiles::tileCreateRotated(int tileNum)
if ((unsigned)tileNum >= MAXTILES) return tileNum; if ((unsigned)tileNum >= MAXTILES) return tileNum;
auto tex = tileGetTexture(tileNum); auto tex = tileGetTexture(tileNum);
if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return tileNum; if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return tileNum;
TArray<uint8_t> buffer = tex->Get8BitPixels(false); TArray<uint8_t> buffer = tex->GetTexture()->Get8BitPixels(false);
TArray<uint8_t> dbuffer(tex->GetTexelWidth() * tex->GetTexelHeight(), true); TArray<uint8_t> dbuffer(tex->GetTexelWidth() * tex->GetTexelHeight(), true);
auto src = buffer.Data(); auto src = buffer.Data();
@ -777,7 +779,7 @@ int BuildTiles::tileCreateRotated(int tileNum)
*(dst + y * width + xofs) = *(src + y + yofs); *(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(); int index = findUnusedTile();
bool mapart = TileFiles.tiledata[tileNum].texture != TileFiles.tiledata[tileNum].backup; bool mapart = TileFiles.tiledata[tileNum].texture != TileFiles.tiledata[tileNum].backup;
TileFiles.AddTile(index, dtex, mapart); TileFiles.AddTile(index, dtex, mapart);
@ -821,7 +823,7 @@ int tileSetHightileReplacement(int picnum, int palnum, const char* filename, flo
return -1; return -1;
} }
replace.faces[0] = TexMan.GetTexture(texid); replace.faces[0] = TexMan.GetGameTexture(texid);
if (replace.faces[0] == nullptr) if (replace.faces[0] == nullptr)
replace.alphacut = min(alphacut,1.f); replace.alphacut = min(alphacut,1.f);
replace.scale = { xscale, yscale }; 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); Printf("%s: Skybox image for tile %d does not exist or is invalid\n", *facenames, picnum);
return -1; return -1;
} }
face = TexMan.GetTexture(texid); face = TexMan.GetGameTexture(texid);
} }
replace.flags = flags; replace.flags = flags;
replace.palnum = (uint16_t)palnum; replace.palnum = (uint16_t)palnum;

View file

@ -62,7 +62,7 @@ struct rottile_t
struct HightileReplacement 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; vec2f_t scale;
float alphacut, specpower, specfactor; float alphacut, specpower, specfactor;
uint16_t palnum, flags; uint16_t palnum, flags;
@ -257,23 +257,24 @@ struct RawCacheNode
struct TileDesc struct TileDesc
{ {
FTexture* texture; // the currently active tile FGameTexture* texture; // the currently active tile
FTexture* backup; // original backup for map tiles FGameTexture* backup; // original backup for map tiles
RawCacheNode rawCache; // this is needed for hitscan testing to avoid reloading the texture each time. RawCacheNode rawCache; // this is needed for hitscan testing to avoid reloading the texture each time.
picanm_t picanm; // animation descriptor picanm_t picanm; // animation descriptor
picanm_t picanmbackup; // animation descriptor backup when using map tiles picanm_t picanmbackup; // animation descriptor backup when using map tiles
rottile_t RotTile;// = { -1,-1 }; rottile_t RotTile;// = { -1,-1 };
TArray<HightileReplacement> Hightiles; TArray<HightileReplacement> Hightiles;
ReplacementType replacement; ReplacementType replacement;
FixedBitArray<256> NoBrightmapFlag;
}; };
struct BuildTiles struct BuildTiles
{ {
FTexture* Placeholder; FGameTexture* Placeholder;
TDeletingArray<BuildArtFile*> ArtFiles; TDeletingArray<BuildArtFile*> ArtFiles;
TileDesc tiledata[MAXTILES]; TileDesc tiledata[MAXTILES];
TArray<FString> addedArt; TArray<FString> addedArt;
TMap<FTexture*, int> TextureToTile; TMap<FGameTexture*, int> TextureToTile;
TArray<FString> maptilesadded; TArray<FString> maptilesadded;
void Init(); // This cannot be a constructor because it needs the texture manager running. void Init(); // This cannot be a constructor because it needs the texture manager running.
@ -284,7 +285,7 @@ struct BuildTiles
void CloseAll(); 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<uint8_t>& store, const char* mapname); void AddTiles(int firsttile, TArray<uint8_t>& store, const char* mapname);
@ -302,7 +303,7 @@ struct BuildTiles
{ {
addedArt = std::move(art); addedArt = std::move(art);
} }
int GetTileIndex(FTexture* tex) int GetTileIndex(FGameTexture* tex)
{ {
auto p = TextureToTile.CheckKey(tex); auto p = TextureToTile.CheckKey(tex);
return p ? *p : -1; 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); int32_t artLoadFiles(const char* filename);
uint8_t* tileMakeWritable(int num); uint8_t* tileMakeWritable(int num);
uint8_t* tileCreate(int tilenum, int width, int height); uint8_t* tileCreate(int tilenum, int width, int height);
void tileSetExternal(int tilenum, int width, int height, uint8_t* data);
int findUnusedTile(void); int findUnusedTile(void);
int tileCreateRotated(int owner); int tileCreateRotated(int owner);
void ClearTextureCache(bool artonly = false);
void InvalidateTile(int num); void InvalidateTile(int num);
void MakeCanvas(int tilenum, int width, int height); void MakeCanvas(int tilenum, int width, int height);
HightileReplacement* FindReplacement(int picnum, int palnum, bool skybox = false); 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; auto tex = TileFiles.tiledata[num].texture;
if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return nullptr; 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(); TileFiles.tiledata[num].rawCache.lastUseTime = I_nsTime();
return TileFiles.tiledata[num].rawCache.data.Data(); return TileFiles.tiledata[num].rawCache.data.Data();
@ -381,7 +380,7 @@ inline bool tileLoad(int tileNum)
inline uint8_t* tileData(int num) inline uint8_t* tileData(int num)
{ {
auto tex = TileFiles.tiledata[num].texture; auto tex = TileFiles.tiledata[num].texture;
auto p = dynamic_cast<FWritableTile*>(tex); auto p = dynamic_cast<FWritableTile*>(tex->GetTexture());
return p ? p->GetRawData() : nullptr; return p ? p->GetRawData() : nullptr;
} }
@ -464,7 +463,7 @@ inline void tileInvalidate(int tilenume, int32_t, int32_t)
TileFiles.InvalidateTile(tilenume); TileFiles.InvalidateTile(tilenume);
} }
inline FTexture* tileGetTexture(int tile) inline FGameTexture* tileGetTexture(int tile)
{ {
assert(tile < MAXTILES); assert(tile < MAXTILES);
return TileFiles.tiledata[tile].texture; return TileFiles.tiledata[tile].texture;

View file

@ -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() }; vec2_t siz = { tex->GetTexelWidth(), tex->GetTexelHeight() };
auto store = tex->Get8BitPixels(false); auto store = tex->GetTexture()->Get8BitPixels(false);
const uint8_t* p = store.Data(); const uint8_t* p = store.Data();
auto glpic = GLInterface.NewTexture(); 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. // Check if the texture is fully transparent. When creating a brightmap such textures can be discarded.
if (checkfulltransparency) 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; 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; if (phwtex) return (FHardwareTexture*)phwtex;
FHardwareTexture *hwtex = nullptr; FHardwareTexture *hwtex = nullptr;
if (textype == TT_INDEXED) if (textype == TT_INDEXED)
hwtex = CreateIndexedTexture(tex); 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); hwtex = CreateTrueColorTexture(tex, textype == TT_HICREPLACE? -1 : palid, textype == TT_BRIGHTMAP, textype == TT_BRIGHTMAP);
else else
hwtex = nullptr; hwtex = nullptr;
if (hwtex) tex->SystemTextures.AddHardwareTexture(palid, false, hwtex); if (hwtex) tex->GetTexture()->SystemTextures.AddHardwareTexture(palid, false, hwtex);
return hwtex; return hwtex;
} }
@ -148,7 +148,7 @@ FHardwareTexture* GLInstance::LoadTexture(FTexture* tex, int textype, int palid)
struct TexturePick struct TexturePick
{ {
FTexture* texture; // which texture to use FGameTexture* texture; // which texture to use
int translation; // which translation table to use int translation; // which translation table to use
int tintFlags; // which shader tinting options to use int tintFlags; // which shader tinting options to use
PalEntry tintColor; // Tint color PalEntry tintColor; // Tint color
@ -165,7 +165,7 @@ TexturePick PickTexture(int tilenum, int basepal, int palette)
auto tex = TileFiles.tiles[tilenum]; auto tex = TileFiles.tiles[tilenum];
auto rep = (hw_hightile && !(h.f & HICTINT_ALWAYSUSEART)) ? TileFiles.FindReplacement(tilenum, usepalswap) : nullptr; 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. // 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; bool applytint = false;
if (truecolor) if (truecolor)
{ {
@ -203,7 +203,7 @@ TexturePick PickTexture(int tilenum, int basepal, int palette)
} }
#endif #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; if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false;
int usepalette = fixpalette >= 0 ? fixpalette : curbasepal; 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. // 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. 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; 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) if (usepalette != 0)
{ {
@ -338,7 +338,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int
} }
} }
#if 1 #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) if (TextureType == TT_HICREPLACE)
{ {
@ -364,7 +364,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int
if (htex == nullptr) if (htex == nullptr)
{ {
// Flag the texture as not being brightmapped for the given palette // Flag the texture as not being brightmapped for the given palette
tex->NoBrightmapFlag.Set(usepalswap); TileFiles.tiledata[picnum].NoBrightmapFlag.Set(usepalswap);
} }
else 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); auto mtex = LoadTexture(tex, palette>= 0? TT_TRUECOLOR : TT_HICREPLACE, palette);
if (!mtex) return false; if (!mtex) return false;
@ -417,11 +417,6 @@ int PalCheck(int tex)
return tex; return tex;
} }
void DeleteSoftwareTexture(FSoftwareTexture *)
{
}
void InitBuildTiles() void InitBuildTiles()
{ {

View file

@ -14,7 +14,7 @@ class FSamplerManager;
class FShader; class FShader;
class PolymostShader; class PolymostShader;
class SurfaceShader; class SurfaceShader;
class FTexture; class FGameTexture;
class GLInstance; class GLInstance;
class F2DDrawer; class F2DDrawer;
struct palette_t; struct palette_t;
@ -115,7 +115,7 @@ class GLInstance
PaletteManager palmanager; PaletteManager palmanager;
int lastPalswapIndex = -1; int lastPalswapIndex = -1;
FHardwareTexture* texv; FHardwareTexture* texv;
FTexture* currentTexture = nullptr; FGameTexture* currentTexture = nullptr;
int TextureType; int TextureType;
int MatrixChange = 0; int MatrixChange = 0;
@ -474,19 +474,19 @@ public:
renderState.AlphaThreshold = al; renderState.AlphaThreshold = al;
} }
FHardwareTexture* CreateIndexedTexture(FTexture* tex); FHardwareTexture* CreateIndexedTexture(FGameTexture* tex);
FHardwareTexture* CreateTrueColorTexture(FTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false); FHardwareTexture* CreateTrueColorTexture(FGameTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false);
FHardwareTexture *LoadTexture(FTexture* tex, int texturetype, int palid); FHardwareTexture *LoadTexture(FGameTexture* tex, int texturetype, int palid);
bool SetTextureInternal(int globalpicnum, FTexture* tex, int palette, int method, int sampleroverride, FTexture *det, float detscale, FTexture *glow); 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); 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); return SetTextureInternal(-1, tex, palette, 8/*DAMETH_MODEL*/, -1, det, detscale, glow);
} }

View file

@ -63,8 +63,8 @@ TArray<FString> I_GetGogPaths();
// The ini could not be saved at exit // The ini could not be saved at exit
bool I_WriteIniFailed (); bool I_WriteIniFailed ();
class FTexture; class FGameTexture;
bool I_SetCursor(FTexture *); bool I_SetCursor(FGameTexture *);
static inline char *strlwr(char *str) static inline char *strlwr(char *str)
{ {

View file

@ -38,14 +38,14 @@
#include "bitmap.h" #include "bitmap.h"
#include "textures.h" #include "textures.h"
bool I_SetCursor(FTexture *cursorpic) bool I_SetCursor(FGameTexture *cursorpic)
{ {
static SDL_Cursor *cursor; static SDL_Cursor *cursor;
static SDL_Surface *cursorSurface; static SDL_Surface *cursorSurface;
if (cursorpic != NULL) if (cursorpic != NULL)
{ {
auto src = cursorpic->GetBgraBitmap(nullptr); auto src = cursorpic->GetTexture()->GetBgraBitmap(nullptr);
// Must be no larger than 32x32. // Must be no larger than 32x32.
if (src.GetWidth() > 32 || src.GetHeight() > 32) if (src.GetWidth() > 32 || src.GetHeight() > 32)
{ {

View file

@ -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; HCURSOR cursor;
if (cursorpic != NULL) if (cursorpic != NULL)
{ {
auto image = cursorpic->GetBgraBitmap(nullptr); auto image = cursorpic->GetTexture()->GetBgraBitmap(nullptr);
// Must be no larger than 32x32. (is this still necessary? // Must be no larger than 32x32. (is this still necessary?
if (image.GetWidth() > 32 || image.GetHeight() > 32) if (image.GetWidth() > 32 || image.GetHeight() > 32)
{ {

View file

@ -62,8 +62,8 @@ void I_Quit (void);
void I_Tactile (int on, int off, int total); void I_Tactile (int on, int off, int total);
// Set the mouse cursor. The texture must be 32x32. // Set the mouse cursor. The texture must be 32x32.
class FTexture; class FGameTexture;
bool I_SetCursor(FTexture *cursor); bool I_SetCursor(FGameTexture *cursor);
// Repaint the pre-game console // Repaint the pre-game console
void I_PaintConsole (void); void I_PaintConsole (void);