mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2024-11-28 00:54:23 +01:00
Add 2BPP helper functions for our blocks.
Namely, there are two things that we need to do: 1. Figure out the sub-mode based on the mode bit and the structure of the modulation data. The comments in Block.h describe how we do this. 2. For a given texel index, return 2BPP texel modulation bits.
This commit is contained in:
parent
08cad3ba86
commit
1115c2f9e4
@ -109,4 +109,40 @@ namespace PVRTCC {
|
||||
return (m_LongData >> (texelIdx * 2)) & 0x3;
|
||||
}
|
||||
|
||||
Block::E2BPPSubMode Block::Get2BPPSubMode() const {
|
||||
uint8 first = GetLerpValue(0);
|
||||
if(!(first & 0x1)) {
|
||||
return e2BPPSubMode_All;
|
||||
}
|
||||
|
||||
uint8 center = GetLerpValue(10);
|
||||
if(center & 0x1) {
|
||||
return e2BPPSubMode_Vertical;
|
||||
}
|
||||
|
||||
return e2BPPSubMode_Horizontal;
|
||||
}
|
||||
|
||||
uint8 Block::Get2BPPLerpValue(uint32 texelIdx) const {
|
||||
|
||||
if(!(GetModeBit())) {
|
||||
assert(texelIdx >= 0);
|
||||
assert(texelIdx < 32);
|
||||
return static_cast<uint8>((m_LongData >> texelIdx) & 0x1);
|
||||
}
|
||||
|
||||
bool firstBitOnly = false;
|
||||
if(texelIdx == 0 ||
|
||||
(texelIdx == 10 && Get2BPPSubMode() != e2BPPSubMode_All)) {
|
||||
firstBitOnly = true;
|
||||
}
|
||||
|
||||
uint8 ret = GetLerpValue(texelIdx);
|
||||
if(firstBitOnly) {
|
||||
// Change 0, 1 => 0 and 2, 3 => 3
|
||||
ret = (ret & 0x2) | ((ret >> 1) & 0x1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // namespace PVRTCC
|
||||
|
@ -70,6 +70,29 @@ class Block {
|
||||
return static_cast<bool>((m_LongData >> 32) & 0x1);
|
||||
}
|
||||
|
||||
// For 2BPP PVRTC, if the mode bit is set, then we use the modulation data
|
||||
// as 2 bits for every other texel in the 8x4 block in a checkerboard pattern.
|
||||
// The interleaved texel data is decided by averaging nearby texel modulation
|
||||
// values. There are three different ways to average nearby texels: Either we
|
||||
// average the neighboring horizontal or vertical pixels using (a + b) / 2, or
|
||||
// we neighbor all four neighbors using (a + b + c + d + 1) / 4.
|
||||
enum E2BPPSubMode {
|
||||
e2BPPSubMode_All,
|
||||
e2BPPSubMode_Horizontal,
|
||||
e2BPPSubMode_Vertical
|
||||
};
|
||||
|
||||
// For 2BPP PVRTC, this function determines the submode of the given block. The
|
||||
// submode is determined by first checking the first 2bit texel index. This texel
|
||||
// uses the high bit as a 1 bit modulation value (i.e. chooses colors A or B) and
|
||||
// the low bit is used to determine the sub-mode. If the low bit is 0, then we
|
||||
// will use e2BPPSubMode_All as defined above. If the low bit is 1, then we must
|
||||
// look at the center texel (index 10) to determine the sub-mode. In this case,
|
||||
// we treat the center texel as 1 bit modulation as well, and we use the low bit to
|
||||
// determine the sub-mode where 0 is e2BPPSubMode_Horizontal and 1 is
|
||||
// e2BPPSubMode_Vertical
|
||||
E2BPPSubMode Get2BPPSubMode() const;
|
||||
|
||||
// Returns the modulation value for the texel in the 4x4 block. The texels are
|
||||
// numbered as follows:
|
||||
// 0 1 2 3
|
||||
@ -78,6 +101,15 @@ class Block {
|
||||
// 12 13 14 15
|
||||
uint8 GetLerpValue(uint32 texelIdx) const;
|
||||
|
||||
// This returns the modulation value for the texel in the block interpreted as
|
||||
// 2BPP. If the modulation bit is not set, then it expects a number from 0-31
|
||||
// and does the same operation as GetLerpValue. If the modulation bit is set,
|
||||
// then this function expects a number from 0-15 and returns the corresponding
|
||||
// modulation bits given the sub-mode. Note, this function does not do the
|
||||
// averaging described for E2BPPSubMode because this averaging relies on
|
||||
// global information.
|
||||
uint8 Get2BPPLerpValue(uint32 texelIdx) const;
|
||||
|
||||
private:
|
||||
union {
|
||||
uint8 m_ByteData[8];
|
||||
|
@ -185,3 +185,54 @@ TEST(Block, GetLerpValue) {
|
||||
EXPECT_EQ(b.GetLerpValue(14), 1);
|
||||
EXPECT_EQ(b.GetLerpValue(15), 0);
|
||||
}
|
||||
|
||||
TEST(Block, Get2BPPLerpValue) {
|
||||
uint8 noModData[8] = { 0xDA, 0x27, 0xE4, 0x1B, 0x0, 0x0, 0x0, 0x0 };
|
||||
PVRTCC::Block b(noModData);
|
||||
|
||||
uint32 dataInt = *(reinterpret_cast<const uint32 *>(noModData));
|
||||
for(uint32 i = 0; i < 32; i++) {
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(i), (dataInt >> i) & 0x1);
|
||||
}
|
||||
|
||||
uint8 modData[8];
|
||||
memcpy(modData, noModData, sizeof(modData));
|
||||
modData[4] = 0x1;
|
||||
|
||||
b = PVRTCC::Block(modData);
|
||||
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(0), 3);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(1), 2);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(2), 1);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(3), 3);
|
||||
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(4), 3);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(5), 1);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(6), 2);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(7), 0);
|
||||
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(8), 0);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(9), 1);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(10), 2);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(11), 3);
|
||||
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(12), 3);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(13), 2);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(14), 1);
|
||||
EXPECT_EQ(b.Get2BPPLerpValue(15), 0);
|
||||
}
|
||||
|
||||
TEST(Block, Get2BPPSubMode) {
|
||||
uint8 data[8] = { 0xDA, 0x27, 0xE4, 0x1B, 0x1, 0x0, 0x0, 0x0 };
|
||||
PVRTCC::Block b(data);
|
||||
|
||||
EXPECT_EQ(b.Get2BPPSubMode(), PVRTCC::Block::e2BPPSubMode_All);
|
||||
|
||||
data[0] = 0xDB;
|
||||
b = PVRTCC::Block(data);
|
||||
EXPECT_EQ(b.Get2BPPSubMode(), PVRTCC::Block::e2BPPSubMode_Horizontal);
|
||||
|
||||
data[2] = 0xF4;
|
||||
b = PVRTCC::Block(data);
|
||||
EXPECT_EQ(b.Get2BPPSubMode(), PVRTCC::Block::e2BPPSubMode_Vertical);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user