[jak1] use etie (#2329)

Use Jak 2's etie to render shiny background things.

To switch back to the old one:
```
(set! *use-etie* #f)
```
and also uncheck this box

![image](https://user-images.githubusercontent.com/48171810/226119270-8d1b8233-bc5f-4bc1-a09b-a6d3183ba2a4.png)
(same for `l1`)
This commit is contained in:
water111 2023-03-20 19:12:33 -04:00 committed by GitHub
parent d1260a0c0b
commit f276251a3a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 285 additions and 144 deletions

View file

@ -94,8 +94,30 @@ std::array<math::Vector3f, 3> tie_normal_transform_v2(const std::array<math::Vec
auto& vf11 = m[1]; auto& vf11 = m[1];
// auto& vf12 = m[2]; // auto& vf12 = m[2];
// lui t6, 16256
// mtc1 f1, t6 ;; 1.0
//
// qmfc2.i s1, vf10
// mtc1 f12, s1
float f12 = vf10.x();
// dsra32 s2, s1, 0
// mtc1 f13, s2
float f13 = vf10.y();
// pextuw s2, r0, s2
// mtc1 f14, s2
float f14 = vf10.z();
// mula.s f12, f12
// madda.s f13, f13
// madd.s f15, f14, f14
float f15 = f12 * f12 + f13 * f13 + f14 * f14;
float scale = 1.f / sqrtf(f15);
// rsqrt.s f15, f1, f15
// mfc1 s1, f15
// qmtc2.i vf14, s1
// vmulx.xyz vf16, vf10, vf14
// vmulx.xyz vf16, vf10, vf14 // vmulx.xyz vf16, vf10, vf14
math::Vector3f vf16 = vf10.xyz() * 1.0; // TODO VF14 math::Vector3f vf16 = vf10.xyz() * scale;
// vopmula.xyz acc, vf11, vf16 // vopmula.xyz acc, vf11, vf16
math::Vector3f acc = vopmula(vf11.xyz(), vf16); math::Vector3f acc = vopmula(vf11.xyz(), vf16);

View file

@ -73,7 +73,7 @@ struct MemoryUsageTracker {
void add(MemoryUsageCategory category, u32 size_bytes) { data[category] += size_bytes; } void add(MemoryUsageCategory category, u32 size_bytes) { data[category] += size_bytes; }
}; };
constexpr int TFRAG3_VERSION = 28; constexpr int TFRAG3_VERSION = 29;
// These vertices should be uploaded to the GPU at load time and don't change // These vertices should be uploaded to the GPU at load time and don't change
struct PreloadedVertex { struct PreloadedVertex {

View file

@ -509,6 +509,13 @@ void TieFragment::read_from_file(TypedRef ref,
auto normals_data_ref = deref_label(get_field_ref(ref, "normal-ref", dts)); auto normals_data_ref = deref_label(get_field_ref(ref, "normal-ref", dts));
memcpy_plain_data((u8*)normals.data(), normals_data_ref, normals_qwc * 16); memcpy_plain_data((u8*)normals.data(), normals_data_ref, normals_qwc * 16);
} }
} else {
u16 generic_qwc = read_plain_data_field<u32>(ref, "generic-count", dts);
if (generic_qwc) {
generic_data.resize(16 * generic_qwc);
auto generic_data_ref = deref_label(get_field_ref(ref, "generic-ref", dts));
memcpy_plain_data((u8*)generic_data.data(), generic_data_ref, generic_qwc * 16);
}
} }
} }
@ -1056,22 +1063,23 @@ void PrototypeBucketTie::read_from_file(TypedRef ref,
time_of_day.colors.push_back(deref_u32(palette, 3 + i)); time_of_day.colors.push_back(deref_u32(palette, 3 + i));
} }
if (version > GameVersion::Jak1) { auto fr = get_field_ref(ref, "envmap-shader", dts);
auto fr = get_field_ref(ref, "envmap-shader", dts); const auto& word = fr.data->words_by_seg.at(fr.seg).at(fr.byte_offset / 4);
const auto& word = fr.data->words_by_seg.at(fr.seg).at(fr.byte_offset / 4); if (word.kind() == decompiler::LinkedWord::PTR) {
if (word.kind() == decompiler::LinkedWord::PTR) { has_envmap_shader = true;
has_envmap_shader = true; Ref envmap_shader_ref(deref_label(fr));
Ref envmap_shader_ref(deref_label(fr)); for (int i = 0; i < 5 * 16; i++) {
for (int i = 0; i < 5 * 16; i++) { int byte = envmap_shader_ref.byte_offset + i;
int byte = envmap_shader_ref.byte_offset + i; u8 val = ref.ref.data->words_by_seg.at(envmap_shader_ref.seg).at(byte / 4).get_byte(byte % 4);
u8 val = envmap_shader[i] = val;
ref.ref.data->words_by_seg.at(envmap_shader_ref.seg).at(byte / 4).get_byte(byte % 4);
envmap_shader[i] = val;
}
} }
}
if (version > GameVersion::Jak1) {
u32 tint = read_plain_data_field<u32>(ref, "tint-color", dts); u32 tint = read_plain_data_field<u32>(ref, "tint-color", dts);
memcpy(tint_color.data(), &tint, 4); memcpy(jak2_tint_color.data(), &tint, 4);
} else {
jak2_tint_color.fill(0xff);
} }
} }

View file

@ -407,7 +407,9 @@ struct TieFragment : public Drawable {
std::string debug_label_name; std::string debug_label_name;
std::vector<s8> normals; std::vector<s8> normals; // jak 2
std::vector<u8> generic_data; // jak 1
// todo, lots more // todo, lots more
}; };
@ -483,8 +485,8 @@ struct PrototypeBucketTie {
TimeOfDayPalette time_of_day; TimeOfDayPalette time_of_day;
bool has_envmap_shader = false; bool has_envmap_shader = false;
u8 envmap_shader[5 * 16]; // jak 2 only u8 envmap_shader[5 * 16];
math::Vector<u8, 4> tint_color; math::Vector<u8, 4> jak2_tint_color; // jak 2 only
// todo collide-frag // todo collide-frag
DrawableInlineArrayCollideFragment collide_frag; DrawableInlineArrayCollideFragment collide_frag;
// todo tie-colors // todo tie-colors

View file

@ -257,7 +257,6 @@ struct TieProtoVertex {
// the vertices make up a triangle strip // the vertices make up a triangle strip
struct TieStrip { struct TieStrip {
AdgifInfo adgif; AdgifInfo adgif;
int adgif_idx = -1;
std::vector<TieProtoVertex> verts; std::vector<TieProtoVertex> verts;
}; };
@ -283,6 +282,8 @@ struct TieFrag {
// after the prototype program runs // after the prototype program runs
std::unordered_map<u32, TieProtoVertex> vertex_by_dest_addr; std::unordered_map<u32, TieProtoVertex> vertex_by_dest_addr;
math::Vector<u8, 4> envmap_tint_color = math::Vector<u8, 4>::zero();
// simulate a load in the points data (using vu mem addr) // simulate a load in the points data (using vu mem addr)
math::Vector<float, 4> lq_points(u32 qw) const { math::Vector<float, 4> lq_points(u32 qw) const {
ASSERT(qw >= 50); ASSERT(qw >= 50);
@ -363,7 +364,6 @@ struct TieProtoInfo {
u32 proto_flag; u32 proto_flag;
float stiffness = 0; // wind float stiffness = 0; // wind
std::optional<AdgifInfo> envmap_adgif; std::optional<AdgifInfo> envmap_adgif;
math::Vector<u8, 4> tint_color = math::Vector<u8, 4>::zero();
std::vector<tfrag3::TimeOfDayColor> time_of_day_colors; // c++ type for time of day data std::vector<tfrag3::TimeOfDayColor> time_of_day_colors; // c++ type for time of day data
std::vector<TieFrag> frags; // the fragments of the prototype std::vector<TieFrag> frags; // the fragments of the prototype
}; };
@ -628,7 +628,8 @@ u64 alpha_value_for_jak2_tie_or_etie_alpha_override(tfrag3::TieCategory category
void update_proto_info(std::vector<TieProtoInfo>* out, void update_proto_info(std::vector<TieProtoInfo>* out,
const std::vector<level_tools::TextureRemap>& map, const std::vector<level_tools::TextureRemap>& map,
const std::vector<level_tools::PrototypeBucketTie>& protos, const std::vector<level_tools::PrototypeBucketTie>& protos,
int geo) { int geo,
GameVersion version) {
out->resize(std::max(out->size(), protos.size())); out->resize(std::max(out->size(), protos.size()));
for (size_t i = 0; i < protos.size(); i++) { for (size_t i = 0; i < protos.size(); i++) {
const auto& proto = protos[i]; const auto& proto = protos[i];
@ -638,13 +639,17 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
info.name = proto.name; info.name = proto.name;
// wind "stiffness" nonzero value means it has the wind effect // wind "stiffness" nonzero value means it has the wind effect
info.stiffness = proto.stiffness; info.stiffness = proto.stiffness;
math::Vector<u8, 4> jak2_tint_color;
if (proto.has_envmap_shader) { if (proto.has_envmap_shader) {
std::vector<u8> adgif; std::vector<u8> adgif;
for (auto x : proto.envmap_shader) { for (auto x : proto.envmap_shader) {
adgif.push_back(x); adgif.push_back(x);
} }
info.envmap_adgif = process_adgif(adgif, 0, map, nullptr); info.envmap_adgif = process_adgif(adgif, 0, map, nullptr);
info.tint_color = proto.tint_color;
if (version > GameVersion::Jak1) {
jak2_tint_color = proto.jak2_tint_color;
}
} }
// bool use_crazy_jak2_etie_alpha_thing = proto.has_envmap_shader; // bool use_crazy_jak2_etie_alpha_thing = proto.has_envmap_shader;
@ -704,7 +709,7 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
} }
} }
// normals // normals (jak 2)
const auto& normal_data = proto.geometry[geo].tie_fragments[frag_idx].normals; const auto& normal_data = proto.geometry[geo].tie_fragments[frag_idx].normals;
frag_info.normal_data_packed.resize(normal_data.size() / 4); frag_info.normal_data_packed.resize(normal_data.size() / 4);
for (size_t ni = 0; ni < normal_data.size() / 4; ni++) { for (size_t ni = 0; ni < normal_data.size() / 4; ni++) {
@ -713,6 +718,41 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
} }
} }
if (version > GameVersion::Jak1) {
frag_info.envmap_tint_color = jak2_tint_color;
}
// normals (jak 1)
auto& generic = proto.geometry[geo].tie_fragments[frag_idx].generic_data;
if (!generic.empty()) {
// fmt::print("Generic for frag {} of {}\n", frag_idx, proto.name);
struct GenericTieHeader {
u8 effect;
u8 interp_table_size;
u8 num_bps;
u8 num_ips;
math::Vector<u8, 4> tint_color;
u16 index_table_offset;
u16 kick_table_offset;
u16 normal_table_offset;
u16 interp_table_offset;
};
static_assert(sizeof(GenericTieHeader) == 16);
ASSERT(generic.size() >= sizeof(GenericTieHeader));
GenericTieHeader header;
memcpy(&header, generic.data(), sizeof(GenericTieHeader));
frag_info.envmap_tint_color = header.tint_color;
int normal_count = header.num_bps + header.num_ips;
frag_info.normal_data_packed.resize(normal_count);
for (int ni = 0; ni < normal_count; ni++) {
for (int j = 0; j < 4; j++) {
frag_info.normal_data_packed[ni][j] =
generic.at(header.normal_table_offset + ni * 4 + j);
}
}
}
info.frags.push_back(std::move(frag_info)); info.frags.push_back(std::move(frag_info));
} }
} }
@ -1578,7 +1618,7 @@ void emulate_tie_instance_program(std::vector<TieProtoInfo>& protos) {
vertex_info.tex.x() = tex_coord.x(); vertex_info.tex.x() = tex_coord.x();
vertex_info.tex.y() = tex_coord.y(); vertex_info.tex.y() = tex_coord.y();
vertex_info.tex.z() = tex_coord.z(); vertex_info.tex.z() = tex_coord.z();
vertex_info.envmap_tint_color = proto.tint_color; vertex_info.envmap_tint_color = frag.envmap_tint_color;
vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++); vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++);
bool inserted = frag.vertex_by_dest_addr.insert({(u32)dest_ptr, vertex_info}).second; bool inserted = frag.vertex_by_dest_addr.insert({(u32)dest_ptr, vertex_info}).second;
@ -1622,7 +1662,7 @@ void emulate_tie_instance_program(std::vector<TieProtoInfo>& protos) {
vertex_info.tex.x() = tex_coord.x(); vertex_info.tex.x() = tex_coord.x();
vertex_info.tex.y() = tex_coord.y(); vertex_info.tex.y() = tex_coord.y();
vertex_info.tex.z() = tex_coord.z(); vertex_info.tex.z() = tex_coord.z();
vertex_info.envmap_tint_color = proto.tint_color; vertex_info.envmap_tint_color = frag.envmap_tint_color;
vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++); vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++);
// lg::print("double draw: {} {}\n", dest_ptr, dest2_ptr); // lg::print("double draw: {} {}\n", dest_ptr, dest2_ptr);
@ -1746,7 +1786,7 @@ void emulate_tie_instance_program(std::vector<TieProtoInfo>& protos) {
vertex_info.tex.x() = tex_coord.x(); vertex_info.tex.x() = tex_coord.x();
vertex_info.tex.y() = tex_coord.y(); vertex_info.tex.y() = tex_coord.y();
vertex_info.tex.z() = tex_coord.z(); vertex_info.tex.z() = tex_coord.z();
vertex_info.envmap_tint_color = proto.tint_color; vertex_info.envmap_tint_color = frag.envmap_tint_color;
vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++); vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++);
bool inserted = frag.vertex_by_dest_addr.insert({(u32)dest_ptr, vertex_info}).second; bool inserted = frag.vertex_by_dest_addr.insert({(u32)dest_ptr, vertex_info}).second;
@ -1780,7 +1820,7 @@ void emulate_tie_instance_program(std::vector<TieProtoInfo>& protos) {
vertex_info.tex.x() = tex_coord.x(); vertex_info.tex.x() = tex_coord.x();
vertex_info.tex.y() = tex_coord.y(); vertex_info.tex.y() = tex_coord.y();
vertex_info.tex.z() = tex_coord.z(); vertex_info.tex.z() = tex_coord.z();
vertex_info.envmap_tint_color = proto.tint_color; vertex_info.envmap_tint_color = frag.envmap_tint_color;
vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++); vertex_info.nrm = frag.get_normal_if_present(normal_table_offset++);
bool inserted = frag.vertex_by_dest_addr.insert({(u32)dest_ptr, vertex_info}).second; bool inserted = frag.vertex_by_dest_addr.insert({(u32)dest_ptr, vertex_info}).second;
@ -1805,10 +1845,15 @@ void emulate_tie_instance_program(std::vector<TieProtoInfo>& protos) {
program_end:; program_end:;
if (!frag.normal_data_packed.empty()) { if (!frag.normal_data_packed.empty()) {
// check that we have a normal per point, if we have normals // check that we have a normal per point, if we have normals
size_t rounded_up_dvert = (nd.bp1 + nd.bp2 + nd.ip1 + nd.ip2) + 3; // in ETIE, the normal count must be a multiple of 4 due to VIF upload
// in Jak 1, generic processes normals on the EE, so there is no multiple of 4 requirement.
// so we allow either a round-up-to-nearest-four or exact match to pass here.
size_t total_dvert = nd.bp1 + nd.bp2 + nd.ip1 + nd.ip2;
size_t rounded_up_dvert = total_dvert + 3;
rounded_up_dvert /= 4; rounded_up_dvert /= 4;
rounded_up_dvert *= 4; rounded_up_dvert *= 4;
ASSERT(rounded_up_dvert == frag.normal_data_packed.size()); ASSERT(rounded_up_dvert == frag.normal_data_packed.size() ||
total_dvert == frag.normal_data_packed.size());
} }
// ASSERT(false); // ASSERT(false);
} }
@ -1838,7 +1883,6 @@ void emulate_kicks(std::vector<TieProtoInfo>& protos) {
ASSERT(frag.prog_info.adgif_offset_in_gif_buf_qw.size() == frag.adgifs.size()); ASSERT(frag.prog_info.adgif_offset_in_gif_buf_qw.size() == frag.adgifs.size());
const AdgifInfo* adgif_info = nullptr; const AdgifInfo* adgif_info = nullptr;
int adgif_info_idx = -1;
int expected_next_tag = 0; int expected_next_tag = 0;
// loop over strgifs // loop over strgifs
@ -1848,7 +1892,6 @@ void emulate_kicks(std::vector<TieProtoInfo>& protos) {
// yep // yep
int idx = adgif_it - frag.prog_info.adgif_offset_in_gif_buf_qw.begin(); int idx = adgif_it - frag.prog_info.adgif_offset_in_gif_buf_qw.begin();
adgif_info = &frag.adgifs.at(idx); adgif_info = &frag.adgifs.at(idx);
adgif_info_idx = idx;
// the next strgif should come 6 qw's after // the next strgif should come 6 qw's after
expected_next_tag += 6; expected_next_tag += 6;
adgif_it++; adgif_it++;
@ -1878,7 +1921,6 @@ void emulate_kicks(std::vector<TieProtoInfo>& protos) {
frag.strips.emplace_back(); frag.strips.emplace_back();
auto& strip = frag.strips.back(); auto& strip = frag.strips.back();
strip.adgif = *adgif_info; strip.adgif = *adgif_info;
strip.adgif_idx = adgif_info_idx;
// loop over all the vertices the strgif says we'll have // loop over all the vertices the strgif says we'll have
for (int vtx = 0; vtx < str_it->nloop; vtx++) { for (int vtx = 0; vtx < str_it->nloop; vtx++) {
// compute the address of this vertex (stored after the strgif) // compute the address of this vertex (stored after the strgif)
@ -2219,6 +2261,15 @@ DrawMode process_draw_mode(const AdgifInfo& info,
if (version == GameVersion::Jak1) { if (version == GameVersion::Jak1) {
// use alpha from adgif shader, that's what we did in the past (could be wrong?) // use alpha from adgif shader, that's what we did in the past (could be wrong?)
update_mode_from_alpha1(info.alpha_val, mode); update_mode_from_alpha1(info.alpha_val, mode);
if (tfrag3::is_envmap_second_draw_category(category)) {
mode.enable_ab();
}
if (tfrag3::is_envmap_first_draw_category(category)) {
// decal seems to be somewhat rarely enbaled on envmapped stuff where it's clearly wrong (edge
// the fj temple before the room with the blue eco switch)
mode.disable_decal();
}
} else { } else {
if (tfrag3::is_envmap_second_draw_category(category)) { if (tfrag3::is_envmap_second_draw_category(category)) {
// envmap shader gets to control its own alpha // envmap shader gets to control its own alpha
@ -2259,8 +2310,10 @@ DrawMode process_envmap_draw_mode(const AdgifInfo& info,
TieCategoryInfo get_jak1_tie_category(u32 flags) { TieCategoryInfo get_jak1_tie_category(u32 flags) {
TieCategoryInfo result; TieCategoryInfo result;
result.category = tfrag3::TieCategory::NORMAL;
result.uses_envmap = flags & 2; result.uses_envmap = flags & 2;
result.category =
result.uses_envmap ? tfrag3::TieCategory::NORMAL_ENVMAP : tfrag3::TieCategory::NORMAL;
result.envmap_second_draw_category = tfrag3::TieCategory::NORMAL_ENVMAP_SECOND_DRAW;
return result; return result;
} }
@ -2495,11 +2548,6 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
if (info.uses_envmap && version == GameVersion::Jak1) {
// envmap ties go through generic (for now...)
continue;
}
// bool using_wind = true; // hack, for testing // bool using_wind = true; // hack, for testing
bool using_wind = proto.stiffness != 0.f; bool using_wind = proto.stiffness != 0.f;
@ -2692,7 +2740,7 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
// convert level format data to a nicer format // convert level format data to a nicer format
auto info = auto info =
collect_instance_info(as_instance_array, &tree->prototypes.prototype_array_tie.data, geo); collect_instance_info(as_instance_array, &tree->prototypes.prototype_array_tie.data, geo);
update_proto_info(&info, tex_map, tree->prototypes.prototype_array_tie.data, geo); update_proto_info(&info, tex_map, tree->prototypes.prototype_array_tie.data, geo, version);
if (version != GameVersion::Jak2) { if (version != GameVersion::Jak2) {
check_wind_vectors_zero(info, tree->prototypes.wind_vectors); check_wind_vectors_zero(info, tree->prototypes.wind_vectors);
} }

View file

@ -283,7 +283,8 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
// 7 : TFRAG_NEAR_LEVEL0 // 7 : TFRAG_NEAR_LEVEL0
// 8 : TIE_NEAR_LEVEL0 // 8 : TIE_NEAR_LEVEL0
// 9 : TIE_LEVEL0 // 9 : TIE_LEVEL0
init_bucket_renderer<Tie3>("l0-tfrag-tie", BucketCategory::TIE, BucketId::TIE_LEVEL0, 0); init_bucket_renderer<Tie3WithEnvmapJak1>("l0-tfrag-tie", BucketCategory::TIE,
BucketId::TIE_LEVEL0, 0);
// 10 : MERC_TFRAG_TEX_LEVEL0 // 10 : MERC_TFRAG_TEX_LEVEL0
init_bucket_renderer<Merc2>("l0-tfrag-merc", BucketCategory::MERC, init_bucket_renderer<Merc2>("l0-tfrag-merc", BucketCategory::MERC,
BucketId::MERC_TFRAG_TEX_LEVEL0); BucketId::MERC_TFRAG_TEX_LEVEL0);
@ -303,7 +304,8 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
// 14 : TFRAG_NEAR_LEVEL1 // 14 : TFRAG_NEAR_LEVEL1
// 15 : TIE_NEAR_LEVEL1 // 15 : TIE_NEAR_LEVEL1
// 16 : TIE_LEVEL1 // 16 : TIE_LEVEL1
init_bucket_renderer<Tie3>("l1-tfrag-tie", BucketCategory::TIE, BucketId::TIE_LEVEL1, 1); init_bucket_renderer<Tie3WithEnvmapJak1>("l1-tfrag-tie", BucketCategory::TIE,
BucketId::TIE_LEVEL1, 1);
// 17 : MERC_TFRAG_TEX_LEVEL1 // 17 : MERC_TFRAG_TEX_LEVEL1
init_bucket_renderer<Merc2>("l1-tfrag-merc", BucketCategory::MERC, init_bucket_renderer<Merc2>("l1-tfrag-merc", BucketCategory::MERC,
BucketId::MERC_TFRAG_TEX_LEVEL1); BucketId::MERC_TFRAG_TEX_LEVEL1);

View file

@ -316,12 +316,18 @@ bool Tie3::set_up_common_data_from_dma(DmaFollower& dma, SharedRenderState* rend
auto proto_mask_data = dma.read_and_advance(); auto proto_mask_data = dma.read_and_advance();
m_common_data.proto_vis_data = proto_mask_data.data; m_common_data.proto_vis_data = proto_mask_data.data;
m_common_data.proto_vis_data_size = proto_mask_data.size_bytes; m_common_data.proto_vis_data_size = proto_mask_data.size_bytes;
// jak 2 envmap color
auto envmap_color = dma.read_and_advance();
ASSERT(envmap_color.size_bytes == 16);
memcpy(m_common_data.envmap_color.data(), envmap_color.data, 16);
m_common_data.envmap_color /= 128.f;
} }
// envmap color
auto envmap_color = dma.read_and_advance();
ASSERT(envmap_color.size_bytes == 16);
memcpy(m_common_data.envmap_color.data(), envmap_color.data, 16);
m_common_data.envmap_color /= 128.f;
if (render_state->version == GameVersion::Jak1) {
m_common_data.envmap_color *= 2;
}
m_common_data.envmap_color *= m_envmap_strength;
m_common_data.frame_idx = render_state->frame_idx; m_common_data.frame_idx = render_state->frame_idx;
while (dma.current_tag_offset() != render_state->next_bucket) { while (dma.current_tag_offset() != render_state->next_bucket) {
@ -386,11 +392,7 @@ void Tie3::draw_matching_draws_for_all_trees(int geom,
ScopedProfilerNode& prof, ScopedProfilerNode& prof,
tfrag3::TieCategory category) { tfrag3::TieCategory category) {
for (u32 i = 0; i < m_trees[geom].size(); i++) { for (u32 i = 0; i < m_trees[geom].size(); i++) {
if (tfrag3::is_envmap_first_draw_category(category)) { draw_matching_draws_for_tree(i, geom, settings, render_state, prof, category);
draw_matching_draws_for_tree(i, geom, settings, render_state, prof, category);
} else {
draw_matching_draws_for_tree(i, geom, settings, render_state, prof, category);
}
} }
} }
@ -630,7 +632,7 @@ void Tie3::draw_matching_draws_for_tree(int idx,
glBindVertexArray(0); glBindVertexArray(0);
if (use_envmap) { if (use_envmap && m_draw_envmap_second_draw) {
envmap_second_pass_draw(tree, settings, render_state, prof, envmap_second_pass_draw(tree, settings, render_state, prof,
tfrag3::get_second_draw_category(category)); tfrag3::get_second_draw_category(category));
} }
@ -695,6 +697,8 @@ void Tie3::envmap_second_pass_draw(const Tree& tree,
} }
void Tie3::draw_debug_window() { void Tie3::draw_debug_window() {
ImGui::Checkbox("envmap 2nd draw", &m_draw_envmap_second_draw);
ImGui::SliderFloat("envmap str", &m_envmap_strength, 0, 2);
ImGui::Checkbox("Fast ToD", &m_use_fast_time_of_day); ImGui::Checkbox("Fast ToD", &m_use_fast_time_of_day);
ImGui::SameLine(); ImGui::SameLine();
ImGui::Checkbox("All Visible", &m_debug_all_visible); ImGui::Checkbox("All Visible", &m_debug_all_visible);
@ -993,3 +997,20 @@ void Tie3AnotherCategory::render(DmaFollower& dma,
} }
m_parent->render_from_another(render_state, prof, m_category); m_parent->render_from_another(render_state, prof, m_category);
} }
Tie3WithEnvmapJak1::Tie3WithEnvmapJak1(const std::string& name, int my_id, int level_id)
: Tie3(name, my_id, level_id, tfrag3::TieCategory::NORMAL) {}
void Tie3WithEnvmapJak1::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
Tie3::render(dma, render_state, prof);
if (m_enable_envmap) {
render_from_another(render_state, prof, tfrag3::TieCategory::NORMAL_ENVMAP);
}
}
void Tie3WithEnvmapJak1::draw_debug_window() {
ImGui::Checkbox("envmap", &m_enable_envmap);
Tie3::draw_debug_window();
}

View file

@ -99,10 +99,12 @@ class Tie3 : public BucketRenderer {
TfragRenderSettings settings; TfragRenderSettings settings;
const u8* proto_vis_data = nullptr; const u8* proto_vis_data = nullptr;
u32 proto_vis_data_size = 0; u32 proto_vis_data_size = 0;
math::Vector4f envmap_color; math::Vector4f envmap_color = math::Vector4f{2.f, 2.f, 2.f, 2.f};
u64 frame_idx = -1; u64 frame_idx = -1;
} m_common_data; } m_common_data;
float m_envmap_strength = 1.f;
struct Tree { struct Tree {
GLuint vertex_buffer; GLuint vertex_buffer;
GLuint index_buffer; GLuint index_buffer;
@ -150,6 +152,7 @@ class Tie3 : public BucketRenderer {
bool m_use_fast_time_of_day = true; bool m_use_fast_time_of_day = true;
bool m_debug_all_visible = false; bool m_debug_all_visible = false;
bool m_hide_wind = false; bool m_hide_wind = false;
bool m_draw_envmap_second_draw = true;
TfragPcPortData m_pc_port_data; TfragPcPortData m_pc_port_data;
@ -183,3 +186,16 @@ class Tie3AnotherCategory : public BucketRenderer {
Tie3* m_parent; Tie3* m_parent;
tfrag3::TieCategory m_category; tfrag3::TieCategory m_category;
}; };
/*!
* Jak 1 - specific renderer that does TIE and TIE envmap in one.
*/
class Tie3WithEnvmapJak1 : public Tie3 {
public:
Tie3WithEnvmapJak1(const std::string& name, int my_id, int level_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
private:
bool m_enable_envmap = true;
};

View file

@ -25,10 +25,7 @@ uniform vec4 persp1;
uniform mat4 cam_no_persp; uniform mat4 cam_no_persp;
void main() { void main() {
fogginess = 0;
// maybe we could do fog faster using intermediate results from below, but it doesn't seem significant.
float fog1 = camera[3].w + camera[0].w * position_in.x + camera[1].w * position_in.y + camera[2].w * position_in.z;
fogginess = 255 - clamp(fog1 + hvdf_offset.w, fog_min, fog_max);
// rotate the normal // rotate the normal
vec3 nrm_vf23 = cam_no_persp[0].xyz * normal.x vec3 nrm_vf23 = cam_no_persp[0].xyz * normal.x
@ -42,7 +39,7 @@ void main() {
vf17 += cam_no_persp[1] * position_in.y; vf17 += cam_no_persp[1] * position_in.y;
vf17 += cam_no_persp[2] * position_in.z; vf17 += cam_no_persp[2] * position_in.z;
/*
// This is the ETIE math. // This is the ETIE math.
// It seems right only if the nrm_vf23 is normalized first // It seems right only if the nrm_vf23 is normalized first
// (and in this case it's identical the emerc math below) // (and in this case it's identical the emerc math below)
@ -50,7 +47,7 @@ void main() {
// likely on PS2, their normal transformation matrix was scaled correctly. // likely on PS2, their normal transformation matrix was scaled correctly.
// ours isn't. (yes, the camera matrix is a pure rotation and that doesn't matter, but the // ours isn't. (yes, the camera matrix is a pure rotation and that doesn't matter, but the
// instance matrix used to de-instance the mesh needs the correction, and we don't have it) // instance matrix used to de-instance the mesh needs the correction, and we don't have it)
if (use_emerc_math == 0) { {
nrm_vf23 = nrm_vf23; nrm_vf23 = nrm_vf23;
// nrm.z -= 1 // nrm.z -= 1
//subw.z vf23, vf23, vf00 //subw.z vf23, vf23, vf00
@ -96,7 +93,7 @@ void main() {
//addw.xy vf23, vf23, vf03 //addw.xy vf23, vf23, vf03
nrm_vf23.xy += 0.5; nrm_vf23.xy += 0.5;
tex_coord = nrm_vf23; tex_coord = nrm_vf23;
}*/ }
//;; perspective transform //;; perspective transform
//mula.xy ACC, vf10, vf17 ;; acc build 1 //mula.xy ACC, vf10, vf17 ;; acc build 1
@ -111,35 +108,35 @@ void main() {
float pQ = 1.f / p_proj.w; float pQ = 1.f / p_proj.w;
// EMERC version of the math // EMERC version of the math
{ // {
// emerc hack // // emerc hack
vec3 vf10 = normalize(r_nrm); // vec3 vf10 = normalize(r_nrm);
//subw.z vf10, vf10, vf00 ;; subtract 1 from z // //subw.z vf10, vf10, vf00 ;; subtract 1 from z
vf10.z -= 1; // vf10.z -= 1;
//addw.z vf09, vf00, vf09 ;; xyww the unperspected thing // //addw.z vf09, vf00, vf09 ;; xyww the unperspected thing
vec4 vf09 = vf17; // vec4 vf09 = vf17;
//mul.xyz vf15, vf09, vf10 ;; // //mul.xyz vf15, vf09, vf10 ;;
vec3 vf15 = vf09.xyz * vf10.xyz; // vec3 vf15 = vf09.xyz * vf10.xyz;
//adday.xyzw vf15, vf15 // //adday.xyzw vf15, vf15
//maddz.x vf15, vf21, vf15 // //maddz.x vf15, vf21, vf15
float vf15_x = vf15.x + vf15.y + vf15.z; // float vf15_x = vf15.x + vf15.y + vf15.z;
//div Q, vf15.x, vf10.z // //div Q, vf15.x, vf10.z
float qq = vf15_x / vf10.z; // float qq = vf15_x / vf10.z;
//mulaw.xyzw ACC, vf09, vf00 // //mulaw.xyzw ACC, vf09, vf00
vec3 ACC = vf09.xyz; // vec3 ACC = vf09.xyz;
//madd.xyzw vf10, vf10, Q // //madd.xyzw vf10, vf10, Q
vf10 = ACC + vf10 * qq; // vf10 = ACC + vf10 * qq;
//eleng.xyz P, vf10 // //eleng.xyz P, vf10
float P = length(vf10.xyz); // float P = length(vf10.xyz);
//mfp.w vf10, P // //mfp.w vf10, P
//div Q, vf23.z, vf10.w // //div Q, vf23.z, vf10.w
float qqq = 0.5 / P; // float qqq = 0.5 / P;
//addaz.xyzw vf00, vf23 // //addaz.xyzw vf00, vf23
ACC = vec3(0.5, 0.5, 0.5); // ACC = vec3(0.5, 0.5, 0.5);
//madd.xyzw vf10, vf10, Q // //madd.xyzw vf10, vf10, Q
vf10 = ACC + vf10 * qqq; // vf10 = ACC + vf10 * qqq;
tex_coord = vf10.xyz; // tex_coord = vf10.xyz;
} // }
vec4 transformed = p_proj * pQ; vec4 transformed = p_proj * pQ;
@ -161,5 +158,4 @@ void main() {
fragment_color = proto_tint * envmap_tod_tint; fragment_color = proto_tint * envmap_tod_tint;
} }

View file

@ -181,6 +181,8 @@
) )
) )
(define *use-etie* #t)
(defun finish-background () (defun finish-background ()
"Complete the background drawing. "Complete the background drawing.
This function should run after the background engine has executed. This function should run after the background engine has executed.
@ -509,31 +511,33 @@
) )
;; TIE Generic ;; TIE Generic
(dotimes (gp-2 (-> *background-work* tie-tree-count)) (when (not *use-etie*)
(when (nonzero? (-> *background-work* tie-generic gp-2)) (dotimes (gp-2 (-> *background-work* tie-tree-count))
;; send to the generic foreground with tfrag textures bucket for this level (when (nonzero? (-> *background-work* tie-generic gp-2))
(let* ((s5-4 (-> *background-work* tie-levels gp-2 tfrag-tex-foreground-sink-group generic-sink)) ;; send to the generic foreground with tfrag textures bucket for this level
(s3-1 (-> *display* frames (-> *display* on-screen) frame global-buf)) (let* ((s5-4 (-> *background-work* tie-levels gp-2 tfrag-tex-foreground-sink-group generic-sink))
(s4-3 (-> s3-1 base)) (s3-1 (-> *display* frames (-> *display* on-screen) frame global-buf))
) (s4-3 (-> s3-1 base))
(generic-tie-execute s5-4 s3-1 (-> *background-work* tie-generic gp-2)) )
(let ((a3-0 (-> s3-1 base))) (generic-tie-execute s5-4 s3-1 (-> *background-work* tie-generic gp-2))
(let ((v1-219 (the-as object (-> s3-1 base)))) (let ((a3-0 (-> s3-1 base)))
(set! (-> (the-as dma-packet v1-219) dma) (new 'static 'dma-tag :id (dma-tag-id next))) (let ((v1-219 (the-as object (-> s3-1 base))))
(set! (-> (the-as dma-packet v1-219) vif0) (new 'static 'vif-tag)) (set! (-> (the-as dma-packet v1-219) dma) (new 'static 'dma-tag :id (dma-tag-id next)))
(set! (-> (the-as dma-packet v1-219) vif1) (new 'static 'vif-tag)) (set! (-> (the-as dma-packet v1-219) vif0) (new 'static 'vif-tag))
(set! (-> s3-1 base) (&+ (the-as pointer v1-219) 16)) (set! (-> (the-as dma-packet v1-219) vif1) (new 'static 'vif-tag))
) (set! (-> s3-1 base) (&+ (the-as pointer v1-219) 16))
(dma-bucket-insert-tag )
(-> *display* frames (-> *display* on-screen) frame bucket-group) (dma-bucket-insert-tag
(-> s5-4 bucket) (-> *display* frames (-> *display* on-screen) frame bucket-group)
s4-3 (-> s5-4 bucket)
(the-as (pointer dma-tag) a3-0) s4-3
(the-as (pointer dma-tag) a3-0)
)
) )
) )
) )
) )
) )
) )
) )

View file

@ -8,6 +8,23 @@
(def-mips2c draw-inline-array-instance-tie (function pointer (inline-array instance-tie) int dma-buffer none)) (def-mips2c draw-inline-array-instance-tie (function pointer (inline-array instance-tie) int dma-buffer none))
(def-mips2c draw-inline-array-prototype-tie-generic-asm (function dma-buffer int prototype-array-tie none)) (def-mips2c draw-inline-array-prototype-tie-generic-asm (function dma-buffer int prototype-array-tie none))
(defun pc-add-tie-envmap-info ((dma-buf dma-buffer))
(let ((packet (the-as dma-packet (-> dma-buf base))))
(set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc 1))
(set! (-> packet vif0) (new 'static 'vif-tag))
(set! (-> packet vif1) (new 'static 'vif-tag :cmd (vif-cmd pc-port)))
(set! (-> dma-buf base) (the pointer (&+ packet 16)))
(set! (-> (the (pointer uint128) (-> dma-buf base)))
(if (and *time-of-day-context*
(nonzero? *time-of-day-context*))
(-> *time-of-day-context* current-sun env-color quad)
(the uint128 0)
)
)
(set! (-> dma-buf base) (the pointer (&+ packet 32)))
)
)
(defun tie-init-buffers ((arg0 dma-buffer)) (defun tie-init-buffers ((arg0 dma-buffer))
"Initialize the TIE buckets. "Initialize the TIE buckets.
Note: the buffer passed in here is _not_ used. Note: the buffer passed in here is _not_ used.
@ -373,7 +390,9 @@
;; note: this is a bit wasteful because we only care about generic ties. ;; note: this is a bit wasteful because we only care about generic ties.
;; non-generics are drawn fully in C++, but we're computing unused stuff here. ;; non-generics are drawn fully in C++, but we're computing unused stuff here.
;; This ends up being so fast it's probably not worth worrying about yet. ;; This ends up being so fast it's probably not worth worrying about yet.
(with-profiler "tie-instance" (draw-inline-array-instance-tie s0-0 s1-0 sv-16 s3-1)) (when (not *use-etie*)
(with-profiler "tie-instance" (draw-inline-array-instance-tie s0-0 s1-0 sv-16 s3-1))
)
;; finish perf stats ;; finish perf stats
(read! (-> *perf-stats* data 9)) (read! (-> *perf-stats* data 9))
(update-wait-stats (-> *perf-stats* data 9) (the-as uint 0) (update-wait-stats (-> *perf-stats* data 9) (the-as uint 0)
@ -401,7 +420,9 @@
) )
;; Generic TIE prototype drawing ;; Generic TIE prototype drawing
(when (logtest? *vu1-enable-user* (vu1-renderer-mask generic)) (when (and (logtest? *vu1-enable-user* (vu1-renderer-mask generic))
(not *use-etie*)
)
(when (logtest? (-> *instance-tie-work* flags) 2) (when (logtest? (-> *instance-tie-work* flags) 2)
(let ((s2-1 (-> *display* frames (-> *display* on-screen) frame global-buf base))) (let ((s2-1 (-> *display* frames (-> *display* on-screen) frame global-buf base)))
(set! (-> *prototype-tie-work* generic-wait-to-spr) (the-as uint 0)) (set! (-> *prototype-tie-work* generic-wait-to-spr) (the-as uint 0))
@ -446,6 +467,7 @@
;;(draw-inline-array-prototype-tie-asm s1-1 s5-1 s4-1) ;;(draw-inline-array-prototype-tie-asm s1-1 s5-1 s4-1)
(add-pc-tfrag3-data s1-1 (-> *level* data (-> (scratchpad-object terrain-context) bsp lev-index))) (add-pc-tfrag3-data s1-1 (-> *level* data (-> (scratchpad-object terrain-context) bsp lev-index)))
(add-pc-wind-data s1-1) (add-pc-wind-data s1-1)
(pc-add-tie-envmap-info s1-1)
(read! (-> *perf-stats* data 11)) (read! (-> *perf-stats* data 11))
(update-wait-stats (-> *perf-stats* data 11) (the-as uint 0) (update-wait-stats (-> *perf-stats* data 11) (the-as uint 0)
(-> *prototype-tie-work* wait-to-spr) (-> *prototype-tie-work* wait-to-spr)