Browse Source

Efficiently pack re-encoded level cel blocks

pull/7856/head
staphen 1 year ago committed by Anders Jenbo
parent
commit
729c794f7a
  1. 6
      Source/levels/gendung.cpp
  2. 17
      Source/levels/reencode_dun_cels.cpp
  3. 10
      Source/levels/reencode_dun_cels.hpp

6
Source/levels/gendung.cpp

@ -524,11 +524,12 @@ void SetDungeonMicros()
uint16_t *pieces = &levelPieces[blocks * levelPieceId];
for (uint32_t block = 0; block < blocks; block++) {
const LevelCelBlock levelCelBlock { SDL_SwapLE16(pieces[blocks - 2 + (block & 1) - (block & 0xE)]) };
DPieceMicros[levelPieceId].mt[block] = levelCelBlock;
LevelCelBlock &mt = DPieceMicros[levelPieceId].mt[block];
mt = levelCelBlock;
if (levelCelBlock.hasValue()) {
if (const auto it = frameToTypeMap.find(levelCelBlock.frame()); it == frameToTypeMap.end()) {
frameToTypeMap.emplace_hint(it, levelCelBlock.frame(),
DunFrameInfo { static_cast<uint8_t>(block), levelCelBlock.type(), SOLData[levelPieceId] });
DunFrameInfo { static_cast<uint8_t>(block), levelCelBlock.type(), SOLData[levelPieceId], &mt.data });
}
}
}
@ -538,6 +539,7 @@ void SetDungeonMicros()
return a.first < b.first;
});
ReencodeDungeonCels(pDungeonCels, frameToTypeList);
ReindexCelBlocks(frameToTypeList);
}
void DRLG_InitTrans()

17
Source/levels/reencode_dun_cels.cpp

@ -252,9 +252,11 @@ void ReencodeDungeonCels(std::unique_ptr<std::byte[]> &dungeonCels, std::span<st
std::unique_ptr<std::byte[]> result { new std::byte[outSize] };
auto *const resultPtr = reinterpret_cast<uint8_t *>(result.get());
WriteLE32(resultPtr, static_cast<uint32_t>(frames.size()));
uint8_t *lookup = resultPtr + 4;
uint8_t *out = resultPtr + (2 + frames.size()) * 4; // number of frames, frame offsets, file size
for (const auto &[frame, info] : frames) {
WriteLE32(&resultPtr[static_cast<size_t>(frame * 4)], static_cast<uint32_t>(out - resultPtr));
WriteLE32(lookup, static_cast<uint32_t>(out - resultPtr));
lookup += 4;
const uint32_t srcFrameBegin = SDL_SwapLE32(srcOffsets[frame]);
const uint8_t *src = &srcData[srcFrameBegin];
switch (info.type) {
@ -288,7 +290,7 @@ void ReencodeDungeonCels(std::unique_ptr<std::byte[]> &dungeonCels, std::span<st
break;
}
}
WriteLE32(&resultPtr[(1 + frames.size()) * 4], static_cast<uint32_t>(outSize));
WriteLE32(lookup, static_cast<uint32_t>(outSize));
const auto *dstOffsets = reinterpret_cast<const uint32_t *>(resultPtr);
LogVerbose(" Re-encoded dungeon CELs: {} frames, {} bytes. Extracted {} foliage tiles.",
@ -299,4 +301,15 @@ void ReencodeDungeonCels(std::unique_ptr<std::byte[]> &dungeonCels, std::span<st
dungeonCels = std::move(result);
}
void ReindexCelBlocks(std::span<std::pair<uint16_t, DunFrameInfo>> frames)
{
uint16_t lastFrameIndex = 0;
uint16_t adjustment = 0;
for (auto &[frame, info] : frames) {
adjustment += frame - lastFrameIndex - 1;
lastFrameIndex = frame;
*info.celBlockData -= adjustment;
}
}
} // namespace devilution

10
Source/levels/reencode_dun_cels.hpp

@ -17,6 +17,8 @@ struct DunFrameInfo {
TileType type;
TileProperties properties;
uint16_t *celBlockData;
[[nodiscard]] bool isFloor() const
{
// The BlockMissile check is for stairs in L3 and L4, e.g. tile 46 sub-tile 141 frame 386 in L4.
@ -36,4 +38,12 @@ struct DunFrameInfo {
*/
void ReencodeDungeonCels(std::unique_ptr<std::byte[]> &dungeonCels, std::span<std::pair<uint16_t, DunFrameInfo>> frames);
/**
* @brief Adjusts frame indexes in cel block data.
*
* Re-encoding the dungeon cels removes frames that are not referenced.
* Indexes must also be adjusted to avoid errors when doing lookups.
*/
void ReindexCelBlocks(std::span<std::pair<uint16_t, DunFrameInfo>> frames);
} // namespace devilution

Loading…
Cancel
Save