mirror of
https://github.com/open-goal/jak-project
synced 2026-05-23 06:54:31 -04:00
b7fe8447e2
* clean up * restore hack
203 lines
7.3 KiB
C++
203 lines
7.3 KiB
C++
#include "TextureConverter.h"
|
|
#include "common/util/assert.h"
|
|
#include "third-party/fmt/core.h"
|
|
#include "common/util/FileUtil.h"
|
|
#include "common/texture/texture_conversion.h"
|
|
|
|
TextureConverter::TextureConverter() {
|
|
m_vram.resize(4 * 1024 * 1024);
|
|
}
|
|
|
|
void TextureConverter::upload(const u8* data, u32 dest, u32 size_vram_words) {
|
|
// all textures are copied to vram 128 pixels wide, regardless of actual width
|
|
int copy_width = 128;
|
|
// scale the copy height to be whatever it needs to be to transfer the right amount of data.
|
|
int copy_height = size_vram_words / copy_width;
|
|
|
|
for (int y = 0; y < copy_height; y++) {
|
|
for (int x = 0; x < copy_width; x++) {
|
|
// VRAM address (bytes)
|
|
auto addr32 = psmct32_addr(x, y, copy_width) + dest * 4;
|
|
*(u32*)(m_vram.data() + addr32) = *((const u32*)(data) + (x + y * copy_width));
|
|
}
|
|
}
|
|
}
|
|
|
|
void TextureConverter::download_rgba8888(u8* result,
|
|
u32 vram_addr,
|
|
u32 goal_tex_width,
|
|
u32 w,
|
|
u32 h,
|
|
u32 psm,
|
|
u32 clut_psm,
|
|
u32 clut_vram_addr,
|
|
u32 expected_size_bytes) {
|
|
u32 out_offset = 0;
|
|
if (psm == int(PSM::PSMT8) && clut_psm == int(CPSM::PSMCT32)) {
|
|
// width is like the TEX0 register, in 64 texel units.
|
|
// not sure what the other widths are yet.
|
|
int read_width = 64 * goal_tex_width;
|
|
// loop over pixels in output texture image
|
|
for (u32 y = 0; y < h; y++) {
|
|
for (u32 x = 0; x < w; x++) {
|
|
// read as the PSMT8 type. The dest field tells us a block offset.
|
|
auto addr8 = psmt8_addr(x, y, read_width) + vram_addr * 256;
|
|
u8 value = *(u8*)(m_vram.data() + addr8);
|
|
|
|
// there's yet another scramble from the CLUT. The palette index turns into an X, Y value
|
|
// See GS manual 2.7.3 CLUT Storage Mode, IDTEX8 in CSM1 mode.
|
|
u32 clut_chunk = value / 16;
|
|
u32 off_in_chunk = value % 16;
|
|
u8 clx = 0, cly = 0;
|
|
if (clut_chunk & 1) {
|
|
clx = 8;
|
|
}
|
|
cly = (clut_chunk >> 1) * 2;
|
|
if (off_in_chunk >= 8) {
|
|
off_in_chunk -= 8;
|
|
cly++;
|
|
}
|
|
clx += off_in_chunk;
|
|
|
|
// the x, y CLUT value is looked up in PSMCT32 mode
|
|
u32 clut_addr = psmct32_addr(clx, cly, 64) + clut_vram_addr * 256;
|
|
u32 clut_value = *(u32*)(m_vram.data() + clut_addr);
|
|
memcpy(result + out_offset, &clut_value, 4);
|
|
out_offset += 4;
|
|
}
|
|
}
|
|
|
|
} else if (psm == int(PSM::PSMT8) && clut_psm == int(CPSM::PSMCT16)) {
|
|
// width is like the TEX0 register, in 64 texel units.
|
|
// not sure what the other widths are yet.
|
|
int read_width = 64 * goal_tex_width;
|
|
|
|
// loop over pixels in output texture image
|
|
for (u32 y = 0; y < h; y++) {
|
|
for (u32 x = 0; x < w; x++) {
|
|
// read as the PSMT8 type. The dest field tells us a block offset.
|
|
auto addr8 = psmt8_addr(x, y, read_width) + vram_addr * 256;
|
|
u8 value = *(u8*)(m_vram.data() + addr8);
|
|
|
|
// there's yet another scramble from the CLUT. The palette index turns into an X, Y value
|
|
// See GS manual 2.7.3 CLUT Storage Mode, IDTEX8 in CSM1 mode.
|
|
u32 clut_chunk = value / 16;
|
|
u32 off_in_chunk = value % 16;
|
|
u8 clx = 0, cly = 0;
|
|
if (clut_chunk & 1) {
|
|
clx = 8;
|
|
}
|
|
cly = (clut_chunk >> 1) * 2;
|
|
if (off_in_chunk >= 8) {
|
|
off_in_chunk -= 8;
|
|
cly++;
|
|
}
|
|
clx += off_in_chunk;
|
|
|
|
// the x, y CLUT value is looked up in PSMCT32 mode
|
|
u32 clut_addr = psmct16_addr(clx, cly, 64) + clut_vram_addr * 256;
|
|
u32 clut_value = *(u16*)(m_vram.data() + clut_addr);
|
|
u32 rgba32 = rgba16_to_rgba32(clut_value);
|
|
memcpy(result + out_offset, &rgba32, 4);
|
|
out_offset += 4;
|
|
}
|
|
}
|
|
|
|
} else if (psm == int(PSM::PSMT4) && clut_psm == int(CPSM::PSMCT16)) {
|
|
// width is like the TEX0 register, in 64 texel units.
|
|
// not sure what the other widths are yet.
|
|
int read_width = 64 * goal_tex_width;
|
|
|
|
// loop over pixels in output texture image
|
|
for (u32 y = 0; y < h; y++) {
|
|
for (u32 x = 0; x < w; x++) {
|
|
// read as the PSMT4 type, use half byte addressing
|
|
auto addr4 = psmt4_addr_half_byte(x, y, read_width) + vram_addr * 512;
|
|
|
|
// read (half bytes)
|
|
u8 value = *(u8*)(m_vram.data() + addr4 / 2);
|
|
if (addr4 & 1) {
|
|
value >>= 4;
|
|
} else {
|
|
value = value & 0x0f;
|
|
}
|
|
|
|
// there's yet another scramble from the CLUT. The palette index turns into an X, Y value
|
|
// See GS manual 2.7.3 CLUT Storage Mode, IDTEX4 in CSM1 mode.
|
|
|
|
u8 clx = value & 0x7;
|
|
u8 cly = value >> 3;
|
|
|
|
// the x, y CLUT value is looked up in PSMCT16 mode
|
|
u32 clut_addr = psmct16_addr(clx, cly, 64) + clut_vram_addr * 256;
|
|
u32 clut_value = *(u16*)(m_vram.data() + clut_addr);
|
|
u32 rgba32 = rgba16_to_rgba32(clut_value);
|
|
memcpy(result + out_offset, &rgba32, 4);
|
|
out_offset += 4;
|
|
}
|
|
}
|
|
} else if (psm == int(PSM::PSMT4) && clut_psm == int(CPSM::PSMCT32)) {
|
|
// width is like the TEX0 register, in 64 texel units.
|
|
// not sure what the other widths are yet.
|
|
int read_width = 64 * goal_tex_width;
|
|
|
|
// loop over pixels in output texture image
|
|
for (u32 y = 0; y < h; y++) {
|
|
for (u32 x = 0; x < w; x++) {
|
|
// read as the PSMT4 type, use half byte addressing
|
|
auto addr4 = psmt4_addr_half_byte(x, y, read_width) + vram_addr * 512;
|
|
|
|
// read (half bytes)
|
|
u8 value = *(u8*)(m_vram.data() + addr4 / 2);
|
|
if (addr4 & 1) {
|
|
value >>= 4;
|
|
} else {
|
|
value = value & 0x0f;
|
|
}
|
|
|
|
// there's yet another scramble from the CLUT. The palette index turns into an X, Y value
|
|
// See GS manual 2.7.3 CLUT Storage Mode, IDTEX4 in CSM1 mode.
|
|
|
|
u8 clx = value & 0x7;
|
|
u8 cly = value >> 3;
|
|
|
|
// the x, y CLUT value is looked up in PSMCT16 mode
|
|
u32 clut_addr = psmct32_addr(clx, cly, 64) + clut_vram_addr * 256;
|
|
u32 clut_value = *(u32*)(m_vram.data() + clut_addr);
|
|
// fmt::print("{} {}\n", value, clut_value);
|
|
memcpy(result + out_offset, &clut_value, 4);
|
|
out_offset += 4;
|
|
}
|
|
}
|
|
} else if (psm == int(PSM::PSMCT16) && clut_psm == 0) {
|
|
// plain 16-bit texture
|
|
// not a clut.
|
|
// will store output pixels, rgba (8888)
|
|
|
|
// width is like the TEX0 register, in 64 texel units.
|
|
// not sure what the other widths are yet.
|
|
int read_width = 64 * goal_tex_width;
|
|
|
|
// loop over pixels in output texture image
|
|
for (u32 y = 0; y < h; y++) {
|
|
for (u32 x = 0; x < w; x++) {
|
|
// read as the PSMT8 type. The dest field tells us a block offset.
|
|
auto addr8 = psmct16_addr(x, y, read_width) + vram_addr * 256;
|
|
u16 value = *(u16*)(m_vram.data() + addr8);
|
|
u32 val32 = rgba16_to_rgba32(value);
|
|
memcpy(result + out_offset, &val32, 4);
|
|
out_offset += 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
else {
|
|
assert(false);
|
|
}
|
|
|
|
assert(out_offset == expected_size_bytes);
|
|
}
|
|
|
|
void TextureConverter::serialize(Serializer& ser) {
|
|
ser.from_pod_vector(&m_vram);
|
|
} |