2019-10-05 17:28:05 +00:00
/*
* * textures . h
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2005 - 2016 Randy Heit
2019-10-12 20:49:46 +00:00
* * Copyright 2005 - 2019 Christoph Oelckers
2019-10-05 17:28:05 +00:00
* * 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 .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
# ifndef __TEXTURES_H
# define __TEXTURES_H
2019-10-14 21:11:01 +00:00
# include "compat.h"
2019-10-05 17:28:05 +00:00
# include "textureid.h"
2019-10-05 19:59:03 +00:00
# include "zstring.h"
2019-10-12 20:49:46 +00:00
# include "tarray.h"
2019-10-05 17:28:05 +00:00
# include "palentry.h"
class FImageSource ;
2019-10-12 20:49:46 +00:00
// picanm[].sf:
// |bit(1<<7)
// |animtype|animtype|texhitscan|nofullbright|speed|speed|speed|speed|
enum AnimFlags
{
PICANM_ANIMTYPE_NONE = 0 ,
PICANM_ANIMTYPE_OSC = ( 1 < < 6 ) ,
PICANM_ANIMTYPE_FWD = ( 2 < < 6 ) ,
PICANM_ANIMTYPE_BACK = ( 3 < < 6 ) ,
PICANM_ANIMTYPE_SHIFT = 6 ,
PICANM_ANIMTYPE_MASK = ( 3 < < 6 ) , // must be 192
PICANM_MISC_MASK = ( 3 < < 4 ) ,
PICANM_TEXHITSCAN_BIT = ( 2 < < 4 ) ,
PICANM_NOFULLBRIGHT_BIT = ( 1 < < 4 ) ,
PICANM_ANIMSPEED_MASK = 15 , // must be 15
} ;
2019-10-05 17:28:05 +00:00
enum ECreateTexBufferFlags
{
CTF_CheckHires = 1 , // use external hires replacement if found
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.
} ;
2019-10-14 21:11:01 +00:00
enum
2019-10-12 06:54:06 +00:00
{
2019-10-14 22:54:14 +00:00
MAXCACHE1DSIZE = ( 50 * 1024 * 1024 ) ,
2019-10-14 21:11:01 +00:00
MAXTILES = 30720 ,
MAXUSERTILES = ( MAXTILES - 16 ) // reserve 16 tiles at the end
2019-10-12 06:54:06 +00:00
} ;
2019-10-05 17:28:05 +00:00
2019-10-12 20:49:46 +00:00
// NOTE: If the layout of this struct is changed, loadpics() must be modified
// accordingly.
struct picanm_t
{
uint8_t num ; // animate number
int8_t xofs , yofs ;
uint8_t sf ; // anim. speed and flags
uint8_t extra ;
void Clear ( )
{
extra = sf = yofs = xofs = num = 0 ;
}
} ;
struct rottile_t
{
int16_t newtile ;
int16_t owner ;
} ;
2019-10-05 17:28:05 +00:00
class FBitmap ;
struct FRemapTable ;
struct FCopyInfo ;
class FScanner ;
// Texture IDs
class FTextureManager ;
class FTerrainTypeArray ;
class IHardwareTexture ;
class FMaterial ;
class FMultipatchTextureBuilder ;
extern int r_spriteadjustSW , r_spriteadjustHW ;
2019-10-12 20:49:46 +00:00
picanm_t tileConvertAnimFormat ( int32_t const picanmdisk ) ;
2019-10-05 17:28:05 +00:00
class FNullTextureID : public FTextureID
{
public :
FNullTextureID ( ) : FTextureID ( 0 ) { }
} ;
class FGLRenderState ;
class FSerializer ;
namespace OpenGLRenderer
{
class FGLRenderState ;
class FHardwareTexture ;
}
union FContentIdBuilder
{
uint64_t id ;
struct
{
unsigned imageID : 24 ;
unsigned translation : 16 ;
unsigned expand : 1 ;
unsigned scaler : 4 ;
unsigned scalefactor : 4 ;
} ;
} ;
struct FTextureBuffer
{
uint8_t * mBuffer = nullptr ;
int mWidth = 0 ;
int mHeight = 0 ;
uint64_t mContentId = 0 ; // unique content identifier. (Two images created from the same image source with the same settings will return the same value.)
FTextureBuffer ( ) = default ;
~ FTextureBuffer ( )
{
if ( mBuffer ) delete [ ] mBuffer ;
}
FTextureBuffer ( const FTextureBuffer & other ) = delete ;
FTextureBuffer ( FTextureBuffer & & other )
{
mBuffer = other . mBuffer ;
mWidth = other . mWidth ;
mHeight = other . mHeight ;
mContentId = other . mContentId ;
other . mBuffer = nullptr ;
}
FTextureBuffer & operator = ( FTextureBuffer & & other )
{
mBuffer = other . mBuffer ;
mWidth = other . mWidth ;
mHeight = other . mHeight ;
mContentId = other . mContentId ;
other . mBuffer = nullptr ;
return * this ;
}
} ;
// Base texture class
class FTexture
{
2019-10-14 21:11:01 +00:00
friend struct BuildFiles ;
friend bool tileLoad ( int tileNum ) ;
friend const uint8_t * tilePtr ( int num ) ;
2019-10-05 17:28:05 +00:00
public :
2019-10-12 20:49:46 +00:00
enum UseType : uint8_t
{
Image , // anything that is not a regular tile.
Art , // from an ART file, readonly
Writable , // A writable texture
Restorable , // a writable copy of something else
User // A texture with user-provided image content
} ;
2019-10-05 17:28:05 +00:00
static FTexture * CreateTexture ( const char * name ) ;
2019-10-05 19:59:03 +00:00
static FTexture * GetTexture ( const char * path ) ;
2019-10-05 17:28:05 +00:00
virtual ~ FTexture ( ) ;
virtual FImageSource * GetImage ( ) const { return nullptr ; }
const FString & GetName ( ) const { return Name ; }
bool isMasked ( ) const { return bMasked ; }
bool isTranslucent ( ) const { return bMasked ; }
PalEntry GetSkyCapColor ( bool bottom ) ;
// Returns the whole texture, stored in column-major order
2019-10-11 17:21:36 +00:00
virtual void Create8BitPixels ( uint8_t * buffer ) ;
virtual const uint8_t * Get8BitPixels ( ) ;
2019-10-12 06:54:06 +00:00
virtual uint8_t * GetWritableBuffer ( ) { return nullptr ; } // For dynamic tiles. Requesting this must also invalidate the texture.
2019-10-05 17:28:05 +00:00
virtual FBitmap GetBgraBitmap ( PalEntry * remap , int * trans = nullptr ) ;
static int SmoothEdges ( unsigned char * buffer , int w , int h ) ;
static PalEntry averageColor ( const uint32_t * data , int size , int maxout ) ;
2019-10-12 20:49:46 +00:00
int GetWidth ( ) const { return Size . x ; }
int GetHeight ( ) const { return Size . y ; }
2019-10-14 21:11:01 +00:00
const vec2_16_t & GetSize ( ) const { return Size ; }
2019-10-12 20:49:46 +00:00
const uint8_t & GetPicSize ( ) const { return PicSize ; }
int GetLeftOffset ( ) const { return PicAnim . xofs ; }
int GetTopOffset ( ) const { return PicAnim . yofs ; }
picanm_t & GetAnim ( ) { return PicAnim ; } // This must be modifiable. There's quite a bit of code messing around with the flags in here.
2019-10-14 21:11:01 +00:00
rottile_t & GetRotTile ( ) { return RotTile ; }
2019-10-05 17:28:05 +00:00
FTextureBuffer CreateTexBuffer ( int translation , int flags = 0 ) ;
bool GetTranslucency ( ) ;
void CheckTrans ( unsigned char * buffer , int size , int trans ) ;
bool ProcessData ( unsigned char * buffer , int w , int h , bool ispatch ) ;
2019-10-12 20:49:46 +00:00
virtual void Reload ( ) { }
2019-10-14 21:11:01 +00:00
UseType GetUseType ( ) const { return useType ; }
int alphaThreshold = 128 ;
picanm_t PicAnim = { } ;
2019-10-05 17:28:05 +00:00
protected :
void CopySize ( FTexture * BaseTexture )
{
2019-10-12 06:54:06 +00:00
Size . x = BaseTexture - > GetWidth ( ) ;
Size . y = BaseTexture - > GetHeight ( ) ;
2019-10-12 20:49:46 +00:00
PicAnim . xofs = BaseTexture - > PicAnim . xofs ;
PicAnim . yofs = BaseTexture - > PicAnim . yofs ;
UpdatePicSize ( ) ;
2019-10-05 17:28:05 +00:00
}
2019-10-12 06:54:06 +00:00
void SetSize ( int w , int h )
{
Size = { int16_t ( w ) , int16_t ( h ) } ;
2019-10-12 20:49:46 +00:00
UpdatePicSize ( ) ;
}
void UpdatePicSize ( )
{
int j = 15 ;
while ( ( j > 1 ) & & ( ( 1 < < j ) > Size . x ) )
j - - ;
2019-10-15 18:02:37 +00:00
PicSize = j ;
2019-10-12 20:49:46 +00:00
j = 15 ;
while ( ( j > 1 ) & & ( ( 1 < < j ) > Size . y ) )
j - - ;
PicSize | = j < < 4 ;
2019-10-12 06:54:06 +00:00
}
2019-10-12 20:49:46 +00:00
2019-10-05 17:28:05 +00:00
FString Name ;
2019-10-14 21:11:01 +00:00
vec2_16_t Size = { 0 , 0 } ; // Keep this in the native format so that we can use it without copying it around.
2019-10-12 20:49:46 +00:00
rottile_t RotTile = { - 1 , - 1 } ;
2019-10-05 17:28:05 +00:00
uint8_t bMasked = true ; // Texture (might) have holes
int8_t bTranslucent = - 1 ; // Does this texture have an active alpha channel?
bool skyColorDone = false ;
2019-10-15 18:02:37 +00:00
uint8_t PicSize = 0 ; // A special piece of Build weirdness.
2019-10-12 20:49:46 +00:00
UseType useType = Image ;
2019-10-05 17:28:05 +00:00
PalEntry FloorSkyColor ;
PalEntry CeilingSkyColor ;
2019-10-14 21:11:01 +00:00
intptr_t CacheHandle = 0 ; // For tiles that do not have a static image but get accessed by the software renderer.
uint8_t CacheLock = 0 ;
2019-10-05 17:28:05 +00:00
FTexture ( const char * name = NULL ) ;
2019-10-05 19:59:03 +00:00
} ;
2019-10-05 17:28:05 +00:00
2019-10-12 06:54:06 +00:00
class FTileTexture : public FTexture
{
public :
2019-10-12 20:49:46 +00:00
FTileTexture ( )
{
useType = Art ;
}
2019-10-12 06:54:06 +00:00
void SetName ( const char * name ) { Name = name ; }
FBitmap GetBgraBitmap ( PalEntry * remap , int * ptrans ) override ;
void Create8BitPixels ( uint8_t * buffer ) override ;
2019-10-12 20:49:46 +00:00
} ;
//==========================================================================
//
// A tile coming from an ART file.
//
//==========================================================================
class FArtTile : public FTileTexture
{
const TArray < uint8_t > & RawPixels ;
const uint32_t Offset ;
public :
FArtTile ( const TArray < uint8_t > & backingstore , uint32_t offset , int width , int height , int picanm )
: RawPixels ( backingstore ) , Offset ( offset )
{
SetSize ( width , height ) ;
PicAnim = tileConvertAnimFormat ( picanm ) ;
}
const uint8_t * Get8BitPixels ( ) override
{
return RawPixels . Data ( ) ? RawPixels . Data ( ) + Offset : nullptr ;
}
2019-10-12 06:54:06 +00:00
} ;
2019-10-14 21:11:01 +00:00
//==========================================================================
//
// A tile with its own pixel buffer
//
//==========================================================================
class FLooseTile : public FTileTexture
{
TArray < uint8_t > RawPixels ;
public :
FLooseTile ( TArray < uint8_t > & store , int width , int height )
{
useType = Art ; // Whatever this was before - now it's a tile!
RawPixels = std : : move ( store ) ;
SetSize ( width , height ) ;
}
const uint8_t * Get8BitPixels ( ) override
{
return RawPixels . Data ( ) ;
}
} ;
//==========================================================================
//
2019-10-16 18:39:59 +00:00
// A non-existent tile
2019-10-14 21:11:01 +00:00
//
//==========================================================================
class FDummyTile : public FTileTexture
{
public :
FDummyTile ( int width , int height )
{
useType = Art ;
SetSize ( width , height ) ;
}
const uint8_t * Get8BitPixels ( ) override
{
2019-10-16 18:39:59 +00:00
return NULL ;
2019-10-14 21:11:01 +00:00
}
} ;
2019-10-12 20:49:46 +00:00
//==========================================================================
//
// A tile with a writable surface
//
//==========================================================================
class FWritableTile : public FTileTexture
{
protected :
TArray < uint8_t > buffer ;
public :
2019-10-14 21:11:01 +00:00
FWritableTile ( )
2019-10-12 20:49:46 +00:00
{
useType = Writable ;
}
const uint8_t * Get8BitPixels ( ) override
{
return buffer . Data ( ) ;
}
2019-10-14 21:11:01 +00:00
uint8_t * GetWritableBuffer ( ) override
2019-10-12 20:49:46 +00:00
{
2019-10-14 21:11:01 +00:00
// Todo: Invalidate all hardware textures depending on this.
return buffer . Data ( ) ;
}
bool Resize ( int w , int h )
{
if ( w < = 0 | | h < = 0 )
2019-10-12 20:49:46 +00:00
{
buffer . Reset ( ) ;
2019-10-14 21:11:01 +00:00
return false ;
2019-10-12 20:49:46 +00:00
}
else
{
SetSize ( w , h ) ;
buffer . Resize ( w * h ) ;
2019-10-14 21:11:01 +00:00
return true ;
2019-10-12 20:49:46 +00:00
}
}
} ;
//==========================================================================
//
// A tile with a writable surface
//
//==========================================================================
class FRestorableTile : public FWritableTile
{
FTexture * Base ;
public :
FRestorableTile ( FTexture * base )
{
useType = Restorable ;
Base = base ;
CopySize ( base ) ;
2019-10-14 21:11:01 +00:00
Resize ( GetWidth ( ) , GetHeight ( ) ) ;
2019-10-12 20:49:46 +00:00
Reload ( ) ;
}
void Reload ( ) override
{
Base - > Create8BitPixels ( buffer . Data ( ) ) ;
}
} ;
//==========================================================================
//
// One ART file.
//
//==========================================================================
struct BuildArtFile
{
FString filename ;
TArray < uint8_t > RawData ;
BuildArtFile ( ) = default ;
BuildArtFile ( const BuildArtFile & ) = delete ;
BuildArtFile & operator = ( const BuildArtFile & ) = delete ;
BuildArtFile ( const BuildArtFile & & other )
{
filename = std : : move ( other . filename ) ;
RawData = std : : move ( other . RawData ) ;
}
BuildArtFile & operator = ( const BuildArtFile & & other )
{
filename = std : : move ( other . filename ) ;
RawData = std : : move ( other . RawData ) ;
}
} ;
//==========================================================================
//
// THe tile container
//
//==========================================================================
struct BuildFiles
{
2019-10-14 21:11:01 +00:00
FTexture * Placeholder ;
TDeletingArray < BuildArtFile * > ArtFiles ;
TDeletingArray < BuildArtFile * > PerMapArtFiles ;
TDeletingArray < FTexture * > AllTiles ; // This is for deleting tiles when shutting down.
TDeletingArray < FTexture * > AllMapTiles ; // Same for map tiles;
FTexture * tiles [ MAXTILES ] ;
FTexture * tilesbak [ MAXTILES ] ;
BuildFiles ( )
{
Placeholder = new FDummyTile ( 0 , 0 ) ;
for ( auto & tile : tiles ) tile = Placeholder ;
for ( auto & tile : tilesbak ) tile = Placeholder ;
}
~ BuildFiles ( )
{
delete Placeholder ;
}
2019-10-15 21:56:29 +00:00
void CloseAll ( )
{
CloseAllMapArt ( ) ;
ArtFiles . DeleteAndClear ( ) ;
AllTiles . DeleteAndClear ( ) ;
delete Placeholder ;
Placeholder = nullptr ;
}
2019-10-14 21:11:01 +00:00
void AddTile ( int tilenum , FTexture * tex , bool permap = false ) ;
void AddTiles ( int firsttile , TArray < uint8_t > & store , bool permap ) ;
2019-10-15 21:56:29 +00:00
void AddFile ( BuildArtFile * bfd , bool permap )
2019-10-12 20:49:46 +00:00
{
2019-10-14 21:11:01 +00:00
if ( ! permap ) ArtFiles . Push ( bfd ) ;
else PerMapArtFiles . Push ( bfd ) ;
2019-10-12 20:49:46 +00:00
}
int FindFile ( const FString & filename )
{
2019-10-14 21:11:01 +00:00
return ArtFiles . FindEx ( [ filename ] ( const BuildArtFile * element ) { return filename . CompareNoCase ( element - > filename ) = = 0 ; } ) ;
2019-10-12 20:49:46 +00:00
}
2019-10-15 18:02:37 +00:00
int LoadArtFile ( const char * file , bool mapart = false , int firsttile = - 1 ) ;
2019-10-12 20:49:46 +00:00
void CloseAllMapArt ( ) ;
void LoadArtSet ( const char * filename ) ;
2019-10-14 21:11:01 +00:00
FTexture * ValidateCustomTile ( int tilenum , int type ) ;
2019-10-15 18:02:37 +00:00
int32_t artLoadFiles ( const char * filename ) ;
2019-10-15 21:56:29 +00:00
uint8_t * tileMakeWritable ( int num ) ;
uint8_t * tileCreate ( int tilenum , int width , int height ) ;
2019-10-14 22:19:31 +00:00
void tileSetExternal ( int tilenum , int width , int height , uint8_t * data ) ;
2019-10-15 21:56:29 +00:00
int findUnusedTile ( void ) ;
int tileCreateRotated ( int owner ) ;
2019-10-12 20:49:46 +00:00
} ;
2019-10-15 21:38:01 +00:00
int tileCRC ( int tileNum ) ;
int tileImportFromTexture ( const char * fn , int tilenum , int alphacut , int istexture ) ;
void tileCopy ( int tile , int tempsource , int temppal , int xoffset , int yoffset , int flags ) ;
2019-10-15 21:29:47 +00:00
void tileSetDummy ( int tile , int width , int height ) ;
void tileDelete ( int tile ) ;
2019-10-15 21:56:29 +00:00
bool tileLoad ( int tileNum ) ;
void artClearMapArt ( void ) ;
void artSetupMapArt ( const char * filename ) ;
void tileSetAnim ( int tile , const picanm_t & anm ) ;
2019-10-12 20:49:46 +00:00
extern BuildFiles TileFiles ;
2019-10-15 21:18:52 +00:00
inline bool tileCheck ( int num )
{
auto tex = TileFiles . tiles [ num ] ;
return tex - > GetWidth ( ) > 0 & & tex - > GetHeight ( ) > 0 ;
}
2019-10-12 20:49:46 +00:00
2019-10-15 21:56:29 +00:00
inline const uint8_t * tilePtr ( int num )
{
auto tex = TileFiles . tiles [ num ] ;
auto p = tex - > Get8BitPixels ( ) ;
if ( p ) return p ;
return ( const uint8_t * ) tex - > CacheHandle ;
}
inline uint8_t * tileData ( int num )
{
auto tex = TileFiles . tiles [ num ] ;
return tex - > GetWritableBuffer ( ) ;
}
2019-10-16 18:39:59 +00:00
// Some hacks to allow accessing the no lpnger existing arrays as if they still were arrays to avoid changing hundreds of lines of code.
struct TileSiz
{
const vec2_16_t & operator [ ] ( size_t index )
{
assert ( index < MAXTILES ) ;
return TileFiles . tiles [ index ] - > GetSize ( ) ;
}
} ;
extern TileSiz tilesiz ;
struct PicAnm
{
picanm_t & operator [ ] ( size_t index )
{
assert ( index < MAXTILES ) ;
return TileFiles . tiles [ index ] - > GetAnim ( ) ;
}
} ;
extern PicAnm picanm ;
struct PicSiz
{
uint8_t operator [ ] ( size_t index )
{
assert ( index < MAXTILES ) ;
return TileFiles . tiles [ index ] - > GetPicSize ( ) ;
}
} ;
extern PicSiz picsiz ;
2019-10-15 21:56:29 +00:00
inline rottile_t & RotTile ( int tile )
{
2019-10-16 18:39:59 +00:00
assert ( tile < MAXTILES ) ;
2019-10-15 21:56:29 +00:00
return TileFiles . tiles [ tile ] - > GetRotTile ( ) ;
}
2019-10-05 17:28:05 +00:00
# endif