jak-project/game/graphics/opengl_renderer/ocean/OceanMid.cpp
Hat Kid 3d08d079c9
jak2: ocean renderer (#2142)
Initial implementation of the `ocean-mid`, `ocean-far` and `ocean-near`
renderers for Jak 2.

There's still a few things to sort out, mainly:

- [x] ~Backwards compatibility with Jak 1. The only thing that currently
stands in the way of that is figuring out a clean way to "un-hardcode"
the texture base pointer in C++ without creating a completely separate
`OceanTexture` class for Jak 2. One thing I thought of would be
modifying `BucketRenderer`'s virtual `init_textures` method to also pass
the `GameVersion`, but I'm not sure if there's a better way.~
- [x] ~The sudden transition from `ocean-near` to `ocean-mid`. Not sure
why it's happening or how to fix it.~
- [x] The ocean has two new methods in Jak 2, `ocean::89` and
`ocean::79`, one of which seems to be related to time of day sky colors.
~Even without them implemented, the end result looks quite close, so we
may be able to skip them?~ `ocean::89` generates `ocean-mid` envmap
textures, so it will likely be required, but will not be handled right
now.

Reverted the VU prologue removals because it made the tests fail.
2023-01-22 18:07:46 -05:00

264 lines
8.7 KiB
C++

#include "OceanMid.h"
#include "common/log/log.h"
static bool is_end_tag(const DmaTag& tag, const VifCode& v0, const VifCode& v1) {
return tag.qwc == 2 && tag.kind == DmaTag::Kind::CNT && v0.kind == VifCode::Kind::NOP &&
v1.kind == VifCode::Kind::DIRECT;
}
OceanMid::OceanMid() {
for (auto& x : m_vu_data) {
x.fill(999.);
}
vu.vf25 = Vf(1, 1, 1, 1);
}
void OceanMid::run(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
m_common_ocean_renderer.init_for_mid();
// first is setting base and offset
{
auto base_offset_tag = dma.read_and_advance();
ASSERT(base_offset_tag.size_bytes == 0);
auto base = base_offset_tag.vifcode0();
ASSERT(base.kind == VifCode::Kind::BASE);
ASSERT(base.immediate == VU1_INPUT_BUFFER_BASE);
auto offset = base_offset_tag.vifcode1();
ASSERT(offset.kind == VifCode::Kind::OFFSET);
ASSERT(offset.immediate == VU1_INPUT_BUFFER_OFFSET);
}
// next is constants
{
auto constants = dma.read_and_advance();
ASSERT(constants.size_bytes == sizeof(Constants));
ASSERT(constants.vifcode0().kind == VifCode::Kind::STCYCL); // for whatever reason they do this
auto unpack = constants.vifcode1();
ASSERT(VifCodeUnpack(unpack).addr_qw == Vu1Data::CONSTANTS);
memcpy(&m_constants, constants.data, sizeof(Constants));
memcpy(m_vu_data + Vu1Data::CONSTANTS, &m_constants, sizeof(Constants));
}
// next is call 0
{
auto call0 = dma.read_and_advance();
ASSERT(call0.vifcode0().kind == VifCode::Kind::STCYCL);
auto c = call0.vifcode1();
ASSERT(c.kind == VifCode::Kind::MSCALF);
ASSERT(c.immediate == 0);
run_call0();
}
while (!is_end_tag(dma.current_tag(), dma.current_tag_vif0(), dma.current_tag_vif1())) {
auto data = dma.read_and_advance();
auto v0 = data.vifcode0();
auto v1 = data.vifcode1();
if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_32) {
auto up = VifCodeUnpack(v1);
// ASSERT(up.use_tops_flag);
u16 addr = up.addr_qw + (up.use_tops_flag ? get_upload_buffer() : 0);
ASSERT(addr + v1.num <= 1024);
memcpy(m_vu_data + addr, data.data, 16 * v1.num);
ASSERT(16 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
memcpy(m_vu_data + addr + i, temp, 16);
}
ASSERT(4 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x204 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
// cl = 4
// wl = 2
u32 addr_off = 4 * (i / 2) + i % 2;
memcpy(m_vu_data + addr + addr_off, temp, 16);
}
ASSERT(8 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::MSCALF) {
switch (v1.immediate) {
case 46:
run_call46_vu2c();
break;
case 73:
run_call73_vu2c();
break;
case 107:
run_call107_vu2c();
break;
case 275:
run_call275_vu2c();
break;
default:
lg::warn("unknown call1: {}", v1.immediate);
}
} else if (v0.kind == VifCode::Kind::MSCALF && v1.kind == VifCode::Kind::FLUSHA) {
switch (v0.immediate) {
case 41:
run_call41_vu2c();
break;
case 43:
run_call43_vu2c();
break;
default:
ASSERT_MSG(false, fmt::format("unknown call2: {}", v0.immediate));
}
} else {
ASSERT_MSG(false, fmt::format("{} {}", data.vifcode0().print(), data.vifcode1().print()));
}
}
m_common_ocean_renderer.flush_mid(render_state, prof);
}
void OceanMid::run_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
m_common_ocean_renderer.init_for_mid();
// first is setting base and offset
{
auto base_offset_tag = dma.read_and_advance();
ASSERT(base_offset_tag.size_bytes == 0);
auto base = base_offset_tag.vifcode0();
ASSERT(base.kind == VifCode::Kind::BASE);
ASSERT(base.immediate == VU1_INPUT_BUFFER_BASE);
auto offset = base_offset_tag.vifcode1();
ASSERT(offset.kind == VifCode::Kind::OFFSET);
ASSERT(offset.immediate == VU1_INPUT_BUFFER_OFFSET);
}
// next is constants
{
auto constants = dma.read_and_advance();
ASSERT(constants.size_bytes == sizeof(Constants));
ASSERT(constants.vifcode0().kind == VifCode::Kind::STCYCL); // for whatever reason they do this
auto unpack = constants.vifcode1();
ASSERT(VifCodeUnpack(unpack).addr_qw == Vu1Data::CONSTANTS);
memcpy(&m_constants, constants.data, sizeof(Constants));
memcpy(m_vu_data + Vu1Data::CONSTANTS, &m_constants, sizeof(Constants));
}
// next is call 0
{
auto call0 = dma.read_and_advance();
ASSERT(call0.vifcode0().kind == VifCode::Kind::STCYCL);
auto c = call0.vifcode1();
ASSERT(c.kind == VifCode::Kind::MSCALF);
ASSERT(c.immediate == 0);
run_call0();
}
while (!is_end_tag(dma.current_tag(), dma.current_tag_vif0(), dma.current_tag_vif1())) {
auto data = dma.read_and_advance();
auto v0 = data.vifcode0();
auto v1 = data.vifcode1();
if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_32) {
auto up = VifCodeUnpack(v1);
// ASSERT(up.use_tops_flag);
u16 addr = up.addr_qw + (up.use_tops_flag ? get_upload_buffer() : 0);
ASSERT(addr + v1.num <= 1024);
memcpy(m_vu_data + addr, data.data, 16 * v1.num);
ASSERT(16 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
memcpy(m_vu_data + addr + i, temp, 16);
}
ASSERT(4 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x204 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
// cl = 4
// wl = 2
u32 addr_off = 4 * (i / 2) + i % 2;
memcpy(m_vu_data + addr + addr_off, temp, 16);
}
ASSERT(8 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::MSCALF) {
switch (v1.immediate) {
case 46:
run_call46_vu2c();
break;
case 73:
run_call73_vu2c_jak2();
break;
case 107:
run_call107_vu2c_jak2();
break;
case 275:
run_call275_vu2c_jak2();
break;
default:
lg::warn("unknown call1: {}", v1.immediate);
}
} else if (v0.kind == VifCode::Kind::MSCALF && v1.kind == VifCode::Kind::FLUSHA) {
switch (v0.immediate) {
case 41:
run_call41_vu2c();
break;
case 43:
run_call43_vu2c();
break;
default:
ASSERT_MSG(false, fmt::format("unknown call2: {}", v0.immediate));
}
} else {
ASSERT_MSG(false, fmt::format("{} {}", data.vifcode0().print(), data.vifcode1().print()));
}
}
m_common_ocean_renderer.flush_mid(render_state, prof);
}
void OceanMid::run_call0() {
run_call0_vu2c();
}
void OceanMid::xgkick(u16 addr) {
m_common_ocean_renderer.kick_from_mid((const u8*)&m_vu_data[addr]);
}