2008-06-15 18:36:26 +00:00
|
|
|
#ifndef __TEXTURES_H
|
|
|
|
#define __TEXTURES_H
|
|
|
|
|
2009-01-03 18:09:33 +00:00
|
|
|
#include "doomtype.h"
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
class FBitmap;
|
|
|
|
struct FRemapTable;
|
|
|
|
struct FCopyInfo;
|
|
|
|
class FScanner;
|
2008-09-14 23:54:38 +00:00
|
|
|
struct PClass;
|
2009-01-03 18:09:33 +00:00
|
|
|
class FArchive;
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
// Texture IDs
|
|
|
|
class FTextureManager;
|
|
|
|
class FTerrainTypeArray;
|
|
|
|
|
|
|
|
class FTextureID
|
|
|
|
{
|
|
|
|
friend class FTextureManager;
|
|
|
|
friend FArchive &operator<< (FArchive &arc, FTextureID &tex);
|
|
|
|
friend FTextureID GetHUDIcon(const PClass *cls);
|
|
|
|
friend void R_InitSpriteDefs ();
|
|
|
|
|
|
|
|
public:
|
2008-06-22 09:13:19 +00:00
|
|
|
FTextureID() throw() {}
|
2008-06-15 18:36:26 +00:00
|
|
|
bool isNull() const { return texnum == 0; }
|
|
|
|
bool isValid() const { return texnum > 0; }
|
|
|
|
bool Exists() const { return texnum >= 0; }
|
|
|
|
void SetInvalid() { texnum = -1; }
|
|
|
|
bool operator ==(const FTextureID &other) const { return texnum == other.texnum; }
|
|
|
|
bool operator !=(const FTextureID &other) const { return texnum != other.texnum; }
|
2008-06-22 09:13:19 +00:00
|
|
|
FTextureID operator +(int offset) throw();
|
2008-06-15 18:36:26 +00:00
|
|
|
int GetIndex() const { return texnum; } // Use this only if you absolutely need the index!
|
|
|
|
|
|
|
|
// The switch list needs these to sort the switches by texture index
|
|
|
|
int operator -(FTextureID other) const { return texnum - other.texnum; }
|
|
|
|
bool operator < (FTextureID other) const { return texnum < other.texnum; }
|
|
|
|
bool operator > (FTextureID other) const { return texnum > other.texnum; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
FTextureID(int num) { texnum = num; }
|
|
|
|
private:
|
|
|
|
int texnum;
|
|
|
|
};
|
|
|
|
|
|
|
|
class FNullTextureID : public FTextureID
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FNullTextureID() : FTextureID(0) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
FArchive &operator<< (FArchive &arc, FTextureID &tex);
|
|
|
|
|
|
|
|
|
|
|
|
// Patches.
|
|
|
|
// A patch holds one or more columns.
|
|
|
|
// Patches are used for sprites and all masked pictures, and we compose
|
|
|
|
// textures from the TEXTURE1/2 lists of patches.
|
|
|
|
struct patch_t
|
|
|
|
{
|
|
|
|
SWORD width; // bounding box size
|
|
|
|
SWORD height;
|
|
|
|
SWORD leftoffset; // pixels to the left of origin
|
|
|
|
SWORD topoffset; // pixels below the origin
|
|
|
|
DWORD columnofs[8]; // only [width] used
|
|
|
|
// the [0] is &columnofs[width]
|
|
|
|
};
|
|
|
|
|
|
|
|
class FileReader;
|
|
|
|
|
|
|
|
// All FTextures present their data to the world in 8-bit format, but if
|
|
|
|
// the source data is something else, this is it.
|
|
|
|
enum FTextureFormat
|
|
|
|
{
|
|
|
|
TEX_Pal,
|
|
|
|
TEX_Gray,
|
|
|
|
TEX_RGB, // Actually ARGB
|
|
|
|
TEX_DXT1,
|
|
|
|
TEX_DXT2,
|
|
|
|
TEX_DXT3,
|
|
|
|
TEX_DXT4,
|
|
|
|
TEX_DXT5,
|
|
|
|
};
|
|
|
|
|
|
|
|
class FNativeTexture;
|
|
|
|
|
|
|
|
// Base texture class
|
|
|
|
class FTexture
|
|
|
|
{
|
|
|
|
public:
|
2008-11-30 12:49:27 +00:00
|
|
|
static FTexture *CreateTexture(const char *name, int lumpnum, int usetype);
|
2008-06-15 18:36:26 +00:00
|
|
|
static FTexture *CreateTexture(int lumpnum, int usetype);
|
|
|
|
virtual ~FTexture ();
|
|
|
|
|
|
|
|
SWORD LeftOffset, TopOffset;
|
|
|
|
|
|
|
|
BYTE WidthBits, HeightBits;
|
|
|
|
|
|
|
|
fixed_t xScale;
|
|
|
|
fixed_t yScale;
|
|
|
|
|
2008-11-30 12:49:27 +00:00
|
|
|
int SourceLump;
|
2009-10-18 14:08:32 +00:00
|
|
|
FTextureID id;
|
2008-11-30 12:49:27 +00:00
|
|
|
|
2009-08-02 03:38:57 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
char Name[9];
|
|
|
|
DWORD dwName; // Used with sprites
|
|
|
|
};
|
2008-06-15 18:36:26 +00:00
|
|
|
BYTE UseType; // This texture's primary purpose
|
|
|
|
|
|
|
|
BYTE bNoDecals:1; // Decals should not stick to texture
|
|
|
|
BYTE bNoRemap0:1; // Do not remap color 0 (used by front layer of parallax skies)
|
|
|
|
BYTE bWorldPanning:1; // Texture is panned in world units rather than texels
|
|
|
|
BYTE bMasked:1; // Texture (might) have holes
|
|
|
|
BYTE bAlphaTexture:1; // Texture is an alpha channel without color information
|
|
|
|
BYTE bHasCanvas:1; // Texture is based off FCanvasTexture
|
|
|
|
BYTE bWarped:2; // This is a warped texture. Used to avoid multiple warps on one texture
|
|
|
|
BYTE bComplex:1; // Will be used to mark extended MultipatchTextures that have to be
|
|
|
|
// fully composited before subjected to any kinf of postprocessing instead of
|
|
|
|
// doing it per patch.
|
|
|
|
|
|
|
|
WORD Rotations;
|
2009-11-13 21:28:39 +00:00
|
|
|
SWORD SkyOffset;
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
enum // UseTypes
|
|
|
|
{
|
|
|
|
TEX_Any,
|
|
|
|
TEX_Wall,
|
|
|
|
TEX_Flat,
|
|
|
|
TEX_Sprite,
|
|
|
|
TEX_WallPatch,
|
|
|
|
TEX_Build,
|
|
|
|
TEX_SkinSprite,
|
|
|
|
TEX_Decal,
|
|
|
|
TEX_MiscPatch,
|
|
|
|
TEX_FontChar,
|
|
|
|
TEX_Override, // For patches between TX_START/TX_END
|
|
|
|
TEX_Autopage, // Automap background - used to enable the use of FAutomapTexture
|
|
|
|
TEX_Null,
|
|
|
|
TEX_FirstDefined,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Span
|
|
|
|
{
|
|
|
|
WORD TopOffset;
|
|
|
|
WORD Length; // A length of 0 terminates this column
|
|
|
|
};
|
|
|
|
|
|
|
|
// Returns a single column of the texture
|
|
|
|
virtual const BYTE *GetColumn (unsigned int column, const Span **spans_out) = 0;
|
|
|
|
|
|
|
|
// Returns the whole texture, stored in column-major order
|
|
|
|
virtual const BYTE *GetPixels () = 0;
|
|
|
|
|
2009-09-30 10:41:24 +00:00
|
|
|
virtual int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate=0, FCopyInfo *inf = NULL);
|
|
|
|
int CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, FRemapTable *remap, FCopyInfo *inf = NULL);
|
2008-06-15 18:36:26 +00:00
|
|
|
virtual bool UseBasePalette();
|
2008-11-30 12:49:27 +00:00
|
|
|
virtual int GetSourceLump() { return SourceLump; }
|
2008-08-14 19:08:38 +00:00
|
|
|
virtual FTexture *GetRedirect(bool wantwarped);
|
2009-10-18 14:08:32 +00:00
|
|
|
FTextureID GetID() const { return id; }
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
virtual void Unload () = 0;
|
|
|
|
|
|
|
|
// Returns the native pixel format for this image
|
|
|
|
virtual FTextureFormat GetFormat();
|
|
|
|
|
|
|
|
// Returns a native 3D representation of the texture
|
|
|
|
FNativeTexture *GetNative(bool wrapping);
|
|
|
|
|
|
|
|
// Frees the native 3D representation of the texture
|
|
|
|
void KillNative();
|
|
|
|
|
|
|
|
// Fill the native texture buffer with pixel data for this image
|
|
|
|
virtual void FillBuffer(BYTE *buff, int pitch, int height, FTextureFormat fmt);
|
|
|
|
|
|
|
|
int GetWidth () { return Width; }
|
|
|
|
int GetHeight () { return Height; }
|
|
|
|
|
|
|
|
int GetScaledWidth () { int foo = (Width << 17) / xScale; return (foo >> 1) + (foo & 1); }
|
|
|
|
int GetScaledHeight () { int foo = (Height << 17) / yScale; return (foo >> 1) + (foo & 1); }
|
- Changed all coordinates for DrawTexture() to floating point so that the
player sprites will retain the same precision they had when they were
rendered as part of the 3D view. (needed for propery alignment of flashes
on top of weapon sprites) It worked just fine for D3D, but software
rendering was another matter. I consequently did battle with imprecisions
in the whole masked texture drawing routines that had previously been
partially masked by only drawing on whole pixel boundaries. Particularly,
the tops of posts are calculated by multiplying by spryscale, and the
texture mapping coordinates are calculated by multiplying by dc_iscale
(where dc_iscale = 1 / spryscale). Since these are both 16.16 fixed point
values, there is a significant variance. For best results, the drawing
routines should only use one of these values, but that would mean
introducing division into the inner loop. If the division removed the
necessity for the fudge code in R_DrawMaskedColumn(), would it be worth it?
Or would the divide be slower than the fudging? Or would I be better off
doing it like Build and using transparent pixel checks instead, not
bothering with skipping transparent areas? For now, I chop off the
fractional part of the top coordinate for software drawing, since it was
the easiest thing to do (even if it wasn't the most correct thing to do).
SVN r1955 (trunk)
2009-11-01 01:27:33 +00:00
|
|
|
double GetScaledWidthDouble () { return (Width * 65536.f) / xScale; }
|
|
|
|
double GetScaledHeightDouble () { return (Height * 65536.f) / yScale; }
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
int GetScaledLeftOffset () { int foo = (LeftOffset << 17) / xScale; return (foo >> 1) + (foo & 1); }
|
|
|
|
int GetScaledTopOffset () { int foo = (TopOffset << 17) / yScale; return (foo >> 1) + (foo & 1); }
|
- Changed all coordinates for DrawTexture() to floating point so that the
player sprites will retain the same precision they had when they were
rendered as part of the 3D view. (needed for propery alignment of flashes
on top of weapon sprites) It worked just fine for D3D, but software
rendering was another matter. I consequently did battle with imprecisions
in the whole masked texture drawing routines that had previously been
partially masked by only drawing on whole pixel boundaries. Particularly,
the tops of posts are calculated by multiplying by spryscale, and the
texture mapping coordinates are calculated by multiplying by dc_iscale
(where dc_iscale = 1 / spryscale). Since these are both 16.16 fixed point
values, there is a significant variance. For best results, the drawing
routines should only use one of these values, but that would mean
introducing division into the inner loop. If the division removed the
necessity for the fudge code in R_DrawMaskedColumn(), would it be worth it?
Or would the divide be slower than the fudging? Or would I be better off
doing it like Build and using transparent pixel checks instead, not
bothering with skipping transparent areas? For now, I chop off the
fractional part of the top coordinate for software drawing, since it was
the easiest thing to do (even if it wasn't the most correct thing to do).
SVN r1955 (trunk)
2009-11-01 01:27:33 +00:00
|
|
|
double GetScaledLeftOffsetDouble() { return (LeftOffset * 65536.f) / xScale; }
|
|
|
|
double GetScaledTopOffsetDouble() { return (TopOffset * 65536.f) / yScale; }
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
virtual void SetFrontSkyLayer();
|
|
|
|
|
|
|
|
void CopyToBlock (BYTE *dest, int dwidth, int dheight, int x, int y, const BYTE *translation=NULL)
|
|
|
|
{
|
|
|
|
CopyToBlock(dest, dwidth, dheight, x, y, 0, translation);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CopyToBlock (BYTE *dest, int dwidth, int dheight, int x, int y, int rotate, const BYTE *translation=NULL);
|
|
|
|
|
|
|
|
// Returns true if the next call to GetPixels() will return an image different from the
|
|
|
|
// last call to GetPixels(). This should be considered valid only if a call to CheckModified()
|
|
|
|
// is immediately followed by a call to GetPixels().
|
|
|
|
virtual bool CheckModified ();
|
|
|
|
|
|
|
|
static void InitGrayMap();
|
|
|
|
|
|
|
|
void CopySize(FTexture *BaseTexture)
|
|
|
|
{
|
|
|
|
Width = BaseTexture->GetWidth();
|
|
|
|
Height = BaseTexture->GetHeight();
|
|
|
|
TopOffset = BaseTexture->TopOffset;
|
|
|
|
LeftOffset = BaseTexture->LeftOffset;
|
|
|
|
WidthBits = BaseTexture->WidthBits;
|
|
|
|
HeightBits = BaseTexture->HeightBits;
|
|
|
|
xScale = BaseTexture->xScale;
|
|
|
|
yScale = BaseTexture->yScale;
|
|
|
|
WidthMask = (1 << WidthBits) - 1;
|
|
|
|
}
|
|
|
|
|
2008-09-14 23:54:38 +00:00
|
|
|
void SetScaledSize(int fitwidth, int fitheight);
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
virtual void HackHack (int newheight); // called by FMultipatchTexture to discover corrupt patches.
|
|
|
|
|
|
|
|
protected:
|
|
|
|
WORD Width, Height, WidthMask;
|
|
|
|
static BYTE GrayMap[256];
|
|
|
|
FNativeTexture *Native;
|
|
|
|
|
2008-11-30 12:49:27 +00:00
|
|
|
FTexture (const char *name = NULL, int lumpnum = -1);
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
Span **CreateSpans (const BYTE *pixels) const;
|
|
|
|
void FreeSpans (Span **spans) const;
|
|
|
|
void CalcBitSize ();
|
2009-01-18 09:31:49 +00:00
|
|
|
void CopyInfo(FTexture *other)
|
|
|
|
{
|
|
|
|
CopySize(other);
|
|
|
|
bNoDecals = other->bNoDecals;
|
|
|
|
Rotations = other->Rotations;
|
|
|
|
}
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
static void FlipSquareBlock (BYTE *block, int x, int y);
|
|
|
|
static void FlipSquareBlockRemap (BYTE *block, int x, int y, const BYTE *remap);
|
|
|
|
static void FlipNonSquareBlock (BYTE *blockto, const BYTE *blockfrom, int x, int y, int srcpitch);
|
|
|
|
static void FlipNonSquareBlockRemap (BYTE *blockto, const BYTE *blockfrom, int x, int y, int srcpitch, const BYTE *remap);
|
|
|
|
|
|
|
|
friend class D3DTex;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Texture manager
|
|
|
|
class FTextureManager
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FTextureManager ();
|
|
|
|
~FTextureManager ();
|
|
|
|
|
|
|
|
// Get texture without translation
|
|
|
|
FTexture *operator[] (FTextureID texnum)
|
|
|
|
{
|
|
|
|
if ((unsigned)texnum.GetIndex() >= Textures.Size()) return NULL;
|
|
|
|
return Textures[texnum.GetIndex()].Texture;
|
|
|
|
}
|
|
|
|
FTexture *operator[] (const char *texname)
|
|
|
|
{
|
|
|
|
FTextureID texnum = GetTexture (texname, FTexture::TEX_MiscPatch);
|
|
|
|
if (!texnum.Exists()) return NULL;
|
|
|
|
return Textures[texnum.GetIndex()].Texture;
|
|
|
|
}
|
|
|
|
FTexture *ByIndex(int i)
|
|
|
|
{
|
|
|
|
if (unsigned(i) >= Textures.Size()) return NULL;
|
|
|
|
return Textures[i].Texture;
|
|
|
|
}
|
|
|
|
FTexture *FindTexture(const char *texname, int usetype = FTexture::TEX_MiscPatch, BITFIELD flags = TEXMAN_TryAny);
|
|
|
|
|
|
|
|
// Get texture with translation
|
|
|
|
FTexture *operator() (FTextureID texnum)
|
|
|
|
{
|
|
|
|
if ((size_t)texnum.texnum >= Textures.Size()) return NULL;
|
|
|
|
return Textures[Translation[texnum.texnum]].Texture;
|
|
|
|
}
|
|
|
|
FTexture *operator() (const char *texname)
|
|
|
|
{
|
|
|
|
FTextureID texnum = GetTexture (texname, FTexture::TEX_MiscPatch);
|
|
|
|
if (texnum.texnum==-1) return NULL;
|
|
|
|
return Textures[Translation[texnum.texnum]].Texture;
|
|
|
|
}
|
|
|
|
|
2009-10-18 14:08:32 +00:00
|
|
|
FTexture *ByIndexTranslated(int i)
|
|
|
|
{
|
|
|
|
if (unsigned(i) >= Textures.Size()) return NULL;
|
|
|
|
return Textures[Translation[i]].Texture;
|
|
|
|
}
|
|
|
|
|
2008-06-15 18:36:26 +00:00
|
|
|
void SetTranslation (FTextureID fromtexnum, FTextureID totexnum)
|
|
|
|
{
|
|
|
|
if ((size_t)fromtexnum.texnum < Translation.Size())
|
|
|
|
{
|
|
|
|
if ((size_t)totexnum.texnum >= Textures.Size())
|
|
|
|
{
|
|
|
|
totexnum.texnum = fromtexnum.texnum;
|
|
|
|
}
|
|
|
|
Translation[fromtexnum.texnum] = totexnum.texnum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
TEXMAN_TryAny = 1,
|
|
|
|
TEXMAN_Overridable = 2,
|
|
|
|
TEXMAN_ReturnFirst = 4,
|
|
|
|
};
|
|
|
|
|
|
|
|
FTextureID CheckForTexture (const char *name, int usetype, BITFIELD flags=TEXMAN_TryAny);
|
|
|
|
FTextureID GetTexture (const char *name, int usetype, BITFIELD flags=0);
|
2008-11-30 12:49:27 +00:00
|
|
|
FTextureID FindTextureByLumpNum (int lumpnum);
|
2008-06-15 18:36:26 +00:00
|
|
|
int ListTextures (const char *name, TArray<FTextureID> &list);
|
|
|
|
|
|
|
|
void AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup=0, bool texture1=false);
|
|
|
|
void AddTexturesLumps (int lump1, int lump2, int patcheslump);
|
2009-04-23 22:49:38 +00:00
|
|
|
void AddGroup(int wadnum, int ns, int usetype);
|
2008-06-15 18:36:26 +00:00
|
|
|
void AddPatches (int lumpnum);
|
|
|
|
void AddTiles (void *tileFile);
|
|
|
|
void AddHiresTextures (int wadnum);
|
|
|
|
void LoadTextureDefs(int wadnum, const char *lumpname);
|
|
|
|
void ParseXTexture(FScanner &sc, int usetype);
|
|
|
|
void SortTexturesByType(int start, int end);
|
2009-06-14 13:47:38 +00:00
|
|
|
bool AreTexturesCompatible (FTextureID picnum1, FTextureID picnum2);
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
FTextureID CreateTexture (int lumpnum, int usetype=FTexture::TEX_Any); // Also calls AddTexture
|
|
|
|
FTextureID AddTexture (FTexture *texture);
|
2009-05-02 09:14:01 +00:00
|
|
|
FTextureID GetDefaultTexture() const { return DefaultTexture; }
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|
|
|
void LoadTextureX(int wadnum);
|
|
|
|
void AddTexturesForWad(int wadnum);
|
|
|
|
void Init();
|
|
|
|
|
|
|
|
// Replaces one texture with another. The new texture will be assigned
|
|
|
|
// the same name, slot, and use type as the texture it is replacing.
|
|
|
|
// The old texture will no longer be managed. Set free true if you want
|
|
|
|
// the old texture to be deleted or set it false if you want it to
|
|
|
|
// be left alone in memory. You will still need to delete it at some
|
|
|
|
// point, because the texture manager no longer knows about it.
|
|
|
|
// This function can be used for such things as warping textures.
|
|
|
|
void ReplaceTexture (FTextureID picnum, FTexture *newtexture, bool free);
|
|
|
|
|
|
|
|
void UnloadAll ();
|
|
|
|
|
|
|
|
int NumTextures () const { return (int)Textures.Size(); }
|
|
|
|
|
|
|
|
void WriteTexture (FArchive &arc, int picnum);
|
|
|
|
int ReadTexture (FArchive &arc);
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
struct TextureHash
|
|
|
|
{
|
|
|
|
FTexture *Texture;
|
|
|
|
int HashNext;
|
|
|
|
};
|
|
|
|
enum { HASH_END = -1, HASH_SIZE = 1027 };
|
|
|
|
TArray<TextureHash> Textures;
|
|
|
|
TArray<int> Translation;
|
|
|
|
int HashFirst[HASH_SIZE];
|
|
|
|
FTextureID DefaultTexture;
|
2009-06-14 13:47:38 +00:00
|
|
|
TArray<int> FirstTextureForFile;
|
2008-06-15 18:36:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
extern FTextureManager TexMan;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|