- initialize all special tiles to their intended type before starting the game.

This ensures that we have an immutable mapping of tile number to texture ID now.
This commit is contained in:
Christoph Oelckers 2022-12-05 20:04:31 +01:00
parent faeb19a485
commit 51ad64f71e
18 changed files with 118 additions and 138 deletions

View file

@ -193,7 +193,7 @@ public:
TArray<RenderCommand> mData;
int Width, Height;
bool isIn2D;
bool locked; // prevents clearing of the data so it can be reused multiple times (useful for screen fades)
bool locked = false; // prevents clearing of the data so it can be reused multiple times (useful for screen fades)
float screenFade = 1.f;
DVector2 offset;
DMatrix3x3 transform;

View file

@ -420,40 +420,6 @@ FGameTexture* BuildTiles::ValidateCustomTile(int tilenum, ReplacementType type)
return rep;
}
//==========================================================================
//
// global interface
//
//==========================================================================
int32_t BuildTiles::artLoadFiles(const char* filename)
{
TileFiles.LoadArtSet(filename);
gotpic.Zero();
return 0;
}
//==========================================================================
//
// Retrieves the pixel store for a modifiable tile
// Modifiable tiles must be declared on startup.
//
//==========================================================================
uint8_t* BuildTiles::tileGet(int tilenum)
{
if (tilenum < 0 || tilenum >= MAXTILES) return nullptr;
auto& td = tiledata[tilenum];
auto tile = td.texture;
auto reptype = td.replacement;
if (reptype == ReplacementType::Writable || reptype == ReplacementType::Restorable)
{
auto wtex = static_cast<FWritableTile*>(tile->GetTexture()->GetImage());
if (wtex) return wtex->GetRawData();
}
return nullptr;
}
//==========================================================================
//
// Creates a tile for displaying custom content
@ -622,6 +588,8 @@ void tileCopy(int tile, int source, int pal, int xoffset, int yoffset, int flags
void tileDelete(int tile)
{
if (TileFiles.locked)
I_FatalError("Modifying tiles after startup is not allowed.");
TileFiles.tiledata[tile].texture = TexMan.GameByIndex(0);
TileFiles.tiledata[tile].replacement = ReplacementType::Art; // whatever this was, now it isn't anymore. (SW tries to nuke camera textures with this, :( )
tiletovox[tile] = -1; // clear the link but don't clear the voxel. It may be in use for another tile.
@ -659,52 +627,6 @@ void BuildTiles::CloseAll()
ArtFiles.DeleteAndClear();
}
//==========================================================================
//
// Copy a block of a tile.
// Only used by RR's bowling lane.
//
//==========================================================================
void tileCopySection(int tilenum1, int sx1, int sy1, int xsiz, int ysiz, int tilenum2, int sx2, int sy2)
{
int xsiz1 = tileWidth(tilenum1);
int ysiz1 = tileHeight(tilenum1);
int xsiz2 = tileWidth(tilenum2);
int ysiz2 = tileHeight(tilenum2);
if (xsiz1 > 0 && ysiz1 > 0 && xsiz2 > 0 && ysiz2 > 0)
{
auto p1 = tilePtr(tilenum1);
auto p2 = tileData(tilenum2);
if (p2 == nullptr) return; // Error: Destination is not writable.
int x1 = sx1;
int x2 = sx2;
for (int i=0; i<xsiz; i++)
{
int y1 = sy1;
int y2 = sy2;
for (int j=0; j<ysiz; j++)
{
if (x2 >= 0 && y2 >= 0 && x2 < xsiz2 && y2 < ysiz2)
{
auto src = p1[x1 * ysiz1 + y1];
if (src != TRANSPARENT_INDEX)
p2[x2 * ysiz2 + y2] = src;
}
y1++;
y2++;
if (y1 >= ysiz1) y1 = 0;
}
x1++;
x2++;
if (x1 >= xsiz1) x1 = 0;
}
}
TileFiles.InvalidateTile(tilenum2);
}
//==========================================================================
//
// Retrieve animation offset

View file

@ -365,10 +365,8 @@ struct BuildTiles
}
FGameTexture* ValidateCustomTile(int tilenum, ReplacementType type);
int32_t artLoadFiles(const char* filename);
uint8_t* tileMakeWritable(int num);
uint8_t* tileCreate(int tilenum, int width, int height);
uint8_t* tileGet(int tilenum);
void InvalidateTile(int num);
void MakeCanvas(int tilenum, int width, int height);
};

View file

@ -75,7 +75,7 @@ void DoFireFrame(void)
memcpy(FrameBuffer + 16896 + i * 128, SeedBuffer[nRand], 128);
}
CellularFrame(FrameBuffer, 128, 132);
auto pData = TileFiles.tileGet(2342);
auto pData = tileData(2342);
uint8_t* pSource = FrameBuffer;
int x = fireSize;
do

View file

@ -44,7 +44,6 @@ MIRROR mirror[16]; // only needed by Polymost.
void InitMirrors(void)
{
mirrorcnt = 0;
tileDelete(504);
portalClear();
for (int i = (int)wall.Size() - 1; i >= 0; i--)
@ -52,13 +51,10 @@ void InitMirrors(void)
auto pWalli = &wall[i];
if (mirrorcnt == 16)
break;
int nTile = 4080 + mirrorcnt;
if (pWalli->overpicnum == 504)
{
if (pWalli->extra > 0 && pWalli->type == kWallStack)
{
pWalli->overpicnum = nTile;
mirror[mirrorcnt].mynum = i;
mirror[mirrorcnt].type = 0;
pWalli->cstat |= CSTAT_WALL_1WAY;
@ -96,7 +92,6 @@ void InitMirrors(void)
{
mirror[mirrorcnt].link = i;
mirror[mirrorcnt].mynum = i;
pWalli->picnum = nTile;
mirror[mirrorcnt].type = 0;
pWalli->cstat |= CSTAT_WALL_1WAY;
pWalli->portalflags = PORTAL_WALL_MIRROR;
@ -176,17 +171,6 @@ void SerializeMirrors(FSerializer& arc)
.Array("mirror", mirror, countof(mirror))
.EndObject();
}
if (arc.isReading())
{
tileDelete(504);
for (int i = 0; i < 16; i++)
{
tileDelete(4080 + i);
}
}
}
END_BLD_NS

View file

@ -155,7 +155,7 @@ void viewInit(void)
lensTable[i] = LittleLong(lensTable[i]);
}
#endif
uint8_t* data = TileFiles.tileGet(4077);
uint8_t* data = tileData(4077);
memset(data, TRANSPARENT_INDEX, kLensSize * kLensSize);
for (int i = 0; i < 16; i++)

View file

@ -34,6 +34,51 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
BEGIN_DUKE_NS
//==========================================================================
//
//
//==========================================================================
void tileCopySection(int tilenum1, int sx1, int sy1, int xsiz, int ysiz, int tilenum2, int sx2, int sy2)
{
int xsiz1 = tileWidth(tilenum1);
int ysiz1 = tileHeight(tilenum1);
int xsiz2 = tileWidth(tilenum2);
int ysiz2 = tileHeight(tilenum2);
if (xsiz1 > 0 && ysiz1 > 0 && xsiz2 > 0 && ysiz2 > 0)
{
auto p1 = tilePtr(tilenum1);
auto p2 = tileData(tilenum2);
if (p2 == nullptr) return; // Error: Destination is not writable.
int x1 = sx1;
int x2 = sx2;
for (int i = 0; i < xsiz; i++)
{
int y1 = sy1;
int y2 = sy2;
for (int j = 0; j < ysiz; j++)
{
if (x2 >= 0 && y2 >= 0 && x2 < xsiz2 && y2 < ysiz2)
{
auto src = p1[x1 * ysiz1 + y1];
if (src != TRANSPARENT_INDEX)
p2[x2 * ysiz2 + y2] = src;
}
y1++;
y2++;
if (y1 >= ysiz1) y1 = 0;
}
x1++;
x2++;
if (x1 >= xsiz1) x1 = 0;
}
}
}
void updatepindisplay(int tag, int pins)
{
static const uint8_t pinx[] = { 64, 56, 72, 48, 64, 80, 40, 56, 72, 88 };
@ -41,11 +86,12 @@ void updatepindisplay(int tag, int pins)
if (tag < 1 || tag > 4) return;
tag += RTILE_BOWLINGLANE1 - 1;
if (TileFiles.tileMakeWritable(tag))
if (tileData(tag))
{
tileCopySection(RTILE_LANEPICBG, 0, 0, 128, 64, tag, 0, 0);
for (int i = 0; i < 10; i++) if (pins & (1 << i))
tileCopySection(RTILE_LANEPICS, 0, 0, 8, 8, tag, pinx[i] - 4, piny[i] - 10);
tileCopySection(RTILE_LANEPICS, 0, 0, 8, 8, tag, pinx[i] - 4, piny[i] - 10);
TileFiles.InvalidateTile(tag);
}
}

View file

@ -23,9 +23,9 @@ struct GameInterface : public ::GameInterface
{
const char* Name() override { return "Duke"; }
void app_init() override;
void loadPalette();
void LoadGameTextures();
void loadPalette() override;
void LoadGameTextures() override;
void SetupSpecialTextures() override;
void clearlocalinputstate() override;
bool GenerateSavePic() override;
void PlayHudSound() override;

View file

@ -279,16 +279,6 @@ static void setupbackdrop()
//
//---------------------------------------------------------------------------
static void initTiles()
{
tileDelete(TILE_MIRROR);
if (isRR())
tileDelete(0);
tileDelete(FOF);
}
#define x(a, b) registerName(#a, b);
#define y(a, b) registerName(#a, b);
static void SetTileNames()
@ -314,6 +304,29 @@ void GameInterface::LoadGameTextures()
SetTileNames();
}
void GameInterface::SetupSpecialTextures()
{
// set up all special tiles here, before we fully hook up with the texture manager.
tileDelete(FOF); // portal marker
if (!isRR())
{
tileDelete(560); // the mirror tile.
TileFiles.MakeCanvas(TILE_VIEWSCR, tileWidth(502), tileHeight(502));
}
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.
}
TileFiles.lock(); // from this point on the tile<->texture associations may not change anymore.
}
void GameInterface::loadPalette()
{
@ -376,7 +389,6 @@ void GameInterface::app_init()
//Net_SendClientInfo();
initTiles();
setupbackdrop();
SetupGameButtons();
InitCheats();

View file

@ -67,7 +67,7 @@ BEGIN_DUKE_NS
void GameInterface::UpdateCameras(double smoothratio)
{
const int VIEWSCREEN_ACTIVE_DISTANCE = 512;
const int VIEWSCREEN_ACTIVE_DISTANCE = 1024;
if (camsprite == nullptr)
return;
@ -78,7 +78,6 @@ 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);
TileFiles.MakeCanvas(TILE_VIEWSCR, (int)tex->GetDisplayWidth(), (int)tex->GetDisplayHeight());
auto canvas = tileGetCanvas(TILE_VIEWSCR);
if (!canvas) return;

View file

@ -112,10 +112,10 @@ void menu_DoPlasma()
if (!PlasmaBuffer)
{
auto pixels = TileFiles.tileCreate(kTile4092, kPlasmaWidth, kPlasmaHeight);
auto pixels = tileData(kTile4092);
memset(pixels, 96, kPlasmaWidth * kPlasmaHeight);
PlasmaBuffer = TileFiles.tileCreate(kTile4093, kPlasmaWidth, kPlasmaHeight);
PlasmaBuffer = tileData(kTile4093);
memset(PlasmaBuffer, 96, kPlasmaWidth * kPlasmaHeight);
@ -437,10 +437,9 @@ void uploadCinemaPalettes()
static int DoStatic(int a, int b)
{
TileFiles.tileMakeWritable(kTileLoboLaptop);
auto tex = dynamic_cast<FRestorableTile*>(tileGetTexture(kTileLoboLaptop)->GetTexture()->GetImage());
if (tex) tex->Reload();
auto pixels = TileFiles.tileMakeWritable(kTileLoboLaptop);
auto pixels = tileData(kTileLoboLaptop);
int y = 160 - a / 2;
int left = 81 - b / 2;

View file

@ -236,7 +236,7 @@ void DrawClock()
{
int ebp = 49;
auto pixels = TileFiles.tileMakeWritable(kTile3603);
auto pixels = tileData(kTile3603);
memset(pixels, TRANSPARENT_INDEX, 4096);
@ -549,6 +549,21 @@ void GameInterface::LoadGameTextures()
SetTileNames();
}
void GameInterface::SetupSpecialTextures()
{
TileFiles.tileCreate(kTile4092, kPlasmaWidth, kPlasmaHeight);
TileFiles.tileCreate(kTile4093, kPlasmaWidth, kPlasmaHeight);
TileFiles.tileCreate(kTileRamsesWorkTile, kSpiritY * 2, kSpiritX * 2);
TileFiles.tileMakeWritable(kTileLoboLaptop);
for(int i = kTile3603; i < kClockSymbol1 + 145; i++)
TileFiles.tileMakeWritable(kTile3603);
TileFiles.tileMakeWritable(kEnergy1);
TileFiles.tileMakeWritable(kEnergy2);
for (int i = 0; i < 16; i++)
TileFiles.tileMakeWritable(kClockSymbol1);
TileFiles.lock();
}
//---------------------------------------------------------------------------
//
//
@ -615,7 +630,7 @@ void CopyTileToBitmap(int nSrcTile, int nDestTile, int xPos, int yPos)
{
int nOffs = tileHeight(nDestTile) * xPos;
auto pixels = TileFiles.tileMakeWritable(nDestTile);
auto pixels = tileData(nDestTile);
uint8_t *pDest = pixels + nOffs + yPos;
uint8_t *pDestB = pDest;

View file

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

View file

@ -93,8 +93,8 @@ void DoEnergyTile()
{
nButtonColor += nButtonColor < 0 ? 8 : 0;
auto energy1 = TileFiles.tileMakeWritable(kEnergy1);
auto energy2 = TileFiles.tileMakeWritable(kEnergy2);
auto energy1 = tileData(kEnergy1);
auto energy2 = tileData(kEnergy2);
uint8_t* ptr1 = energy1 + 1984;
uint8_t* ptr2 = energy1 + 2048;

View file

@ -121,7 +121,7 @@ void InitSpiritHead()
nHeadStage = 0;
// work tile is twice as big as the normal head size
Worktile = TileFiles.tileCreate(kTileRamsesWorkTile, kSpiritY * 2, kSpiritX * 2);
Worktile = tileData(kTileRamsesWorkTile);
pSpiritSpr->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE;

View file

@ -225,6 +225,16 @@ void GameInterface::LoadGameTextures()
SetTileNames();
}
void GameInterface::SetupSpecialTextures()
{
tileDelete(MIRROR); // mirror
for (int i = 0; i < MAXMIRRORS; i++)
{
tileDelete(i + MIRRORLABEL);
TileFiles.MakeCanvas(CAMSPRITE + i, 128, 114);
}
TileFiles.lock();
}
//---------------------------------------------------------------------------
//
//

View file

@ -1657,8 +1657,9 @@ struct GameInterface : public ::GameInterface
{
const char* Name() override { return "ShadowWarrior"; }
void app_init() override;
void LoadGameTextures();
void loadPalette();
void LoadGameTextures() override;
void SetupSpecialTextures() override;
void loadPalette() override;
void clearlocalinputstate() override;
void FreeLevelData() override;
bool GenerateSavePic() override;

View file

@ -261,12 +261,10 @@ void JS_InitMirrors(void)
// Scan wall tags for mirrors
mirrorcnt = 0;
tileDelete(MIRROR);
oscilationclock = I_GetBuildTime();
for (i = 0; i < MAXMIRRORS; i++)
{
tileDelete(i + MIRRORLABEL);
mirror[i].campic = -1;
mirror[i].camspriteActor = nullptr;
mirror[i].cameraActor = nullptr;
@ -348,10 +346,6 @@ void JS_InitMirrors(void)
{
mirror[mirrorcnt].campic = itActor->spr.picnum;
mirror[mirrorcnt].camspriteActor = itActor;
// JBF: commenting out this line results in the screen in $BULLET being visible
tileDelete(mirror[mirrorcnt].campic);
Found_Cam = true;
}
}
@ -603,7 +597,6 @@ void JS_DrawCameras(PLAYER* pp, const DVector3& campos, double smoothratio)
// Set up the tile for drawing
TileFiles.MakeCanvas(mirror[cnt].campic, 128, 114);
{
if (dist < MAXCAMDIST)