Compare commits

..
Author SHA1 Message Date
Tyler Wilding 55204e6996 decomp: ensure out_folder exists before being written to 2024-06-21 22:58:16 -04:00
Tyler Wilding b2cfefb669 decomp/config: simplify enabling streamed audio ripping, string wasn't even in use anymore 2024-06-19 23:43:34 -04:00
Tyler Wilding bc586f0cca lint: formatting 2024-06-15 15:43:04 -04:00
Tyler Wilding 13e7a28c08 decomp: eliminate duplicate code in extractor/decompiler
This allows the extractor's decompilation routine to do all the things the normal decompiler can (ie. extract audio)
2024-06-15 15:42:27 -04:00
Tyler Wilding 17665a4615 decomp: pull out main decompilation process into an isolated function 2024-06-15 15:41:56 -04:00
Tyler Wilding d209766078 util: support get_peak_rss on windows 2024-06-15 15:41:40 -04:00
606 changed files with 9681 additions and 68700 deletions

No files matched your search

-5
View File
@@ -58,11 +58,6 @@ custom_assets/jak1/texture_replacements/*
custom_assets/jak2/texture_replacements/*
custom_assets/jak3/texture_replacements/*
# merc replacements
custom_assets/jak1/merc_replacements/*
custom_assets/jak2/merc_replacements/*
custom_assets/jak3/merc_replacements/*
# generated cmake files
svnrev.h
common/versions/revision.h
+1
View File
@@ -145,6 +145,7 @@
"name": "Game - Jak 1 - Runtime (boot)",
"args": [
"-v",
"--portable",
"--game",
"jak1",
"--",
+2 -2
View File
@@ -4,7 +4,7 @@
#include "fmt/core.h"
std::string DmaTag::print() const {
std::string DmaTag::print() {
std::string result;
const char* mode_names[8] = {"refe", "cnt", "next", "ref", "refs", "call", "ret", "end"};
result += fmt::format("TAG: 0x{:08x} {:4s} qwc 0x{:04x}", addr, mode_names[(int)kind], qwc);
@@ -15,7 +15,7 @@ std::string DmaTag::print() const {
return result;
}
std::string VifCode::print() const {
std::string VifCode::print() {
std::string result;
switch (kind) {
+2 -2
View File
@@ -52,7 +52,7 @@ struct DmaTag {
bool operator!=(const DmaTag& other) const { return !((*this) == other); }
std::string print() const;
std::string print();
};
inline void emulate_dma(const void* source_base, void* dest_base, u32 tadr, u32 dadr) {
@@ -148,7 +148,7 @@ struct VifCode {
u16 num;
u16 immediate;
std::string print() const;
std::string print();
};
struct VifCodeStcycl {
-1
View File
@@ -240,7 +240,6 @@ static FormFormattingConfig new_top_level_inline_form(bool elide_new_line) {
const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config = {
{"case", new_pair_rule(true)},
{"case-str", new_pair_rule(true)},
{"cond", new_pair_rule(false)},
{"#cond", new_pair_rule(false)},
{"in-package", new_top_level_inline_form(true)},
+7 -28
View File
@@ -26,8 +26,6 @@ u64 get_current_tid() {
}
#endif
#include "common/log/log.h"
#include "common/util/compress.h"
#include "common/util/string_util.h"
// clang-format on
u64 get_current_ts() {
@@ -36,12 +34,12 @@ u64 get_current_ts() {
GlobalProfiler::GlobalProfiler() {
m_t0 = get_current_ts();
m_nodes.resize(m_max_events);
set_max_events(65536);
}
void GlobalProfiler::update_event_buffer_size(size_t new_size) {
m_max_events = new_size;
m_nodes.resize(m_max_events);
void GlobalProfiler::set_max_events(size_t event_count) {
ASSERT(!m_enabled);
m_nodes.resize(event_count);
}
void GlobalProfiler::set_waiting_for_event(const std::string& event_name) {
@@ -74,10 +72,6 @@ void GlobalProfiler::root_event() {
instant_event("ROOT");
}
size_t GlobalProfiler::get_next_idx() {
return (m_next_idx % m_nodes.size());
}
void GlobalProfiler::begin_event(const char* name) {
event(name, ProfNode::BEGIN);
}
@@ -102,10 +96,8 @@ void GlobalProfiler::set_enable(bool en) {
m_enabled = en;
}
void GlobalProfiler::dump_to_json() {
if (m_enabled) {
set_enable(false);
}
void GlobalProfiler::dump_to_json(const std::string& path) {
ASSERT(!m_enabled);
nlohmann::json json;
auto& trace_events = json["traceEvents"];
@@ -193,20 +185,7 @@ void GlobalProfiler::dump_to_json() {
t.second.highest_at_target);
}
if (m_enable_compression) {
const auto json_str = json.dump();
const auto compressed_data =
compression::compress_zstd_no_header(json_str.data(), json_str.size());
auto file_path = file_util::get_jak_project_dir() / "profile_data" /
fmt::format("prof-{}.json.zst", str_util::current_local_timestamp_no_colons());
file_util::create_dir_if_needed_for_file(file_path);
file_util::write_binary_file(file_path, compressed_data.data(), compressed_data.size());
} else {
auto file_path = file_util::get_jak_project_dir() / "profile_data" /
fmt::format("prof-{}.json", str_util::current_local_timestamp_no_colons());
file_util::create_dir_if_needed_for_file(file_path);
file_util::write_text_file(file_path, json.dump());
}
file_util::write_text_file(path, json.dump());
}
GlobalProfiler gprof;
+2 -8
View File
@@ -17,8 +17,7 @@ struct ProfNode {
class GlobalProfiler {
public:
GlobalProfiler();
size_t get_max_events() { return m_max_events; }
void update_event_buffer_size(size_t new_size);
void set_max_events(size_t event_count);
void set_waiting_for_event(const std::string& event_name);
void instant_event(const char* name);
void begin_event(const char* name);
@@ -26,16 +25,11 @@ class GlobalProfiler {
void end_event();
void clear();
void set_enable(bool en);
void dump_to_json();
void dump_to_json(const std::string& path);
void root_event();
bool is_enabled() { return m_enabled; }
size_t get_next_idx();
bool m_enable_compression = false;
private:
std::atomic_bool m_enabled = false;
size_t m_max_events = 65536;
u64 m_t0 = 0;
std::atomic_size_t m_next_idx = 0;
std::vector<ProfNode> m_nodes;
+1 -1
View File
@@ -140,7 +140,7 @@ void printstd(const char* format, va_list arg_list) {
internal::log_vprintf(format, arg_list);
}
// how many extra log files for a single program should be kept
// how many extra log files for a single program should be kept?
constexpr int LOG_ROTATE_MAX = 10;
void set_file(const std::string& filename,
+2 -5
View File
@@ -29,11 +29,8 @@ class Wrapper {
Wrapper(const std::string& _username,
const Config& config,
const StartupFile& startup,
bool _nrepl_alive)
: username(_username),
repl_config(config),
startup_file(startup),
nrepl_alive(_nrepl_alive) {}
bool nrepl_alive)
: username(_username), repl_config(config), startup_file(startup), nrepl_alive(nrepl_alive) {}
replxx::Replxx& get_repl() { return repl; }
void init_settings();
void reload_startup_file();
+1 -145
View File
@@ -43,151 +43,7 @@ std::vector<std::string> jak2_slots = {
};
std::vector<std::string> jak3_slots = {
"skull-gem-dest",
"jakc-arm",
"jakc-eyebrow",
"jakc-face",
"jakc-finger",
"jakc-hair",
"jakchires-arm",
"jakchires-eye",
"jakchires-eyebrow",
"jakchires-eyelid",
"jakchires-facelft",
"jakchires-facert",
"jakchires-hair",
// default-water
"bomb-gradient",
"blue-beam-dest",
"lightjak-wings",
"mushroom-dest",
// default-warp
"shield-env-rim-dest",
// templea-water
"templea-waterfall-dest",
// templea-warp
"holograph-env-rim-dest",
// hanga-sprite
"glider-ring-dest2",
"glider-ring-dest",
// foresta-water
"fora-water-dest",
"fora-waterfall-01-dest",
"fora-water-wave-01-dest",
// forestb-water
"forb-water-dest",
"forb-waterfall-01-dest",
"forb-water-wave-01-dest",
// lforplnt-pris
"mh-gem-dest",
// lmhcitya-tfrag
"mhcitya-base-goo-01-dest",
// lmhcityb-tfrag
"mhcityb-base-goo-01-dest",
// mhcitya-pris
// "mhcity-de-door-skin-01-dest",
// templec-water
"tplc-water-dest",
// sewc-water
"sewer-water-01-c-dest",
"sewer-waterfall-01-c-dest",
"sewer-waterfall-02-c-dest",
"sewer-water-wave-01-c-dest",
"sewer-water-highlight-01-c-dest",
// sewd-water
"sewer-water-01-d-dest",
"sewer-waterfall-02-d-dest",
"sewer-water-highlight-01-d-dest",
"sewer-water-wave-01-d-dest",
"sewer-water-wave-02-d-dest",
"sewer-water-still-01-d-dest",
// sewe-water
"sewer-water-01-e-dest",
"sewer-waterfall-01-e-dest",
"sewer-waterfall-02-e-dest",
"sewer-water-highlight-01-e-dest",
// sewg-water
"sewer-water-01-g-dest",
"sewer-waterfall-02-g-dest",
"sewer-water-wave-01-g-dest",
// sewh-water
"sewer-water-01-h-dest",
"sewer-waterfall-02-h-dest",
"sewer-water-wave-02-h-dest",
"sewer-watefall-froth-01-h-dest",
// sewi-water
"sewer-water-still-01-i-dest",
"sewer-waterfall-02-i-dest",
"sewer-water-wave-01-i-dest",
// sewj-water
"sewer-waterfall-02-j-dest",
"sewer-watefall-froth-01-j-dest",
// sewl-water
"sewer-waterfall-02-l-dest",
"sewer-watefall-froth-01-l-dest",
// sewm-water
"sewer-water-01-m-dest",
"sewer-waterfall-01-m-dest",
"sewer-waterfall-02-m-dest",
"sewer-water-highlight-01-m-dest",
"sewer-water-wave-01-m-dest",
"sewer-water-still-01-m-dest",
"sewer-watefall-froth-01-m-dest",
// sewn-water
"sewer-waterfall-01-n-dest",
"sewer-waterfall-02-n-dest",
// "sewer-water-highlight-01-n-dest",
"sewer-water-wave-01-n-dest",
"sewer-water-still-01-n-dest",
// hanga-water
// "des-thermal-01-dest",
// desresc-warp
"sat-shield-dest",
// security
"security-env-dest",
"security-dot-dest",
// lgunnorm-water
"kg-target-c-forcefield-01-dest",
// templex-water
"temple-waterfall-dest",
// desertd-water
"des-waterfall-dest",
// towerb-water
"tow-energy-bridge-dest",
// factoryb-water
"hemi-gradient-dest",
"hemi-gradient-flames-dest",
// factoryc-alpha
"facc-convey-dest",
"facc-convey-02-dest",
// waspal-water
"waspala-water-dest",
"waspala-waterfall-dest",
// rubblea-water
"rub-water-dest",
// rubblea2-water
"rub-water-desta2",
// rubbleb-water
"rub-water-destb",
// rubblec-water
"rub-water-destc",
// nstb-quicksand
"nstb-quicksand-dest",
// ctyslumb-water
"ctyslumb-water-dest",
"ctyslumb-fountain-fall-dest",
// ctyslumc-water
"ctyslumc-water-dest",
"ctyslumc-fountain-fall-dest",
// mined-tfrag
"mined-pillar-side-dest",
"mined-pillar-top2side-dest",
"mined-pillar-top-dest",
// volcanoa-alpha
"vola-lava-01-dest",
"vola-lava-fall-dest",
// wasstada-alpha
"wstd-lava-base-dest",
"skull-gem-dest", "jakc-arm", "jakc-eyebrow", "jakc-face", "jakc-finger", "jakc-hair",
};
} // namespace
-13
View File
@@ -46,17 +46,4 @@ std::vector<u8> decompress_zstd(const void* data, size_t size) {
ASSERT(decomp_size == decompressed_size);
return result;
}
std::vector<u8> compress_zstd_no_header(const void* data, size_t size) {
size_t max_compressed = ZSTD_compressBound(size);
std::vector<u8> result(max_compressed);
size_t compressed_size = ZSTD_compress(result.data(), max_compressed, data, size, 1);
if (ZSTD_isError(compressed_size)) {
ASSERT_MSG(false, fmt::format("ZSTD error: {}", ZSTD_getErrorName(compressed_size)));
}
result.resize(compressed_size);
return result;
}
} // namespace compression
+1 -2
View File
@@ -8,5 +8,4 @@ namespace compression {
// compress and decompress data with zstd
std::vector<u8> compress_zstd(const void* data, size_t size);
std::vector<u8> decompress_zstd(const void* data, size_t size);
std::vector<u8> compress_zstd_no_header(const void* data, size_t size);
} // namespace compression
} // namespace compression
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include <string>
#include "common/common_types.h"
inline u64 fnv64(const void* data, u64 len) {
u64 ret = 0xcbf29ce484222325;
const auto* ptr = (const u8*)data;
for (u64 i = 0; i < len; i++) {
ret = 1099511628211 * (((u64)*ptr) ^ ret);
ptr++;
}
return ret;
}
inline u64 fnv64(const std::string& str) {
return fnv64(str.data(), str.length());
}
+3 -3
View File
@@ -27,11 +27,11 @@ Range<int> parse_json_optional_integer_range(const nlohmann::json& json);
}
template <typename T>
void json_get_optional(const nlohmann::json& j,
void json_get_optional(const nlohmann::json& json,
const std::string& key,
std::optional<T>& optionalValue) {
if (j.contains(key) && !j[key].is_null()) {
optionalValue = j[key].get<T>();
if (json.contains(key) && !json[key].is_null()) {
optionalValue = json[key].get<T>();
}
}
@@ -62,7 +62,7 @@
// Note: You will still have to add them to your level's .gd file.
// "art_groups": ["plat-ag"],
// If you have any custom models in the "custom_assets/jak1/models/custom_levels" folder that you want to use in your level, add them to this list.
// If you have any custom models in the "custom_assets/jak1/models" folder that you want to use in your level, add them to this list.
// Note: Like with art groups, these should also be added to your level's .gd file.
"custom_models": ["test-actor"],
-1
View File
@@ -68,7 +68,6 @@ add_library(
level_extractor/fr3_to_gltf.cpp
level_extractor/MercData.cpp
level_extractor/tfrag_tie_fixup.cpp
level_extractor/merc_replacement.cpp
ObjectFile/LinkedObjectFile.cpp
ObjectFile/LinkedObjectFileCreation.cpp
+1 -1
View File
@@ -25,7 +25,7 @@ namespace decompiler {
*/
class LinkedObjectFile {
public:
LinkedObjectFile(GameVersion _version) : version(_version) {}
LinkedObjectFile(GameVersion version) : version(version){};
void set_segment_count(int n_segs);
void push_back_word_to_segment(uint32_t word, int segment);
int get_label_id_for(int seg, int offset);
+6 -2
View File
@@ -54,8 +54,12 @@ void append_body_to_function_definition(goos::Object* top_form,
body_elements.insert(body_elements.end(), inline_body.begin(), inline_body.end());
// If the first element in the body is a docstring, add it first
if (body_elements.size() > 0 && body_elements.at(0).is_string()) {
initial_top_level_forms.push_back(
goos::StringObject::make_new(fix_docstring_indent(inline_body.at(0).as_string()->data)));
if (version > GameVersion::Jak2) {
initial_top_level_forms.push_back(
goos::StringObject::make_new(fix_docstring_indent(inline_body.at(0).as_string()->data)));
} else {
initial_top_level_forms.push_back(inline_body.at(0));
}
body_elements.erase(body_elements.begin());
}
+1 -1
View File
@@ -21102,7 +21102,7 @@
:size-assert #x94
:flag-assert #xf00300094
(:methods
(spawn-particles! (_type_) none))
(dumb-15 (_type_) none))
(:states
hud-normal
hud-coming-in
-14
View File
@@ -2515,7 +2515,6 @@
(iop-mem 48)
(cancel-dgo 49)
(set-stereo-mode 50) ;; sound-rpc-set-stereo-mode
(set-mirror 201)
)
(defenum sound-group
@@ -2830,17 +2829,6 @@
:flag-assert #x900000004
)
; added
(defenum sound-mirror-mode
:type uint8
(normal)
(mirrored)
)
; added for mirror mode
(deftype sound-rpc-set-mirror-mode (sound-rpc-cmd)
((mirror sound-mirror-mode)))
(deftype sound-rpc-union (structure)
((data uint32 20 :offset-assert 0)
(load-bank sound-rpc-load-bank :offset 0)
@@ -2864,7 +2852,6 @@
(shutdown sound-rpc-shutdown :offset 0)
(list-sounds sound-rpc-list-sounds :offset 0)
(unload-music sound-rpc-unload-music :offset 0)
(mirror-mode sound-rpc-set-mirror-mode :overlay-at (-> data 0))
)
:method-count-assert 9
:size-assert #x50
@@ -8787,7 +8774,6 @@ Unlike [[engine]], users can use [[engine-pers]] as a parent class."
(progress-graphics-ps2-lod-dist #x1337)
(progress-graphics-msaa-off #x1338)
(progress-graphics-display #x1339)
(language-name-finnish #x133a)
)
;; ---text-id-h:text-id
+108 -177
View File
@@ -15147,8 +15147,8 @@
:size-assert #x4
:flag-assert #xb00000004
(:methods
(update! (_type_) int) ;; 9
(setup-from-params! (_type_ cloth-params handle) int) ;; 10
(init! (_type_) int) ;; 9
(cloth-base-method-10 (_type_ cloth-params handle) int) ;; 10
)
)
@@ -25908,33 +25908,8 @@
:flag-assert #xe00000010
)
;; doesn't exist, but referenced by type ref in the entity table.
(deftype sail-boat-a (process-drawable-reserved)
()
)
(deftype cty-window-a (process-drawable-reserved)
()
)
(deftype city-window-a (process-drawable-reserved)
()
)
(deftype cty-guard-turret (process-drawable-reserved)
()
)
(deftype cty-fruit-stand (process-drawable-reserved)
()
)
(deftype torn (process-drawable-reserved)
()
)
(deftype entity-info (basic)
((ptype object :offset-assert 4) ;; guessed by decompiler
((ptype type :offset-assert 4) ;; guessed by decompiler
(pool symbol :offset-assert 8) ;; guessed by decompiler
(heap-size int32 :offset-assert 12)
)
@@ -33975,7 +33950,7 @@
)
(deftype particle-array (inline-array-class)
((data verlet-particle :dynamic :inline :offset-assert 16 :score 1)
((data verlet-particle :dynamic :inline :offset-assert 16)
)
:method-count-assert 14
:size-assert #x10
@@ -34042,12 +34017,12 @@
:size-assert #x40
:flag-assert #x1000000040
(:methods
(accumulate-external-forces!
(calculate-wind!
"If this cloth system has the wind flag, calculate the wind force."
(_type_) none) ;; 11
(compute-verlet-step (_type_ float) none) ;; 12
(run-one-iteration "Run one iteration of the system." (_type_) none) ;; 13
(reset! "Reset to stationary/default state." (_type_) none) ;; 14
(verlet-particle-system-method-12 (_type_ float) none) ;; 12
(verlet-particle-system-method-13 (_type_) none) ;; 13
(verlet-particle-system-method-14 (_type_) none) ;; 14
(debug-draw (_type_) none) ;; 15
)
)
@@ -34107,9 +34082,9 @@
"Set up this cloth system with the given [[cloth-params]]."
(_type_ cloth-params) none) ;; 16
(debug-draw-spheres (_type_) none) ;; 17
(post-physics-update (_type_) int) ;; 18
(enforce-constraints-1 (_type_) none) ;; 19
(enforce-constraints-2 (_type_) none) ;; 20
(cloth-system-method-18 (_type_) int) ;; 18
(cloth-system-method-19 (_type_) none) ;; 19
(cloth-system-method-20 (_type_) none) ;; 20
(cloth-system-method-21 (_type_) none) ;; 21
(cloth-system-method-22 (_type_) none) ;; 22
(cloth-system-method-23 (_type_) none) ;; 23
@@ -34123,9 +34098,9 @@
(cloth-system-method-31 (_type_ current-position-info) none) ;; 31
(cloth-system-method-32 (_type_ vector int int current-position-info) none) ;; 32
(cloth-system-method-33 (_type_ vu-lights) none) ;; 33
(hide! (_type_) none) ;; 34
(reset-locations (_type_) none) ;; 35
(pre-physics-update "Callback to update prior to running verlet integration. Can handle movement of the entire system in the world, for example" (_type_) none) ;; 36
(cloth-system-method-34 (_type_) none) ;; 34
(cloth-system-method-35 (_type_) none) ;; 35
(cloth-system-method-36 (_type_) none) ;; 36
(cloth-system-cmd-handler (_type_ pair) none) ;; 37
)
)
@@ -34147,8 +34122,8 @@
;; cloth ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern get-neighboring-faces (function vector4w int int int int int))
(define-extern *normal-array* (inline-array vector))
(define-extern get-neighboring-faces (function vector int int int int int))
(define-extern *normal-array* (pointer vector))
(define-extern light-vertex (function current-position-info vector rgba))
(define-extern *once* symbol)
(define-extern *cloth-fade-alpha* gs-alpha)
@@ -34221,17 +34196,7 @@
;; curves ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defenum loop-behavior
:type uint64
:bitfield #f
(wrap)
(clamp)
(b2)
(use-default)
)
(deftype float-pair (structure)
"Two floats. Specifies one point on a piecewise linear curve."
((first float :offset-assert 0)
(second float :offset-assert 4)
(x float :offset 0)
@@ -34243,7 +34208,6 @@
)
(deftype float-pair-array (inline-array-class)
"Array of points used to make a piecewise linear curve."
((data float-pair :dynamic :inline :offset-assert 16)
)
:method-count-assert 14
@@ -34252,50 +34216,39 @@
)
(deftype curve2d (basic)
"Interface for evaluating a 2d curve.
The input is a float (x-position) and the output is a float (y-position).
The curve is over (0, 1). Values outside of the range are either clamped
or wrapped depending on the loop-behavior flag."
()
:method-count-assert 10
:size-assert #x4
:flag-assert #xa00000004
(:methods
(evaluate "Compute value of curve at the given position." (_type_ float loop-behavior) float) ;; 9
(curve2d-method-9 (_type_ float int) float) ;; 9
)
)
(deftype curve-color (basic)
"Interface for evaluating a color curve. The input is a float, representing
progress through the curve, and the result is a floating point rgba color."
()
:method-count-assert 10
:size-assert #x4
:flag-assert #xa00000004
(:methods
(evaluate "Compute value of curve at the given position." (_type_ float rgbaf loop-behavior) rgbaf) ;; 9
(curve-color-method-9 (_type_ float rgbaf int) rgbaf) ;; 9
)
)
(deftype curve2d-piecewise (curve2d)
"Implementation of 2d-curve for a piecewise linear curve.
Not particularly efficient - each evaluation needs to check each point."
((pts float-pair-array :offset-assert 4)
(default-loop-behavior loop-behavior :offset-assert 8)
(default-loop-behavior uint64 :offset-assert 8)
)
:method-count-assert 12
:size-assert #x10
:flag-assert #xc00000010
(:methods
(allocate! "Allocate memory for points." (_type_ int symbol symbol) none) ;; 10
(curve2d-piecewise-method-10 (_type_ int symbol int) none) ;; 10
(curve2d-piecewise-method-11 (_type_) none) ;; 11
)
)
(deftype curve2d-fast (curve2d)
"Implementation of 2d piecewise linear curve which tries to be faster.
While it is faster, it places the huge restriction that you can only have 4 points.
Note that the xs should be negative here."
((xs vector :inline :offset-assert 16)
(ys vector :inline :offset-assert 32)
(one-over-x-deltas vector :inline :offset-assert 48)
@@ -34306,9 +34259,6 @@
)
(deftype curve-color-fast (curve-color)
"Implementation of color curve which tries to be faster.
While it is faster, it again has the restriction that you only
get 4 piecewise sections."
((xs vector :inline :offset-assert 16)
(ys vector 4 :inline :offset-assert 32)
(one-over-x-deltas vector :inline :offset-assert 96)
@@ -34319,8 +34269,6 @@
)
(deftype color-pair (structure)
"Single section of a piecewise linear color curve.
Unlike the fast version, this stores x values exactly like you'd expect."
((first float :offset-assert 0)
(second rgbaf :inline :offset-assert 16)
(x float :offset 0)
@@ -34332,7 +34280,6 @@
)
(deftype color-pair-array (inline-array-class)
"Array of points for piecewise linear color curve."
((data color-pair :dynamic :inline :offset-assert 16)
)
:method-count-assert 14
@@ -34341,22 +34288,21 @@
)
(deftype curve-color-piecewise (curve-color)
"Implementation of curve-color."
((pts color-pair-array :offset-assert 4)
(default-loop-behavior loop-behavior :offset-assert 8)
(default-loop-behavior uint64 :offset-assert 8)
)
:method-count-assert 11
:size-assert #x10
:flag-assert #xb00000010
(:methods
(allocate! "Allocate memory for points." (_type_ int symbol symbol) none) ;; 10
(curve-color-piecewise-method-10 (_type_ int symbol uint) none) ;; 10
)
)
(define-extern rgbaf-lerp! "Lerp all four components of rgba." (function rgbaf rgbaf rgbaf float rgbaf))
(define-extern evaluate-curve-fast "Evaluate a curve2d-fast at the given value." (function curve2d-fast float float))
(define-extern evaluate-color-curve-fast "Evaluate a color-curve-fast at the given value." (function curve-color-fast float rgbaf rgbaf))
(define-extern rgba<-rgbaf "Convert rgbaf to rgba. Seems like the input rgba's value is not used in any way." (function rgba rgbaf rgba))
(define-extern rgbaf-lerp! (function rgbaf rgbaf rgbaf float rgbaf))
(define-extern evaluate-curve-fast (function curve2d-fast rgbaf rgbaf float))
(define-extern evaluate-color-curve-fast (function curve-color-fast rgbaf rgbaf rgbaf))
(define-extern rgba<-rgbaf (function rgba rgbaf int))
(define-extern *curve-unity* curve2d-fast)
(define-extern *curve-linear-up* curve2d-fast)
(define-extern *curve-linear-down* curve2d-fast)
@@ -34733,14 +34679,6 @@
:flag-assert #xe00000010
)
(defenum lie-mode
:type uint64
(appearance0)
(appearance1)
(appearance2)
(use-two-strips 3)
)
(deftype light-trail-composition (structure)
((color-mode uint64 :offset-assert 0)
(color-curve curve-color-piecewise :offset-assert 8)
@@ -34758,8 +34696,8 @@
(uv-mode uint64 :offset-assert 72)
(uv-repeat-dist float :offset-assert 80)
(max-age time-frame :offset-assert 88)
(tex-id texture-id :offset-assert 96)
(lie-mode lie-mode :offset-assert 104)
(tex-id uint32 :offset-assert 96)
(lie-mode uint64 :offset-assert 104)
(lie-vector vector :inline :offset-assert 112)
(zbuffer? symbol :offset-assert 128)
(use-tape-mode? symbol :offset-assert 132)
@@ -34773,7 +34711,7 @@
(deftype light-trail-breadcrumb (structure)
((pos vector :inline :offset-assert 0)
(birth-time uint32 :offset 12 :decomp-as time-frame :score 1)
(birth-time uint32 :offset 12 :decomp-as time-frame)
)
:method-count-assert 9
:size-assert #x10
@@ -34788,22 +34726,15 @@
:flag-assert #xe00000010
)
(defenum light-trail-decision
:type uint64
(added 0)
(not-added 1)
(reset 2)
)
(deftype light-trail (basic)
((crumb-array (array uint8) :offset-assert 4)
((crumb-array (array light-trail-breadcrumb) :offset-assert 4)
(crumb-size uint8 :offset-assert 8)
(crumb-count int16 :offset-assert 10)
(max-crumb-count int16 :offset-assert 12)
(appearance light-trail-composition :offset-assert 16)
(start-marker uint64 :offset-assert 24)
(end-marker uint64 :offset-assert 32)
(decision light-trail-decision :offset-assert 40)
(decision uint64 :offset-assert 40)
(total-distance-traveled float :offset-assert 48)
(strip prim-strip :offset-assert 52)
(strip2 prim-strip :offset-assert 56)
@@ -34813,19 +34744,19 @@
:size-assert #x80
:flag-assert #x1600000080
(:methods
(setup! "Initialize, including allocation of crumbs and strips on the process heap." (_type_ light-trail-composition int) none) ;; 9
(reset! "Clear all tracked crumbs." (_type_) none) ;; 10
(add-crumb! "Try adding a crumb, kicking out the oldest if there's not enough room. This may reject if it's too close to the previous." (_type_ vector time-frame) int) ;; 11
(build-prim-strip! "Build the mesh for this light trail." (_type_) none) ;; 12
(common-trans! "Call this on each frame to handle max-age." (_type_) int) ;; 13
(expire-old-points! "Internal function to kill off points that are too old." (_type_) none) ;; 14
(light-trail-method-9 (_type_ light-trail-composition int) none) ;; 9
(light-trail-method-10 (_type_) none) ;; 10
(light-trail-method-11 (_type_ vector time-frame) int) ;; 11
(light-trail-method-12 (_type_) none) ;; 12
(light-trail-method-13 (_type_) int) ;; 13
(light-trail-method-14 (_type_) none) ;; 14
(light-trail-method-15 (_type_) none) ;; 15
(add-vert-to-prim-strip! "Add a single vertex to the prim." (_type_ prim-strip vector rgba float float) none) ;; 16
(add-tri-pair-to-prim! "Add two vertices to the prim strip to add two triangles" (_type_ vector rgba float vector float) symbol) ;; 17
(calc-vertex-pos! (_type_ light-trail-breadcrumb int vector vector) none) ;; 18
(crumb-age-out-callback "To be implemented by the user to smoothly interpolate out non-default entries in their crumb type." (_type_ float int) none) ;; 19
(add-vert! (_type_ prim-strip vector float float float) none) ;; 16
(light-trail-method-17 (_type_ vector float float vector float) symbol) ;; 17
(light-trail-method-18 (_type_ light-trail-breadcrumb int vector vector) none) ;; 18
(light-trail-method-19 (_type_ float int) none) ;; 19
(reset-crumbs! (_type_) none) ;; 20
(replace-last-crumb! "Similar to add-crumb, but will modify the last crumb instead of advancing." (_type_ vector) none) ;; 21
(light-trail-method-21 (_type_ vector) none) ;; 21
)
)
@@ -34843,7 +34774,7 @@
:size-assert #x80
:flag-assert #x1800000080
(:methods
(add-crumb-with-offset "Given two points, add the first and offset to a crumb." (_type_ vector vector) light-trail-breadcrumb) ;; 22
(weapon-trail-method-22 (_type_ vector vector) light-trail-breadcrumb) ;; 22
(weapon-trail-method-23 (_type_ vector vector) none) ;; 23
)
)
@@ -34862,8 +34793,8 @@
:size-assert #x80
:flag-assert #x1800000080
(:methods
(add-crumb-with-offset (_type_ vector vector) none) ;; 22
(tread-trail-method-23 (_type_ vector vector) none) ;; 23
(tread-trail-method-22 (_type_ vector vector) light-trail-breadcrumb) ;; 22
(tread-trail-method-23 (_type_ vector vector) light-trail-breadcrumb) ;; 23
)
)
@@ -34903,11 +34834,11 @@
die ;; 15
)
(:methods
(get-tracked-object-pos (_type_ process-focusable vector) vector) ;; 16
(should-track? (_type_ process-focusable) symbol) ;; 17
(should-end? (_type_ process-focusable) symbol) ;; 18
(should-draw? (_type_) symbol) ;; 19
(add-crumb! (_type_ vector) none) ;; 20
(light-trail-tracker-method-16 (_type_ process-focusable vector) vector) ;; 16
(light-trail-tracker-method-17 (_type_ process-focusable) symbol) ;; 17
(light-trail-tracker-method-18 (_type_ process-focusable) symbol) ;; 18
(light-trail-tracker-method-19 (_type_) symbol) ;; 19
(light-trail-tracker-method-20 (_type_ vector) none) ;; 20
)
)
@@ -42848,7 +42779,7 @@
:size-assert #xfc
:flag-assert #x22008000fc
(:methods
(get-mgr-name (_type_) string) ;; 32
(task-manager-desert-bbush-ring-method-32 (_type_) none) ;; 32
(task-manager-desert-bbush-ring-method-33 (_type_) none) ;; 33
)
)
@@ -44565,12 +44496,12 @@
;; templea-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *templea-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *templea-warp-texture-anim-array* (texture-anim-array texture-anim))
(define-extern templea-warp-texture-anim-func (function none))
(define-extern *templeb-warp-texture-anim-array* (texture-anim-array texture-anim))
(define-extern templeb-warp-texture-anim-func (function none))
(define-extern *templec-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *templea-water-texture-anim-array* texture-anim-array)
;; (define-extern *templea-warp-texture-anim-array* texture-anim-array)
;; (define-extern templea-warp-texture-anim-func function)
;; (define-extern *templeb-warp-texture-anim-array* texture-anim-array)
;; (define-extern templeb-warp-texture-anim-func function)
;; (define-extern *templec-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; hover-training ;;
@@ -46353,16 +46284,16 @@
;; sewer-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *sewc-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewd-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewe-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewg-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewh-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewi-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewj-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewl-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewm-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *sewn-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *sewc-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewd-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewe-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewg-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewh-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewi-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewj-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewl-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewm-water-texture-anim-array* texture-anim-array)
;; (define-extern *sewn-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; kg-hopper ;;
@@ -50356,7 +50287,7 @@
;; desresc-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *desresc-warp-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *desresc-warp-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; desert-rescue ;;
@@ -51053,7 +50984,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern check-drop-level-ctyslumb-drop-userdata (function sparticle-system sparticle-cpuinfo vector none))
(define-extern *ctyslumb-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *ctyslumb-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; mech-part ;;
@@ -51159,7 +51090,7 @@
;; nstb-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *nstb-quicksand-anim-array* (texture-anim-array texture-anim))
;; (define-extern *nstb-quicksand-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; nst-mood ;;
@@ -51802,7 +51733,7 @@
)
)
(define-extern *ctyslumc-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *ctyslumc-water-texture-anim-array* texture-anim-array)
(define-extern ctyslumc-flag-init-by-other (function vector entity-actor object :behavior ctyslumc-flag))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -51977,8 +51908,8 @@
;; factoryc-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *factoryc-alpha-texture-anim-array* (texture-anim-array texture-anim))
(define-extern set-facc-conveyor-speed! (function float float))
;; (define-extern *factoryc-alpha-texture-anim-array* texture-anim-array)
;; (define-extern set-facc-conveyor-speed! function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; conveyor ;;
@@ -52627,7 +52558,7 @@
(define-extern wang-texture-anim-init (function texture-anim none))
(define-extern real-wang-texture-anim-func (function texture-anim texture-anim none))
(define-extern wang-texture-anim-func (function texture-anim texture-anim none))
(define-extern wang-texture-anim-func (function none))
(define-extern *hfrag-texture-anim-array* (texture-anim-array texture-anim))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -54251,7 +54182,7 @@
;; glider-ring-part ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *hanga-sprite-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *hanga-sprite-texture-anim-array* texture-anim-array)
(define-extern cloud-shadow-find-ground (function vector matrix vector vector float))
(define-extern birth-func-fader (function sparticle-system sparticle-cpuinfo sparticle-launchinfo none))
(define-extern sparticle-fader (function sparticle-system sparticle-cpuinfo sparticle-launchinfo none))
@@ -54454,7 +54385,7 @@
(define-extern hanga-login (function level none))
(define-extern hanga-activate (function level none))
(define-extern hanga-deactivate (function level none))
(define-extern *hanga-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *hanga-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; elec-gate ;;
@@ -57106,7 +57037,7 @@
;; desertd-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *desertd-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *desertd-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ctyfarm-obs ;;
@@ -57930,7 +57861,7 @@
(deftype tire-trail-crumb (light-trail-breadcrumb)
((offset vector :inline :offset-assert 16)
(uu float :offset 28 :score 1)
(uu float :offset 28)
)
:method-count-assert 9
:size-assert #x20
@@ -57943,13 +57874,13 @@
:size-assert #x80
:flag-assert #x1800000080
(:methods
(add-crumb-with-offset-and-uu (_type_ vector vector float) none) ;; 22
(tire-trail-method-23 (_type_ vector vector float) none) ;; 23
(tire-trail-method-22 (_type_) none) ;; 22
(tire-trail-method-23 (_type_) none) ;; 23
)
)
(deftype tire-trail-tracker (light-trail-tracker)
((trail tire-trail :override))
()
:method-count-assert 21
:size-assert #xac
:flag-assert #x15003000ac
@@ -60350,7 +60281,7 @@
;; mhcityb-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *lmhcityb-tfrag-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *lmhcityb-tfrag-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; rublcst-scenes ;;
@@ -61360,7 +61291,7 @@
(define-extern init-mood-tower (function mood-context float))
(define-extern update-tower-lights (function mood-context none))
(define-extern update-mood-tower (function mood-context float int none :behavior time-of-day-proc))
(define-extern *towerb-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *towerb-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; tower-scenes ;;
@@ -63400,7 +63331,7 @@
;; wasstada-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *wasstada-alpha-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *wasstada-alpha-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; wasstada-mood ;;
@@ -63424,7 +63355,7 @@
;; factorya-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *factoryb-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *factoryb-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; factoryb-init ;;
@@ -63436,9 +63367,9 @@
;; mhcitya-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *lmhcitya-tfrag-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *mhcitya-pris-texture-anim-array* (texture-anim-array texture-anim))
(define-extern set-mhcity-de-door-skin! (function float float))
;; (define-extern *lmhcitya-tfrag-texture-anim-array* texture-anim-array)
;; (define-extern *mhcitya-pris-texture-anim-array* texture-anim-array)
;; (define-extern set-mhcity-de-door-skin! function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ctyinda-part ;;
@@ -63746,10 +63677,10 @@
;; rubble-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *rubblea-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *rubblea2-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *rubbleb-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *rubblec-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *rubblea-water-texture-anim-array* texture-anim-array)
;; (define-extern *rubblea2-water-texture-anim-array* texture-anim-array)
;; (define-extern *rubbleb-water-texture-anim-array* texture-anim-array)
;; (define-extern *rubblec-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; stadiuma-part ;;
@@ -65220,9 +65151,9 @@
;; forest-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *foresta-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *forestb-water-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *lforplnt-pris-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *foresta-water-texture-anim-array* texture-anim-array)
;; (define-extern *forestb-water-texture-anim-array* texture-anim-array)
;; (define-extern *lforplnt-pris-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; forest-ring-chase ;;
@@ -65479,8 +65410,8 @@
;; ltnfxhip-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *ltnfxhip-texture-anim-array* (texture-anim-array texture-anim))
(define-extern ltnfxhip-texture-anim-func (function none))
;; (define-extern *ltnfxhip-texture-anim-array* texture-anim-array)
;; (define-extern ltnfxhip-texture-anim-func function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ctygenb-part ;;
@@ -67881,7 +67812,7 @@
;; gungame-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *lgunnorm-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *lgunnorm-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; gungame-obs ;;
@@ -68161,8 +68092,8 @@
;; ljkdxvin-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *ljkdxvin-texture-anim-array* (texture-anim-array texture-anim))
(define-extern ljkdxvin-texture-anim-func (function none))
;; (define-extern *ljkdxvin-texture-anim-array* texture-anim-array)
;; (define-extern ljkdxvin-texture-anim-func function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; target-tube ;;
@@ -71558,7 +71489,7 @@
;; waspal-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *waspal-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *waspal-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; throne-scenes ;;
@@ -72734,7 +72665,7 @@
;; mined-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *mined-tfrag-texture-anim-array* (texture-anim-array texture-anim))
(define-extern *mined-tfrag-texture-anim-array* texture-anim-array)
(define-extern set-mined-pillar-texture! (function float none))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -73120,8 +73051,8 @@
;; volcanox-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *volcanox-warp-texture-anim-array* (texture-anim-array texture-anim))
(define-extern volcanox-warp-texture-anim-func (function none))
;; (define-extern *volcanox-warp-texture-anim-array* texture-anim-array)
;; (define-extern volcanox-warp-texture-anim-func function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; volcanox-mood ;;
@@ -73321,7 +73252,7 @@
;; templex-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *templex-water-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *templex-water-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; templex-scenes ;;
@@ -73704,7 +73635,7 @@
;; volcano-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *volcanoa-alpha-texture-anim-array* (texture-anim-array texture-anim))
;; (define-extern *volcanoa-alpha-texture-anim-array* texture-anim-array)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; spiky-frog ;;
@@ -74417,8 +74348,8 @@
;; deshover-texture ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *deshover-texture-anim-array* (texture-anim-array texture-anim))
(define-extern deshover-texture-anim-func (function none))
;; (define-extern *deshover-texture-anim-array* texture-anim-array)
;; (define-extern deshover-texture-anim-func function)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; terraformer-head ;;
@@ -138,7 +138,7 @@
[7, "(function none)"],
[3, "(function symbol :behavior process)"]
],
"scene": [[4, "(function symbol :behavior scene-player)"]],
"scene": [[4, "(function none :behavior scene-player)"]],
"pov-camera": [
[
7,
+1 -305
View File
@@ -361,315 +361,11 @@
"jakc-finger-dark",
"jakc-hair-dark",
// darkjak-highres
"jakchires-arm",
"jakchires-arm-norm",
"jakchires-arm-dark",
"jakchires-eye",
"jakchires-eye-norm",
"jakchires-eye-dark",
"jakchires-eyebrow",
"jakchires-eyebrow-norm",
"jakchires-eyebrow-dark",
"jakchires-eyelid",
"jakchires-eyelid-norm",
"jakchires-eyelid-dark",
"jakchires-facelft",
"jakchires-facelft-norm",
"jakchires-facelft-dark",
"jakchires-facert",
"jakchires-facert-norm",
"jakchires-facert-dark",
"jakchires-hair",
"jakchires-hair-norm",
"jakchires-hair-dark",
// Skull Gem
"skull-gem-dest",
"skull-gem-alpha-00",
"skull-gem-alpha-01",
"skull-gem-alpha-02",
// default-water
"bomb-gradient",
"bomb-gradient-rim",
"bomb-gradient-flames",
"lightjak-wings",
"lighjak-wings-u-src",
"lightjak-wings-v-src",
"mushroom-dest",
"mushroom-src",
// default-warp
"shield-env-rim-dest",
"common-white",
"shield-env-uscroll",
"shield-env-rim-src",
// hanga-sprite
"glider-ring-dest2",
"glider-ring-dest",
"splash-foam",
"racegate",
// templea-water
"templea-waterfall-dest",
"templea-waterfall",
// templea-warp
"holograph-env-rim-dest",
"holograph-env-noise",
"holograph-env-scan",
"holograph-env-rim",
"environment-phong-rim",
// foresta-water
"fora-water-dest",
"fora-water",
"fora-waterfall-01-dest",
"fora-waterfall-01",
"fora-water-wave-01-dest",
"fora-water-wave-01",
// forestb-water
"forb-water-dest",
"forb-water",
"forb-waterfall-01-dest",
"forb-waterfall-01",
"forb-water-wave-01-dest",
"forb-water-wave-01",
// lforplnt-pris
"mh-gem-dest",
"mh-gem",
"mh-gem-alpha-01",
"mh-gem-alpha-02",
// lmhcitya-tfrag
"mhcitya-base-goo-01-dest",
"mhcitya-base-goo-01",
// lmhcityb-tfrag
"mhcityb-base-goo-01-dest",
"mhcityb-base-goo-01",
// mhcitya-pris
// "mhcity-de-door-skin-01-dest",
// "mhcity-de-door-skin-01",
// "mhcity-de-door-skin-02"
// templec-water
"tplc-water-dest",
"tplc-water",
// sewc-water
"sewer-water-01-c-dest",
"sewer-water-01-c",
"sewer-waterfall-01-c-dest",
"sewer-waterfall-01-c",
"sewer-waterfall-02-c-dest",
"sewer-waterfall-02-c",
"sewer-water-wave-01-c-dest",
"sewer-water-wave-01-c",
"sewer-water-highlight-01-c-dest",
"sewer-water-highlight-01-c",
// sewd-water
"sewer-water-01-d-dest",
"sewer-water-01-d",
"sewer-waterfall-02-d-dest",
"sewer-waterfall-02-d",
"sewer-water-highlight-01-d-dest",
"sewer-water-highlight-01-d",
"sewer-water-wave-01-d-dest",
"sewer-water-wave-01-d",
"sewer-water-wave-02-d-dest",
"sewer-water-wave-02-d",
"sewer-water-still-01-d-dest",
"sewer-water-still-01-d",
// sewe-water
"sewer-water-01-e-dest",
"sewer-water-01-e",
"sewer-waterfall-01-e-dest",
"sewer-waterfall-01-e",
"sewer-waterfall-02-e-dest",
"sewer-waterfall-02-e",
"sewer-water-highlight-01-e-dest",
"sewer-water-highlight-01-e",
// sewg-water
"sewer-water-01-g-dest",
"sewer-water-01-g",
"sewer-waterfall-02-g-dest",
"sewer-waterfall-02-g",
"sewer-water-wave-01-g-dest",
"sewer-water-wave-01-g",
// sewh-water
"sewer-water-01-h-dest",
"sewer-water-01-h",
"sewer-waterfall-02-h-dest",
"sewer-waterfall-02-h",
"sewer-water-wave-02-h-dest",
"sewer-water-wave-02-h",
"sewer-watefall-froth-01-h-dest",
"sewer-watefall-froth-01-h",
// sewi-water
"sewer-water-still-01-i-dest",
"sewer-water-still-01-i",
"sewer-waterfall-02-i-dest",
"sewer-waterfall-02-i",
"sewer-water-wave-01-i-dest",
"sewer-water-wave-01-i",
// sewj-water
"sewer-waterfall-02-j-dest",
"sewer-waterfall-02-j",
"sewer-watefall-froth-01-j-dest",
"sewer-watefall-froth-01-j",
// sewl-water
"sewer-waterfall-02-l-dest",
"sewer-waterfall-02-l",
"sewer-watefall-froth-01-l-dest",
"sewer-watefall-froth-01-l",
// sewm-water
"sewer-water-01-m-dest",
"sewer-water-01-m",
"sewer-waterfall-01-m-dest",
"sewer-waterfall-01-m",
"sewer-waterfall-02-m-dest",
"sewer-waterfall-02-m",
"sewer-water-highlight-01-m-dest",
"sewer-water-highlight-01-m",
"sewer-water-wave-01-m-dest",
"sewer-water-wave-01-m",
"sewer-water-still-01-m-dest",
"sewer-water-still-01-m",
"sewer-watefall-froth-01-m-dest",
"sewer-watefall-froth-01-m",
// sewn-water
"sewer-waterfall-01-n-dest",
"sewer-waterfall-01-n",
"sewer-waterfall-02-n-dest",
"sewer-waterfall-02-n",
// "sewer-water-highlight-01-n-dest",
// "sewer-water-highlight-01-n",
"sewer-water-wave-01-n-dest",
"sewer-water-wave-01-n",
"sewer-water-still-01-n-dest",
"sewer-water-still-01-n",
// hanga-water
// "des-thermal-01-dest",
// "des-thermal-01"
// desresc-warp
"sat-shield-dest",
"sat-shield-env-uvscroll",
"sat-shield",
// security
"security-env-dest",
"security-env-uscroll",
"security-dot-dest",
"security-dot-src",
// lgunnorm-water
"kg-target-c-forcefield-01-dest",
"kg-target-c-forcefield-01",
// templex-water
"temple-waterfall-dest",
"temple-waterfall",
// desertd-water
"des-waterfall-dest",
"des-waterfall",
// towerb-water
"tow-energy-bridge-dest",
"tow-energy-bridge",
// factoryb-water
"hemi-gradient-dest",
"hemi-gradient-rim",
"hemi-gradient-flames-dest",
"hemi-gradient-flames",
// factoryc-alpha
"facc-convey-dest",
"facc-convey",
"facc-convey-02-dest",
"facc-convey-02",
// waspal-water
"waspala-water-dest",
"waspala-water",
"waspala-waterfall-dest",
"waspala-waterfall",
// rubblea-water
"rub-water-dest",
"rub-water",
// rubblea2-water
"rub-water-desta2",
"rub-watera2",
// rubbleb-water
"rub-water-destb",
"rub-waterb",
// rubblec-water
"rub-water-destc",
"rub-waterc",
// nstb-quicksand
"nstb-quicksand-dest",
"nstb-quicksand-scroll",
// ctyslumb-water
"ctyslumb-water-dest",
"ctyslumb-water",
"ctyslumb-fountain-fall-dest",
"ctyslumb-fountain-fall",
// ctyslumc-water
"ctyslumc-water-dest",
"ctyslumc-water",
"ctyslumc-fountain-fall-dest",
"ctyslumc-fountain-fall",
// mined-tfrag
"mined-pillar-side-dest",
"mined-pillar-side-cold",
"mined-pillar-side-cooling",
"mined-pillar-side-hot",
"mined-pillar-molten",
"mined-pillar-top2side-dest",
"mined-pillar-top2side-cold",
"mined-pillar-top2side-cooling",
"mined-pillar-top2side-hot",
"mined-pillar-top-dest",
"mined-pillar-top-cold",
"mined-pillar-top-cooling",
"mined-pillar-top-hot",
"mined-pillar-molten-top",
// volcanoa-alpha
"vola-lava-01-dest",
"vola-lava-01",
"vola-lava-fall-dest",
"vola-lava-fall",
// wasstada-alpha
"wstd-lava-base-dest",
"wstd-lava-base"
"skull-gem-alpha-02"
],
"levels_to_extract": [
+16 -22
View File
@@ -1850,8 +1850,6 @@
["_stack_", 148, "float"],
["_stack_", 152, "float"],
["_stack_", 156, "float"],
[25, "a1", "light-trail-breadcrumb"],
[178, "s4", "light-trail-breadcrumb"],
[556, "a0", "vector"]
],
"compute-trail-scaled-t": [[17, "v1", "float"]],
@@ -2685,13 +2683,8 @@
[[21, 25], "a0", "prim-strip"]
],
"(event tracking light-trail-tracker)": [[55, "v1", "float"]],
"(method 21 light-trail)": [[[18, 64], "gp", "light-trail-breadcrumb"]],
"(method 14 light-trail)": [
[47, "a0", "uint"],
[[10, 32], "a1", "light-trail-breadcrumb"],
[[34, 60], "s3", "light-trail-breadcrumb"],
[[34, 73], "s2", "light-trail-breadcrumb"]
],
"(method 21 light-trail)": [[50, "v1", "light-trail-breadcrumb"]],
"(method 14 light-trail)": [[47, "a0", "uint"]],
"debug-menu-item-var-update-display-str": [
[48, "v1", "int"],
[63, "v1", "int"],
@@ -2742,12 +2735,16 @@
[27, "gp", "process-drawable"],
[30, "gp", "process-drawable"]
],
"(method 23 weapon-trail)": [[[0, 100], "gp", "weapon-trail-crumb"]],
"(method 23 weapon-trail)": [
[62, "v1", "light-trail-breadcrumb"],
[65, "v1", "light-trail-breadcrumb"]
],
"(method 22 weapon-trail)": [[32, "v0", "light-trail-breadcrumb"]],
"(method 22 tread-trail)": [[19, "v0", "light-trail-breadcrumb"]],
"(method 23 tread-trail)": [[[0, 100], "s5", "tread-trail-crumb"]],
"(method 23 tire-trail)": [[[0, 74], "s5", "tire-trail-crumb"]],
"(method 22 tire-trail)": [[[18, 24], "v1", "tire-trail-crumb"]],
"(method 23 tread-trail)": [
[51, "v1", "light-trail-breadcrumb"],
[67, "v0", "light-trail-breadcrumb"]
],
"(trans idle fma-sphere)": [[39, "a2", "process-drawable"]],
"part-water-splash-callback": [[3, "v1", "float"]],
"(method 15 water-control)": [[48, "v1", "float"]],
@@ -6431,11 +6428,11 @@
],
"cshape-reaction-scorp-shot": [[15, "v1", "v-scorp-shot"]],
"(method 78 wvehicle)": [
[262, "s1", "tire-trail-tracker"],
[271, "s1", "tire-trail-tracker"],
[287, "s1", "tire-trail-tracker"],
[309, "s1", "tire-trail-tracker"],
[322, "s1", "tire-trail-tracker"],
[262, "s1", "process-focusable"],
[271, "s1", "process-focusable"],
[287, "s1", "process-focusable"],
[309, "s1", "process-focusable"],
[322, "s1", "process-focusable"],
[358, "v1", "collide-shape-prim-group"]
],
"(method 97 wvehicle)": [
@@ -6554,10 +6551,7 @@
[15, "v1", "process-drawable"],
[22, "v1", "process-drawable"]
],
"(method 19 tire-trail)": [
[[5, 28], "s5", "tire-trail-crumb"],
[[5, 28], "s4", "tire-trail-crumb"]
],
"(method 19 tire-trail)": [],
"vehicle-spawn": [[93, "gp", "vehicle"]],
"vehicle-spawn-hack": [[41, "gp", "vehicle"]],
"(method 11 w-parking-spot)": [[42, "v0", "vector"]],
+3 -41
View File
@@ -515,44 +515,8 @@ TPageResultStats process_tpage(ObjectFileData& data,
// currently not needed.
break;
case int(PSM::PSMT8):
if (tex.clutpsm == (int)CPSM::PSMCT16) {
// will store output pixels, rgba (8888)
std::vector<u8> index_out;
// width is like the TEX0 register, in 64 texel units.
// not sure what the other widths are yet.
int read_width = 64 * tex.width[0];
// loop over pixels in output texture image
for (int y = 0; y < tex.h; y++) {
for (int x = 0; x < tex.w; x++) {
// read as the PSMT8 type. The dest field tells us a block offset.
auto addr8 = psmt8_addr(x, y, read_width) + tex.dest[0] * 256;
u8 value = *(u8*)(vram.data() + addr8);
index_out.push_back(value);
}
}
std::array<math::Vector4<u8>, 256> unscrambled_clut{};
for (int i = 0; i < 256; i++) {
u32 clut_chunk = i / 16;
u32 off_in_chunk = i % 16;
u8 clx = 0, cly = 0;
if (clut_chunk & 1) {
clx = 8;
}
cly = (clut_chunk >> 1) * 2;
if (off_in_chunk >= 8) {
off_in_chunk -= 8;
cly++;
}
clx += off_in_chunk;
u32 clut_addr = psmct16_addr(clx, cly, 64) + tex.clutdest * 256;
memcpy(&unscrambled_clut[i], vram.data() + clut_addr, 4);
}
texture_db.add_index_texture(texture_page.id, tex_id, index_out, unscrambled_clut,
tex.w, tex.h, tex.name, texture_page.name, level_names);
stats.successful_textures++;
} else if (tex.clutpsm == (int)PSM::PSMCT32) {
ASSERT(tex.clutpsm == int(CPSM::PSMCT32));
{
// will store output pixels, index (u8)
std::vector<u8> index_out;
@@ -591,12 +555,10 @@ TPageResultStats process_tpage(ObjectFileData& data,
texture_db.add_index_texture(texture_page.id, tex_id, index_out, unscrambled_clut,
tex.w, tex.h, tex.name, texture_page.name, level_names);
stats.successful_textures++;
} else {
ASSERT_NOT_REACHED();
}
break;
default:
lg::die("Animated texture {} format {} clut {}\n", tex.name, tex.psm, tex.clutpsm);
lg::die("Animated texture {} format {}\n", tex.name, tex.psm);
}
}
+4 -7
View File
@@ -322,8 +322,7 @@ void extract_common(const ObjectFileDB& db,
compressed.data(), compressed.size());
if (config.rip_levels) {
auto file_path = file_util::get_jak_project_dir() / "glb_out" /
game_version_names[config.game_version] / "common.glb";
auto file_path = file_util::get_jak_project_dir() / "glb_out" / "common.glb";
file_util::create_dir_if_needed_for_file(file_path);
save_level_foreground_as_gltf(tfrag_level, art_group_data, file_path);
}
@@ -361,17 +360,15 @@ void extract_from_level(const ObjectFileDB& db,
if (config.rip_levels) {
auto back_file_path = file_util::get_jak_project_dir() / "glb_out" /
game_version_names[config.game_version] /
fmt::format("{}-background.glb", level_data.level_name);
fmt::format("{}_background.glb", level_data.level_name);
file_util::create_dir_if_needed_for_file(back_file_path);
save_level_background_as_gltf(level_data, back_file_path);
auto fore_file_path = file_util::get_jak_project_dir() / "glb_out" /
game_version_names[config.game_version] /
fmt::format("{}-foreground.glb", level_data.level_name);
fmt::format("{}_foreground.glb", level_data.level_name);
file_util::create_dir_if_needed_for_file(fore_file_path);
save_level_foreground_as_gltf(level_data, art_group_data, fore_file_path);
}
file_util::write_text_file(entities_folder / fmt::format("{}-actors.json", level_data.level_name),
file_util::write_text_file(entities_folder / fmt::format("{}_actors.json", level_data.level_name),
extract_actors_to_json(bsp_header.actors));
}
@@ -1,7 +1,5 @@
#include "extract_merc.h"
#include "merc_replacement.h"
#include "common/log/log.h"
#include "common/util/BitUtils.h"
#include "common/util/FileUtil.h"
@@ -1599,60 +1597,6 @@ void create_modifiable_vertex_data(
}
}
void replace_model(tfrag3::Level& lvl, tfrag3::MercModel& model, const fs::path& mdl_path) {
if (model.max_bones < 100) {
auto lvl_name = lvl.level_name == "" ? "common" : lvl.level_name;
lg::info("Replacing {} for {}: {} effects, {} max bones, {} max draws\n", model.name, lvl_name,
model.effects.size(), model.max_bones, model.max_draws);
std::vector<tfrag3::MercVertex> old_verts;
for (auto& e : model.effects) {
for (auto& d : e.all_draws) {
for (size_t i = 0; i < d.index_count; i++) {
auto idx = lvl.merc_data.indices.at(i + d.first_index);
if (idx != UINT32_MAX) {
old_verts.push_back(lvl.merc_data.vertices[idx]);
}
}
}
}
auto swap_info = load_replacement_merc_model(model.name, lvl.merc_data.indices.size(),
lvl.merc_data.vertices.size(), lvl.textures.size(),
mdl_path.string(), old_verts, false);
model = swap_info.new_model;
size_t old_start = lvl.merc_data.vertices.size();
for (auto& ind : swap_info.new_indices) {
ASSERT(ind >= old_start);
}
lvl.merc_data.indices.insert(lvl.merc_data.indices.end(), swap_info.new_indices.begin(),
swap_info.new_indices.end());
lvl.merc_data.vertices.insert(lvl.merc_data.vertices.end(), swap_info.new_vertices.begin(),
swap_info.new_vertices.end());
lvl.textures.insert(lvl.textures.end(), swap_info.new_textures.begin(),
swap_info.new_textures.end());
}
}
void add_custom_model_to_level(tfrag3::Level& lvl,
const std::string& name,
const fs::path& mdl_path) {
auto lvl_name = lvl.level_name == "" ? "common" : lvl.level_name;
lg::info("Adding custom model {} to {}", name, lvl_name);
auto merc_data =
load_replacement_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
lvl.textures.size(), mdl_path.string(), {}, true);
for (auto& idx : merc_data.new_indices) {
lvl.merc_data.indices.push_back(idx);
}
for (auto& vert : merc_data.new_vertices) {
lvl.merc_data.vertices.push_back(vert);
}
lvl.merc_data.models.push_back(merc_data.new_model);
lvl.textures.insert(lvl.textures.end(), merc_data.new_textures.begin(),
merc_data.new_textures.end());
}
/*!
* Top-level merc extraction
*/
@@ -1787,33 +1731,5 @@ void extract_merc(const ObjectFileData& ag_data,
}
}
}
// do model replacements if present
auto merc_replacement_folder = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "merc_replacements";
if (file_util::file_exists(merc_replacement_folder.string())) {
auto merc_replacements =
file_util::find_files_in_dir(merc_replacement_folder, std::regex(".*\\.glb"));
for (auto& path : merc_replacements) {
auto name = path.stem().string();
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
[&](const auto& m) { return m.name == name; });
if (it != out.merc_data.models.end()) {
auto& model = *it;
replace_model(out, model, path);
}
}
}
// add custom models if present
auto lvl_name = out.level_name == "" ? "common" : out.level_name;
auto models_folder = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "models" / lvl_name;
if (file_util::file_exists(models_folder.string())) {
auto custom_models = file_util::find_files_in_dir(models_folder, std::regex(".*\\.glb"));
for (auto& mdl : custom_models) {
add_custom_model_to_level(out, mdl.stem().string(), mdl);
}
}
}
} // namespace decompiler
@@ -1,211 +0,0 @@
#include "merc_replacement.h"
using namespace gltf_util;
namespace decompiler {
void extract(const std::string& name,
MercExtractData& out,
const tinygltf::Model& model,
const std::vector<NodeWithTransform>& all_nodes,
u32 index_offset,
u32 vertex_offset,
u32 tex_offset) {
ASSERT(out.new_vertices.empty());
std::map<int, tfrag3::MercDraw> draw_by_material;
int mesh_count = 0;
int prim_count = 0;
for (const auto& n : all_nodes) {
const auto& node = model.nodes[n.node_idx];
if (node.extras.Has("set_invisible") && node.extras.Get("set_invisible").Get<int>()) {
continue;
}
if (node.mesh >= 0) {
const auto& mesh = model.meshes[node.mesh];
mesh_count++;
for (const auto& prim : mesh.primitives) {
prim_count++;
// extract index buffer
std::vector<u32> prim_indices = gltf_util::gltf_index_buffer(
model, prim.indices, out.new_vertices.size() + vertex_offset);
ASSERT_MSG(prim.mode == TINYGLTF_MODE_TRIANGLES, "Unsupported triangle mode");
// extract vertices
auto verts =
gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name);
out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end());
out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(),
verts.vtx_colors.end());
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
ASSERT(out.new_colors.size() == out.new_vertices.size());
// TODO: just putting it all in one material
auto& draw = draw_by_material[prim.material];
draw.mode = gltf_util::make_default_draw_mode(); // todo rm
draw.tree_tex_id = 0; // todo rm
draw.num_triangles += prim_indices.size() / 3;
draw.no_strip = true;
draw.index_count = prim_indices.size();
draw.first_index = index_offset + out.new_indices.size();
out.new_indices.insert(out.new_indices.end(), prim_indices.begin(), prim_indices.end());
}
}
}
tfrag3::MercEffect e;
out.new_model.name = name;
out.new_model.max_bones = 120;
out.new_model.max_draws = 200;
for (const auto& [mat_idx, d_] : draw_by_material) {
e.all_draws.push_back(d_);
auto& draw = e.all_draws.back();
draw.mode = make_default_draw_mode();
if (mat_idx == -1) {
lg::warn("Draw had a material index of -1, using default texture.");
draw.tree_tex_id = 0;
continue;
}
const auto& mat = model.materials[mat_idx];
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
if (tex_idx == -1) {
lg::warn("Material {} has no texture, using default texture.", mat.name);
draw.tree_tex_id = 0;
continue;
}
const auto& tex = model.textures[tex_idx];
ASSERT(tex.sampler >= 0);
ASSERT(tex.source >= 0);
draw.mode = draw_mode_from_sampler(model.samplers.at(tex.sampler));
const auto& img = model.images[tex.source];
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
}
lg::info("total of {} unique materials", e.all_draws.size());
e.has_mod_draw = false;
out.new_model.effects.push_back(e);
out.new_model.effects.push_back(e);
out.new_model.effects.push_back(e);
out.new_model.effects.push_back(e);
lg::info("Merged {} meshes and {} prims into {} vertices", mesh_count, prim_count,
out.new_vertices.size());
}
const tfrag3::MercVertex& find_closest(const std::vector<tfrag3::MercVertex>& old,
float x,
float y,
float z) {
float best_dist = 1e10;
int best_idx = 0;
for (int i = 0; i < old.size(); i++) {
auto& v = old[i];
float dx = v.pos[0] - x;
float dy = v.pos[1] - y;
float dz = v.pos[2] - z;
float dist = (dx * dx) + (dy * dy) + (dz * dz);
if (dist < best_dist) {
best_dist = dist;
best_idx = i;
}
}
return old[best_idx];
}
void merc_convert_replacement(MercSwapData& out,
const MercExtractData& in,
const std::vector<tfrag3::MercVertex>& old_verts) {
out.new_model = in.new_model;
out.new_indices = in.new_indices;
out.new_textures = in.tex_pool.textures_by_idx;
// convert vertices
for (size_t i = 0; i < in.new_vertices.size(); i++) {
const auto& y = in.new_vertices[i];
const auto& copy_from = find_closest(old_verts, y.x, y.y, y.z);
auto& x = out.new_vertices.emplace_back();
x.pos[0] = y.x;
x.pos[1] = y.y;
x.pos[2] = y.z;
x.normal[0] = copy_from.normal[0];
x.normal[1] = copy_from.normal[1];
x.normal[2] = copy_from.normal[2];
x.weights[0] = copy_from.weights[0];
x.weights[1] = copy_from.weights[1];
x.weights[2] = copy_from.weights[2];
x.st[0] = y.s;
x.st[1] = y.t;
x.rgba[0] = in.new_colors[i][0];
x.rgba[1] = in.new_colors[i][1];
x.rgba[2] = in.new_colors[i][2];
x.rgba[3] = in.new_colors[i][3];
x.mats[0] = copy_from.mats[0];
x.mats[1] = copy_from.mats[1];
x.mats[2] = copy_from.mats[2];
}
}
void merc_convert_custom(MercSwapData& out, const MercExtractData& in) {
out.new_model = in.new_model;
out.new_indices = in.new_indices;
out.new_textures = in.tex_pool.textures_by_idx;
// convert vertices
for (size_t i = 0; i < in.new_vertices.size(); i++) {
const auto& y = in.new_vertices[i];
auto& x = out.new_vertices.emplace_back();
x.pos[0] = y.x;
x.pos[1] = y.y;
x.pos[2] = y.z;
x.normal[0] = in.normals.at(i).x();
x.normal[1] = in.normals.at(i).y();
x.normal[2] = in.normals.at(i).z();
x.weights[0] = 1.0f;
x.weights[1] = 0.0f;
x.weights[2] = 0.0f;
x.st[0] = y.s;
x.st[1] = y.t;
x.rgba[0] = in.new_colors[i][0];
x.rgba[1] = in.new_colors[i][1];
x.rgba[2] = in.new_colors[i][2];
x.rgba[3] = in.new_colors[i][3];
x.mats[0] = 3;
x.mats[1] = 0;
x.mats[2] = 0;
}
}
MercSwapData load_replacement_merc_model(const std::string& name,
u32 current_idx_count,
u32 current_vtx_count,
u32 current_tex_count,
const std::string& path,
const std::vector<tfrag3::MercVertex>& old_verts,
bool custom_mdl) {
MercSwapData result;
lg::info("Reading gltf mesh: {}", path);
tinygltf::TinyGLTF loader;
tinygltf::Model model;
std::string err, warn;
bool res = loader.LoadBinaryFromFile(&model, &err, &warn, path);
ASSERT_MSG(warn.empty(), warn.c_str());
ASSERT_MSG(err.empty(), err.c_str());
ASSERT_MSG(res, "Failed to load GLTF file!");
auto all_nodes = flatten_nodes_from_all_scenes(model);
MercExtractData extract_data;
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
current_tex_count);
if (custom_mdl) {
merc_convert_custom(result, extract_data);
} else {
merc_convert_replacement(result, extract_data, old_verts);
}
return result;
}
} // namespace decompiler
@@ -1,32 +0,0 @@
#pragma once
#include "common/log/log.h"
#include "common/util/gltf_util.h"
namespace decompiler {
struct MercExtractData {
gltf_util::TexturePool tex_pool;
std::vector<u32> new_indices;
std::vector<tfrag3::PreloadedVertex> new_vertices;
std::vector<math::Vector<u8, 4>> new_colors;
std::vector<math::Vector3f> normals;
tfrag3::MercModel new_model;
};
// Data produced by loading a replacement model
struct MercSwapData {
std::vector<u32> new_indices;
std::vector<tfrag3::MercVertex> new_vertices;
std::vector<tfrag3::Texture> new_textures;
tfrag3::MercModel new_model;
};
MercSwapData load_replacement_merc_model(const std::string& name,
u32 current_idx_count,
u32 current_vtx_count,
u32 current_tex_count,
const std::string& path,
const std::vector<tfrag3::MercVertex>& old_verts,
bool custom_mdl);
} // namespace decompiler
+1
View File
@@ -2576,6 +2576,7 @@ void CallOp::propagate_types2(types2::Instruction& instr,
if (can_use_call_parent) {
out_types[Register(Reg::GPR, Reg::V0)]->type = TP_Type::make_from_ts(call_parent_result_type);
lg::print("used special {}\n", call_parent_result_type.print());
use_normal_last_arg = false;
}
}
-24
View File
@@ -201,7 +201,6 @@ set(RUNTIME_SOURCE
mips2c/jak3_functions/sky.cpp
mips2c/jak3_functions/texture.cpp
mips2c/jak3_functions/particle_curves.cpp
mips2c/jak3_functions/cloth.cpp
mips2c/jak3_functions/collide_cache.cpp
mips2c/jak3_functions/collide_hash.cpp
mips2c/jak3_functions/collide_edge_grab.cpp
@@ -255,29 +254,6 @@ set(RUNTIME_SOURCE
overlord/jak2/streamlfo.cpp
overlord/jak2/streamlist.cpp
overlord/jak2/vag.cpp
overlord/jak3/overlord.cpp
overlord/jak3/pagemanager.cpp
overlord/jak3/iso_cd.cpp
overlord/jak3/dma.cpp
overlord/jak3/iso.cpp
overlord/jak3/iso_queue.cpp
overlord/jak3/srpc.cpp
overlord/jak3/vag.cpp
overlord/jak3/ssound.cpp
overlord/jak3/iso_api.cpp
overlord/jak3/spustreams.cpp
overlord/jak3/list.cpp
overlord/jak3/vblank_handler.cpp
overlord/jak3/dvd_driver.cpp
overlord/jak3/basefile.cpp
overlord/jak3/basefilesystem.cpp
overlord/jak3/ramdisk.cpp
overlord/jak3/isocommon.cpp
overlord/jak3/init.cpp
overlord/jak3/stream.cpp
overlord/jak3/sbank.cpp
overlord/jak3/soundcommon.cpp
overlord/jak3/streamlist.cpp
runtime.cpp
sce/deci2.cpp
sce/iop.cpp
-7
View File
@@ -54,11 +54,4 @@
:lines "game/assets/jak2/subtitle/subtitle_lines_en-GB.json"
:meta "game/assets/jak2/subtitle/subtitle_meta_en-GB.json"
:lines-base "game/assets/jak2/subtitle/subtitle_lines_en-US.json"
:meta-base "game/assets/jak2/subtitle/subtitle_meta_en-US.json")
(file-json
:language-id 9
:text-version "jak2"
:lines "game/assets/jak2/subtitle/subtitle_lines_fi-FI.json"
:meta "game/assets/jak2/subtitle/subtitle_meta_fi-FI.json"
:lines-base "game/assets/jak2/subtitle/subtitle_lines_en-US.json"
:meta-base "game/assets/jak2/subtitle/subtitle_meta_en-US.json"))
+1 -2
View File
@@ -21,8 +21,7 @@
(file-json 7 jak2 "common" '("game/assets/jak2/text/game_custom_text_en-GB.json"))
;; custom languages
(file-json 8 jak2 "common" '("game/assets/jak2/text/game_custom_text_pt-PT.json"))
(file-json 9 jak2 "common" '("game/assets/jak2/text/game_custom_text_fi-FI.json"
"game/assets/jak2/text/game_base_text_fi-FI.json"))
(file-json 9 jak2 "common" '("game/assets/jak2/text/game_custom_text_fi-FI.json"))
(file-json 10 jak2 "common" '("game/assets/jak2/text/game_custom_text_sv-SE.json"))
(file-json 11 jak2 "common" '("game/assets/jak2/text/game_custom_text_da-DK.json"))
(file-json 12 jak2 "common" '("game/assets/jak2/text/game_custom_text_no-NO.json"))
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,7 +1,6 @@
{
"1a3": "138",
"1b5": "161",
"133a": "1113",
"1200": "1031",
"1201": "1032",
"1202": "1034",
@@ -1,531 +0,0 @@
{
"0100": "Lopeta",
"0101": "Tauko~",
"0102": "Tekstityksen kieli",
"0103": "Ääniformaatti",
"0104": "Mono",
"0105": "Stereo",
"0106": "Surround",
"0107": "Äänitehosteet",
"0108": "Musiikki",
"0109": "Puhe",
"010a": "Kieli",
"010b": "Värinätoiminto",
"010c": "Vinkit",
"010d": "Keskitä ruutu",
"010e": "Päällä",
"010f": "Pois",
"0110": "Käytä suuntanäppäimiä",
"0111": "<FLAG_USA> English",
"0112": "<FLAG_FRANCE> Fran,cais",
"0113": "<FLAG_GERMAN> Deutsch",
"0114": "<FLAG_SPAIN> Español",
"0115": "<FLAG_ITALIAN> Italiano",
"0116": "<FLAG_KOREA> ~Y~Z<K32e>~Z<K31a>~Z<K3c8>~Y~Z<K35e>~Z<K36b>~Z<K3de>~Y~Z<K30f>~Z<K31d>",
"0117": "<FLAG_JAPAN> にほんご",
"0118": "Kuvasuhde",
"0119": "Progressiivinen skannaus",
"011a": "Videotila",
"011b": "Peliasetukset",
"011c": "Grafiikan asetukset",
"011d": "Ääniasetukset",
"011e": "4x3",
"011f": "16x9",
"0120": "60Hz",
"0121": "50Hz",
"0122": "Jak II",
"0123": "Poistu demosta",
"0124": "Kyllä",
"0125": "Ei",
"0126": "Takaisin",
"0127": "OK",
"0128": "Seuraava",
"0129": "Edellinen",
"012a": "Jatka tallentamatta",
"012b": "Valitse tallennuspaikka",
"012c": "Valitse ladattava tallennus",
"012d": "Lataa peli",
"012e": "Tallenna peli",
"012f": "Tyhjä",
"0130": "Asetukset",
"0131": "Uusi peli",
"0132": "Paina START-näppäintä",
"0133": "Lopeta peli",
"0134": "Kartta",
"0135": "Valitse aloitus",
"0136": "Ennätykset",
"0137": "1. sija",
"0138": "2. sija",
"0139": "3. sija",
"013a": "4. sija",
"013b": "5. sija",
"013c": "6. sija",
"013d": "7. sija",
"013e": "8. sija",
"013f": "NYFE-leijuri",
"0140": "Luokka 1",
"0141": "Luokka 2",
"0142": "Luokka 3",
"0143": "Harjoitusrata",
"0144": "Haulikko",
"0145": "Läjäytin",
"0146": "Vulkanus-piippu",
"0147": "Rauhantekijä",
"0148": "Oninin haaste",
"0149": "Metallipää-mäiskintä",
"014a": "JET-lauta-haaste",
"014b": "Oninin teltta",
"014c": "Sikahevon saluuna",
"014d": "Stadion",
"014e": "Luokka 1 - käänteinen",
"014f": "Luokka 2 - käänteinen",
"0150": "Luokka 3 - käänteinen",
"0151": "Sataman kisa",
"0152": "Kaupungin kisa",
"0153": "Salaisuudet",
"0154": "Avattu",
"0155": "Poista Jakin pukinparta",
"0156": "Käänteinen maailma",
"0157": "Loputtomat ammukset",
"0158": "Haavoittumattomuus",
"0159": "Sankaritila",
"015a": "Välinäytösten 1. näytös",
"015b": "Välinäytösten 2. näytös",
"015c": "Välinäytösten 3. näytös",
"015d": "Leikekirja",
"015e": "Mega-leikekirja",
"015f": "Leikekirja 3",
"0160": "Tehtävän valinta",
"0161": "Loputon Raivo-Jak",
"0162": "Vulkanus-tykin harjoitusrata",
"0163": "Rauhantekijän harjoitusrata",
"0164": "Käänteiset kisat",
"0165": "Isopäinen Jak",
"0166": "Pienipäinen Jak",
"0167": "Saatavilla",
"0168": "Kerätty",
"0169": "Tehtävät",
"016a": "Valitse esialoitus",
"016b": "Valitse kioski-aloitus",
"016c": "Valitse kohtaus",
"016d": "Tekstitys",
"016e": "Aloita uudelleen",
"016f": "<ICON_MISSION_TODO>",
"0170": "<ICON_MISSION_COMPLETE>",
"0171": "Ei mitään",
"0172": "Peli",
"0173": "Aloita/lopeta",
"0174": "Osta",
"0175": "Voitto",
"0176": "Häviö",
"0177": "Kokonaisaika",
"0178": "Kierros ",
"0179": "Palauta painamalla <PAD_SQUARE>",
"017a": "Kiireinen",
"017b": "Jatka painamalla <PAD_X>",
"017c": "____~%Suoritetut tehtävät",
"017d": "Suorittamattomat tehtävät",
"017e": "Yritä uudelleen?",
"017f": "Salaisuus saatavilla päävalikosta",
"0180": "<PAD_X> = Kyllä, <PAD_TRIANGLE> = Ei",
"0181": "Paina <PAD_TRIANGLE> puhuaksesi.",
"0182": "Paina <PAD_TRIANGLE> käyttääksesi.",
"0183": "Paina <PAD_TRIANGLE> matkustaaksesi.",
"0184": "Valitse taso suuntanäppäimellä",
"0185": "Paina <PAD_TRIANGLE> poistuaksesi.",
"0186": "Paina <PAD_TRIANGLE> pelataksesi.",
"0187": "Halutako pelata uudelleen?",
"0188": "Tehtävä suoritettu",
"0189": "Tehtävä epäonnistui",
"018a": "Yritä uudelleen?",
"018b": "Ruutu ottaa nyt käyttöön 60Hz-tilan",
"018c": "Ruutu ottaa nyt käyttöön progressiivisen skannauksen",
"018d": "Jos kuva näkyy virheellisenä, televisiosi ei tue tätä tilaa",
"018e": "Jos niin käy, odota 10 sekuntia, niin ruutu palautuu takaisin",
"018f": "Ruutu on nyt 60Hz-tilassa",
"0190": "Ruutu on nyt Progresiivinen skannaus -tilassa",
"0191": "Haluatko pitää tämän tilan käytössä?",
"0192": "Levy poistettiin",
"0193": "Syötä Jak II -levy sisään, jotta voit jatkaa pelaamista",
"0194": "Virhe tietojen lukemisessa",
"0195": "Tarkista Jak II -levysi ja yritä uudelleen",
"0196": "Haluatko varmasti lopettaa?",
"0197": "Haluatko aloittaa pelin?",
"0198": "Ei tarpeeksi tilaa muistikortilla Memory__Card__(PS2) paikassa Memory__Card__Slot__~D",
"0199": "Ei Memory__Card__(PS2) liitettynä paikassa Memory__Card__slot__~D",
"019a": "Memory__Card__(PS2) paikassa Memory__Card__slot__~D on alustamaton",
"019b": "Jak II vaatii ~D Kt vapaata tilaa",
"019c": "Syötä Jak II -pelitietoja sisältävä Memory__Card__(PS2) paikkaan Memory__Card__slot__~D",
"019d": "Syötä Memory__Card__(PS2) jossa on tarpeeksi tilaa, muuten pelitietojasi ei voida tallentaa",
"019e": "Ilman alustamista pelitietoja ei voida tallentaa",
"019f": "Tallennetaan tietoja",
"01a0": "Ladataan tietoja",
"01a1": "Alustetaan",
"01a2": "Luodaan tallennustiedostoa",
"01a3": "Älä poista Memory__Card__(PS2) paikassa Memory__Card__slot__~D tai sammuta laitettasi",
"01a4": "Jak II -tallennus on jo olemassa valitsemassasi tiedostossa",
"01a5": "Haluatko korvata tämän?",
"01a6": "Alusta?",
"01a7": "Jatka?",
"01a8": "Takaisin?",
"01a9": "Virhe ladattaessa",
"01aa": "virhe tallentaessa",
"01ab": "Virhe alustaessa",
"01ac": "Virhe luodessa tallennustiedostoa",
"01ad": "Tarkista Memory__Card__(PS2) paikassa Memory__Card__slot__~D",
"01ae": "Tarkista Memory__Card__(PS2) paikassa Memory__Card__slot__~D ja yritä uudelleen",
"01af": "Memory__Card__(PS2) paikasta Memory__Card__slot__~D poistettiin",
"01b0": "Automaattinen tallennus on poistettu käytöstä",
"01b1": "Tallenna pelisi manuaalisesti, niin automaattinen tallennus palautetaan käyttöön",
"01b2": "Jak II -tallennustietoja ei löytynyt kortilta Memory__Card__(PS2) paikassa Memory__Card__slot__~D",
"01b3": "Haluatko luoda uuden Jak II -tallennuksen?",
"01b4": "Kun oheinen kuvake ilmestyy, edistykesi tallennetaan",
"01b5": "Kun tämä kuvake on ruudulla, älä irrota Memory__Card__(PS2) tai sammuta laitettasi",
"01b6": "Pakene <COLOR_WHITE>linnoituksesta",
"01b7": "Suojele Koria ja lasta",
"01b8": "Nouda lippu <COLOR_WHITE>aavekaupungista",
"01b9": "Etsi <COLOR_WHITE>pumppaamon<COLOR_PROGRESS> venttiili",
"01ba": "Räjäytä ammukset <COLOR_WHITE>linnoituksessa",
"01bb": "Kuljeta toimitus <COLOR_WHITE>Sikahevon saluunaan",
"01bc": "Läpäise haulikon <COLOR_WHITE>harjoitusrata",
"01bd": "Suojele Sigiä <COLOR_WHITE>pumppaamolla",
"01be": "Tuhoa tykit <COLOR_WHITE>viemärissä",
"01bf": "Etsi <COLOR_WHITE>läjäytin<COLOR_PROGRESS>-modi",
"01c0": "Pelasta Vin <COLOR_WHITE>avolouhoksella",
"01c1": "Voita aika <COLOR_WHITE>kisatalliin",
"01c2": "Läpäise läjäyttimen <COLOR_WHITE>harjoitusrata",
"01c3": "Tuhoa munat <COLOR_WHITE>poralautalla",
"01c4": "Etsi <COLOR_WHITE>pumppaamon<COLOR_PROGRESS> partio",
"01c5": "Nouda rahat Krewille",
"01c6": "Voita JET-lauta-haaste <COLOR_WHITE>stadionilla",
"01c7": "Etsi Linssi <COLOR_WHITE>vuoristotemppelissä",
"01c8": "Etsi Siru <COLOR_WHITE>vuoristotemppelissä",
"01c9": "Etsi Ratas <COLOR_WHITE>vuoristotemppelissä",
"01ca": "Käynnistä 5 virtakytkintä",
"01cb": "Nouse hissillä <COLOR_WHITE>palatsiin",
"01cc": "Päihitä paroni <COLOR_WHITE>palatsissa",
"01cd": "Kuljeta Vastarinnan jäsenet",
"01ce": "Suojele paikkaa <COLOR_WHITE>aavekaupungissa",
"01cf": "Nappaa tarkkailijat <COLOR_WHITE>Havenin metsässä",
"01d0": "Saata lapsi <COLOR_WHITE>voimalaan",
"01d1": "Pelasta vaanijoita Brutterille",
"01d2": "Tuhoa lasti <COLOR_WHITE>satamalla",
"01d3": "Pysäytä tankkeri",
"01d4": "Tuhoa välineistö <COLOR_WHITE>kaivannolla",
"01d5": "Räjäytä ecokaivot <COLOR_WHITE>avolouhoksella",
"01d6": "Tyhjennä <COLOR_WHITE>viemäri<COLOR_PROGRESS> löytääksesi patsaan",
"01d7": "Tuhoa alus <COLOR_WHITE>poralautalla",
"01d8": "Pelasta vaanijat <COLOR_WHITE>kaivannolla",
"01d9": "Tapa Metallipäät <COLOR_WHITE>Havenin metsässä",
"01da": "Voita luokan 3 kisa <COLOR_WHITE>stadionilla",
"01db": "Nouda sinetin pala <COLOR_WHITE>kaivannolla",
"01dc": "Nouda sinetin pala <COLOR_WHITE>vesislummeilla",
"01dd": "Tuhoa 5 Villikissa-leijuria",
"01de": "Voita Oninin haaste",
"01df": "Käytä esineitä <COLOR_WHITE>Ei-kenenkään-kanjonissa",
"01e0": "Kohtaa testit <COLOR_WHITE>Marin haudassa",
"01e1": "Avaa holvin ovi <COLOR_WHITE>Marin haudassa",
"01e2": "Läpäise ensimmäinen <COLOR_WHITE>miehuuden testi",
"01e3": "Läpäise toinen <COLOR_WHITE>miehuuden testi",
"01e4": "Päihitä paroni <COLOR_WHITE>Marin haudassa",
"01e5": "Pelasta ystävät <COLOR_WHITE>linnoituksesta",
"01e6": "Saata miehet <COLOR_WHITE>viemärien<COLOR_PROGRESS> läpi",
"01e7": "Etsi <COLOR_WHITE>Rauhantekijä",
"01e8": "Voita luokan 2 kisa <COLOR_WHITE>stadionilla",
"01e9": "Suojele piilopaikkaa pommiboteilta",
"01ea": "Tutki <COLOR_WHITE>rakennustyömaa",
"01eb": "Kiipeä <COLOR_WHITE>rakennustyömaata",
"01ec": "Voita Erol kisahaasteessa",
"01ed": "Tuhoa munat <COLOR_WHITE>avolouhoksella",
"01ee": "Nouda Elämän siemen <COLOR_WHITE>aavekaupungissa",
"01ef": "Vie Elämän siemen <COLOR_WHITE>Havenin metsään",
"01f0": "Suojele Samosia <COLOR_WHITE>Havenin metsässä",
"01f1": "Tuhoa <COLOR_WHITE>poralautan<COLOR_PROGRESS> torni",
"01f2": "Voita luokan 1 kisa <COLOR_WHITE>stadionilla",
"01f3": "Tutki <COLOR_WHITE>palatsia",
"01f4": "Hanki Marin sydän <COLOR_WHITE>asetehtaalla",
"01f5": "Päihitä Krew <COLOR_WHITE>asetehtaalla",
"01f6": "Voita peli <COLOR_WHITE>Sikahevon saluunassa",
"01f7": "Etsi Sig <COLOR_WHITE>satamanpohjalla",
"01f8": "Saata Sig <COLOR_WHITE>satamanpohjan<COLOR_PROGRESS> läpi",
"01f9": "Puolusta <COLOR_WHITE>stadionia",
"01fa": "Puolusta vaanijapalloa",
"01fb": "Tuhoa tunnelit <COLOR_WHITE>satamanpohjalla",
"01fc": "Taistele tiesi <COLOR_WHITE>pesän muurille",
"01fd": "Löydä Paroni <COLOR_WHITE>rakennustyömaalla",
"01fe": "Tuhoa <COLOR_WHITE>pesän muuri",
"01ff": "Tuhoa Metalli-Kor <COLOR_WHITE>pesällä",
"0200": "Puhu <COLOR_WHITE>Korille",
"0201": "Puhu <COLOR_WHITE>Tornille",
"0202": "Puhu <COLOR_WHITE>Krewille",
"0203": "Puhu <COLOR_WHITE>Oninille",
"0204": "Puhu <COLOR_WHITE>Vinille",
"0205": "Puhu <COLOR_WHITE>Varjolle",
"0206": "Puhu <COLOR_WHITE>Sigille",
"0207": "Puhu <COLOR_WHITE>Mekaanikolle",
"0208": "Puhu <COLOR_WHITE>Keiralle",
"0209": "Puhu <COLOR_WHITE>Brutterille",
"020a": "Tarkista <COLOR_WHITE>basaari",
"020b": "Tarkista <COLOR_WHITE>vesislummit",
"020c": "Mene <COLOR_WHITE>Ei-kenenkään-kanjonille",
"020d": "Mene <COLOR_WHITE>Marin hautaan",
"020e": "Voita <COLOR_WHITE>Metallipää-mäiskintä",
"020f": "Puolusta <COLOR_WHITE>sataman muuria",
"0210": "Tarkista <COLOR_WHITE>rakennustyömaa",
"0211": "Hyökkää <COLOR_WHITE>Metallipäiden pesään",
"0212": "Käy <COLOR_WHITE>Oraakkelin<COLOR_PROGRESS> luona",
"0213": "Haven City",
"0214": "Linnoitus",
"0215": "Laskeutumisalusta",
"0216": "Palatsin katto",
"0217": "Palatsi",
"0218": "Asetehdas",
"0219": "Aavekaupunki",
"021a": "Pumppaamo",
"021b": "Viemäri",
"021c": "Avolouhos",
"021d": "Vuoristotemppeli",
"021e": "Havenin metsä",
"021f": "Poralautta",
"0220": "Marin hauta",
"0221": "Kaivanto",
"0222": "Satamanpohja",
"0223": "Pesä",
"0224": "Hyppää painamalla <PAD_X>",
"0225": "Kieri painamalla <PAD_L1> liikkeessä",
"0226": "Paina <PAD_X> ja sitten <PAD_X> uudelleen ilmassa",
"0227": "Hyökkää painamalla <PAD_SQUARE> tai <PAD_CIRCLE>",
"0228": "Kieri ja paina sitten <PAD_X> syöksyhyppyyn",
"0229": "Hyppää ja paina <PAD_SQUARE> ilmassa",
"022a": "Paina <PAD_L1> ja sitten <PAD_X> korkeaan hyppyyn",
"022b": "Ammu painamalla <PAD_R1>",
"022c": "<PAD_DPAD_UP> laittaa aseen pois",
"022d": "<PAD_DPAD_UP> tai <PAD_R1> tuo aseen esiin",
"022e": "Pelaa haulikon harjoitusrata painamalla <PAD_X>",
"022f": "<PAD_X> = Haulikon harjoitus~%<PAD_SQUARE> = Vulkanus-tykin harjoitus",
"0230": "Vaihda asetta painamalla <PAD_DPAD_DOWN>",
"0231": "Pelaa läjäyttimen harjoitusrata painamalla <PAD_X>",
"0232": "<PAD_X> = Läjäyttimen harjoitus~%<PAD_SQUARE> = Rauhantekijän harjoitus",
"0233": "Potkaise kohdetta ja paina <PAD_R1> tehdäksesi pikatulisarjan",
"0234": "Ammu laatikoita",
"0235": "Tavoite",
"0236": "Kulta",
"0237": "Hopea",
"0238": "Pronssi",
"0239": "Käytä lautaa painamalla <PAD_R2>",
"023a": "Hyppy: Paina <PAD_X>",
"023b": "Kyykkyhyppy: Paina <PAD_L1> ja sitten <PAD_X>",
"023c": "Voimahyppy: Paina <PAD_X> hieman laskeuduttuasi hypystä",
"023d": "Kaideliuku: Paina <PAD_SQUARE> ja <PAD_ANALOG_ANY>",
"023e": "Pyörähdys: Paina <PAD_X> ja sitten <PAD_R1> ja <PAD_ANALOG_LEFT_RIGHT>",
"023f": "Voltti: Paina <PAD_X> ja sitten <PAD_R1> ja <PAD_ANALOG_UP_DOWN>",
"0240": "Temppu: Paina <PAD_X> ja sitten <PAD_L1> ja <PAD_ANALOG_ANY>",
"0241": "Saat paljon pisteitä, jos liu'ut ja teet tempun liukuaksesi uudestaan",
"0242": "Aloita haaste aktivoimalla tuomari",
"0243": "Yritä uudelleen!",
"0244": "Palaa talliin",
"0245": "Tehtävä suoritettu: Palaa Krewin luo",
"0246": "Vaihda leijuvyöhykettä painamalla <PAD_R2>",
"0247": "Sukella painamalla <PAD_CIRCLE> pohjassa uidessasi",
"0248": "<PAD_CIRCLE> = Turbo~%<PAD_R1> tai <PAD_L1> = Hyppy",
"0249": "Iske Titaaniasulla painamalla <PAD_SQUARE>",
"024a": "Tartu Titaaniasulla lohkareisiin painamalla <PAD_R1>",
"024b": "Heitä nostetut esineet painamalla <PAD_SQUARE>",
"024c": "Paina <PAD_X> rampin yläpäässä",
"024d": "Liu'u kaidetta JET-laudalla painamalla <PAD_SQUARE> tai <PAD_CIRCLE>",
"024e": "Käytä <PAD_DPAD_ANY> ja <PAD_X> <PAD_CIRCLE> <PAD_SQUARE> <PAD_TRIANGLE>",
"024f": "Pumppaamo",
"0250": "Avolouhos",
"0251": "Katso traileri",
"0252": "<PAD_R2> mennäksesi laudan päälle tai pois",
"0253": "Käytä pimeää voimaa painamalla <PAD_L2>",
"0254": "Sony Computer Entertainment America~%presents",
"0255": "Sony Computer Entertainment Europe~%presents",
"0256": "Sony Computer Entertainment Korea~%presents",
"0257": "Sony Computer Entertainment Inc.~%presents",
"0258": "A game by",
"0259": "Jak II",
"025a": "Kaksi vuotta myöhemmin...",
"025b": "Viikko myöhemmin...",
"025c": "Asepäivitys hankittu",
"025d": "Haulikko hankittu",
"025e": "Läjäytin-modi mankittu",
"025f": "Vulkanus-piippu hankittu",
"0260": "Rauhantekijä hankittu",
"0261": "Haulikon tulinopeus päivitetty",
"0262": "Aseiden ammuskapasiteetti päivitetty",
"0263": "Aseiden vahinkoa päivitetty",
"0264": "Tehtävä suoritettu",
"0265": "Punainen turvapassi hankittu",
"0266": "Vihreä turvapassi hankittu",
"0267": "Keltainen turvapassi hankittu",
"0268": "Palatsin turvapassi hankittu",
"0269": "Musta turvapassi hankittu",
"026a": "Linssi hankittu",
"026b": "Ratas hankittu",
"026c": "Siru hankittu",
"026d": "Tuo 25 metallipäiden kallohelmeä",
"026e": "Tuo 200 metallipäiden kallohelmeä",
"026f": "Tuo 25 metallipäiden kallohelmeä",
"0270": "Tuo 200 metallipäiden kallohelmeä",
"0271": "Tuo 200 metallipäiden kallohelmeä",
"0272": "Tuo 100 metallipäiden kallohelmeä",
"0273": "Raivopommi: Paina <PAD_X> ja sitten <PAD_SQUARE>",
"0274": "Raivopurkaus: Paina <PAD_SQUARE> ja sitten <PAD_X>",
"0275": "Raivo-Jak on nyt haavoittumaton!",
"0276": "Raivojätti: Paina <PAD_L2> raivotilassa",
"0277": "Ohi",
"0278": "Valitse tapahtuma",
"0279": "Skeittipuisto",
"027a": "Luokan 3 kisa",
"027b": "Luokan 2 kisa",
"027c": "Luokan 1 kisa",
"027d": "Käänteinen luokan 3 kisa",
"027e": "Käänteinen luokan 2 kisa",
"027f": "Käänteinen luokan 1 kisa",
"0280": "Daxter saa suupalan",
"0281": "Tavataan Torn",
"0282": "Noutamassa lippua",
"0283": "Suojele pyhää paikkaa",
"0284": "Meidän maailmamme!",
"0285": "Vanhoja muistoja",
"0286": "Vin tarvitsee apua",
"0287": "Tavataan Vin",
"0288": "Hyviä ja huonoja uutisia",
"0289": "Suuri murskaus",
"028a": "Meillä on yhä ongelmia",
"028b": "Kaivot posahtavat!",
"028c": "Tavataan Kor ja lapsi",
"028d": "Vastarinta",
"028e": "Villikissa-tehtävä",
"028f": "Tornin toimitus",
"0290": "Tavataan Krew ja Sig",
"0291": "Yllätyshyökkäys!",
"0292": "Ashelin on huolissaan",
"0293": "Vin, kamu. Tarvitsemme palveluksen.",
"0294": "Kuka on verhojen takana?",
"0295": "Tiedonjyvä",
"0296": "Iloinen jälleennäkeminen",
"0297": "Kissatappelu",
"0298": "Jak poistuu paikalta",
"0299": "Daxterin suuri voitto",
"029a": "Keira paljastaa suunnitelmansa",
"029b": "Suuri kilpailu",
"029c": "Voittajan piiri",
"029d": "Tavataan Oraakkeli",
"029e": "Jak saa pimeän voiman",
"029f": "Jak saa toisen pimeän voiman",
"02a0": "Jak saa kolmannen pimeän voiman",
"02a1": "Jak saa neljännen pimeän voiman",
"02a2": "Valitus, naiset, ja laulu",
"02a3": "Rahankerääjät",
"02a4": "Mikä tämän lapsen tarina on?",
"02a5": "Krewilla on uusi keikka",
"02a6": "Tavataan Brutter",
"02a7": "Krewin kilpailusopimus",
"02a8": "Mitä te kaksi oikein teitte?",
"02a9": "Oninin haaste",
"02aa": "Marin sinetti on valmis",
"02ab": "Pelasta lisää vaanijoita",
"02ac": "Suojele piilopaikkaa",
"02ad": "Krew uhkailee",
"02ae": "Pelaaja astelee esiin",
"02af": "Saadaan aikakartta",
"02b0": "Brutter pelastaa päivän",
"02b1": "Leijutaan pois",
"02b2": "Saadaan keltainen ase",
"02b3": "Saadaan JET-lauta",
"02b4": "Jak laittaa JET-laudan pois",
"02b5": "Ihka oma Rauhantekijämme!",
"02b6": "Ulosmeno",
"02b7": "Jak matkaa pesään",
"02b8": "Paluu",
"02b9": "Ashelin kuljettaa Jakin",
"02ba": "Pala sinettiä",
"02bb": "Erol inhoaa häviötä",
"02bc": "Torn ja ammusvarasto",
"02bd": "Metallipäitä kaupungissa?",
"02be": "Nyt räjähtää!",
"02bf": "Torn myöntää petoksensa",
"02c0": "Aikakaksoset",
"02c1": "Krewin viemärikeikka",
"02c2": "Mikä on tuo löyhkä?",
"02c3": "Taiteenkeräilijä",
"02c4": "Että kaipaankin housuja!",
"02c5": "Sig paljastaa sielunsa",
"02c6": "Patsaanposauttelua",
"02c7": "Se on ansa!",
"02c8": "Daxter saa suupalan",
"02c9": "Daxter matkustaa putkea",
"02ca": "Työtarjous",
"02cb": "Torn tarjoaa tehtävän",
"02cc": "Tavataan Ashelin",
"02cd": "Daxter tekee siirtonsa",
"02ce": "Tästä tulee hauskaa!",
"02cf": "Boom, beibi!",
"02d0": "Peukut alas",
"02d1": "Heihei",
"02d2": "Temppu",
"02d3": "Hyvää yötä",
"02d4": "Toimit hienosti, tulokas",
"02d5": "Vin tahtoo munakokkelia",
"02d6": "Kor on huolissaan",
"02d7": "Poika on kadoksissa",
"02d8": "Ohjaustorni räjähtää",
"02d9": "Tavataan Onin ja Pecker",
"02da": "Vekotin romahtaa",
"02db": "Hyvät fiilikset",
"02dc": "Daxter kärventyy",
"02dd": "Salatapaaminen",
"02de": "Paroni kohtaa Jakin",
"02df": "Minä tuhoan sinut!",
"02e0": "Takaisin mistä aloitimme",
"02e1": "Salaisuus pommin rakentamiseen",
"02e2": "Krewin kaunotar",
"02e3": "Oi voi...",
"02e4": "Lentoon",
"02e5": "Laskeutumisalusta",
"02e6": "Jak löytää Marin haudan!",
"02e7": "tomb-open-door-res",
"02e8": "tomb-open-door-2-res",
"02e9": "Haudan ovet",
"02ea": "Ensimmäinen säde",
"02eb": "Toinen säde",
"02ec": "Ovet avautuvat",
"02ed": "Edeltäjäkivi!",
"02ee": "Paroni varastaa show'n",
"02ef": "Daxter ojentaa auttavan kätensä",
"02f0": "Daxterin karvainen takaa-ajo",
"02f1": "Tavataan Varjo",
"02f2": "Daxterin pöhkötarina",
"02f3": "Pecker haastaa riitaa",
"02f4": "Samos ja siemen",
"02f5": "Näky",
"02f6": "Kor ja lapsi",
"02f7": "Pelasta lisää vaanijoita",
"02f8": "Marin haudan legenda",
"02f9": "Se on kirous, eikö vain?",
"02fa": "Pora romahtaa",
"02fb": "Valotorni nousee",
"02fc": "Sinetti avaa portin",
"02fd": "Sig on ongelmissa",
"02fe": "Juokse!",
"02ff": "Sigin vahva käsi",
"0300": "Sieltä se taas tulee!",
"0301": "Sigin viimeinen hetki",
"0302": "Kivi... ase... pesä!",
"0303": "Jak matkaa pesään",
"0304": "Poistutaan pesästä",
"0305": "Kor hyppää esiin",
"0306": "Etkö tunnista häntä?",
"0307": "Outo uusi maailma",
"0308": "Juhlinta",
"0309": "<ICON_MISSION_COMPLETE>",
"030a": "<ICON_MISSION_TODO>",
"030b": "<FLAG_UK> English",
"030c": "Ota tekstitys käyttöön painamalla <PAD_SQUARE>",
"030d": "Tekstitys käytössä",
"030e": "Tekstitys ei käytössä",
"030f": "JET-lauta",
"0310": "Jatka"
}
@@ -232,6 +232,5 @@
"1336": "Fast Progress Menu",
"1337": "PS2 LOD Distance",
"1338": "Off",
"1339": "Display",
"133a": "Suomi"
"1339": "Display"
}
@@ -5,7 +5,7 @@
"1101": "Pelataan bonustehtävää",
"1102": "Haulikon harjoitusrata",
"1103": "Läjäyttimen harjoitusrata",
"1104": "Vulkanus-tykin harjoitusrata",
"1104": "Vulkanusraivon harjoitusrata",
"1105": "Rauhantekijän harjoitusrata",
"1106": "Oninin haaste",
"1107": "Metallipää-mäiskintä",
@@ -18,8 +18,8 @@
"1206": "4x3 (PS2)",
"1207": "16x9 (PS2)",
"1208": "Valitse leveys- ja korkeussuhde",
"1209": "Vahvista ja poistu painamalla <PAD_X>.",
"120a": "Vahvista ja poistu painamalla <PAD_CIRCLE>.",
"1209": "Paina <PAD_X> vahvistaaksesi ja poistuaksesi.",
"120a": "Paina <PAD_CIRCLE> vahvistaaksesi ja poistuaksesi.",
"120b": "Kuvasuhde ei saa olla pienempi kuin 4x3!",
"120c": "Musiikkisoitin",
"120d": "Pystytahdistus",
@@ -34,7 +34,7 @@
"1216": "Muuntoase",
"1217": "JET-lauta",
"1218": "Titaaniasu",
"1219": "Raivo-Jak",
"1219": "Pimeä Jak",
"121a": "Ajoneuvo",
"121b": "Vaara",
"121c": "Ei mikään",
@@ -85,10 +85,10 @@
"124a": "Ohjaimen LED-asetukset",
"124b": "Näytä pelaajan tila",
"124c": "Näytä terveyden määrä",
"124d": "Lopeta autom. tallennus",
"124e": "Autom. tallennus pois",
"124d": "Lopeta auto-tallennus",
"124e": "Auto-tallennus pois päältä",
"124f": "Haluatko varmasti lopettaa automaattisen tallentamisen?",
"1250": "Turbo-JET-lauta Haven Cityssä",
"1250": "Turbo JET-lauta Haven Cityssä",
"1251": "Vihollisten terveyspalkit",
"1252": "Ajoneuvojen terveyspalkit",
"1253": "Ajoneuvojen haavoittumattomuus",
@@ -96,13 +96,13 @@
"1255": "Kerää kerättävät automaattisesti",
"1256": "Musiikkisoitin",
"1257": "Tekstuuriton tila",
"1258": "Nopeat välinäytökset",
"1259": "Hitaat välinäytökset",
"1258": "Nopeat välianimaatiot",
"1259": "Hitaat välianimaatiot",
"125a": "Nopea pelattavuus",
"125b": "Hidas pelattavuus",
"125c": "Pikamatkustus Haven Cityssä",
"125d": "Edeltäjähelmien seuranta",
"125e": "Todellinen vuorokaudenaika",
"125e": "Todellinen vuorokauden aika",
"125f": "Tyyni Haven City",
"1260": "Näytä JET-laudan temput",
"1261": "Huono sää",
@@ -112,14 +112,14 @@
"1265": "Käännä kaikki 3 venttiiliä ja löydä Marin patsas tehtävässä \"~S\" alle ~D sekunnissa",
"1266": "Vähennä Haven Cityn asukaslukua ~D kappaleella",
"1267": "Vähennä Haven Cityn ajoneuvojen määrää ~D kappaleella",
"1268": "Metsästä jokaista metallipää-lajia",
"1268": "Metsästä jokaista Metallipäälajia",
"1269": "Käytä JET-lautaa rikkoaksesi säiliöt auki",
"126a": "Siirrä repeämäkuljetin jättäen Samos ja nuori Samos vaurioitta",
"1280": "Kuvakulma-asetukset",
"1281": "Vasen/oikea (1. persoona)",
"1282": "Ylös/alas (1. persoona)",
"1283": "Vasen/oikea (3. persoona)",
"1284": "Ylös/alas (3. persoona)",
"1281": "Vasen/oikea (ensimmäinen persoona)",
"1282": "Ylös/alas (ensimmäinen persoona)",
"1283": "Vasen/oikea (kolmas persoona)",
"1284": "Ylös/alas (kolmas persoona)",
"1285": "Palauta oletukset",
"1286": "Normaali",
"1287": "Käänteinen",
@@ -137,15 +137,15 @@
"1293": "Ohjainasetukset",
"1294": "Valitse ohjain",
"1295": "Analogisauvan katvealue",
"1296": "Älä huomioi työpöydällä",
"1296": "Älä huomioi, kun ikkuna ei aktiivinen",
"1297": "Ohjaimen LED terveydelle",
"1298": "Ohjaimen LED muihin tiloihin",
"1299": "Salli näppäimistö",
"129a": "Salli hiiri",
"129b": "Hiiriasetukset",
"129c": "Kameran ohjaus hiirellä",
"129d": "Herkkyys (vaakasuunta)",
"129e": "Herkkyys (pystysuunta)",
"129d": "Vaakasuuntainen herkkyys",
"129e": "Pystysuuntainen herkkyys",
"129f": "Pelaajan ohjaus hiirellä",
"12a0": "Objektien varjot",
"12a1": "Normaali",
@@ -156,25 +156,25 @@
"12a6": "Muut tilastot",
"12a7": "Tappoja yhteensä",
"12a8": "Jakin tappamia",
"12a9": "Raivo-Jakin tappamia",
"12a9": "Pimeän Jakin tappamia",
"12aa": "Daxterin tappamia",
"12ab": "Muiden tappamia",
"12ac": "Läjäytin",
"12ad": "Haulikko",
"12ae": "Vulkanus-tykki",
"12ae": "Vulkanusraivo",
"12af": "Rauhantekijä",
"12b0": "JET-lauta",
"12b1": "JET-lauta-temppu",
"12b1": "JET-lautatemppu",
"12b2": "Titaaniasun isku",
"12b3": "Titaaniasun runko",
"12b4": "Tykki",
"12b5": "Isku",
"12b6": "Maaisku",
"12b6": "Lyyhistyi",
"12b7": "Kohokoukku",
"12b8": "Pyörähdys",
"12b9": "Kierintä",
"12bf": "Raivopommi",
"12c0": "Raivopurkaus",
"12bf": "Pimeä pommi",
"12c0": "Pimeä purkaus",
"12c3": "Karmiinivartija",
"12c4": "Sig",
"12c5": "Ashelin",
@@ -208,24 +208,24 @@
"1315": "Tämä asetus on erittäin kokeellinen. Kun peliä ei pelata 60 Hz:n kuvataajuudella, visuaalisia sekä pelattavuuden ongelmia voi ilmaantua sen seurauksena.",
"1316": "Paikallinen tulos",
"1320": "Ei mitään",
"1321": "Pyörähdys",
"1322": "Nopeuslisä",
"1321": "Spin",
"1322": "Buusti",
"1323": "Voltti",
"1324": "Kaideliuku",
"1325": "Kaidehyppy",
"1326": "Nosegrab",
"1327": "Method",
"1328": "Lautapyörähdys",
"1329": "Lautavoltti",
"1328": "Board Spin",
"1329": "Board Flip",
"132a": "Noseflip",
"132b": "Kickflip",
"132c": "Hyppy",
"132d": "Kyykkyhyppy",
"132e": "Pikahyppy",
"132f": "Raivo-Jak",
"1330": "Raivopommi",
"1331": "Raivopurkaus",
"1332": "Raivojätti",
"132f": "Pimeä Jak",
"1330": "Pimeä pommi",
"1331": "Pimeä purkaus",
"1332": "Pimeä jätti",
"1333": "PS2-asetukset",
"1334": "Objektien vähennys",
"1335": "Pakota ympäristökartoitus",
+4 -9
View File
@@ -484,7 +484,7 @@
03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000011a7000000000000,PowerA Core Plus GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -873,7 +873,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:MacOSX
03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X,
030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
@@ -1081,7 +1080,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b10,start:b7,leftstick:b8,rightstick:b9,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X,
030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -1091,7 +1090,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -1390,7 +1388,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b000001050000,Microsoft Xbox Series X Controller,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Linux,
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@@ -1468,7 +1465,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000011a7000011010000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1690,7 +1687,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050082795e040000e002000003090000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1698,8 +1694,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000015050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+16
View File
@@ -31,3 +31,19 @@ struct RPC_Dgo_Cmd {
// a buffer.
uint8_t pad[32];
};
namespace jak3 {
struct RPC_Dgo_Cmd {
uint16_t rsvd;
uint16_t result;
uint32_t buffer1;
uint32_t buffer2;
uint32_t buffer_heap_top;
char name[16];
uint16_t cgo_id;
uint8_t pad[30];
};
static_assert(sizeof(RPC_Dgo_Cmd) == 0x40);
} // namespace jak3
static_assert(sizeof(RPC_Dgo_Cmd) == sizeof(jak3::RPC_Dgo_Cmd));
@@ -3,10 +3,6 @@
#include "fmt/core.h"
#include "third-party/imgui/imgui.h"
std::string BucketRenderer::name() const {
return m_name;
}
std::string BucketRenderer::name_and_id() const {
return fmt::format("[{:2d}] {}", (int)m_my_id, m_name);
}
@@ -26,8 +26,8 @@ class EyeRenderer;
struct SharedRenderState {
explicit SharedRenderState(std::shared_ptr<TexturePool> _texture_pool,
std::shared_ptr<Loader> _loader,
GameVersion _version)
: shaders(_version), texture_pool(_texture_pool), loader(_loader), version(_version) {}
GameVersion version)
: shaders(version), texture_pool(_texture_pool), loader(_loader) {}
ShaderLibrary shaders;
std::shared_ptr<TexturePool> texture_pool;
std::shared_ptr<Loader> loader;
@@ -98,7 +98,6 @@ class BucketRenderer {
virtual void render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) = 0;
std::string name() const;
std::string name_and_id() const;
virtual ~BucketRenderer() = default;
bool& enabled() { return m_enabled; }
@@ -159,4 +158,4 @@ class PrintRenderer : public BucketRenderer {
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
bool empty() const override { return true; }
void draw_debug_window() override {}
};
};
@@ -579,7 +579,6 @@ u32 get_direct_qwc_or_nop(const VifCode& code) {
return code.immediate;
}
default:
printf("expected direct, got %s\n", code.print().c_str());
ASSERT(false);
}
}
+7 -27
View File
@@ -186,7 +186,7 @@ EyeRenderer::SpriteInfo decode_sprite(const DmaTransfer& dma) {
memcpy(&result.a, dma.data + 16 + 12, 1); // a
// uv0
memcpy(&result.uv0, &dma.data[32], 8);
memcpy(&result.uv0[0], &dma.data[32], 8);
// xyz0
memcpy(&result.xyz0[0], &dma.data[48], 12);
@@ -236,11 +236,8 @@ std::vector<EyeRenderer::SingleEyeDraws> EyeRenderer::get_draws(DmaFollower& dma
bool using_64 = false;
{
auto draw0 = read_eye_draw(dma);
// ASSERT(draw0.sprite.uv0[0] == 0);
// ASSERT(draw0.sprite.uv0[1] == 0);
// printf("hashed name is 0x%x 0x%x\n", draw0.sprite.uv0[0], draw0.sprite.uv0[1]);
l_draw.fnv_name_hash = draw0.sprite.uv0;
r_draw.fnv_name_hash = draw0.sprite.uv0;
ASSERT(draw0.sprite.uv0[0] == 0);
ASSERT(draw0.sprite.uv0[1] == 0);
ASSERT(draw0.sprite.uv1[0] == 0);
ASSERT(draw0.sprite.uv1[1] == 0);
if (draw0.scissor.y1 - draw0.scissor.y0 == 63) {
@@ -512,9 +509,7 @@ void EyeRenderer::run_gpu(const std::vector<SingleEyeDraws>& draws,
buffer_idx = 0;
for (size_t draw_idx = 0; draw_idx < draws.size(); draw_idx++) {
const auto& draw = draws[draw_idx];
auto& out_tex = m_gpu_eye_textures[draw.tex_slot()];
out_tex.fnv_name_hash = draw.fnv_name_hash;
out_tex.lr = draw.lr;
const auto& out_tex = m_gpu_eye_textures[draw.tex_slot()];
// first, the clear
float clear[4] = {0, 0, 0, 0};
@@ -579,30 +574,15 @@ std::optional<u64> EyeRenderer::lookup_eye_texture(u8 eye_id) {
}
}
std::optional<u64> EyeRenderer::lookup_eye_texture_hash(u64 hash, bool lr) {
for (auto& slot : m_gpu_eye_textures) {
if (slot.fnv_name_hash == hash && slot.lr == lr) {
auto* gpu_tex = slot.gpu_tex;
if (gpu_tex) {
return gpu_tex->gpu_textures.at(0).gl;
} else {
fmt::print("lookup eye failed for {} (1)\n", hash);
return {};
}
}
}
fmt::print("lookup eye failed for {} (2)\n", hash);
return {};
}
//////////////////////
// DMA Decode
//////////////////////
std::string EyeRenderer::SpriteInfo::print() const {
std::string result;
result += fmt::format("a: {:x} uv: ({}), ({}, {}) xyz: ({}, {}, {}), ({}, {}, {})", a, uv0,
uv1[0], uv1[1], xyz0[0], xyz0[1], xyz0[2], xyz1[0], xyz1[1], xyz1[2]);
result +=
fmt::format("a: {:x} uv: ({}, {}), ({}, {}) xyz: ({}, {}, {}), ({}, {}, {})", a, uv0[0],
uv0[1], uv1[0], uv1[1], xyz0[0], xyz0[1], xyz0[2], xyz1[0], xyz1[1], xyz1[2]);
return result;
}
+1 -5
View File
@@ -22,11 +22,10 @@ class EyeRenderer : public BucketRenderer {
void handle_eye_dma2(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
std::optional<u64> lookup_eye_texture(u8 eye_id);
std::optional<u64> lookup_eye_texture_hash(u64 hash, bool lr);
struct SpriteInfo {
u8 a;
u64 uv0; // stores hashed name of merc-ctrl that reads this eye.
u32 uv0[2];
u32 uv1[2];
u32 xyz0[3];
u32 xyz1[3];
@@ -54,8 +53,6 @@ class EyeRenderer : public BucketRenderer {
GpuTexture* gpu_tex = nullptr;
u32 tbp;
FramebufferTexturePair fb;
u64 fnv_name_hash = 0;
bool lr = false;
// note: eye texture increased to 128x128 (originally 32x32) here.
GpuEyeTex() : fb(128, 128, GL_UNSIGNED_INT_8_8_8_8_REV) {}
@@ -68,7 +65,6 @@ class EyeRenderer : public BucketRenderer {
GLuint m_gl_vertex_buffer;
struct SingleEyeDraws {
u64 fnv_name_hash = 0;
int lr;
int pair;
bool using_64 = false;
@@ -28,7 +28,6 @@
#include "game/graphics/pipelines/opengl.h"
#include "third-party/imgui/imgui.h"
#include "third-party/imgui/imgui_stdlib.h"
// for the vif callback
#include "game/kernel/common/kmachine.h"
@@ -37,7 +36,6 @@
#ifdef _WIN32
#include <Windows.h>
#endif
#include "common/util/string_util.h"
namespace {
std::string g_current_renderer;
@@ -86,11 +84,7 @@ OpenGLRenderer::OpenGLRenderer(std::shared_ptr<TexturePool> texture_pool,
&gl_error_ignores_api_other[0], GL_FALSE);
#endif
lg::info("OpenGL context version: {}", (const char*)glGetString(GL_VERSION));
lg::info("OpenGL context renderer: {}", (const char*)glGetString(GL_RENDERER));
lg::info("OpenGL context vendor: {}", (const char*)glGetString(GL_VENDOR));
lg::info("OpenGL context shading language version: {}",
(const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
lg::debug("OpenGL context information: {}", (const char*)glGetString(GL_VERSION));
const tfrag3::Level* common_level = nullptr;
{
@@ -269,11 +263,6 @@ void OpenGLRenderer::init_bucket_renderers_jak3() {
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_PRIS, BucketId::GMERC_L1_PRIS, i), m_generic2,
Generic2::Mode::NORMAL);
init_bucket_renderer<Generic2BucketRenderer>(
fmt::format("gmerc2-l{}-pris", i), BucketCategory::GENERIC,
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC2_L0_PRIS, BucketId::GMERC2_L1_PRIS, i), m_generic2,
Generic2::Mode::PRIM);
init_bucket_renderer<Merc2BucketRenderer>(
fmt::format("merc-l{}-pris2", i), BucketCategory::MERC,
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_PRIS2, BucketId::MERC_L1_PRIS2, i), m_merc2);
@@ -281,10 +270,6 @@ void OpenGLRenderer::init_bucket_renderers_jak3() {
fmt::format("gmerc-l{}-pris2", i), BucketCategory::GENERIC,
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC_L0_PRIS2, BucketId::GMERC_L1_PRIS2, i), m_generic2,
Generic2::Mode::NORMAL);
init_bucket_renderer<Generic2BucketRenderer>(
fmt::format("gmerc2-l{}-pris2", i), BucketCategory::GENERIC,
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC2_L0_PRIS2, BucketId::GMERC2_L1_PRIS2, i),
m_generic2, Generic2::Mode::PRIM);
}
// 401
@@ -296,10 +281,6 @@ void OpenGLRenderer::init_bucket_renderers_jak3() {
BucketId::GMERC_LCOM_PRIS, m_generic2,
Generic2::Mode::NORMAL);
init_bucket_renderer<Generic2BucketRenderer>("gmerc2-lcom-pris", BucketCategory::GENERIC,
BucketId::GMERC2_LCOM_PRIS, m_generic2,
Generic2::Mode::PRIM);
// 461
init_bucket_renderer<TextureUploadHandler>("tex-lcom-sky-post", BucketCategory::TEX,
BucketId::TEX_LCOM_SKY_POST, m_texture_animator);
@@ -325,10 +306,6 @@ void OpenGLRenderer::init_bucket_renderers_jak3() {
fmt::format("tfrag-l{}-water", i), BucketCategory::TFRAG,
GET_BUCKET_ID_FOR_LIST(BucketId::TFRAG_L0_WATER, BucketId::TFRAG_L1_WATER, i),
std::vector{tfrag3::TFragmentTreeKind::WATER}, false, i, anim_slot_array());
init_bucket_renderer<Generic2BucketRenderer>(
fmt::format("gmerc2-l{}-water", i), BucketCategory::GENERIC,
GET_BUCKET_ID_FOR_LIST(BucketId::GMERC2_L0_WATER, BucketId::GMERC2_L1_WATER, i),
m_generic2, Generic2::Mode::PRIM);
}
// 563
@@ -336,20 +313,11 @@ void OpenGLRenderer::init_bucket_renderers_jak3() {
BucketId::TEX_LCOM_WATER, m_texture_animator);
init_bucket_renderer<Merc2BucketRenderer>("merc-lcom-water", BucketCategory::MERC,
BucketId::MERC_LCOM_WATER, m_merc2);
init_bucket_renderer<Generic2BucketRenderer>("generic2-lcom-water", BucketCategory::GENERIC,
BucketId::GMERC2_LCOM_WATER, m_generic2,
Generic2::Mode::PRIM);
// 568
init_bucket_renderer<TextureUploadHandler>("tex-sprite", BucketCategory::TEX,
BucketId::TEX_SPRITE, m_texture_animator);
init_bucket_renderer<Generic2BucketRenderer>("generic-sprite-1", BucketCategory::GENERIC,
BucketId::GENERIC_SPRITE_1, m_generic2,
Generic2::Mode::PRIM);
init_bucket_renderer<Sprite3>("particles", BucketCategory::SPRITE, BucketId::PARTICLES);
init_bucket_renderer<Generic2BucketRenderer>("generic-sprite-2", BucketCategory::GENERIC,
BucketId::GENERIC_SPRITE_2, m_generic2,
Generic2::Mode::PRIM);
init_bucket_renderer<Generic2BucketRenderer>("generic-sprite-3", BucketCategory::OTHER,
BucketId::GENERIC_SPRITE_3, m_generic2,
Generic2::Mode::LIGHTNING);
@@ -1110,13 +1078,8 @@ void OpenGLRenderer::draw_renderer_selection_window() {
ImGui::TreePop();
}
ImGui::InputText("Renderer Filter", &m_renderer_filter);
for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
auto renderer = m_bucket_renderers[i].get();
if (!m_renderer_filter.empty() && !str_util::contains(renderer->name(), m_renderer_filter)) {
continue;
}
if (renderer && !renderer->empty()) {
ImGui::PushID(i);
if (ImGui::TreeNode(renderer->name_and_id().c_str())) {
@@ -123,7 +123,6 @@ class OpenGLRenderer {
float m_last_pmode_alp = 1.;
bool m_enable_fast_blackout_loads = true;
std::string m_renderer_filter = "";
struct FboState {
struct {
+126 -612
View File
@@ -60,48 +60,23 @@
* A simple list of preallocated textures by size. If a texture needs to be resized, it's faster
* to swap to a different OpenGL texture from this pool than glTexImage2D with a different size.
*/
OpenGLTexturePool::OpenGLTexturePool(GameVersion version) {
OpenGLTexturePool::OpenGLTexturePool() {
struct Alloc {
u64 w, h, n;
};
// list of sizes to preallocate: {width, height, count}.
PerGameVersion<std::vector<Alloc>> tex_allocs{{{4, 4, 2},
{4, 64, 2},
{16, 16, 5},
{32, 16, 1},
{32, 32, 10},
{32, 64, 1},
{64, 32, 6},
{64, 64, 30},
{64, 128, 4},
{128, 128, 10},
{256, 1, 2},
{256, 256, 7}},
{{4, 4, 2},
{4, 64, 2},
{16, 16, 5},
{32, 16, 1},
{32, 32, 10},
{32, 64, 1},
{64, 32, 6},
{64, 64, 30},
{64, 128, 4},
{128, 128, 10},
{256, 1, 2},
{256, 256, 7}},
{{4, 4, 3},
{4, 64, 6},
{16, 16, 5},
{32, 16, 1},
{32, 32, 20},
{32, 64, 1},
{64, 32, 15},
{64, 64, 85},
{64, 128, 4},
{128, 128, 185},
{256, 1, 2},
{256, 256, 7}}};
for (const auto& a : tex_allocs[version]) {
for (const auto& a : std::vector<Alloc>{{4, 4, 2},
{4, 64, 2},
{16, 16, 5},
{32, 16, 1},
{32, 32, 10},
{32, 64, 1},
{64, 32, 6},
{64, 64, 30},
{64, 128, 4},
{128, 128, 10},
{256, 1, 2},
{256, 256, 7}}) {
auto& l = textures[(a.w << 32) | a.h];
l.resize(a.n);
glGenTextures(a.n, l.data());
@@ -395,7 +370,6 @@ TextureAnimator::TextureAnimator(ShaderLibrary& shaders,
const tfrag3::Level* common_level,
GameVersion version)
: m_common_level(common_level),
m_opengl_texture_pool(version),
m_psm32_to_psm8_8_8(8, 8, 8, 64),
m_psm32_to_psm8_16_16(16, 16, 16, 64),
m_psm32_to_psm8_32_32(32, 32, 16, 64),
@@ -446,7 +420,6 @@ TextureAnimator::TextureAnimator(ShaderLibrary& shaders,
m_shader_id = shader.id();
m_uniforms.rgba = glGetUniformLocation(shader.id(), "rgba");
m_uniforms.enable_tex = glGetUniformLocation(shader.id(), "enable_tex");
m_uniforms.set_alpha = glGetUniformLocation(shader.id(), "set_alpha");
m_uniforms.positions = glGetUniformLocation(shader.id(), "positions");
m_uniforms.uvs = glGetUniformLocation(shader.id(), "uvs");
m_uniforms.channel_scramble = glGetUniformLocation(shader.id(), "channel_scramble");
@@ -669,7 +642,7 @@ GLuint TextureAnimator::get_by_slot(int idx) {
}
// IDs sent from GOAL telling us what texture operation to perform.
enum class PcTextureAnimCodesJak2 : u16 {
enum PcTextureAnimCodes {
FINISH_ARRAY = 13,
ERASE_DEST_TEXTURE = 14,
UPLOAD_CLUT_16_16 = 15,
@@ -700,361 +673,6 @@ enum class PcTextureAnimCodesJak2 : u16 {
CLOUDS_HIRES = 43,
};
struct FixedAnimInfoJak2 {
PcTextureAnimCodesJak2 code = (PcTextureAnimCodesJak2)0;
std::string name;
int anim_array_idx = -1;
};
FixedAnimInfoJak2 anim_code_to_info(PcTextureAnimCodesJak2 code, const TextureAnimator& animator) {
ASSERT(code > (PcTextureAnimCodesJak2)0);
FixedAnimInfoJak2 anim;
anim.code = code;
switch (code) {
case PcTextureAnimCodesJak2::SKULL_GEM: {
anim.name = "skull-gem";
anim.anim_array_idx = animator.m_skull_gem_fixed_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::BOMB: {
anim.name = "bomb";
anim.anim_array_idx = animator.m_bomb_fixed_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::CAS_CONVEYOR: {
anim.name = "cas-conveyor";
anim.anim_array_idx = animator.m_cas_conveyor_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::SECURITY: {
anim.name = "security";
anim.anim_array_idx = animator.m_security_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::WATERFALL: {
anim.name = "waterfall";
anim.anim_array_idx = animator.m_waterfall_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::WATERFALL_B: {
anim.name = "waterfall-b";
anim.anim_array_idx = animator.m_waterfall_b_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::LAVA: {
anim.name = "lava";
anim.anim_array_idx = animator.m_lava_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::LAVA_B: {
anim.name = "lava-b";
anim.anim_array_idx = animator.m_lava_b_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::STADIUMB: {
anim.name = "stadiumb";
anim.anim_array_idx = animator.m_stadiumb_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::FORTRESS_PRIS: {
anim.name = "fort-pris";
anim.anim_array_idx = animator.m_fortress_pris_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::FORTRESS_WARP: {
anim.name = "fort-warp";
anim.anim_array_idx = animator.m_fortress_warp_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::METKOR: {
anim.name = "metkor";
anim.anim_array_idx = animator.m_metkor_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::SHIELD: {
anim.name = "shield";
anim.anim_array_idx = animator.m_shield_anim_array_idx;
} break;
case PcTextureAnimCodesJak2::KREW_HOLO: {
anim.name = "krew-holo";
anim.anim_array_idx = animator.m_krew_holo_anim_array_idx;
} break;
default:
anim.name = "unknown";
lg::error("Unknown texture anim code {}", (int)code);
}
return anim;
}
enum class PcTextureAnimCodesJak3 : u16 {
FINISH_ARRAY = 13,
ERASE_DEST_TEXTURE = 14,
UPLOAD_CLUT_16_16 = 15,
GENERIC_UPLOAD = 16,
SET_SHADER = 17,
DRAW = 18,
DARKJAK = 22,
DARKJAK_HIGHRES = 23,
SKULL_GEM = 27,
DEFAULT_WATER = 28,
DEFAULT_WARP = 29,
TEMPLEA_WATER = 30,
TEMPLEA_WARP = 31,
TEMPLEB_WARP = 32,
TEMPLEC_WATER = 33,
SEWC_WATER = 34,
SEWD_WATER = 35,
SEWE_WATER = 36,
SEWG_WATER = 37,
SEWH_WATER = 38,
SEWI_WATER = 39,
SEWJ_WATER = 40,
SEWL_WATER = 41,
SEWM_WATER = 42,
SEWN_WATER = 43,
DESRESC_WARP = 44,
CTYSLUMB_WATER = 45,
NSTB_QUICKSAND = 46,
CTYSLUMC_WATER = 47,
FACTORYC_ALPHA = 48,
HFRAG = 49,
HANGA_SPRITE = 50,
HANGA_WATER = 51,
DESERTD_WATER = 52,
LMHCITYB_TFRAG = 53,
TOWERB_WATER = 54,
COMB_FIELD = 55,
WASSTADA_ALPHA = 56,
FACTORYB_WATER = 57,
LMHCITYA_TFRAG = 58,
MHCITYA_PRIS = 59,
RUBBLEA_WATER = 60,
RUBBLEA2_WATER = 61,
RUBBLEB_WATER = 62,
RUBBLEC_WATER = 63,
FORESTA_WATER = 64,
FORESTB_WATER = 65,
LFORPLNT_PRIS = 66,
LTNFXHIP = 67,
LGUNNORM_WATER = 68,
LJKDXVIN = 69,
SECURITY = 70,
WASPAL_WATER = 71,
MINED_TFRAG = 72,
VOLCANOX_WARP = 73,
TEMPLEX_WATER = 74,
VOLCANOA_WATER = 75,
DESHOVER = 76,
CLOUDS_AND_FOG = 77,
CLOUDS_HIRES = 78,
};
struct FixedAnimInfoJak3 {
PcTextureAnimCodesJak3 code = (PcTextureAnimCodesJak3)0;
std::string name;
int anim_array_idx = -1;
};
FixedAnimInfoJak3 anim_code_to_info(PcTextureAnimCodesJak3 code, const TextureAnimator& animator) {
ASSERT(code > (PcTextureAnimCodesJak3)0);
FixedAnimInfoJak3 anim;
anim.code = code;
switch (code) {
case PcTextureAnimCodesJak3::SKULL_GEM: {
anim.name = "skull-gem";
anim.anim_array_idx = animator.m_skull_gem_fixed_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::DEFAULT_WATER: {
anim.name = "default-water";
anim.anim_array_idx = animator.m_default_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::DEFAULT_WARP: {
anim.name = "default-warp";
anim.anim_array_idx = animator.m_default_warp_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::TEMPLEA_WATER: {
anim.name = "templea-water";
anim.anim_array_idx = animator.m_templea_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::TEMPLEA_WARP: {
anim.name = "templea-warp";
anim.anim_array_idx = animator.m_templea_warp_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::TEMPLEB_WARP: {
anim.name = "templeb-warp";
anim.anim_array_idx = animator.m_templeb_warp_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::TEMPLEC_WATER: {
anim.name = "templec-water";
anim.anim_array_idx = animator.m_templec_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWC_WATER: {
anim.name = "sewc-water";
anim.anim_array_idx = animator.m_sewc_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWD_WATER: {
anim.name = "sewd-water";
anim.anim_array_idx = animator.m_sewd_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWE_WATER: {
anim.name = "sewe-water";
anim.anim_array_idx = animator.m_sewe_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWG_WATER: {
anim.name = "sewg-water";
anim.anim_array_idx = animator.m_sewg_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWH_WATER: {
anim.name = "sewh-water";
anim.anim_array_idx = animator.m_sewh_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWI_WATER: {
anim.name = "sewi-water";
anim.anim_array_idx = animator.m_sewi_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWJ_WATER: {
anim.name = "sewj-water";
anim.anim_array_idx = animator.m_sewj_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWL_WATER: {
anim.name = "sewl-water";
anim.anim_array_idx = animator.m_sewl_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWM_WATER: {
anim.name = "sewm-water";
anim.anim_array_idx = animator.m_sewm_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SEWN_WATER: {
anim.name = "sewn-water";
anim.anim_array_idx = animator.m_sewn_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::DESRESC_WARP: {
anim.name = "desresc-warp";
anim.anim_array_idx = animator.m_desresc_warp_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::CTYSLUMB_WATER: {
anim.name = "ctyslumb-water";
anim.anim_array_idx = animator.m_ctyslumb_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::NSTB_QUICKSAND: {
anim.name = "nstb-quicksand";
anim.anim_array_idx = animator.m_nstb_quicksand_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::CTYSLUMC_WATER: {
anim.name = "ctyslumc-water";
anim.anim_array_idx = animator.m_ctyslumc_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::FACTORYC_ALPHA: {
anim.name = "factoryc-alpha";
anim.anim_array_idx = animator.m_factoryc_alpha_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::HFRAG: {
anim.name = "hfrag";
anim.anim_array_idx = animator.m_hfrag_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::HANGA_SPRITE: {
anim.name = "hanga-sprite";
anim.anim_array_idx = animator.m_hanga_sprite_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::HANGA_WATER: {
anim.name = "hanga-water";
anim.anim_array_idx = animator.m_hanga_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::DESERTD_WATER: {
anim.name = "desertd-water";
anim.anim_array_idx = animator.m_desertd_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::LMHCITYB_TFRAG: {
anim.name = "lmhcityb-tfrag";
anim.anim_array_idx = animator.m_lmhcityb_tfrag_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::TOWERB_WATER: {
anim.name = "towerb-water";
anim.anim_array_idx = animator.m_towerb_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::COMB_FIELD: {
anim.name = "comb-field";
anim.anim_array_idx = animator.m_comb_field_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::WASSTADA_ALPHA: {
anim.name = "wasstada-alpha";
anim.anim_array_idx = animator.m_wasstada_alpha_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::FACTORYB_WATER: {
anim.name = "factoryb-water";
anim.anim_array_idx = animator.m_factoryb_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::LMHCITYA_TFRAG: {
anim.name = "lmhcitya-tfrag";
anim.anim_array_idx = animator.m_lmhcitya_tfrag_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::MHCITYA_PRIS: {
anim.name = "mhcitya-pris";
anim.anim_array_idx = animator.m_mhcitya_pris_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::RUBBLEA_WATER: {
anim.name = "rubblea-water";
anim.anim_array_idx = animator.m_rubblea_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::RUBBLEA2_WATER: {
anim.name = "rubblea2-water";
anim.anim_array_idx = animator.m_rubblea2_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::RUBBLEB_WATER: {
anim.name = "rubbleb-water";
anim.anim_array_idx = animator.m_rubbleb_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::RUBBLEC_WATER: {
anim.name = "rubblec-water";
anim.anim_array_idx = animator.m_rubblec_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::FORESTA_WATER: {
anim.name = "foresta-water";
anim.anim_array_idx = animator.m_foresta_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::FORESTB_WATER: {
anim.name = "forestb-water";
anim.anim_array_idx = animator.m_forestb_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::LFORPLNT_PRIS: {
anim.name = "lforplnt-pris";
anim.anim_array_idx = animator.m_lforplnt_pris_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::LTNFXHIP: {
anim.name = "ltnfxhip";
anim.anim_array_idx = animator.m_ltnfxhip_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::LGUNNORM_WATER: {
anim.name = "lgunnorm-water";
anim.anim_array_idx = animator.m_lgunnorm_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::LJKDXVIN: {
anim.name = "ljkdxvin";
anim.anim_array_idx = animator.m_ljkdxvin_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::SECURITY: {
anim.name = "security";
anim.anim_array_idx = animator.m_security_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::WASPAL_WATER: {
anim.name = "waspal-water";
anim.anim_array_idx = animator.m_waspal_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::MINED_TFRAG: {
anim.name = "mined-tfrag";
anim.anim_array_idx = animator.m_mined_tfrag_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::VOLCANOX_WARP: {
anim.name = "volcanox-warp";
anim.anim_array_idx = animator.m_volcanox_warp_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::TEMPLEX_WATER: {
anim.name = "templex-water";
anim.anim_array_idx = animator.m_templex_water_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::VOLCANOA_WATER: {
anim.name = "volcanoa-water";
anim.anim_array_idx = animator.m_volcanoa_anim_array_idx;
} break;
case PcTextureAnimCodesJak3::DESHOVER: {
anim.name = "deshover";
anim.anim_array_idx = animator.m_deshover_anim_array_idx;
} break;
default:
anim.name = "unknown";
lg::error("Unknown texture anim code {}", (int)code);
}
return anim;
}
// metadata for an upload from GOAL memory
struct TextureAnimPcUpload {
u32 data; // goal pointer
@@ -1108,191 +726,117 @@ void TextureAnimator::handle_texture_anim_data(DmaFollower& dma,
auto tf = dma.read_and_advance();
auto vif0 = tf.vifcode0();
if (vif0.kind == VifCode::Kind::PC_PORT) {
switch (this->m_version) {
case GameVersion::Jak2:
switch (static_cast<PcTextureAnimCodesJak2>(vif0.immediate)) {
case PcTextureAnimCodesJak2::UPLOAD_CLUT_16_16: {
auto p = scoped_prof("clut-16-16");
handle_upload_clut_16_16(tf, ee_mem);
} break;
case PcTextureAnimCodesJak2::ERASE_DEST_TEXTURE: {
auto p = scoped_prof("erase");
handle_erase_dest(dma);
} break;
case PcTextureAnimCodesJak2::GENERIC_UPLOAD: {
auto p = scoped_prof("generic-upload");
handle_generic_upload(tf, ee_mem);
} break;
case PcTextureAnimCodesJak2::SET_SHADER: {
auto p = scoped_prof("set-shader");
handle_set_shader(dma);
} break;
case PcTextureAnimCodesJak2::DRAW: {
auto p = scoped_prof("draw");
handle_draw(dma, *texture_pool);
} break;
case PcTextureAnimCodesJak2::FINISH_ARRAY:
done = true;
break;
case PcTextureAnimCodesJak2::DARKJAK: {
auto p = scoped_prof("darkjak");
run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx);
} break;
case PcTextureAnimCodesJak2::PRISON_JAK: {
auto p = scoped_prof("prisonjak");
run_clut_blender_group(tf, m_jakb_prison_clut_blender_idx, frame_idx);
} break;
case PcTextureAnimCodesJak2::ORACLE_JAK: {
auto p = scoped_prof("oraclejak");
run_clut_blender_group(tf, m_jakb_oracle_clut_blender_idx, frame_idx);
} break;
case PcTextureAnimCodesJak2::NEST_JAK: {
auto p = scoped_prof("nestjak");
run_clut_blender_group(tf, m_jakb_nest_clut_blender_idx, frame_idx);
} break;
case PcTextureAnimCodesJak2::KOR_TRANSFORM: {
auto p = scoped_prof("kor");
run_clut_blender_group(tf, m_kor_transform_clut_blender_idx, frame_idx);
} break;
case PcTextureAnimCodesJak2::SKULL_GEM:
case PcTextureAnimCodesJak2::BOMB:
case PcTextureAnimCodesJak2::CAS_CONVEYOR:
case PcTextureAnimCodesJak2::SECURITY:
case PcTextureAnimCodesJak2::WATERFALL:
case PcTextureAnimCodesJak2::WATERFALL_B:
case PcTextureAnimCodesJak2::LAVA:
case PcTextureAnimCodesJak2::LAVA_B:
case PcTextureAnimCodesJak2::STADIUMB:
case PcTextureAnimCodesJak2::FORTRESS_PRIS:
case PcTextureAnimCodesJak2::FORTRESS_WARP:
case PcTextureAnimCodesJak2::METKOR:
case PcTextureAnimCodesJak2::SHIELD:
case PcTextureAnimCodesJak2::KREW_HOLO: {
auto anim =
anim_code_to_info(static_cast<PcTextureAnimCodesJak2>(vif0.immediate), *this);
auto p = scoped_prof(anim.name.c_str());
run_fixed_animation_array(anim.anim_array_idx, tf, texture_pool);
break;
}
case PcTextureAnimCodesJak2::CLOUDS_AND_FOG:
case PcTextureAnimCodesJak2::CLOUDS_HIRES: {
auto p = scoped_prof("clouds-and-fog");
handle_clouds_and_fog(tf, texture_pool,
vif0.immediate == (u16)PcTextureAnimCodesJak2::CLOUDS_HIRES);
} break;
case PcTextureAnimCodesJak2::SLIME: {
auto p = scoped_prof("slime");
handle_slime(tf, texture_pool);
break;
}
default:
lg::print("bad imm: {}\n", vif0.immediate);
ASSERT_NOT_REACHED();
}
break;
case GameVersion::Jak3:
switch (static_cast<PcTextureAnimCodesJak3>(vif0.immediate)) {
case PcTextureAnimCodesJak3::UPLOAD_CLUT_16_16: {
auto p = scoped_prof("clut-16-16");
handle_upload_clut_16_16(tf, ee_mem);
} break;
case PcTextureAnimCodesJak3::ERASE_DEST_TEXTURE: {
auto p = scoped_prof("erase");
handle_erase_dest(dma);
} break;
case PcTextureAnimCodesJak3::GENERIC_UPLOAD: {
auto p = scoped_prof("generic-upload");
handle_generic_upload(tf, ee_mem);
} break;
case PcTextureAnimCodesJak3::SET_SHADER: {
auto p = scoped_prof("set-shader");
handle_set_shader(dma);
} break;
case PcTextureAnimCodesJak3::DRAW: {
auto p = scoped_prof("draw");
handle_draw(dma, *texture_pool);
} break;
case PcTextureAnimCodesJak3::FINISH_ARRAY:
done = true;
break;
case PcTextureAnimCodesJak3::DARKJAK: {
auto p = scoped_prof("darkjak");
run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx);
} break;
case PcTextureAnimCodesJak3::DARKJAK_HIGHRES: {
auto p = scoped_prof("darkjak-highres");
run_clut_blender_group(tf, m_darkjak_highres_clut_blender_idx, frame_idx);
} break;
case PcTextureAnimCodesJak3::SKULL_GEM:
case PcTextureAnimCodesJak3::DEFAULT_WATER:
case PcTextureAnimCodesJak3::DEFAULT_WARP:
case PcTextureAnimCodesJak3::TEMPLEA_WATER:
case PcTextureAnimCodesJak3::TEMPLEA_WARP:
case PcTextureAnimCodesJak3::TEMPLEB_WARP:
case PcTextureAnimCodesJak3::TEMPLEC_WATER:
case PcTextureAnimCodesJak3::SEWC_WATER:
case PcTextureAnimCodesJak3::SEWD_WATER:
case PcTextureAnimCodesJak3::SEWE_WATER:
case PcTextureAnimCodesJak3::SEWG_WATER:
case PcTextureAnimCodesJak3::SEWH_WATER:
case PcTextureAnimCodesJak3::SEWI_WATER:
case PcTextureAnimCodesJak3::SEWJ_WATER:
case PcTextureAnimCodesJak3::SEWL_WATER:
case PcTextureAnimCodesJak3::SEWM_WATER:
case PcTextureAnimCodesJak3::SEWN_WATER:
case PcTextureAnimCodesJak3::DESRESC_WARP:
case PcTextureAnimCodesJak3::CTYSLUMB_WATER:
case PcTextureAnimCodesJak3::NSTB_QUICKSAND:
case PcTextureAnimCodesJak3::CTYSLUMC_WATER:
case PcTextureAnimCodesJak3::FACTORYC_ALPHA:
case PcTextureAnimCodesJak3::HFRAG:
case PcTextureAnimCodesJak3::HANGA_SPRITE:
case PcTextureAnimCodesJak3::HANGA_WATER:
case PcTextureAnimCodesJak3::DESERTD_WATER:
case PcTextureAnimCodesJak3::LMHCITYB_TFRAG:
case PcTextureAnimCodesJak3::TOWERB_WATER:
case PcTextureAnimCodesJak3::COMB_FIELD:
case PcTextureAnimCodesJak3::WASSTADA_ALPHA:
case PcTextureAnimCodesJak3::FACTORYB_WATER:
case PcTextureAnimCodesJak3::LMHCITYA_TFRAG:
case PcTextureAnimCodesJak3::MHCITYA_PRIS:
case PcTextureAnimCodesJak3::RUBBLEA_WATER:
case PcTextureAnimCodesJak3::RUBBLEA2_WATER:
case PcTextureAnimCodesJak3::RUBBLEB_WATER:
case PcTextureAnimCodesJak3::RUBBLEC_WATER:
case PcTextureAnimCodesJak3::FORESTA_WATER:
case PcTextureAnimCodesJak3::FORESTB_WATER:
case PcTextureAnimCodesJak3::LFORPLNT_PRIS:
case PcTextureAnimCodesJak3::LTNFXHIP:
case PcTextureAnimCodesJak3::LGUNNORM_WATER:
case PcTextureAnimCodesJak3::LJKDXVIN:
case PcTextureAnimCodesJak3::SECURITY:
case PcTextureAnimCodesJak3::WASPAL_WATER:
case PcTextureAnimCodesJak3::MINED_TFRAG:
case PcTextureAnimCodesJak3::VOLCANOX_WARP:
case PcTextureAnimCodesJak3::TEMPLEX_WATER:
case PcTextureAnimCodesJak3::VOLCANOA_WATER:
case PcTextureAnimCodesJak3::DESHOVER: {
auto anim =
anim_code_to_info(static_cast<PcTextureAnimCodesJak3>(vif0.immediate), *this);
auto p = scoped_prof(anim.name.c_str());
run_fixed_animation_array(anim.anim_array_idx, tf, texture_pool);
break;
}
case PcTextureAnimCodesJak3::CLOUDS_AND_FOG:
case PcTextureAnimCodesJak3::CLOUDS_HIRES: {
auto p = scoped_prof("clouds-and-fog");
handle_clouds_and_fog(tf, texture_pool,
vif0.immediate == (u16)PcTextureAnimCodesJak3::CLOUDS_HIRES);
break;
}
default:
lg::print("bad imm: {}\n", vif0.immediate);
ASSERT_NOT_REACHED();
}
switch (vif0.immediate) {
case UPLOAD_CLUT_16_16: {
auto p = scoped_prof("clut-16-16");
handle_upload_clut_16_16(tf, ee_mem);
} break;
case ERASE_DEST_TEXTURE: {
auto p = scoped_prof("erase");
handle_erase_dest(dma);
} break;
case GENERIC_UPLOAD: {
auto p = scoped_prof("generic-upload");
handle_generic_upload(tf, ee_mem);
} break;
case SET_SHADER: {
auto p = scoped_prof("set-shader");
handle_set_shader(dma);
} break;
case DRAW: {
auto p = scoped_prof("draw");
handle_draw(dma, *texture_pool);
} break;
case FINISH_ARRAY:
done = true;
break;
case DARKJAK: {
auto p = scoped_prof("darkjak");
run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx);
} break;
case PRISON_JAK: {
auto p = scoped_prof("prisonjak");
run_clut_blender_group(tf, m_jakb_prison_clut_blender_idx, frame_idx);
} break;
case ORACLE_JAK: {
auto p = scoped_prof("oraclejak");
run_clut_blender_group(tf, m_jakb_oracle_clut_blender_idx, frame_idx);
} break;
case NEST_JAK: {
auto p = scoped_prof("nestjak");
run_clut_blender_group(tf, m_jakb_nest_clut_blender_idx, frame_idx);
} break;
case KOR_TRANSFORM: {
auto p = scoped_prof("kor");
run_clut_blender_group(tf, m_kor_transform_clut_blender_idx, frame_idx);
} break;
case SKULL_GEM: {
auto p = scoped_prof("skull-gem");
run_fixed_animation_array(m_skull_gem_fixed_anim_array_idx, tf, texture_pool);
} break;
case BOMB: {
auto p = scoped_prof("bomb");
run_fixed_animation_array(m_bomb_fixed_anim_array_idx, tf, texture_pool);
} break;
case CAS_CONVEYOR: {
auto p = scoped_prof("cas-conveyor");
run_fixed_animation_array(m_cas_conveyor_anim_array_idx, tf, texture_pool);
} break;
case SECURITY: {
auto p = scoped_prof("security");
run_fixed_animation_array(m_security_anim_array_idx, tf, texture_pool);
} break;
case WATERFALL: {
auto p = scoped_prof("waterfall");
run_fixed_animation_array(m_waterfall_anim_array_idx, tf, texture_pool);
} break;
case WATERFALL_B: {
auto p = scoped_prof("waterfall-b");
run_fixed_animation_array(m_waterfall_b_anim_array_idx, tf, texture_pool);
} break;
case LAVA: {
auto p = scoped_prof("lava");
run_fixed_animation_array(m_lava_anim_array_idx, tf, texture_pool);
} break;
case LAVA_B: {
auto p = scoped_prof("lava-b");
run_fixed_animation_array(m_lava_b_anim_array_idx, tf, texture_pool);
} break;
case STADIUMB: {
auto p = scoped_prof("stadiumb");
run_fixed_animation_array(m_stadiumb_anim_array_idx, tf, texture_pool);
} break;
case FORTRESS_PRIS: {
auto p = scoped_prof("fort-pris");
run_fixed_animation_array(m_fortress_pris_anim_array_idx, tf, texture_pool);
} break;
case FORTRESS_WARP: {
auto p = scoped_prof("fort-warp");
run_fixed_animation_array(m_fortress_warp_anim_array_idx, tf, texture_pool);
} break;
case METKOR: {
auto p = scoped_prof("metkor");
run_fixed_animation_array(m_metkor_anim_array_idx, tf, texture_pool);
} break;
case SHIELD: {
auto p = scoped_prof("shield");
run_fixed_animation_array(m_shield_anim_array_idx, tf, texture_pool);
} break;
case KREW_HOLO: {
auto p = scoped_prof("krew-holo");
run_fixed_animation_array(m_krew_holo_anim_array_idx, tf, texture_pool);
} break;
case CLOUDS_AND_FOG:
case CLOUDS_HIRES: {
auto p = scoped_prof("clouds-and-fog");
handle_clouds_and_fog(tf, texture_pool, vif0.immediate == CLOUDS_HIRES);
} break;
case SLIME: {
auto p = scoped_prof("slime");
handle_slime(tf, texture_pool);
} break;
default:
lg::print("unsupported game version {}\n", (int)this->m_version);
lg::print("bad imm: {}\n", vif0.immediate);
ASSERT_NOT_REACHED();
}
} else {
@@ -2274,21 +1818,6 @@ void TextureAnimator::set_up_opengl_for_fixed(const FixedLayerDef& def,
blend_c == GsAlpha::BlendMode::SOURCE && blend_d == GsAlpha::BlendMode::DEST) {
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
} else if (blend_a == GsAlpha::BlendMode::SOURCE &&
blend_b == GsAlpha::BlendMode::ZERO_OR_FIXED &&
blend_c == GsAlpha::BlendMode::ZERO_OR_FIXED &&
blend_d == GsAlpha::BlendMode::ZERO_OR_FIXED && def.blend_fix == 128) {
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
} else if (blend_a == GsAlpha::BlendMode::SOURCE &&
blend_b == GsAlpha::BlendMode::ZERO_OR_FIXED &&
blend_c == GsAlpha::BlendMode::ZERO_OR_FIXED &&
blend_d == GsAlpha::BlendMode::DEST) {
// 0, 2, 2, 1
// (Cs - 0) * FIX / 128 + Cd
// So source is fix / 128, and dest is 1
float color = (float)def.blend_fix / 128.f;
glBlendColor(color, color, color, color);
glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE, GL_ONE, GL_ZERO);
} else {
lg::print("unhandled blend: {} {} {} {}\n", (int)blend_a, (int)blend_b, (int)blend_c,
(int)blend_d);
@@ -2429,23 +1958,14 @@ void TextureAnimator::set_draw_data_from_interpolated(DrawData* result,
const LayerVals& vals,
int w,
int h) {
ASSERT(vals.rot == 0);
result->color = (vals.color * 128.f).cast<u32>();
math::Vector2f pos_scale(vals.scale.x() * w, vals.scale.y() * h);
math::Vector2f pos_offset(2048.f + (vals.offset.x() * w), 2048.f + (vals.offset.y() * h));
math::Vector2f st_scale = vals.st_scale;
math::Vector2f st_offset = vals.st_offset;
math::Vector2f corners[4] = {math::Vector2f{-0.5, -0.5}, math::Vector2f{0.5, -0.5},
math::Vector2f{-0.5, 0.5}, math::Vector2f{0.5, 0.5}};
if (vals.rot) {
const float rotation_radians = 2.f * M_PI * vals.rot / 65536.f;
const float sine = std::sin(rotation_radians);
const float cosine = std::cos(rotation_radians);
math::Vector2f vx(sine, cosine);
math::Vector2f vy(cosine, -sine);
for (auto& corner : corners) {
corner = vx * corner.x() + vy * corner.y();
}
}
const math::Vector2f corners[4] = {math::Vector2f{-0.5, -0.5}, math::Vector2f{0.5, -0.5},
math::Vector2f{-0.5, 0.5}, math::Vector2f{0.5, 0.5}};
math::Vector2f sts[4];
math::Vector2<u32> poss[4];
@@ -2536,14 +2056,8 @@ void TextureAnimator::run_fixed_animation(FixedAnim& anim, float time) {
if (true) { // todo
glColorMask(true, true, true, false);
glUniform1f(m_uniforms.alpha_multiply, 2.f);
glUniform1i(m_uniforms.set_alpha, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glColorMask(false, false, false, true);
if (anim.def.set_alpha) {
glUniform1i(m_uniforms.set_alpha, 1);
glUniform4f(m_uniforms.rgba, draw_data.color.x(), draw_data.color.x(),
draw_data.color.x(), 128.f);
}
glUniform1f(m_uniforms.alpha_multiply, 1.f);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} else {
@@ -59,7 +59,7 @@ struct ShaderContext {
};
struct OpenGLTexturePool {
OpenGLTexturePool(GameVersion version);
OpenGLTexturePool();
~OpenGLTexturePool();
GLuint allocate(u64 w, u64 h);
void free(GLuint texture, u64 w, u64 h);
@@ -148,18 +148,6 @@ struct FixedLayerDef {
GsAlpha::BlendMode blend_modes[4]; // abcd
u8 blend_fix = 0;
void set_blend(GsAlpha::BlendMode a,
GsAlpha::BlendMode b,
GsAlpha::BlendMode c,
GsAlpha::BlendMode d,
u8 fix) {
blend_modes[0] = a;
blend_modes[1] = b;
blend_modes[2] = c;
blend_modes[3] = d;
blend_fix = fix;
}
void set_blend_b2_d1() {
blend_modes[0] = GsAlpha::BlendMode::SOURCE;
blend_modes[1] = GsAlpha::BlendMode::ZERO_OR_FIXED;
@@ -193,15 +181,6 @@ struct FixedAnimDef {
// alpha blend off, so alpha doesn't matter i think.
std::vector<FixedLayerDef> layers;
bool move_to_pool = false;
bool set_alpha = false;
void set_times(std::vector<std::pair<float, float>> times) {
ASSERT(layers.size() >= times.size());
for (size_t i = 0; i < layers.size(); i++) {
auto& layer = layers.at(i);
layer.start_time = times.at(i).first;
layer.end_time = times.at(i).second;
}
}
};
struct DynamicLayerData {
@@ -364,7 +343,6 @@ class TextureAnimator {
GLuint tcc;
GLuint alpha_multiply;
GLuint minimum, maximum;
GLuint set_alpha;
} m_uniforms;
struct {
@@ -418,8 +396,6 @@ class TextureAnimator {
m_psm32_to_psm8_64_64;
ClutReader m_clut_table;
public:
// jak 2
int m_skull_gem_fixed_anim_array_idx = -1;
int m_bomb_fixed_anim_array_idx = -1;
int m_cas_conveyor_anim_array_idx = -1;
@@ -435,59 +411,9 @@ class TextureAnimator {
int m_shield_anim_array_idx = -1;
int m_krew_holo_anim_array_idx = -1;
// jak 3
int m_default_water_anim_array_idx = -1;
int m_default_warp_anim_array_idx = -1;
int m_templea_water_anim_array_idx = -1;
int m_templea_warp_anim_array_idx = -1;
int m_templeb_warp_anim_array_idx = -1;
int m_templec_water_anim_array_idx = -1;
int m_sewc_water_anim_array_idx = -1;
int m_sewd_water_anim_array_idx = -1;
int m_sewe_water_anim_array_idx = -1;
int m_sewg_water_anim_array_idx = -1;
int m_sewh_water_anim_array_idx = -1;
int m_sewi_water_anim_array_idx = -1;
int m_sewj_water_anim_array_idx = -1;
int m_sewl_water_anim_array_idx = -1;
int m_sewm_water_anim_array_idx = -1;
int m_sewn_water_anim_array_idx = -1;
int m_desresc_warp_anim_array_idx = -1;
int m_ctyslumb_water_anim_array_idx = -1;
int m_nstb_quicksand_anim_array_idx = -1;
int m_ctyslumc_water_anim_array_idx = -1;
int m_factoryc_alpha_anim_array_idx = -1;
int m_hfrag_anim_array_idx = -1;
int m_hanga_sprite_anim_array_idx = -1;
int m_hanga_water_anim_array_idx = -1;
int m_desertd_water_anim_array_idx = -1;
int m_lmhcityb_tfrag_anim_array_idx = -1;
int m_towerb_water_anim_array_idx = -1;
int m_comb_field_anim_array_idx = -1;
int m_wasstada_alpha_anim_array_idx = -1;
int m_factoryb_water_anim_array_idx = -1;
int m_lmhcitya_tfrag_anim_array_idx = -1;
int m_mhcitya_pris_anim_array_idx = -1;
int m_rubblea_water_anim_array_idx = -1;
int m_rubblea2_water_anim_array_idx = -1;
int m_rubbleb_water_anim_array_idx = -1;
int m_rubblec_water_anim_array_idx = -1;
int m_foresta_water_anim_array_idx = -1;
int m_forestb_water_anim_array_idx = -1;
int m_lforplnt_pris_anim_array_idx = -1;
int m_ltnfxhip_anim_array_idx = -1;
int m_lgunnorm_water_anim_array_idx = -1;
int m_ljkdxvin_anim_array_idx = -1;
int m_waspal_water_anim_array_idx = -1;
int m_mined_tfrag_anim_array_idx = -1;
int m_volcanox_warp_anim_array_idx = -1;
int m_templex_water_anim_array_idx = -1;
int m_volcanoa_anim_array_idx = -1;
int m_deshover_anim_array_idx = -1;
int m_darkjak_highres_clut_blender_idx = -1;
std::vector<FixedAnimArray> m_fixed_anim_arrays;
public:
// note: for now these can't be easily changed because each layer has its own hand-tuned
// parameters from the original game. If you want to change it, you'll need to make up parameters
// for those new layers.
File diff suppressed because it is too large. Load diff
@@ -119,7 +119,3 @@ void TextureUploadHandler::draw_debug_window() {
m_direct->draw_debug_window();
}
}
bool TextureUploadHandler::empty() const {
return m_upload_count == 0;
}
@@ -18,7 +18,6 @@ class TextureUploadHandler : public BucketRenderer {
bool add_direct = false);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
bool empty() const override;
private:
struct TextureUpload {
@@ -129,8 +129,8 @@ Hfrag::HfragLevel* Hfrag::get_hfrag_level(const std::string& name,
// first, see if this level is loaded. If not, there's nothing we can do.
auto lev_data = render_state->loader->get_tfrag3_level(name);
if (!lev_data) {
// printf("[hfrag] can't display %s because it's not loaded.\n", name.c_str());
// render_state->loader->debug_print_loaded_levels();
printf("[hfrag] can't display %s because it's not loaded.\n", name.c_str());
render_state->loader->debug_print_loaded_levels();
return nullptr;
}
+5 -20
View File
@@ -1,7 +1,9 @@
#include "debug_gui.h"
#include <algorithm>
#include "common/global_profiler/GlobalProfiler.h"
#include "common/util/string_util.h"
#include "game/graphics/display.h"
#include "game/graphics/gfx.h"
@@ -162,27 +164,10 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
}
if (ImGui::BeginMenu("Event Profiler")) {
if (ImGui::Checkbox("Record Events", &record_events)) {
if (ImGui::Checkbox("Record", &record_events)) {
prof().set_enable(record_events);
}
ImGui::SameLine();
ImGui::Text(fmt::format("({}/{})", prof().get_next_idx(), prof().get_max_events()).c_str());
ImGui::InputInt("Event Buffer Size", &max_event_buffer_size);
if (ImGui::Button("Resize")) {
prof().update_event_buffer_size(max_event_buffer_size);
}
if (ImGui::Button("Reset Events")) {
prof().clear();
}
ImGui::Separator();
ImGui::Checkbox("Enable Compression", &prof().m_enable_compression);
if (ImGui::Button("Dump to File")) {
record_events = false;
prof().dump_to_json();
}
// if (ImGui::Button("Open dump folder")) {
// // TODO - https://github.com/mlabbe/nativefiledialog
// }
ImGui::MenuItem("Dump to file", nullptr, &dump_events);
ImGui::EndMenu();
}
+1 -1
View File
@@ -64,7 +64,7 @@ class OpenGlDebugGui {
bool small_profiler = false;
bool record_events = false;
int max_event_buffer_size = 65536;
bool dump_events = false;
bool want_reboot_in_debug = false;
bool screenshot_hotkey_enabled = true;
@@ -70,16 +70,11 @@ void Generic2::render_in_mode(DmaFollower& dma,
case Mode::LIGHTNING:
process_dma_lightning(dma, render_state->next_bucket);
break;
case Mode::PRIM:
process_dma_prim(dma, render_state->next_bucket);
break;
default:
ASSERT_NOT_REACHED();
}
}
m_empty = m_next_free_vert == 0;
{
// the next pass is to look at all of that data, and figure out the best order to draw it
// using OpenGL
@@ -89,7 +84,6 @@ void Generic2::render_in_mode(DmaFollower& dma,
setup_draws(true, true);
break;
case Mode::LIGHTNING:
case Mode::PRIM:
setup_draws(false, true);
break;
case Mode::WARP:
@@ -11,7 +11,7 @@ class Generic2 {
u32 num_buckets = 800);
~Generic2();
enum class Mode { NORMAL, LIGHTNING, WARP, PRIM };
enum class Mode { NORMAL, LIGHTNING, WARP };
void render_in_mode(DmaFollower& dma,
SharedRenderState* render_state,
@@ -19,7 +19,6 @@ class Generic2 {
Mode mode);
void draw_debug_window();
bool empty() { return m_empty; }
struct Vertex {
math::Vector<float, 3> xyz;
@@ -43,7 +42,6 @@ class Generic2 {
void process_dma_jak1(DmaFollower& dma, u32 next_bucket);
void process_dma_lightning(DmaFollower& dma, u32 next_bucket);
void process_dma_jak2(DmaFollower& dma, u32 next_bucket);
void process_dma_prim(DmaFollower& dma, u32 next_bucket);
void setup_draws(bool enable_at, bool default_fog);
void do_draws(SharedRenderState* render_state, ScopedProfilerNode& prof);
void do_draws_for_alpha(SharedRenderState* render_state,
@@ -86,8 +84,6 @@ class Generic2 {
float hud_mat_23, hud_mat_32, hud_mat_33;
bool uses_hud = false;
bool uses_full_matrix = false;
math::Vector4f full_matrix[4];
} m_drawing_config;
struct GsState {
@@ -202,10 +198,8 @@ class Generic2 {
GLuint vertex_buffer;
GLuint index_buffer;
GLuint alpha_reject, color_mult, fog_color, scale, mat_23, mat_32, mat_33, fog_consts,
hvdf_offset, use_full_matrix, full_matrix;
hvdf_offset;
GLuint gfx_hack_no_tex;
GLuint warp_sample_mode;
} m_ogl;
bool m_empty = false;
};
@@ -22,9 +22,4 @@ void Generic2BucketRenderer::render(DmaFollower& dma,
return;
}
m_generic->render_in_mode(dma, render_state, prof, m_mode);
m_empty = m_generic->empty();
}
bool Generic2BucketRenderer::empty() const {
return m_empty;
}
@@ -11,10 +11,8 @@ class Generic2BucketRenderer : public BucketRenderer {
Generic2::Mode mode);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
bool empty() const override;
private:
std::shared_ptr<Generic2> m_generic;
Generic2::Mode m_mode;
bool m_empty = false;
};
@@ -190,16 +190,6 @@ void Generic2::determine_draw_modes(bool enable_at, bool default_fog) {
current_mode.set_alpha_fail(reg.afail());
current_mode.set_zt(reg.zte());
current_mode.set_depth_test(reg.ztest());
// detect a strange way of disabling z writes by light-trail.
// we don't actually handle alpha_fail later on in Direct - it doesn't map well to modern
// graphics and would require a draw call per primitive.
if (current_mode.get_alpha_fail() == GsTest::AlphaFail::FB_ONLY &&
current_mode.get_aref() == 0x80 &&
current_mode.get_alpha_test() == DrawMode::AlphaTest::GEQUAL) {
current_mode.set_alpha_test(DrawMode::AlphaTest::ALWAYS);
current_mode.disable_depth_write();
}
}
m_adgifs[i].mode = current_mode;
@@ -281,10 +271,6 @@ void Generic2::process_matrices() {
bool found_proj_matrix = false;
std::array<math::Vector4f, 4> projection_matrix, hud_matrix;
for (u32 i = 0; i < m_next_free_frag; i++) {
if (m_drawing_config.uses_full_matrix) {
memcpy(&m_drawing_config.full_matrix, m_fragments[i].header, 64);
break;
}
float mat_33;
memcpy(&mat_33, m_fragments[i].header + 15 * sizeof(float), sizeof(float));
if (mat_33 == 0) {
@@ -550,83 +550,6 @@ void unpack_vertex(Generic2::Vertex* out, const u8* in, int count) {
}
}
void Generic2::process_dma_prim(DmaFollower& dma, u32 next_bucket) {
reset_buffers();
auto first_data = dma.read_and_advance();
// handle the stuff at the beginning.
// if the engine didn't run the generic renderer setup function, this bucket will end here.
if (is_nop_zero(first_data) && next_bucket == dma.current_tag_offset()) {
return;
}
// MARK NOP (for profiling)
auto v0k = first_data.vifcode0().kind;
ASSERT((v0k == VifCode::Kind::MARK || v0k == VifCode::Kind::NOP) &&
first_data.vifcode1().kind == VifCode::Kind::NOP);
// NOP DIRECT (set up GS, from generic setup)
auto direct_setup = dma.read_and_advance();
ASSERT(direct_setup.size_bytes == 32 && direct_setup.vifcode0().kind == VifCode::Kind::NOP &&
direct_setup.vifcode1().kind == VifCode::Kind::DIRECT);
m_drawing_config.zmsk = false;
m_drawing_config.uses_full_matrix = true;
// STYCYCL to set up generic VU1 constants
auto constants = dma.read_and_advance();
ASSERT(constants.size_bytes == 128);
ASSERT(constants.vifcode0().kind == VifCode::Kind::STCYCL);
ASSERT(constants.vifcode1().kind == VifCode::Kind::UNPACK_V4_32);
memcpy(&m_drawing_config.pfog0, constants.data + 0, 4);
memcpy(&m_drawing_config.fog_min, constants.data + 4, 4);
memcpy(&m_drawing_config.fog_max, constants.data + 8, 4);
memcpy(m_drawing_config.hvdf_offset.data(), constants.data + 32, 16);
// 32: MSCALF 0x0 STMOD 0b0 init generic VU1
auto mscalf = dma.read_and_advance();
ASSERT(mscalf.vifcode0().kind == VifCode::Kind::MSCALF &&
mscalf.vifcode1().kind == VifCode::Kind::STMOD);
// 0: NOP NOP
// auto another_nop = dma.read_and_advance();
// ASSERT(is_nop_zero(another_nop));
while (dma.current_tag_offset() != next_bucket) {
auto up1 = dma.read_and_advance();
while (up1.vifcode0().kind == VifCode::Kind::NOP && up1.vifcode1().kind == VifCode::Kind::NOP) {
up1 = dma.read_and_advance();
}
if (up1.vifcode0().kind == VifCode::Kind::FLUSHA) {
while (dma.current_tag_offset() != next_bucket) {
auto it = dma.read_and_advance();
}
break;
}
auto up2 = dma.read_and_advance();
auto call = dma.read_and_advance();
// up1 is a 12 qw upload for control:
// up2 is vertex upload.
auto* frag = &next_frag();
ASSERT(up1.size_bytes == Generic2::FRAG_HEADER_SIZE + 5 * 16); // header + adgif
memcpy(frag->header, up1.data, Generic2::FRAG_HEADER_SIZE);
frag->adgif_idx = m_next_free_adgif;
frag->adgif_count = 1;
frag->mscal_addr = 6;
frag->uses_hud = false;
auto* adgif = &next_adgif();
memcpy(&adgif->data, up1.data + Generic2::FRAG_HEADER_SIZE, sizeof(AdGifData));
// (new 'static 'gif-tag-regs-32 :regs0 (gif-reg-id st) :regs1 (gif-reg-id rgbaq) :regs2
// (gif-reg-id xyzf2))
int num_vtx = up2.size_bytes / (16 * 3);
frag->vtx_count = num_vtx;
frag->vtx_idx = m_next_free_vert;
alloc_vtx(num_vtx);
unpack_vertex(&m_verts[frag->vtx_idx], up2.data, num_vtx);
}
}
void Generic2::process_dma_lightning(DmaFollower& dma, u32 next_bucket) {
reset_buffers();
auto first_data = dma.read_and_advance();
@@ -74,8 +74,6 @@ void Generic2::opengl_setup(ShaderLibrary& shaders) {
m_ogl.hvdf_offset = glGetUniformLocation(id, "hvdf_offset");
m_ogl.gfx_hack_no_tex = glGetUniformLocation(id, "gfx_hack_no_tex");
m_ogl.warp_sample_mode = glGetUniformLocation(id, "warp_sample_mode");
m_ogl.use_full_matrix = glGetUniformLocation(id, "use_full_matrix");
m_ogl.full_matrix = glGetUniformLocation(id, "full_matrix");
}
void Generic2::opengl_cleanup() {
@@ -309,12 +307,6 @@ void Generic2::do_draws(SharedRenderState* render_state, ScopedProfilerNode& pro
glPrimitiveRestartIndex(UINT32_MAX);
opengl_bind_and_setup_proj(render_state);
if (m_drawing_config.uses_full_matrix) {
glUniform1i(m_ogl.use_full_matrix, 1);
glUniformMatrix4fv(m_ogl.full_matrix, 1, GL_FALSE, m_drawing_config.full_matrix[0].data());
} else {
glUniform1i(m_ogl.use_full_matrix, 0);
}
constexpr DrawMode::AlphaBlend alpha_order[ALPHA_MODE_COUNT] = {
DrawMode::AlphaBlend::SRC_0_FIX_DST, DrawMode::AlphaBlend::SRC_SRC_SRC_SRC,
DrawMode::AlphaBlend::SRC_DST_SRC_DST, DrawMode::AlphaBlend::SRC_0_SRC_DST,
@@ -7,7 +7,6 @@
#endif
#include "common/global_profiler/GlobalProfiler.h"
#include "common/util/fnv.h"
#include "game/graphics/opengl_renderer/EyeRenderer.h"
#include "game/graphics/opengl_renderer/background/background_common.h"
@@ -55,8 +54,6 @@ std::mutex g_merc_data_mutex;
Merc2::Merc2(ShaderLibrary& shaders, const std::vector<GLuint>* anim_slot_array)
: m_anim_slot_array(anim_slot_array) {
ASSERT(fnv64("the quick brown fox jumps over the lazy dog") == 0x7404cea13ff89bb0);
// Set up main vertex array. This will point to the data stored in the .FR3 level file, and will
// be uploaded to the GPU by the Loader.
glGenVertexArrays(1, &m_vao);
@@ -538,14 +535,11 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
auto* flags = (const PcMercFlags*)input_data;
int num_effects = flags->effect_count; // mostly just a sanity check
ASSERT(num_effects < kMaxEffect);
// hack for custom models to disable blerc/mod draws
bool is_custom_model = model->effects.at(0).all_draws.at(0).no_strip;
u64 current_ignore_alpha_bits = flags->ignore_alpha_mask; // shader settings
u64 current_effect_enable_bits = flags->enable_mask; // mask for game to disable an effect
bool model_uses_mod =
flags->bitflags & 1 && !is_custom_model; // if we should update vertices from game.
bool model_uses_mod = flags->bitflags & 1; // if we should update vertices from game.
bool model_disables_fog = flags->bitflags & 2;
bool model_uses_pc_blerc = flags->bitflags & 4 && !is_custom_model;
bool model_uses_pc_blerc = flags->bitflags & 4;
bool model_disables_envmap = flags->bitflags & 8;
input_data += 32;
@@ -615,8 +609,6 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
u32 lights = alloc_lights(current_lights);
stats->num_lights++;
u64 hash = fnv64(model->name);
// loop over effects, creating draws for each
for (size_t ei = 0; ei < model->effects.size(); ei++) {
// game has disabled it?
@@ -641,7 +633,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
// do fixed draws:
for (auto& fdraw : effect.mod.fix_draw) {
alloc_normal_draw(fdraw, ignore_alpha, lev_bucket, first_bone, lights, uses_water,
model_disables_fog, hash);
model_disables_fog);
if (should_envmap) {
try_alloc_envmap_draw(fdraw, effect.envmap_mode, effect.envmap_texture, lev_bucket,
fade_buffer + 4 * ei, first_bone, lights, uses_water);
@@ -651,7 +643,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
// do mod draws
for (auto& mdraw : effect.mod.mod_draw) {
auto n = alloc_normal_draw(mdraw, ignore_alpha, lev_bucket, first_bone, lights, uses_water,
model_disables_fog, hash);
model_disables_fog);
// modify the draw, set the mod flag and point it to the opengl buffer
n->flags |= MOD_VTX;
n->mod_vtx_buffer = mod_opengl_buffers[ei];
@@ -673,7 +665,7 @@ void Merc2::handle_pc_model(const DmaTransfer& setup,
fade_buffer + 4 * ei, first_bone, lights, uses_water);
}
alloc_normal_draw(draw, ignore_alpha, lev_bucket, first_bone, lights, uses_water,
model_disables_fog, hash);
model_disables_fog);
}
}
}
@@ -769,9 +761,7 @@ void Merc2::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof,
MercDebugStats* stats) {
bool hack = stats->collect_debug_model_list;
*stats = {};
stats->collect_debug_model_list = hack;
if (stats->collect_debug_model_list) {
stats->model_list.clear();
}
@@ -1063,7 +1053,6 @@ Merc2::Draw* Merc2::try_alloc_envmap_draw(const tfrag3::MercDraw& mdraw,
draw->first_index = mdraw.first_index;
draw->index_count = mdraw.index_count;
draw->mode = envmap_mode;
draw->hash = 0;
if (jak1_water_mode) {
draw->mode.enable_ab();
draw->mode.disable_depth_write();
@@ -1084,14 +1073,12 @@ Merc2::Draw* Merc2::alloc_normal_draw(const tfrag3::MercDraw& mdraw,
u32 first_bone,
u32 lights,
bool jak1_water_mode,
bool disable_fog,
u64 hash) {
bool disable_fog) {
Draw* draw = &lev_bucket->draws[lev_bucket->next_free_draw++];
draw->flags = 0;
draw->first_index = mdraw.first_index;
draw->index_count = mdraw.index_count;
draw->mode = mdraw.mode;
draw->hash = hash;
if (jak1_water_mode) {
draw->mode.set_ab(true);
draw->mode.disable_depth_write();
@@ -1218,7 +1205,7 @@ void Merc2::do_draws(const Draw* draw_array,
bool set_fade,
SharedRenderState* render_state) {
glBindVertexArray(m_vao);
s32 last_tex = INT32_MIN;
int last_tex = -1;
int last_light = -1;
bool normal_vtx_buffer_bound = true;
@@ -1257,19 +1244,10 @@ void Merc2::do_draws(const Draw* draw_array,
if (draw.texture < (int)lev->textures.size() && draw.texture >= 0) {
glBindTexture(GL_TEXTURE_2D, lev->textures.at(draw.texture));
} else if ((draw.texture & 0xffffff00) == 0xefffff00) {
if (render_state->version >= GameVersion::Jak3) {
auto maybe_eye =
render_state->eye_renderer->lookup_eye_texture_hash(draw.hash, (draw.texture & 1));
if (maybe_eye) {
glBindTexture(GL_TEXTURE_2D, *maybe_eye);
}
} else {
auto maybe_eye = render_state->eye_renderer->lookup_eye_texture(draw.texture & 0xff);
if (maybe_eye) {
glBindTexture(GL_TEXTURE_2D, *maybe_eye);
}
auto maybe_eye = render_state->eye_renderer->lookup_eye_texture(draw.texture & 0xff);
if (maybe_eye) {
glBindTexture(GL_TEXTURE_2D, *maybe_eye);
}
use_mipmaps_for_filtering = false;
} else if (draw.texture < 0) {
int slot = -(draw.texture + 1);
@@ -192,7 +192,6 @@ class Merc2 {
u8 fade[4];
// no strip hack for custom models
u8 no_strip;
u64 hash;
};
struct LevelDrawBucket {
@@ -214,8 +213,7 @@ class Merc2 {
u32 first_bone,
u32 lights,
bool jak1_water_mode,
bool disable_fog,
u64 hash);
bool disable_fog);
Draw* try_alloc_envmap_draw(const tfrag3::MercDraw& mdraw,
const DrawMode& envmap_mode,
@@ -17,14 +17,8 @@ void Merc2BucketRenderer::render(DmaFollower& dma,
}
m_renderer->render(dma, render_state, prof, &m_debug_stats);
m_empty = m_debug_stats.num_predicted_draws == 0;
}
void Merc2BucketRenderer::draw_debug_window() {
m_renderer->draw_debug_window(&m_debug_stats);
}
bool Merc2BucketRenderer::empty() const {
return m_empty;
}
@@ -8,10 +8,8 @@ class Merc2BucketRenderer : public BucketRenderer {
Merc2BucketRenderer(const std::string& name, int my_id, std::shared_ptr<Merc2> merc);
void draw_debug_window() override;
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
bool empty() const override;
private:
bool m_empty = false;
std::shared_ptr<Merc2> m_renderer;
MercDebugStats m_debug_stats;
};
@@ -10,8 +10,6 @@ uniform vec3 fog_constants;
uniform vec4 scale;
uniform float mat_23;
uniform float mat_33;
uniform bool use_full_matrix;
uniform mat4 full_matrix;
uniform vec4 hvdf_offset;
uniform uint warp_sample_mode;
@@ -40,17 +38,11 @@ void main() {
// maddax.xyzw ACC, vf08, vf16 matrix multiply X
// vu.acc.madda(Mask::xyzw, gen.mat0, gen.vtx_load0.x());
if (use_full_matrix) {
transformed = -full_matrix[3];
transformed -= full_matrix[0] * position_in.x ;
transformed -= full_matrix[1] * position_in.y;
transformed -= full_matrix[2] * position_in.z ;
} else {
transformed.xyz = position_in * scale.xyz;
transformed.z += mat_32;
transformed.w = mat_23 * position_in.z + mat_33;
transformed *= -1;
}
transformed.xyz = position_in * scale.xyz;
transformed.z += mat_32;
transformed.w = mat_23 * position_in.z + mat_33;
transformed *= -1; // todo?
// div Q, vf01.x, vf12.w perspective divide
@@ -4,7 +4,6 @@ out vec4 color;
uniform vec4 rgba;
uniform int enable_tex;
uniform int set_alpha;
uniform int tcc;
uniform ivec4 channel_scramble;
uniform float alpha_multiply;
@@ -58,9 +57,5 @@ void main() {
} else {
color = (rgba / 128.);
}
if (set_alpha == 1) {
color.a = 0.5;
} else {
color.a *= alpha_multiply;
}
color.a *= alpha_multiply;
}
+18
View File
@@ -448,6 +448,23 @@ void render_game_frame(int game_width,
}
}
void update_global_profiler() {
if (g_gfx_data->debug_gui.dump_events) {
prof().set_enable(false);
g_gfx_data->debug_gui.dump_events = false;
// TODO - the file rotation code had an infinite loop here if it couldn't find anything
// matching the format
//
// Does the existing log rotation code have that problem?
auto file_path = file_util::get_jak_project_dir() / "profile_data" /
fmt::format("prof-{}.json", str_util::current_local_timestamp_no_colons());
file_util::create_dir_if_needed_for_file(file_path);
prof().dump_to_json(file_path.string());
}
}
void GLDisplay::process_sdl_events() {
SDL_Event evt;
while (SDL_PollEvent(&evt) != 0) {
@@ -586,6 +603,7 @@ void GLDisplay::render() {
// Start timing for the next frame.
g_gfx_data->debug_gui.start_frame();
prof().instant_event("ROOT");
update_global_profiler();
// toggle even odd and wake up engine waiting on vsync.
// TODO: we could play with moving this earlier, right after the final bucket renderer.
+1
View File
@@ -125,6 +125,7 @@ struct link_control {
}
};
void klink_init_globals();
Ptr<u8> c_symlink2(Ptr<u8> objData, Ptr<u8> linkObj, Ptr<u8> relocTable);
extern link_control saved_link_control;
+17 -33
View File
@@ -448,19 +448,6 @@ u64 pc_get_mips2c(u32 name) {
return Mips2C::gLinkedFunctionTable.get(n);
}
u64 pc_get_display_id() {
if (Display::GetMainDisplay()) {
return Display::GetMainDisplay()->get_display_manager()->get_active_display_id();
}
return 0;
}
void pc_set_display_id(u64 display_id) {
if (Display::GetMainDisplay()) {
Display::GetMainDisplay()->get_display_manager()->enqueue_set_display_id(display_id);
}
}
u64 pc_get_display_name(u32 id, u32 str_dest_ptr) {
std::string name = "";
if (Display::GetMainDisplay()) {
@@ -482,16 +469,17 @@ u64 pc_get_display_name(u32 id, u32 str_dest_ptr) {
}
u32 pc_get_display_mode() {
auto display_mode = game_settings::DisplaySettings::DisplayMode::Windowed;
auto display_mode = WindowDisplayMode::Windowed;
if (Display::GetMainDisplay()) {
display_mode = Display::GetMainDisplay()->get_display_manager()->get_display_mode();
display_mode = Display::GetMainDisplay()->get_display_manager()->get_window_display_mode();
}
switch (display_mode) {
case game_settings::DisplaySettings::DisplayMode::Borderless:
case WindowDisplayMode::Borderless:
return g_pc_port_funcs.intern_from_c("borderless").offset;
case game_settings::DisplaySettings::DisplayMode::Fullscreen:
case WindowDisplayMode::Fullscreen:
return g_pc_port_funcs.intern_from_c("fullscreen").offset;
default:
case WindowDisplayMode::Windowed:
return g_pc_port_funcs.intern_from_c("windowed").offset;
}
}
@@ -502,13 +490,13 @@ void pc_set_display_mode(u32 symptr) {
}
if (symptr == g_pc_port_funcs.intern_from_c("windowed").offset || symptr == s7.offset) {
Display::GetMainDisplay()->get_display_manager()->enqueue_set_window_display_mode(
game_settings::DisplaySettings::DisplayMode::Windowed);
WindowDisplayMode::Windowed);
} else if (symptr == g_pc_port_funcs.intern_from_c("borderless").offset) {
Display::GetMainDisplay()->get_display_manager()->enqueue_set_window_display_mode(
game_settings::DisplaySettings::DisplayMode::Borderless);
WindowDisplayMode::Borderless);
} else if (symptr == g_pc_port_funcs.intern_from_c("fullscreen").offset) {
Display::GetMainDisplay()->get_display_manager()->enqueue_set_window_display_mode(
game_settings::DisplaySettings::DisplayMode::Fullscreen);
WindowDisplayMode::Fullscreen);
}
}
@@ -580,6 +568,12 @@ void pc_get_window_scale(u32 x_ptr, u32 y_ptr) {
}
}
void pc_get_fullscreen_display(u64 display_id) {
if (Display::GetMainDisplay()) {
Display::GetMainDisplay()->get_display_manager()->enqueue_set_fullscreen_display_id(display_id);
}
}
void pc_set_window_size(u64 width, u64 height) {
if (Display::GetMainDisplay()) {
Display::GetMainDisplay()->get_display_manager()->enqueue_set_window_size(width, height);
@@ -607,14 +601,6 @@ void pc_get_resolution(u32 id, u32 w_ptr, u32 h_ptr) {
}
}
u64 pc_is_supported_resolution(u64 width, u64 height) {
if (Display::GetMainDisplay()) {
return bool_to_symbol(
Display::GetMainDisplay()->get_display_manager()->is_supported_resolution(width, height));
}
return bool_to_symbol(false);
}
u64 pc_get_controller_name(u32 id, u32 str_dest_ptr) {
std::string name = "";
if (Display::GetMainDisplay()) {
@@ -926,11 +912,9 @@ void init_common_pc_port_functions(
// -- DISPLAY RELATED --
// Returns the name of the display with the given id or #f if not found / empty
make_func_symbol_func("pc-get-display-id", (void*)pc_get_display_id);
make_func_symbol_func("pc-set-display-id!", (void*)pc_set_display_id);
make_func_symbol_func("pc-get-display-name", (void*)pc_get_display_name);
make_func_symbol_func("pc-get-display-mode", (void*)pc_get_display_mode);
make_func_symbol_func("pc-set-display-mode!", (void*)pc_set_display_mode);
make_func_symbol_func("pc-set-display-mode", (void*)pc_set_display_mode);
make_func_symbol_func("pc-get-display-count", (void*)pc_get_display_count);
// Returns resolution of the monitor's current display mode
make_func_symbol_func("pc-get-active-display-size", (void*)pc_get_active_display_size);
@@ -941,10 +925,10 @@ void init_common_pc_port_functions(
make_func_symbol_func("pc-get-window-size", (void*)pc_get_window_size);
// Returns scale of window. This is for DPI stuff.
make_func_symbol_func("pc-get-window-scale", (void*)pc_get_window_scale);
make_func_symbol_func("pc-set-window-size!", (void*)pc_set_window_size);
make_func_symbol_func("pc-set-fullscreen-display", (void*)pc_get_fullscreen_display);
make_func_symbol_func("pc-set-window-size", (void*)pc_set_window_size);
make_func_symbol_func("pc-get-num-resolutions", (void*)pc_get_num_resolutions);
make_func_symbol_func("pc-get-resolution", (void*)pc_get_resolution);
make_func_symbol_func("pc-is-supported-resolution?", (void*)pc_is_supported_resolution);
// -- INPUT RELATED --
// Returns the name of the display with the given id or #f if not found / empty
+1
View File
@@ -16,6 +16,7 @@ void load_and_link_dgo_from_c_fast(const char* name,
Ptr<kheapinfo> heap,
u32 linkFlag,
s32 bufferSize);
void load_and_link_dgo(u64 name_gstr, u64 heap_info, u64 flag, u64 buffer_size);
void kdgo_init_globals();
extern RPC_Dgo_Cmd sMsg[2];
extern RPC_Dgo_Cmd* sLastMsg;
+4 -5
View File
@@ -8,7 +8,6 @@
#include "game/kernel/common/kdgo.h"
#include "game/kernel/common/kmalloc.h"
#include "game/kernel/jak3/klink.h"
#include "game/overlord/jak3/rpc_interface.h"
namespace jak3 {
@@ -40,7 +39,7 @@ void BeginLoadingDGO(const char* name, Ptr<u8> buffer1, Ptr<u8> buffer2, Ptr<u8>
RpcSync(DGO_RPC_CHANNEL); // make sure old RPC is finished
// put a dummy value here just to make sure the IOP overwrites it.
sMsg[msgID].status = DGO_RPC_RESULT_INIT; // !! this is 666
sMsg[msgID].result = DGO_RPC_RESULT_INIT; // !! this is 666
// inform IOP of buffers
sMsg[msgID].buffer1 = buffer1.offset;
@@ -79,13 +78,13 @@ Ptr<u8> GetNextDGO(u32* lastObjectFlag) {
Ptr<u8> buffer(0);
if (sLastMsg) {
// if we got a good result, get pointer to object
if ((sLastMsg->status == DGO_RPC_RESULT_MORE) || (sLastMsg->status == DGO_RPC_RESULT_DONE)) {
if ((sLastMsg->result == DGO_RPC_RESULT_MORE) || (sLastMsg->result == DGO_RPC_RESULT_DONE)) {
buffer.offset =
sLastMsg->buffer1; // buffer 1 always contains location of most recently loaded object.
}
// not the last one, so don't set the flag.
if (sLastMsg->status == DGO_RPC_RESULT_MORE) {
if (sLastMsg->result == DGO_RPC_RESULT_MORE) {
*lastObjectFlag = 0;
}
@@ -112,7 +111,7 @@ void ContinueLoadingDGO(Ptr<u8> b1, Ptr<u8> b2, Ptr<u8> heapPtr) {
u32 msgID = sMsgNum;
jak3::RPC_Dgo_Cmd* sendBuff = sMsg + sMsgNum;
sMsgNum = sMsgNum ^ 1;
sendBuff->status = DGO_RPC_RESULT_INIT;
sendBuff->result = DGO_RPC_RESULT_INIT;
sMsg[msgID].buffer1 = b1.offset;
sMsg[msgID].buffer2 = b2.offset;
sMsg[msgID].buffer_heap_top = heapPtr.offset;
-220
View File
@@ -1,220 +0,0 @@
//--------------------------MIPS2C---------------------
// clang-format off
#include "game/mips2c/mips2c_private.h"
#include "game/kernel/jak3/kscheme.h"
using ::jak3::intern_from_c;
namespace Mips2C::jak3 {
namespace method_21_cloth_system {
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
u32 call_addr = 0;
c->daddiu(sp, sp, -80); // daddiu sp, sp, -80
c->daddiu(a3, sp, 16); // daddiu a3, sp, 16
c->daddiu(t0, sp, 32); // daddiu t0, sp, 32
c->lwu(v1, 68, a0); // lwu v1, 68(a0)
c->lw(v1, 0, v1); // lw v1, 0(v1)
c->lw(a1, 96, a0); // lw a1, 96(a0)
c->daddiu(a1, a1, -1); // daddiu a1, a1, -1
c->lw(a2, 100, a0); // lw a2, 100(a0)
c->daddiu(a2, a2, -1); // daddiu a2, a2, -1
c->addiu(t1, r0, 0); // addiu t1, r0, 0
c->addiu(t1, r0, 0); // addiu t1, r0, 0
c->mov64(t1, a3); // or t1, a3, r0
c->lui(t2, 16000); // lui t2, 16000
c->mtc1(f0, t2); // mtc1 f0, t2
c->swc1(f0, 0, t1); // swc1 f0, 0(t1)
c->lui(t2, 16000); // lui t2, 16000
c->mtc1(f0, t2); // mtc1 f0, t2
c->swc1(f0, 4, t1); // swc1 f0, 4(t1)
c->lui(t2, 16000); // lui t2, 16000
c->mtc1(f0, t2); // mtc1 f0, t2
c->swc1(f0, 8, t1); // swc1 f0, 8(t1)
c->lui(t2, 16000); // lui t2, 16000
c->mtc1(f0, t2); // mtc1 f0, t2
c->swc1(f0, 12, t1); // swc1 f0, 12(t1)
c->mov64(t1, t0); // or t1, t0, r0
c->mtc1(f0, r0); // mtc1 f0, r0
c->swc1(f0, 0, t1); // swc1 f0, 0(t1)
c->mtc1(f0, r0); // mtc1 f0, r0
c->swc1(f0, 4, t1); // swc1 f0, 4(t1)
c->mtc1(f0, r0); // mtc1 f0, r0
c->swc1(f0, 8, t1); // swc1 f0, 8(t1)
c->lwc1(f0, 144, a0); // lwc1 f0, 144(a0)
c->swc1(f0, 12, t1); // swc1 f0, 12(t1)
c->vmax_bc(DEST::xyzw, BC::w, vf1, vf0, vf0); // vmaxw.xyzw vf1, vf0, vf0
c->lqc2(vf10, 0, a3); // lqc2 vf10, 0(a3)
c->lqc2(vf15, 0, t0); // lqc2 vf15, 0(t0)
c->sd(r0, 48, sp); // sd r0, 48(sp)
c->addiu(a3, r0, 0); // addiu a3, r0, 0
//beq r0, r0, L187 // beq r0, r0, L187
// nop // sll r0, r0, 0
goto block_10; // branch always
block_1:
c->addiu(t0, r0, 0); // addiu t0, r0, 0
//beq r0, r0, L186 // beq r0, r0, L186
// nop // sll r0, r0, 0
goto block_8; // branch always
block_2:
c->addiu(t1, r0, 48); // addiu t1, r0, 48
c->ld(t2, 48, sp); // ld t2, 48(sp)
c->mult3(t1, t1, t2); // mult3 t1, t1, t2
c->daddiu(t1, t1, 12); // daddiu t1, t1, 12
c->lwu(t2, 0, a0); // lwu t2, 0(a0)
c->daddu(t1, t1, t2); // daddu t1, t1, t2
c->sw(t1, 56, sp); // sw t1, 56(sp)
c->addiu(t1, r0, 48); // addiu t1, r0, 48
c->ld(t2, 48, sp); // ld t2, 48(sp)
c->daddiu(t2, t2, 1); // daddiu t2, t2, 1
c->mult3(t1, t1, t2); // mult3 t1, t1, t2
c->daddiu(t1, t1, 12); // daddiu t1, t1, 12
c->lwu(t2, 0, a0); // lwu t2, 0(a0)
c->daddu(t1, t1, t2); // daddu t1, t1, t2
c->sw(t1, 60, sp); // sw t1, 60(sp)
c->addiu(t1, r0, 48); // addiu t1, r0, 48
c->ld(t2, 48, sp); // ld t2, 48(sp)
c->lw(t3, 96, a0); // lw t3, 96(a0)
c->daddu(t2, t2, t3); // daddu t2, t2, t3
c->mult3(t1, t1, t2); // mult3 t1, t1, t2
c->daddiu(t1, t1, 12); // daddiu t1, t1, 12
c->lwu(t2, 0, a0); // lwu t2, 0(a0)
c->daddu(t1, t1, t2); // daddu t1, t1, t2
c->sw(t1, 64, sp); // sw t1, 64(sp)
c->addiu(t1, r0, 48); // addiu t1, r0, 48
c->lw(t2, 96, a0); // lw t2, 96(a0)
c->daddiu(t2, t2, 1); // daddiu t2, t2, 1
c->ld(t3, 48, sp); // ld t3, 48(sp)
c->daddu(t2, t2, t3); // daddu t2, t2, t3
c->mult3(t1, t1, t2); // mult3 t1, t1, t2
c->daddiu(t1, t1, 12); // daddiu t1, t1, 12
c->lwu(t2, 0, a0); // lwu t2, 0(a0)
c->daddu(t1, t1, t2); // daddu t1, t1, t2
c->sw(t1, 68, sp); // sw t1, 68(sp)
c->lwu(t1, 56, sp); // lwu t1, 56(sp)
c->lqc2(vf2, 0, t1); // lqc2 vf2, 0(t1)
c->lwu(t1, 68, sp); // lwu t1, 68(sp)
c->lqc2(vf5, 0, t1); // lqc2 vf5, 0(t1)
c->lwu(t1, 60, sp); // lwu t1, 60(sp)
c->lqc2(vf3, 0, t1); // lqc2 vf3, 0(t1)
c->lwu(t1, 64, sp); // lwu t1, 64(sp)
c->lqc2(vf4, 0, t1); // lqc2 vf4, 0(t1)
c->lwu(t1, 56, sp); // lwu t1, 56(sp)
c->lqc2(vf20, 32, t1); // lqc2 vf20, 32(t1)
c->lwu(t1, 68, sp); // lwu t1, 68(sp)
c->lqc2(vf23, 32, t1); // lqc2 vf23, 32(t1)
c->lwu(t1, 60, sp); // lwu t1, 60(sp)
c->lqc2(vf21, 32, t1); // lqc2 vf21, 32(t1)
c->lwu(t1, 64, sp); // lwu t1, 64(sp)
c->lqc2(vf22, 32, t1); // lqc2 vf22, 32(t1)
c->vmula_bc(DEST::xyzw, BC::x, vf2, vf20); // vmulax.xyzw acc, vf2, vf20
c->vmadda_bc(DEST::xyzw, BC::x, vf3, vf21); // vmaddax.xyzw acc, vf3, vf21
c->vmadda_bc(DEST::xyzw, BC::x, vf5, vf23); // vmaddax.xyzw acc, vf5, vf23
c->vmadd_bc(DEST::xyzw, BC::x, vf8, vf4, vf22); // vmaddx.xyzw vf8, vf4, vf22
c->vmul_bc(DEST::xyzw, BC::x, vf8, vf8, vf10); // vmulx.xyzw vf8, vf8, vf10
c->lwu(t1, 68, a0); // lwu t1, 68(a0)
c->daddiu(t1, t1, 12); // daddiu t1, t1, 12
c->addiu(t2, r0, 0); // addiu t2, r0, 0
//beq r0, r0, L185 // beq r0, r0, L185
// nop // sll r0, r0, 0
goto block_6; // branch always
block_3:
c->lqc2(vf11, 0, t1); // lqc2 vf11, 0(t1)
c->vsub(DEST::xyzw, vf13, vf8, vf11); // vsub.xyzw vf13, vf8, vf11
c->vmul(DEST::xyzw, vf9, vf13, vf13); // vmul.xyzw vf9, vf13, vf13
c->vmula_bc(DEST::xyzw, BC::x, vf1, vf9); // vmulax.xyzw acc, vf1, vf9
c->vmadda_bc(DEST::xyzw, BC::y, vf1, vf9); // vmadday.xyzw acc, vf1, vf9
c->vmadd_bc(DEST::xyzw, BC::z, vf14, vf1, vf9); // vmaddz.xyzw vf14, vf1, vf9
c->vadd_bc(DEST::w, BC::w, vf11, vf11, vf15); // vaddw.w vf11, vf11, vf15
c->vmul(DEST::xyzw, vf12, vf11, vf11); // vmul.xyzw vf12, vf11, vf11
c->vsub_bc(DEST::xyzw, BC::w, vf9, vf14, vf12); // vsubw.xyzw vf9, vf14, vf12
c->mov128_gpr_vf(t3, vf9); // qmfc2.i t3, vf9
bc = ((s64)c->sgpr64(t3)) >= 0; // bgez t3, L184
// nop // sll r0, r0, 0
if (bc) {goto block_5;} // branch non-likely
c->vrsqrt(vf11, BC::w, vf14, BC::x); // vrsqrt Q, vf11.w, vf14.x
c->vmax_bc(DEST::xyz, BC::x, vf20, vf0, vf20); // vmaxx.xyz vf20, vf0, vf20
c->vmax_bc(DEST::xyz, BC::x, vf21, vf0, vf21); // vmaxx.xyz vf21, vf0, vf21
c->vmax_bc(DEST::xyz, BC::x, vf22, vf0, vf22); // vmaxx.xyz vf22, vf0, vf22
c->vmax_bc(DEST::xyz, BC::x, vf23, vf0, vf23); // vmaxx.xyz vf23, vf0, vf23
c->vwaitq(); // vwaitq
// Unknown instr: vmulaq.xyzw acc, vf13, Q
c->vmula_q(DEST::xyzw, vf13);
c->vmsuba(DEST::xyzw, vf1, vf13); // vmsuba.xyzw acc, vf1, vf13
c->vmadd(DEST::xyzw, vf2, vf1, vf2); // vmadd.xyzw vf2, vf1, vf2
c->vmadd(DEST::xyzw, vf3, vf1, vf3); // vmadd.xyzw vf3, vf1, vf3
c->vmadd(DEST::xyzw, vf5, vf1, vf5); // vmadd.xyzw vf5, vf1, vf5
c->vmadd(DEST::xyzw, vf4, vf1, vf4); // vmadd.xyzw vf4, vf1, vf4
c->vmadd(DEST::xyzw, vf8, vf1, vf8); // vmadd.xyzw vf8, vf1, vf8
block_5:
c->daddiu(t1, t1, 16); // daddiu t1, t1, 16
c->daddiu(t2, t2, 1); // daddiu t2, t2, 1
block_6:
c->slt(t3, t2, v1); // slt t3, t2, v1
bc = c->sgpr64(t3) != 0; // bne t3, r0, L183
// nop // sll r0, r0, 0
if (bc) {goto block_3;} // branch non-likely
c->mov64(t1, s7); // or t1, s7, r0
c->mov64(t1, s7); // or t1, s7, r0
c->lwu(t1, 56, sp); // lwu t1, 56(sp)
c->sqc2(vf2, 0, t1); // sqc2 vf2, 0(t1)
c->lwu(t1, 68, sp); // lwu t1, 68(sp)
c->sqc2(vf5, 0, t1); // sqc2 vf5, 0(t1)
c->lwu(t1, 60, sp); // lwu t1, 60(sp)
c->sqc2(vf3, 0, t1); // sqc2 vf3, 0(t1)
c->lwu(t1, 64, sp); // lwu t1, 64(sp)
c->sqc2(vf4, 0, t1); // sqc2 vf4, 0(t1)
c->mov128_gpr_vf(t1, vf4); // qmfc2.i t1, vf4
c->ld(t1, 48, sp); // ld t1, 48(sp)
c->daddiu(t1, t1, 1); // daddiu t1, t1, 1
c->sd(t1, 48, sp); // sd t1, 48(sp)
c->daddiu(t0, t0, 1); // daddiu t0, t0, 1
block_8:
c->slt(t1, t0, a1); // slt t1, t0, a1
bc = c->sgpr64(t1) != 0; // bne t1, r0, L182
// nop // sll r0, r0, 0
if (bc) {goto block_2;} // branch non-likely
c->mov64(t0, s7); // or t0, s7, r0
c->mov64(t0, s7); // or t0, s7, r0
c->ld(t0, 48, sp); // ld t0, 48(sp)
c->daddiu(t0, t0, 1); // daddiu t0, t0, 1
c->sd(t0, 48, sp); // sd t0, 48(sp)
c->daddiu(a3, a3, 1); // daddiu a3, a3, 1
block_10:
c->slt(t0, a3, a2); // slt t0, a3, a2
bc = c->sgpr64(t0) != 0; // bne t0, r0, L181
// nop // sll r0, r0, 0
if (bc) {goto block_1;} // branch non-likely
c->mov64(v1, s7); // or v1, s7, r0
c->mov64(v0, s7); // or v0, s7, r0
//jr ra // jr ra
c->daddiu(sp, sp, 80); // daddiu sp, sp, 80
goto end_of_function; // return
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
end_of_function:
return c->gprs[v0].du64[0];
}
void link() {
gLinkedFunctionTable.reg("(method 21 cloth-system)", execute, 256);
}
} // namespace method_21_cloth_system
} // namespace Mips2C
-10
View File
@@ -905,16 +905,6 @@ struct ExecutionContext {
}
}
void vmula_q(DEST mask, int src0) {
auto s0 = vf_src(src0);
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
acc.f[i] = s0.f[i] * Q;
}
}
}
void vadda_bc(DEST mask, BC bc, int src0, int src1) {
auto s0 = vf_src(src0);
auto s1 = vf_src(src1);
+1 -3
View File
@@ -393,7 +393,6 @@ namespace shadow_add_double_edges { extern void link(); }
namespace shadow_add_single_tris { extern void link(); }
namespace shadow_add_double_tris { extern void link(); }
namespace shadow_execute { extern void link(); }
namespace method_21_cloth_system { extern void link(); }
}
// clang-format on
@@ -655,8 +654,7 @@ PerGameVersion<std::unordered_map<std::string, std::vector<void (*)()>>> gMips2C
jak3::shadow_find_single_edges::link, jak3::shadow_find_double_edges::link,
jak3::shadow_add_verts::link, jak3::shadow_add_facing_single_tris::link,
jak3::shadow_add_single_edges::link, jak3::shadow_add_double_edges::link,
jak3::shadow_add_single_tris::link, jak3::shadow_add_double_tris::link}},
{"cloth", {jak3::method_21_cloth_system::link}}}};
jak3::shadow_add_single_tris::link, jak3::shadow_add_double_tris::link}}}};
void LinkedFunctionTable::reg(const std::string& name, u64 (*exec)(void*), u32 stack_size) {
const auto& it = m_executes.insert({name, {exec, Ptr<u8>()}});
-3
View File
@@ -460,9 +460,6 @@ void* RPC_Loader(unsigned int /*fno*/, void* data, int size) {
snd_SetPlayBackMode(0);
}
} break;
case Jak2SoundCommand::mirror_mode: {
gMirrorMode = cmd->mirror.value;
} break;
default:
ASSERT_MSG(false, fmt::format("Unhandled RPC Loader command {}", int(cmd->j2command)));
}
-1
View File
@@ -58,7 +58,6 @@ enum class Jak2SoundCommand : u16 {
iop_mem = 48,
cancel_dgo = 49,
set_stereo_mode = 50,
mirror_mode = 201,
};
struct SoundRpcCommand {
+1 -1
View File
@@ -30,7 +30,7 @@ void StopVAG(VagCmd* cmd, int /*param_2*/);
enum VolumeCategory {
DIALOGUE = 2, // VAG streams. Copied "dialogue" name from jak 1.
};
int MasterVolume[32];
int MasterVolume[17];
void vag_init_globals() {
memset(VagCmds, 0, sizeof(VagCmds));
+1 -1
View File
@@ -113,7 +113,7 @@ extern int TrapSRAM[N_VAG_CMDS];
extern int StreamVoice[N_VAG_CMDS];
extern int ActiveVagStreams;
extern int MasterVolume[32];
extern int MasterVolume[17];
void vag_init_globals();
-333
View File
@@ -1,333 +0,0 @@
#include "basefile.h"
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "game/overlord/jak3/overlord.h"
#include "game/overlord/jak3/pagemanager.h"
#include "game/overlord/jak3/vag.h"
namespace jak3 {
void jak3_overlord_init_globals_basefile() {}
/*!
* Construct a CBaseFile in an unused state.
*/
CBaseFile::CBaseFile() {
m_Buffer.m_pCurrentData = nullptr;
m_Buffer.m_pCurrentPageStart = nullptr;
m_Buffer.m_nMinNumPages = 1;
m_Buffer.m_nMaxNumPages = kDefaultBufferPageCount;
m_Buffer.m_nDataLength = 0;
m_Buffer.m_pPageList = nullptr;
m_Buffer.m_pIsoCmd = nullptr;
m_Buffer.m_eBufferType = CBuffer::BufferType::EBT_FREE;
m_ProcessDataSemaphore = -1;
m_FileDef = nullptr;
m_FileKind = Kind::UNKNOWN;
m_Status = EIsoStatus::NONE_0;
m_ReadRate = 0;
m_LengthPages = 0;
m_PageOffset = 0;
m_nNumPages = kDefaultBufferPageCount;
}
/*!
* Construct a CBaseFile for a given file, but keep it in the "idle" state, with no buffer
* allocated.
*/
CBaseFile::CBaseFile(const jak3::ISOFileDef* file, int semaphore) {
m_Buffer.m_pCurrentData = nullptr;
m_Buffer.m_nMaxNumPages = kDefaultBufferPageCount;
m_Buffer.m_nDataLength = 0;
m_Buffer.m_nMinNumPages = 1;
m_Buffer.m_pPageList = nullptr;
m_Buffer.m_pIsoCmd = nullptr;
m_Buffer.m_pCurrentPageStart = nullptr;
m_Buffer.m_eBufferType = CBuffer::BufferType::EBT_FREE;
m_nNumPages = kDefaultBufferPageCount;
m_FileDef = file;
m_ProcessDataSemaphore = semaphore;
m_FileKind = Kind::UNKNOWN;
m_Status = EIsoStatus::IDLE_1;
m_ReadRate = 0;
m_LengthPages = 0;
m_PageOffset = 0;
}
/*!
* Update our buffer to handle crossing page boundaries, return pointer to next data.
*/
uint8_t* CBaseFile::CheckPageBoundary() {
// Can't check page boundary if the buffer is not allocated.
ASSERT(m_Buffer.m_eBufferType != CBuffer::BufferType::EBT_FREE);
// Can't check page boundary if there is no manager
ASSERT(m_Buffer.m_pPageList);
CPageList* page_list = m_Buffer.m_pPageList;
CPage* page = page_list->m_pCurrentActivePage;
// can only return data if there's an active page
if (!page || page_list->m_nNumActivePages <= 0) {
return nullptr;
}
// buffer doesn't know the current page, just reset it to the start of the active page.
if (m_Buffer.m_pCurrentPageStart == nullptr) {
m_Buffer.m_pCurrentData = page->m_pPageMemStart;
m_Buffer.m_pCurrentPageStart = page->m_pPageMemStart;
} else {
uint8_t* end_ptr = page->m_pPageMemEnd;
// check if our data pointer crossed the page boundary
if (end_ptr <= m_Buffer.m_pCurrentData) {
// it did!
uint8_t* past_boundary_ptr = m_Buffer.m_pCurrentData;
// get the next active page
CPage* next_page = page_list->StepActivePage();
if (!next_page) {
// no more active pages, no data to process
m_Buffer.m_pCurrentPageStart = nullptr;
m_Buffer.m_pCurrentData = nullptr;
ovrld_log(LogCategory::PAGING, "File {} ran out of pages in CheckPageBoundary",
m_FileDef->name.data);
} else {
// this is a little weird, but if we went past the end of the previous page, we actually
// start at an offset into the next page - perhaps the user could know that pages are
// consecutive in memory?
uint8_t* new_page_mem = next_page->m_pPageMemStart;
m_Buffer.m_pCurrentData = new_page_mem + (end_ptr + 1 - past_boundary_ptr);
m_Buffer.m_pCurrentPageStart = new_page_mem;
ovrld_log(LogCategory::PAGING, "File {} advanced to next page (wrapped {} bytes)",
m_FileDef->name.data, (end_ptr + 1 - past_boundary_ptr));
}
}
}
return m_Buffer.m_pCurrentData;
}
/*!
* Allocate pages and set up the CBuffer for the given ISO Msg and type.
*/
int CBaseFile::InitBuffer(CBuffer::BufferType type, jak3::ISO_Hdr* msg) {
ASSERT(msg);
m_Buffer.m_pCurrentData = nullptr;
m_Buffer.m_pPageList = nullptr;
m_Buffer.m_pIsoCmd = msg;
m_Buffer.m_pCurrentPageStart = nullptr;
m_Buffer.m_nDataLength = 0;
m_Buffer.m_eBufferType = CBuffer::BufferType::EBT_FREE;
m_Buffer.m_nMinNumPages = 1;
m_Buffer.m_nMaxNumPages = kDefaultBufferPageCount;
m_nNumPages = 4;
// adjust size based on the request buffer type
switch (type) {
case CBuffer::BufferType::REQUEST_NORMAL: { // 3
m_Buffer.m_pCurrentData = nullptr;
m_Buffer.m_nMinNumPages = 1;
m_Buffer.m_nMaxNumPages = 4;
m_nNumPages = 4;
m_Buffer.m_nDataLength = 0;
m_Buffer.m_pCurrentPageStart = nullptr;
m_Buffer.m_eBufferType = CBuffer::BufferType::NORMAL; // 1
// and the iso msg request.
switch (msg->msg_type) {
case ISO_Hdr::MsgType::LOAD_EE:
case ISO_Hdr::MsgType::LOAD_IOP:
case ISO_Hdr::MsgType::LOAD_EE_CHUNK:
m_Buffer.m_nMinNumPages = 1;
m_nNumPages = 4;
m_Buffer.m_nMaxNumPages = 4;
break;
case ISO_Hdr::MsgType::LOAD_SOUNDBANK:
m_Buffer.m_nMinNumPages = 1;
m_Buffer.m_nMaxNumPages = 2;
break;
default:
break;
}
} break;
case CBuffer::BufferType::REQUEST_VAG: {
m_Buffer.m_pCurrentData = nullptr;
m_Buffer.m_eBufferType = CBuffer::BufferType::VAG;
m_Buffer.m_nMinNumPages = 1;
m_nNumPages = 0x10;
m_Buffer.m_nDataLength = 0;
m_Buffer.m_pCurrentPageStart = nullptr;
m_Buffer.m_nMaxNumPages = 0x10;
} break;
default:
ASSERT_NOT_REACHED(); // bad buffer type
}
ovrld_log(LogCategory::PAGING, "File {} initializing buffer ({} pages {} min {} max)",
m_FileDef->name.data, m_nNumPages, m_Buffer.m_nMinNumPages, m_Buffer.m_nMaxNumPages);
// Actual allocation of page data
CPageList* page_list = AllocPages();
if (page_list) {
// set up the current pointers of the buffer.
m_Buffer.m_pCurrentPageStart = page_list->m_pFirstPage->m_pPageMemStart;
m_Buffer.m_pCurrentData = m_Buffer.m_pCurrentPageStart;
return 1;
} else {
ovrld_log(LogCategory::WARN, "File {} failed to allocate a page list.", m_FileDef->name.data);
// if it failed, terminate the buffer
TerminateBuffer();
return 0;
}
}
/*!
* Free page memory, clear event flags for cpages.
*/
void CBaseFile::TerminateBuffer() {
ovrld_log(LogCategory::PAGING, "File {} terminating buffer.", m_FileDef->name.data);
auto buffer_type = m_Buffer.m_eBufferType;
if (buffer_type != CBuffer::BufferType::EBT_FREE) {
// clean up our pages
auto* page_list = m_Buffer.m_pPageList;
if (page_list) {
// stop try to load
page_list->CancelActivePages();
}
switch (buffer_type) {
case CBuffer::BufferType::EBT_FREE:
case CBuffer::BufferType::NORMAL:
case CBuffer::BufferType::VAG:
case CBuffer::BufferType::REQUEST_NORMAL:
case CBuffer::BufferType::REQUEST_VAG:
// return memory
FreePages();
// reset our buffer
m_Buffer.m_nDataLength = 0;
m_Buffer.m_pCurrentPageStart = 0;
m_Buffer.m_eBufferType = CBuffer::BufferType::EBT_FREE;
// reset our command
if (buffer_type != CBuffer::BufferType::EBT_FREE) {
ASSERT(m_Buffer.m_pIsoCmd);
m_Buffer.m_pIsoCmd = nullptr;
}
break;
default:
ASSERT_NOT_REACHED(); // Invalid buffer type
}
} else {
ASSERT_NOT_REACHED(); // Buffer already terminated, shouldn't happen again.
}
}
/*!
* Allocate CPage and CPageList as needed to reach the target number of pages.
*/
CPageList* CBaseFile::AllocPages() {
// should have picked a buffer type
ASSERT(m_Buffer.m_eBufferType != CBuffer::BufferType::EBT_FREE);
if (m_Buffer.m_eBufferType == CBuffer::BufferType::EBT_FREE) {
return nullptr;
}
// We might have a PageList or not
auto* old_plist = m_Buffer.m_pPageList;
int old_unstepped_pages = 0;
bool have_plist = old_plist != nullptr;
CPageList* ret_plist = nullptr;
// if we do have a pagelist, we'll reuse it and any unstepped pages.
if (have_plist) {
old_unstepped_pages = old_plist->m_nNumUnsteppedPages;
ret_plist = old_plist;
}
int page_alloc_count = 0;
// to increase unstepped pages to the target m_nNumPages, we need to allocate this many more.
page_alloc_count = m_nNumPages - old_unstepped_pages;
// lg::warn("page counts in AllocPages: {} {}", m_nNumPages, old_unstepped_pages);
if (old_plist) {
// lg::warn(" {} {}", old_plist->m_nNumPages, old_plist->m_nNumActivePages);
}
if (old_unstepped_pages < (int)m_nNumPages) {
// alloc count will be positive.
// reduce allocation count to at most the number of free pages
if (get_page_manager()->m_CCache.m_nNumFreePages < page_alloc_count) {
page_alloc_count = get_page_manager()->m_CCache.m_nNumFreePages;
}
} else {
// alloc count would be negative, don't allocate
page_alloc_count = 0;
}
switch (m_Buffer.m_eBufferType) {
case CBuffer::BufferType::NORMAL:
case CBuffer::BufferType::REQUEST_NORMAL: {
// don't do anything special
} break;
case CBuffer::BufferType::VAG:
case CBuffer::BufferType::REQUEST_VAG: {
// for VAG commands, we don't bother buffering more than the DMA transfer size
int dma_xfer_size = ((ISO_VAGCommand*)m_Buffer.m_pIsoCmd)->xfer_size;
if (dma_xfer_size) {
ASSERT(dma_xfer_size > 0);
int limit = (dma_xfer_size + 0x7fff) >> 0xf;
if (page_alloc_count > limit) {
ovrld_log(LogCategory::WARN, "File {} wants {} pages, but VAG DMA sizes limit us to ",
m_FileDef->name.data, page_alloc_count, limit);
lg::info("page count dma limit {} -> {}\n", page_alloc_count, limit);
page_alloc_count = limit;
}
}
} break;
default:
ASSERT_NOT_REACHED(); // bad buffer type.
}
if (page_alloc_count == 0) {
return ret_plist;
}
ovrld_log(LogCategory::PAGING, "File {} wants {} more pages in AllocPages.", m_FileDef->name.data,
page_alloc_count);
if (have_plist) {
ret_plist = get_page_manager()->GrowPageList(m_Buffer.m_pPageList, page_alloc_count);
} else {
ret_plist = get_page_manager()->AllocPageList(page_alloc_count, 0);
}
if (ret_plist) {
m_Buffer.m_pPageList = ret_plist;
if (!have_plist) {
m_Buffer.m_pCurrentData = ret_plist->m_pFirstPage->m_pPageMemStart;
}
} else {
ASSERT_NOT_REACHED(); // might be ok.
}
return ret_plist;
}
/*!
* Free all pages and the page list.
*/
void CBaseFile::FreePages() {
ASSERT(m_Buffer.m_eBufferType != CBuffer::BufferType::EBT_FREE);
if (m_Buffer.m_pPageList) {
get_page_manager()->FreePageList(m_Buffer.m_pPageList);
}
m_Buffer.m_pPageList = nullptr;
}
} // namespace jak3
-76
View File
@@ -1,76 +0,0 @@
#pragma once
#include "common/common_types.h"
#include "game/overlord/jak3/isocommon.h"
#include "game/overlord/jak3/pagemanager.h"
namespace jak3 {
void jak3_overlord_init_globals_basefile();
struct CPageList;
struct ISOFileDef;
struct ISO_Hdr;
constexpr int kDefaultBufferPageCount = 4;
/*!
* Base class for a file that the ISO system is processing.
* This represents an "open" file, and contains references to the buffer holding this file's data
*/
struct CBaseFile {
CBaseFile();
CBaseFile(const ISOFileDef* file, int semaphore);
virtual ~CBaseFile() = default;
uint8_t* CheckPageBoundary();
int InitBuffer(CBuffer::BufferType type, ISO_Hdr* msg);
CPageList* AllocPages();
void TerminateBuffer();
void FreePages();
// buffer that stores some contents of this file
CBuffer m_Buffer;
// the number of pages that were allocated for reading this file.
u32 m_nNumPages;
// Metadata about the file
const ISOFileDef* m_FileDef;
// The compression format used on the file
enum class Kind {
UNKNOWN = 0,
NORMAL = 1,
LZO_COMPRESSED = 2,
} m_FileKind = Kind::UNKNOWN;
EIsoStatus m_Status = EIsoStatus::NONE_0;
// The expected read rate for streaming, used to prioritize CD reads. Can be 0 if unknown/not
// applicable.
int m_ReadRate = 0;
// Number of sectors that we should read in total, decided based on the file size and request from
// user when they opened this file.
int m_LengthPages = 0; // really, in pages...
// The current offset. (todo: is this for data we read, processed?)
int m_PageOffset = 0;
// Semaphore that we should wait on before handing new data to the process callback.
// Set to -1 if there is no semaphore.
// (this is a bit of hack, only used for VAG streaming).
int m_ProcessDataSemaphore = 0;
// virtual methods
virtual EIsoStatus BeginRead() = 0;
virtual EIsoStatus SyncRead() = 0;
virtual void Close() = 0;
virtual int RecoverPages(int num_pages) = 0;
virtual int GetSector() = 0;
// ??
// ??
// ??
};
} // namespace jak3
-26
View File
@@ -1,26 +0,0 @@
#include "basefilesystem.h"
#include "common/util/Assert.h"
#include "game/sce/iop.h"
using namespace iop;
namespace jak3 {
void jak3_overlord_init_globals_basefilesystem() {}
CBaseFileSystem::CBaseFileSystem() {
for (auto& sema : m_Sema) {
sema = -1;
SemaParam param;
param.max_count = 1;
param.attr = 0;
param.init_count = 1;
param.option = 0;
sema = CreateSema(&param);
if (sema < 0) {
ASSERT_NOT_REACHED();
}
}
}
} // namespace jak3
-33
View File
@@ -1,33 +0,0 @@
#pragma once
namespace jak3 {
void jak3_overlord_init_globals_basefilesystem();
struct ISOFileDef;
struct ISOName;
struct CBaseFile;
struct VagDirEntry;
constexpr int kMaxOpenFiles = 16;
/*!
* Base class for "FileSystem", which supports finding and opening files.
* The only implementation we have is CISOCDFileSystem
*/
struct CBaseFileSystem {
CBaseFileSystem();
virtual ~CBaseFileSystem() = default;
// semaphores for processing open files
int m_Sema[kMaxOpenFiles];
virtual int Init() = 0;
// polldrive
virtual ISOFileDef* Find(const char* name) = 0;
virtual ISOFileDef* FindIN(const ISOName* name) = 0;
virtual int GetLength(const ISOFileDef* file) = 0;
virtual CBaseFile* Open(const ISOFileDef* file_def, int sector_offset, int file_kind) = 0;
virtual CBaseFile* OpenWAD(const ISOFileDef* file_def, int page_offset) = 0;
virtual VagDirEntry* FindVAGFile(const char* name) = 0;
};
} // namespace jak3
-526
View File
@@ -1,526 +0,0 @@
#include "dma.h"
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "game/overlord/jak3/basefile.h"
#include "game/overlord/jak3/overlord.h"
#include "game/overlord/jak3/vag.h"
#include "game/sce/iop.h"
#include "game/sound/sdshim.h"
#include "game/sound/sndshim.h"
#define VOICE_BIT(voice) (1 << ((voice) >> 1))
namespace jak3 {
using namespace iop;
namespace {
// most recent call to voice_trans_wrapper's arguments
u32 g_voiceTransMode = 0;
u32 g_voiceTransSize = 0;
s16 g_voiceTransChannel = 0;
const void* g_voiceTransAddr = nullptr;
u32 g_voiceTransSpuAddr = 0;
// if we've started a transfer recently
bool g_voiceTransRunning = false;
// when that transfer was started
u32 g_voiceTransTime = 0;
// despite the name, this is really an indicator that the SPU streaming system is waiting
// for a SPU interrupt on completion.
bool g_bSpuDmaBusy = false;
int g_nSpuDmaChannel = 0;
ISO_VAGCommand* g_pDmaVagCmd = nullptr;
ISO_VAGCommand* g_pDmaStereoVagCmd = nullptr;
int g_nSpuDmaChunks = 0;
std::array<DmaQueueEntry, 16> g_aSpuDmaQueue;
int g_nSpuDmaQueueHead = 0;
int g_nSpuDmaQueueTail = 0;
int g_nSpuDmaQueueCount = 0;
struct DmaInterruptHandlerHack {
s32 chan = 0;
sceSdTransIntrHandler cb = nullptr;
void* data;
int countdown = 0;
} g_DmaInterruptHack;
} // namespace
void jak3_overlord_init_globals_dma() {
g_voiceTransMode = 0;
g_voiceTransSize = 0;
g_voiceTransChannel = 0;
g_voiceTransAddr = nullptr;
g_voiceTransSpuAddr = 0;
g_voiceTransRunning = false;
g_voiceTransTime = 0;
g_bSpuDmaBusy = false;
g_nSpuDmaChannel = 0;
g_pDmaVagCmd = nullptr;
g_pDmaStereoVagCmd = nullptr;
g_nSpuDmaChunks = 0;
g_aSpuDmaQueue = {};
g_nSpuDmaQueueHead = 0;
g_nSpuDmaQueueCount = 0;
g_nSpuDmaQueueTail = 0;
g_DmaInterruptHack = {};
}
// The DMA callback hack below is used to defer dma completion "interrupts" until the next run
// of the ISO Thread. This avoids re-entry type problems where the original design would set off
// a dma transfer in the completion handler of the previous transfer, and expect a few instructions
// to run after.
void uninstall_dma_intr() {
g_DmaInterruptHack = {};
}
void set_dma_intr_handler_hack(s32 chan, sceSdTransIntrHandler cb, void* data) {
ASSERT(!g_DmaInterruptHack.cb);
g_DmaInterruptHack.chan = chan;
g_DmaInterruptHack.cb = cb;
g_DmaInterruptHack.data = data;
g_DmaInterruptHack.countdown = 10;
}
int SPUDmaIntr(int channel, void* userdata);
void dma_intr_hack() {
if (g_DmaInterruptHack.countdown) {
g_DmaInterruptHack.countdown--;
if (g_DmaInterruptHack.countdown == 0) {
int chan = g_DmaInterruptHack.chan;
void* data = g_DmaInterruptHack.data;
g_DmaInterruptHack = {};
SPUDmaIntr(chan, data);
}
}
}
/*!
* This function is used to set up a DMA transfer to SPU DMA.
*
* This wrapper was added very close to the end of Jak 3's development.
*
* I believe it basically checks for dma transfers that are somehow "dropped", and retries them.
* Since I don't think our IOP framework will ever do this, we have an assert if the dropped logic
* ever goes off.
*/
int voice_trans_wrapper(s16 chan, u32 mode, const void* iop_addr, u32 spu_addr, u32 size) {
// remember the transfer settings. If there's a transfer in progress, so we can't start here,
// we'll use these to start the transfer later.
g_voiceTransMode = mode;
g_voiceTransSize = size;
g_voiceTransChannel = chan;
g_voiceTransAddr = iop_addr;
g_voiceTransSpuAddr = spu_addr;
if (g_voiceTransRunning) {
// I claim this should never happen, and this is their workaround for a bug.
ASSERT_NOT_REACHED();
return -0xd2; // busy
} else {
g_voiceTransRunning = true;
g_voiceTransTime = GetSystemTimeLow();
return sceSdVoiceTrans(chan, mode, iop_addr, spu_addr, size);
}
}
u32 read_rate_calc(u32 pitch) {
u64 pitch1 = (pitch >> 3);
u64 mult_result = pitch1 * 0x2492'4925ull;
return mult_result >> 32;
}
/*!
* The worst function of all time - the SPU DMA completion interrupt.
*/
int SPUDmaIntr(int channel, void* userdata) {
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr enter! {} 0x{:x}", channel, (u64)userdata);
if (!g_bSpuDmaBusy) {
// we got an interrupt, but weren't expecting it, or no longer have the need for the data.
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr exit - not busy");
return 0;
}
if (channel != g_nSpuDmaChannel) {
// interrupt was for the wrong channel, somehow.
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr exit - not our channel ??");
return 0;
}
// since we're in the completion handler, we know that there is no voice trans (SPU DMA) running.
g_voiceTransRunning = false;
// This next block will handle updating the playback command that triggered this dma:
if (g_pDmaVagCmd) {
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDma for cmd {}", g_pDmaVagCmd->name);
if (!g_pDmaStereoVagCmd) {
// non-stereo audio
// set a flag to indicate even/odd number of chunks have been dma'd
if ((g_nSpuDmaChunks & 1) == 0) {
g_pDmaVagCmd->flags.dma_complete_even_chunk_count = 1;
} else {
g_pDmaVagCmd->flags.dma_complete_odd_chunk_count = 1;
}
} else {
// stereo audio. This requires two uploads, one for left/right audio. If we've finished the
// first, start the second one here:
if (g_pDmaStereoVagCmd->xfer_size) {
// parameters for second upload
int chan = g_pDmaVagCmd->dma_chan;
const u8* iop_addr = g_pDmaStereoVagCmd->dma_iop_mem_ptr;
int size = g_pDmaStereoVagCmd->xfer_size;
// SPU addr - toggle the buffer based on stereo side:
// TODO: better explanation of why this picks the correct buffer.
int spu_addr;
if ((g_nSpuDmaChunks & 1) == 0) {
spu_addr = g_pDmaStereoVagCmd->stream_sram;
} else {
spu_addr = g_pDmaStereoVagCmd->stream_sram + 0x2000;
}
// these lines reordered to possibly support immediate dma completion callback??
// clear flag so we know not to transfer the next part
g_pDmaStereoVagCmd->xfer_size = 0;
g_pDmaStereoVagCmd->dma_iop_mem_ptr = nullptr;
// start next transfer
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr starting stereo sibling transfer");
set_dma_intr_handler_hack(g_nSpuDmaChannel, SPUDmaIntr, userdata);
voice_trans_wrapper(chan, 0, iop_addr, spu_addr, size);
return 0;
}
// second stereo upload completed - update double-buffering flags
if ((g_nSpuDmaChunks & 1) == 0) {
g_pDmaVagCmd->flags.dma_complete_even_chunk_count = 1;
g_pDmaStereoVagCmd->flags.dma_complete_even_chunk_count = 1;
} else {
g_pDmaVagCmd->flags.dma_complete_odd_chunk_count = 1;
g_pDmaStereoVagCmd->flags.dma_complete_odd_chunk_count = 1;
}
}
// if this is the first chunk, we'll start the actual audio here:
// lg::warn("----------> interrupt with chunks {}\n", g_nSpuDmaChunks);
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr chunks count {}", g_nSpuDmaChunks);
if (g_nSpuDmaChunks == 0) {
// compute pitch/playback rate
int pitch = CalculateVAGPitch(g_pDmaVagCmd->pitch1, g_pDmaVagCmd->pitch_cmd);
ASSERT(pitch == (pitch & 0xffff));
// inform the ISO system how fast we're reading
if (g_pDmaVagCmd->m_pBaseFile) {
// unlike actual playback, this is done with the pitch1 value from the file itself - so if
// we speed up/slow down stuff in debug, it won't change streaming modes
const int pitch_from_file =
CalculateVAGPitch(g_pDmaVagCmd->pitch1_file, g_pDmaVagCmd->pitch_cmd);
int rate = g_pDmaStereoVagCmd ? pitch_from_file * 0x2ee : pitch_from_file * 0x177;
g_pDmaVagCmd->m_pBaseFile->m_ReadRate = read_rate_calc(rate);
}
// start!
u32 voice_mask = 0;
if (!g_pDmaStereoVagCmd) {
// forget any previous spu address
g_pDmaVagCmd->current_spu_address = 0;
static_assert(SD_VA_SSA == 0x2040);
static_assert(SD_S_KOFF == 0x1600);
static_assert(SD_S_KON == 0x1500);
static_assert(SD_VP_ADSR1 == 0x300);
static_assert(SD_VP_ADSR2 == 0x400);
static_assert(SD_VP_PITCH == 0x200);
// before touching SPU2 hardware, wait for voice safety:
BlockUntilVoiceSafe(g_pDmaVagCmd->voice, 0x900);
// set address and ADSR settings
sceSdSetAddr(g_pDmaVagCmd->voice | SD_VA_SSA, g_pDmaVagCmd->stream_sram + 0x30);
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_ADSR1, 0xff);
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_ADSR2, 0x1fc0);
if (g_pDmaVagCmd->flags.paused) {
pitch = 0;
}
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_PITCH, pitch);
voice_mask = VOICE_BIT(g_pDmaVagCmd->voice);
} else {
// forget any previous spu address
g_pDmaVagCmd->current_spu_address = 0;
g_pDmaStereoVagCmd->current_spu_address = 0;
// wait for voices to be safe to adjust
BlockUntilVoiceSafe(g_pDmaVagCmd->voice, 0x900);
BlockUntilVoiceSafe(g_pDmaStereoVagCmd->voice, 0x900);
// set voice params
sceSdSetAddr(g_pDmaVagCmd->voice | SD_VA_SSA, g_pDmaVagCmd->stream_sram + 0x30);
sceSdSetAddr(g_pDmaStereoVagCmd->voice | SD_VA_SSA, g_pDmaStereoVagCmd->stream_sram + 0x30);
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_ADSR1, 0xff);
sceSdSetParam(g_pDmaStereoVagCmd->voice | SD_VP_ADSR1, 0xff);
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_ADSR2, 0x1fc0);
sceSdSetParam(g_pDmaStereoVagCmd->voice | SD_VP_ADSR2, 0x1fc0);
if (g_pDmaVagCmd->flags.paused) {
pitch = 0;
}
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_PITCH, pitch);
sceSdSetParam(g_pDmaStereoVagCmd->voice | SD_VP_PITCH, pitch);
voice_mask = VOICE_BIT(g_pDmaVagCmd->voice) | VOICE_BIT(g_pDmaStereoVagCmd->voice);
}
// do key-on or key-off
if (g_pDmaVagCmd->flags.paused) {
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr chunks 0, key off");
BlockUntilAllVoicesSafe();
sceSdSetSwitch(SD_S_KOFF | (g_pDmaVagCmd->voice & 1), voice_mask);
} else {
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr chunks 0, key on");
BlockUntilAllVoicesSafe();
sceSdSetSwitch(SD_S_KON | (g_pDmaVagCmd->voice & 1), voice_mask);
}
// remember the time of the key-on/off. This is used to avoid sending voice commands
// quickly, which somehow confuses the sound hardware.
auto sys_time = GetSystemTimeLow();
MarkVoiceKeyedOnOff(g_pDmaVagCmd->voice, sys_time);
if (g_pDmaStereoVagCmd) {
MarkVoiceKeyedOnOff(g_pDmaStereoVagCmd->voice, sys_time);
}
} else if (g_nSpuDmaChunks == 1) {
g_pDmaVagCmd->flags.saw_chunks1 = 1;
if (g_pDmaStereoVagCmd) {
g_pDmaStereoVagCmd->flags.saw_chunks1 = 1;
}
if (g_pDmaVagCmd->flags.paused) {
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr chunks 1, pausing");
u32 voice_mask = 0;
if (!g_pDmaStereoVagCmd) {
// pause by setting pitches to 0
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_PITCH, 0);
BlockUntilVoiceSafe(VOICE_BIT(g_pDmaVagCmd->voice), 0x900);
voice_mask = VOICE_BIT(g_pDmaVagCmd->voice);
} else {
sceSdSetParam(g_pDmaStereoVagCmd->voice | SD_VP_PITCH, 0);
sceSdSetParam(g_pDmaVagCmd->voice | SD_VP_PITCH, 0);
BlockUntilVoiceSafe(VOICE_BIT(g_pDmaVagCmd->voice), 0x900);
BlockUntilVoiceSafe(VOICE_BIT(g_pDmaStereoVagCmd->voice), 0x900);
voice_mask = VOICE_BIT(g_pDmaVagCmd->voice) | VOICE_BIT(g_pDmaStereoVagCmd->voice);
}
// switch off
BlockUntilAllVoicesSafe();
sceSdSetSwitch(SD_S_KOFF | (g_pDmaVagCmd->voice & 1), voice_mask);
auto sys_time = GetSystemTimeLow();
MarkVoiceKeyedOnOff(g_pDmaVagCmd->voice, sys_time);
if (g_pDmaStereoVagCmd) {
MarkVoiceKeyedOnOff(g_pDmaStereoVagCmd->voice, sys_time);
}
} else {
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr chunks 1, unpausing by call to UnPauseVAG");
g_pDmaVagCmd->flags.paused = 1;
UnPauseVAG(g_pDmaVagCmd);
}
}
// now that we've processed the command from this interrupt, mark it as safe to modify
g_pDmaVagCmd->safe_to_modify_dma = 1;
if (g_pDmaStereoVagCmd) {
g_pDmaStereoVagCmd->safe_to_modify_dma = 1;
}
// and forget it!
g_pDmaVagCmd = nullptr;
g_pDmaStereoVagCmd = nullptr;
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr dma handling of VAG cmd is complete");
}
// release ref on this page. (interestingly, not a dma ref...)
if (userdata) {
CPage* page = (CPage*)userdata;
int ret = page->ReleaseRef();
ASSERT(ret >= 0);
}
// now - see if we have another queued dma transfer
ASSERT(g_nSpuDmaQueueCount >= 0);
if (g_nSpuDmaQueueCount == 0) {
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr dma queue is empty, disabling interrupt");
// we're done!
// set_dma_intr_handler_hack(channel, nullptr, nullptr);
uninstall_dma_intr();
// if (-1 < channel) {
// snd_FreeSPUDMA(channel);
// }
g_bSpuDmaBusy = false;
} else {
ovrld_log(LogCategory::SPU_DMA_STR,
"SPUDmaIntr dma queue is not empty, preparing to run {} ({} pending)",
g_nSpuDmaQueueHead, g_nSpuDmaQueueCount);
// nope, more dma to run
auto* next_xfer = &g_aSpuDmaQueue[g_nSpuDmaQueueHead];
// set up the next interrupt handler
set_dma_intr_handler_hack(channel, SPUDmaIntr, next_xfer->user_data);
// args for the dma transfer
int next_chan = channel;
int next_mode = 0;
const void* next_iop = next_xfer->iop_mem;
u32 next_spu = next_xfer->spu_addr;
u32 next_length = next_xfer->length;
// load up the commands to handle
g_pDmaVagCmd = next_xfer->command;
g_pDmaStereoVagCmd = nullptr;
if (g_pDmaVagCmd) {
g_pDmaStereoVagCmd = g_pDmaVagCmd->stereo_sibling;
}
g_nSpuDmaChunks = next_xfer->num_isobuffered_chunks;
// advance the queue!
g_nSpuDmaQueueCount = g_nSpuDmaQueueCount + -1;
g_nSpuDmaQueueHead = g_nSpuDmaQueueHead + 1;
if (0xf < g_nSpuDmaQueueHead) {
g_nSpuDmaQueueHead = 0;
}
// start the next one!
// set_dma_intr_handler_hack(g_nSpuDmaChannel, SPUDmaIntr, userdata);
voice_trans_wrapper(next_chan, next_mode, next_iop, next_spu, next_length);
}
ovrld_log(LogCategory::SPU_DMA_STR, "SPUDmaIntr exit - end of function");
return 0;
}
/*!
* Start DMA to EE.
*/
void DMA_SendToEE(void* ee_dest,
const void* iop_src,
u32 length,
void callback(void*),
void* callback_arg) {
ASSERT(iop_src);
ASSERT(ee_dest);
ASSERT(((uintptr_t)iop_src & 3) == 0);
ASSERT(((uintptr_t)ee_dest & 0xf) == 0);
ASSERT(length < 0xffff0);
sceSifDmaData cmd; // DMA settings
// setup command
cmd.mode = 0;
cmd.data = iop_src;
cmd.addr = ee_dest;
cmd.size = length;
// instant DMA
// ovrld_log(LogCategory::EE_DMA, "DMA_SendToEE: 0x{:x}, size {}", (u64)ee_dest, length);
sceSifSetDma(&cmd, 1);
// for now, we'll do the callback here, but I bet it will cause problems
if (callback) {
callback(callback_arg);
}
}
/*!
* Start DMA transfer to SPU. Despite the name, this does not actually "sync" - the transfer will
* be ongoing. If there is an ongoing transfer when this is called, the transfer will be queued.
*/
int DMA_SendToSPUAndSync(const u8* iop_mem,
int length,
int spu_addr,
ISO_VAGCommand* cmd,
void* user_data) {
// CpuSuspendIntr(local_28);
int ret = 1;
bool defer = false;
ovrld_log(LogCategory::SPU_DMA_STR,
"DMA to SPU requested for {}, {} bytes to 0x{:x}, currently busy? {}",
cmd ? cmd->name : "NO-CMD", length, spu_addr, g_bSpuDmaBusy);
if (g_bSpuDmaBusy == 0) {
// not busy, we can actually start dma now.
g_nSpuDmaChannel = snd_GetFreeSPUDMA();
if (g_nSpuDmaChannel == -1) {
return 0;
}
// set globals for DMA processing
if (cmd) {
g_nSpuDmaChunks = cmd->num_isobuffered_chunks;
g_pDmaStereoVagCmd = cmd->stereo_sibling;
g_pDmaVagCmd = cmd;
}
} else {
// busy, need to queue the dma
ASSERT(g_nSpuDmaQueueCount <= (int)g_aSpuDmaQueue.size());
// set values:
g_aSpuDmaQueue[g_nSpuDmaQueueTail].length = length;
g_aSpuDmaQueue[g_nSpuDmaQueueTail].spu_addr = spu_addr;
g_aSpuDmaQueue[g_nSpuDmaQueueTail].user_data = user_data;
g_aSpuDmaQueue[g_nSpuDmaQueueTail].num_isobuffered_chunks =
cmd ? cmd->num_isobuffered_chunks : 0;
g_aSpuDmaQueue[g_nSpuDmaQueueTail].command = cmd;
g_aSpuDmaQueue[g_nSpuDmaQueueTail].iop_mem = iop_mem;
g_nSpuDmaQueueCount = g_nSpuDmaQueueCount + 1;
g_nSpuDmaQueueTail = g_nSpuDmaQueueTail + 1;
if (0xf < g_nSpuDmaQueueTail) {
g_nSpuDmaQueueTail = 0;
}
defer = true;
}
// set up the stereo command
if (cmd) {
cmd->safe_to_modify_dma = 0;
auto* stereo = cmd->stereo_sibling;
if (stereo) {
stereo->num_isobuffered_chunks = cmd->num_isobuffered_chunks;
stereo->dma_iop_mem_ptr = iop_mem + length;
cmd->dma_chan = g_nSpuDmaChannel;
stereo->xfer_size = length;
}
}
// kick off dma, if we decided not to queue.
if (!defer) {
g_bSpuDmaBusy = true;
set_dma_intr_handler_hack(g_nSpuDmaChannel, SPUDmaIntr, user_data);
voice_trans_wrapper(g_nSpuDmaChannel, 0, iop_mem, spu_addr, length);
}
return ret;
}
/*!
* Run a dma transfer that was delayed or dropped.
*/
void RunDeferredVoiceTrans() {
// only if there's a currently happening transfer.
if (g_voiceTransRunning) {
if (GetSystemTimeLow() - g_voiceTransTime > 0x384000) {
ovrld_log(LogCategory::WARN, "DeferredVoiceTrans has detected hung dma... expect problems.");
// original game also check sceSdVoiceTransStatus here, we'll possibly need to mess with this
// if we delay dma completion interrupts...
g_voiceTransRunning = false;
voice_trans_wrapper(g_voiceTransChannel, g_voiceTransMode, g_voiceTransAddr,
g_voiceTransSpuAddr, g_voiceTransSize);
}
}
}
} // namespace jak3
-32
View File
@@ -1,32 +0,0 @@
#pragma once
#include "common/common_types.h"
namespace jak3 {
void jak3_overlord_init_globals_dma();
struct ISO_VAGCommand;
int voice_trans_wrapper(s16 chan, u32 mode, const void* iop_addr, u32 spu_addr, u32 size);
void DMA_SendToEE(void* ee_dest,
const void* iop_src,
u32 length,
void callback(void*),
void* callback_arg);
int DMA_SendToSPUAndSync(const u8* iop_mem,
int length,
int spu_addr,
ISO_VAGCommand* cmd,
void* user_data);
void RunDeferredVoiceTrans();
struct ISO_VAGCommand;
struct DmaQueueEntry {
ISO_VAGCommand* command = nullptr;
const void* iop_mem = nullptr;
u32 spu_addr = 0;
u32 length = 0;
void* user_data = nullptr;
u32 num_isobuffered_chunks = 0;
};
void dma_intr_hack();
} // namespace jak3
-583
View File
@@ -1,583 +0,0 @@
#include "dvd_driver.h"
#include <cstring>
#include <memory>
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "common/util/FileUtil.h"
#include "game/overlord/jak3/isocommon.h"
#include "game/overlord/jak3/overlord.h"
#include "game/sce/iop.h"
namespace jak3 {
using namespace iop;
std::unique_ptr<CDvdDriver> g_DvdDriver;
s32 g_nDvdDriverThread = -1;
void jak3_overlord_init_globals_dvd_driver() {
g_DvdDriver = std::make_unique<CDvdDriver>();
g_nDvdDriverThread = -1;
}
CDvdDriver* get_driver() {
return g_DvdDriver.get();
}
CMsg::CMsg(jak3::CMsg::MsgKind msg) : m_msg(msg) {
m_ret = 1;
m_thread = GetThreadId();
}
int CMsg::send() {
// note: changed from passing data
// and removed corresponding -4 to skip back past the vtable in DVD thread
// (what were they thinking?)
s32 ret = SendMbx(get_driver()->msgbox, this);
if (ret == 0) {
get_driver()->KickDvdThread();
SleepThread();
return m_ret;
}
return ret;
}
// CMsgLock::CMsgLock() : CMsg(CMsg::MsgKind::LOCK) {}
//
// void CMsgLock::handler() {
// get_driver()->Lock();
// m_ret = 0;
// }
// CMsgReadRaw::CMsgReadRaw(jak3::BlockParams* params) : CMsg(CMsg::MsgKind::READ_RAW) {
// m_block_params = *params;
// }
//
// void CMsgReadRaw::handler() {
// m_ret = get_driver()->ReadDirect(&m_block_params);
// }
CMsgCancelRead::CMsgCancelRead(jak3::CDescriptor* desc) : CMsg(CMsg::MsgKind::CANCEL_READ) {
m_desc = desc;
}
void CMsgCancelRead::handler() {
get_driver()->CancelRead(m_desc);
m_ret = 0;
}
u32 DvdThread();
CDvdDriver::CDvdDriver() {
fifo_entry_sema = -1;
current_thread_priority = 0x13;
disk_type = 5;
tray_flag = 1;
// m_nLockCount = 0;
event_flag = -1;
fifo_access_sema = -1;
tray_flag2 = 1;
initialized = 0;
m_nNumFifoEntries = 0;
ring_head = 0;
ring_tail = 0;
read_in_progress = 0;
callback = nullptr;
// locked = false;
trayflag3 = 0;
m_nDvdThreadAccessSemaCount = 0;
memset(ring, 0, sizeof(Block) * 16);
}
void CDvdDriver::Initialize() {
if (!initialized) {
*this = {};
ThreadParam thread_param;
thread_param.attr = 0x2000000;
// mbox_param.option = gDvdDriverThreadOptions; // ???
thread_param.entry = DvdThread;
thread_param.stackSize = 0x800;
thread_param.initPriority = 0x13;
thread_param.option = 0;
strcpy(thread_param.name, "dvd");
// mbox_param.attr = (int)PTR_DvdThread_00015c98; // ???
g_nDvdDriverThread = CreateThread(&thread_param);
ASSERT(g_nDvdDriverThread >= 0);
SemaParam sema_param;
sema_param.attr = 0;
sema_param.init_count = 1;
sema_param.max_count = 1;
sema_param.option = 0;
fifo_access_sema = CreateSema(&sema_param);
ASSERT(fifo_access_sema >= 0);
sema_param.max_count = 0x10;
sema_param.attr = 0;
sema_param.init_count = 0x10;
sema_param.option = 0;
fifo_entry_sema = CreateSema(&sema_param);
ASSERT(fifo_entry_sema >= 0);
MbxParam mbox_param;
mbox_param.attr = 0;
mbox_param.option = 0;
msgbox = CreateMbx(&mbox_param);
ASSERT(msgbox >= 0);
EventFlagParam param;
param.attr = 0;
param.option = 0;
param.init_pattern = 0;
event_flag = CreateEventFlag(&param);
ASSERT(event_flag >= 0);
StartThread(g_nDvdDriverThread, 0); // this...
}
initialized = 1;
}
void CDvdDriver::SetDriverCallback(std::function<void(int)> f) {
callback = f;
}
// GetDriveCallback
// Poll - would kick the thread...
// void CDvdDriver::Lock() {
// ASSERT_NOT_REACHED();
// if (GetThreadId() == g_nDvdDriverThread) {
// m_nLockCount++;
// locked = true;
// // needs break HACK
// needs_break = false;
// } else {
// CMsgLock lock;
// lock.send();
// }
// }
// Read
int CDvdDriver::ReadMultiple(CDescriptor* descriptor,
int* pages_read_out,
BlockParams* params,
int num_blocks,
bool block_if_queue_full) {
*pages_read_out = 0;
s32 ret = 1;
// check block parameters are reasonable
if (ValidateBlockParams(params, num_blocks) != 0) {
bool from_dvd_thread = GetThreadId() == g_nDvdDriverThread;
if (from_dvd_thread) {
// there is a setting to control if this function should block if there are too many
// queued reads. If the is called from the DVD thread, then this would deadlock.
// the original game ignored the block argument, but I'm asserting
block_if_queue_full = 0;
ASSERT_NOT_REACHED();
}
ovrld_log(LogCategory::DRIVER, "[driver] ReadMultiple (from our thread? {}) num_blocks {}",
from_dvd_thread, num_blocks);
ret = 0;
if (0 < num_blocks) {
// loop, until we've done all the requested reads.
do {
s32 acquired_slots = 0;
if (0 < num_blocks) {
// loop to try to get up to num_blocks slots in the fifo
// but, if we get less, we'll take that too
do {
if (PollSema(this->fifo_entry_sema) == -0x1a3)
break;
acquired_slots = acquired_slots + 1;
} while (acquired_slots < num_blocks);
}
ovrld_log(LogCategory::DRIVER, "[driver] ReadMultiple acquired {} slots in ring",
acquired_slots);
// if we are blocking, and we acquired no slots, then we'll wait here until we get one slot.
if ((block_if_queue_full != 0) && (acquired_slots < 1)) {
ovrld_log(LogCategory::DRIVER, "[driver] ring is full, blocking!");
acquired_slots = 1; // the one we'll get from the WaitSema below
do {
} while (WaitSema(fifo_entry_sema) != 0);
}
// lock, now that we've gotten the slots
AcquireFIFOSema(from_dvd_thread);
num_blocks = num_blocks - acquired_slots;
// if we didn't get any slots, bail.
if (acquired_slots < 1) {
ovrld_log(LogCategory::DRIVER, "[driver] ring is full, bailing!");
ReleaseFIFOSema(from_dvd_thread);
if (0 < *pages_read_out) {
KickDvdThread();
}
return 2;
}
// loop, updating the ring for each slot we aquired
do {
auto* slot = ring + ring_tail;
ovrld_log(LogCategory::DRIVER, "[driver] inserting in ring slot {}", ring_tail);
ring_tail++;
if (0xf < ring_tail) {
ring_tail = 0;
}
m_nNumFifoEntries++;
auto* tail = descriptor->m_pTail;
slot->descriptor = descriptor;
slot->params = params[*pages_read_out];
*pages_read_out = (*pages_read_out) + 1;
if (!tail) {
descriptor->m_pHead = slot;
} else {
tail->next = slot;
}
acquired_slots = acquired_slots + -1;
descriptor->m_pTail = slot;
slot->next = nullptr;
} while (acquired_slots != 0);
ReleaseFIFOSema(from_dvd_thread);
KickDvdThread();
ret = 0;
} while (0 < num_blocks);
}
} else {
ASSERT_NOT_REACHED();
}
return ret;
}
void CDvdDriver::CancelRead(jak3::CDescriptor* desc) {
if (GetThreadId() == g_nDvdDriverThread) {
AcquireFIFOSema(true);
if ((read_in_progress != 0) && (ring[ring_head].descriptor == desc)) {
// while (iVar1 = sceCdBreak(), iVar1 == 0) {
// DelayThread(8000);
// sceCdSync(0);
// }
// sceCdSync(0);
read_in_progress = 0;
}
Block* iter = desc->m_pHead;
Block* tail = desc->m_pTail;
while (iter) {
if (iter->descriptor) {
CompletionHandler(iter, 6);
}
iter->descriptor = nullptr;
iter->next = nullptr;
if (iter == tail)
break;
iter = desc->m_pHead;
}
if (desc->m_pTail == tail) {
desc->m_pTail = nullptr;
}
ReleaseFIFOSema(true);
} else {
CMsgCancelRead msg(desc);
msg.send();
}
}
s32 CDvdDriver::ValidateBlockParams(jak3::BlockParams* params, int num_params) {
if (!params) {
lg::die("Invalid BlockParams: nullptr");
return 0;
}
if (num_params < 1) {
lg::die("Invalid BlockParams: size == 0");
return 0;
}
for (int i = 0; i < num_params; i++) {
auto& p = params[i];
if (p.destination == nullptr) {
lg::die("Invalid BlockParams: {} had nullptr dest", i);
return 0;
}
int kMaxSector = 1000000;
if (p.sector_num > kMaxSector) {
// this is just a sanity check - if we ever have larger files this is okay to increase.
lg::die("Invalid BlockParams: {} had sector num {}", i, p.sector_num);
return 0;
}
if (p.num_sectors > 0x1d0) {
lg::die("Invalid BlockParams: {} had sector count {}", i, p.num_sectors);
return 0;
}
if (!p.file_def) {
lg::die("Invalid BlockParams: {} had no file", i);
return 0;
}
}
return 1;
}
void CDvdDriver::KickDvdThread() {
while (SetEventFlag(event_flag, 1)) {
;
}
}
int CDvdDriver::AcquireFIFOSema(bool from_dvd_thread) {
int iVar1;
int iVar2;
if ((from_dvd_thread != 0) &&
(iVar2 = m_nDvdThreadAccessSemaCount, m_nDvdThreadAccessSemaCount = iVar2 + 1, 0 < iVar2)) {
return 0;
}
iVar1 = WaitSema(this->fifo_access_sema);
iVar2 = 0;
if ((iVar1 != 0) && (iVar2 = iVar1, from_dvd_thread != 0)) {
m_nDvdThreadAccessSemaCount = m_nDvdThreadAccessSemaCount + -1;
iVar2 = iVar1;
}
return iVar2;
}
int CDvdDriver::ReleaseFIFOSema(bool from_dvd_thread) {
int iVar1;
int iVar2;
if (from_dvd_thread != 0) {
iVar2 = m_nDvdThreadAccessSemaCount + -1;
if (m_nDvdThreadAccessSemaCount < 1) {
return -0x1a4;
}
m_nDvdThreadAccessSemaCount = iVar2;
if (0 < iVar2) {
return 0;
}
}
iVar1 = SignalSema(fifo_access_sema);
iVar2 = 0;
if ((iVar1 != 0) && (iVar2 = iVar1, from_dvd_thread != 0)) {
m_nDvdThreadAccessSemaCount = m_nDvdThreadAccessSemaCount + 1;
iVar2 = iVar1;
}
return iVar2;
}
/*!
* PC port added function to actually do a read of a block.
*/
void CDvdDriver::read_from_file(const jak3::Block* block) {
const auto* fd = block->params.file_def;
ASSERT(fd);
FileCacheEntry* selected_entry = nullptr;
// get a cache entry
for (auto& entry : m_file_cache) {
// if we already opened this file, use that
if (entry.def == fd) {
selected_entry = &entry;
break;
}
// otherwise pick the least recently used
if (!selected_entry) {
selected_entry = &entry;
} else {
if (selected_entry->last_use_count > entry.last_use_count) {
selected_entry = &entry;
}
}
}
// open a new file if needed
if (selected_entry->def != fd) {
lg::debug("CDvdDriver swapping files {} - > {}",
selected_entry->def ? selected_entry->def->name.data : "NONE", fd->name.data);
if (selected_entry->def) {
fclose(selected_entry->fp);
}
selected_entry->def = fd;
selected_entry->fp = file_util::open_file(fd->full_path, "rb");
if (!selected_entry->fp) {
lg::die("Failed to open {} {}", fd->full_path, strerror(errno));
}
selected_entry->offset_in_file = 0;
}
// increment use counter
selected_entry->last_use_count = m_file_cache_counter++;
const u64 desired_offset = block->params.sector_num * 0x800;
// see if we're reading entirely past the end of the file
if (desired_offset >= fd->length) {
return;
}
if (selected_entry->offset_in_file != desired_offset) {
lg::debug("CDvdDriver jumping in file {}: {} -> {}", fd->name.data,
selected_entry->offset_in_file, desired_offset);
if (fseek(selected_entry->fp, desired_offset, SEEK_SET)) {
ASSERT_NOT_REACHED_MSG("Failed to fseek");
}
selected_entry->offset_in_file = desired_offset;
}
// read
s64 read_length = block->params.num_sectors * 0x800;
s64 extra_length = read_length + desired_offset - fd->length;
if (extra_length > 0) {
read_length -= extra_length;
}
auto ret = fread(block->params.destination, read_length, 1, selected_entry->fp);
if (ret != 1) {
lg::die("Failed to read {} {}, size {} of {} (ret {})", fd->full_path, strerror(errno),
read_length, fd->length, ret);
}
selected_entry->offset_in_file += read_length;
}
u32 DvdThread() {
auto* driver = get_driver();
while (true) {
// Poll for messages
CMsg* msg = nullptr;
while (true) {
int poll_status = PollMbx((MsgPacket**)&msg, driver->msgbox);
if (poll_status || !msg) {
break;
}
// run message code
msg->handler();
// wake the waiting thread.
WakeupThread(msg->m_thread);
}
bool completed = false;
// if a read is in progress, wait for it to finish.
if (driver->read_in_progress) {
// TODO: if we switch to async reads, this is where we'd want to sync.
// sceCdSync(0);
completed = true;
// error checking
}
driver->AcquireFIFOSema(true);
// error handling
// handle ring book-keeping.
// note that these are somewhat double-buffered - we'll sync on read i-1, start read i, then
// run the completion handler for read i - 1.
// the completion is what actually removes stuff from the ring.
s32 fifo_slots_freed = completed ? 1 : 0;
s32 ring_entry = driver->ring_head + (completed ? 1 : 0);
if (ring_entry > 15) {
ring_entry = 0;
}
Block* block = driver->ring + ring_entry;
s32 fifo_entries = driver->m_nNumFifoEntries - fifo_slots_freed;
if (fifo_entries) {
// start a new read.
driver->read_in_progress = 1;
ovrld_log(LogCategory::DRIVER, "[driver thread] Reading for slot {}", block - driver->ring);
driver->read_from_file(block);
} else {
driver->read_in_progress = 0;
}
// run completion handler for the previous read - not the one we just started!
Block sblock;
if (completed) {
auto* last_block = &driver->ring[driver->ring_head];
ovrld_log(LogCategory::DRIVER, "[driver thread] Completion handler for {}",
driver->ring_head);
sblock = *last_block;
if (sblock.descriptor && sblock.descriptor->m_pHead) {
ASSERT(sblock.descriptor->m_pHead == last_block);
}
if (((sblock.descriptor)->m_pHead == last_block) &&
((sblock.descriptor)->m_pHead = &sblock, (sblock.descriptor)->m_pTail == last_block)) {
(sblock.descriptor)->m_pTail = &sblock;
}
}
driver->ring_head = ring_entry;
driver->m_nNumFifoEntries = fifo_entries;
while (0 < fifo_slots_freed) {
fifo_slots_freed = fifo_slots_freed + -1;
SignalSema(driver->fifo_entry_sema);
}
if (completed != 0) {
driver->CompletionHandler(&sblock, 0);
}
driver->ReleaseFIFOSema(true);
// this logic here was modified - we go to waiting if we have no more reads.
if (driver->m_nNumFifoEntries == 0) {
ovrld_log(LogCategory::DRIVER, "[driver thread] No work, waiting.");
WaitEventFlag(driver->event_flag, 1, 0x11);
ovrld_log(LogCategory::DRIVER, "[driver thread] Woken up!");
}
// s32 status;
// if ((((driver->locked != false)) ||
// ((driver->needs_break == 0 && (driver->m_nNumFifoEntries == 0)))) &&
// ((status = WaitEventFlag(driver->event_flag, 1, 0x11),
// status != 0 && (status != -0x1a2)))) {
// if (status == -0x1a9) {
// do {
// SleepThread();
// } while (true);
// }
// DelayThread(8000);
// }
}
}
void CDvdDriver::CompletionHandler(jak3::Block* block, int code) {
// there is some janky thread priority changes here,
// but they do not seem to be needed with the changes to the ISO thread.
// PushPri(this,local_20,0x35);
auto* desc = block->descriptor;
if (desc && desc->m_pHead) {
desc->m_status = code;
int thread = desc->m_ThreadID;
if (desc->m_Callback) {
(desc->m_Callback)(desc->m_File, block, code);
}
if (0 < thread) {
WakeupThread(thread);
}
Block* next;
if ((desc->m_pHead == block) && (next = block->next, desc->m_pHead = next, next == nullptr)) {
desc->m_pTail = nullptr;
}
}
block->next = nullptr;
block->descriptor = nullptr;
// PopPri(this, local_20[0]);
}
CDvdDriver::~CDvdDriver() {
for (auto& entry : m_file_cache) {
if (entry.fp) {
fclose(entry.fp);
}
}
}
} // namespace jak3
-144
View File
@@ -1,144 +0,0 @@
#pragma once
#include <functional>
#include "common/common_types.h"
#include "game/overlord/jak3/isocommon.h"
namespace jak3 {
void jak3_overlord_init_globals_dvd_driver();
/*!
* The DVD Driver is what actually called the Sony CD library functions.
* It also had many special cases for handling errors, open trays, retries, etc that are not
* recreated in this port.
*
* The original DVD driver thread didn't run the actual reads - the Sony CD library had its own
* threads for async reads. However, they would call sceCdSync() to wait until a read finished.
* It's not clear if sceCdSync would allow other threads to run while waiting on the read to finish.
* but if it did, this is a bit of a difference in the blocking behavior.
*
* This is something that could be revisited, as freads will now essentially block the entire
* overlord, including refilling sound RAM.
*/
struct CDescriptor;
struct BlockParams;
struct CPage;
struct ISOFileDef;
// The CMSG system is used to pass messages from external threads to the driver. It's mostly used
// internally by the driver, when functions are called on it from outside threads. In these cases
// the Cmsg will get send to the driver thread and handler will run on it here.
struct CMsg {
enum class MsgKind {
// LOCK = 0,
READ_RAW = 1,
CANCEL_READ = 2,
};
CMsg(MsgKind msg);
virtual int send();
virtual void handler() = 0;
u8 data[8];
MsgKind m_msg;
int m_thread;
int m_ret;
};
// struct CMsgLock : public CMsg {
// CMsgLock();
// void handler() override;
// };
// struct CMsgReadRaw : public CMsg {
// explicit CMsgReadRaw(BlockParams* params);
// void handler() override;
// BlockParams m_block_params;
// };
struct CMsgCancelRead : public CMsg {
explicit CMsgCancelRead(CDescriptor* desc);
void handler() override;
CDescriptor* m_desc;
};
struct CISOCDFile;
/*!
* Reference to an ongoing or requested read at the driver level, possibly made up of multiple
* blocks. In this case, the head/tail pointers point to Blocks stored inside the CDvdDriver's
* internal FIFO.
*/
struct CDescriptor {
CDescriptor() = default;
int m_unk0 = 0;
void (*m_Callback)(CISOCDFile*, Block*, s32) = nullptr;
int m_ThreadID = 0;
int m_status = 0;
CISOCDFile* m_File = nullptr;
Block* m_pHead = nullptr;
Block* m_pTail = nullptr;
};
class CDvdDriver {
public:
CDvdDriver();
~CDvdDriver();
void Initialize();
void CancelRead(CDescriptor* descriptor);
int ReadMultiple(CDescriptor* descriptor,
int* pages_read_out,
BlockParams* params,
int num_pages,
bool block_if_queue_full);
void SetDriverCallback(std::function<void(int)> f);
// int ReadDirect(BlockParams* params);
void KickDvdThread();
// void Lock();
int GetDiskType() const { return disk_type; }
s32 ValidateBlockParams(BlockParams* params, int num_params);
int ReleaseFIFOSema(bool from_dvd_thread);
int AcquireFIFOSema(bool from_dvd_thread);
void read_from_file(const Block* block);
void CompletionHandler(Block* block, int code);
u8 initialized = 0;
s32 event_flag = -1;
s32 fifo_access_sema = -1;
s32 fifo_entry_sema = -1;
s32 msgbox = -1;
s32 m_nNumFifoEntries = 0;
s32 ring_head = 0;
s32 ring_tail = 0;
Block ring[16];
u8 read_in_progress; // more likely: read in progress
std::function<void(int)> callback;
s32 current_thread_priority = 0;
// s32 m_nLockCount = 0;
// bool locked = false;
//
s32 disk_type;
u8 tray_flag2;
u8 trayflag3;
u8 tray_flag;
s32 m_nDvdThreadAccessSemaCount = 0;
private:
struct FileCacheEntry {
const ISOFileDef* def = nullptr;
FILE* fp = nullptr;
u32 last_use_count = 0;
u64 offset_in_file = 0;
};
u32 m_file_cache_counter = 0;
static constexpr int kNumFileCacheEntries = 6;
FileCacheEntry m_file_cache[kNumFileCacheEntries];
};
// replacement for g_DvdDriver
CDvdDriver* get_driver();
} // namespace jak3
-50
View File
@@ -1,50 +0,0 @@
#include "game/overlord/jak3/basefile.h"
#include "game/overlord/jak3/basefilesystem.h"
#include "game/overlord/jak3/dma.h"
#include "game/overlord/jak3/dvd_driver.h"
#include "game/overlord/jak3/iso.h"
#include "game/overlord/jak3/iso_api.h"
#include "game/overlord/jak3/iso_cd.h"
#include "game/overlord/jak3/iso_queue.h"
#include "game/overlord/jak3/isocommon.h"
#include "game/overlord/jak3/list.h"
#include "game/overlord/jak3/overlord.h"
#include "game/overlord/jak3/pagemanager.h"
#include "game/overlord/jak3/ramdisk.h"
#include "game/overlord/jak3/sbank.h"
#include "game/overlord/jak3/soundcommon.h"
#include "game/overlord/jak3/spustreams.h"
#include "game/overlord/jak3/srpc.h"
#include "game/overlord/jak3/ssound.h"
#include "game/overlord/jak3/stream.h"
#include "game/overlord/jak3/streamlist.h"
#include "game/overlord/jak3/vag.h"
#include "game/overlord/jak3/vblank_handler.h"
namespace jak3 {
void jak3_overlord_init_globals_all() {
jak3_overlord_init_globals_overlord();
jak3_overlord_init_globals_pagemanager();
jak3_overlord_init_globals_iso_cd();
jak3_overlord_init_globals_dma();
jak3_overlord_init_globals_iso();
jak3_overlord_init_globals_iso_queue();
jak3_overlord_init_globals_srpc();
jak3_overlord_init_globals_vag();
jak3_overlord_init_globals_ssound();
jak3_overlord_init_globals_iso_api();
jak3_overlord_init_globals_spustreams();
jak3_overlord_init_globals_list();
jak3_overlord_init_globals_vblank_handler();
jak3_overlord_init_globals_dvd_driver();
jak3_overlord_init_globals_basefile();
jak3_overlord_init_globals_basefilesystem();
jak3_overlord_init_globals_ramdisk();
jak3_overlord_init_globals_isocommon();
jak3_overlord_init_globals_stream();
jak3_overlord_init_globals_sbank();
jak3_overlord_init_globals_soundcommon();
jak3_overlord_init_globals_streamlist();
}
} // namespace jak3
-5
View File
@@ -1,5 +0,0 @@
#pragma once
namespace jak3 {
void jak3_overlord_init_globals_all();
}
File diff suppressed because it is too large. Load diff
-92
View File
@@ -1,92 +0,0 @@
#pragma once
#include "common/link_types.h"
#include "game/overlord/jak3/isocommon.h"
namespace jak3 {
struct ISOFileDef;
void jak3_overlord_init_globals_iso();
void InitISOFS();
const ISOFileDef* FindISOFile(const char*);
struct ISO_VAGCommand;
struct VagStreamData;
struct RPC_Dgo_Cmd;
struct ISO_DGOCommand : public ISO_Hdr {
u8* buffer1 = nullptr;
u8* buffer2 = nullptr;
u8* buffer_top = nullptr;
DgoHeader dgo_header; //
ObjectHeader obj_header; //
u8* ee_dest_buffer = nullptr; // 192
int bytes_processed = 0; // 196
int objects_loaded = 0; // 200
enum class State {
INIT = 0,
READ_DGO_HEADER = 1,
FINISH_OBJ = 2,
READ_LAST_OBJ = 3,
READ_OBJ_HEADER = 4,
READ_OBJ_DATA = 5,
FINISH_DGO = 6,
FINISH_OBJ_SINGLE_BUFFER = 7,
} state = State::INIT; // 204
int finished_first_object = 0; // 208
int buffer_toggle = 0; // 212
u8* selected_buffer = nullptr; // 216
int selected_id = 0; // 220
int last_id = 0; // 224
int acked_cancel_id = 0; // 228
u8 nosync_cancel_pending_flag = 0; // 232
int request_cancel_id = 0; // 236
u8 nosync_cancel_ack = 0; // 240
int sync_sent_count = 0; // 244
// the number of times we looked in the iso thread's sync mbox
// I think just used for debugging/asserts.
int sync_mbox_wait_count = 0; // 248
int sync_ret_count = 0; // 252
int want_abort = 0; // 256
};
enum class CopyKind {
EE = 0,
IOP = 1,
SBK = 2,
};
void set_active_a(ISO_Hdr* cmd, int val);
void set_active_b(ISO_Hdr* cmd, int val);
void set_active_c(ISO_Hdr* cmd, int val);
void IsoStopVagStream(ISO_VAGCommand* cmd);
void IsoPlayVagStream(ISO_VAGCommand* user_cmd);
EIsoStatus NullCallback(ISO_Hdr* msg);
EIsoStatus CopyDataToIOP(ISO_Hdr* msg);
EIsoStatus CopyDataSbkLoad(ISO_Hdr* msg);
EIsoStatus CopyDataToEE(ISO_Hdr* msg);
EIsoStatus RunDGOStateMachine(ISO_Hdr* msg);
void QueueVAGStream(VagStreamData* cmd);
void CopyDataDmaCallback(void*);
void* RPC_DGO(unsigned int fno, void* msg_ptr, int);
void LoadDGO(RPC_Dgo_Cmd* cmd);
void CancelDGO(RPC_Dgo_Cmd* cmd);
void LoadNextDGO(RPC_Dgo_Cmd* cmd);
EIsoStatus CopyData(ISO_LoadCommon* msg, CopyKind kind);
void CancelDGONoSync(int id);
void IsoPlayMusicStream(ISO_VAGCommand* user_cmd);
void IsoQueueVagStream(ISO_VAGCommand* user_cmd);
extern int g_nISOThreadID;
extern int g_nISOMbx;
extern bool g_bMusicPause;
extern int g_nMusicSemaphore;
extern char g_szTargetMusicName[0x30];
extern int g_nActiveMusicStreams;
extern bool g_bVagCmdsInitialized;
extern bool g_bMusicIsPaused;
extern bool g_bAnotherMusicPauseFlag;
extern int g_nMusicFade;
extern int g_nMusicTweak;
extern int g_nMusicFadeDir;
} // namespace jak3
-229
View File
@@ -1,229 +0,0 @@
#include "iso_api.h"
#include <cstring>
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "common/util/FileUtil.h"
#include "game/overlord/jak3/iso.h"
#include "game/overlord/jak3/iso_cd.h"
#include "game/overlord/jak3/iso_queue.h"
#include "game/overlord/jak3/srpc.h"
#include "game/overlord/jak3/vag.h"
#include "game/sce/iop.h"
namespace jak3 {
using namespace iop;
void jak3_overlord_init_globals_iso_api() {}
/*!
* This file is the "API" that implementations of RPCs or other code can use to submit things to the
* ISO thread. Note that not all RPCs use this API - for example the DGO RPC just manually submits
* messages. Generally, these functions will not return until the actual action is complete, like a
* file is loaded.
* - except for messages to pause/play audio, those functions will return immediately, but there may
* be a delay until they are actually processed.
*/
// PluginVagAndVagWad not ported.
u32 EEVagAndVagWad(ISO_VAGCommand* cmd, char* name) {
ISOName name_buff;
if (*name == '$' || strlen(name) < 9) {
if (*name == '$') {
name++;
}
MakeISOName(&name_buff, name);
} else {
file_util::ISONameFromAnimationName(name_buff.data, name);
}
cmd->vag_dir_entry = get_file_system()->FindVAGFile(name_buff.data);
if (cmd->vag_dir_entry) {
memcpy(name_buff.data, "VAGWAD ", 8);
strncpy(name_buff.data + 8, g_pszLanguage, 4);
auto* file_def = get_file_system()->FindIN(&name_buff);
// piVar1 = g_pFileSystem;
cmd->file_def = file_def;
strncpy(name_buff.data + 8, "INT", 4);
cmd->vag_file_def = get_file_system()->FindIN(&name_buff);
if (cmd->vag_dir_entry && cmd->file_def && cmd->vag_file_def) {
return 1;
}
}
cmd->vag_dir_entry = nullptr;
cmd->file_def = nullptr;
cmd->vag_file_def = nullptr;
return 0;
}
int LoadISOFileToIOP(const ISOFileDef* file_def, void* addr, int length) {
ISO_LoadSingle cmd;
cmd.msg_type = ISO_Hdr::MsgType::LOAD_IOP;
cmd.mbox_reply = 0;
cmd.thread_to_wake = GetThreadId();
cmd.file_def = file_def;
cmd.addr = (u8*)addr;
cmd.maxlen = length;
lg::warn("--------------- LoadISOFileToIOP START");
SendMbx(g_nISOMbx, &cmd);
SleepThread();
lg::warn("--------------- LoadISOFileToIOP END");
if (cmd.status == EIsoStatus::NONE_0) {
return cmd.length_to_copy;
} else {
return 0;
}
}
int LoadISOFileToEE(const ISOFileDef* file_def, u32 addr, int length) {
ISO_LoadSingle cmd;
cmd.msg_type = ISO_Hdr::MsgType::LOAD_EE;
cmd.mbox_reply = 0;
cmd.thread_to_wake = GetThreadId();
cmd.file_def = file_def;
cmd.addr = (u8*)(u64)addr;
cmd.maxlen = length;
lg::warn("--------------- LoadISOFileToEE START");
SendMbx(g_nISOMbx, &cmd);
SleepThread();
lg::warn("--------------- LoadISOFileToEE END");
if (cmd.status == EIsoStatus::NONE_0) {
return cmd.length_to_copy;
}
return 0;
}
int LoadISOFileChunkToEE(const ISOFileDef* file_def, u32 addr, int max_len, int sector_offset) {
ISO_LoadSingle cmd;
cmd.msg_type = ISO_Hdr::MsgType::LOAD_EE_CHUNK;
cmd.mbox_reply = 0;
cmd.thread_to_wake = GetThreadId();
cmd.file_def = file_def;
cmd.addr = (u8*)(u64)addr;
cmd.maxlen = max_len;
cmd.sector_offset = sector_offset;
lg::warn("--------------- LoadISOFileChunkToEE START");
SendMbx(g_nISOMbx, &cmd);
SleepThread();
lg::warn("--------------- LoadISOFileChunkToEE END");
if (cmd.status == EIsoStatus::NONE_0) {
return cmd.length_to_copy;
}
return 0;
}
u32 LoadSoundBankToIOP(const char* name, SoundBankInfo* bank, u32 mode) {
ISO_LoadSoundbank cmd;
cmd.msg_type = ISO_Hdr::MsgType::LOAD_SOUNDBANK;
cmd.mbox_reply = 0;
cmd.thread_to_wake = GetThreadId();
cmd.bank_info = bank;
cmd.name = name;
cmd.priority = mode;
lg::warn("--------------- LoadSoundBankToIOP START");
SendMbx(g_nISOMbx, &cmd);
SleepThread();
lg::warn("--------------- LoadSoundBankToIOP END");
return (u32)cmd.status;
}
void PlayMusicStream(VagStreamData* stream) {
int iVar1;
ISO_VAGCommand cmd;
cmd.msg_type = ISO_Hdr::MsgType::PLAY_MUSIC_STREAM;
cmd.mbox_reply = 0;
cmd.thread_to_wake = 0;
iVar1 = EEVagAndVagWad(&cmd, stream->name);
if (iVar1 == 0) {
// if (bWarn == 0) {
// bWarn = 1;
// }
} else {
cmd.play_volume = 0x400;
// bWarn = 0;
strncpy(cmd.name, stream->name, 0x30);
cmd.id = stream->id;
cmd.priority_pq = 9;
cmd.music_flag = 1;
cmd.maybe_sound_handler = 0;
cmd.plugin_id = 0;
cmd.art_flag = 0;
cmd.movie_flag = 0;
cmd.updated_trans = 0;
IsoPlayMusicStream(&cmd);
}
}
void QueueVAGStream(VagStreamData* stream) {
bool bVar1;
bool bVar2;
ISO_VAGCommand cmd;
cmd.msg_type = ISO_Hdr::MsgType::VAG_QUEUE;
cmd.mbox_reply = 0;
cmd.thread_to_wake = 0;
if (stream->sound_handler == 0) {
EEVagAndVagWad(&cmd, stream->name);
cmd.play_volume = 0x400;
cmd.play_group = 2;
} else {
ASSERT_NOT_REACHED();
// PluginVagAndVagWad(&cmd,stream);
// cmd.play_volume = stream->maybe_volume2;
// cmd.oog = stream->maybe_volume_3;
// cmd.play_group = stream->group;
}
strncpy(cmd.name, stream->name, 0x30);
cmd.id = stream->id;
cmd.plugin_id = stream->plugin_id;
cmd.priority_pq = stream->priority;
cmd.maybe_sound_handler = stream->sound_handler;
bVar1 = stream->movie_art_load != 0;
cmd.movie_flag = bVar1;
bVar2 = stream->art_load != 0;
cmd.art_flag = bVar2;
cmd.music_flag = 0;
if (bVar2) {
cmd.flags.art = 1;
}
if (bVar1) {
cmd.flags.movie = 1;
}
cmd.updated_trans = 0;
IsoQueueVagStream(&cmd);
}
void PauseVAGStreams() {
auto* cmd = GetVAGCommand();
cmd->msg_type = ISO_Hdr::MsgType::VAG_PAUSE;
cmd->mbox_reply = 0;
cmd->thread_to_wake = 0;
SendMbx(g_nISOMbx, cmd);
}
void UnpauseVAGStreams() {
auto* cmd = GetVAGCommand();
cmd->msg_type = ISO_Hdr::MsgType::VAG_UNPAUSE;
cmd->mbox_reply = 0;
cmd->thread_to_wake = 0;
SendMbx(g_nISOMbx, cmd);
}
void SetVAGStreamPitch(int id, int pitch) {
auto* cmd = GetVAGCommand();
cmd->msg_type = ISO_Hdr::MsgType::VAG_SET_PITCH_VOL;
cmd->id = id;
cmd->pitch_cmd = pitch;
cmd->mbox_reply = 0;
cmd->thread_to_wake = 0;
SendMbx(g_nISOMbx, cmd);
}
} // namespace jak3
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include "common/common_types.h"
namespace jak3 {
void jak3_overlord_init_globals_iso_api();
struct ISOFileDef;
struct VagStreamData;
struct SoundBankInfo;
int LoadISOFileToEE(const ISOFileDef* file_def, u32 addr, int length);
int LoadISOFileToIOP(const ISOFileDef* file_def, void* addr, int length);
void PlayMusicStream(VagStreamData* data);
int LoadISOFileChunkToEE(const ISOFileDef* file_def, u32 addr, int max_len, int sector_offset);
void SetVAGStreamPitch(s32 id, s32 pitch);
void UnpauseVAGStreams();
u32 LoadSoundBankToIOP(const char* name, SoundBankInfo* bank, u32 mode);
} // namespace jak3
-529
View File
@@ -1,529 +0,0 @@
#include "iso_cd.h"
#include <vector>
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "common/util/FileUtil.h"
#include "game/overlord/jak3/iso.h"
#include "game/overlord/jak3/isocommon.h"
#include "game/overlord/jak3/overlord.h"
#include "game/overlord/jak3/spustreams.h"
#include "game/sce/iop.h"
using namespace iop;
namespace jak3 {
VagDir g_VagDir;
MusicTweaks gMusicTweakInfo;
CISOCDFile g_CISOCDFiles[kMaxOpenFiles];
namespace {
CISOCDFile* g_pReadInfo = nullptr;
std::vector<ISOFileDef> g_FileDefs;
std::unique_ptr<CISOCDFileSystem> g_ISOCDFileSystem;
} // namespace
void jak3_overlord_init_globals_iso_cd() {
g_pReadInfo = nullptr;
for (auto& f : g_CISOCDFiles) {
f = CISOCDFile();
}
g_FileDefs.clear();
g_VagDir = {};
g_ISOCDFileSystem = std::make_unique<CISOCDFileSystem>();
gMusicTweakInfo = {};
}
CBaseFileSystem* get_file_system() {
return g_ISOCDFileSystem.get();
}
CISOCDFile::CISOCDFile() {
m_nSector = -1;
m_nLoaded = 0;
m_nLength = 0;
}
namespace {
void ReadPagesCallbackF(CISOCDFile* file, Block* block, s32 error) {
file->ReadPagesCallback(block, error);
}
} // namespace
CISOCDFile::CISOCDFile(const jak3::ISOFileDef* filedef, s32 process_data_semaphore)
: CBaseFile(filedef, process_data_semaphore) {
m_nSector = -1;
m_nLoaded = 0;
m_nLength = 0;
m_Descriptor.m_File = this;
m_Descriptor.m_Callback = ReadPagesCallbackF;
}
/*!
* Call ReadPages to read data from this file into its PageList. I believe that the read
* is finished after this function returns. Note that this returns COMPLETE enum in many cases, both
* if the read succeeds, or if the read is not attempted for some reasons.
*/
EIsoStatus CISOCDFile::BeginRead() {
ASSERT(m_Buffer.m_pPageList);
ASSERT(m_Buffer.m_eBufferType != CBuffer::BufferType::EBT_FREE);
if (m_Status == EIsoStatus::NONE_0) {
return EIsoStatus::ERROR_b;
}
if (m_Status == EIsoStatus::OK_2) {
return EIsoStatus::OK_2;
}
ASSERT(m_Status == EIsoStatus::IDLE_1);
auto* plist = m_Buffer.m_pPageList;
// how many pages are in our list, but not filled?
int num_pages_desired = plist->m_nNumPages - plist->m_nNumActivePages;
if (!num_pages_desired) {
// no space to read
return EIsoStatus::OK_2;
}
// convert pages to active, indicating that a read will attempt to fill them:
auto* first_page = plist->AddActivePages(num_pages_desired);
if (!first_page) {
lg::warn("Failed to add {} active pages", num_pages_desired);
}
// convert buffer type - ??
switch (m_Buffer.m_eBufferType) {
case CBuffer::BufferType::EBT_FREE:
ASSERT_NOT_REACHED();
case CBuffer::BufferType::NORMAL:
m_Buffer.m_eBufferType = CBuffer::BufferType::REQUEST_NORMAL;
break;
case CBuffer::BufferType::VAG:
m_Buffer.m_eBufferType = CBuffer::BufferType::REQUEST_VAG;
break;
case CBuffer::BufferType::REQUEST_NORMAL:
case CBuffer::BufferType::REQUEST_VAG:
break;
}
m_Status = EIsoStatus::OK_2;
// remember this as our currently reading file
g_pReadInfo = this;
if (m_FileKind != CBaseFile::Kind::LZO_COMPRESSED) {
if (m_nLength == 0 || m_nLoaded < m_nLength) {
ovrld_log(LogCategory::PAGING, "Calling ReadPages: sector {}, pages {}", m_nSector,
num_pages_desired);
ReadPages(m_nSector, first_page, num_pages_desired, nullptr, true);
int bytes = 0x8000 * num_pages_desired;
m_nLoaded += bytes;
m_Buffer.AddData(bytes);
m_nSector += bytes >> 0xb;
}
} else {
ASSERT_NOT_REACHED();
}
return EIsoStatus::OK_2;
}
/*!
* Called by ?? to indicate that the read is done.
*/
EIsoStatus CISOCDFile::SyncRead() {
if (m_Status != EIsoStatus::IDLE_1 && g_pReadInfo) {
if (m_Status == EIsoStatus::OK_2) {
m_Status = EIsoStatus::IDLE_1;
}
g_pReadInfo = nullptr;
return EIsoStatus::OK_2;
}
return EIsoStatus::ERROR_b;
}
/*!
* As soon as possible, stop ongoing reads and free buffers.
*/
void CISOCDFile::Close() {
// cancel ongoing reading in the driver
get_driver()->CancelRead(&m_Descriptor);
ASSERT(m_FileKind != CBaseFile::Kind::LZO_COMPRESSED); // unsupported in pc
if (this == g_pReadInfo) {
g_pReadInfo = nullptr;
}
if (m_Buffer.m_eBufferType != CBuffer::BufferType::EBT_FREE) {
TerminateBuffer();
}
// reset self
*this = CISOCDFile();
}
/*!
* In the case where we have run out of page memory, take pages that we have loaded, but aren't yet
* using, and discard them back to the pool.
*/
int CISOCDFile::RecoverPages(int num_pages_desired) {
// we only allow ourselves to recover pages for VAG streaming.
if (!m_Buffer.m_pIsoCmd || m_Buffer.m_pIsoCmd->callback != ProcessVAGData) {
return 0;
}
// lock semaphore for processing
ASSERT(m_ProcessDataSemaphore != -1);
WaitSema(m_ProcessDataSemaphore);
auto* plist = m_Buffer.m_pPageList;
int num_removed = 0;
if (plist) {
int pages_to_ask_for = plist->m_nNumUnsteppedPages;
if (pages_to_ask_for > 1) {
// don't ask for more than user asked for
if (pages_to_ask_for > num_pages_desired) {
pages_to_ask_for = num_pages_desired;
}
num_removed = plist->RemoveActivePages(pages_to_ask_for);
if (num_removed) {
m_nSector -= 0x10 * num_removed;
m_nLoaded -= 0x8000 * num_removed;
// suspend intr
ASSERT(m_Buffer.m_nDataLength >= 0);
if (m_Buffer.m_nDataLength > 0) {
m_Buffer.AddData(-num_removed * 0x8000);
}
// resume intr
ASSERT(m_nLoaded >= 0);
}
}
}
// move our reading pointer back.
m_PageOffset -= num_removed;
// unlock processing
SignalSema(m_ProcessDataSemaphore);
return num_removed;
}
/*!
* Get the next sector to read.
*/
int CISOCDFile::GetSector() {
return m_nSector;
}
// WaitForLZOPages - not ported.
void CISOCDFile::ReadPages(int sector,
jak3::CPage* destination_page,
int num_pages,
char* done_flag_ptr,
bool sleep_until_done) {
ASSERT(destination_page);
ASSERT(num_pages >= 1);
constexpr int kMaxPages = 24;
// I _think_ this might have been an alloca...
BlockParams params_array[kMaxPages];
ASSERT(num_pages <= kMaxPages);
// iVar2 = -((num_pages + -1) * 0x14 + 0x1bU & 0xfffffff8);
// params = (BlockParams*)((int)local_30 + iVar2);
BlockParams* params = params_array;
// increment our progress in the file - the distributed update of the various progress integers
// is somewhat confusing, especially since failures here don't seem to reset it properly.
m_PageOffset += num_pages;
// Set up block params for each page to read
CPage* page = destination_page;
int pg_remaining = num_pages;
do {
page->input_state = CPage::State::READING;
ClearEventFlag(get_page_manager()->m_CCache.m_PagesFilledEventFlag, ~page->mask);
params->destination = page->m_pPageMemStart;
params->num_sectors = 0x10;
params->sector_num = sector;
params->file_def = m_FileDef;
params->page = page;
params->flag = nullptr;
if (pg_remaining == 1) { // on the last page...
params->flag = (char*)0xffffffff; // flag this
if (!sleep_until_done) {
params->flag = done_flag_ptr;
}
}
ovrld_log(LogCategory::PAGING, "[paging] building block for driver: 0x{:x}, {}, {}, flag: {}",
(u64)params->destination, params->sector_num, params->file_def->name.data,
(u64)params->flag);
page = page->m_pNextPage;
pg_remaining = pg_remaining + -1;
sector += 0x10;
params++;
} while (page && pg_remaining > 0);
if (pg_remaining == 0) {
// we set up block params for all the requested pages.
int pages_actually_read = -1;
ovrld_log(LogCategory::PAGING, "[paging] Submitting {} blocks to driver.\n", num_pages);
int status = get_driver()->ReadMultiple(&m_Descriptor, &pages_actually_read, params_array,
num_pages, true);
if ((status == 0) && pages_actually_read == num_pages) {
if (!sleep_until_done) {
return;
}
// put us to sleep...
ovrld_log(LogCategory::PAGING, "[paging] Sleeping, waiting for driver to read {}",
pages_actually_read);
SleepThread();
ovrld_log(LogCategory::PAGING, "[paging] Driver woke us up!");
return;
}
ASSERT_NOT_REACHED(); // unexpected failure to issue read
} else {
// ran out of pages....
ASSERT_NOT_REACHED(); // this was just a warning.. but I think it shouldn't happen.
if (destination_page) {
do {
destination_page->input_state = CPage::State::ACTIVE;
ClearEventFlag(get_page_manager()->m_CCache.m_PagesFilledEventFlag,
~destination_page->mask);
destination_page = destination_page->m_pNextPage;
} while (destination_page);
}
}
ASSERT_NOT_REACHED();
// only get here is we failed.... set the done flag.
if (sleep_until_done == 0 && done_flag_ptr) {
*done_flag_ptr = 1;
}
}
/*!
* Callback run by the dvd driver when a page is finished reading.
*/
void CISOCDFile::ReadPagesCallback(jak3::Block* block, int error) {
if (error == 0) {
ASSERT(block->params.page->m_nAllocState == 1);
// flag page as done
block->params.page->input_state = CPage::State::READ_DONE;
// set flag
SetEventFlag(get_page_manager()->m_CCache.m_PagesFilledEventFlag, block->params.page->mask);
// if this block has a notification, process it:
if (block->params.flag == (char*)0xffffffff) { // indicates we should wake caller
// we assume the caller is the iso thread
WakeupThread(g_nISOThreadID);
} else if (block->params.flag) {
// in this case, it's a pointer.
*block->params.flag = 1;
}
}
}
// DecompressBlock - not ported
/*!
* Initialize the file system - find all files and set up their definitions.
*/
int CISOCDFileSystem::Init() {
// drive ready event flag - not ported
// get disc type - not ported
// this is mostly not needed... except for some vag pausing nonsense :(
get_driver()->SetDriverCallback([&](int a) { DvdDriverCallback(a); });
// skipped a bunch of lzo pages crap
ReadDirectory();
LoadMusicTweaks();
// skip load Disc ID
// should already be done in the constructor...
for (auto& f : g_CISOCDFiles) {
f.m_FileDef = nullptr;
}
return 0;
}
// PollDrive - not ported
/*!
* Find a file definition by name.
*/
ISOFileDef* CISOCDFileSystem::Find(const char* name) {
ISOName iname;
file_util::MakeISOName(iname.data, name);
return FindIN(&iname);
}
/*!
* Find a file definition by its "ISO Name", a 12-byte name.
*/
ISOFileDef* CISOCDFileSystem::FindIN(const jak3::ISOName* name) {
for (auto& def : g_FileDefs) {
if (def.name == *name) {
return &def;
}
}
return nullptr;
}
/*!
* Get the length of a file, in bytes.
*/
int CISOCDFileSystem::GetLength(const jak3::ISOFileDef* file) {
// return file->length;
lg::info("getlength");
file_util::assert_file_exists(file->full_path.c_str(), "CISOCDFileSystem GetLength");
FILE* fp = file_util::open_file(file->full_path.c_str(), "rb");
ASSERT(fp);
fseek(fp, 0, SEEK_END);
uint32_t len = ftell(fp);
fclose(fp);
return len;
}
/*!
* Open a file for reading.
*/
CBaseFile* CISOCDFileSystem::Open(const jak3::ISOFileDef* file_def,
int sector_offset,
int file_kind) {
auto* file = AllocateFile(file_def);
ASSERT(file);
// file kind must be known to be non-compressed (1). (TODO: remove arg)
ASSERT(file_kind == 1);
file->m_FileKind = CBaseFile::Kind::NORMAL;
file->m_nLength = file_def->length;
file->m_LengthPages = (0x7fff + file->m_nLength) >> 0xf;
if (file->m_LengthPages < 1) {
ASSERT_NOT_REACHED();
}
file->m_nLoaded = 0;
file->m_PageOffset = 0;
// in the original game, this was the sector of the start of the file
// we just make it 0, since we don't build up a whole iso file.
file->m_nSector = 0;
if (sector_offset != -1) {
file->m_nSector += sector_offset;
}
return file;
}
/*!
* Open a WAD file for reading, given the offset of the data to read, in pages.
*/
CBaseFile* CISOCDFileSystem::OpenWAD(const jak3::ISOFileDef* file_def, int page_offset) {
auto* file = AllocateFile(file_def);
ASSERT(file);
file->m_LengthPages = 1; // this is not really true..
file->m_FileKind = CBaseFile::Kind::NORMAL;
file->m_PageOffset = 0;
file->m_nSector = page_offset * 0x10;
file->m_nLoaded = 0;
file->m_nLength = 0;
return file;
}
/*!
* Locate the entry for a VAG file in the VAG directory.
*/
VagDirEntry* CISOCDFileSystem::FindVAGFile(const char* name) {
u32 packed_name[2];
PackVAGFileName(packed_name, name);
for (int i = 0; i < g_VagDir.num_entries; i++) {
auto& entry = g_VagDir.entries[i];
if (packed_name[0] == entry.words[0] && packed_name[1] == (entry.words[1] & 0x3ff)) {
return &entry;
}
}
return nullptr;
}
/*!
* Get a CISOCDFile* for a newly opened file.
*/
CISOCDFile* CISOCDFileSystem::AllocateFile(const jak3::ISOFileDef* file_def) {
for (int i = 0; i < kMaxOpenFiles; i++) {
auto* file = &g_CISOCDFiles[i];
if (!file->m_FileDef) {
*file = CISOCDFile(file_def, m_Sema[i]);
return file;
}
}
ASSERT_NOT_REACHED();
}
/*!
* Callback from the DVD driver itself into the filesystem. This was originally used for notifying
* when the tray is opened or closed.
*/
void CISOCDFileSystem::DvdDriverCallback(int) {
// the only callbacks that do anything are tray open/close, which we don't care about
ASSERT_NOT_REACHED();
}
// CheckDiscID - not ported
// LoadDiscID - not ported
// ReadSectorsNow - not ported
/*!
* Find all the files on the disc and set up their information. This is modified for the PC port to
* just search for files in the appropriate out folder.
*/
void CISOCDFileSystem::ReadDirectory() {
for (const auto& f :
fs::directory_iterator(file_util::get_jak_project_dir() / "out" / "jak3" / "iso")) {
if (f.is_regular_file()) {
auto& e = g_FileDefs.emplace_back();
std::string file_name = f.path().filename().string();
ASSERT(file_name.length() < 16); // should be 8.3.
MakeISOName(&e.name, file_name.c_str());
e.full_path =
fmt::format("{}/out/jak3/iso/{}", file_util::get_jak_project_dir().string(), file_name);
auto* fp = file_util::open_file(e.full_path, "rb");
ASSERT(fp);
fseek(fp, 0, SEEK_END);
e.length = ftell(fp);
fclose(fp);
}
}
}
/*!
* Load the "Music Tweaks" file, which contains a volume setting per music track.
*/
void CISOCDFileSystem::LoadMusicTweaks() {
ISOName tweakname;
MakeISOName(&tweakname, "TWEAKVAL.MUS");
auto file = g_ISOCDFileSystem->FindIN(&tweakname);
if (file) {
auto fp = file_util::open_file(file->full_path, "rb");
ASSERT(fp);
ASSERT(file->length <= sizeof(gMusicTweakInfo));
auto ret = fread(&gMusicTweakInfo, file->length, 1, fp);
ASSERT(ret == 1);
fclose(fp);
} else {
lg::warn("Failed to open music tweak file.");
gMusicTweakInfo.TweakCount = 0;
}
}
// Crc32 - not ported
// ReadU32 - not ported
} // namespace jak3
-58
View File
@@ -1,58 +0,0 @@
#pragma once
#include <string>
#include "game/overlord/jak3/basefile.h"
#include "game/overlord/jak3/basefilesystem.h"
#include "game/overlord/jak3/dvd_driver.h"
#include "game/overlord/jak3/isocommon.h"
namespace jak3 {
void jak3_overlord_init_globals_iso_cd();
CBaseFileSystem* get_file_system();
extern VagDir g_VagDir;
extern MusicTweaks gMusicTweakInfo;
struct CISOCDFile : public CBaseFile {
CISOCDFile();
CISOCDFile(const ISOFileDef* filedef, s32 process_data_semaphore);
int m_nLoaded = 0; // bytes loaded so far
int m_nSector = 0; // next sector to read.
int m_nLength = 0; // bytes that we want to load. 0 for the whole file
CDescriptor m_Descriptor;
EIsoStatus BeginRead() override;
void ReadPages(int sector,
CPage* destination_page,
int num_pages,
char* done_flag_ptr,
bool flag);
EIsoStatus SyncRead() override;
void Close() override;
int RecoverPages(int num_pages) override;
int GetSector() override;
void ReadPagesCallback(Block* block, int error);
};
struct CISOCDFileSystem : public CBaseFileSystem {
CISOCDFileSystem() = default;
int Init() override;
ISOFileDef* Find(const char* name) override;
ISOFileDef* FindIN(const ISOName* name) override;
int GetLength(const ISOFileDef* file) override;
CBaseFile* Open(const ISOFileDef* file_def, int sector_offset, int file_kind) override;
CBaseFile* OpenWAD(const ISOFileDef* file_def, int page_offset) override;
VagDirEntry* FindVAGFile(const char* name) override;
void DvdDriverCallback(int a);
void ReadDirectory();
void LoadMusicTweaks();
CISOCDFile* AllocateFile(const ISOFileDef* file);
// int m_drive_ready_event_flag = -1;
};
} // namespace jak3
-732
View File
@@ -1,732 +0,0 @@
#include "iso_queue.h"
#include "common/log/log.h"
#include "common/util/Assert.h"
#include "game/overlord/jak3/basefile.h"
#include "game/overlord/jak3/dma.h"
#include "game/overlord/jak3/iso.h"
#include "game/overlord/jak3/isocommon.h"
#include "game/overlord/jak3/pagemanager.h"
#include "game/overlord/jak3/spustreams.h"
#include "game/overlord/jak3/vag.h"
#include "game/sce/iop.h"
#include "game/sound/sndshim.h"
using namespace iop;
namespace jak3 {
s32 g_nPriQueueSema = 0;
s32 g_VagCmdSema = 0;
u32 g_auStrmSRAM[6];
u32 g_auTrapSRAM[6];
PriStackEntry gPriStack[2];
extern u32 time_of_last_unknown_rate_drive_op;
u32 g_cmds_with_speed_total = 0;
bool unk_time_mode_flag = false;
ISO_Hdr* g_selected_cmd = nullptr;
bool unk_time_mflag = 0;
s32 unk_sector = 0;
u32 vag_cmd_cnt = 0;
u32 vag_cmd_used = 0;
u32 max_vag_cmd_cnt = 0;
ISO_VAGCommand vag_cmds[16];
static constexpr s32 LOOP_END = 1;
static constexpr s32 LOOP_REPEAT = 2;
static constexpr s32 LOOP_START = 4;
// Empty ADPCM block with loop flags
// clang-format off
u8 VAG_SilentLoop[0x60] = {
0x0, LOOP_START | LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, LOOP_END | LOOP_REPEAT, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
// clang-format on
void jak3_overlord_init_globals_iso_queue() {
g_nPriQueueSema = 0;
g_VagCmdSema = 0;
for (auto& x : gPriStack) {
x = {};
}
g_cmds_with_speed_total = 0;
unk_time_mode_flag = false;
g_selected_cmd = nullptr;
unk_time_mflag = 0;
unk_sector = 0;
vag_cmd_cnt = 0;
vag_cmd_used = 0;
for (auto& x : vag_cmds) {
x = {};
}
}
/*!
* Added function to check if there is a pending DGO load command.
* On PC, DOG loads are really the only loading time that users see. If there is a pending
* DGO load, we can modify logic to take advantage of PCs being dramatically faster than PS2 and
* get much better load times.
*/
bool DgoCmdWaiting() {
for (auto& level : gPriStack) {
for (int i = 0; i < level.count; i++) {
auto* cmd = level.cmds[i];
if (cmd && cmd->msg_type == ISO_Hdr::MsgType::DGO_LOAD) {
if (cmd->m_pBaseFile) {
auto* file = cmd->m_pBaseFile;
if (file->m_Buffer.m_nDataLength) {
return true;
}
}
}
}
}
return false;
}
void InitBuffers() {
SemaParam sema_param;
sema_param.max_count = 1;
sema_param.init_count = 1;
sema_param.attr = 0;
sema_param.option = 0;
g_nPriQueueSema = CreateSema(&sema_param);
ASSERT(g_nPriQueueSema >= 0);
get_page_manager()->Initialize();
g_auStrmSRAM[0] = 0x5040;
g_auTrapSRAM[0] = 0x9040;
snd_SRAMMarkUsed(0x5040, 0x4040);
g_auStrmSRAM[1] = 0x9080;
g_auTrapSRAM[1] = 0xd080;
snd_SRAMMarkUsed(0x9080, 0x4040);
g_auStrmSRAM[2] = 0xd0c0;
g_auTrapSRAM[2] = 0x110c0;
snd_SRAMMarkUsed(0xd0c0, 0x4040);
g_auStrmSRAM[3] = 0x11100;
g_auTrapSRAM[3] = 0x15100;
snd_SRAMMarkUsed(0x11100, 0x4040);
g_auStrmSRAM[4] = 0x15140; // 86384 - 48
g_auTrapSRAM[4] = 0x19140;
snd_SRAMMarkUsed(0x15140, 0x4040);
g_auStrmSRAM[5] = 0x019180;
g_auTrapSRAM[5] = 0x001d180;
snd_SRAMMarkUsed(0x19180, 0x4040);
for (int i = 0; i < 6; i++) {
if (!DMA_SendToSPUAndSync(VAG_SilentLoop, 0x30, g_auTrapSRAM[i], nullptr, nullptr)) {
DelayThread(1000);
ASSERT_NOT_REACHED();
break;
}
}
sema_param.max_count = 1;
sema_param.attr = 1;
sema_param.init_count = 1;
sema_param.option = 0;
g_VagCmdSema = CreateSema(&sema_param);
ASSERT(g_VagCmdSema >= 0);
}
int QueueMessage(ISO_Hdr* msg, int pri) {
msg->status = EIsoStatus::OK_2;
msg->priority = pri;
WaitSema(g_nPriQueueSema);
int queue_idx = (pri == 5) ? 1 : 0;
bool ok = gPriStack[queue_idx].count != 8;
if (ok) {
gPriStack[queue_idx].cmds[gPriStack[queue_idx].count] = msg;
gPriStack[queue_idx].count++;
SignalSema(g_nPriQueueSema);
} else {
msg->status = EIsoStatus::FAILED_TO_QUEUE_4;
SignalSema(g_nPriQueueSema);
ReturnMessage(msg);
ASSERT_NOT_REACHED();
}
return ok;
}
int UnqueueMessage(ISO_Hdr* msg) {
WaitSema(g_nPriQueueSema);
int iVar5 = 0;
PriStackEntry* stack = gPriStack;
do {
int iVar4 = 0;
ISO_Hdr** cmd = stack->cmds;
if (0 < stack->count) {
do {
if (*cmd == msg)
break;
iVar4 = iVar4 + 1;
cmd++;
} while (iVar4 < stack->count);
}
iVar5 = iVar5 + 1;
if (iVar4 < stack->count) {
stack->count = stack->count + -1;
if (iVar4 < stack->count) {
ISO_Hdr** ppIVar3 = stack->cmds + iVar4;
do {
iVar4 = iVar4 + 1;
*ppIVar3 = ppIVar3[1];
ppIVar3 = ppIVar3 + 1;
} while (iVar4 < stack->count);
}
return SignalSema(g_nPriQueueSema);
}
stack = stack + 1;
if (1 < iVar5) {
return SignalSema(g_nPriQueueSema);
}
} while (true);
}
/*!
* Select which command to read for next
* This function considers things like seeking time, reading rates of streamed files,
* and buffer sizing. To be entirely honest, I don't understand it almost at all, and it's not
* clear that it works as expected. It seems to work good enough, and no commands get entirely
* starved of data while there are multiple streams.
*/
ISO_Hdr* GetMessage() {
// bool been_a_while;
// bool bVar2;
// int now;
// int iVar3;
// int iVar4;
// CISOCDFile *file;
// CISOCDFile *pCVar5;
// int iVar6;
// CPageList *plist;
// uint uVar7;
// int iVar8;
// int iVar9;
// PriStack *local_t2_216;
// PriStack *pri_level;
// CISOCDFile *tfile4;
// code *pcVar10;
// CISOCDFile *tfile2;
// CISOCDFile *tfile3;
// uint uVar11;
// ISO_VAGCommand *cmd;
// int idx_on_level;
// ISO_VAGCommand **ppIVar12;
// int iVar13;
// CBaseFile *tfile;
// int cmds_total;
// int iVar14;
// uint uVar15;
ISO_Hdr* cmds_array[16];
u32 read_rates_array[16];
int num_pages_array[16];
int unstepped_pages_array[16];
int remaining_pages_array[16];
// uint its_been_a_while;
// int pages_total;
// int read_rate_total;
// int min_nospeed_pages_total;
// int max_pages_total;
// int min_speed_pages_total;
// ISO_VAGCommand *selected_cmd;
// int cmds_with_speed_total;
// uint cmd2_read_rate;
// int selected_cmd_rem_sectors;
// int pri_level_idx;
// simple logic to select which command to use next.
u32 now = GetSystemTimeLow();
bool been_a_while = false;
if (unk_time_mode_flag == 0) {
been_a_while = 0x384000 < (now - time_of_last_unknown_rate_drive_op);
} else {
unk_time_mode_flag = 0;
time_of_last_unknown_rate_drive_op = now;
}
s32 cmds_total = 0;
get_page_manager()->GarbageCollect();
s32 pages_total = 0;
s32 read_rate_total = 0;
s32 min_nospeed_pages_total = 0;
s32 max_pages_total = 0;
s32 min_speed_pages_total = 0;
LAB_000080e4:
s32 iVar9 = g_cmds_with_speed_total * 400 + 0x2ee;
s32 iVar13 = 0x7fffffff;
ISO_Hdr* selected_cmd = nullptr;
s32 cmds_with_speed_total = 0;
s32 cmd2_read_rate = 0;
s32 selected_cmd_rem_sectors = -1;
s32 pri_level_idx = 1;
PriStackEntry* pri_level = gPriStack + 1;
s32 iVar8 = iVar13;
// loop over priority levels
do {
s32 idx_on_level = pri_level->count + -1;
// if any exist on this level
if (-1 < idx_on_level) {
ISO_Hdr** ppIVar12 = pri_level->cmds + idx_on_level;
// iVar14 = cmds_total << 2;
// loop over commands on this level
do {
ISO_Hdr* cmd = *ppIVar12;
CBaseFile* file = nullptr;
// iVar4 = iVar14;
// basic check if this command is even valid:
if (cmd && (file = cmd->m_pBaseFile, file) && cmd->status == EIsoStatus::OK_2 &&
cmd->active_a != 0) {
u32 read_rate = file->m_ReadRate;
read_rate_total = read_rate_total + read_rate; // maybe this is an inverse rate...
// build up arrays of info for each command
read_rates_array[cmds_total] = read_rate;
cmds_array[cmds_total] = cmd;
if ((int)read_rate < 1) {
min_nospeed_pages_total = min_nospeed_pages_total + file->m_Buffer.m_nMinNumPages;
max_pages_total = max_pages_total + file->m_Buffer.m_nMaxNumPages;
} else {
min_speed_pages_total = min_speed_pages_total + file->m_Buffer.m_nMinNumPages;
cmds_with_speed_total = cmds_with_speed_total + 1;
}
CPageList* plist = file->m_Buffer.m_pPageList;
s32 npages = 0;
if (plist != (CPageList*)0x0) {
npages = plist->m_nNumPages;
}
pages_total = pages_total + npages;
num_pages_array[cmds_total] = npages;
s32 n_untepped_pages = 0;
if (plist != (CPageList*)0x0) {
n_untepped_pages = plist->m_nNumUnsteppedPages;
}
unstepped_pages_array[cmds_total] = n_untepped_pages;
s32 n_remaining_pages = 4;
if (cmd->callback != RunDGOStateMachine) {
n_remaining_pages = n_untepped_pages + file->m_LengthPages - file->m_PageOffset;
// lg::warn("remaining pages is {} = {} + {} - {}", n_remaining_pages, n_untepped_pages,
// file->m_LengthPages, file->m_PageOffset);
}
remaining_pages_array[cmds_total] = n_remaining_pages;
if (remaining_pages_array[cmds_total] < 1) {
remaining_pages_array[cmds_total] = 1;
}
// careful, this increments in a weird spot.
// I use cmds_total - 1 below...
int old_cmds_total = cmds_total;
cmds_total = cmds_total + 1;
// iVar4 = iVar14 + 4;
// next, we'll determine a desired page cutoff and discard commands where
// we have enough pages.
if (read_rate && plist) {
// 3/4 * mNumPages, this is if our allocated buffer is 75% full.
s32 desired_pages = (int)(file->m_nNumPages * 0x30) >> 6;
// but, we want at least min pages
if (desired_pages < file->m_Buffer.m_nMinNumPages) {
desired_pages = file->m_Buffer.m_nMinNumPages;
}
// and we want at least 2
if (desired_pages < 2) {
desired_pages = 2;
}
// but, we never want more pages than we plan to eventually read.
if (remaining_pages_array[old_cmds_total] < desired_pages) {
desired_pages = remaining_pages_array[old_cmds_total];
}
// if we have that many, we can just forget the command - no point in filling it now.
if (desired_pages <= unstepped_pages_array[old_cmds_total])
goto LAB_00008420;
}
s32 iVar14 = iVar9;
if ((0 < (int)read_rate) &&
(iVar14 = (int)(file->m_Buffer.m_nDataLength * 1000) / (int)read_rate,
read_rate == 0)) {
ASSERT_NOT_REACHED();
}
s32 pri = cmd->priority;
// really not sure what this is...
if (been_a_while) {
if ((read_rate == 0) || (iVar14 < 0x2ee)) {
been_a_while = false;
goto LAB_000080e4;
}
// if this isn't the command we said last time.
if (g_selected_cmd != cmd) {
s32 current_sector = file->GetSector();
current_sector = current_sector - unk_sector;
bool sector_ok = false;
if (current_sector < 0) {
current_sector = -current_sector;
if (unk_time_mflag != 0) {
LAB_000083ac:
current_sector = current_sector + 10000000;
}
sector_ok = current_sector < iVar13;
} else {
sector_ok = current_sector < iVar13;
if ((0 < current_sector) && (unk_time_mflag == 0))
goto LAB_000083ac;
}
if (sector_ok) {
iVar13 = current_sector;
iVar8 = iVar14;
selected_cmd = cmd;
cmd2_read_rate = read_rate;
}
}
} else {
// normal selection logic???
if ((((iVar14 == iVar8) && (selected_cmd_rem_sectors < pri)) || (iVar14 < iVar8)) &&
(iVar14 <= iVar9)) {
iVar8 = iVar14;
selected_cmd = cmd;
cmd2_read_rate = read_rate;
selected_cmd_rem_sectors = pri;
}
}
}
LAB_00008420:
idx_on_level = idx_on_level + -1;
/* WARNING: ptrarith problems */
ppIVar12 = ppIVar12 + -1;
// iVar14 = iVar4;
} while (-1 < idx_on_level);
}
pri_level--;
pri_level_idx = pri_level_idx + -1;
} while (-1 < pri_level_idx);
if (selected_cmd) {
if (cmd2_read_rate == 0) {
unk_time_mode_flag = 1;
time_of_last_unknown_rate_drive_op = now;
}
iVar13 = unk_sector;
if (selected_cmd->m_pBaseFile) {
iVar13 = selected_cmd->m_pBaseFile->GetSector();
}
if (unk_sector < iVar13) {
unk_time_mflag = 1;
unk_sector = iVar13;
} else {
been_a_while = iVar13 != unk_sector;
unk_sector = iVar13;
if (been_a_while) {
unk_time_mflag = 0;
unk_sector = iVar13;
}
}
}
min_speed_pages_total = min_speed_pages_total + min_nospeed_pages_total;
g_cmds_with_speed_total = cmds_with_speed_total;
g_selected_cmd = selected_cmd;
pages_total = get_page_manager()->m_CCache.m_nNumFreePages + pages_total;
if ((0 < min_speed_pages_total) && (0 < pages_total)) {
if (min_speed_pages_total == 0) {
// trap(0x1c00);
ASSERT_NOT_REACHED();
}
min_speed_pages_total = (min_nospeed_pages_total * pages_total) / min_speed_pages_total;
if (min_speed_pages_total < min_nospeed_pages_total) {
min_speed_pages_total = min_nospeed_pages_total;
}
if (max_pages_total < min_speed_pages_total) {
min_speed_pages_total = max_pages_total;
}
pages_total = pages_total - min_speed_pages_total;
iVar9 = 0;
iVar13 = min_speed_pages_total;
iVar8 = pages_total;
if (0 < cmds_total) {
// iVar14 = 0;
iVar13 = min_speed_pages_total;
iVar8 = pages_total;
do {
CBaseFile* tfile = cmds_array[iVar9]->m_pBaseFile;
if (read_rates_array[iVar9] < 1) {
s32 uVar11 = (tfile->m_Buffer).m_nMaxNumPages;
if (max_pages_total == 0) {
ASSERT_NOT_REACHED();
}
s32 uVar15 = (tfile->m_Buffer).m_nMinNumPages;
s32 uVar7 = (int)(uVar11 * min_speed_pages_total) / max_pages_total;
if ((int)uVar7 < (int)uVar15) {
uVar7 = uVar15;
}
tfile->m_nNumPages = uVar7;
if ((int)uVar11 < (int)uVar7) {
uVar7 = uVar11;
}
tfile->m_nNumPages = uVar7;
if (remaining_pages_array[iVar9] < (int)uVar7) {
uVar7 = remaining_pages_array[iVar9];
}
tfile->m_nNumPages = uVar7;
// lg::warn("num pages mod {}", uVar7);
iVar13 = iVar13 - uVar7;
} else {
s32 uVar11 = (tfile->m_Buffer).m_nMinNumPages;
s32 uVar7 = (tfile->m_Buffer).m_nMaxNumPages;
// lg::warn("taking else case: {} {} {}", uVar11, uVar7, tfile->m_nNumPages);
s32 uVar15 = -1;
if (read_rate_total == 0) {
LAB_000085e4:
// lg::warn("going to min! (rrt is {})", read_rate_total);
uVar15 = uVar11;
} else {
if (read_rate_total == 0) {
ASSERT_NOT_REACHED();
}
uVar15 = (read_rates_array[iVar9] * pages_total) / read_rate_total;
// lg::warn("read rate math is {}", uVar15);
if ((int)uVar15 < (int)uVar11)
goto LAB_000085e4;
}
// lg::warn("vals {} {}", uVar7, uVar15);
if ((int)uVar7 < (int)uVar15) {
uVar15 = uVar7;
}
// lg::warn("vals 2 {} {}", remaining_pages_array[iVar9], uVar15);
if (remaining_pages_array[iVar9] < (int)uVar15) {
uVar15 = remaining_pages_array[iVar9];
}
iVar8 = iVar8 - uVar15;
tfile->m_nNumPages = uVar15;
// lg::warn("num pages mod 2 {}", uVar15);
}
iVar9 = iVar9 + 1;
// iVar14 = iVar9 * 4;
} while (iVar9 < cmds_total);
}
while (0 < iVar13) {
iVar9 = 0;
s32 iVar14 = iVar13;
if (0 < cmds_total) {
s32 iVar4 = 0;
iVar14 = iVar13;
while (0 < iVar14) {
CBaseFile* tfile2 = cmds_array[iVar4 / 4]->m_pBaseFile;
iVar9 = iVar9 + 1;
s32 uVar11;
if (read_rates_array[iVar4 / 4] == 0 &&
(uVar11 = tfile2->m_nNumPages, (int)uVar11 < remaining_pages_array[iVar4 / 4]) &&
((int)uVar11 < tfile2->m_Buffer.m_nMaxNumPages)) {
tfile2->m_nNumPages = uVar11 + 1;
iVar14 = iVar14 + -1;
}
if (cmds_total <= iVar9)
break;
iVar4 = iVar9 * 4;
}
}
been_a_while = iVar13 == iVar14;
iVar13 = iVar14;
if (been_a_while) {
iVar8 = iVar8 + iVar14;
iVar13 = 0;
}
}
while (0 < iVar8) {
iVar13 = 0;
iVar9 = iVar8;
if (0 < cmds_total) {
s32 iVar14 = 0;
iVar9 = iVar8;
while (0 < iVar9) {
CBaseFile* tfile4 = cmds_array[iVar14 / 4]->m_pBaseFile;
iVar13 = iVar13 + 1;
s32 uVar11;
if (((0 < read_rates_array[iVar14 / 4]) &&
(uVar11 = tfile4->m_nNumPages, (int)uVar11 < remaining_pages_array[iVar14 / 4])) &&
((int)uVar11 < tfile4->m_Buffer.m_nMaxNumPages)) {
tfile4->m_nNumPages = uVar11 + 1;
iVar9 = iVar9 + -1;
}
if (cmds_total <= iVar13)
break;
iVar14 = iVar13 * 4;
}
}
been_a_while = iVar8 == iVar9;
iVar8 = iVar9;
if (been_a_while) {
iVar8 = 0;
}
}
iVar13 = 0;
if (0 < cmds_total) {
iVar8 = 0;
do {
CBaseFile* tfile3 = cmds_array[iVar8 / 4]->m_pBaseFile;
iVar13 = iVar13 + 1;
s32 uVar11 = tfile3->m_nNumPages;
// lg::warn("mystery values: {} - {} = {} (from {})", num_pages_array[iVar8 / 4],
// uVar11,
// num_pages_array[iVar8 / 4] - uVar11,
// cmds_array[iVar8 / 4]->m_pBaseFile->m_FileDef->name.data);
if (((int)uVar11 < num_pages_array[iVar8 / 4]) &&
(iVar8 = tfile3->RecoverPages(num_pages_array[iVar8 / 4] - uVar11), 0 < iVar8)) {
get_page_manager()->GarbageCollectPageList(tfile3->m_Buffer.m_pPageList);
}
iVar8 = iVar13 * 4;
} while (iVar13 < cmds_total);
}
}
return selected_cmd;
}
int ProcessMessageData(ISO_Hdr* tgt_msg) {
EIsoStatus stat;
s32 ret = 1;
LAB_000088a4:
s32 num_remaining = gPriStack[0].count + -1;
if (num_remaining < 0) {
return ret;
}
auto* cmd_array = gPriStack[0].cmds + num_remaining;
ISO_Hdr* cmd = nullptr;
do {
EIsoStatus (*cb)(ISO_Hdr*) = nullptr;
cmd = *cmd_array;
if (cmd && cmd->active_a) {
stat = cmd->status;
if (stat == EIsoStatus::OK_2) {
auto* file = cmd->m_pBaseFile;
auto* buffer = &file->m_Buffer;
if (!file) {
buffer = nullptr;
}
if ((buffer && (buffer->m_eBufferType != CBuffer::BufferType::EBT_FREE)) &&
(cb = cmd->callback, cb != ProcessVAGData)) {
stat = (cb)(cmd);
}
}
if (stat != EIsoStatus::OK_2)
break;
cmd->status = EIsoStatus::OK_2;
}
num_remaining = num_remaining + -1;
cmd_array = cmd_array + -1;
if (num_remaining < 0) {
return ret;
}
} while (true);
if (cmd == tgt_msg) {
ret = 0;
}
ReleaseMessage(cmd);
if (stat != EIsoStatus::IDLE_1) {
cmd->status = stat;
ReturnMessage(cmd);
}
goto LAB_000088a4;
}
void ReturnMessage(ISO_Hdr* msg) {
if (msg->mbox_reply == 0) {
if (msg->thread_to_wake == 0) {
FreeVAGCommand((ISO_VAGCommand*)msg);
} else {
WakeupThread(msg->thread_to_wake);
}
} else {
SendMbx(msg->mbox_reply, msg);
}
}
void ReleaseMessage(ISO_Hdr* msg) {
if (GetThreadId() == g_nISOThreadID) {
auto* file = msg->m_pBaseFile;
if (file && file->m_Status != EIsoStatus::NONE_0) {
file->Close();
}
UnqueueMessage(msg);
} else {
if (msg->msg_type != ISO_Hdr::MsgType::ABADBABE) {
set_active_a(msg, 0);
set_active_c(msg, 0);
msg->msg_type = ISO_Hdr::MsgType::ABADBABE;
SendMbx(g_nISOMbx, msg);
}
}
}
ISO_VAGCommand* GetVAGCommand() {
int iVar1;
u32 uVar2;
u32 uVar3;
do {
while (vag_cmd_cnt == 0x1f) {
DelayThread(1000);
}
do {
iVar1 = WaitSema(g_VagCmdSema);
uVar2 = 0;
} while (iVar1 != 0);
do {
uVar3 = uVar2 + 1;
if (((vag_cmd_used >> (uVar2 & 0x1f) ^ 1U) & 1) != 0) {
vag_cmd_cnt = vag_cmd_cnt + 1;
vag_cmd_used = vag_cmd_used | 1 << (uVar2 & 0x1f);
if (max_vag_cmd_cnt < vag_cmd_cnt) {
max_vag_cmd_cnt = vag_cmd_cnt;
}
SignalSema(g_VagCmdSema);
return vag_cmds + uVar2;
}
uVar2 = uVar3;
} while ((int)uVar3 < 0x1f);
SignalSema(g_VagCmdSema);
} while (true);
}
void FreeVAGCommand(ISO_VAGCommand* param_1) {
u32 uVar1;
int iVar2;
uVar1 = param_1 - vag_cmds;
ASSERT(uVar1 < 16);
if ((uVar1 < 0x1f) && (((vag_cmd_used >> (uVar1 & 0x1f) ^ 1U) & 1) == 0)) {
do {
iVar2 = WaitSema(g_VagCmdSema);
} while (iVar2 != 0);
vag_cmd_cnt = vag_cmd_cnt - 1;
vag_cmd_used = vag_cmd_used & ~(1 << (uVar1 & 0x1f));
SignalSema(g_VagCmdSema);
}
}
} // namespace jak3
-30
View File
@@ -1,30 +0,0 @@
#pragma once
#include "common/common_types.h"
namespace jak3 {
void jak3_overlord_init_globals_iso_queue();
struct ISO_Hdr;
struct ISO_VAGCommand;
void ReleaseMessage(ISO_Hdr* msg);
void FreeVagCmd(ISO_VAGCommand* msg);
int QueueMessage(ISO_Hdr* msg, int pri);
int UnqueueMessage(ISO_Hdr* msg);
void ReturnMessage(ISO_Hdr* msg);
void InitBuffers();
bool DgoCmdWaiting();
ISO_Hdr* GetMessage();
int ProcessMessageData(ISO_Hdr* msg);
void FreeVAGCommand(ISO_VAGCommand* msg);
ISO_VAGCommand* GetVAGCommand();
struct PriStackEntry {
ISO_Hdr* cmds[8];
int count = 0;
};
extern u32 g_auTrapSRAM[6];
extern u32 g_auStrmSRAM[6];
extern s32 g_nPriQueueSema;
extern PriStackEntry gPriStack[2];
} // namespace jak3
Loaded 100 of 606 files, more files were not shown because too many files have changed in this diff. Show more