mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-28 12:30:46 +00:00
- link hires replacements to textures instead of tile numbers.
This is needed to connect them to fonts as well because its glyphs have no tile index.
This commit is contained in:
parent
ed599d0f05
commit
873f4d7c0c
7 changed files with 392 additions and 393 deletions
|
@ -999,6 +999,7 @@ set (PCH_SOURCES
|
|||
|
||||
|
||||
core/textures/buildtiles.cpp
|
||||
core/textures/hightile.cpp
|
||||
core/music/s_advsound.cpp
|
||||
|
||||
core/menu/loadsavemenu.cpp
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
#include "palettecontainer.h"
|
||||
#include "mapinfo.h"
|
||||
|
||||
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags);
|
||||
int tileSetSkybox(int picnum, int palnum, const char** facenames, int flags);
|
||||
void tileRemoveReplacement(int num);
|
||||
|
||||
|
||||
int32_t getatoken(scriptfile *sf, const tokenlist *tl, int32_t ntokens)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,8 @@ Ken Silverman's official web site: http://www.advsys.net/ken
|
|||
#include "hw_renderstate.h"
|
||||
#include "printf.h"
|
||||
|
||||
int checkTranslucentReplacement(FTextureID picnum, int pal);
|
||||
|
||||
CVAR(Bool, hw_detailmapping, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, hw_glowmapping, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVARD(Bool, hw_animsmoothing, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable model animation smoothing")
|
||||
|
@ -201,11 +203,7 @@ int32_t polymost_maskWallHasTranslucency(uwalltype const * const wall)
|
|||
if (wall->cstat & CSTAT_WALL_TRANSLUCENT)
|
||||
return true;
|
||||
|
||||
auto tex = tileGetTexture(wall->picnum);
|
||||
auto si = TileFiles.FindReplacement(wall->picnum, wall->pal);
|
||||
if (si && hw_hightile) tex = si->faces[0];
|
||||
if (tex->GetTexelWidth() == 0 || tex->GetTexelHeight() == 0) return false;
|
||||
return tex && tex->GetTranslucency();
|
||||
return checkTranslucentReplacement(tileGetTexture(wall->picnum)->GetID(), wall->pal);
|
||||
}
|
||||
|
||||
int32_t polymost_spriteHasTranslucency(tspritetype const * const tspr)
|
||||
|
@ -214,11 +212,7 @@ int32_t polymost_spriteHasTranslucency(tspritetype const * const tspr)
|
|||
((unsigned)tspr->owner < MAXSPRITES && spriteext[tspr->owner].alpha))
|
||||
return true;
|
||||
|
||||
auto tex = tileGetTexture(tspr->picnum);
|
||||
auto si = TileFiles.FindReplacement(tspr->picnum, tspr->shade, 0);
|
||||
if (si && hw_hightile) tex = si->faces[0];
|
||||
if (tex->GetTexelWidth() == 0 || tex->GetTexelHeight() == 0) return false;
|
||||
return tex && tex->GetTranslucency();
|
||||
return checkTranslucentReplacement(tileGetTexture(tspr->picnum)->GetID(), tspr->pal);
|
||||
}
|
||||
|
||||
int32_t polymost_spriteIsModelOrVoxel(tspritetype const * const tspr)
|
||||
|
|
|
@ -132,6 +132,7 @@ void LoadScripts();
|
|||
void MainLoop();
|
||||
void SetConsoleNotifyBuffer();
|
||||
bool PreBindTexture(FRenderState* state, FGameTexture*& tex, EUpscaleFlags& flags, int& scaleflags, int& clampmode, int& translation, int& overrideshader);
|
||||
void PostLoadSetup();
|
||||
|
||||
DBaseStatusBar* StatusBar;
|
||||
|
||||
|
@ -922,7 +923,7 @@ int RunGame()
|
|||
|
||||
V_LoadTranslations(); // loading the translations must be delayed until the palettes have been fully set up.
|
||||
lookups.postLoadTables();
|
||||
TileFiles.PostLoadSetup();
|
||||
PostLoadSetup();
|
||||
videoInit();
|
||||
|
||||
D_CheckNetGame();
|
||||
|
|
|
@ -50,8 +50,6 @@
|
|||
|
||||
#include "hw_renderstate.h"
|
||||
|
||||
CVARD(Bool, hw_shadeinterpolate, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable shade interpolation")
|
||||
|
||||
enum
|
||||
{
|
||||
MAXARTFILES_BASE = 200,
|
||||
|
@ -61,6 +59,8 @@ enum
|
|||
|
||||
BuildTiles TileFiles;
|
||||
|
||||
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -211,57 +211,6 @@ void BuildTiles::AddTiles (int firsttile, TArray<uint8_t>& RawData, const char *
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Replacement textures
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void BuildTiles::AddReplacement(int picnum, const HightileReplacement& replace)
|
||||
{
|
||||
auto& Hightiles = tiledata[picnum].Hightiles;
|
||||
for (auto& ht : Hightiles)
|
||||
{
|
||||
if (replace.palnum == ht.palnum && (replace.faces[1] == nullptr) == (ht.faces[1] == nullptr))
|
||||
{
|
||||
ht = replace;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Hightiles.Push(replace);
|
||||
}
|
||||
|
||||
void BuildTiles::DeleteReplacement(int picnum, int palnum)
|
||||
{
|
||||
auto& Hightiles = tiledata[picnum].Hightiles;
|
||||
for (int i = Hightiles.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (Hightiles[i].palnum == palnum) Hightiles.Delete(i);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
HightileReplacement* BuildTiles::FindReplacement(int picnum, int palnum, bool skybox)
|
||||
{
|
||||
auto& Hightiles = tiledata[picnum].Hightiles;
|
||||
for (;;)
|
||||
{
|
||||
for (auto& rep : Hightiles)
|
||||
{
|
||||
if (rep.palnum == palnum && (rep.faces[1] != nullptr) == skybox) return &rep;
|
||||
}
|
||||
if (!palnum || palnum >= MAXPALOOKUPS - RESERVEDPALS) break;
|
||||
palnum = 0;
|
||||
}
|
||||
return nullptr; // no replacement found
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// CountTiles
|
||||
|
@ -308,13 +257,6 @@ void BuildTiles::InvalidateTile(int num)
|
|||
{
|
||||
auto tex = tiledata[num].texture;
|
||||
tex->GetTexture()->SystemTextures.Clean();
|
||||
for (auto &rep : tiledata[num].Hightiles)
|
||||
{
|
||||
for (auto &reptex : rep.faces)
|
||||
{
|
||||
if (reptex) reptex->GetTexture()->SystemTextures.Clean();
|
||||
}
|
||||
}
|
||||
tiledata[num].rawCache.data.Clear();
|
||||
}
|
||||
}
|
||||
|
@ -343,8 +285,6 @@ void BuildTiles::MakeCanvas(int tilenum, int width, int height)
|
|||
// Returns the number of tiles found.
|
||||
//
|
||||
// let's load everything into memory on startup.
|
||||
// Even for Ion Fury this will merely add 80 MB, because the engine already needs to cache the data, albeit in a compressed-per-lump form,
|
||||
// so its 100MB art file will only have a partial impact on memory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
|
@ -502,61 +442,6 @@ uint8_t* BuildTiles::tileMakeWritable(int num)
|
|||
return wtex ? wtex->GetRawData() : nullptr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Processes data from .def files into the textures
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void BuildTiles::PostLoadSetup()
|
||||
{
|
||||
SetupReverseTileMap();
|
||||
|
||||
for (auto& tile : tiledata)
|
||||
{
|
||||
FGameTexture* detailTex = nullptr, * glowTex = nullptr, * normalTex = nullptr, *specTex = nullptr;
|
||||
float scalex = 1.f, scaley = 1.f;
|
||||
for (auto& rep : tile.Hightiles)
|
||||
{
|
||||
if (rep.palnum == GLOWPAL)
|
||||
{
|
||||
glowTex = rep.faces[0];
|
||||
}
|
||||
if (rep.palnum == NORMALPAL)
|
||||
{
|
||||
normalTex = rep.faces[0];
|
||||
}
|
||||
if (rep.palnum == SPECULARPAL)
|
||||
{
|
||||
specTex = rep.faces[0];
|
||||
}
|
||||
if (rep.palnum == DETAILPAL)
|
||||
{
|
||||
detailTex = rep.faces[0];
|
||||
scalex = rep.scale.X;
|
||||
scaley = rep.scale.Y;
|
||||
}
|
||||
}
|
||||
if (!detailTex && !glowTex && !normalTex && !specTex) continue; // if there's no layers there's nothing to do.
|
||||
for (auto& rep : tile.Hightiles)
|
||||
{
|
||||
if (rep.faces[1]) continue; // do not muck around with skyboxes (yet)
|
||||
if (rep.palnum < NORMALPAL)
|
||||
{
|
||||
auto tex = rep.faces[0];
|
||||
// Make a copy so that multiple appearances of the same texture can be handled. They will all refer to the same internal texture anyway.
|
||||
tex = MakeGameTexture(tex->GetTexture(), "", ETextureType::Any);
|
||||
if (glowTex) tex->SetGlowmap(glowTex->GetTexture());
|
||||
if (detailTex) tex->SetDetailmap(detailTex->GetTexture());
|
||||
if (normalTex) tex->SetNormalmap(normalTex->GetTexture());
|
||||
if (specTex) tex->SetSpecularmap(specTex->GetTexture());
|
||||
tex->SetDetailScale(scalex, scaley);
|
||||
rep.faces[0] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Returns checksum for a given tile
|
||||
|
@ -702,7 +587,6 @@ void artClearMapArt(void)
|
|||
td.texture = td.backup;
|
||||
td.picanm = td.picanmbackup;
|
||||
}
|
||||
TileFiles.SetupReverseTileMap();
|
||||
currentMapArt = "";
|
||||
}
|
||||
|
||||
|
@ -753,7 +637,6 @@ void artSetupMapArt(const char* filename)
|
|||
FStringf fullname("%s_%02d.art", filename, i);
|
||||
TileFiles.LoadArtFile(fullname, filename);
|
||||
}
|
||||
TileFiles.SetupReverseTileMap();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -764,23 +647,9 @@ void artSetupMapArt(const char* filename)
|
|||
|
||||
void tileDelete(int tile)
|
||||
{
|
||||
TileFiles.TextureToTile.Remove(tileGetTexture(tile));
|
||||
TileFiles.tiledata[tile].texture = TileFiles.tiledata[tile].backup = TexMan.GameByIndex(0);
|
||||
vox_undefine(tile);
|
||||
md_undefinetile(tile);
|
||||
tileRemoveReplacement(tile);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void tileRemoveReplacement(int tile)
|
||||
{
|
||||
if ((unsigned)tile >= MAXTILES) return;
|
||||
TileFiles.DeleteReplacements(tile);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -870,95 +739,6 @@ void BuildTiles::CloseAll()
|
|||
ArtFiles.DeleteAndClear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Specifies a replacement texture for an ART tile.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags)
|
||||
{
|
||||
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
|
||||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
|
||||
auto tex = tileGetTexture(picnum);
|
||||
if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0)
|
||||
{
|
||||
Printf("Warning: defined hightile replacement for empty tile %d.", picnum);
|
||||
return -1; // cannot add replacements to empty tiles, must create one beforehand
|
||||
}
|
||||
HightileReplacement replace = {};
|
||||
|
||||
FTextureID texid = TexMan.CheckForTexture(filename, ETextureType::Any);
|
||||
if (!texid.isValid())
|
||||
{
|
||||
Printf("%s: Replacement for tile %d does not exist or is invalid\n", filename, picnum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
replace.faces[0] = TexMan.GetGameTexture(texid);
|
||||
if (replace.faces[0] == nullptr)
|
||||
replace.alphacut = min(alphacut,1.f);
|
||||
replace.scale = { xscale, yscale };
|
||||
replace.specpower = specpower; // currently unused
|
||||
replace.specfactor = specfactor; // currently unused
|
||||
replace.flags = flags;
|
||||
replace.palnum = (uint16_t)palnum;
|
||||
TileFiles.AddReplacement(picnum, replace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Define the faces of a skybox
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int tileSetSkybox(int picnum, int palnum, const char **facenames, int flags )
|
||||
{
|
||||
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
|
||||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
|
||||
auto tex = tileGetTexture(picnum);
|
||||
if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0)
|
||||
{
|
||||
Printf("Warning: defined skybox replacement for empty tile %d.", picnum);
|
||||
return -1; // cannot add replacements to empty tiles, must create one beforehand
|
||||
}
|
||||
HightileReplacement replace = {};
|
||||
|
||||
for (auto &face : replace.faces)
|
||||
{
|
||||
FTextureID texid = TexMan.CheckForTexture(*facenames, ETextureType::Any);
|
||||
if (!texid.isValid())
|
||||
{
|
||||
Printf("%s: Skybox image for tile %d does not exist or is invalid\n", *facenames, picnum);
|
||||
return -1;
|
||||
}
|
||||
face = TexMan.GetGameTexture(texid);
|
||||
}
|
||||
replace.flags = flags;
|
||||
replace.palnum = (uint16_t)palnum;
|
||||
TileFiles.AddReplacement(picnum, replace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Remove a replacement
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int tileDeleteReplacement(int picnum, int palnum)
|
||||
{
|
||||
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
|
||||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
TileFiles.DeleteReplacement(picnum, palnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Copy a block of a tile.
|
||||
|
@ -1050,78 +830,6 @@ void tileUpdateAnimations()
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Picks a texture for rendering for a given tilenum/palette combination
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
|
||||
bool PickTexture(int picnum, FGameTexture* tex, int paletteid, TexturePick& pick)
|
||||
{
|
||||
if (!tex) tex = tileGetTexture(picnum);
|
||||
if (picnum == -1) picnum = TileFiles.GetTileIndex(tex); // Allow getting replacements also when the texture is not passed by its tile number.
|
||||
|
||||
if (!tex->isValid() || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false;
|
||||
int usepalette = GetTranslationType(paletteid) - Translation_Remap;
|
||||
int usepalswap = GetTranslationIndex(paletteid);
|
||||
int TextureType = hw_int_useindexedcolortextures && picnum >= 0 ? TT_INDEXED : TT_TRUECOLOR;
|
||||
|
||||
pick.translation = paletteid;
|
||||
pick.basepalTint = 0xffffff;
|
||||
|
||||
auto& h = lookups.tables[usepalswap];
|
||||
bool applytint = false;
|
||||
// Canvas textures must be treated like hightile replacements in the following code.
|
||||
if (picnum < 0) picnum = TileFiles.GetTileIndex(tex); // Allow getting replacements also when the texture is not passed by its tile number.
|
||||
auto rep = (picnum >= 0 && hw_hightile && !(h.tintFlags & TINTF_ALWAYSUSEART)) ? TileFiles.FindReplacement(picnum, usepalswap) : nullptr;
|
||||
if (rep || tex->GetTexture()->isHardwareCanvas())
|
||||
{
|
||||
if (usepalette != 0)
|
||||
{
|
||||
// This is a global setting for the entire scene, so let's do it here, right at the start. (Fixme: Store this in a static table instead of reusing the same entry for all palettes.)
|
||||
auto& hh = lookups.tables[MAXPALOOKUPS - 1];
|
||||
// This sets a tinting color for global palettes, e.g. water or slime - only used for hires replacements (also an option for low-resource hardware where duplicating the textures may be problematic.)
|
||||
pick.basepalTint = hh.tintColor;
|
||||
}
|
||||
|
||||
if (rep)
|
||||
{
|
||||
tex = rep->faces[0];
|
||||
}
|
||||
if (!rep || rep->palnum != usepalswap || (h.tintFlags & TINTF_APPLYOVERALTPAL)) applytint = true;
|
||||
pick.translation = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only look up the palette if we really want to use it (i.e. when creating a true color texture of an ART tile.)
|
||||
if (TextureType == TT_TRUECOLOR)
|
||||
{
|
||||
if (h.tintFlags & (TINTF_ALWAYSUSEART | TINTF_USEONART))
|
||||
{
|
||||
applytint = true;
|
||||
if (!(h.tintFlags & TINTF_APPLYOVERPALSWAP)) usepalswap = 0;
|
||||
}
|
||||
pick.translation = TRANSLATION(usepalette + Translation_Remap, usepalswap);
|
||||
}
|
||||
else pick.translation |= 0x80000000;
|
||||
}
|
||||
|
||||
if (applytint && h.tintFlags)
|
||||
{
|
||||
pick.tintFlags = h.tintFlags;
|
||||
pick.tintColor = h.tintColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
pick.tintFlags = -1;
|
||||
pick.tintColor = 0xffffff;
|
||||
}
|
||||
pick.texture = tex;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Parsing stuff for tile data comes below.
|
||||
|
@ -1243,50 +951,3 @@ DEFINE_ACTION_FUNCTION_NATIVE(_TileFiles, GetTexture, GetTexture)
|
|||
#endif
|
||||
|
||||
|
||||
bool PreBindTexture(FRenderState* state, FGameTexture*& tex, EUpscaleFlags& flags, int& scaleflags, int& clampmode, int& translation, int& overrideshader)
|
||||
{
|
||||
TexturePick pick;
|
||||
auto t = tex;
|
||||
|
||||
if (PickTexture(-1, tex, translation, pick))
|
||||
{
|
||||
int TextureType = (pick.translation & 0x80000000) ? TT_INDEXED : TT_TRUECOLOR;
|
||||
int lookuppal = pick.translation & 0x7fffffff;
|
||||
|
||||
if (pick.translation & 0x80000000) scaleflags |= CTF_Indexed;
|
||||
tex = pick.texture;
|
||||
translation = lookuppal;
|
||||
|
||||
FVector4 addcol(0, 0, 0, 0);
|
||||
FVector4 modcol(pick.basepalTint.r * (1.f / 255.f), pick.basepalTint.g * (1.f / 255.f), pick.basepalTint.b * (1.f / 255.f), 1);
|
||||
FVector4 blendcol(0, 0, 0, 0);
|
||||
int flags = 0;
|
||||
|
||||
if (pick.basepalTint != 0xffffff) flags |= TextureManipulation::ActiveBit;
|
||||
if (pick.tintFlags != -1)
|
||||
{
|
||||
flags |= TextureManipulation::ActiveBit;
|
||||
if (pick.tintFlags & TINTF_COLORIZE)
|
||||
{
|
||||
modcol.X *= pick.tintColor.r * (1.f / 64.f);
|
||||
modcol.Y *= pick.tintColor.g * (1.f / 64.f);
|
||||
modcol.Z *= pick.tintColor.b * (1.f / 64.f);
|
||||
}
|
||||
if (pick.tintFlags & TINTF_GRAYSCALE)
|
||||
modcol.W = 1.f;
|
||||
|
||||
if (pick.tintFlags & TINTF_INVERT)
|
||||
flags |= TextureManipulation::InvertBit;
|
||||
|
||||
if (pick.tintFlags & TINTF_BLENDMASK)
|
||||
{
|
||||
blendcol = modcol; // WTF???, but the tinting code really uses the same color for both!
|
||||
flags |= (((pick.tintFlags & TINTF_BLENDMASK) >> 6) + 1) & TextureManipulation::BlendMask;
|
||||
}
|
||||
}
|
||||
addcol.W = flags;
|
||||
if ((pick.translation & 0x80000000) && hw_shadeinterpolate) addcol.W += 16384; // hijack a free bit in here.
|
||||
state->SetTextureColors(&modcol.X, &addcol.X, &blendcol.X);
|
||||
}
|
||||
return tex->GetTexelWidth() > t->GetTexelWidth() && tex->GetTexelHeight() > t->GetTexelHeight(); // returning 'true' means to disable programmatic upscaling.
|
||||
}
|
||||
|
|
|
@ -69,14 +69,6 @@ struct rottile_t
|
|||
int16_t owner;
|
||||
};
|
||||
|
||||
struct HightileReplacement
|
||||
{
|
||||
FGameTexture* faces[6]; // only one gets used by a texture, the other 5 are for skyboxes only
|
||||
FVector2 scale;
|
||||
float alphacut, specpower, specfactor;
|
||||
uint16_t palnum, flags;
|
||||
};
|
||||
|
||||
class FTileTexture : public FImageSource
|
||||
{
|
||||
public:
|
||||
|
@ -272,7 +264,6 @@ struct TileDesc
|
|||
picanm_t picanm; // animation descriptor
|
||||
picanm_t picanmbackup; // animation descriptor backup when using map tiles
|
||||
rottile_t RotTile;// = { -1,-1 };
|
||||
TArray<HightileReplacement> Hightiles;
|
||||
ReplacementType replacement;
|
||||
float alphaThreshold;
|
||||
|
||||
|
@ -297,7 +288,6 @@ struct BuildTiles
|
|||
TDeletingArray<BuildArtFile*> ArtFiles;
|
||||
TileDesc tiledata[MAXTILES];
|
||||
TArray<FString> addedArt;
|
||||
TMap<FGameTexture*, int> TextureToTile;
|
||||
TArray<FString> maptilesadded;
|
||||
|
||||
void Init(); // This cannot be a constructor because it needs the texture manager running.
|
||||
|
@ -335,21 +325,6 @@ struct BuildTiles
|
|||
{
|
||||
addedArt = std::move(art);
|
||||
}
|
||||
int GetTileIndex(FGameTexture* tex)
|
||||
{
|
||||
auto p = TextureToTile.CheckKey(tex);
|
||||
return p ? *p : -1;
|
||||
}
|
||||
|
||||
void SetupReverseTileMap()
|
||||
{
|
||||
TextureToTile.Clear();
|
||||
for (int i = 0; i < MAXTILES; i++)
|
||||
{
|
||||
if (tiledata[i].texture != nullptr && tiledata[i].texture != Placeholder) TextureToTile.Insert(tiledata[i].texture, i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setAnim(int tile, int type, int speed, int frames)
|
||||
{
|
||||
|
@ -367,17 +342,6 @@ struct BuildTiles
|
|||
int tileCreateRotated(int owner);
|
||||
void InvalidateTile(int num);
|
||||
void MakeCanvas(int tilenum, int width, int height);
|
||||
HightileReplacement* FindReplacement(int picnum, int palnum, bool skybox = false);
|
||||
void AddReplacement(int picnum, const HightileReplacement&);
|
||||
void DeleteReplacement(int picnum, int palnum);
|
||||
void DeleteReplacements(int picnum)
|
||||
{
|
||||
assert(picnum < MAXTILES);
|
||||
tiledata[picnum].Hightiles.Clear();
|
||||
}
|
||||
|
||||
void PostLoadSetup();
|
||||
|
||||
};
|
||||
|
||||
int tileGetCRC32(int tileNum);
|
||||
|
@ -385,13 +349,9 @@ int tileImportFromTexture(const char* fn, int tilenum, int alphacut, int istextu
|
|||
void tileCopy(int tile, int tempsource, int temppal, int xoffset, int yoffset, int flags);
|
||||
void tileSetDummy(int tile, int width, int height);
|
||||
void tileDelete(int tile);
|
||||
void tileRemoveReplacement(int tile);
|
||||
bool tileLoad(int tileNum);
|
||||
void artClearMapArt(void);
|
||||
void artSetupMapArt(const char* filename);
|
||||
int tileSetHightileReplacement(int picnum, int palnum, const char *filen, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags);
|
||||
int tileSetSkybox(int picnum, int palnum, const char **facenames, int flags );
|
||||
int tileDeleteReplacement(int picnum, int palnum);
|
||||
void tileCopySection(int tilenum1, int sx1, int sy1, int xsiz, int ysiz, int tilenum2, int sx2, int sy2);
|
||||
|
||||
extern BuildTiles TileFiles;
|
||||
|
@ -505,7 +465,7 @@ inline FGameTexture* tileGetTexture(int tile, bool animate = false)
|
|||
bool tileEqualTo(int me, int other);
|
||||
void tileUpdateAnimations();
|
||||
|
||||
bool PickTexture(int picnum, FGameTexture* tex, int paletteid, TexturePick& pick);
|
||||
bool PickTexture(FGameTexture* tex, int paletteid, TexturePick& pick);
|
||||
|
||||
|
||||
bool ValidateTileRange(const char* cmd, int& begin, int& end, FScriptPosition pos, bool allowswap = true);
|
||||
|
|
378
source/core/textures/hightile.cpp
Normal file
378
source/core/textures/hightile.cpp
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
** hightile.cpp
|
||||
** Handling hires replacement definitions
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 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 "files.h"
|
||||
#include "zstring.h"
|
||||
#include "buildtiles.h"
|
||||
#include "image.h"
|
||||
|
||||
#include "palette.h"
|
||||
#include "m_crc32.h"
|
||||
#include "build.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "texturemanager.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "sc_man.h"
|
||||
#include "gamestruct.h"
|
||||
#include "hw_renderstate.h"
|
||||
|
||||
CVARD(Bool, hw_shadeinterpolate, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable shade interpolation")
|
||||
|
||||
struct HightileReplacement
|
||||
{
|
||||
FGameTexture* faces[6]; // only one gets used by a texture, the other 5 are for skyboxes only
|
||||
FVector2 scale;
|
||||
float alphacut, specpower, specfactor;
|
||||
uint16_t palnum, flags;
|
||||
};
|
||||
|
||||
static TMap<int, TArray<HightileReplacement>> tileReplacements;
|
||||
static TMap<int, TArray<HightileReplacement>> textureReplacements;
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Replacement textures
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static void AddReplacement(int picnum, const HightileReplacement& replace)
|
||||
{
|
||||
auto& Hightiles = tileReplacements[picnum];
|
||||
for (auto& ht : Hightiles)
|
||||
{
|
||||
if (replace.palnum == ht.palnum && (replace.faces[1] == nullptr) == (ht.faces[1] == nullptr))
|
||||
{
|
||||
ht = replace;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Hightiles.Push(replace);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Remove a replacement
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void tileRemoveReplacement(int picnum)
|
||||
{
|
||||
tileReplacements.Remove(picnum);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static HightileReplacement* FindReplacement(FTextureID picnum, int palnum, bool skybox)
|
||||
{
|
||||
auto Hightiles = textureReplacements.CheckKey(picnum.GetIndex());
|
||||
if (!Hightiles) return nullptr;
|
||||
for (;;)
|
||||
{
|
||||
for (auto& rep : *Hightiles)
|
||||
{
|
||||
if (rep.palnum == palnum && (rep.faces[1] != nullptr) == skybox) return &rep;
|
||||
}
|
||||
if (!palnum || palnum >= MAXPALOOKUPS - RESERVEDPALS) break;
|
||||
palnum = 0;
|
||||
}
|
||||
return nullptr; // no replacement found
|
||||
}
|
||||
|
||||
int checkTranslucentReplacement(FTextureID picnum, int pal)
|
||||
{
|
||||
FGameTexture* tex = nullptr;
|
||||
auto si = FindReplacement(picnum, pal, 0);
|
||||
if (si && hw_hightile) tex = si->faces[0];
|
||||
if (!tex || tex->GetTexelWidth() == 0 || tex->GetTexelHeight() == 0) return false;
|
||||
return tex && tex->GetTranslucency();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Processes data from .def files into the textures
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PostLoadSetup()
|
||||
{
|
||||
for(int i=0;i<MAXTILES;i++)
|
||||
{
|
||||
auto tex = tileGetTexture(i);
|
||||
if (!tex->isValid()) continue;
|
||||
auto Hightile = tileReplacements.CheckKey(i);
|
||||
if (!Hightile) continue;
|
||||
|
||||
FGameTexture* detailTex = nullptr, * glowTex = nullptr, * normalTex = nullptr, *specTex = nullptr;
|
||||
float scalex = 1.f, scaley = 1.f;
|
||||
for (auto& rep : *Hightile)
|
||||
{
|
||||
if (rep.palnum == GLOWPAL)
|
||||
{
|
||||
glowTex = rep.faces[0];
|
||||
}
|
||||
if (rep.palnum == NORMALPAL)
|
||||
{
|
||||
normalTex = rep.faces[0];
|
||||
}
|
||||
if (rep.palnum == SPECULARPAL)
|
||||
{
|
||||
specTex = rep.faces[0];
|
||||
}
|
||||
if (rep.palnum == DETAILPAL)
|
||||
{
|
||||
detailTex = rep.faces[0];
|
||||
scalex = rep.scale.X;
|
||||
scaley = rep.scale.Y;
|
||||
}
|
||||
}
|
||||
|
||||
if (detailTex || glowTex || normalTex || specTex)
|
||||
{
|
||||
for (auto& rep : *Hightile)
|
||||
{
|
||||
if (rep.faces[1]) continue; // do not muck around with skyboxes (yet)
|
||||
if (rep.palnum < NORMALPAL)
|
||||
{
|
||||
auto tex = rep.faces[0];
|
||||
// Make a copy so that multiple appearances of the same texture with different layers can be handled. They will all refer to the same internal texture anyway.
|
||||
tex = MakeGameTexture(tex->GetTexture(), "", ETextureType::Any);
|
||||
if (glowTex) tex->SetGlowmap(glowTex->GetTexture());
|
||||
if (detailTex) tex->SetDetailmap(detailTex->GetTexture());
|
||||
if (normalTex) tex->SetNormalmap(normalTex->GetTexture());
|
||||
if (specTex) tex->SetSpecularmap(specTex->GetTexture());
|
||||
tex->SetDetailScale(scalex, scaley);
|
||||
rep.faces[0] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
textureReplacements.Insert(tex->GetID().GetIndex(), std::move(*Hightile));
|
||||
}
|
||||
tileReplacements.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Specifies a replacement texture for an ART tile.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, uint8_t flags)
|
||||
{
|
||||
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
|
||||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
|
||||
auto tex = tileGetTexture(picnum);
|
||||
if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0)
|
||||
{
|
||||
Printf("Warning: defined hightile replacement for empty tile %d.", picnum);
|
||||
return -1; // cannot add replacements to empty tiles, must create one beforehand
|
||||
}
|
||||
HightileReplacement replace = {};
|
||||
|
||||
FTextureID texid = TexMan.CheckForTexture(filename, ETextureType::Any);
|
||||
if (!texid.isValid())
|
||||
{
|
||||
Printf("%s: Replacement for tile %d does not exist or is invalid\n", filename, picnum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
replace.faces[0] = TexMan.GetGameTexture(texid);
|
||||
if (replace.faces[0] == nullptr)
|
||||
replace.alphacut = min(alphacut,1.f);
|
||||
replace.scale = { xscale, yscale };
|
||||
replace.specpower = specpower; // currently unused
|
||||
replace.specfactor = specfactor; // currently unused
|
||||
replace.flags = flags;
|
||||
replace.palnum = (uint16_t)palnum;
|
||||
AddReplacement(picnum, replace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Define the faces of a skybox
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int tileSetSkybox(int picnum, int palnum, const char **facenames, int flags )
|
||||
{
|
||||
if ((uint32_t)picnum >= (uint32_t)MAXTILES) return -1;
|
||||
if ((uint32_t)palnum >= (uint32_t)MAXPALOOKUPS) return -1;
|
||||
|
||||
auto tex = tileGetTexture(picnum);
|
||||
if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0)
|
||||
{
|
||||
Printf("Warning: defined skybox replacement for empty tile %d.", picnum);
|
||||
return -1; // cannot add replacements to empty tiles, must create one beforehand
|
||||
}
|
||||
HightileReplacement replace = {};
|
||||
|
||||
for (auto &face : replace.faces)
|
||||
{
|
||||
FTextureID texid = TexMan.CheckForTexture(*facenames, ETextureType::Any);
|
||||
if (!texid.isValid())
|
||||
{
|
||||
Printf("%s: Skybox image for tile %d does not exist or is invalid\n", *facenames, picnum);
|
||||
return -1;
|
||||
}
|
||||
face = TexMan.GetGameTexture(texid);
|
||||
}
|
||||
replace.flags = flags;
|
||||
replace.palnum = (uint16_t)palnum;
|
||||
AddReplacement(picnum, replace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Picks a texture for rendering for a given tilenum/palette combination
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static bool PickTexture(FGameTexture* tex, int paletteid, TexturePick& pick)
|
||||
{
|
||||
if (!tex->isValid() || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false;
|
||||
int usepalette = GetTranslationType(paletteid) - Translation_Remap;
|
||||
int usepalswap = GetTranslationIndex(paletteid);
|
||||
int TextureType = hw_int_useindexedcolortextures? TT_INDEXED : TT_TRUECOLOR;
|
||||
|
||||
pick.translation = paletteid;
|
||||
pick.basepalTint = 0xffffff;
|
||||
|
||||
auto& h = lookups.tables[usepalswap];
|
||||
bool applytint = false;
|
||||
// Canvas textures must be treated like hightile replacements in the following code.
|
||||
auto rep = (hw_hightile && !(h.tintFlags & TINTF_ALWAYSUSEART)) ? FindReplacement(tex->GetID(), usepalswap, false) : nullptr;
|
||||
if (rep || tex->GetTexture()->isHardwareCanvas())
|
||||
{
|
||||
if (usepalette != 0)
|
||||
{
|
||||
// This is a global setting for the entire scene, so let's do it here, right at the start. (Fixme: Store this in a static table instead of reusing the same entry for all palettes.)
|
||||
auto& hh = lookups.tables[MAXPALOOKUPS - 1];
|
||||
// This sets a tinting color for global palettes, e.g. water or slime - only used for hires replacements (also an option for low-resource hardware where duplicating the textures may be problematic.)
|
||||
pick.basepalTint = hh.tintColor;
|
||||
}
|
||||
|
||||
if (rep)
|
||||
{
|
||||
tex = rep->faces[0];
|
||||
}
|
||||
if (!rep || rep->palnum != usepalswap || (h.tintFlags & TINTF_APPLYOVERALTPAL)) applytint = true;
|
||||
pick.translation = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only look up the palette if we really want to use it (i.e. when creating a true color texture of an ART tile.)
|
||||
if (TextureType == TT_TRUECOLOR)
|
||||
{
|
||||
if (h.tintFlags & (TINTF_ALWAYSUSEART | TINTF_USEONART))
|
||||
{
|
||||
applytint = true;
|
||||
if (!(h.tintFlags & TINTF_APPLYOVERPALSWAP)) usepalswap = 0;
|
||||
}
|
||||
pick.translation = TRANSLATION(usepalette + Translation_Remap, usepalswap);
|
||||
}
|
||||
else pick.translation |= 0x80000000;
|
||||
}
|
||||
|
||||
if (applytint && h.tintFlags)
|
||||
{
|
||||
pick.tintFlags = h.tintFlags;
|
||||
pick.tintColor = h.tintColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
pick.tintFlags = -1;
|
||||
pick.tintColor = 0xffffff;
|
||||
}
|
||||
pick.texture = tex;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PreBindTexture(FRenderState* state, FGameTexture*& tex, EUpscaleFlags& flags, int& scaleflags, int& clampmode, int& translation, int& overrideshader)
|
||||
{
|
||||
TexturePick pick;
|
||||
auto t = tex;
|
||||
|
||||
if (PickTexture(tex, translation, pick))
|
||||
{
|
||||
int TextureType = (pick.translation & 0x80000000) ? TT_INDEXED : TT_TRUECOLOR;
|
||||
int lookuppal = pick.translation & 0x7fffffff;
|
||||
|
||||
if (pick.translation & 0x80000000) scaleflags |= CTF_Indexed;
|
||||
tex = pick.texture;
|
||||
translation = lookuppal;
|
||||
|
||||
FVector4 addcol(0, 0, 0, 0);
|
||||
FVector4 modcol(pick.basepalTint.r * (1.f / 255.f), pick.basepalTint.g * (1.f / 255.f), pick.basepalTint.b * (1.f / 255.f), 1);
|
||||
FVector4 blendcol(0, 0, 0, 0);
|
||||
int flags = 0;
|
||||
|
||||
if (pick.basepalTint != 0xffffff) flags |= TextureManipulation::ActiveBit;
|
||||
if (pick.tintFlags != -1)
|
||||
{
|
||||
flags |= TextureManipulation::ActiveBit;
|
||||
if (pick.tintFlags & TINTF_COLORIZE)
|
||||
{
|
||||
modcol.X *= pick.tintColor.r * (1.f / 64.f);
|
||||
modcol.Y *= pick.tintColor.g * (1.f / 64.f);
|
||||
modcol.Z *= pick.tintColor.b * (1.f / 64.f);
|
||||
}
|
||||
if (pick.tintFlags & TINTF_GRAYSCALE)
|
||||
modcol.W = 1.f;
|
||||
|
||||
if (pick.tintFlags & TINTF_INVERT)
|
||||
flags |= TextureManipulation::InvertBit;
|
||||
|
||||
if (pick.tintFlags & TINTF_BLENDMASK)
|
||||
{
|
||||
blendcol = modcol; // WTF???, but the tinting code really uses the same color for both!
|
||||
flags |= (((pick.tintFlags & TINTF_BLENDMASK) >> 6) + 1) & TextureManipulation::BlendMask;
|
||||
}
|
||||
}
|
||||
addcol.W = flags;
|
||||
if ((pick.translation & 0x80000000) && hw_shadeinterpolate) addcol.W += 16384; // hijack a free bit in here.
|
||||
state->SetTextureColors(&modcol.X, &addcol.X, &blendcol.X);
|
||||
}
|
||||
return tex->GetTexelWidth() > t->GetTexelWidth() && tex->GetTexelHeight() > t->GetTexelHeight(); // returning 'true' means to disable programmatic upscaling.
|
||||
}
|
||||
|
Loading…
Reference in a new issue