Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

decompiler: defskelgroup macro detection for jak 3, fix art group dumping for jak 3 and some more decomp work #3370

Merged
merged 12 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 144 additions & 9 deletions decompiler/IR2/Form.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "decompiler/util/data_decompile.h"
#include "decompiler/util/sparticle_decompile.h"

#include "third-party/fmt/ranges.h"

namespace decompiler {

///////////////////
Expand Down Expand Up @@ -3065,6 +3067,120 @@ void DefskelgroupElement::get_modified_regs(RegSet& regs) const {
m_info.jgeo->get_modified_regs(regs);
}

goos::Object DefskelgroupElement::ClothParams::to_list(const std::string& ag_name,
const Env& env) const {
std::vector<goos::Object> result;
if (mesh != 0) {
// TODO use art element name for mesh
(void)ag_name;
// const auto& art = env.dts->art_group_info;
// if (art.find(ag_name) != art.end() && art.at(ag_name).find(mesh) != art.at(ag_name).end()) {
// auto name = art.at(ag_name).at(mesh);
// result.push_back(pretty_print::build_list(
// {pretty_print::to_symbol("mesh"), pretty_print::to_symbol(name)}));
// } else {
// result.push_back(pretty_print::build_list(
// {pretty_print::to_symbol("mesh"), pretty_print::to_symbol(std::to_string(mesh))}));
// }
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("mesh"), pretty_print::to_symbol(std::to_string(mesh))}));
}
if (gravity != 0.0f) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("gravity-constant"),
pretty_print::to_symbol(fmt::format("(meters {})", meters_to_string(gravity)))}));
}
if (wind != 0.0f) {
result.push_back(pretty_print::build_list({pretty_print::to_symbol("wind-constant"),
pretty_print::to_symbol(float_to_string(wind))}));
}
if (width != 0) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("cloth-width"), pretty_print::to_symbol(std::to_string(width))}));
}
if (sphere_constraints != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-sphere-constraints"),
pretty_print::to_symbol(std::to_string(sphere_constraints))}));
}
if (disc_constraints != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-disc-constraints"),
pretty_print::to_symbol(std::to_string(disc_constraints))}));
}
if (anchor_points != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-anchor-points"),
pretty_print::to_symbol(std::to_string(anchor_points))}));
}
if (flags != 0) {
auto bits = decompile_bitfield_enum_from_int(TypeSpec("cloth-flag"), env.dts->ts, flags);
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("flags"),
pretty_print::to_symbol(fmt::format("(cloth-flag {})", fmt::join(bits, " ")))}));
}
if (!tex_name.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("tex-name"), pretty_print::new_string(tex_name)}));
}
if (!tex_name2.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("tex-name2"), pretty_print::new_string(tex_name2)}));
}
if (!tex_name3.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("tex-name3"), pretty_print::new_string(tex_name3)}));
}
if (!alt_tex_name.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("alt-tex-name"), pretty_print::new_string(alt_tex_name)}));
}
if (!alt_tex_name2.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("alt-tex-name2"), pretty_print::new_string(alt_tex_name2)}));
}
if (!alt_tex_name3.empty()) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("alt-tex-name3"), pretty_print::new_string(alt_tex_name3)}));
}
if (thickness != 0.0f) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("cloth-thickness"),
pretty_print::to_symbol(float_to_string(thickness))}));
}
if (xform != 0) {
result.push_back(pretty_print::build_list({pretty_print::to_symbol("initial-xform"),
pretty_print::to_symbol(std::to_string(xform))}));
}
if (drag != 0.0f) {
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("drag"), pretty_print::to_symbol(float_to_string(drag))}));
}
if (ball_collision_radius != 0.0f) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("ball-collision-radius"),
pretty_print::to_symbol(fmt::format(
"(meters {})", meters_to_string(ball_collision_radius)))}));
}
if (iterations != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("num-iterations"),
pretty_print::to_symbol(std::to_string(iterations))}));
}
if (timestep_freq != 0) {
result.push_back(
pretty_print::build_list({pretty_print::to_symbol("timestep-frequency"),
pretty_print::to_symbol(std::to_string(timestep_freq))}));
}
if (secret != 0) {
auto bits = decompile_bitfield_enum_from_int(TypeSpec("game-secrets"), env.dts->ts, flags);
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("secret-disable"),
pretty_print::to_symbol(fmt::format("(game-secrets {})", fmt::join(bits, " ")))}));
}
return pretty_print::build_list(result);
}

goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
std::vector<goos::Object> forms;
forms.push_back(pretty_print::to_symbol("defskelgroup"));
Expand Down Expand Up @@ -3124,15 +3240,21 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
if (m_static_info.sort != 0) {
forms.push_back(pretty_print::to_symbol(fmt::format(":sort {}", m_static_info.sort)));
}
// jak 2 skelgroups seem to be using version 7
if (env.version != GameVersion::Jak1) {
if (m_static_info.version != 7) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
} else {
if (m_static_info.version != 6) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
switch (env.version) {
case GameVersion::Jak1:
if (m_static_info.version != 6) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
break;
case GameVersion::Jak2:
if (m_static_info.version != 7) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
break;
case GameVersion::Jak3:
if (m_static_info.version != 8) {
forms.push_back(pretty_print::to_symbol(fmt::format(":version {}", m_static_info.version)));
}
}
if (env.version != GameVersion::Jak1) {
if (m_static_info.origin_joint_index != 0) {
Expand All @@ -3147,6 +3269,19 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
forms.push_back(
pretty_print::to_symbol(fmt::format(":light-index {}", m_static_info.light_index)));
}
if (m_static_info.global_effects != 0) {
forms.push_back(
pretty_print::to_symbol(fmt::format(":global-effects {}", m_static_info.global_effects)));
}
if (!m_static_info.clothing.empty()) {
std::vector<goos::Object> cloth_list;
forms.push_back(pretty_print::to_symbol(":clothing"));
for (const auto& p : m_static_info.clothing) {
auto macro = p.to_list(m_static_info.art_group_name + "-ag", env);
cloth_list.push_back(macro);
}
forms.push_back(pretty_print::build_list(cloth_list));
}
}

return pretty_print::build_list(forms);
Expand Down
30 changes: 29 additions & 1 deletion decompiler/IR2/Form.h
Original file line number Diff line number Diff line change
Expand Up @@ -1687,8 +1687,33 @@ class DefstateElement : public FormElement {

class DefskelgroupElement : public FormElement {
public:
struct ClothParams {
u16 mesh;
float gravity;
float wind;
u16 width;
u16 sphere_constraints;
u16 disc_constraints;
u16 anchor_points;
u64 flags;
std::string tex_name;
std::string tex_name2;
std::string tex_name3;
std::string alt_tex_name;
std::string alt_tex_name2;
std::string alt_tex_name3;
float thickness;
u16 xform;
float drag;
float ball_collision_radius;
u8 iterations;
u8 timestep_freq;
u64 secret;

goos::Object to_list(const std::string& ag_name, const Env& env) const;
};
struct StaticInfo {
std::string name; // jak 2
std::string name; // jak 2/3
std::string art_group_name;
math::Vector4f bounds;
int max_lod;
Expand All @@ -1700,6 +1725,9 @@ class DefskelgroupElement : public FormElement {
s8 origin_joint_index;
s8 shadow_joint_index;
s8 light_index;
// jak 3
s8 global_effects;
std::vector<ClothParams> clothing;
};
struct Entry {
Form* mgeo = nullptr;
Expand Down
65 changes: 64 additions & 1 deletion decompiler/ObjectFile/ObjectFileDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,8 @@ void get_joint_info(ObjectFileDB& db, ObjectFileData& obj, JointGeo jg) {
}

void get_art_info(ObjectFileDB& db, ObjectFileData& obj) {
if (obj.obj_version == 4 || (obj.obj_version == 5 && obj.linked_data.segments == 1)) {
// jak 1/2
if (obj.obj_version == 4) {
const auto& words = obj.linked_data.words_by_seg.at(MAIN_SEGMENT);
if (words.at(0).kind() == LinkedWord::Kind::TYPE_PTR &&
words.at(0).symbol_name() == "art-group") {
Expand Down Expand Up @@ -961,6 +962,68 @@ void get_art_info(ObjectFileDB& db, ObjectFileData& obj) {
}
}
}
// jak 3
if (obj.obj_version == 5 && obj.linked_data.segments == 1) {
const auto& words = obj.linked_data.words_by_seg.at(MAIN_SEGMENT);
if (words.at(0).kind() == LinkedWord::Kind::TYPE_PTR &&
words.at(0).symbol_name() == "art-group") {
auto obj_unique_name = obj.to_unique_name();

// lg::print("art-group {}:\n", obj.to_unique_name());
auto name = obj.linked_data.get_goal_string_by_label(words.at(2).label_id());
int length = words.at(3).data;
// lg::print(" length: {}\n", length);
for (int i = 0; i < length; ++i) {
const auto& word = words.at(8 + i);
if (word.kind() == LinkedWord::Kind::SYM_PTR && word.symbol_name() == "#f") {
continue;
}
const auto& label = obj.linked_data.labels.at(word.label_id());
auto elt_name =
obj.linked_data.get_goal_string_by_label(words.at(label.offset / 4 + 1).label_id());
auto unique_name = elt_name;

auto ag_name = obj_unique_name;
int elt_index = i;
std::string elt_type = words.at(label.offset / 4 - 1).symbol_name();
auto& word_master_ag = words.at(label.offset / 4 + 4);
auto& word_master_idx = words.at(label.offset / 4 + 5);
if (word_master_ag.kind() == LinkedWord::Kind::PTR &&
word_master_idx.kind() == LinkedWord::Kind::PLAIN_DATA) {
ag_name = obj.linked_data.get_goal_string_by_label(word_master_ag.label_id()) + "-ag";
if (elt_type != "art-cloth-geo") {
elt_index = word_master_idx.data;
}
}

if (elt_type == "art-joint-geo") {
// the skeleton!
unique_name += "-jg";
JointGeo jg;
jg.offset = label.offset;
jg.name = unique_name;
jg.length = words.at(label.offset / 4 + 2).data;
get_joint_info(db, obj, jg);
} else if (elt_type == "merc-ctrl" || elt_type == "shadow-geo") {
// (maybe mesh-geo as well but that doesnt exist)
// the skin!
unique_name += "-mg";
} else if (elt_type == "art-joint-anim") {
// the animations!
unique_name += "-ja";
} else if (elt_type == "art-cloth-geo") {
// cloth geometry (jak 3)
unique_name += "-cg";
} else {
// the something idk!
throw std::runtime_error(
fmt::format("unknown art elt type {} in {}", elt_type, obj.to_unique_name()));
}
// lg::print(" {}: {} ({}) -> {} @ {}\n", i, elt_name, elt_type, unique_name, elt_index);
db.dts.add_art_group_elt(ag_name, unique_name, elt_index);
}
}
}
}
} // namespace

Expand Down
Loading
Loading