- big texture system refactor.

Finally that quickly slapped together BuildTiles class is gone and replaced with something that better integrates with the underlying texture manager
This commit is contained in:
Christoph Oelckers 2022-12-07 17:10:27 +01:00
parent 9a1a90a730
commit 20edd800f9
63 changed files with 1583 additions and 2101 deletions

View file

@ -1220,9 +1220,9 @@ set (PCH_SOURCES
common/scripting/backend/vmbuilder.cpp
common/scripting/backend/codegen.cpp
core/textures/buildtiles.cpp
core/textures/tiletexture.cpp
core/textures/texinfo.cpp
core/textures/tilesetbuilder.cpp
core/textures/skytexture.cpp
core/textures/hightile.cpp
core/music/s_advsound.cpp

View file

@ -17,7 +17,6 @@ static_assert('\xff' == 255, "Char must be unsigned!");
#include "printf.h"
#include "palette.h"
#include "buildtiles.h"
#include "c_cvars.h"
#include "cmdlib.h"

View file

@ -12,6 +12,7 @@
#include "gamefuncs.h"
#include "coreactor.h"
#include "texturemanager.h"
#include "buildtiles.h"
enum { MAXCLIPDIST = 1024 };

View file

@ -186,6 +186,7 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset
// The name matches, so check the texture type
if (usetype == ETextureType::Any)
{
if (flags & TEXMAN_ReturnAll) return FTextureID(i); // user asked to skip all checks, including null textures.
// All NULL textures should actually return 0
if (texUseType == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return 0;
if (texUseType == ETextureType::SkinGraphic && !(flags & TEXMAN_AllowSkins)) return 0;
@ -229,6 +230,7 @@ FTextureID FTextureManager::CheckForTexture (const char *name, ETextureType uset
// Never return the index of NULL textures.
if (firstfound != -1)
{
if (flags & TEXMAN_ReturnAll) return FTextureID(i); // user asked to skip all checks, including null textures.
if (firsttype == ETextureType::Null) return FTextureID(0);
if (firsttype == ETextureType::FirstDefined && !(flags & TEXMAN_ReturnFirst)) return FTextureID(0);
return FTextureID(firstfound);
@ -1601,14 +1603,10 @@ void FTextureManager::SetTranslation(FTextureID fromtexnum, FTextureID totexnum)
//
//-----------------------------------------------------------------------------
void FTextureManager::AddAlias(const char* name, FGameTexture* tex)
void FTextureManager::AddAlias(const char* name, int texindex)
{
FTextureID id = tex->GetID();
if (tex != Textures[id.GetIndex()].Texture)// || !tex->isValid())
{
return; // Whatever got passed in here was not valid, so ignore the alias.
}
aliases.Insert(name, id.GetIndex());
if (texindex < 0 || texindex >= NumTextures()) return; // Whatever got passed in here was not valid, so ignore the alias.
aliases.Insert(name, texindex);
}
void FTextureManager::Listaliases()

View file

@ -100,6 +100,7 @@ public:
TEXMAN_Localize = 64,
TEXMAN_ForceLookup = 128,
TEXMAN_NoAlias = 256,
TEXMAN_ReturnAll = 512,
};
enum
@ -155,7 +156,11 @@ public:
tmanips.Remove(cname);
}
void AddAlias(const char* name, FGameTexture* tex);
void AddAlias(const char* name, int texindex);
void AddAlias(const char* name, FTextureID texindex)
{
AddAlias(name, texindex.GetIndex());
}
private:

View file

@ -45,6 +45,8 @@
#include "types.h"
#include "filesystem.h"
#include "texturemanager.h"
#include "texinfo.h"
#include "buildtiles.h"
extern void LoadActors ();

View file

@ -38,6 +38,7 @@
#include "raze_sound.h"
#include "vm.h"
#include "texturemanager.h"
#include "buildtiles.h"
// Doubly linked ring list of Actors

File diff suppressed because it is too large Load diff

View file

@ -46,6 +46,9 @@
#include "i_system.h"
#include "gamecontrol.h"
#include "coreactor.h"
#include "texinfo.h"
#include "buildtiles.h"
extern TArray<ClusterDef> clusters;
extern TArray<VolumeRecord> volumes;
@ -500,18 +503,18 @@ void FMapInfoParser::ParseTextureFlags()
do
{
sc.MustGetString();
int tile = tileForName(sc.String);
// this must also get null textures and ones not yet loaded.
auto tex = TexMan.CheckForTexture(sc.String, ETextureType::Any, FTextureManager::TEXMAN_ReturnAll | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ForceLookup);
if (tile == -1)
if (!tex.isValid())
{
sc.ScriptMessage("textureflags:Unknown texture name '%s'", sc.String);
}
else
{
TileFiles.tiledata[tile].tileflags |= num;
texExtInfo[tex.GetIndex()].flags |= num;
}
// tileflags |= sc.Number;
} while (sc.CheckString(","));
}
}

View file

@ -82,6 +82,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "findfile.h"
#include "version.h"
#include "hw_material.h"
#include "tiletexture.h"
#include "tilesetbuilder.h"
#include "buildtiles.h"
void LoadHexFont(const char* filename);
@ -629,7 +633,6 @@ int GameMain()
voxClear();
ClearPalManager();
TexMan.DeleteAll();
TileFiles.CloseAll(); // delete the texture data before shutting down graphics.
I_ShutdownGraphics();
if (gi)
{
@ -950,22 +953,32 @@ void GetGames()
//
//==========================================================================
static void InitTextures()
static void InitTextures(TArray<GrpEntry>& usedgroups)
{
voxInit();
TexMan.usefullnames = true;
TexMan.Init();
TexMan.AddTextures([]() {}, [](BuildInfo&) {});
StartWindow->Progress();
TileFiles.Init();
TileFiles.LoadArtSet("tiles%03d.art"); // it's the same for all games.
voxInit();
gi->LoadGameTextures(); // loads game-side data that must be present before processing the .def files.
LoadDefinitions();
TArray<FString> addArt;
for (auto& grp : usedgroups)
{
for (auto& art : grp.FileInfo.loadart)
{
addArt.Push(art);
}
}
if (userConfig.AddArt) for (auto& art : *userConfig.AddArt)
{
addArt.Push(art);
}
InitArtFiles(addArt);
ConstructTileset();
InitFont(); // InitFonts may only be called once all texture data has been initialized.
gi->SetupSpecialTextures(); // For installing dynamic or deleted textures in the texture manager. This must be done after parsing .def and before setting the aliases.
TileFiles.SetAliases();
//TileFiles.SetAliases();
lookups.postLoadTables();
highTileSetup();
@ -1074,20 +1087,6 @@ int RunGame()
StartWindow = FStartupScreen::CreateInstance(8, true);
StartWindow->Progress();
TArray<FString> addArt;
for (auto& grp : usedgroups)
{
for (auto& art : grp.FileInfo.loadart)
{
addArt.Push(art);
}
}
if (userConfig.AddArt) for (auto& art : *userConfig.AddArt)
{
addArt.Push(art);
}
TileFiles.AddArt(addArt);
inputState.ClearAllInput();
if (!GameConfig->IsInitialized())
@ -1108,7 +1107,7 @@ int RunGame()
gi->loadPalette();
BuildFogTable();
StartWindow->Progress();
InitTextures();
InitTextures(usedgroups);
StartWindow->Progress();
I_InitSound();
@ -1419,61 +1418,6 @@ void DrawCrosshair(int deftile, int health, double xdelta, double ydelta, double
ST_DrawCrosshair(health, xpos, ypos, 1, angle);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void LoadDefinitions()
{
const char* defsfile = G_DefFile();
FString razedefsfile = defsfile;
razedefsfile.Substitute(".def", "-raze.def");
loaddefinitionsfile("engine/engine.def", true, true); // Internal stuff that is required.
// check what we have.
// user .defs override the default ones and are not cumulative.
// if we fine even one Raze-specific file, all of those will be loaded cumulatively.
// otherwise the default rules inherited from older ports apply.
if (userConfig.UserDef.IsNotEmpty())
{
loaddefinitionsfile(userConfig.UserDef, false);
}
else
{
if (fileSystem.FileExists(razedefsfile))
{
loaddefinitionsfile(razedefsfile, true);
}
else if (fileSystem.FileExists(defsfile))
{
loaddefinitionsfile(defsfile, false);
}
}
if (userConfig.AddDefs)
{
for (auto& m : *userConfig.AddDefs)
{
loaddefinitionsfile(m, false);
}
userConfig.AddDefs.reset();
}
if (GameStartupInfo.def.IsNotEmpty())
{
loaddefinitionsfile(GameStartupInfo.def); // Stuff from gameinfo.
}
// load the widescreen replacements last. This ensures that mods still get the correct CRCs for their own tile replacements.
if (fileSystem.FindFile("engine/widescreen.def") >= 0 && !Args->CheckParm("-nowidescreen"))
{
loaddefinitionsfile("engine/widescreen.def");
}
fileSystem.InitHashChains(); // make sure that any resources that got added can be found again.
}
bool M_Active()
{

View file

@ -146,9 +146,6 @@ struct GrpEntry
GrpInfo FileInfo;
};
extern int g_gameType;
const char* G_DefaultDefFile(void);
const char* G_DefFile(void);
void LoadDefinitions();
// game check shortcuts
inline bool isNam()

View file

@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "interpolate.h"
#include "texturemanager.h"
#include "hw_voxels.h"
#include "texinfo.h"
#include "buildtiles.h"
IntRect viewport3d;
constexpr double MAXCLIPDISTF = 64;
@ -205,7 +207,7 @@ void GetWallSpritePosition(const spritetypebase* spr, const DVector2& pos, DVect
auto tex = TexMan.GetGameTexture(spr->spritetexture());
double width, xoffset;
TileOffs* tofs;
const TileOffs* tofs;
if (render && hw_hightile && (tofs = GetHiresOffset(spr->spritetexture())))
{
width = tofs->xsize;
@ -245,7 +247,7 @@ void TGetFlatSpritePosition(const spritetypebase* spr, const DVector2& pos, DVec
int xo = heinum ? 0 : spr->xoffset;
int yo = heinum ? 0 : spr->yoffset;
TileOffs* tofs;
const TileOffs* tofs;
if (render && hw_hightile && (tofs = GetHiresOffset(spr->spritetexture())))
{
width = tofs->xsize * xrepeat;

View file

@ -205,8 +205,6 @@ inline void dragpoint(walltype* startwall, const DVector2& pos)
extern double cameradist, cameraclock;
void loaddefinitionsfile(const char* fn, bool cumulative = false, bool maingrp = false);
bool calcChaseCamPos(DVector3& ppos, DCoreActor* pspr, sectortype** psectnum, const DRotator& angles, double const interpfrac, double const backamp);
int getslopeval(sectortype* sect, const DVector3& pos, double bazez);
bool cansee(const DVector3& start, sectortype* sect1, const DVector3& end, sectortype* sect2);

View file

@ -46,6 +46,10 @@
#include "v_font.h"
#include "gamestruct.h"
#include "gamefuncs.h"
#include "texinfo.h"
#include "buildtiles.h"
F2DDrawer twodpsp;
@ -56,9 +60,7 @@ void hud_drawsprite(double sx, double sy, double sz, double a, int picnum, int d
alpha *= (dastat & RS_TRANS1)? glblend[0].def[!!(dastat & RS_TRANS2)].alpha : 1.;
int palid = TRANSLATION(Translation_Remap + curbasepal, dapalnum);
tileUpdatePicnum(&picnum);
auto tex = tileGetTexture(picnum);
auto tex = tileGetTexture(picnum, true);
DrawTexture(&twodpsp, tex, sx, sy,
DTA_ScaleX, sz, DTA_ScaleY, sz,

View file

@ -49,6 +49,7 @@ struct ReservedSpace
enum EMenuSounds : int;
struct MapRecord;
struct TilesetBuildInfo;
extern cycle_t drawtime, actortime, thinktime, gameupdatetime;
@ -71,8 +72,8 @@ struct GameInterface
virtual ~GameInterface() {}
virtual bool GenerateSavePic() { return false; }
virtual void app_init() = 0;
virtual void LoadGameTextures() {}
virtual void SetupSpecialTextures() {}
virtual void LoadTextureInfo(TilesetBuildInfo& info) {}
virtual void SetupSpecialTextures(TilesetBuildInfo&) {}
virtual void loadPalette();
virtual void clearlocalinputstate() {}
virtual void UpdateScreenSize() {}

View file

@ -89,6 +89,7 @@
#include "gamehud.h"
#include "wipe.h"
#include "i_interface.h"
#include "texinfo.h"
#include "texturemanager.h"
CVAR(Bool, vid_activeinbackground, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)

View file

@ -47,6 +47,7 @@
#include "render.h"
#include "hw_sections.h"
#include "interpolate.h"
#include "tiletexture.h"
#include "games/blood/src/mapstructs.h"
extern BitArray clipsectormap;

View file

@ -4,6 +4,7 @@
#include "texturemanager.h"
#include "hw_voxels.h"
#include "gamefuncs.h"
#include "tiletexture.h"
#include "build.h"

View file

@ -45,6 +45,9 @@
#include "mapinfo.h"
#include "models/modeldata.h"
#include "gamefuncs.h"
#include "texinfo.h"
#include "buildtiles.h"
BEGIN_BLD_NS
extern short voxelIndex[MAXTILES];

View file

@ -34,9 +34,10 @@
*/
#include "psky.h"
#include "buildtiles.h"
#include "gamefuncs.h"
#include "tarray.h"
#include "texinfo.h"
#include "buildtiles.h"
static TArray<SkyDefinition> skies;

View file

@ -29,6 +29,7 @@
#include "build.h"
#include "voxels.h"
#include "hw_voxels.h"
#include "tiletexture.h"
#include "gamecontrol.h"
int16_t tiletovox[MAXTILES];

View file

@ -43,6 +43,9 @@
#include "automap.h"
#include "hw_voxels.h"
#include "coreactor.h"
#include "tiletexture.h"
#include "buildtiles.h"
EXTERN_CVAR(Float, r_visibility)
CVAR(Bool, gl_no_skyclear, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -275,23 +278,26 @@ void HWDrawInfo::DispatchSprites()
for (unsigned i = 0; i < tsprites.Size(); i++)
{
auto tspr = tsprites.get(i);
int tilenum = tspr->picnum;
auto actor = tspr->ownerActor;
auto texid = tspr->spritetexture();
if (actor == nullptr || tspr->scale.X == 0 || tspr->scale.Y == 0 || (unsigned)tilenum >= MAXTILES)
if (actor == nullptr || tspr->scale.X == 0 || tspr->scale.Y == 0)
continue;
actor->spr.cstat2 |= CSTAT2_SPRITE_MAPPED;
if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) != CSTAT_SPRITE_ALIGNMENT_SLAB && !(tspr->cstat2 & CSTAT2_SPRITE_NOANIMATE))
tileUpdatePicnum(&tilenum, false, (actor->GetIndex() & 16383));
{
tileUpdatePicnum(texid, (actor->GetIndex() & 16383));
}
if (tspr->cstat2 & CSTAT2_SPRITE_FULLBRIGHT)
tspr->shade = -127;
tspr->picnum = tilenum;
tspr->picnum = legacyTileNum(texid);
int tilenum = tspr->picnum;
if (!(actor->sprext.renderflags & SPREXT_NOTMD))
{
auto pt = modelManager.GetModel(tilenum, tspr->pal);
auto pt = modelManager.GetModel(tspr->picnum, tspr->pal);
if (hw_models && pt && pt->modelid >= 0 && pt->framenum >= 0)
{
//HWSprite hwsprite;
@ -315,6 +321,7 @@ void HWDrawInfo::DispatchSprites()
}
}
}
if (!texid.isValid()) return; // due to CSTAT_SPRITE_ALIGNMENT_SLAB this can only be checked here
if (actor->sprext.renderflags & SPREXT_AWAY1)
{

View file

@ -38,6 +38,7 @@
#include "sectorgeometry.h"
#include "hw_sections.h"
#include "texturemanager.h"
#include "buildtiles.h"
#ifdef _DEBUG
CVAR(Int, gl_breaksec, -1, 0)

View file

@ -31,6 +31,8 @@
#include "cmdlib.h"
#include "psky.h"
#include "buildtiles.h"
CVAR(Bool,gl_noskyboxes, false, 0)
FGameTexture* GetSkyTexture(int basetile, int lognumtiles, const int16_t* tilemap, int remap);
FGameTexture* SkyboxReplacement(FTextureID picnum, int palnum);
@ -45,7 +47,7 @@ void initSkyInfo(HWDrawInfo *di, HWSkyInfo* sky, sectortype* sector, int plane)
{
int picnum = plane == plane_ceiling ? sector->ceilingpicnum : sector->floorpicnum;
auto tex = tileGetTexture(picnum);
tileUpdatePicnum(&picnum);
//tileUpdatePicnum(&picnum); // for now we can make do without this.
int palette = plane == plane_ceiling ? sector->ceilingpal : sector->floorpal;
FGameTexture* skytex = SkyboxReplacement(tex->GetID(), palette);

View file

@ -30,6 +30,7 @@
#include "vectors.h"
#include "texturemanager.h"
#include "basics.h"
#include "texinfo.h"
//#include "hw_models.h"
#include "hw_drawstructs.h"
@ -45,6 +46,7 @@
#include "hw_models.h"
#include "hw_viewpointbuffer.h"
#include "hw_voxels.h"
#include "buildtiles.h"
//==========================================================================
//
@ -345,7 +347,7 @@ void HWSprite::Process(HWDrawInfo* di, tspritetype* spr, sectortype* sector, int
int flags = spr->cstat;
int xsize, ysize, tilexoff, tileyoff;
TileOffs* tofs;
const TileOffs* tofs;
if (hw_hightile && (tofs = GetHiresOffset(spr->spritetexture())))
{

View file

@ -33,8 +33,10 @@
#include "hw_skydome.h"
#include "hw_drawstructs.h"
#include "hw_vertexmap.h"
#include "buildtiles.h"
#include "gamefuncs.h"
#include "cmdlib.h"
#include "texinfo.h"
#include "v_video.h"
#include "flatvertices.h"
@ -1163,7 +1165,7 @@ void HWWall::ProcessWallSprite(HWDrawInfo* di, tspritetype* spr, sectortype* sec
SetSpriteTranslucency(Sprite, alpha, RenderStyle);
TileOffs* tofs;
const TileOffs* tofs;
int height, topofs;
if (hw_hightile && (tofs = GetHiresOffset(spr->spritetexture())))
{

View file

@ -63,8 +63,12 @@
#include "ns.h"
#include "serialize_obj.h"
#include "games/blood/src/mapstructs.h"
#include "texinfo.h"
#include <zlib.h>
#include "buildtiles.h"
void WriteSavePic(FileWriter* file, int width, int height);
bool WriteZip(const char* filename, TArray<FString>& filenames, TArray<FCompressedBuffer>& content);

View file

@ -36,6 +36,7 @@
#include "sectorgeometry.h"
#include "build.h"
#include "buildtiles.h"
#include "gamefuncs.h"
#include "texturemanager.h"
#include "earcut.hpp"

View file

@ -1,820 +0,0 @@
/*
** buildtexture.cpp
** Handling Build textures
**
**---------------------------------------------------------------------------
** Copyright 2019 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 "gamefuncs.h"
#include "palettecontainer.h"
#include "texturemanager.h"
#include "c_dispatch.h"
#include "sc_man.h"
#include "gamestruct.h"
#include "hw_voxels.h"
#include "models/modeldata.h"
#include "hw_renderstate.h"
enum
{
MAXARTFILES_BASE = 200,
MAXARTFILES_TOTAL = 220
};
BuildTiles TileFiles;
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, bool indexed = false);
//==========================================================================
//
//
//
//==========================================================================
picanm_t tileConvertAnimFormat(int32_t const picanimraw, int* lo, int* to)
{
// Unpack a 4 byte packed anim descriptor into something more accessible
picanm_t anm;
anm.num = picanimraw & 63;
*lo = (int8_t)((picanimraw >> 8) & 255);
*to = (int8_t)((picanimraw >> 16) & 255);
anm.sf = ((picanimraw >> 24) & 15) | (picanimraw & 192);
anm.extra = (picanimraw >> 28) & 15;
return anm;
}
//==========================================================================
//
// Base class for Build tile textures
// This needs a few subclasses for different use cases.
//
//==========================================================================
int FTileTexture::CopyPixels(FBitmap* bmp, int conversion)
{
TArray<uint8_t> buffer;
auto ppix = GetRawData();
if (ppix)
{
bmp->CopyPixelData(0, 0, ppix, Width, Height, Height, 1, 0, GPalette.BaseColors);
}
return 0;
}
TArray<uint8_t> FTileTexture::CreatePalettedPixels(int conversion)
{
TArray<uint8_t> buffer(Width * Height, true);
auto p = GetRawData();
if (p) memcpy(buffer.Data(), p, buffer.Size());
else memset(buffer.Data(), 0, buffer.Size());
return buffer;
}
//==========================================================================
//
// raw pixel cache. This is for accessing pixel data in the game code,
// not for rendering.
//
//==========================================================================
struct RawCacheNode
{
TArray<uint8_t> data;
uint64_t lastUseTime;
RawCacheNode() = default;
RawCacheNode(RawCacheNode& other) = default;
RawCacheNode& operator=(RawCacheNode& other) = default;
RawCacheNode(RawCacheNode&& other) noexcept
{
data = std::move(other.data);
lastUseTime = other.lastUseTime;
}
RawCacheNode& operator=(RawCacheNode&& other) noexcept
{
data = std::move(other.data);
lastUseTime = other.lastUseTime;
return *this;
}
};
//==========================================================================
//
//
//
//==========================================================================
static TMap<int, RawCacheNode> CacheNodes;
const uint8_t* GetRawPixels(FTextureID texid)
{
if (!texid.isValid()) return nullptr;
auto gtex = TexMan.GetGameTexture(texid);
auto tex = dynamic_cast<FImageTexture*>(gtex->GetTexture());
if (!tex || !tex->GetImage()) return nullptr;
auto img = tex->GetImage();
auto timg = dynamic_cast<FTileTexture*>(img);
if (!timg || !timg->GetRawData())
{
auto cache = CacheNodes.CheckKey(texid.GetIndex());
if (cache)
{
cache->lastUseTime = I_nsTime();
return cache->data.Data();
}
RawCacheNode newnode;
newnode.data = img->GetPalettedPixels(0);
newnode.lastUseTime = I_nsTime();
auto retval =newnode.data.Data();
CacheNodes.Insert(texid.GetIndex(), std::move(newnode));
return retval;
}
else
{
return timg->GetRawData();
}
}
//==========================================================================
//
//To use this the texture must have been made writable during texture init.
//
//==========================================================================
uint8_t* GetWritablePixels(FTextureID texid)
{
if (!texid.isValid()) return nullptr;
auto gtex = TexMan.GetGameTexture(texid);
auto tex = dynamic_cast<FImageTexture*>(gtex->GetTexture());
if (!tex || !tex->GetImage()) return nullptr;
auto timg = dynamic_cast<FWritableTile*>(tex->GetImage());
if (!timg) return nullptr;
gtex->CleanHardwareData(); // we can safely assume that this only gets called when the texture is about to be changed.
return timg->GetRawData();
}
//==========================================================================
//
//
//
//==========================================================================
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 p = &backingstore[offset];
auto siz = width * height;
for (int i = 0; i < siz; i++, p++)
{
// move transparent color to index 0 to get in line with the rest of the texture management.
if (*p == 0) *p = 255;
else if (*p == 255) *p = 0;
}
if (tex)
{
return MakeGameTexture(new FImageTexture(tex), name, ETextureType::Any);
}
return nullptr;
}
void BuildTiles::Init()
{
Placeholder = TexMan.GameByIndex(0);
tiledata.Resize(MAXTILES);
memset(tiledata.Data(), 0, sizeof(tiledata[0]) * MAXTILES);
for (auto& tile : tiledata)
{
tile.texture = Placeholder;
tile.alphaThreshold = 0.5;
}
}
//==========================================================================
//
//
//
//==========================================================================
void BuildTiles::AddTile(int tilenum, FGameTexture* tex)
{
if (!tex->GetID().isValid())
TexMan.AddGameTexture(tex);
tiledata[tilenum].texture = tex;
}
//===========================================================================
//
// AddTiles
//
// Adds all the tiles in an artfile to the texture manager.
//
//===========================================================================
void BuildTiles::AddTiles (int firsttile, TArray<uint8_t>& RawData, const char *mapname)
{
const uint8_t *tiles = RawData.Data();
// int numtiles = LittleLong(((uint32_t *)tiles)[1]); // This value is not reliable
int tilestart = LittleLong(((int *)tiles)[2]);
int tileend = LittleLong(((int *)tiles)[3]);
const uint16_t *tilesizx = &((const uint16_t *)tiles)[8];
const uint16_t *tilesizy = &tilesizx[tileend - tilestart + 1];
const uint32_t *picanm = (const uint32_t *)&tilesizy[tileend - tilestart + 1];
const uint8_t *tiledata = (const uint8_t *)&picanm[tileend - tilestart + 1];
if (firsttile != -1)
{
tileend = tileend - tilestart + firsttile;
tilestart = firsttile;
}
for (int i = tilestart; i <= tileend; ++i)
{
int pic = i - tilestart;
int width = LittleShort(tilesizx[pic]);
int height = LittleShort(tilesizy[pic]);
uint32_t anm = LittleLong(picanm[pic]);
int size = width*height;
if (width <= 0 || height <= 0) continue;
FString texname;
if (mapname) texname.Format("maptile_%s_%05d", mapname, i);
else texname.Format("#%05d", i);
auto tex = GetTileTexture(texname, RawData, uint32_t(tiledata - tiles), width, height);
AddTile(i, tex);
int leftoffset, topoffset;
this->tiledata[i].picanm = tileConvertAnimFormat(anm, &leftoffset, &topoffset);
tex->SetOffsets(leftoffset, topoffset);
tiledata += size;
}
}
//===========================================================================
//
// CountTiles
//
// Returns the number of tiles provided by an artfile
//
//===========================================================================
int CountTiles (const char *fn, const uint8_t *RawData)
{
int version = LittleLong(*(uint32_t *)RawData);
if (version != 1)
{
Printf("%s: Invalid art file version. Must be 1, got %d\n", fn, version);
return 0;
}
int tilestart = LittleLong(((uint32_t *)RawData)[2]);
int tileend = LittleLong(((uint32_t *)RawData)[3]);
if ((unsigned)tilestart >= MAXUSERTILES || (unsigned)tileend >= MAXUSERTILES)
{
Printf("%s: Invalid tilestart or tileend\n", fn);
return 0;
}
if (tileend < tilestart)
{
Printf("%s: tileend < tilestart\n", fn);
return 0;
}
return tileend >= tilestart ? tileend - tilestart + 1 : 0;
}
//===========================================================================
//
// MakeCanvas
//
// Turns texture into a canvas (i.e. camera texture)
//
//===========================================================================
void BuildTiles::MakeCanvas(int tilenum, int width, int height)
{
auto canvas = ValidateCustomTile(tilenum, ReplacementType::Canvas);
canvas->SetSize(width*4, height*4);
canvas->SetDisplaySize((float)width, (float)height);
canvas->GetTexture()->SetSize(width * 4, height * 4);
static_cast<FCanvasTexture*>(canvas->GetTexture())->aspectRatio = (float)width / height;
}
//===========================================================================
//
// LoadArtFile
//
// Returns the number of tiles found.
//
// let's load everything into memory on startup.
//
//===========================================================================
int BuildTiles::LoadArtFile(const char *fn, const char *mapname, int firsttile)
{
unsigned old = FindFile(fn);
if (old >= ArtFiles.Size()) // Do not process if already loaded.
{
FileReader fr = fileSystem.OpenFileReader(fn);
if (fr.isOpen())
{
auto artdata = fr.Read();
const uint8_t *artptr = artdata.Data();
if (artdata.Size() > 16)
{
if (memcmp(artptr, "BUILDART", 8) == 0)
{
artdata.Delete(0, 8);
}
// Only load the data if the header is present
if (CountTiles(fn, artptr) > 0)
{
auto file = new BuildArtFile;
ArtFiles.Push(file);
file->filename = fn;
file->RawData = std::move(artdata);
AddTiles(firsttile, file->RawData, mapname);
}
}
}
else
{
//Printf("%s: file not found\n", fn);
return -1;
}
}
return 0;
}
//==========================================================================
//
//
//
//==========================================================================
void BuildTiles::LoadArtSet(const char* filename)
{
for (int index = 0; index < MAXARTFILES_BASE; index++)
{
FStringf fn(filename, index);
LoadArtFile(fn, nullptr);
}
for (auto& addart : addedArt)
{
LoadArtFile(addart, nullptr);
}
}
//===========================================================================
//
//
//
//===========================================================================
void BuildTiles::SetAliases()
{
TMap<FName, int>::Iterator it(nametoindex);
TMap<FName, int>::Pair* pair;
while (it.NextPair(pair))
TexMan.AddAlias(pair->Key.GetChars(), tileGetTexture(pair->Value));
}
//==========================================================================
//
// Checks if a custom tile has alredy been added to the list.
// For each tile index there may only be one replacement and its
// type may never change!
//
// All these uses will need some review further down the line so that the texture manager's content is immutable.
//
//==========================================================================
FGameTexture* BuildTiles::ValidateCustomTile(int tilenum, ReplacementType type)
{
if (locked) I_FatalError("Modifying tiles after startup is not allowed.");
if (tilenum < 0 || tilenum >= MAXTILES) return nullptr;
auto &td = tiledata[tilenum];
auto tile = td.texture;
auto reptype = td.replacement;
if (reptype == type) return tile; // already created
if (reptype > ReplacementType::Art) return nullptr; // different custom type - cannot replace again.
FTexture* replacement = nullptr;
td.replacement = type;
if (type == ReplacementType::Writable)
{
// Creates an empty writable tile.
// Current use cases are:
// Blood's 'lens' effect (apparently MP only) - combination of a camera texture with a distortion map - should be made a shader effect to be applied to the camera texture.
replacement = new FImageTexture(new FWritableTile);
}
else if (type == ReplacementType::Restorable)
{
// This is for modifying an existing tile.
// It only gets used for a few specific effects:
// A) the fire in Blood.
// B) the pin display in Redneck Rampage's bowling lanes.
// C) Exhumed's menu plus one special effect tile.
if (tile->GetTexelWidth() == 0 || tile->GetTexelHeight() == 0) return nullptr; // The base must have a size for this to work.
replacement = new FImageTexture(new FRestorableTile(tile->GetTexture()->GetImage()));
}
else if (type == ReplacementType::Canvas)
{
replacement = new FCanvasTexture(1, 1);
}
else return nullptr;
auto rep = MakeGameTexture(replacement, tile->GetName(), ETextureType::Override);
AddTile(tilenum, rep);
return rep;
}
//==========================================================================
//
// Creates a tile for displaying custom content
//
//==========================================================================
uint8_t* BuildTiles::tileCreate(int tilenum, int width, int height)
{
if (width <= 0 || height <= 0) return nullptr;
auto tex = ValidateCustomTile(tilenum, ReplacementType::Writable);
if (tex == nullptr) return nullptr;
auto wtex = static_cast<FWritableTile*>(tex->GetTexture()->GetImage());
if (!wtex->ResizeImage(width, height)) return nullptr;
tex->SetSize(width, height);
return wtex->GetRawData();
}
//==========================================================================
//
// Makes a tile writable - only used for a handful of special cases
// (todo: Investigate how to get rid of this)
//
//==========================================================================
uint8_t* BuildTiles::tileMakeWritable(int num)
{
auto tex = ValidateCustomTile(num, ReplacementType::Restorable);
auto wtex = static_cast<FWritableTile*>(tex->GetTexture()->GetImage());
return wtex ? wtex->GetRawData() : nullptr;
}
//==========================================================================
//
// Returns checksum for a given tile
//
//==========================================================================
int32_t tileGetCRC32(int tileNum)
{
if ((unsigned)tileNum >= (unsigned)MAXTILES) return 0;
auto tile = dynamic_cast<FArtTile*>(TileFiles.tiledata[tileNum].texture->GetTexture()->GetImage()); // only consider original ART tiles.
if (!tile) return 0;
auto pixels = tile->GetRawData();
if (!pixels) return 0;
auto size = tile->GetWidth() * tile->GetHeight();
if (size == 0) return 0;
// Temporarily revert the data to its original form with 255 being transparent. Otherwise the CRC won't match.
auto p = pixels;
for (int i = 0; i < size; i++, p++)
{
// move transparent color to index 0 to get in line with the rest of the texture management.
if (*p == 0) *p = 255;
else if (*p == 255) *p = 0;
}
auto crc = crc32(0, (const Bytef*)pixels, size);
// ... and back again.
p = pixels;
for (int i = 0; i < size; i++, p++)
{
// move transparent color to index 0 to get in line with the rest of the texture management.
if (*p == 0) *p = 255;
else if (*p == 255) *p = 0;
}
return crc;
}
CCMD(tilecrc)
{
if (argv.argc() > 1)
{
int tile = atoi(argv[1]);
Printf("%d\n", tileGetCRC32(tile));
}
}
//==========================================================================
//
// Import a tile from an external image.
// This has been signifcantly altered so it may not cover everything yet.
//
//==========================================================================
int tileImportFromTexture(const char* fn, int tilenum, int alphacut, int istexture)
{
FTextureID texid = TexMan.CheckForTexture(fn, ETextureType::Any, FTextureManager::TEXMAN_ForceLookup);
if (!texid.isValid()) return -1;
auto tex = TexMan.GetGameTexture(texid);
int32_t xsiz = tex->GetTexelWidth(), ysiz = tex->GetTexelHeight();
if (xsiz <= 0 || ysiz <= 0)
return -2;
// create a new game texture here - we want to give it a different name!
tex = MakeGameTexture(tex->GetTexture(), FStringf("#%05d", tilenum), ETextureType::Override);
TileFiles.AddTile(tilenum, tex);
if (istexture)
tileSetHightileReplacement(tilenum, 0, fn, (float)(255 - alphacut) * (1.f / 255.f), 1.0f, 1.0f, 1.0, 1.0);
return 0;
}
//==========================================================================
//
// Copies a tile into another and optionally translates its palette.
//
//==========================================================================
void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags)
{
picanm_t* picanm = nullptr;
picanm_t* sourceanm = nullptr;
int srcxo, srcyo;
FGameTexture* tex;
if (pal == -1 && tile == source)
{
// Only modify the picanm info.
tex = tileGetTexture(tile);
if (!tex) return;
picanm = &TileFiles.tiledata[tile].picanm;
sourceanm = picanm;
srcxo = tex->GetTexelLeftOffset(0);
srcyo = tex->GetTexelTopOffset(0);
}
else
{
if (source == -1) source = tile;
tex = tileGetTexture(source);
if (!tex) return;
sourceanm = &TileFiles.tiledata[source].picanm;
srcxo = tex->GetTexelLeftOffset(0);
srcyo = tex->GetTexelTopOffset(0);
TArray<uint8_t> buffer = tex->GetTexture()->Get8BitPixels(false);
if (pal != -1)
{
auto remap = lookups.getTable(pal);
for (auto& pixel : buffer)
{
pixel = remap[pixel];
}
}
tex = MakeGameTexture(new FImageTexture(new FLooseTile(buffer, tex->GetTexelWidth(), tex->GetTexelHeight())), FStringf("#%05d", tile), ETextureType::Any);
picanm = &TileFiles.tiledata[tile].picanm;
TileFiles.AddTile(tile, tex);
}
if (xoffset != -1024) srcxo = clamp(xoffset, -128, 127);
if (yoffset != -1024) srcyo = clamp(yoffset, -128, 127);
tex->SetOffsets(srcxo, srcyo);
picanm->sf = (picanm->sf & ~PICANM_MISC_MASK) | (sourceanm->sf & PICANM_MISC_MASK) | flags;
}
//==========================================================================
//
//
//
//==========================================================================
FImageSource* CreateEmptyTexture();
void tileDelete(int tile)
{
if (TileFiles.locked)
I_FatalError("Modifying tiles after startup is not allowed.");
// explicitly deleted textures must be unique null textures
auto nulltex = MakeGameTexture(new FImageTexture(CreateEmptyTexture()), FStringf("#%05d", tile), ETextureType::Null);
TileFiles.AddTile(tile, nulltex);
TileFiles.tiledata[tile].replacement = ReplacementType::Art; // whatever this was, now it isn't anymore.
tiletovox[tile] = -1; // clear the link but don't clear the voxel. It may be in use for another tile.
modelManager.UndefineTile(tile);
}
//==========================================================================
//
//
//
//==========================================================================
void tileSetDummy(int tile, int width, int height)
{
if (width == 0 || height == 0)
{
tileDelete(tile);
}
else if (width > 0 && height > 0)
{
FStringf texname("#%05d", tile);
auto dtile = MakeGameTexture(new FImageTexture(new FDummyTile(width, height)), texname, ETextureType::Any);
TileFiles.AddTile(tile, dtile);
}
}
//==========================================================================
//
//
//
//==========================================================================
void BuildTiles::CloseAll()
{
ArtFiles.DeleteAndClear();
}
//==========================================================================
//
// Retrieve animation offset
//
//==========================================================================
int tileAnimateOfs(int tilenum, int randomize)
{
int framecount = picanm[tilenum].num;
if (framecount > 0)
{
int frametime = !isBlood() ? I_GetBuildTime() : PlayClock;
if (isBlood() && randomize)
{
frametime += Bcrc32(&randomize, 2, 0);
}
int curframe = (frametime & 0x7fffffff) >> (picanm[tilenum].speed());
switch (picanm[tilenum].type())
{
case PICANM_ANIMTYPE_FWD:
return curframe % (framecount + 1);
case PICANM_ANIMTYPE_BACK:
return -(curframe % (framecount + 1));
case PICANM_ANIMTYPE_OSC:
curframe = curframe % (framecount << 1);
if (curframe >= framecount) return (framecount << 1) - curframe;
else return curframe;
}
}
return 0;
}
//===========================================================================
//
// Picks a texture for rendering for a given tilenum/palette combination
//
//===========================================================================
void tileUpdateAnimations()
{
for (int i = 0; i < MAXTILES; i++)
{
if (TileFiles.tiledata[i].picanm.type())
{
int j = i + tileAnimateOfs(i);
auto id1 = TileFiles.tiledata[i].texture->GetID();
auto id2 = TileFiles.tiledata[j].texture->GetID();
TexMan.SetTranslation(id1, id2);
}
}
}
//===========================================================================
//
// validates the texture for rendering to a given tilenum
//
//===========================================================================
FCanvasTexture* tileGetCanvas(int tilenum)
{
auto tex = tileGetTexture(tilenum);
if (!tex || !tex->isHardwareCanvas()) return nullptr;
auto canvas = static_cast<FCanvasTexture*>(tex->GetTexture());
if (!canvas) return nullptr;
int xsiz = tex->GetTexelWidth(), ysiz = tex->GetTexelHeight();
if (xsiz <= 0 || ysiz <= 0)
return nullptr;
return canvas;
}
PicAnm picanm;
// wrappers that allow partial migration to a textureID-based setup.
const FTextureID walltype::walltexture() const
{
return tileGetTextureID(wallpicnum);
}
const FTextureID walltype::overtexture() const
{
return tileGetTextureID(overpicnum);
}
const FTextureID sectortype::ceilingtexture() const
{
return tileGetTextureID(ceilingpicnum);
}
const FTextureID sectortype::floortexture() const
{
return tileGetTextureID(floorpicnum);
}
const FTextureID spritetypebase::spritetexture() const
{
return tileGetTextureID(picnum);
}
void sectortype::setfloortexture(FTextureID tex)
{
auto p = TileFiles.textotile.CheckKey(tex.GetIndex());
if (p) floorpicnum = *p;
}
void sectortype::setceilingtexture(FTextureID tex)
{
auto p = TileFiles.textotile.CheckKey(tex.GetIndex());
if (p) ceilingpicnum = *p;
}
void walltype::setwalltexture(FTextureID tex)
{
auto p = TileFiles.textotile.CheckKey(tex.GetIndex());
if (p) wallpicnum = *p;
}
void walltype::setovertexture(FTextureID tex)
{
auto p = TileFiles.textotile.CheckKey(tex.GetIndex());
if (p) overpicnum = *p;
else overpicnum = -1; // unlike the others this one can be invalid.
}
TileOffs* GetHiresOffset(FTextureID tex)
{
// fixme: This must return nullptr if the tile has no replacement.
auto p = TileFiles.textotile.CheckKey(tex.GetIndex());
if (p && TileFiles.tiledata[*p].hiofs.xsize != 0) return &TileFiles.tiledata[*p].hiofs;
else return nullptr;
}

View file

@ -6,432 +6,102 @@
#include "i_time.h"
#include "intvec.h"
#include "name.h"
#include "tiletexture.h"
#include "maptypes.h"
#include "texinfo.h"
#include "texturemanager.h"
enum AnimFlags
// all that's left here is the wrappers that need to go away.
// wrappers that allow partial migration to a textureID-based setup.
inline const FTextureID walltype::walltexture() const
{
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
};
enum
return tileGetTextureID(wallpicnum);
}
inline const FTextureID walltype::overtexture() const
{
MAXTILES = 30720,
MAXUSERTILES = (MAXTILES-16) // reserve 16 tiles at the end
};
enum ETexType
{
TT_INDEXED,
TT_TRUECOLOR,
};
enum class ReplacementType : int
{
Art,
Writable,
Restorable,
Canvas
};
// NOTE: If the layout of this struct is changed, loadpics() must be modified
// accordingly.
struct picanm_t
{
uint16_t num; // animate number
uint8_t sf; // anim. speed and flags
uint8_t extra;
void Clear()
{
extra = sf = 0;
num = 0;
return tileGetTextureID(overpicnum);
}
int speed()
inline const FTextureID sectortype::ceilingtexture() const
{
return sf & PICANM_ANIMSPEED_MASK;
return tileGetTextureID(ceilingpicnum);
}
int type()
inline const FTextureID sectortype::floortexture() const
{
return sf & PICANM_ANIMTYPE_MASK;
return tileGetTextureID(floorpicnum);
}
};
picanm_t tileConvertAnimFormat(int32_t const picanmdisk, int* lo, int* to);
class FTileTexture : public FImageSource
inline const FTextureID spritetypebase::spritetexture() const
{
public:
FTileTexture()
{
bUseGamePalette = true;
bTranslucent = false;
}
virtual uint8_t* GetRawData() = 0;
virtual TArray<uint8_t> CreatePalettedPixels(int conversion);
virtual int CopyPixels(FBitmap* bmp, int conversion); // This will always ignore 'luminance'.
};
//==========================================================================
//
// 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)
: RawPixels(backingstore), Offset(offset)
{
Width = width;
Height = height;
}
uint8_t* GetRawData() override final
{
return &RawPixels[Offset];
}
};
//==========================================================================
//
// 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)
{
RawPixels = std::move(store);
Width = width;
Height = height;
return tileGetTextureID(picnum);
}
uint8_t* GetRawData() override
inline void sectortype::setfloortexture(FTextureID tex)
{
return RawPixels.Data();
floorpicnum = legacyTileNum(tex);
}
};
//==========================================================================
//
// A non-existent tile
//
//==========================================================================
class FDummyTile : public FTileTexture
inline void sectortype::setceilingtexture(FTextureID tex)
{
public:
FDummyTile(int width, int height)
{
Width = width;
Height = height;
ceilingpicnum = legacyTileNum(tex);
}
uint8_t* GetRawData() override
inline void walltype::setwalltexture(FTextureID tex)
{
return nullptr;
}
};
//==========================================================================
//
// A tile with a writable surface
//
//==========================================================================
class FWritableTile : public FTileTexture
{
protected:
TArray<uint8_t> buffer;
public:
FWritableTile()
{
//useType = Writable;
wallpicnum = legacyTileNum(tex);
}
uint8_t* GetRawData() override
inline void walltype::setovertexture(FTextureID tex)
{
return buffer.Data();
if (tex.isValid()) overpicnum = legacyTileNum(tex);
else overpicnum = -1; // unlike the others this one can be invalid.
}
bool ResizeImage(int w, int h)
{
if (w <= 0 || h <= 0)
{
buffer.Reset();
return false;
}
else
{
Width = w;
Height = h;
buffer.Resize(w * h);
return true;
}
}
};
//==========================================================================
//
// A tile with a writable surface
//
//==========================================================================
class FRestorableTile : public FWritableTile
{
FImageSource* Base;
public:
FRestorableTile(FImageSource* base)
{
Base = base;
CopySize(*base);
ResizeImage(Width, Height);
Reload();
}
void Reload()
{
buffer = Base->GetPalettedPixels(0);
}
};
//==========================================================================
//
// 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);
return *this;
}
};
//==========================================================================
//
// THe tile container
//
//==========================================================================
struct TileOffs
{
int xsize, ysize, xoffs, yoffs;
};
struct TileDesc
{
FGameTexture* texture; // the currently active tile
picanm_t picanm; // animation descriptor
ReplacementType replacement;
float alphaThreshold;
int tileflags;
// Sprite offset hackery for hires replacements. This only gets used for sprites in the 3D view, nothing else.
TileOffs hiofs;
};
struct TexturePick
{
FGameTexture* texture; // which texture to use
int translation; // which translation table to use
int tintFlags; // which shader tinting options to use
PalEntry tintColor; // Tint color
PalEntry basepalTint; // can the base palette be done with a global tint effect?
};
struct BuildTiles
{
FGameTexture* Placeholder;
TDeletingArray<BuildArtFile*> ArtFiles;
TArray<TileDesc> tiledata;
TArray<FString> addedArt;
TMap<FName, int> nametoindex;
TMap<int, int> textotile;
bool locked; // if this is true, no more tile modifications are allowed.
void addName(const char* name, int index)
{
nametoindex.Insert(name, index);
}
void lock()
{
locked = true;
// Now we can set up the reverse map.
for (unsigned i = 0; i < MAXTILES; i++)
{
if (tiledata[i].texture != Placeholder)
{
textotile.Insert(tiledata[i].texture->GetID().GetIndex(), i);
}
}
}
void SetAliases();
void Init(); // This cannot be a constructor because it needs the texture manager running.
~BuildTiles()
{
CloseAll();
}
void CloseAll();
void AddTile(int tilenum, FGameTexture* tex);
void AddTiles(int firsttile, TArray<uint8_t>& store, const char* mapname);
void AddFile(BuildArtFile* bfd)
{
ArtFiles.Push(bfd);
}
int FindFile(const FString& filename)
{
return ArtFiles.FindEx([filename](const BuildArtFile* element) { return filename.CompareNoCase(element->filename) == 0; });
}
int LoadArtFile(const char* file, const char* mapname = nullptr, int firsttile = -1);
void LoadArtSet(const char* filename);
void AddArt(TArray<FString>& art)
{
addedArt = std::move(art);
}
void setAnim(int tile, int type, int speed, int frames)
{
auto& anm = tiledata[tile].picanm;
anm.sf &= ~(PICANM_ANIMTYPE_MASK | PICANM_ANIMSPEED_MASK);
anm.sf |= clamp(speed, 0, 15) | (type << PICANM_ANIMTYPE_SHIFT);
anm.num = frames;
}
FGameTexture* ValidateCustomTile(int tilenum, ReplacementType type);
uint8_t* tileMakeWritable(int num);
uint8_t* tileCreate(int tilenum, int width, int height);
void MakeCanvas(int tilenum, int width, int height);
};
int tileGetCRC32(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);
void tileSetDummy(int tile, int width, int height);
void tileDelete(int tile);
extern BuildTiles TileFiles;
//[[deprecated]]
inline int tileForName(const char* name)
{
FName nm(name, true);
if (nm == NAME_None) return -1;
auto nmm = TileFiles.nametoindex.CheckKey(nm);
if (!nmm) return -1;
return *nmm;
auto texid = TexMan.CheckForTexture(name, ETextureType::Any, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnAll);
if (!texid.isValid()) return -1;
return legacyTileNum(texid);
}
// Some hacks to allow accessing the no longer existing arrays as if they still were arrays to avoid changing hundreds of lines of code.
struct PicAnm
{
picanm_t& operator[](size_t index)
//[[deprecated]]
const picanm_t& operator[](int index) const
{
assert(index < MAXTILES);
return TileFiles.tiledata[index].picanm;
assert((unsigned)index < MAXTILES);
return GetExtInfo(tileGetTextureID(index)).picanm;
}
};
extern PicAnm picanm;
inline PicAnm picanm;
//[[deprecated]]
inline int tileWidth(int num)
{
assert((unsigned)num < MAXTILES);
if ((unsigned)num >= MAXTILES) return 1;
return (int)TileFiles.tiledata[num].texture->GetDisplayWidth();
auto texid = tileGetTextureID(num);
if (!texid.isValid()) return 1;
else return (int)TexMan.GetGameTexture(texid)->GetDisplayWidth();
}
//[[deprecated]]
inline int tileHeight(int num)
{
assert((unsigned)num < MAXTILES);
if ((unsigned)num >= MAXTILES) return 1;
return (int)TileFiles.tiledata[num].texture->GetDisplayHeight();
}
int tileAnimateOfs(int tilenum, int randomize = -1);
inline void tileUpdatePicnum(int* const tileptr, bool mayrotate = false, int randomize = -1)
{
auto& tile = *tileptr;
if (picanm[tile].type())
tile += tileAnimateOfs(tile, randomize);
auto texid = tileGetTextureID(num);
if (!texid.isValid()) return 1;
else return (int)TexMan.GetGameTexture(texid)->GetDisplayHeight();
}
//[[deprecated]]
inline FGameTexture* tileGetTexture(int tile, bool animate = false)
{
assert((unsigned)tile < MAXTILES && tile != -1); // -1 is valid for overpicnum as 'no texture'.
if (tile < 0 || tile >= MAXTILES) return nullptr;
if (animate) tileUpdatePicnum(&tile);
return TileFiles.tiledata[tile].texture;
auto texid = tileGetTextureID(tile);
if (animate) tileUpdatePicnum(texid);
return TexMan.GetGameTexture(texid);
}
inline FTextureID tileGetTextureID(int tile)
{
if (tile < 0 || tile >= MAXTILES) return FNullTextureID();
return TileFiles.tiledata[tile].texture->GetID();
}
inline int legacyTileNum(FTextureID tex)
{
auto p = TileFiles.textotile.CheckKey(tex.GetIndex());
return p ? *p : -1;
}
void tileUpdateAnimations();
const uint8_t* GetRawPixels(FTextureID texid);
uint8_t* GetWritablePixels(FTextureID texid);
void InvalidateTexture(FTextureID num);
TileOffs* GetHiresOffset(FTextureID num);
class FGameTexture;
bool PickTexture(FGameTexture* tex, int paletteid, TexturePick& pick, bool wantindexed = false);
FCanvasTexture* tileGetCanvas(int tilenum);

View file

@ -51,6 +51,13 @@
#include "skyboxtexture.h"
#include "gamefuncs.h"
enum ETexType
{
TT_INDEXED,
TT_TRUECOLOR,
};
CVARD(Bool, hw_shadeinterpolate, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable shade interpolation")
struct HightileReplacement
@ -244,26 +251,10 @@ void highTileSetup()
//
//==========================================================================
int tileSetHightileReplacement(int picnum, int palnum, const char* filename, float alphacut, float xscale, float yscale, float specpower, float specfactor, bool indexed)
int tileSetHightileReplacement(int picnum, int palnum, FTextureID texid, float alphacut, float xscale, float yscale, float specpower, float specfactor, bool indexed)
{
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
}
// assumes the texture was already validated.
HightileReplacement replace = {};
FTextureID texid = TexMan.CheckForTexture(filename, ETextureType::Any, FTextureManager::TEXMAN_ForceLookup);
if (!texid.isValid())
{
Printf("%s: Replacement for tile %d does not exist or is invalid\n", filename, picnum);
return -1;
}
replace.image = TexMan.GetGameTexture(texid);
replace.alphacut = min(alphacut,1.f);
replace.scale = { xscale, yscale };

View file

@ -40,6 +40,7 @@
#include "printf.h"
#include "texturemanager.h"
#include "buildtiles.h"
#include "texinfo.h"
FGameTexture* GetSkyTexture(int basetile, int lognumtiles, const int16_t *tilemap, int remap)
{

View file

@ -0,0 +1,100 @@
/*
** texinfo.cpp
** Extended texture information / handling
**
**---------------------------------------------------------------------------
** Copyright 2019-2022 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 "texturemanager.h"
#include "texinfo.h"
#include "m_crc32.h"
//==========================================================================
//
// Retrieve animation offset
//
//==========================================================================
static int tileAnimateOfs(FTextureID texid, int randomize)
{
auto ext = GetExtInfo(texid);
int framecount = ext.picanm.num;
if (framecount > 0)
{
int frametime = !isBlood() ? I_GetBuildTime() : PlayClock;
if (isBlood() && randomize)
{
frametime += Bcrc32(&randomize, 2, 0);
}
int curframe = (frametime & 0x7fffffff) >> (ext.picanm.speed());
switch (ext.picanm.type())
{
case PICANM_ANIMTYPE_FWD:
return curframe % (framecount + 1);
case PICANM_ANIMTYPE_BACK:
return -(curframe % (framecount + 1));
case PICANM_ANIMTYPE_OSC:
curframe = curframe % (framecount << 1);
if (curframe >= framecount) return (framecount << 1) - curframe;
else return curframe;
}
}
return 0;
}
void tileUpdatePicnum(FTextureID& tileptr, int randomize)
{
tileptr = FSetTextureID(tileptr.GetIndex() + tileAnimateOfs(tileptr, randomize));
}
//===========================================================================
//
// update the animation info inside the texture manager.
//
//===========================================================================
void tileUpdateAnimations()
{
for (unsigned i = 0; i < texExtInfo.Size(); i++)
{
auto& x = texExtInfo[i];
if (x.picanm.type())
{
int j = i + tileAnimateOfs(FSetTextureID(i), false);
TexMan.SetTranslation(FSetTextureID(i), FSetTextureID(j));
}
}
}

View file

@ -0,0 +1,122 @@
#pragma once
#include <stdint.h>
#include "gamefuncs.h"
#include "tiletexture.h"
// extended texture info for which there is no room in the texture manager.
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
};
// NOTE: If the layout of this struct is changed, loadpics() must be modified
// accordingly.
struct picanm_t
{
uint16_t num; // animate number
uint8_t sf; // anim. speed and flags
uint8_t extra;
void Clear()
{
extra = sf = 0;
num = 0;
}
int speed() const
{
return sf & PICANM_ANIMSPEED_MASK;
}
int type() const
{
return sf & PICANM_ANIMTYPE_MASK;
}
};
struct TileOffs
{
int16_t xsize, ysize, xoffs, yoffs;
};
struct TexExtInfo
{
// TexAnim *texanim // todo: extended texture animation like ZDoom's ANIMDEFS.
uint8_t terrain; // Contents depend on the game, e.g. this holds Blood's surfType.
uint8_t shadeinfo; // Blood's shade.dat
uint16_t voxindex;
picanm_t picanm;
uint32_t flags; // contents are game dependent.
TileOffs hiofs;
};
inline TArray<TexExtInfo> texExtInfo;
inline int firstarttile, maxarttile; // we need this for conversion between tile numbers and texture IDs
//==========================================================================
//
// THe tile container
//
//==========================================================================
struct TexturePick
{
FGameTexture* texture; // which texture to use
int translation; // which translation table to use
int tintFlags; // which shader tinting options to use
PalEntry tintColor; // Tint color
PalEntry basepalTint; // can the base palette be done with a global tint effect?
};
bool PickTexture(FGameTexture* tex, int paletteid, TexturePick& pick, bool wantindexed = false);
void tileUpdatePicnum(FTextureID& tileptr, int randomize = -1);
void tileUpdateAnimations();
inline const TexExtInfo& GetExtInfo(FTextureID tex) // this is only for reading, not for modifying!
{
unsigned index = tex.GetIndex();
if (index >= texExtInfo.Size()) index = 0; // index 0 (the null texture) serves as backup if textures get added at runtime.
return texExtInfo[index];
}
inline FTextureID tileGetTextureID(int tilenum)
{
if ((unsigned)tilenum >= MAXTILES) return FNullTextureID();
return FSetTextureID(firstarttile + min(tilenum, maxarttile));
}
// Use this only for places where some legacy feature needs a tile index. The only such places are CON and nnext.
inline int legacyTileNum(FTextureID id)
{
int index = id.GetIndex() - firstarttile;
if (index < 0 || index > maxarttile) return maxarttile;
return index;
}
inline const TileOffs* GetHiresOffset(FTextureID tex)
{
// fixme: This must return nullptr if the tile has no replacement.
auto& x = GetExtInfo(tex);
if (x.hiofs.xsize != 0) return &x.hiofs;
else return nullptr;
}

View file

@ -0,0 +1,315 @@
/*
** tilesetbuilder.cpp
** Constructs the full tile set and adds it to the texture manager.
**
**---------------------------------------------------------------------------
** Copyright 2019-2022 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 "image.h"
#include "texturemanager.h"
#include "m_crc32.h"
#include "c_dispatch.h"
#include "tiletexture.h"
#include "tilesetbuilder.h"
#include "gamecontrol.h"
#include "startupinfo.h"
#include "printf.h"
#include "m_argv.h"
#include "gamestruct.h"
const char* G_DefFile(void);
void loaddefinitionsfile(TilesetBuildInfo& info, const char* fn, bool cumulative = false, bool maingrp = false);
//==========================================================================
//
// Returns checksum for a given tile or texture
//
//==========================================================================
int32_t tileGetCRC32(FImageSource* image)
{
if (image == nullptr) return 0;
auto pixels = image->GetPalettedPixels(0);
if (pixels.Size() == 0) return 0;
// To get proper CRCs as the calling code expects we need to put the translucent index back to 255.
for (auto& p : pixels)
{
if (p == 0) p = 255;
else if (p == 255) p = 0;
}
return crc32(0, (const Bytef*)pixels.Data(), pixels.Size());
}
CCMD(tilecrc)
{
if (argv.argc() > 1)
{
char* p;
int tile = strtol(argv[1], &p, 10);
FGameTexture* tex;
if (tile >= 0 && tile < MAXTILES && !*p)
{
// tex = tileGetTexture(tile);
}
else
{
tex = TexMan.FindGameTexture(argv[1], ETextureType::Any);
}
auto img = tex? tex->GetTexture()->GetImage() : nullptr;
if (!img) Printf("%s: not a valid texture", argv[1]);
else Printf("%d\n", tileGetCRC32(img));
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static void LoadDefinitions(TilesetBuildInfo& info)
{
const char* defsfile = G_DefFile();
FString razedefsfile = defsfile;
razedefsfile.Substitute(".def", "-raze.def");
loaddefinitionsfile(info, "engine/engine.def", true, true); // Internal stuff that is required.
// check what we have.
// user .defs override the default ones and are not cumulative.
// if we fine even one Raze-specific file, all of those will be loaded cumulatively.
// otherwise the default rules inherited from older ports apply.
if (userConfig.UserDef.IsNotEmpty())
{
loaddefinitionsfile(info, userConfig.UserDef, false);
}
else
{
if (fileSystem.FileExists(razedefsfile))
{
loaddefinitionsfile(info, razedefsfile, true);
}
else if (fileSystem.FileExists(defsfile))
{
loaddefinitionsfile(info, defsfile, false);
}
}
if (userConfig.AddDefs)
{
for (auto& m : *userConfig.AddDefs)
{
loaddefinitionsfile(info, m, false);
}
userConfig.AddDefs.reset();
}
if (GameStartupInfo.def.IsNotEmpty())
{
loaddefinitionsfile(info, GameStartupInfo.def); // Stuff from gameinfo.
}
// load the widescreen replacements last. This ensures that mods still get the correct CRCs for their own tile replacements.
if (fileSystem.FindFile("engine/widescreen.def") >= 0 && !Args->CheckParm("-nowidescreen"))
{
loaddefinitionsfile(info, "engine/widescreen.def");
}
fileSystem.InitHashChains(); // make sure that any resources that got added can be found again.
}
//==========================================================================
//
//
//
//==========================================================================
picanm_t tileConvertAnimFormat(int32_t const picanimraw)
{
// Unpack a 4 byte packed anim descriptor into something more accessible
picanm_t anm;
anm.num = picanimraw & 63;
anm.sf = ((picanimraw >> 24) & 15) | (picanimraw & 192);
anm.extra = (picanimraw >> 28) & 15;
return anm;
}
//==========================================================================
//
//
//
//==========================================================================
FImageSource* createWritableTile(int width, int height);
FImageSource* makeTileWritable(FImageSource* img);
void TilesetBuildInfo::MakeWritable(int tileno)
{
if (tile[tileno].tileimage != nullptr)
{
auto newtex = makeTileWritable(tile[tileno].tileimage);
tile[tileno].tileimage = newtex;
tile[tileno].imported = nullptr;
}
}
void TilesetBuildInfo::CreateWritable(int tileno, int w, int h)
{
auto newtex = createWritableTile(w, h);
tile[tileno].tileimage = newtex;
tile[tileno].imported = nullptr;
}
//===========================================================================
//
// MakeCanvas
//
// Turns texture into a canvas (i.e. camera texture)
//
//===========================================================================
void TilesetBuildInfo::MakeCanvas(int tilenum, int width, int height)
{
auto ftex = new FCanvasTexture(width * 4, height * 4);
ftex->aspectRatio = (float)width / height;
auto canvas = MakeGameTexture(ftex, FStringf("#%05d", tilenum), ETextureType::Any);
canvas->SetSize(width * 4, height * 4);
canvas->SetDisplaySize((float)width, (float)height);
canvas->GetTexture()->SetSize(width * 4, height * 4);
tile[tilenum].imported = canvas;
tile[tilenum].tileimage = nullptr;
}
//==========================================================================
//
//
//
//==========================================================================
void ConstructTileset()
{
TilesetBuildInfo info;
TArray<FImageSource*> images;
TArray<unsigned> rawpicanm;
GetArtImages(images, rawpicanm);
info.tile.Resize(MAXTILES);
memset(info.tile.Data(), 0, info.tile.Size() * sizeof(info.tile[0]));
// fill up the arrays to the maximum allowed but remember the highest original number.
for (unsigned i = 0; i < images.Size(); i++)
{
info.tile[i].orgimage = info.tile[i].tileimage = images[i];
if (images[i])
{
auto s = images[i]->GetOffsets();
info.tile[i].leftOffset = s.first;
info.tile[i].topOffset = s.second;
}
info.tile[i].extinfo.picanm = tileConvertAnimFormat(rawpicanm[i]);
}
images.Reset();
rawpicanm.Reset();
for (auto& a : info.tile) a.alphathreshold = 0.5f;
gi->LoadTextureInfo(info); // initialize game data that must be done before loading .DEF
LoadDefinitions(info);
gi->SetupSpecialTextures(info); // initialize game data that needs .DEF being processed.
// now that everything has been set up, we can add the textures to the texture manager.
// To keep things simple everything from .ART files and its replacements will remain in order and
// converting between a Build tilenum and a texture ID can done with a single addition.
// Even though this requires adding quite a few empty textures to the texture manager, it makes things a lot easier,
// because it ensures an unambiguous mapping and allows communicating with features that only work with tile numbers.
// as long as no named textures are used.
auto nulltex = TexMan.GameByIndex(0); // Use the null texture's backing data for all empty placeholders.
// Only the outward facing FGameTexture needs to be different
firstarttile = TexMan.NumTextures();
maxarttile = MAXTILES - 1;
while (maxarttile >= 0 && info.tile[maxarttile].tileimage == nullptr) maxarttile--;
if (maxarttile < 0) return; // should never happen, but who knows - maybe someone will make a game without ART files later... :D
maxarttile++; // create a placeholder in the first unused spot. This will later get used for all out of range tile numbers.
int lastid = firstarttile - 1;
for (int i = 0; i <= maxarttile; i++)
{
FTexture* ftex = nullptr;
FGameTexture* gtex;
FStringf tname("#%05d", i);
if (info.tile[i].tileimage == nullptr)
{
if (info.tile[i].imported == nullptr)
{
ftex = nulltex->GetTexture();
gtex = MakeGameTexture(ftex, tname, ETextureType::Null);
}
else
{
// Canvas textures can be used directly without wrapping them again.
gtex = info.tile[i].imported;
}
}
else
{
if (info.tile[i].imported) ftex = info.tile[i].imported->GetTexture();
else ftex = new FImageTexture(info.tile[i].tileimage);
gtex = MakeGameTexture(ftex, tname, ETextureType::Any);
gtex->SetOffsets(info.tile[i].leftOffset, info.tile[i].topOffset);
}
if (info.tile[i].extinfo.picanm.sf & PICANM_NOFULLBRIGHT_BIT)
{
gtex->SetDisableFullbright(true);
}
auto id = TexMan.AddGameTexture(gtex, true);
if (id.GetIndex() != lastid + 1)
{
// this should never happen unless the texture manager gets redone in an incompatible fashion.
I_FatalError("Unable to assign consecutive texture IDs to tile set.");
}
lastid = id.GetIndex();
}
// Now create the extended info. This will leave room for all regular textures as well so that later code can assign info to these, too.
// Textures being added afterward will always see the default extinfo, even if they are not covered by this array.
texExtInfo.Resize(TexMan.NumTextures());
memset(texExtInfo.Data(), 0, sizeof(texExtInfo[0]) * texExtInfo.Size());
for (auto& x : texExtInfo) x.voxindex = -1;
// now copy all extinfo stuff that got parsed by .DEF or some game specific setup.
for (int i = 0; i <= maxarttile; i++)
{
texExtInfo[i + firstarttile] = info.tile[i].extinfo;
}
for (auto& a : info.aliases)
{
TexMan.AddAlias(a.first.GetChars(), a.second + firstarttile);
}
}

View file

@ -0,0 +1,44 @@
#pragma once
#include "texinfo.h"
struct TileBuildDesc
{
// persistent data that will be present for the entire run of the game.
TexExtInfo extinfo;
// work data
FImageSource* orgimage; // this is the original tile image, not connected to a FTexture yet.
FImageSource* tileimage; // this is the current tile image, it may be connected to 'imported'. Used for convenient access.
FGameTexture* imported; // imported replacement from the texture manager;
// info that will be copied into the final texture object
float alphathreshold;
int leftOffset, topOffset; // overrides for imported textures.
};
struct TilesetBuildInfo
{
TArray<TileBuildDesc> tile;
unsigned maxtileofart;
TArray <std::pair<FName, int>> aliases;
void addName(const char* name, int index)
{
aliases.Push(std::make_pair(name, index));
}
void Delete(int tileno)
{
tile[tileno].tileimage = nullptr;
tile[tileno].imported = nullptr;
}
void MakeWritable(int tile);
void CreateWritable(int tile, int w, int h);
void MakeCanvas(int tilenum, int width, int height);
};
void ConstructTileset();
int32_t tileGetCRC32(FImageSource* image);

View file

@ -0,0 +1,525 @@
/*
** tiletexture.cpp
** Image sources and file management for Build tile textures
**
**---------------------------------------------------------------------------
** Copyright 2019-2022 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 "i_time.h"
#include "zstring.h"
#include "tiletexture.h"
#include "texturemanager.h"
#include "filesystem.h"
#include "printf.h"
class FTileTexture : public FImageSource
{
public:
FTileTexture() noexcept
{
bUseGamePalette = true;
bTranslucent = false;
}
virtual uint8_t* GetRawData() = 0;
virtual TArray<uint8_t> CreatePalettedPixels(int conversion);
virtual int CopyPixels(FBitmap* bmp, int conversion); // This will always ignore 'luminance'.
};
//==========================================================================
//
// 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) noexcept
: RawPixels(backingstore), Offset(offset)
{
Width = width;
Height = height;
}
uint8_t* GetRawData() override final
{
return &RawPixels[Offset];
}
};
//==========================================================================
//
// A non-existent tile
//
//==========================================================================
class FDummyTile : public FTileTexture
{
public:
FDummyTile(int width, int height)
{
Width = width;
Height = height;
}
uint8_t* GetRawData() override
{
return nullptr;
}
};
//==========================================================================
//
// A tile with a writable surface
//
//==========================================================================
class FWritableTile : public FTileTexture
{
protected:
TArray<uint8_t> buffer;
public:
FWritableTile()
{
//useType = Writable;
}
uint8_t* GetRawData() override
{
return buffer.Data();
}
bool ResizeImage(int w, int h)
{
if (w <= 0 || h <= 0)
{
buffer.Reset();
return false;
}
else
{
Width = w;
Height = h;
buffer.Resize(w * h);
return true;
}
}
virtual void Reload() {}
};
//==========================================================================
//
// A tile with a writable surface
//
//==========================================================================
class FRestorableTile : public FWritableTile
{
FImageSource* Base;
public:
FRestorableTile(FImageSource* base)
{
Base = base;
CopySize(*base);
ResizeImage(Width, Height);
Reload();
}
void Reload() override
{
buffer = Base->GetPalettedPixels(0);
}
};
//==========================================================================
//
// Base class for Build tile textures
// This needs a few subclasses for different use cases.
//
//==========================================================================
int FTileTexture::CopyPixels(FBitmap* bmp, int conversion)
{
TArray<uint8_t> buffer;
auto ppix = GetRawData();
if (ppix)
{
bmp->CopyPixelData(0, 0, ppix, Width, Height, Height, 1, 0, GPalette.BaseColors);
}
return 0;
}
TArray<uint8_t> FTileTexture::CreatePalettedPixels(int conversion)
{
TArray<uint8_t> buffer(Width * Height, true);
auto p = GetRawData();
if (p) memcpy(buffer.Data(), p, buffer.Size());
else memset(buffer.Data(), 0, buffer.Size());
return buffer;
}
//==========================================================================
//
// raw pixel cache. This is for accessing pixel data in the game code,
// not for rendering.
//
//==========================================================================
struct RawCacheNode
{
TArray<uint8_t> data;
uint64_t lastUseTime;
RawCacheNode() = default;
RawCacheNode(const RawCacheNode& other) = default;
RawCacheNode& operator=(const RawCacheNode& other) = default;
RawCacheNode(RawCacheNode&& other) noexcept
{
data = std::move(other.data);
lastUseTime = other.lastUseTime;
}
RawCacheNode& operator=(RawCacheNode&& other) noexcept
{
data = std::move(other.data);
lastUseTime = other.lastUseTime;
return *this;
}
};
//==========================================================================
//
// access raw pixel data for in-game checking. Works for all texture types.
//
//==========================================================================
static TMap<int, RawCacheNode> CacheNodes;
const uint8_t* GetRawPixels(FTextureID texid)
{
if (!texid.isValid()) return nullptr;
auto gtex = TexMan.GetGameTexture(texid);
auto tex = dynamic_cast<FImageTexture*>(gtex->GetTexture());
if (!tex || !tex->GetImage()) return nullptr;
auto img = tex->GetImage();
auto timg = dynamic_cast<FTileTexture*>(img);
if (!timg || !timg->GetRawData())
{
auto cache = CacheNodes.CheckKey(texid.GetIndex());
if (cache)
{
cache->lastUseTime = I_nsTime();
return cache->data.Data();
}
RawCacheNode newnode;
newnode.data = img->GetPalettedPixels(0);
newnode.lastUseTime = I_nsTime();
auto retval =newnode.data.Data();
CacheNodes.Insert(texid.GetIndex(), std::move(newnode));
return retval;
}
else
{
return timg->GetRawData();
}
}
//==========================================================================
//
//To use this the texture must have been made writable during texture init.
//
//==========================================================================
uint8_t* GetWritablePixels(FTextureID texid, bool reload)
{
if (!texid.isValid()) return nullptr;
auto gtex = TexMan.GetGameTexture(texid);
auto tex = dynamic_cast<FImageTexture*>(gtex->GetTexture());
if (!tex || !tex->GetImage()) return nullptr;
auto timg = dynamic_cast<FWritableTile*>(tex->GetImage());
if (!timg) return nullptr;
if (reload)
timg->Reload();
gtex->CleanHardwareData(); // we can safely assume that this only gets called when the texture is about to be changed.
return timg->GetRawData();
}
//==========================================================================
//
//
//
//==========================================================================
static FImageSource* GetTileImage(const TArray<uint8_t>& backingstore, uint32_t offset, int width, int height, TArray<void*> freelist)
{
FImageSource* tex;
void* mem = nullptr;
if (freelist.Size() > 0) freelist.Pop(mem);
// recycle discarded image sources if available. They are all the same type so this is safe.
if (mem) tex = new(mem) FArtTile(backingstore, offset, width, height);
else tex = new FArtTile(backingstore, offset, width, height);
auto p = &backingstore[offset];
auto siz = width * height;
for (int i = 0; i < siz; i++, p++)
{
// move transparent color to index 0 to get in line with the rest of the texture management.
if (*p == 0) *p = 255;
else if (*p == 255) *p = 0;
}
return tex;
}
//===========================================================================
//
// Creates image sources for all valid tiles in one ART file.
// In case this overwrites older tiles, these get added to a freelist
// and reused later
//
//===========================================================================
static void GetImagesFromFile(TArray<FImageSource*>& array, TArray<unsigned>& picanmarray, TArray<void*> freelist, TArray<uint8_t>& RawData)
{
const uint8_t* tiles = RawData.Data();
// int numtiles = LittleLong(((uint32_t *)tiles)[1]); // This value is not reliable
unsigned tilestart = LittleLong(((unsigned*)tiles)[2]);
unsigned tileend = LittleLong(((unsigned*)tiles)[3]);
const uint16_t* tilesizx = &((const uint16_t*)tiles)[8];
const uint16_t* tilesizy = &tilesizx[tileend - tilestart + 1];
const uint32_t* picanm = (const uint32_t*)&tilesizy[tileend - tilestart + 1];
const uint8_t* tiledata = (const uint8_t*)&picanm[tileend - tilestart + 1];
unsigned oldsize = array.Size();
if (array.Size() < tileend + 1)
array.Resize(tileend + 1);
// picanm info needs to be stashed aside for later use, except for the offsets which are written into the image object
if (picanmarray.Size() < tileend + 1)
picanmarray.Resize(tileend + 1);
// If there's a gap, initialize it.
for (unsigned i = oldsize; i < tilestart; i++)
{
array[i] = nullptr;
picanmarray[i] = {};
}
for (unsigned i = tilestart; i <= tileend; ++i)
{
int pic = i - tilestart;
int width = LittleShort(tilesizx[pic]);
int height = LittleShort(tilesizy[pic]);
uint32_t anm = LittleLong(picanm[pic]);
int size = width * height;
picanmarray[i] = picanm[pic]; // this must also be retained for invalid tiles.
if (width <= 0 || height <= 0)
{
// If an existing tile is discarded, add it to the free list
if (array[i] && i < oldsize)
{
array[i]->~FImageSource(); // really a no-op but let's stay on the safe side.
freelist.Push(array[i]);
}
array[i] = nullptr;
continue;
}
FString texname;
auto tex = GetTileImage(RawData, uint32_t(tiledata - tiles), width, height, freelist);
int leftoffset = (int8_t)((anm >> 8) & 255);
int topoffset = (int8_t)((anm >> 16) & 255);
tex->SetOffsets(leftoffset, topoffset);
tiledata += size;
array[i] = tex;
}
}
//===========================================================================
//
// CountTiles
//
// Returns the number of tiles provided by an artfile
//
//===========================================================================
int CountTiles(const char* fn, const uint8_t* RawData)
{
int version = LittleLong(*(uint32_t*)RawData);
if (version != 1)
{
Printf("%s: Invalid art file version. Must be 1, got %d\n", fn, version);
return 0;
}
int tilestart = LittleLong(((uint32_t*)RawData)[2]);
int tileend = LittleLong(((uint32_t*)RawData)[3]);
if ((unsigned)tilestart >= MAXUSERTILES || (unsigned)tileend >= MAXUSERTILES)
{
Printf("%s: Invalid tilestart or tileend\n", fn);
return 0;
}
if (tileend < tilestart)
{
Printf("%s: tileend < tilestart\n", fn);
return 0;
}
return tileend >= tilestart ? tileend - tilestart + 1 : 0;
}
//===========================================================================
//
// LoadArtFile
//
// Returns the number of tiles found.
//
// let's load everything into memory on startup.
//
//===========================================================================
static void AddArtFile(const FString& filename)
{
FileReader fr = fileSystem.OpenFileReader(filename);
if (fr.isOpen())
{
auto artdata = fr.Read();
if (artdata.Size() > 16)
{
if (memcmp(artdata.Data(), "BUILDART", 8) == 0)
{
artdata.Delete(0, 8);
}
// Only load the data if the header is present
if (CountTiles(filename, artdata.Data()) > 0)
{
// The texture manager already has a store for Build ART files, so let's use it. :)
auto& store = TexMan.GetNewBuildTileData();
store = std::move(artdata);
}
}
}
}
//===========================================================================
//
// Loads an art set but does not do anything with the tiles yet.
//
//===========================================================================
void InitArtFiles(TArray<FString>& addedArt)
{
const int MAXARTFILES_BASE = 200;
for (int index = 0; index < MAXARTFILES_BASE; index++)
{
FStringf fn("tiles%03d.art", index);
AddArtFile(fn);
}
for (auto& addart : addedArt)
{
AddArtFile(addart);
}
}
//===========================================================================
//
// Creates image sources for all valid tiles in the ART set.
//
//===========================================================================
void GetArtImages(TArray<FImageSource*>& array, TArray<unsigned>& picanm)
{
TArray<void*> freelist;
for (auto& f : TexMan.GetBuildTileDataStore())
{
GetImagesFromFile(array, picanm, freelist, f);
}
}
//==========================================================================
//
//
//
//==========================================================================
FImageSource* createDummyTile(int width, int height)
{
if (width > 0 && height > 0)
return new FDummyTile(width, height);
else
return nullptr;
}
//==========================================================================
//
//
//
//==========================================================================
FImageSource* createWritableTile(int width, int height)
{
if (width > 0 && height > 0)
{
auto tile = new FWritableTile;
tile->ResizeImage(width, height);
return tile;
}
else
return nullptr;
}
//==========================================================================
//
//
//
//==========================================================================
FImageSource* makeTileWritable(FImageSource* img)
{
return new FRestorableTile(img);
}

View file

@ -0,0 +1,18 @@
#pragma once
#include <stdint.h>
#include "image.h"
#include "textureid.h"
#include "tarray.h"
const uint8_t* GetRawPixels(FTextureID texid);
uint8_t* GetWritablePixels(FTextureID texid, bool reload = false);
FImageSource* createDummyTile(int width, int height);
void InitArtFiles(TArray<FString>& addart);
void GetArtImages(TArray<FImageSource*>& array, TArray<unsigned>& picanm);
enum
{
MAXTILES = 30720,
MAXUSERTILES = (MAXTILES - 16) // reserve 16 tiles at the end
};

View file

@ -38,6 +38,9 @@
#include "gamefuncs.h"
#include "raze_sound.h"
#include "texturemanager.h"
#include "texinfo.h"
#include "buildtiles.h"
sectortype* Raze_updatesector(double x, double y, sectortype* sec, double dist)
{
@ -478,7 +481,7 @@ int sector_checktexture(sectortype* sec, int place, int intname)
{
if (!sec) ThrowAbortException(X_READ_NIL, nullptr);
auto tex = TexMan.CheckForTexture(FName(ENamedName(intname)).GetChars(), ETextureType::Any);
auto tex = TexMan.CheckForTexture(FName(ENamedName(intname)).GetChars(), ETextureType::Any, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnAll);
return tex == (place == 0 ? sec->ceilingtexture() : sec->floortexture());
}

View file

@ -48,6 +48,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "texturemanager.h"
#include "statusbar.h"
#include "vm.h"
#include "tilesetbuilder.h"
BEGIN_BLD_NS
@ -74,6 +75,7 @@ IMPLEMENT_POINTERS_END
//
//---------------------------------------------------------------------------
void MarkSprInSect();
void tileInitProps();
size_t DBloodActor::PropagateMark()
{
@ -585,6 +587,9 @@ void GameInterface::loadPalette(void)
void GameInterface::app_init()
{
mirrortile = tileGetTextureID(504);
tileInitProps();
GC::AddMarkerFunc(markgcroots);
InitCheats();
@ -717,7 +722,11 @@ enum
DEFINE_ACTION_FUNCTION(_Blood, OriginalLoadScreen)
{
static int bLoadScreenCrcMatch = -1;
if (bLoadScreenCrcMatch == -1) bLoadScreenCrcMatch = tileGetCRC32(kLoadScreen) == kLoadScreenCRC;
if (bLoadScreenCrcMatch == -1)
{
auto tex = tileGetTexture(kLoadScreen)->GetTexture()->GetImage(); // if this is invalid we have a bigger problem on our hand than the inevitable crash.
bLoadScreenCrcMatch = tileGetCRC32(tex) == kLoadScreenCRC;
}
ACTION_RETURN_INT(bLoadScreenCrcMatch);
}

View file

@ -142,8 +142,8 @@ struct GameInterface : public ::GameInterface
void processSprites(tspriteArray& tsprites, const DVector3& view, DAngle viewang, double interpfrac) override;
void EnterPortal(DCoreActor* viewer, int type) override;
void LeavePortal(DCoreActor* viewer, int type) override;
void LoadGameTextures() override;
void SetupSpecialTextures() override;
void LoadTextureInfo(TilesetBuildInfo& info) override;
void SetupSpecialTextures(TilesetBuildInfo&) override;
int GetCurrentSkill() override;
bool IsQAVInterpTypeValid(const FString& type) override;
void AddQAVInterpProps(const int res_id, const FString& interptype, const bool loopable, const TMap<int, TArray<int>>&& ignoredata) override;

View file

@ -89,7 +89,10 @@ static void viewBurnTime(int gScale)
for (int i = 0; i < 9; i++)
{
int nTile = burnTable[i].nTile;
tileUpdatePicnum(&nTile);
// This is needed because hud_drawsprite still works with tilenums.
FTextureID nID = tileGetTextureID(nTile);
tileUpdatePicnum(nID);
nTile = legacyTileNum(nID);
int nScale = burnTable[i].nScale;
if (gScale < 600)
{

View file

@ -24,6 +24,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "m_fixed.h"
#include "filesystem.h"
#include "texinfo.h"
#include "buildtiles.h"
BEGIN_BLD_NS

View file

@ -28,6 +28,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "build.h"
#include "blood.h"
#include "hw_voxels.h"
#include "tilesetbuilder.h"
BEGIN_BLD_NS
@ -40,16 +42,20 @@ static int8_t tileShade[kMaxTiles];
short voxelIndex[kMaxTiles];
#define x(a, b) registerName(#a, b);
static void SetTileNames()
static void SetTileNames(TilesetBuildInfo& info)
{
auto registerName = [](const char* name, int index)
auto registerName = [&](const char* name, int index)
{
TileFiles.addName(name, index);
info.addName(name, index);
};
#include "namelist.h"
// Oh Joy! Plasma Pak changes the tile number of the title screen, but we preferably want mods that use the original one to display it.
// Oh Joy! Plasma Pak changes the tile number of the title screen, but we preferably want mods that use the original one to display it, e.g. Cryptic Passage
// So let's make this remapping depend on the CRC.
if (tileGetCRC32(2518) == 1170870757 && (tileGetCRC32(2046) != 290208654 || tileWidth(2518) == 0)) registerName("titlescreen", 2046);
const int OTITLE = 2046, PTITLE = 2518;
auto& orgtitle = info.tile[OTITLE];
auto& pptile = info.tile[PTITLE];
if (tileGetCRC32(pptile.tileimage) == 1170870757 && (tileGetCRC32(orgtitle.tileimage) != 290208654 || pptile.tileimage->GetWidth() == 0)) registerName("titlescreen", 2046);
else registerName("titlescreen", 2518);
}
#undef x
@ -60,7 +66,7 @@ static void SetTileNames()
//
//---------------------------------------------------------------------------
void GameInterface::LoadGameTextures()
void GameInterface::LoadTextureInfo(TilesetBuildInfo& info)
{
auto hFile = fileSystem.OpenFileReader("SURFACE.DAT");
if (hFile.isOpen())
@ -86,16 +92,19 @@ void GameInterface::LoadGameTextures()
if (voxelIndex[i] >= 0 && voxelIndex[i] < MAXVOXELS)
voxreserve.Set(voxelIndex[i]);
}
SetTileNames();
}
void GameInterface::SetupSpecialTextures()
void GameInterface::SetupSpecialTextures(TilesetBuildInfo& info)
{
SetTileNames(info);
// set up all special tiles here, before we fully hook up with the texture manager.
tileDelete(504);
TileFiles.tileMakeWritable(2342);
TileFiles.lock(); // from this point on the tile<->texture associations may not change anymore.
mirrortile = tileGetTextureID(504);
info.Delete(504);
info.MakeWritable(2342);
}
void tileInitProps()
{
for (int i = 0; i < MAXTILES; i++)
{
auto tex = tileGetTexture(i);
@ -106,7 +115,6 @@ void GameInterface::SetupSpecialTextures()
}
}
}
//---------------------------------------------------------------------------
//
//

View file

@ -33,6 +33,8 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
#include "dukeactor.h"
#include "interpolate.h"
#include "buildtiles.h"
BEGIN_DUKE_NS
static int torchcnt;

View file

@ -32,6 +32,8 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
#include "gamefuncs.h"
#include "models/modeldata.h"
#include "buildtiles.h"
BEGIN_DUKE_NS
void drawshadows(tspriteArray& tsprites, tspritetype* t, DDukeActor* h)

View file

@ -26,7 +26,10 @@ enum
GPSPEED = 10,
FOF = 13,
TILE_VIEWSCR = (MAXTILES-5)
// hack alert! CYCLER is free for use here as all items of this type get destroyed right on map spawn and this value never gets checked anywhere else.
// This avoids overallocation of empty tile slots as a high value slightly below the tile limit would do.
// Once we can do texture management without tile numbers this can be done as a regular texture without a valid tile index.
TILE_VIEWSCR = CYCLER
};

View file

@ -24,8 +24,7 @@ struct GameInterface : public ::GameInterface
const char* Name() override { return "Duke"; }
void app_init() override;
void loadPalette() override;
void LoadGameTextures() override;
void SetupSpecialTextures() override;
void SetupSpecialTextures(TilesetBuildInfo& info) override;
void clearlocalinputstate() override;
bool GenerateSavePic() override;
void PlayHudSound() override;

View file

@ -43,6 +43,7 @@ Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
#include "psky.h"
#include "vm.h"
#include "thingdef.h"
#include "tilesetbuilder.h"
BEGIN_DUKE_NS
@ -281,11 +282,11 @@ static void setupbackdrop()
#define x(a, b) registerName(#a, b);
#define y(a, b) registerName(#a, b);
static void SetTileNames()
static void SetTileNames(TilesetBuildInfo& info)
{
auto registerName = [](const char* name, int index)
auto registerName = [&](const char* name, int index)
{
TileFiles.addName(name, index);
info.addName(name, index);
};
if (!isRR())
{
@ -299,31 +300,29 @@ static void SetTileNames()
#undef x
#undef y
void GameInterface::LoadGameTextures()
{
SetTileNames();
}
void GameInterface::SetupSpecialTextures()
void GameInterface::SetupSpecialTextures(TilesetBuildInfo& info)
{
SetTileNames(info);
// set up all special tiles here, before we fully hook up with the texture manager.
tileDelete(FOF); // portal marker
info.Delete(FOF); // portal marker
FImageSource* viewscreen;
if (!isRR())
{
tileDelete(560); // the mirror tile.
TileFiles.MakeCanvas(TILE_VIEWSCR, tileWidth(502), tileHeight(502));
info.Delete(560); // the mirror tile.
viewscreen = info.tile[502].tileimage;
}
else
{
tileDelete(1089); // the mirror tile.
tileDelete(0); // RR uses this as an empty texture
TileFiles.tileMakeWritable(2025); // bowling lane pin displays
TileFiles.tileMakeWritable(2026);
TileFiles.tileMakeWritable(2027);
TileFiles.tileMakeWritable(2028);
TileFiles.MakeCanvas(TILE_VIEWSCR, tileWidth(1055), tileHeight(1055)); // not used by the game but all the support code is present, meaning maps are free to use it.
info.Delete(1089); // the mirror tile.
info.Delete(0); // RR uses this as an empty texture
info.MakeWritable(2025); // bowling lane pin displays
info.MakeWritable(2026);
info.MakeWritable(2027);
info.MakeWritable(2028);
viewscreen = info.tile[1055].tileimage;
}
TileFiles.lock(); // from this point on the tile<->texture associations may not change anymore.
info.MakeCanvas(TILE_VIEWSCR, viewscreen? viewscreen->GetWidth() : 128, viewscreen? viewscreen->GetHeight() : 128);
}

View file

@ -8,6 +8,7 @@
#include "types.h"
#include "d_net.h"
#include "serialize_obj.h"
#include "tiletexture.h"
BEGIN_DUKE_NS

View file

@ -36,6 +36,7 @@ source as it is released.
#include "global.h"
#include "names_d.h"
#include "dukeactor.h"
#include "buildtiles.h"
BEGIN_DUKE_NS

View file

@ -3,6 +3,7 @@
#include "gamehud.h"
#include "global.h"
#include "models/modeldata.h"
#include "texinfo.h"
// all inline functions.
BEGIN_DUKE_NS
@ -119,11 +120,9 @@ inline bool inventory(DDukeActor* S)
return actorflag(S, SFLAG_INVENTORY);
}
inline int& tileflags(unsigned int tilenum)
inline const unsigned& tileflags(unsigned int tilenum)
{
static int sink = 0;
if (tilenum >= MAXTILES) return sink;
return TileFiles.tiledata[tilenum].tileflags;
return GetExtInfo(tileGetTextureID(tilenum)).flags;
}
inline bool wallswitchcheck(DDukeActor* s)

View file

@ -933,5 +933,5 @@ x(DEVELOPERCOMMENTARYON, 5295)
x(BOSS5, 5310)
x(BOSS5STAYPUT, 5311)
x(SERIOUSSAM, 5846)
x(VIEWSCR, 30715) // MAXTILES-5
x(VIEWSCR, 7) // hijacks CYCLER

View file

@ -1553,4 +1553,4 @@ x(MAMACLOUD, 8663)
x(MAMA, 8705)
x(MAMAJIBA, 8890)
x(MAMAJIBB, 8895)
x(VIEWSCR, 30715) // MAXTILES-5
x(VIEWSCR, 7) // hijacks CYCLER

View file

@ -77,10 +77,10 @@ void GameInterface::UpdateCameras(double smoothratio)
if (camsprite->GetOwner() && (p->GetActor()->spr.pos - camsprite->spr.pos).Length() < VIEWSCREEN_ACTIVE_DISTANCE)
{
auto tex = tileGetTexture(camsprite->spr.picnum);
auto tex = TexMan.FindGameTexture("VIEWSCR", ETextureType::Any);
if (!tex || !tex->GetTexture()->isCanvas()) return;
auto canvas = tileGetCanvas(TILE_VIEWSCR);
if (!canvas) return;
auto canvas = static_cast<FCanvasTexture*>(tex->GetTexture());
screen->RenderTextureView(canvas, [=](IntRect& rect)
{

View file

@ -42,7 +42,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "vm.h"
#include "razefont.h"
#include <string>
#include "buildtiles.h"
#include <assert.h>
@ -436,9 +437,7 @@ void uploadCinemaPalettes()
static int DoStatic(int a, int b)
{
auto tex = dynamic_cast<FRestorableTile*>(tileGetTexture(kTileLoboLaptop)->GetTexture()->GetImage());
if (tex) tex->Reload();
auto pixels = GetWritablePixels(tileGetTextureID(kTileLoboLaptop));
auto pixels = GetWritablePixels(tileGetTextureID(kTileLoboLaptop), true);
int y = 160 - a / 2;
int left = 81 - b / 2;
@ -463,10 +462,8 @@ static int DoStatic(int a, int b)
static int UndoStatic()
{
auto tex = dynamic_cast<FRestorableTile*>(tileGetTexture(kTileLoboLaptop)->GetTexture()->GetImage());
if (tex) tex->Reload();
auto texid = tileGetTextureID(kTileLoboLaptop);
GetWritablePixels(texid);
GetWritablePixels(texid, true);
return texid.GetIndex();
}

View file

@ -49,6 +49,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "razemenu.h"
#include "v_draw.h"
#include "interpolate.h"
#include "tilesetbuilder.h"
#include "psky.h"
BEGIN_PS_NS
@ -534,34 +535,29 @@ void LevelFinished()
//---------------------------------------------------------------------------
#define x(a, b) registerName(#a, b);
static void SetTileNames()
static void SetTileNames(TilesetBuildInfo& info)
{
auto registerName = [](const char* name, int index)
auto registerName = [&](const char* name, int index)
{
TileFiles.addName(name, index);
info.addName(name, index);
};
#include "namelist.h"
}
#undef x
void GameInterface::LoadGameTextures()
void GameInterface::SetupSpecialTextures(TilesetBuildInfo& info)
{
SetTileNames();
}
void GameInterface::SetupSpecialTextures()
{
TileFiles.tileCreate(kTile4092, kPlasmaWidth, kPlasmaHeight);
TileFiles.tileCreate(kTile4093, kPlasmaWidth, kPlasmaHeight);
TileFiles.tileCreate(kTileRamsesWorkTile, kSpiritY * 2, kSpiritX * 2);
TileFiles.tileMakeWritable(kTileLoboLaptop);
SetTileNames(info);
info.CreateWritable(kTile4092, kPlasmaWidth, kPlasmaHeight);
info.CreateWritable(kTile4093, kPlasmaWidth, kPlasmaHeight);
info.CreateWritable(kTileRamsesWorkTile, kSpiritY * 2, kSpiritX * 2);
info.MakeWritable(kTileLoboLaptop);
for(int i = kTile3603; i < kClockSymbol1 + 145; i++)
TileFiles.tileMakeWritable(kTile3603);
TileFiles.tileMakeWritable(kEnergy1);
TileFiles.tileMakeWritable(kEnergy2);
info.MakeWritable(kTile3603);
info.MakeWritable(kEnergy1);
info.MakeWritable(kEnergy2);
for (int i = 0; i < 16; i++)
TileFiles.tileMakeWritable(kClockSymbol1);
TileFiles.lock();
info.MakeWritable(kClockSymbol1);
}
//---------------------------------------------------------------------------

View file

@ -209,8 +209,7 @@ struct GameInterface : public ::GameInterface
{
const char* Name() override { return "Exhumed"; }
void app_init() override;
void LoadGameTextures() override;
void SetupSpecialTextures() override;
void SetupSpecialTextures(TilesetBuildInfo& info) override;
void clearlocalinputstate() override;
void loadPalette() override;
bool GenerateSavePic() override;

View file

@ -41,6 +41,7 @@ not load" error messages.
#include "sounds.h"
#include "network.h"
#include "precache.h"
#include "texinfo.h"
BEGIN_SW_NS

View file

@ -58,6 +58,8 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
#include "razefont.h"
#include "models/modeldata.h"
#include "buildtiles.h"
extern DCoreActor* wall_to_sprite_actors[8];
BEGIN_SW_NS

View file

@ -49,6 +49,7 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
#include "i_interface.h"
#include "psky.h"
#include "startscreen.h"
#include "tilesetbuilder.h"
@ -209,46 +210,39 @@ int ThemeTrack[6];
/////////////////////////////////////////////////////////////////////////////////////////////
#define x(a, b) registerName(#a, b);
static void SetTileNames()
static void SetTileNames(TilesetBuildInfo& info)
{
auto registerName = [](const char* name, int index)
auto registerName = [&](const char* name, int index)
{
TileFiles.addName(name, index);
info.addName(name, index);
};
#include "namelist.h"
}
#undef x
void GameInterface::LoadGameTextures()
void GameInterface::LoadTextureInfo(TilesetBuildInfo& info)
{
LoadKVXFromScript("swvoxfil.txt"); // Load voxels from script file
SetTileNames();
}
void GameInterface::SetupSpecialTextures()
{
enum
{
FAF_PLACE_MIRROR_PIC = 341,
FAF_MIRROR_PIC = 2356
};
tileDelete(MIRROR); // mirror
void GameInterface::SetupSpecialTextures(TilesetBuildInfo& info)
{
info.Delete(MIRROR); // mirror
for (int i = 0; i < MAXMIRRORS; i++)
{
tileDelete(i + MIRRORLABEL);
TileFiles.MakeCanvas(CAMSPRITE + i, 128, 114);
info.Delete(i + MIRRORLABEL);
info.MakeCanvas(CAMSPRITE + i, 128, 114);
}
// make these two unique, they are empty by default.
tileDelete(FAF_MIRROR_PIC);
tileDelete(FAF_MIRROR_PIC + 1);
TileFiles.lock();
// these are frequently checked markers.
FAFPlaceMirrorPic[0] = tileGetTextureID(FAF_PLACE_MIRROR_PIC);
FAFPlaceMirrorPic[1] = tileGetTextureID(FAF_PLACE_MIRROR_PIC + 1);
FAFMirrorPic[0] = tileGetTextureID(FAF_MIRROR_PIC);
FAFMirrorPic[1] = tileGetTextureID(FAF_MIRROR_PIC + 1);
info.Delete(FAF_MIRROR_PIC);
info.Delete(FAF_MIRROR_PIC + 1);
SetTileNames(info);
}
//---------------------------------------------------------------------------
//
@ -258,6 +252,12 @@ void GameInterface::SetupSpecialTextures()
void GameInterface::app_init()
{
// these are frequently checked markers.
FAFPlaceMirrorPic[0] = tileGetTextureID(FAF_PLACE_MIRROR_PIC);
FAFPlaceMirrorPic[1] = tileGetTextureID(FAF_PLACE_MIRROR_PIC + 1);
FAFMirrorPic[0] = tileGetTextureID(FAF_MIRROR_PIC);
FAFMirrorPic[1] = tileGetTextureID(FAF_MIRROR_PIC + 1);
GC::AddMarkerFunc(markgcroots);
GameTicRate = TICS_PER_SEC / synctics;

View file

@ -1654,8 +1654,8 @@ struct GameInterface : public ::GameInterface
{
const char* Name() override { return "ShadowWarrior"; }
void app_init() override;
void LoadGameTextures() override;
void SetupSpecialTextures() override;
void LoadTextureInfo(TilesetBuildInfo& info) override;
void SetupSpecialTextures(TilesetBuildInfo& info) override;
void loadPalette() override;
void clearlocalinputstate() override;
void FreeLevelData() override;

View file

@ -397,12 +397,13 @@ void JS_InitMirrors(void)
/////////////////////////////////////////////////////
void drawroomstotile(const DVector3& pos, DAngle ang, DAngle horiz, sectortype* dacursect, short tilenume, double smoothratio)
{
auto canvas = tileGetCanvas(tilenume);
auto tex = tileGetTexture(tilenume);
auto canvas = dynamic_cast<FCanvasTexture*>(tex->GetTexture());
if (!canvas) return;
screen->RenderTextureView(canvas, [=](IntRect& rect)
{
render_camtex(nullptr, pos, dacursect, DRotator(horiz, ang, nullAngle), tileGetTexture(tilenume), rect, smoothratio);
render_camtex(nullptr, pos, dacursect, DRotator(horiz, ang, nullAngle), tex, rect, smoothratio);
});
}