Skip to content

Commit

Permalink
Added shared .MIF layer decode function.
Browse files Browse the repository at this point in the history
  • Loading branch information
afritz1 committed Dec 21, 2024
1 parent 7d4b81c commit 97dffef
Showing 1 changed file with 35 additions and 80 deletions.
115 changes: 35 additions & 80 deletions OpenTESArena/src/Assets/MIFFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,38 @@ namespace
{ Tag_MAP1, MIFLevel::loadMAP1 },
{ Tag_MAP2, MIFLevel::loadMAP2 }
};

uint16_t DecodeMifLayer(const uint8_t *tagStart, WEInt levelWidth, SNInt levelDepth, Buffer2D<ArenaTypes::VoxelID> &outLayer)
{
// Compressed size is in chunks and contains a 2 byte decompressed length after it, which
// should not be included when determining the end of the compressed range.
const uint16_t compressedSize = Bytes::getLE16(tagStart + 4);
const uint16_t uncompressedSize = Bytes::getLE16(tagStart + 6);

// Allocate space for this floor, using 2 bytes per voxel. Note: this seems to be more
// space than the level can fit.
std::vector<uint8_t> decomp(uncompressedSize, 0);

// Decode the data with type 8 decompression.
const uint8_t *tagDataStart = tagStart + 8;
const uint8_t *tagDataEnd = tagStart + 6 + compressedSize;
Compression::decodeType08(tagDataStart, tagDataEnd, decomp);

// Write into 16-bit map voxels in little-endian.
outLayer.init(levelWidth, levelDepth);
for (SNInt z = 0; z < levelDepth; z++)
{
for (WEInt x = 0; x < levelWidth; x++)
{
const int srcIndex = (x + (z * levelWidth)) * sizeof(ArenaTypes::VoxelID);
DebugAssertIndex(decomp, srcIndex);
const ArenaTypes::VoxelID srcValue = Bytes::getLE16(decomp.data() + srcIndex);
outLayer.set(x, z, srcValue);
}
}

return compressedSize + 6;
}
}

MIFLevel::MIFLevel()
Expand Down Expand Up @@ -120,94 +152,17 @@ int MIFLevel::loadFLAT(MIFLevel &level, const uint8_t *tagStart)

int MIFLevel::loadFLOR(MIFLevel &level, const uint8_t *tagStart, WEInt levelWidth, SNInt levelDepth)
{
// Compressed size is in chunks and contains a 2 byte decompressed length after it, which
// should not be included when determining the end of the compressed range.
const uint16_t compressedSize = Bytes::getLE16(tagStart + 4);
const uint16_t uncompressedSize = Bytes::getLE16(tagStart + 6);

// Allocate space for this floor, using 2 bytes per voxel. Note: this seems to be more
// space than the level can fit.
std::vector<uint8_t> decomp(uncompressedSize, 0);

// Decode the data with type 8 decompression.
const uint8_t *tagDataStart = tagStart + 8;
const uint8_t *tagDataEnd = tagStart + 6 + compressedSize;
Compression::decodeType08(tagDataStart, tagDataEnd, decomp);

// Write into 16-bit map voxels in little-endian.
level.flor.init(levelWidth, levelDepth);
for (SNInt z = 0; z < levelDepth; z++)
{
for (WEInt x = 0; x < levelWidth; x++)
{
const int srcIndex = (x + (z * levelWidth)) * sizeof(ArenaTypes::VoxelID);
DebugAssertIndex(decomp, srcIndex);
const ArenaTypes::VoxelID srcValue = Bytes::getLE16(decomp.data() + srcIndex);
level.flor.set(x, z, srcValue);
}
}

return compressedSize + 6;
return DecodeMifLayer(tagStart, levelWidth, levelDepth, level.flor);
}

int MIFLevel::loadMAP1(MIFLevel &level, const uint8_t *tagStart, WEInt levelWidth, SNInt levelDepth)
{
const uint16_t compressedSize = Bytes::getLE16(tagStart + 4);
const uint16_t uncompressedSize = Bytes::getLE16(tagStart + 6);

// Allocate space for this floor, using 2 bytes per voxel. Note: this seems to be more
// space than the level can fit.
std::vector<uint8_t> decomp(uncompressedSize, 0);

// Decode the data with type 8 decompression.
const uint8_t *tagDataStart = tagStart + 8;
const uint8_t *tagDataEnd = tagStart + 6 + compressedSize;
Compression::decodeType08(tagDataStart, tagDataEnd, decomp);

// Write into 16-bit map voxels in little-endian.
level.map1.init(levelWidth, levelDepth);
for (SNInt z = 0; z < levelDepth; z++)
{
for (WEInt x = 0; x < levelWidth; x++)
{
const int srcIndex = (x + (z * levelWidth)) * sizeof(ArenaTypes::VoxelID);
DebugAssertIndex(decomp, srcIndex);
const ArenaTypes::VoxelID srcValue = Bytes::getLE16(decomp.data() + srcIndex);
level.map1.set(x, z, srcValue);
}
}

return compressedSize + 6;
return DecodeMifLayer(tagStart, levelWidth, levelDepth, level.map1);
}

int MIFLevel::loadMAP2(MIFLevel &level, const uint8_t *tagStart, WEInt levelWidth, SNInt levelDepth)
{
const uint16_t compressedSize = Bytes::getLE16(tagStart + 4);
const uint16_t uncompressedSize = Bytes::getLE16(tagStart + 6);

// Allocate space for this floor, using 2 bytes per voxel. Note: this seems to be more
// space than the level can fit.
std::vector<uint8_t> decomp(uncompressedSize, 0);

// Decode the data with type 8 decompression.
const uint8_t *tagDataStart = tagStart + 8;
const uint8_t *tagDataEnd = tagStart + 6 + compressedSize;
Compression::decodeType08(tagDataStart, tagDataEnd, decomp);

// Write into 16-bit map voxels in little-endian.
level.map2.init(levelWidth, levelDepth);
for (SNInt z = 0; z < levelDepth; z++)
{
for (WEInt x = 0; x < levelWidth; x++)
{
const int srcIndex = (x + (z * levelWidth)) * sizeof(ArenaTypes::VoxelID);
DebugAssertIndex(decomp, srcIndex);
const ArenaTypes::VoxelID srcValue = Bytes::getLE16(decomp.data() + srcIndex);
level.map2.set(x, z, srcValue);
}
}

return compressedSize + 6;
return DecodeMifLayer(tagStart, levelWidth, levelDepth, level.map2);
}

int MIFLevel::loadINFO(MIFLevel &level, const uint8_t *tagStart)
Expand Down

0 comments on commit 97dffef

Please sign in to comment.