mirror of
https://github.com/open-goal/jak-project
synced 2026-08-20 06:16:35 -04:00
up to bsp
This commit is contained in:
@@ -272,6 +272,7 @@ void try_reverse_lookup_inline_array(const FieldReverseLookupInput& input,
|
||||
next_input.stride = 0;
|
||||
next_input.offset = input.offset; // includes the offset.
|
||||
next_input.base_type = di.result_type;
|
||||
next_input.field_score_overrides = input.field_score_overrides;
|
||||
try_reverse_lookup(next_input, ts, &var_idx_node, output, max_count);
|
||||
return;
|
||||
}
|
||||
@@ -318,6 +319,7 @@ void try_reverse_lookup_inline_array(const FieldReverseLookupInput& input,
|
||||
next_input.stride = input.stride;
|
||||
next_input.offset = offset_into_elt;
|
||||
next_input.base_type = di.result_type;
|
||||
next_input.field_score_overrides = input.field_score_overrides;
|
||||
try_reverse_lookup(next_input, ts, &const_idx_node, output, max_count);
|
||||
}
|
||||
|
||||
@@ -368,6 +370,12 @@ void try_reverse_lookup_other(const FieldReverseLookupInput& input,
|
||||
token.kind = FieldReverseLookupOutput::Token::Kind::FIELD;
|
||||
token.name = field.name();
|
||||
token.field_score = field.field_score();
|
||||
for (const auto& score_override : input.field_score_overrides) {
|
||||
if (score_override.type_name == input.base_type.base_type() &&
|
||||
score_override.field_name == field.name()) {
|
||||
token.field_score += score_override.score;
|
||||
}
|
||||
}
|
||||
|
||||
if (field_deref.needs_deref) {
|
||||
if (offset_into_field == 0) {
|
||||
@@ -440,6 +448,7 @@ void try_reverse_lookup_other(const FieldReverseLookupInput& input,
|
||||
next_input.offset = offset_into_field - expected_offset_into_field;
|
||||
next_input.stride = input.stride;
|
||||
next_input.base_type = field_deref.type;
|
||||
next_input.field_score_overrides = input.field_score_overrides;
|
||||
ReverseLookupNode node;
|
||||
node.prev = parent;
|
||||
node.token = token;
|
||||
|
||||
@@ -64,11 +64,20 @@ struct DerefKind {
|
||||
RegClass reg_kind = RegClass::INVALID;
|
||||
};
|
||||
|
||||
struct FieldReverseLookupScoreOverride {
|
||||
std::string type_name;
|
||||
std::string field_name;
|
||||
double score = 0;
|
||||
};
|
||||
|
||||
struct FieldReverseLookupInput {
|
||||
std::optional<DerefKind> deref = std::nullopt; // if we actually access memory
|
||||
int offset = 0; // if we apply a constant offset
|
||||
int stride = 0; // if we are doing a + (idx * stride)
|
||||
TypeSpec base_type; // the type of the thing we're accessing
|
||||
// Per-call scoring adjustments for ambiguous overlay fields. Lookup still discovers and
|
||||
// validates every candidate normally; these only affect which valid candidate is preferred.
|
||||
std::vector<FieldReverseLookupScoreOverride> field_score_overrides;
|
||||
};
|
||||
|
||||
constexpr double CONSTANT_INDEX_SCORE = -10.0;
|
||||
|
||||
@@ -76,7 +76,7 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const {
|
||||
rd_in.stride = 0;
|
||||
rd_in.offset = m_src.get_arg(1).get_int();
|
||||
rd_in.base_type = arg0_type.typespec();
|
||||
auto rd = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
|
||||
@@ -235,7 +235,7 @@ FormElement* StoreOp::get_vf_store_as_form(FormPool& pool, const Env& env) const
|
||||
rd_in.base_type = input_type.typespec();
|
||||
rd_in.stride = 0;
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
|
||||
@@ -251,7 +251,7 @@ FormElement* StoreOp::get_vf_store_as_form(FormPool& pool, const Env& env) const
|
||||
} else {
|
||||
// try again with no deref.
|
||||
rd_in.deref = {};
|
||||
auto rd_no_deref = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto rd_no_deref = env.reverse_field_lookup(rd_in);
|
||||
if (rd_no_deref.success) {
|
||||
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
|
||||
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
|
||||
@@ -378,7 +378,7 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
|
||||
rd_in.base_type = input_type.get_obj_plus_const_mult_typespec();
|
||||
rd_in.stride = input_type.get_multiplier();
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
std::vector<DerefToken> tokens;
|
||||
@@ -412,7 +412,7 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const {
|
||||
rd_in.base_type = input_type.typespec();
|
||||
rd_in.stride = 0;
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
|
||||
@@ -626,7 +626,7 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const {
|
||||
rd_in.stride = 1;
|
||||
}
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
std::vector<DerefToken> tokens;
|
||||
@@ -673,7 +673,7 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const {
|
||||
rd_in.base_type = input_type.typespec();
|
||||
rd_in.stride = 0;
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
// todo, error here?
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ TP_Type get_stack_type_at_constant_offset(int offset,
|
||||
rd_in.stride = 0; // not a strided access
|
||||
rd_in.offset = offset - var.hint.stack_offset; // offset into this var
|
||||
rd_in.base_type = var.ref_type; // use ref type for ptr.
|
||||
auto rd = dts.ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
if (rd.success) {
|
||||
auto result = TP_Type::make_from_ts(coerce_to_reg_type(rd.result_type));
|
||||
lg::print("Matched a stack variable! {}\n", result.print());
|
||||
@@ -476,7 +476,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.offset = arg1_type.get_integer_constant();
|
||||
rd_in.stride = 0;
|
||||
rd_in.base_type = arg0_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto out = env.reverse_field_lookup(rd_in);
|
||||
if (out.success) {
|
||||
sum_type = coerce_to_reg_type(out.result_type);
|
||||
}
|
||||
@@ -514,7 +514,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.offset = arg0_type.get_add_int_constant();
|
||||
rd_in.stride = arg0_type.get_mult_int_constant();
|
||||
rd_in.base_type = arg1_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto out = env.reverse_field_lookup(rd_in);
|
||||
if (out.success) {
|
||||
return TP_Type::make_from_ts(coerce_to_reg_type(out.result_type));
|
||||
}
|
||||
@@ -524,7 +524,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.offset = arg1_type.get_add_int_constant();
|
||||
rd_in.stride = arg1_type.get_mult_int_constant();
|
||||
rd_in.base_type = arg0_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto out = env.reverse_field_lookup(rd_in);
|
||||
if (out.success) {
|
||||
return TP_Type::make_from_ts(coerce_to_reg_type(out.result_type));
|
||||
}
|
||||
@@ -535,7 +535,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.offset = arg0_type.get_integer_constant();
|
||||
rd_in.stride = 1;
|
||||
rd_in.base_type = arg1_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto out = env.reverse_field_lookup(rd_in);
|
||||
if (out.success) {
|
||||
return TP_Type::make_from_ts(coerce_to_reg_type(out.result_type));
|
||||
}
|
||||
@@ -577,7 +577,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.stride = 0;
|
||||
rd_in.offset = m_args[1].get_int();
|
||||
rd_in.base_type = arg0_type.typespec();
|
||||
auto rd = dts.ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
return TP_Type::make_from_ts(coerce_to_reg_type(rd.result_type));
|
||||
@@ -593,7 +593,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.stride = arg1_type.get_multiplier();
|
||||
rd_in.offset = 0;
|
||||
rd_in.base_type = arg0_type.typespec();
|
||||
auto rd = dts.ts.reverse_field_multi_lookup(rd_in);
|
||||
auto rd = env.reverse_field_multi_lookup(rd_in);
|
||||
|
||||
for (int i = 0; i < (int)rd.results.size(); i++) {
|
||||
if (rd.results.at(i).has_variable_token()) {
|
||||
@@ -611,7 +611,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.stride = arg0_type.get_multiplier();
|
||||
rd_in.offset = 0;
|
||||
rd_in.base_type = arg1_type.typespec();
|
||||
auto rd = dts.ts.reverse_field_multi_lookup(rd_in);
|
||||
auto rd = env.reverse_field_multi_lookup(rd_in);
|
||||
|
||||
for (int i = 0; i < (int)rd.results.size(); i++) {
|
||||
if (rd.results.at(i).has_variable_token()) {
|
||||
@@ -698,7 +698,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
rd_in.offset = arg0_type.get_integer_constant();
|
||||
rd_in.stride = 0;
|
||||
rd_in.base_type = arg1_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(rd_in);
|
||||
auto out = env.reverse_field_lookup(rd_in);
|
||||
if (out.success) {
|
||||
sum_type = coerce_to_reg_type(out.result_type);
|
||||
}
|
||||
@@ -1100,7 +1100,7 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
|
||||
rd_in.base_type = input_type.get_obj_plus_const_mult_typespec();
|
||||
rd_in.stride = input_type.get_multiplier();
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = dts.ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
// load_path_set = true;
|
||||
@@ -1145,7 +1145,7 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
|
||||
rd_in.base_type = input_type.typespec();
|
||||
rd_in.stride = 0;
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = dts.ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
|
||||
if (rd.success) {
|
||||
if (rd_in.base_type.base_type() == "state" && rd.tokens.size() == 1 &&
|
||||
@@ -1210,7 +1210,7 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
|
||||
rd_in.deref = dk;
|
||||
rd_in.base_type = input_type.get_objects_typespec();
|
||||
rd_in.offset = ro.offset;
|
||||
auto rd = dts.ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
if (rd.success) {
|
||||
return TP_Type::make_from_ts(coerce_to_reg_type(rd.result_type));
|
||||
}
|
||||
@@ -1227,7 +1227,7 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input,
|
||||
rd_in.base_type = input_type.get_objects_typespec();
|
||||
rd_in.stride = 0;
|
||||
rd_in.offset = input_type.get_integer_constant();
|
||||
auto rd = dts.ts.reverse_field_lookup(rd_in);
|
||||
auto rd = env.reverse_field_lookup(rd_in);
|
||||
if (rd.success) {
|
||||
return TP_Type::make_from_ts(coerce_to_reg_type(rd.result_type));
|
||||
}
|
||||
|
||||
@@ -17,6 +17,17 @@
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
FieldReverseLookupOutput Env::reverse_field_lookup(FieldReverseLookupInput input) const {
|
||||
input.field_score_overrides = m_reverse_lookup_field_score_overrides;
|
||||
return dts->ts.reverse_field_lookup(input);
|
||||
}
|
||||
|
||||
FieldReverseMultiLookupOutput Env::reverse_field_multi_lookup(FieldReverseLookupInput input,
|
||||
int max_count) const {
|
||||
input.field_score_overrides = m_reverse_lookup_field_score_overrides;
|
||||
return dts->ts.reverse_field_multi_lookup(input, max_count);
|
||||
}
|
||||
|
||||
constexpr const char* reg_names[] = {"a0-0", "a1-0", "a2-0", "a3-0",
|
||||
"t0-0", "t1-0", "t2-0", "t3-0"};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/goos/Object.h"
|
||||
#include "common/type_system/TypeSystem.h"
|
||||
#include "common/util/Assert.h"
|
||||
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
@@ -187,6 +188,13 @@ class Env {
|
||||
|
||||
void set_scratchpad_type(const TypeSpec& type) { m_scratchpad_type = type; }
|
||||
const std::optional<TypeSpec>& scratchpad_type() const { return m_scratchpad_type; }
|
||||
void set_reverse_lookup_field_score_overrides(
|
||||
std::vector<FieldReverseLookupScoreOverride> overrides) {
|
||||
m_reverse_lookup_field_score_overrides = std::move(overrides);
|
||||
}
|
||||
FieldReverseLookupOutput reverse_field_lookup(FieldReverseLookupInput input) const;
|
||||
FieldReverseMultiLookupOutput reverse_field_multi_lookup(FieldReverseLookupInput input,
|
||||
int max_count = 100) const;
|
||||
void note_scratchpad_access() const { m_uses_scratchpad = true; }
|
||||
bool uses_scratchpad() const { return m_uses_scratchpad; }
|
||||
|
||||
@@ -288,6 +296,7 @@ class Env {
|
||||
std::unordered_map<int, std::vector<RegisterTypeCast>> m_typecasts;
|
||||
std::unordered_map<int, StackTypeCast> m_stack_typecasts;
|
||||
std::optional<TypeSpec> m_scratchpad_type;
|
||||
std::vector<FieldReverseLookupScoreOverride> m_reverse_lookup_field_score_overrides;
|
||||
mutable bool m_uses_scratchpad = false;
|
||||
std::vector<StackStructureEntry> m_stack_structures;
|
||||
std::unordered_map<std::string, std::string> m_var_remap;
|
||||
|
||||
@@ -671,8 +671,6 @@ Form* cast_form_from(Form* in,
|
||||
FormPool& pool,
|
||||
const Env& env,
|
||||
bool tc_pass = false) {
|
||||
auto& ts = env.dts->ts;
|
||||
|
||||
auto form_type = try_get_deref_form_type(in, env);
|
||||
if (form_type == new_type) {
|
||||
return in;
|
||||
@@ -694,7 +692,7 @@ Form* cast_form_from(Form* in,
|
||||
suffix_lookup.offset = 0;
|
||||
suffix_lookup.stride = 0;
|
||||
suffix_lookup.base_type = new_type;
|
||||
auto suffix_results = ts.reverse_field_multi_lookup(suffix_lookup);
|
||||
auto suffix_results = env.reverse_field_multi_lookup(suffix_lookup);
|
||||
for (const auto& result : suffix_results.results) {
|
||||
if (!result.addr_of && result.result_type == *form_type &&
|
||||
deref_suffix_matches_lookup(deref->tokens(), keep, result)) {
|
||||
@@ -717,7 +715,7 @@ Form* cast_form_from(Form* in,
|
||||
lookup_input.offset = 0;
|
||||
lookup_input.stride = 0;
|
||||
lookup_input.base_type = form_type.value_or(old_type);
|
||||
auto lookup_result = ts.reverse_field_multi_lookup(lookup_input);
|
||||
auto lookup_result = env.reverse_field_multi_lookup(lookup_input);
|
||||
if (lookup_result.success) {
|
||||
for (auto& result : lookup_result.results) {
|
||||
if (result.result_type == new_type) {
|
||||
@@ -1337,7 +1335,7 @@ DerefElement* try_reassociate_inline_array_field_access(Form* field_access,
|
||||
lookup.stride = stride;
|
||||
lookup.offset = 0;
|
||||
lookup.base_type = *base_type;
|
||||
auto reverse = env.dts->ts.reverse_field_multi_lookup(lookup);
|
||||
auto reverse = env.reverse_field_multi_lookup(lookup);
|
||||
for (const auto& candidate : reverse.results) {
|
||||
if (candidate.has_variable_token()) {
|
||||
auto tokens = deref->tokens();
|
||||
@@ -1360,7 +1358,7 @@ DerefElement* try_reassociate_inline_array_field_access(Form* field_access,
|
||||
lookup.stride = stride;
|
||||
lookup.offset = 0;
|
||||
lookup.base_type = *field_type;
|
||||
auto reverse = env.dts->ts.reverse_field_multi_lookup(lookup);
|
||||
auto reverse = env.reverse_field_multi_lookup(lookup);
|
||||
for (const auto& candidate : reverse.results) {
|
||||
if (!candidate.has_variable_token()) {
|
||||
continue;
|
||||
@@ -1472,7 +1470,7 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
|
||||
input.offset = arg0_type.get_integer_constant();
|
||||
input.stride = 1;
|
||||
input.base_type = arg1_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(input);
|
||||
auto out = env.reverse_field_lookup(input);
|
||||
if (out.success && out.has_variable_token()) {
|
||||
// it is. now we have to modify things
|
||||
// first, look for the index
|
||||
@@ -1509,7 +1507,7 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
|
||||
input.offset = arg0_type.get_add_int_constant();
|
||||
input.stride = arg0_type.get_mult_int_constant();
|
||||
input.base_type = arg1_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(input);
|
||||
auto out = env.reverse_field_lookup(input);
|
||||
if (out.success && out.has_variable_token()) {
|
||||
// it is. now we have to modify things
|
||||
// first, look for the index
|
||||
@@ -1585,7 +1583,7 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
|
||||
rd_in.stride = arg1_type.get_multiplier();
|
||||
rd_in.offset = 0;
|
||||
rd_in.base_type = arg0_type.typespec();
|
||||
auto rd = env.dts->ts.reverse_field_multi_lookup(rd_in);
|
||||
auto rd = env.reverse_field_multi_lookup(rd_in);
|
||||
int idx_of_success = -1;
|
||||
if (rd.success) {
|
||||
for (int i = 0; i < (int)rd.results.size(); i++) {
|
||||
@@ -1637,7 +1635,7 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
|
||||
rd_in.stride = arg0_type.get_multiplier();
|
||||
rd_in.offset = 0;
|
||||
rd_in.base_type = arg1_type.typespec();
|
||||
auto rd = env.dts->ts.reverse_field_multi_lookup(rd_in);
|
||||
auto rd = env.reverse_field_multi_lookup(rd_in);
|
||||
int idx_of_success = -1;
|
||||
if (rd.success) {
|
||||
for (int i = 0; i < (int)rd.results.size(); i++) {
|
||||
@@ -1689,7 +1687,7 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
|
||||
input.offset = arg0_type.get_integer_constant();
|
||||
input.stride = 0;
|
||||
input.base_type = arg1_type.typespec();
|
||||
auto out = env.dts->ts.reverse_field_lookup(input);
|
||||
auto out = env.reverse_field_lookup(input);
|
||||
if (out.success && !out.has_variable_token()) {
|
||||
// it is. now we have to modify things
|
||||
// first, look for the index
|
||||
|
||||
@@ -614,7 +614,13 @@ void ObjectFileDB::ir2_type_analysis_pass(int seg, const Config& config, ObjectF
|
||||
|
||||
auto scratchpad_type = config.scratchpad_types_by_object.find(obj_name);
|
||||
if (scratchpad_type != config.scratchpad_types_by_object.end()) {
|
||||
func.ir2.env.set_scratchpad_type(TypeSpec(scratchpad_type->second));
|
||||
func.ir2.env.set_scratchpad_type(TypeSpec(scratchpad_type->second.type_name));
|
||||
std::vector<FieldReverseLookupScoreOverride> score_overrides;
|
||||
for (const auto& override_config : scratchpad_type->second.field_score_overrides) {
|
||||
score_overrides.push_back(
|
||||
{override_config.type_name, override_config.field_name, override_config.score});
|
||||
}
|
||||
func.ir2.env.set_reverse_lookup_field_score_overrides(std::move(score_overrides));
|
||||
}
|
||||
|
||||
if (config.hacks.pair_functions_by_name.find(func_name) !=
|
||||
|
||||
+16
-1
@@ -196,7 +196,22 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
if (json.contains("scratchpad_types_file")) {
|
||||
auto scratchpad_types_json = read_json_file_from_config(json, "scratchpad_types_file");
|
||||
for (auto& kv : scratchpad_types_json.items()) {
|
||||
config.scratchpad_types_by_object[kv.key()] = kv.value().get<std::string>();
|
||||
ScratchpadTypeConfig scratchpad_config;
|
||||
if (kv.value().is_string()) {
|
||||
scratchpad_config.type_name = kv.value().get<std::string>();
|
||||
} else {
|
||||
scratchpad_config.type_name = kv.value().at("type").get<std::string>();
|
||||
if (kv.value().contains("field_score_overrides")) {
|
||||
for (const auto& score_json : kv.value().at("field_score_overrides")) {
|
||||
ScratchpadTypeConfig::FieldScoreOverride score_override;
|
||||
score_override.type_name = score_json.at("type").get<std::string>();
|
||||
score_override.field_name = score_json.at("field").get<std::string>();
|
||||
score_override.score = score_json.at("score").get<double>();
|
||||
scratchpad_config.field_score_overrides.push_back(std::move(score_override));
|
||||
}
|
||||
}
|
||||
}
|
||||
config.scratchpad_types_by_object[kv.key()] = std::move(scratchpad_config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -28,6 +28,16 @@ struct StackTypeCast {
|
||||
std::string type_name;
|
||||
};
|
||||
|
||||
struct ScratchpadTypeConfig {
|
||||
std::string type_name;
|
||||
struct FieldScoreOverride {
|
||||
std::string type_name;
|
||||
std::string field_name;
|
||||
double score = 0;
|
||||
};
|
||||
std::vector<FieldScoreOverride> field_score_overrides;
|
||||
};
|
||||
|
||||
struct LabelConfigInfo {
|
||||
// if the label is a "value" type, it will be loaded directly into a register.
|
||||
// in all cases, this is a constant, either a 64-bit integer or a float.
|
||||
@@ -167,7 +177,7 @@ struct Config {
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, LabelConfigInfo>> label_types;
|
||||
std::unordered_map<std::string, std::vector<StackStructureHint>>
|
||||
stack_structure_hints_by_function;
|
||||
std::unordered_map<std::string, std::string> scratchpad_types_by_object;
|
||||
std::unordered_map<std::string, ScratchpadTypeConfig> scratchpad_types_by_object;
|
||||
std::unordered_map<std::string, ObjectPatchInfo> object_patches;
|
||||
|
||||
std::unordered_map<std::string, int> bad_format_strings;
|
||||
|
||||
@@ -4319,7 +4319,7 @@ sound." (_type_ int) int) ;; 12
|
||||
(define-extern dma-send-chain-no-tte "Wait for a channel, flush the cache, and start a source-chain DMA without transferring its tags. This function is unused." (function dma-bank-source uint none))
|
||||
(define-extern dma-send-chain-no-flush "Wait for a channel and start a source-chain DMA with tag transfer enabled without first flushing the data cache." (function dma-bank-source uint none))
|
||||
(define-extern dma-send-to-spr "Transfer quadwords from main memory to scratchpad, optionally waiting for completion." (function uint uint uint symbol none))
|
||||
(define-extern dma-send-to-spr-no-flush "Transfer quadwords from main memory to scratchpad without flushing the data cache, optionally waiting for completion." (function uint uint uint symbol none))
|
||||
(define-extern dma-send-to-spr-no-flush "Transfer quadwords from main memory to scratchpad without flushing the data cache, optionally waiting for completion." (function pointer pointer uint symbol none))
|
||||
(define-extern dma-send-from-spr "Transfer quadwords from scratchpad to main memory, optionally waiting for completion." (function uint uint uint symbol none))
|
||||
(define-extern dma-send-from-spr-no-flush "Transfer quadwords from scratchpad to main memory without flushing the data cache, optionally waiting for completion." (function uint uint uint symbol none))
|
||||
(define-extern dma-initialize "Mask the VIF0 and VIF1 DMAtag mismatch error required by the EE hardware workaround." (function none))
|
||||
|
||||
@@ -155,6 +155,26 @@
|
||||
{"count": "14", "fields": ":regs0 (gif-reg-id $reg0) :regs1 (gif-reg-id $reg1) :regs2 (gif-reg-id $reg2) :regs3 (gif-reg-id $reg3) :regs4 (gif-reg-id $reg4) :regs5 (gif-reg-id $reg5) :regs6 (gif-reg-id $reg6) :regs7 (gif-reg-id $reg7) :regs8 (gif-reg-id $reg8) :regs9 (gif-reg-id $reg9) :regs10 (gif-reg-id $reg10) :regs11 (gif-reg-id $reg11) :regs12 (gif-reg-id $reg12) :regs13 (gif-reg-id $reg13)", "regs": "$reg0 $reg1 $reg2 $reg3 $reg4 $reg5 $reg6 $reg7 $reg8 $reg9 $reg10 $reg11 $reg12 $reg13"},
|
||||
{"count": "15", "fields": ":regs0 (gif-reg-id $reg0) :regs1 (gif-reg-id $reg1) :regs2 (gif-reg-id $reg2) :regs3 (gif-reg-id $reg3) :regs4 (gif-reg-id $reg4) :regs5 (gif-reg-id $reg5) :regs6 (gif-reg-id $reg6) :regs7 (gif-reg-id $reg7) :regs8 (gif-reg-id $reg8) :regs9 (gif-reg-id $reg9) :regs10 (gif-reg-id $reg10) :regs11 (gif-reg-id $reg11) :regs12 (gif-reg-id $reg12) :regs13 (gif-reg-id $reg13) :regs14 (gif-reg-id $reg14)", "regs": "$reg0 $reg1 $reg2 $reg3 $reg4 $reg5 $reg6 $reg7 $reg8 $reg9 $reg10 $reg11 $reg12 $reg13 $reg14"},
|
||||
{"count": "16", "fields": ":regs0 (gif-reg-id $reg0) :regs1 (gif-reg-id $reg1) :regs2 (gif-reg-id $reg2) :regs3 (gif-reg-id $reg3) :regs4 (gif-reg-id $reg4) :regs5 (gif-reg-id $reg5) :regs6 (gif-reg-id $reg6) :regs7 (gif-reg-id $reg7) :regs8 (gif-reg-id $reg8) :regs9 (gif-reg-id $reg9) :regs10 (gif-reg-id $reg10) :regs11 (gif-reg-id $reg11) :regs12 (gif-reg-id $reg12) :regs13 (gif-reg-id $reg13) :regs14 (gif-reg-id $reg14) :regs15 (gif-reg-id $reg15)", "regs": "$reg0 $reg1 $reg2 $reg3 $reg4 $reg5 $reg6 $reg7 $reg8 $reg9 $reg10 $reg11 $reg12 $reg13 $reg14 $reg15"}
|
||||
],
|
||||
// A static rgba constructor omits fields whose component is zero. Recover the source macro
|
||||
// for every possible subset while supplying the omitted zeroes explicitly.
|
||||
"static-rgba": [
|
||||
{"mask": "0000", "fields": "", "r": "0", "g": "0", "b": "0", "a": "0"},
|
||||
{"mask": "1000", "fields": ":r $r", "r": "$r", "g": "0", "b": "0", "a": "0"},
|
||||
{"mask": "0100", "fields": ":g $g", "r": "0", "g": "$g", "b": "0", "a": "0"},
|
||||
{"mask": "0010", "fields": ":b $b", "r": "0", "g": "0", "b": "$b", "a": "0"},
|
||||
{"mask": "0001", "fields": ":a $a", "r": "0", "g": "0", "b": "0", "a": "$a"},
|
||||
{"mask": "1100", "fields": ":r $r :g $g", "r": "$r", "g": "$g", "b": "0", "a": "0"},
|
||||
{"mask": "1010", "fields": ":r $r :b $b", "r": "$r", "g": "0", "b": "$b", "a": "0"},
|
||||
{"mask": "1001", "fields": ":r $r :a $a", "r": "$r", "g": "0", "b": "0", "a": "$a"},
|
||||
{"mask": "0110", "fields": ":g $g :b $b", "r": "0", "g": "$g", "b": "$b", "a": "0"},
|
||||
{"mask": "0101", "fields": ":g $g :a $a", "r": "0", "g": "$g", "b": "0", "a": "$a"},
|
||||
{"mask": "0011", "fields": ":b $b :a $a", "r": "0", "g": "0", "b": "$b", "a": "$a"},
|
||||
{"mask": "1110", "fields": ":r $r :g $g :b $b", "r": "$r", "g": "$g", "b": "$b", "a": "0"},
|
||||
{"mask": "1101", "fields": ":r $r :g $g :a $a", "r": "$r", "g": "$g", "b": "0", "a": "$a"},
|
||||
{"mask": "1011", "fields": ":r $r :b $b :a $a", "r": "$r", "g": "0", "b": "$b", "a": "$a"},
|
||||
{"mask": "0111", "fields": ":g $g :b $b :a $a", "r": "0", "g": "$g", "b": "$b", "a": "$a"},
|
||||
{"mask": "1111", "fields": ":r $r :g $g :b $b :a $a", "r": "$r", "g": "$g", "b": "$b", "a": "$a"}
|
||||
]
|
||||
},
|
||||
"rules": [
|
||||
@@ -496,6 +516,17 @@
|
||||
"match": "(new 'static 'gif-tag-regs {{fields}})",
|
||||
"rewrite": "(gs-reg-list {{regs}})"
|
||||
},
|
||||
{
|
||||
"name": "static-rgba-{{mask}}",
|
||||
"for_each": "static-rgba",
|
||||
"match": "(new 'static 'rgba {{fields}})",
|
||||
"rewrite": "(static-rgba {{r}} {{g}} {{b}} {{a}})"
|
||||
},
|
||||
{
|
||||
"name": "add-profile-frame",
|
||||
"match": "(if *debug-segment* (add-frame (-> (current-frame) profile-bar 0) $name (static-rgba $r $g $b $a)))",
|
||||
"rewrite": "(add-profile-frame! $r $g $b $a $name)"
|
||||
},
|
||||
{
|
||||
"name": "scratchpad-object-direct-{{type}}",
|
||||
"for_each": "scratchpad-object-type",
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
{
|
||||
"cam-debug": "cam-dbg-scratch"
|
||||
"cam-debug": "cam-dbg-scratch",
|
||||
"bsp": {
|
||||
"type": "terrain-context",
|
||||
"field_score_overrides": [
|
||||
{"type": "work-area", "field": "background", "score": 1000}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,16 +1208,7 @@
|
||||
],
|
||||
"(method 10 bsp-header)": [
|
||||
[[51, 61], "a0", "(pointer uint128)"],
|
||||
[[51, 61], "a1", "(pointer uint128)"],
|
||||
[133, "v1", "terrain-bsp"],
|
||||
[141, "v1", "terrain-bsp"],
|
||||
[148, "v1", "terrain-bsp"],
|
||||
[5, "a0", "terrain-bsp"],
|
||||
[8, "a0", "terrain-bsp"]
|
||||
],
|
||||
"(method 15 bsp-header)": [
|
||||
[5, "a0", "terrain-bsp"],
|
||||
[8, "a0", "terrain-bsp"]
|
||||
[[51, 61], "a1", "(pointer uint128)"]
|
||||
],
|
||||
"upload-vis-bits": [
|
||||
[[4, 16], "a1", "(pointer uint128)"],
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
(if wait-for-completion? (dma-sync (the-as pointer bank) 0 0))
|
||||
(none))
|
||||
|
||||
(defun dma-send-to-spr-no-flush ((scratchpad-address uint) (memory-address uint) (quadword-count uint) (wait-for-completion? symbol))
|
||||
(defun dma-send-to-spr-no-flush ((scratchpad-address pointer) (memory-address pointer) (quadword-count uint) (wait-for-completion? symbol))
|
||||
"Transfer quadwords from main memory to scratchpad without flushing the data cache, optionally
|
||||
waiting for completion."
|
||||
(local-vars (bank dma-bank-spr))
|
||||
|
||||
@@ -9,34 +9,23 @@
|
||||
|
||||
;; Both shapes are stored the same way: origin is one end of the centerline, axis is a unit
|
||||
;; direction, length is the centerline length, and radius is the distance from the centerline. So the
|
||||
;; far end is origin + axis * length, and a capsule extends radius beyond each end while a flat
|
||||
;; cylinder does not.
|
||||
;; far end is origin + axis * length.
|
||||
;;
|
||||
;; The intersect methods take a finite probe: the segment from probe-origin to
|
||||
;; probe-origin + probe-displacement. They return the fraction of that displacement at which the
|
||||
;; earliest contact happens, always between zero and one, or COLLISION_MISS. Compare a returned
|
||||
;; fraction against zero before using it, since COLLISION_MISS is a large negative number rather
|
||||
;; than a distinguished type.
|
||||
;;
|
||||
;; The debug-draw methods build one longitudinal outline, rotate it a sixteenth of a revolution at a
|
||||
;; time, and draw both the rotated copy and the segment joining it to the previous one. The rotation
|
||||
;; matrix has its translation row patched so it turns about the shape's own axis rather than the
|
||||
;; world origin, which is what lets the same matrix be reapplied sixteen times.
|
||||
;; earliest contact happens, always between zero and one, or COLLISION_MISS.
|
||||
|
||||
;; DECOMP BEGINS
|
||||
|
||||
(defmethod ray-capsule-intersect ((this cylinder) (probe-origin vector) (probe-displacement vector))
|
||||
"Test the finite probe origin + fraction * displacement against the cylindrical wall and both
|
||||
hemispherical ends. Return the earliest zero-to-one fraction, or COLLISION_MISS.
|
||||
The wall test's axis-point output is computed into a stack vector and discarded, so this method
|
||||
reports when the capsule is hit but not where."
|
||||
hemispherical ends. Return the earliest zero-to-one fraction, or COLLISION_MISS."
|
||||
(let ((axis-point (new 'stack-no-clear 'vector))
|
||||
(end-center (new 'stack-no-clear 'vector)))
|
||||
0.0
|
||||
0.0
|
||||
;; Test the wall first, then keep either spherical-cap contact when it is earlier.
|
||||
;; A negative wall fraction means the wall was missed, so the first cap contact replaces it
|
||||
;; outright; after that the comparison is a genuine "is this one earlier".
|
||||
|
||||
;; test wall
|
||||
(let ((contact-fraction (ray-cylinder-intersect probe-origin
|
||||
probe-displacement
|
||||
(-> this origin)
|
||||
@@ -44,13 +33,18 @@
|
||||
(-> this radius)
|
||||
(-> this length)
|
||||
axis-point)))
|
||||
;; test near cap
|
||||
(let ((origin-cap-fraction (ray-sphere-intersect probe-origin probe-displacement (-> this origin) (-> this radius))))
|
||||
(if (and (>= origin-cap-fraction 0.0) (or (< contact-fraction 0.0) (< origin-cap-fraction contact-fraction)))
|
||||
(set! contact-fraction origin-cap-fraction)))
|
||||
(set! contact-fraction origin-cap-fraction)))
|
||||
|
||||
;; test far cap
|
||||
(vector+float*! end-center (-> this origin) (-> this axis) (-> this length))
|
||||
(let ((end-cap-fraction (ray-sphere-intersect probe-origin probe-displacement end-center (-> this radius))))
|
||||
(if (and (>= end-cap-fraction 0.0) (or (< contact-fraction 0.0) (< end-cap-fraction contact-fraction)))
|
||||
(set! contact-fraction end-cap-fraction)))
|
||||
(set! contact-fraction end-cap-fraction)))
|
||||
|
||||
;; return closest hit.
|
||||
contact-fraction)))
|
||||
|
||||
;; This is used to hold vertices for debug-drawing cylinders.
|
||||
@@ -124,14 +118,11 @@
|
||||
(defun ray-arbitrary-circle-intersect ((probe-origin vector) (probe-displacement vector) (circle-origin vector) (circle-normal vector) (radius float))
|
||||
"Intersect the finite probe origin + fraction * displacement with the filled disk centered at
|
||||
circle-origin in circle-normal's plane. Return a zero-to-one fraction only when the plane contact
|
||||
lies strictly inside radius; return COLLISION_MISS otherwise.
|
||||
circle-normal need not be unit, since it appears in both halves of the ratio, but it must not be
|
||||
perpendicular to probe-displacement: a displacement parallel to the plane divides by zero and the
|
||||
resulting fraction is compared without any special case. A point exactly on the rim counts as a
|
||||
miss, and the disk is two-sided."
|
||||
lies strictly inside radius; return COLLISION_MISS otherwise."
|
||||
;; The membership test squares both sides rather than taking a square root of the radial offset.
|
||||
(let* ((center-offset (vector-! (new 'stack-no-clear 'vector) circle-origin probe-origin))
|
||||
(contact-fraction (/ (vector-dot center-offset circle-normal) (vector-dot probe-displacement circle-normal))))
|
||||
(contact-fraction (/ (vector-dot center-offset circle-normal)
|
||||
(vector-dot probe-displacement circle-normal))))
|
||||
(cond
|
||||
((or (< 1.0 contact-fraction) (< contact-fraction 0.0)) COLLISION_MISS)
|
||||
((let ((radial-offset (new 'stack-no-clear 'vector)))
|
||||
@@ -143,9 +134,7 @@
|
||||
|
||||
(defmethod ray-flat-cyl-intersect ((this cylinder-flat) (probe-origin vector) (probe-displacement vector))
|
||||
"Test the finite probe origin + fraction * displacement against the cylindrical wall and both
|
||||
filled end caps. Return the earliest zero-to-one fraction, or COLLISION_MISS.
|
||||
Unlike ray-capsule-intersect this keeps a contact position in a stack vector, overwriting it with
|
||||
the relevant cap center when a cap wins, but that vector is local and is discarded on return."
|
||||
filled end caps. Return the earliest zero-to-one fraction, or COLLISION_MISS."
|
||||
(let ((axis-point (new 'stack-no-clear 'vector))
|
||||
(end-center (new 'stack-no-clear 'vector)))
|
||||
0.0
|
||||
@@ -217,7 +206,9 @@
|
||||
(dotimes (vertex-index 10)
|
||||
(vector-matrix*! (-> rotated-vertices vert vertex-index) (-> vertices vert vertex-index) rotation-matrix)
|
||||
(camera-line (-> vertices vert vertex-index) (-> rotated-vertices vert vertex-index) color)
|
||||
(if (nonzero? vertex-index) (camera-line (-> vertices vert vertex-index) (-> vertices vert (+ vertex-index -1)) color)))
|
||||
(let ((swap vertices)) (set! vertices rotated-vertices) (set! rotated-vertices swap)))))
|
||||
(if (nonzero? vertex-index)
|
||||
(camera-line (-> vertices vert vertex-index) (-> vertices vert (+ vertex-index -1)) color)))
|
||||
(let ((swap vertices))
|
||||
(set! vertices rotated-vertices) (set! rotated-vertices swap)))))
|
||||
0
|
||||
(none)))
|
||||
|
||||
@@ -202,6 +202,11 @@
|
||||
(defmacro current-frame ()
|
||||
`(-> *display* frames (-> *display* on-screen) frame))
|
||||
|
||||
(defmacro add-profile-frame! (r g b a name)
|
||||
"Add a colored marker to the current profile bar in debug builds."
|
||||
`(if *debug-segment*
|
||||
(add-frame (-> (current-frame) profile-bar 0) ,name (static-rgba ,r ,g ,b ,a))))
|
||||
|
||||
(defmacro current-time ()
|
||||
`(-> *display* base-frame-counter))
|
||||
|
||||
|
||||
+208
-252
@@ -15,7 +15,7 @@
|
||||
|
||||
(defun-recursive mem-usage-bsp-tree none ((header bsp-header) (node bsp-node) (mem-use memory-usage-block) (flags mem-usage-flags))
|
||||
"Recursively count the 32-byte internal nodes reachable from node in the BSP-node memory
|
||||
category. Nonpositive terminal children are not followed; header and flags are unused."
|
||||
category."
|
||||
(cond
|
||||
((zero? node))
|
||||
(else
|
||||
@@ -30,238 +30,173 @@
|
||||
(defmethod mem-usage ((this bsp-header) (mem-use memory-usage-block) (flags mem-usage-flags))
|
||||
"Account for this header's owned level data and delegate memory accounting to its drawable
|
||||
trees and cameras."
|
||||
;; start off by setting the current bsp
|
||||
;; seems unused?
|
||||
(set! (-> mem-use work-bsp) this)
|
||||
;; this seems slightly wrong, we count the file-info toward array.
|
||||
(when (nonzero? (-> this info))
|
||||
(mem-usage-add! mem-use array 1 (asize-of (-> this info))))
|
||||
;; measure the drawable trees.
|
||||
(if (nonzero? (-> this drawable-trees)) (mem-usage (-> this drawable-trees) mem-use flags))
|
||||
;; add stuff
|
||||
(if (nonzero? (-> this drawable-trees))
|
||||
(mem-usage (-> this drawable-trees) mem-use flags))
|
||||
;; set some names for categories that don't use the normal macros
|
||||
(set! (-> mem-use length) (max 63 (-> mem-use length)))
|
||||
(set! (-> mem-use data 43 name) "entity")
|
||||
(set! (-> mem-use data 44 name) "camera")
|
||||
(set! (-> mem-use data 62 name) "pat")
|
||||
(set! (-> mem-use data 58 name) "bsp-node")
|
||||
;; add the bsp-header itself
|
||||
(mem-usage-add! mem-use bsp-main 1 400)
|
||||
;; add the visible list
|
||||
(mem-usage-add! mem-use bsp-leaf-vis-self 1 (-> this visible-list-length))
|
||||
;; add the unk-data-0
|
||||
(mem-usage-add! mem-use bsp-misc 1 (* (-> this texture-remap-table-len) 8))
|
||||
;; add the unk-data-1
|
||||
(mem-usage-add! mem-use bsp-misc 1 (* (-> this texture-page-count) 4))
|
||||
;; add unk-zero-0
|
||||
(when (nonzero? (-> this unk-zero-0))
|
||||
(mem-usage-add! mem-use bsp-misc 1 (asize-of (-> this unk-zero-0))))
|
||||
;; add adgifs
|
||||
(when (nonzero? (-> this adgifs))
|
||||
(mem-usage-add! mem-use bsp-misc 1 (asize-of (-> this adgifs))))
|
||||
;; add boxes
|
||||
(when (nonzero? (-> this boxes))
|
||||
(mem-usage-add! mem-use bsp-misc 1 (asize-of (-> this boxes)))
|
||||
;; add box indices
|
||||
(when (nonzero? (-> this split-box-indices))
|
||||
(mem-usage-add! mem-use bsp-misc 1 (* (-> this boxes length) 2))))
|
||||
;; add actor-birth-order
|
||||
(when (nonzero? (-> this actor-birth-order))
|
||||
;; add actors
|
||||
(mem-usage-add! mem-use bsp-misc 1 (* (-> this actors length) 4)))
|
||||
;; add pat
|
||||
(+! (-> mem-use data 62 count) (-> this pat-length))
|
||||
(let ((pat-bytes (* (-> this pat-length) 4)))
|
||||
(+! (-> mem-use data 62 used) pat-bytes)
|
||||
(+! (-> mem-use data 62 total) (logand -16 (+ pat-bytes 15))))
|
||||
;; add cameras
|
||||
(let ((cameras (-> this cameras)))
|
||||
(when (nonzero? cameras)
|
||||
(dotimes (i (-> cameras length))
|
||||
(mem-usage (-> cameras i) mem-use (logior flags (mem-usage-flags resource-camera))))))
|
||||
;; add the tree itself
|
||||
(mem-usage-bsp-tree this (the-as bsp-node (-> this nodes)) mem-use flags)
|
||||
;; recursively add bsp tree nodes
|
||||
(mem-usage-bsp-tree this (-> this nodes 0) mem-use flags)
|
||||
this)
|
||||
|
||||
(defmethod login ((this bsp-header))
|
||||
"Log in the level's drawable trees and every ADGIF shader."
|
||||
"Log in the level's drawable trees and every ADGIF shader.
|
||||
This method takes too long to run and level.gc's login state
|
||||
machine splits the work over multiple frames."
|
||||
;; login our drawables
|
||||
(if (nonzero? (-> this drawable-trees)) (login (-> this drawable-trees)))
|
||||
(if (nonzero? (-> this drawable-trees))
|
||||
(login (-> this drawable-trees)))
|
||||
;; login our shaders
|
||||
(when (nonzero? (-> this adgifs))
|
||||
(let ((shaders (-> this adgifs))) (dotimes (i (-> shaders length)) (adgif-shader-login-no-remap (-> shaders data i)))))
|
||||
(let ((shaders (-> this adgifs)))
|
||||
(dotimes (i (-> shaders length))
|
||||
(adgif-shader-login-no-remap (-> shaders data i)))))
|
||||
this)
|
||||
|
||||
(define *test-shrub* 0) ;; unused.
|
||||
|
||||
(defmacro setup-drawing-registers ()
|
||||
"Set VU0 registers to hold camera constants used in background rendering code."
|
||||
`(let ((math-cam *math-camera*))
|
||||
(with-vf (vf16 vf17 vf18 vf19 vf20 vf21 vf22 vf23 vf24 vf25 vf26 vf27 vf28 vf29 vf30 vf31)
|
||||
:rw 'write
|
||||
(.lvf vf16 (&-> math-cam plane 0 quad))
|
||||
(.lvf vf17 (&-> math-cam plane 1 quad))
|
||||
(.lvf vf18 (&-> math-cam plane 2 quad))
|
||||
(.lvf vf19 (&-> math-cam plane 3 quad))
|
||||
(.lvf vf20 (&-> math-cam shrub-mat vector 0 quad))
|
||||
(.lvf vf21 (&-> math-cam shrub-mat vector 1 quad))
|
||||
(.lvf vf22 (&-> math-cam shrub-mat vector 2 quad))
|
||||
(.lvf vf23 (&-> math-cam shrub-mat vector 3 quad))
|
||||
(.lvf vf24 (&-> math-cam camera-rot vector 0 quad))
|
||||
(.lvf vf25 (&-> math-cam camera-rot vector 1 quad))
|
||||
(.lvf vf26 (&-> math-cam camera-rot vector 2 quad))
|
||||
(.lvf vf27 (&-> math-cam camera-rot vector 3 quad))
|
||||
(.lvf vf28 (&-> math-cam camera-temp vector 0 quad))
|
||||
(.lvf vf29 (&-> math-cam camera-temp vector 1 quad))
|
||||
(.lvf vf30 (&-> math-cam camera-temp vector 2 quad))
|
||||
(.lvf vf31 (&-> math-cam camera-temp vector 3 quad)))))
|
||||
|
||||
(defmethod draw ((this bsp-header) (other-draw bsp-header) (disp-frame display-frame))
|
||||
"Prepare scratchpad visibility, subdivision state, and math-camera VU registers; draw the
|
||||
level's drawable trees and three foreground engines for the current display frame."
|
||||
(local-vars (inverted-quad uint128) (flipped-quad uint128) (zero-quad uint128))
|
||||
(set! zero-quad (the-as uint128 0))
|
||||
(let ((lev (-> this level)))
|
||||
;; set up some stuff in the scratchpad
|
||||
(set! (-> (scratchpad-object terrain-bsp :offset TERRAIN_BSP_SCRATCHPAD) lev-index) (-> lev index))
|
||||
(set! (-> (scratchpad-object terrain-bsp :offset TERRAIN_BSP_SCRATCHPAD) mood) (-> lev mood))
|
||||
;; update the subdivision settings
|
||||
(if *artist-use-menu-subdiv*
|
||||
(update-subdivide-settings! *subdivide-settings* *math-camera* 3)
|
||||
(update-subdivide-settings! *subdivide-settings* *math-camera* (-> lev index)))
|
||||
;; at this point we are no longer adding textures, so we can mark the end of the
|
||||
;; textures with interrupts to get rendering VIF interrupts for profiling.
|
||||
(add-irq-to-tex-buckets! lev)
|
||||
;; upload the visible list to the scratchpad.
|
||||
;; the final result of all visibility calculations is stored in vis-bits.
|
||||
;; this goes at the end of the scratchpad.
|
||||
(let ((vis-list-qwc (/ (+ (-> this visible-list-length) 15) 16)))
|
||||
(dma-send-to-spr-no-flush (scratchpad-object uint :offset VISIBLE_LIST_SCRATCHPAD)
|
||||
(the-as uint (-> lev vis-bits))
|
||||
(the-as uint vis-list-qwc)
|
||||
#f)))
|
||||
;; this is a race condition with the previous DMA transfer.
|
||||
;; probably the DMA wins though.
|
||||
;; this messes with the visibility bits to invert what was just uploaded
|
||||
(when *artist-flip-visible*
|
||||
(let ((vis-list-qwc2 (/ (+ (-> this visible-list-length) 15) 16))
|
||||
(vis-list-spad (scratchpad-object (pointer uint128) :offset VISIBLE_LIST_SCRATCHPAD))
|
||||
(vis-list-lev (the-as (pointer uint128) (-> this all-visible-list))))
|
||||
;; iterate through all qw's in the visible list.
|
||||
(dotimes (current-qw vis-list-qwc2)
|
||||
;; invert the stuff in the spad list
|
||||
(let ((scratch-quad (-> vis-list-spad current-qw)))
|
||||
;; note: this isn't great x86 code, but it's probably fine.
|
||||
(.pnor inverted-quad scratch-quad zero-quad))
|
||||
;; and with the all visible list so we don't
|
||||
;; accidentally turn on the vis bit for something that
|
||||
;; doesn't exist.
|
||||
(let ((all-visible-quad (-> vis-list-lev current-qw))) (.pand flipped-quad inverted-quad all-visible-quad))
|
||||
(set! (-> vis-list-spad current-qw) flipped-quad))))
|
||||
;; set up the math camera registers
|
||||
(let ((math-cam *math-camera*))
|
||||
(with-vf (vf16 vf17 vf18 vf19 vf20 vf21 vf22 vf23 vf24 vf25 vf26 vf27 vf28 vf29 vf30 vf31)
|
||||
:rw 'write
|
||||
(.lvf vf16 (&-> math-cam plane 0 quad))
|
||||
(.lvf vf17 (&-> math-cam plane 1 quad))
|
||||
(.lvf vf18 (&-> math-cam plane 2 quad))
|
||||
(.lvf vf19 (&-> math-cam plane 3 quad))
|
||||
(.lvf vf20 (&-> math-cam shrub-mat vector 0 quad))
|
||||
(.lvf vf21 (&-> math-cam shrub-mat vector 1 quad))
|
||||
(.lvf vf22 (&-> math-cam shrub-mat vector 2 quad))
|
||||
(.lvf vf23 (&-> math-cam shrub-mat vector 3 quad))
|
||||
(.lvf vf24 (&-> math-cam camera-rot vector 0 quad))
|
||||
(.lvf vf25 (&-> math-cam camera-rot vector 1 quad))
|
||||
(.lvf vf26 (&-> math-cam camera-rot vector 2 quad))
|
||||
(.lvf vf27 (&-> math-cam camera-rot vector 3 quad))
|
||||
(.lvf vf28 (&-> math-cam camera-temp vector 0 quad))
|
||||
(.lvf vf29 (&-> math-cam camera-temp vector 1 quad))
|
||||
(.lvf vf30 (&-> math-cam camera-temp vector 2 quad))
|
||||
(.lvf vf31 (&-> math-cam camera-temp vector 3 quad))))
|
||||
;; draw the drawables!
|
||||
;; start a profile bar.
|
||||
(when (nonzero? (-> this drawable-trees))
|
||||
(if *debug-segment*
|
||||
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
|
||||
'draw
|
||||
(new 'static 'rgba :r #x40 :b #x40 :a #x80)))
|
||||
;; draw!
|
||||
(let ((trees (-> this drawable-trees))) (draw trees trees disp-frame))
|
||||
;; end a profile bar
|
||||
(if *debug-segment*
|
||||
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
|
||||
'draw
|
||||
(new 'static 'rgba :r #x80 :g #xc0 :a #x80))))
|
||||
;; run the foreground system (0 check added)
|
||||
(when (nonzero? foreground-engine-execute)
|
||||
(local-vars (inverted-quad uint128) (flipped-quad uint128))
|
||||
(slet (spad terrain-context)
|
||||
(let ((lev (-> this level)))
|
||||
;; cache level info in scratchpad
|
||||
(set! (-> spad bsp lev-index) (-> lev index))
|
||||
(set! (-> spad bsp mood) (-> lev mood))
|
||||
|
||||
;; update background rendering subdivision (level of detail) thresholds consumed by
|
||||
;; renderers. level "3" is set from the menu
|
||||
(if *artist-use-menu-subdiv*
|
||||
(update-subdivide-settings! *subdivide-settings* *math-camera* 3)
|
||||
(update-subdivide-settings! *subdivide-settings* *math-camera* (-> lev index)))
|
||||
|
||||
;; set up interrupts on texture bucket completion
|
||||
;; texture upload DMA is already built, using info from the last frame.
|
||||
(add-irq-to-tex-buckets! lev)
|
||||
|
||||
;; upload visibility list to scratchpad (no sync happens, this is a race)
|
||||
(let ((vis-list-qwc (/ (+ (-> this visible-list-length) 15) 16)))
|
||||
(dma-send-to-spr-no-flush (-> spad work background vis-list) (-> lev vis-bits) (the-as uint vis-list-qwc) #f)))
|
||||
|
||||
;; flip visibility bits. Note that not every bit in the string is used and we only toggle used bits.
|
||||
(when *artist-flip-visible*
|
||||
(let ((vis-list-qwc2 (/ (+ (-> this visible-list-length) 15) 16))
|
||||
(vis-list-spad (the-as (pointer uint128) (-> spad work background vis-list)))
|
||||
(vis-list-lev (the-as (pointer uint128) (-> this all-visible-list))))
|
||||
(dotimes (current-qw vis-list-qwc2)
|
||||
;; invert all bits
|
||||
(let ((scratch-quad (-> vis-list-spad current-qw)))
|
||||
(.pnor inverted-quad scratch-quad 0))
|
||||
;; mask with all-visible list
|
||||
(let ((all-visible-quad (-> vis-list-lev current-qw)))
|
||||
(.pand flipped-quad inverted-quad all-visible-quad))
|
||||
(set! (-> vis-list-spad current-qw) flipped-quad))))
|
||||
|
||||
;; set up VU0 registers prior to traversing drawable trees
|
||||
(setup-drawing-registers)
|
||||
|
||||
(when (nonzero? (-> this drawable-trees))
|
||||
(add-profile-frame! #x40 0 #x40 #x80 'draw)
|
||||
(let ((trees (-> this drawable-trees)))
|
||||
;; draw! This ends up doing relatively little, most trees defer their drawing,
|
||||
;; and this just does book-keeping on what needs drawing later.
|
||||
(draw trees trees disp-frame))
|
||||
(add-profile-frame! #x80 #xc0 0 #x80 'draw))
|
||||
|
||||
;; draw foreground geometry. The foreground engines store the process-drawables associated with
|
||||
;; this level.
|
||||
(let ((frame (current-frame)))
|
||||
;; 0
|
||||
(foreground-engine-execute (-> this level foreground-draw-engine 0)
|
||||
frame
|
||||
(-> (scratchpad-object terrain-bsp :offset TERRAIN_BSP_SCRATCHPAD) lev-index)
|
||||
0)
|
||||
;; 1
|
||||
(foreground-engine-execute (-> this level foreground-draw-engine 1)
|
||||
frame
|
||||
(-> (scratchpad-object terrain-bsp :offset TERRAIN_BSP_SCRATCHPAD) lev-index)
|
||||
1)
|
||||
;; 2
|
||||
(foreground-engine-execute (-> this level foreground-draw-engine 2)
|
||||
frame
|
||||
(-> (scratchpad-object terrain-bsp :offset TERRAIN_BSP_SCRATCHPAD) lev-index)
|
||||
2)))
|
||||
(none))
|
||||
(foreground-engine-execute (-> this level foreground-draw-engine 0) frame (-> spad bsp lev-index) 0)
|
||||
(foreground-engine-execute (-> this level foreground-draw-engine 1) frame (-> spad bsp lev-index) 1)
|
||||
(foreground-engine-execute (-> this level foreground-draw-engine 2) frame (-> spad bsp lev-index) 2))
|
||||
(none)))
|
||||
|
||||
(defmethod debug-draw ((this bsp-header) (other-draw drawable) (disp-frame display-frame))
|
||||
"Prepare the level's scratchpad visibility and math-camera VU registers, then submit debug
|
||||
geometry from its drawable trees."
|
||||
(let ((lev (-> this level)))
|
||||
;; set up some stuff in the scratchpad
|
||||
(set! (-> (scratchpad-object terrain-bsp :offset TERRAIN_BSP_SCRATCHPAD) lev-index) (-> lev index))
|
||||
(set! (-> (scratchpad-object terrain-bsp :offset TERRAIN_BSP_SCRATCHPAD) mood) (-> lev mood))
|
||||
(add-irq-to-tex-buckets! lev)
|
||||
(let ((vis-list-qwc (/ (+ (-> this visible-list-length) 15) 16)))
|
||||
(dma-send-to-spr-no-flush (scratchpad-object uint :offset VISIBLE_LIST_SCRATCHPAD)
|
||||
(the-as uint (-> lev vis-bits))
|
||||
(the-as uint vis-list-qwc)
|
||||
#f)))
|
||||
(let ((math-cam *math-camera*))
|
||||
(with-vf (vf16 vf17 vf18 vf19 vf20 vf21 vf22 vf23 vf24 vf25 vf26 vf27 vf28 vf29 vf30 vf31)
|
||||
:rw 'write
|
||||
(.lvf vf16 (&-> math-cam plane 0 quad))
|
||||
(.lvf vf17 (&-> math-cam plane 1 quad))
|
||||
(.lvf vf18 (&-> math-cam plane 2 quad))
|
||||
(.lvf vf19 (&-> math-cam plane 3 quad))
|
||||
(.lvf vf20 (&-> math-cam shrub-mat vector 0 quad))
|
||||
(.lvf vf21 (&-> math-cam shrub-mat vector 1 quad))
|
||||
(.lvf vf22 (&-> math-cam shrub-mat vector 2 quad))
|
||||
(.lvf vf23 (&-> math-cam shrub-mat vector 3 quad))
|
||||
(.lvf vf24 (&-> math-cam camera-rot vector 0 quad))
|
||||
(.lvf vf25 (&-> math-cam camera-rot vector 1 quad))
|
||||
(.lvf vf26 (&-> math-cam camera-rot vector 2 quad))
|
||||
(.lvf vf27 (&-> math-cam camera-rot vector 3 quad))
|
||||
(.lvf vf28 (&-> math-cam camera-temp vector 0 quad))
|
||||
(.lvf vf29 (&-> math-cam camera-temp vector 1 quad))
|
||||
(.lvf vf30 (&-> math-cam camera-temp vector 2 quad))
|
||||
(.lvf vf31 (&-> math-cam camera-temp vector 3 quad))))
|
||||
(when (nonzero? (-> this drawable-trees))
|
||||
(if *debug-segment*
|
||||
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
|
||||
'draw
|
||||
(new 'static 'rgba :r #x40 :b #x40 :a #x80)))
|
||||
(let ((trees (-> this drawable-trees))) (debug-draw trees trees disp-frame))
|
||||
(if *debug-segment*
|
||||
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
|
||||
'draw
|
||||
(new 'static 'rgba :r #x80 :g #xc0 :a #x80))))
|
||||
(none))
|
||||
(slet (spad terrain-context)
|
||||
(let ((lev (-> this level)))
|
||||
(set! (-> spad bsp lev-index) (-> lev index))
|
||||
(set! (-> spad bsp mood) (-> lev mood))
|
||||
(add-irq-to-tex-buckets! lev)
|
||||
(let ((vis-list-qwc (/ (+ (-> this visible-list-length) 15) 16)))
|
||||
(dma-send-to-spr-no-flush (-> spad work background vis-list) (-> lev vis-bits) (the-as uint vis-list-qwc) #f)))
|
||||
|
||||
(setup-drawing-registers)
|
||||
|
||||
(when (nonzero? (-> this drawable-trees))
|
||||
(add-profile-frame! #x40 0 #x40 #x80 'draw)
|
||||
(let ((trees (-> this drawable-trees)))
|
||||
(debug-draw trees trees disp-frame))
|
||||
(add-profile-frame! #x80 #xc0 0 #x80 'draw))
|
||||
(none)))
|
||||
|
||||
(defmethod collect-stats ((this bsp-header))
|
||||
"Upload the current visibility bits and math-camera VU registers, then collect renderer
|
||||
statistics from the level's drawable trees."
|
||||
(let ((lev (-> this level))
|
||||
(vis-list-qwc (/ (+ (-> this visible-list-length) 15) 16)))
|
||||
(dma-send-to-spr-no-flush (scratchpad-object uint :offset VISIBLE_LIST_SCRATCHPAD)
|
||||
(the-as uint (-> lev vis-bits))
|
||||
(the-as uint vis-list-qwc)
|
||||
#f))
|
||||
(let ((math-cam *math-camera*))
|
||||
(with-vf (vf16 vf17 vf18 vf19 vf20 vf21 vf22 vf23 vf24 vf25 vf26 vf27 vf28 vf29 vf30 vf31)
|
||||
:rw 'write
|
||||
(.lvf vf16 (&-> math-cam plane 0 quad))
|
||||
(.lvf vf17 (&-> math-cam plane 1 quad))
|
||||
(.lvf vf18 (&-> math-cam plane 2 quad))
|
||||
(.lvf vf19 (&-> math-cam plane 3 quad))
|
||||
(.lvf vf20 (&-> math-cam shrub-mat vector 0 quad))
|
||||
(.lvf vf21 (&-> math-cam shrub-mat vector 1 quad))
|
||||
(.lvf vf22 (&-> math-cam shrub-mat vector 2 quad))
|
||||
(.lvf vf23 (&-> math-cam shrub-mat vector 3 quad))
|
||||
(.lvf vf24 (&-> math-cam camera-rot vector 0 quad))
|
||||
(.lvf vf25 (&-> math-cam camera-rot vector 1 quad))
|
||||
(.lvf vf26 (&-> math-cam camera-rot vector 2 quad))
|
||||
(.lvf vf27 (&-> math-cam camera-rot vector 3 quad))
|
||||
(.lvf vf28 (&-> math-cam camera-temp vector 0 quad))
|
||||
(.lvf vf29 (&-> math-cam camera-temp vector 1 quad))
|
||||
(.lvf vf30 (&-> math-cam camera-temp vector 2 quad))
|
||||
(.lvf vf31 (&-> math-cam camera-temp vector 3 quad))))
|
||||
(if (nonzero? (-> this drawable-trees)) (collect-stats (-> this drawable-trees)))
|
||||
(none))
|
||||
(slet (spad terrain-context)
|
||||
(let ((lev (-> this level))
|
||||
(vis-list-qwc (/ (+ (-> this visible-list-length) 15) 16)))
|
||||
(dma-send-to-spr-no-flush (-> spad work background vis-list) (-> lev vis-bits) (the-as uint vis-list-qwc) #f))
|
||||
(setup-drawing-registers)
|
||||
(if (nonzero? (-> this drawable-trees))
|
||||
(collect-stats (-> this drawable-trees)))
|
||||
(none)))
|
||||
|
||||
|
||||
(#unless PC_PORT
|
||||
(defun bsp-camera-asm ((header bsp-header) (camera-position vector))
|
||||
@@ -302,36 +237,24 @@
|
||||
(m result r0)
|
||||
(jr ra :delay (add sp sp r0)))))
|
||||
|
||||
(#when PC_PORT
|
||||
(defun bsp-camera-asm ((header bsp-header) (camera-position vector))
|
||||
"Traverse the BSP for camera-position. At each split, select front when
|
||||
dot(camera-position, plane.xyz) - plane.w is nonnegative. Store the terminal leaf index and
|
||||
that side's packed neighboring-level flags in header."
|
||||
(local-vars (plane-side int) (node bsp-node))
|
||||
(rlet ((vf1 :class vf)
|
||||
(vf2 :class vf))
|
||||
(nop!)
|
||||
(let ((next-node (the-as bsp-node (-> header nodes))))
|
||||
(.lvf vf1 (&-> camera-position quad))
|
||||
(label cfg-1)
|
||||
(b! (< (the-as int next-node) 0) cfg-4 :delay (set! node next-node))
|
||||
(.lvf vf2 (&-> node plane quad))
|
||||
(.mul.vf.xyz vf2 vf2 vf1)
|
||||
(.add.x.vf.y vf2 vf2 vf2)
|
||||
(.add.z.vf.y vf2 vf2 vf2)
|
||||
(.sub.w.vf.y vf2 vf2 vf2)
|
||||
;; The integer sign test reads the y lane's sign after the VU-to-EE transfer.
|
||||
(.mov plane-side vf2)
|
||||
(let ((side-flags (-> node front-flags)))
|
||||
(b! (>= plane-side 0) cfg-1 :delay (set! next-node (the-as bsp-node (-> node front))))
|
||||
(set! side-flags (-> node back-flags))
|
||||
(b! #t cfg-1 :delay (set! next-node (the-as bsp-node (-> node back))))
|
||||
(label cfg-4)
|
||||
(set! (-> header current-leaf-idx) (the-as uint next-node))
|
||||
(set! (-> header current-bsp-flags) side-flags)
|
||||
))
|
||||
0
|
||||
(none))))
|
||||
(defun bsp-camera-asm ((bsp bsp-header) (pos vector))
|
||||
"Look up the leaf node containing pos and store its index in flags in the bsp-header"
|
||||
(let ((iter (-> bsp nodes 0))
|
||||
(flags (the uint 0)))
|
||||
(while (>= (the int iter) 0)
|
||||
;; do front/back test
|
||||
(let ((plane-test (- (vector-dot pos (-> iter plane)) (-> iter plane w))))
|
||||
(cond
|
||||
((>= plane-test 0.0)
|
||||
(set! flags (-> iter front-flags))
|
||||
(set! iter (the bsp-node (-> iter front))))
|
||||
(else
|
||||
(set! flags (-> iter back-flags))
|
||||
(set! iter (the bsp-node (-> iter back)))))))
|
||||
;; update header - lower 16-bits of the final front/back value
|
||||
(set! (-> bsp current-leaf-idx) (the uint iter))
|
||||
(set! (-> bsp current-bsp-flags) flags))
|
||||
(none))
|
||||
|
||||
;;;;;;;;;;;;;;;
|
||||
;; Collision
|
||||
@@ -356,10 +279,12 @@
|
||||
(none))
|
||||
|
||||
(defmethod collide-ray ((this bsp-header) (length int) (result collide-list))
|
||||
"Forward the active swept-sphere ray query to every drawable tree and append their geometry to
|
||||
result. length is passed through for child implementations that use it."
|
||||
"Forward the active swept-sphere ray query to every drawable tree and append their geometry
|
||||
to result. length is passed through for child implementations that use it."
|
||||
(+! (-> *collide-stats* calls) 1)
|
||||
(let ((trees (-> this drawable-trees))) (dotimes (i (-> trees length)) (collide-ray (-> trees trees i) length result)))
|
||||
(let ((trees (-> this drawable-trees)))
|
||||
(dotimes (i (-> trees length))
|
||||
(collide-ray (-> trees trees i) length result)))
|
||||
(none))
|
||||
|
||||
(defmethod collect-ambients ((this bsp-header) (query-sphere sphere) (length int) (result ambient-list))
|
||||
@@ -400,10 +325,7 @@
|
||||
"Print the frame's collision counts, per-call averages, and target timing breakdown, then clear
|
||||
the counters and restart all three collision stopwatches."
|
||||
;; for some unknown reason, we profile this.
|
||||
(if *debug-segment*
|
||||
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
|
||||
'draw
|
||||
(new 'static 'rgba :r #x40 :b #x40 :a #x80)))
|
||||
(add-profile-frame! #x40 0 #x40 #x80 'draw)
|
||||
(format *stdcon* "~0k frags tris output~%")
|
||||
(print-cl-stat (-> *collide-stats* other) "other")
|
||||
(format *stdcon* "~0k---------------------------------------------------------------~%")
|
||||
@@ -431,43 +353,77 @@
|
||||
(stopwatch-init (-> *collide-stats* total-target))
|
||||
(stopwatch-init (-> *collide-stats* target-cache-fill))
|
||||
(stopwatch-init (-> *collide-stats* target-ray-poly))
|
||||
(if *debug-segment*
|
||||
(add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0) 'draw (new 'static 'rgba :b #xff :a #x80)))
|
||||
(add-profile-frame! 0 0 #xff #x80 'draw)
|
||||
0
|
||||
(none))
|
||||
|
||||
(defun level-remap-texture ((tex-id texture-id))
|
||||
"Binary-search the active level's sorted texture-remap table using the texture ID's upper 24
|
||||
bits. Return the original ID when no level BSP or matching entry exists; otherwise return the
|
||||
entry's remapped ID with the canonical #x14 low-byte tag."
|
||||
(let ((bsp-hdr (-> *level* log-in-level-bsp)))
|
||||
(when bsp-hdr
|
||||
(let* ((table-size (-> bsp-hdr texture-remap-table-len)) ;; in 64-bit entries
|
||||
(search-start (-> bsp-hdr texture-remap-table))
|
||||
(table-start search-start)
|
||||
(entry-align-mask (the-as uint #xfffffff8)) ;; mask for table entry addresses
|
||||
(lookup-id (logand (the-as uint #xffffff00) tex-id)) ;; bits of tex-id we care about
|
||||
(search-end (&+ table-start (* table-size 8))))
|
||||
;; top of binary search
|
||||
(label cfg-2)
|
||||
;; if we didn't find anything, quit
|
||||
(b! (= search-start search-end) cfg-8)
|
||||
;; find the middle entry.
|
||||
(let ((midpoint (logand (/ (+ (the-as int search-start) (the-as int search-end)) 2) entry-align-mask)))
|
||||
;; how did we do?
|
||||
(let ((diff (- (-> (the-as (pointer int32) midpoint) 0) (the-as int lookup-id))))
|
||||
(b! (zero? diff) cfg-7)
|
||||
(b! (< diff 0) cfg-6 :delay (nop!)))
|
||||
;; in the lower section
|
||||
(b! #t cfg-2 :delay (set! search-end (the-as (pointer uint64) midpoint)))
|
||||
;; in the upper section (not including the midpoint)
|
||||
(label cfg-6)
|
||||
(b! #t cfg-2 :delay (set! search-start (the-as (pointer uint64) (+ (the-as int midpoint) 8))))
|
||||
;; exact match
|
||||
(label cfg-7)
|
||||
;; The key ignores the low byte. The matched value has that byte clear, so restore the
|
||||
;; canonical #x14 tag used by in-game texture IDs.
|
||||
(set! tex-id (the-as texture-id (logior (-> (the-as (pointer int32) midpoint) 1) 20)))))
|
||||
(label cfg-8)
|
||||
0))
|
||||
(the-as texture-id tex-id))
|
||||
"Remap an actor texture ID to its combined level texture-page ID."
|
||||
;; actor art data references textures in a per-actor texture page.
|
||||
;; levels contain a larger texture page merging all the per-actor pages and this function
|
||||
;; remaps from the per-actor texture page to the big level page.
|
||||
|
||||
;; simplified GOAL version
|
||||
(let ((bsp (-> *level* log-in-level-bsp)))
|
||||
(when bsp
|
||||
(let ((table (the-as (pointer texture-id) (-> bsp texture-remap-table)))
|
||||
(lookup-id (the texture-id (logand tex-id #xffffff00)))
|
||||
(begin 0)
|
||||
(end (-> bsp texture-remap-table-len)))
|
||||
(while (< begin end)
|
||||
(let* ((midpoint (/ (+ begin end) 2))
|
||||
(entry-index (* midpoint 2))
|
||||
(source-id (-> table entry-index)))
|
||||
(cond
|
||||
((< source-id lookup-id)
|
||||
(set! begin (+ midpoint 1)))
|
||||
((> source-id lookup-id)
|
||||
(set! end midpoint))
|
||||
(else
|
||||
(let ((remapped-id (-> table (+ entry-index 1))))
|
||||
;; restore 0x14 here: low bytes of texture-id are part of A+D
|
||||
;; format data, this 0x14 specifies TEX1_1 register.
|
||||
(return (the texture-id (logior remapped-id #x14)))))))))))
|
||||
tex-id)
|
||||
|
||||
(#unless PC_PORT
|
||||
(defun level-remap-texture ((tex-id texture-id))
|
||||
"Binary-search the active level's sorted texture-remap table using the texture ID's upper 24
|
||||
bits. Return the original ID when no level BSP or matching entry exists; otherwise return the
|
||||
entry's remapped ID with the canonical #x14 low-byte tag."
|
||||
|
||||
;; actor art data references textures in a per-actor texture page.
|
||||
;; levels contain a larger texture page merging all the per-actor pages and this function
|
||||
;; remaps from the per-actor texture page to the big level page.
|
||||
(let ((bsp-hdr (-> *level* log-in-level-bsp)))
|
||||
(when bsp-hdr
|
||||
(let* ((table-size (-> bsp-hdr texture-remap-table-len)) ;; in 64-bit entries
|
||||
(search-start (-> bsp-hdr texture-remap-table))
|
||||
(table-start search-start)
|
||||
(entry-align-mask (the-as uint #xfffffff8)) ;; mask for table entry addresses
|
||||
(lookup-id (logand (the-as uint #xffffff00) tex-id)) ;; bits of tex-id we care about
|
||||
(search-end (&+ table-start (* table-size 8))))
|
||||
;; top of binary search
|
||||
(label cfg-2)
|
||||
;; if we didn't find anything, quit
|
||||
(b! (= search-start search-end) cfg-8)
|
||||
;; find the middle entry.
|
||||
(let ((midpoint (logand (/ (+ (the-as int search-start) (the-as int search-end)) 2) entry-align-mask)))
|
||||
;; how did we do?
|
||||
(let ((diff (- (-> (the-as (pointer int32) midpoint) 0) (the-as int lookup-id))))
|
||||
(b! (zero? diff) cfg-7)
|
||||
(b! (< diff 0) cfg-6 :delay (nop!)))
|
||||
;; in the lower section
|
||||
(b! #t cfg-2 :delay (set! search-end (the-as (pointer uint64) midpoint)))
|
||||
;; in the upper section (not including the midpoint)
|
||||
(label cfg-6)
|
||||
(b! #t cfg-2 :delay (set! search-start (the-as (pointer uint64) (+ (the-as int midpoint) 8))))
|
||||
;; exact match
|
||||
(label cfg-7)
|
||||
;; The key ignores the low byte. The matched value has that byte clear, so restore the
|
||||
;; canonical #x14 tag used by in-game texture IDs.
|
||||
(set! tex-id (the-as texture-id (logior (-> (the-as (pointer int32) midpoint) 1) 20)))))
|
||||
(label cfg-8)
|
||||
0))
|
||||
(the-as texture-id tex-id)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user