mirror of
https://github.com/open-goal/jak-project
synced 2026-06-04 02:47:17 -04:00
Merge remote-tracking branch 'water111/master' into shrubbery
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import glob
|
||||
|
||||
src_files = glob.glob("./goal_src/**/*.g[cs]", recursive=True)
|
||||
data_files = glob.glob("./goal_src/**/*.gd", recursive=True)
|
||||
|
||||
# Find how many of each have been started
|
||||
|
||||
@@ -20,12 +19,6 @@ for f in src_files:
|
||||
else:
|
||||
src_files_started = src_files_started + 1
|
||||
|
||||
for f in data_files:
|
||||
with open(f, "r") as temp_file:
|
||||
line_count = len(temp_file.readlines())
|
||||
if line_count > 7:
|
||||
data_files_started = data_files_started + 1
|
||||
|
||||
import json
|
||||
with open('./docs/gh-pages-proj/src/config/progress.json', 'r+', encoding='utf-8') as f:
|
||||
data = {
|
||||
@@ -33,9 +26,7 @@ with open('./docs/gh-pages-proj/src/config/progress.json', 'r+', encoding='utf-8
|
||||
'fileProgress': {
|
||||
'src_files_total': len(src_files),
|
||||
'src_files_finished': src_files_finished,
|
||||
'src_files_started': src_files_started,
|
||||
'data_files_total': len(data_files),
|
||||
'data_files_started': data_files_started
|
||||
'src_files_started': src_files_started
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import glob
|
||||
import os
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
galleryLinks = {
|
||||
'jak1': {
|
||||
'name': "Jak 1",
|
||||
'media': [],
|
||||
},
|
||||
'jak2': {
|
||||
'name': "Jak 2",
|
||||
'media': [],
|
||||
},
|
||||
'jak3': {
|
||||
'name': "Jak 3",
|
||||
'media': [],
|
||||
},
|
||||
'jakx': {
|
||||
'name': "Jak X",
|
||||
'media': [],
|
||||
},
|
||||
'misc': {
|
||||
'name': "Miscellaneous",
|
||||
'media': [],
|
||||
}
|
||||
}
|
||||
|
||||
def get_links(key, folder_to_search):
|
||||
if os.path.isdir(folder_to_search):
|
||||
files = glob.glob(folder_to_search + "/*.png", recursive=True)
|
||||
files.extend(glob.glob(folder_to_search + "/*.jpg", recursive=True))
|
||||
files.extend(glob.glob(folder_to_search + "/*.jpeg", recursive=True))
|
||||
for f in files:
|
||||
galleryLinks[key]["media"].append({
|
||||
'fileName': os.path.basename(f),
|
||||
'timestamp': Path(f).stem.split("_")[1],
|
||||
'caption': Path(f).stem.split("_")[0].replace("-", " ").title(),
|
||||
'video': False
|
||||
})
|
||||
# get videos potentially
|
||||
if os.path.exists("{}/videos.json".format(folder_to_search)):
|
||||
with open("{}/videos.json".format(folder_to_search), 'r') as f:
|
||||
data = json.load(f)
|
||||
for video in data:
|
||||
galleryLinks[key]["media"].append({
|
||||
'link': video["link"].replace("watch?v=", "embed/"),
|
||||
'timestamp': video["timestamp"],
|
||||
'video': True
|
||||
})
|
||||
# sort by timestamp
|
||||
galleryLinks[key]["media"].sort(key=lambda x: x["timestamp"], reverse=True)
|
||||
|
||||
get_links('jak1', './docs/gh-pages-proj/src/assets/gallery/jak1')
|
||||
get_links('jak2', './docs/gh-pages-proj/src/assets/gallery/jak2')
|
||||
get_links('jak3', './docs/gh-pages-proj/src/assets/gallery/jak3')
|
||||
get_links('jakx', './docs/gh-pages-proj/src/assets/gallery/jakx')
|
||||
get_links('misc', './docs/gh-pages-proj/src/assets/gallery/misc')
|
||||
|
||||
with open('./docs/gh-pages-proj/src/config/gallery.json', 'r+', encoding='utf-8') as f:
|
||||
f.seek(0)
|
||||
json.dump(galleryLinks, f, ensure_ascii=False, indent=2)
|
||||
f.truncate()
|
||||
@@ -21,7 +21,10 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Update Line Count
|
||||
run: python ./scripts/update-file-progress.py
|
||||
run: python ./.github/scripts/update-file-progress.py
|
||||
|
||||
- name: Update Gallery Links
|
||||
run: python ./.github/scripts/update-gallery.py
|
||||
|
||||
- name: Update Site
|
||||
run: |
|
||||
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
run: git submodule update --init --recursive -j 2
|
||||
|
||||
- name: Install Dependencies
|
||||
run: choco install nasm
|
||||
run: Choco-Install -PackageName nasm
|
||||
|
||||
- name: Setup Buildcache
|
||||
uses: mikehardy/buildcache-action@v1.2.2
|
||||
|
||||
@@ -31,3 +31,6 @@ gfx_dumps/*
|
||||
# game stuff
|
||||
game_config/*
|
||||
imgui.ini
|
||||
|
||||
# website stuff
|
||||
node_modules/
|
||||
|
||||
Vendored
+32
-3
@@ -48,13 +48,31 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"(lwu .., 4\\(..\\).*)(dma-buffer)": {
|
||||
"filterFileRegex": ".*ir2\\.asm",
|
||||
"decorations": [
|
||||
{},
|
||||
{
|
||||
"overviewRulerColor": "transparent",
|
||||
"color": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"(\\d+\\(sp\\))": {
|
||||
"filterFileRegex": ".*ir2\\.asm",
|
||||
"decorations": [
|
||||
{
|
||||
"overviewRulerColor": "transparent",
|
||||
"color": "#00ff08"
|
||||
}
|
||||
]
|
||||
},
|
||||
"(sp, -?\\d+ )": {
|
||||
"filterFileRegex": ".*ir2\\.asm",
|
||||
"decorations": [
|
||||
{
|
||||
"overviewRulerColor": "transparent",
|
||||
"color": "#00ff08",
|
||||
"fontWeight": "bold"
|
||||
"color": "#00ff08"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -272,7 +290,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"(WARN:.*)": {
|
||||
"(WARN: Unsupported.*)": {
|
||||
"filterFileRegex": ".*ir2\\.asm",
|
||||
"decorations": [
|
||||
{
|
||||
"overviewRulerColor": "#ea00ff",
|
||||
"color": "#ea00ff",
|
||||
"fontWeight": "bold",
|
||||
"filterFileRegex": ".*ir2\\.asm"
|
||||
}
|
||||
]
|
||||
},
|
||||
"(WARN: (?!Unsupported).*)": {
|
||||
"filterFileRegex": ".*ir2\\.asm",
|
||||
"decorations": [
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<a href="https://coveralls.io/github/water111/jak-project?branch=master" rel="nofollow"><img src="https://coveralls.io/repos/github/water111/jak-project/badge.svg?branch=master" alt="Coverage Status" style="max-width:100%;"></a>
|
||||
<a href="https://www.codacy.com/gh/water111/jak-project/dashboard?utm_source=github.com&utm_medium=referral&utm_content=xTVaser/jak-project&utm_campaign=Badge_Grade" rel="nofollow"><img src="https://app.codacy.com/project/badge/Grade/7c3cdc07523f43aca3433484ebc62ff9" alt="Codacy Badge" style="max-width:100%;"></a>
|
||||
<a href="https://discord.gg/E7yFpd6w9G"><img src="https://img.shields.io/discord/756287461377703987" alt="Discord"></a>
|
||||
<a href="https://makeapullrequest.com"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt=PRs Welcome></a>
|
||||
</p>
|
||||
|
||||
## Table of Contents
|
||||
@@ -17,15 +18,20 @@
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Project Description](#project-description)
|
||||
- [Current Status](#current-status)
|
||||
- [What's Next](#whats-next)
|
||||
- [Getting Started - Linux (Ubuntu)](#getting-started---linux-ubuntu)
|
||||
- [Getting Started - Linux (Arch)](#getting-started---linux-arch)
|
||||
- [Getting Started - Nixpkgs](#getting-started---nixpkgs)
|
||||
- [Getting Started - Windows](#getting-started---windows)
|
||||
- [Building and Running the Game](#building-and-running-the-game)
|
||||
- [Extract Assets](#extract-assets)
|
||||
- [Build Game](#build-game)
|
||||
- [Run Game](#run-game)
|
||||
- [Project Layout](#project-layout)
|
||||
- [Directory Layout](#directory-layout)
|
||||
- [More Documentation](#more-documentation)
|
||||
- [ASan Build](#asan-build)
|
||||
- [On Windows / Visual Studio](#on-windows--visual-studio)
|
||||
- [On Windows / Visual Studio](#on-windows--visual-studio)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## Project Description
|
||||
@@ -44,6 +50,8 @@ Our objectives are:
|
||||
|
||||
We support both Linux and Windows on x86-64.
|
||||
|
||||
We have a Discord server where we discuss development. https://discord.gg/BVEHQmm8
|
||||
|
||||
## Current Status
|
||||
So far, we've decompiled around 341,233 lines of GOAL code, out of an estimated 500,000 total lines and we've started work on an OpenGL renderer. Currently, the main display process (`*dproc*`) runs and sends data to our renderer. We can load textures, text files, and level files. Using keyboard controls, we can open the debug menu and turn on some simple debug visualizations.
|
||||
|
||||
@@ -138,14 +146,16 @@ nix-build -A packages.x86_64-linux.jak-asan # package with Clang ASan build
|
||||
|
||||
## Getting Started - Windows
|
||||
|
||||
Install Visual Studio 2019 and get the C++ and CMake tools via the Visual Studio Installer
|
||||
Install Visual Studio 2022 and get the `Desktop development with C++` workload during the installation process.
|
||||
|
||||
> if you already have visual studio and don't have this installed - open your `Visual Studio Installer` and modify the installation
|
||||
|
||||
On Windows, it's recommended to get Scoop to use as a package manager, making the follow steps _much_ easier. Follow the steps on the bottom of the homepage here https://scoop.sh/
|
||||
|
||||
Once Scoop is installed, run the following command:
|
||||
|
||||
```ps1
|
||||
scoop install llvm nasm
|
||||
```sh
|
||||
scoop install git llvm nasm
|
||||
```
|
||||
|
||||
Initialize the repository's third-party dependencies:
|
||||
@@ -154,17 +164,13 @@ Initialize the repository's third-party dependencies:
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
Open the project as a CMake project, browse for the root level `CMakeLists.txt`:
|
||||
Open the project as a CMake project.
|
||||
|
||||

|
||||

|
||||
|
||||
In the toolbar, you should be able to select an individual component to compile, or combine within the root CMakeLists.txt. In the future we will pre-define configurations to make this easier.
|
||||
Then build the entire project
|
||||
|
||||

|
||||
|
||||
You may also wish to view the files that pertain to each CMake target, rather than the project as it is normally:
|
||||
|
||||

|
||||

|
||||
|
||||
## Building and Running the Game
|
||||
|
||||
@@ -200,7 +206,7 @@ gc> (test-play)
|
||||
(play :use-vis #t :init-game #f) has been called!
|
||||
0 #x0 0.0000 0
|
||||
|
||||
gc>
|
||||
gc>
|
||||
```
|
||||
Then, in the graphics window, you can use the period key to bring up the debug menu. Controllers also work, using the same mapping as the original game.
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ tasks:
|
||||
ignore_error: true
|
||||
run-game:
|
||||
cmds:
|
||||
- ./out/build/Release/bin/gk.exe -fakeiso -debug
|
||||
- ./out/build/Release/bin/gk.exe -fakeiso -debug -v
|
||||
run-game-headless:
|
||||
cmds:
|
||||
- ./out/build/Release/bin/gk.exe -fakeiso -debug -nodisplay
|
||||
|
||||
@@ -11,6 +11,20 @@ void StripDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&num_triangles);
|
||||
}
|
||||
|
||||
void InstancedStripDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&mode);
|
||||
ser.from_ptr(&tree_tex_id);
|
||||
ser.from_pod_vector(&vertex_index_stream);
|
||||
ser.from_pod_vector(&instance_groups);
|
||||
ser.from_ptr(&num_triangles);
|
||||
}
|
||||
|
||||
void TieWindInstance::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&matrix);
|
||||
ser.from_ptr(&wind_idx);
|
||||
ser.from_ptr(&stiffness);
|
||||
}
|
||||
|
||||
void TfragTree::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&kind);
|
||||
|
||||
@@ -38,6 +52,24 @@ void TieTree::serialize(Serializer& ser) {
|
||||
draw.serialize(ser);
|
||||
}
|
||||
|
||||
if (ser.is_saving()) {
|
||||
ser.save<size_t>(instanced_wind_draws.size());
|
||||
} else {
|
||||
instanced_wind_draws.resize(ser.load<size_t>());
|
||||
}
|
||||
for (auto& draw : instanced_wind_draws) {
|
||||
draw.serialize(ser);
|
||||
}
|
||||
|
||||
if (ser.is_saving()) {
|
||||
ser.save<size_t>(instance_info.size());
|
||||
} else {
|
||||
instance_info.resize(ser.load<size_t>());
|
||||
}
|
||||
for (auto& inst : instance_info) {
|
||||
inst.serialize(ser);
|
||||
}
|
||||
|
||||
ser.from_pod_vector(&vertices);
|
||||
ser.from_pod_vector(&colors);
|
||||
bvh.serialize(ser);
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
// Data format for the tfrag3 renderer.
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/assert.h"
|
||||
#include "common/dma/gs.h"
|
||||
#include "common/util/Serializer.h"
|
||||
#include "common/math/Vector.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace tfrag3 {
|
||||
|
||||
constexpr int TFRAG3_VERSION = 7;
|
||||
constexpr int TFRAG3_VERSION = 9;
|
||||
|
||||
// These vertices should be uploaded to the GPU at load time and don't change
|
||||
struct PreloadedVertex {
|
||||
@@ -41,8 +42,8 @@ struct StripDraw {
|
||||
// to do culling, the above vertex stream is grouped.
|
||||
// by following the visgroups and checking the visibility, you can leave out invisible vertices.
|
||||
struct VisGroup {
|
||||
u32 num = 0; // number of vertex indices in this group
|
||||
u32 vis_idx = 0; // the visibility group they belong to
|
||||
u32 num = 0; // number of vertex indices in this group
|
||||
u32 vis_idx_in_pc_bvh = 0; // the visibility group they belong to (in BVH)
|
||||
};
|
||||
std::vector<VisGroup> vis_groups;
|
||||
|
||||
@@ -51,12 +52,34 @@ struct StripDraw {
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
struct InstancedStripDraw {
|
||||
DrawMode mode; // the OpenGL draw settings.
|
||||
u32 tree_tex_id = 0; // the texture that should be bound for the draw
|
||||
|
||||
// the list of vertices in the draw. This includes the restart code of UINT32_MAX that OpenGL
|
||||
// will use to start a new strip.
|
||||
std::vector<u32> vertex_index_stream;
|
||||
|
||||
// the vertex stream above is segmented by instance.
|
||||
struct InstanceGroup {
|
||||
u32 num = 0; // number of vertex indices in this group
|
||||
u32 instance_idx = 0; // the instance they belong to
|
||||
u32 vis_idx = 0;
|
||||
};
|
||||
std::vector<InstanceGroup> instance_groups;
|
||||
|
||||
// for debug counting.
|
||||
u32 num_triangles = 0;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
// node in the BVH.
|
||||
struct VisNode {
|
||||
math::Vector<float, 4> bsphere; // the bounding sphere, in meters (4096 = 1 game meter). w = rad
|
||||
u16 child_id = 0xffff; // the ID of our first child.
|
||||
u8 num_kids = 0xff; // number of children. The children are consecutive in memory
|
||||
u8 flags = 0; // flags. If 1, we have a DrawVisNode child, otherwise a leaf.
|
||||
u16 my_id = 0xffff;
|
||||
u8 num_kids = 0xff; // number of children. The children are consecutive in memory
|
||||
u8 flags = 0; // flags. If 1, we have a DrawVisNode child, otherwise a leaf.
|
||||
};
|
||||
|
||||
// The leaf nodes don't actually exist in the vector of VisNodes, but instead they are ID's used
|
||||
@@ -114,6 +137,13 @@ struct TfragTree {
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
struct TieWindInstance {
|
||||
std::array<math::Vector4f, 4> matrix;
|
||||
u16 wind_idx;
|
||||
float stiffness;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
// A shrub model
|
||||
struct ShrubTree {
|
||||
BVH bvh;
|
||||
@@ -132,7 +162,8 @@ struct TieTree {
|
||||
std::vector<PreloadedVertex> vertices; // mesh vertices
|
||||
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
|
||||
|
||||
// TODO wind stuff
|
||||
std::vector<InstancedStripDraw> instanced_wind_draws;
|
||||
std::vector<TieWindInstance> instance_info;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "common/util/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
struct DmaStats {
|
||||
double sync_time_ms = 0;
|
||||
@@ -117,4 +117,4 @@ struct VifCodeUnpack {
|
||||
u16 addr_qw;
|
||||
bool is_unsigned; // only care for 8/16 bit data.
|
||||
bool use_tops_flag; // uses double buffering
|
||||
};
|
||||
};
|
||||
|
||||
+8
-1
@@ -339,7 +339,7 @@ struct AdGifData {
|
||||
u64 tex1_addr;
|
||||
u64 mip_data;
|
||||
u64 mip_addr;
|
||||
u64 clamp_data;
|
||||
u64 clamp_data; // can also be zbuf!!
|
||||
u64 clamp_addr;
|
||||
u64 alpha_data;
|
||||
u64 alpha_addr;
|
||||
@@ -366,6 +366,13 @@ class DrawMode {
|
||||
bool get_depth_write_enable() const { return m_val & 0b1; }
|
||||
void enable_depth_write() { m_val = m_val | 0b1; }
|
||||
void disable_depth_write() { m_val = m_val & ~(0b1); }
|
||||
void set_depth_write_enable(bool x) {
|
||||
if (x) {
|
||||
enable_depth_write();
|
||||
} else {
|
||||
disable_depth_write();
|
||||
}
|
||||
}
|
||||
|
||||
GsTest::ZTest get_depth_test() const { return (GsTest::ZTest)((m_val >> 1) & 0b11); }
|
||||
void set_depth_test(GsTest::ZTest dt) { m_val = (m_val & ~(0b110)) | ((u32)(dt) << 1); }
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Interpreter.h"
|
||||
#include "ParseHelpers.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include <third-party/fmt/core.h>
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
namespace goos {
|
||||
Interpreter::Interpreter(const std::string& username) {
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "common/util/assert.h"
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@@ -50,6 +49,7 @@
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* It is not very good, but significantly better than putting everything on one line
|
||||
*/
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <cstring>
|
||||
@@ -14,6 +13,7 @@
|
||||
#include "common/log/log.h"
|
||||
|
||||
#include "common/goos/PrettyPrinter2.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace pretty_print {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "PrettyPrinter2.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/assert.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace pretty_print {
|
||||
|
||||
@@ -11,9 +11,6 @@ namespace v2 {
|
||||
// The previous issues we had with stack overflow only happened when there was a stack frame per
|
||||
// element in a list.
|
||||
|
||||
// TODO: there's a different style of splitting that we should do for forms like:
|
||||
// set!, and, or, <, >, +... where we try leaving operator + one other.
|
||||
|
||||
// The main node type.
|
||||
// unlike v1, this nests lists.
|
||||
// these have pointers to parents, so generally not safe to copy.
|
||||
@@ -71,6 +68,19 @@ struct Node {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string debug_to_string() const {
|
||||
switch (kind) {
|
||||
case Kind::ATOM:
|
||||
return fmt::format("[atom {}]", atom_str);
|
||||
case Kind::LIST:
|
||||
return "[list]";
|
||||
case Kind::IMPROPER_LIST:
|
||||
return "[improper list]";
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// how wide is this text? not including the indentation of this subtree.
|
||||
u32 text_len = 0;
|
||||
|
||||
@@ -193,7 +203,8 @@ void break_list(Node* node) {
|
||||
node->top_line_count = 1;
|
||||
|
||||
const std::unordered_set<std::string> sameline_splitters = {
|
||||
"if", "<", ">", "<=", ">=", "set!", "=", "!=", "+", "-", "*", "/", "the", "->"};
|
||||
"if", "<", ">", "<=", ">=", "set!", "=", "!=", "+", "-", "*",
|
||||
"/", "the", "->", "and", "or", "logand", "logior", "logxor", "+!", "*!", "logtest?"};
|
||||
|
||||
if (node->child_nodes.at(0).kind == Node::Kind::LIST) {
|
||||
// ((foo
|
||||
@@ -208,7 +219,7 @@ void break_list(Node* node) {
|
||||
// things with 4 things in the top line: (defmethod <method> <type> <args>
|
||||
node->top_line_count = 4;
|
||||
} else if (name == "until" || name == "while" || name == "dotimes" || name == "countdown" ||
|
||||
name == "when" || name == "behavior" || name == "lambda") {
|
||||
name == "when" || name == "behavior" || name == "lambda" || name == "defpart") {
|
||||
node->top_line_count = 2;
|
||||
} else if (name == "let" || name == "let*" || name == "rlet") {
|
||||
// special case for things like let.
|
||||
@@ -253,9 +264,9 @@ void break_list(Node* node) {
|
||||
|
||||
void insert_required_breaks(const std::vector<Node*>& bfs_order) {
|
||||
const std::unordered_set<std::string> always_break = {
|
||||
"when", "defun-debug", "countdown", "case", "defun", "defmethod",
|
||||
"let", "until", "while", "if", "dotimes", "cond",
|
||||
"else", "defbehavior", "with-pp", "rlet", "defstate"};
|
||||
"when", "defun-debug", "countdown", "case", "defun", "defmethod", "let",
|
||||
"until", "while", "if", "dotimes", "cond", "else", "defbehavior",
|
||||
"with-pp", "rlet", "defstate", "behavior", "defpart"};
|
||||
for (auto node : bfs_order) {
|
||||
if (!node->break_list && node->kind == Node::Kind::LIST &&
|
||||
node->child_nodes.at(0).kind == Node::Kind::ATOM) {
|
||||
@@ -328,18 +339,26 @@ void append_node_to_string(const Node* node,
|
||||
|
||||
int listing_indent = next_indent_level + node->quoted + node->sub_elt_indent;
|
||||
int extra_indent = 0;
|
||||
int old_indent = listing_indent;
|
||||
if (node->top_line_count) {
|
||||
listing_indent -= node->sub_elt_indent;
|
||||
listing_indent += node->child_nodes.front().kind == Node::Kind::LIST ? 1 : 2;
|
||||
}
|
||||
for (; node_idx < node->top_line_count; node_idx++) {
|
||||
size_t s0 = str.length();
|
||||
if (node->kind == Node::Kind::IMPROPER_LIST &&
|
||||
&node->child_nodes.at(node_idx) == &node->child_nodes.back()) {
|
||||
str.append(". ");
|
||||
}
|
||||
// so, if these need to break, they should have a bigger indent.
|
||||
append_node_to_string(&node->child_nodes.at(node_idx), str, 0,
|
||||
listing_indent + extra_indent);
|
||||
// extra_indent += (str.length() - s0);
|
||||
extra_indent = compute_extra_offset(str, s0, extra_indent);
|
||||
str.push_back(' ');
|
||||
}
|
||||
if (node->top_line_count) {
|
||||
listing_indent = old_indent;
|
||||
}
|
||||
if (node->top_line_count > 0) {
|
||||
str.pop_back();
|
||||
}
|
||||
|
||||
@@ -217,9 +217,11 @@ std::optional<Object> Reader::read_from_stdin(const std::string& prompt, ReplWra
|
||||
/*!
|
||||
* Read a string.
|
||||
*/
|
||||
Object Reader::read_from_string(const std::string& str, bool add_top_level) {
|
||||
Object Reader::read_from_string(const std::string& str,
|
||||
bool add_top_level,
|
||||
const std::optional<std::string>& string_name) {
|
||||
// create text fragment and add to the DB
|
||||
auto textFrag = std::make_shared<ProgramString>(str);
|
||||
auto textFrag = std::make_shared<ProgramString>(str, string_name.value_or("Program string"));
|
||||
db.insert(textFrag);
|
||||
|
||||
// perform read
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include "common/util/assert.h"
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
@@ -22,6 +21,8 @@
|
||||
|
||||
#include "ReplUtils.h"
|
||||
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
/*!
|
||||
@@ -71,7 +72,9 @@ struct Token {
|
||||
class Reader {
|
||||
public:
|
||||
Reader();
|
||||
Object read_from_string(const std::string& str, bool add_top_level = true);
|
||||
Object read_from_string(const std::string& str,
|
||||
bool add_top_level = true,
|
||||
const std::optional<std::string>& string_name = {});
|
||||
std::optional<Object> read_from_stdin(const std::string& prompt, ReplWrapper& repl);
|
||||
Object read_from_file(const std::vector<std::string>& file_path, bool check_encoding = false);
|
||||
bool check_string_is_valid(const std::string& str) const;
|
||||
|
||||
@@ -65,9 +65,14 @@ class ReplText : public SourceText {
|
||||
*/
|
||||
class ProgramString : public SourceText {
|
||||
public:
|
||||
explicit ProgramString(const std::string& text_) : SourceText(text_) {}
|
||||
std::string get_description() override { return "Program string"; }
|
||||
explicit ProgramString(const std::string& text_,
|
||||
const std::string& string_name = "Program string")
|
||||
: SourceText(text_), m_string_name(string_name) {}
|
||||
std::string get_description() override { return m_string_name; }
|
||||
~ProgramString() = default;
|
||||
|
||||
private:
|
||||
std::string m_string_name;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
+1
-1
@@ -1,12 +1,12 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include "common/util/assert.h"
|
||||
#include <mutex>
|
||||
#include "third-party/fmt/color.h"
|
||||
#include "log.h"
|
||||
#ifdef _WIN32 // see lg::initialize
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace lg {
|
||||
struct Logger {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include "common/util/assert.h"
|
||||
#include <third-party/fmt/core.h>
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "Type.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace {
|
||||
std::string reg_kind_to_string(RegClass kind) {
|
||||
@@ -696,9 +696,9 @@ StructureType::StructureType(std::string parent,
|
||||
std::string StructureType::print() const {
|
||||
std::string result = fmt::format(
|
||||
"[StructureType] {}\n parent: {}\n boxed: {}\n dynamic: {}\n size: {}\n pack: {}\n misalign: "
|
||||
"{}\n heap-base: {}\n fields:\n",
|
||||
m_name, m_parent, m_is_boxed, m_dynamic, m_size_in_mem, m_pack, m_allow_misalign,
|
||||
m_heap_base);
|
||||
"{}\n heap-base: {}\n stack-singleton: {}\n fields:\n",
|
||||
m_name, m_parent, m_is_boxed, m_dynamic, m_size_in_mem, m_pack, m_allow_misalign, m_heap_base,
|
||||
m_always_stack_singleton);
|
||||
for (auto& x : m_fields) {
|
||||
result += " " + x.print() + "\n";
|
||||
}
|
||||
@@ -727,7 +727,8 @@ bool StructureType::operator==(const Type& other) const {
|
||||
m_pack == p_other->m_pack &&
|
||||
m_allow_misalign == p_other->m_allow_misalign &&
|
||||
m_offset == p_other->m_offset &&
|
||||
m_idx_of_first_unique_field == p_other->m_idx_of_first_unique_field;
|
||||
m_idx_of_first_unique_field == p_other->m_idx_of_first_unique_field &&
|
||||
m_always_stack_singleton == p_other->m_always_stack_singleton;
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
@@ -773,6 +774,11 @@ std::string StructureType::diff_structure_common(const StructureType& other) con
|
||||
result += fmt::format("allow_misalign: {} vs. {}\n", m_allow_misalign, other.m_allow_misalign);
|
||||
}
|
||||
|
||||
if (m_always_stack_singleton != other.m_always_stack_singleton) {
|
||||
result += fmt::format("always_stack_singleton: {} vs. {}\n", m_always_stack_singleton,
|
||||
other.m_always_stack_singleton);
|
||||
}
|
||||
|
||||
if (m_offset != other.m_offset) {
|
||||
result += fmt::format("offset: {} vs. {}\n", m_offset, other.m_offset);
|
||||
}
|
||||
@@ -906,7 +912,8 @@ bool BasicType::operator==(const Type& other) const {
|
||||
m_allow_misalign == p_other->m_allow_misalign &&
|
||||
m_offset == p_other->m_offset &&
|
||||
m_idx_of_first_unique_field == p_other->m_idx_of_first_unique_field &&
|
||||
m_final == p_other->m_final;
|
||||
m_final == p_other->m_final &&
|
||||
m_always_stack_singleton == p_other->m_always_stack_singleton;
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "common/util/assert.h"
|
||||
#include <unordered_map>
|
||||
#include "common/goal_constants.h"
|
||||
#include "TypeSpec.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
class TypeSystem;
|
||||
|
||||
@@ -275,9 +275,11 @@ class StructureType : public ReferenceType {
|
||||
bool is_dynamic() const { return m_dynamic; }
|
||||
~StructureType() = default;
|
||||
void set_pack(bool pack) { m_pack = pack; }
|
||||
void set_always_stack_singleton() { m_always_stack_singleton = true; }
|
||||
void set_heap_base(int hb) { m_heap_base = hb; }
|
||||
bool is_packed() const { return m_pack; }
|
||||
bool is_allowed_misalign() const { return m_allow_misalign; };
|
||||
bool is_always_stack_singleton() const { return m_always_stack_singleton; }
|
||||
void set_allow_misalign(bool misalign) { m_allow_misalign = misalign; }
|
||||
void set_gen_inspect(bool gen_inspect) { m_generate_inspect = gen_inspect; }
|
||||
|
||||
@@ -300,6 +302,7 @@ class StructureType : public ReferenceType {
|
||||
bool m_pack = false;
|
||||
bool m_allow_misalign = false;
|
||||
int m_offset = 0;
|
||||
bool m_always_stack_singleton = false;
|
||||
size_t m_idx_of_first_unique_field = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "common/util/assert.h"
|
||||
#include "common/util/SmallVector.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
/*!
|
||||
* A :name value modifier to apply to a type.
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
* access types, and reverse type lookups.
|
||||
*/
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "third-party/fmt/color.h"
|
||||
#include <stdexcept>
|
||||
#include <third-party/fmt/core.h>
|
||||
#include "TypeSystem.h"
|
||||
#include "common/util/math_util.h"
|
||||
#include "third-party/fmt/color.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace {
|
||||
template <typename... Args>
|
||||
@@ -1615,7 +1615,10 @@ std::string TypeSystem::generate_deftype_footer(const Type* type) const {
|
||||
result.append(" :pack-me\n");
|
||||
}
|
||||
if (as_structure->is_allowed_misalign()) {
|
||||
result.append(" :allow-misaligned");
|
||||
result.append(" :allow-misaligned\n");
|
||||
}
|
||||
if (as_structure->is_always_stack_singleton()) {
|
||||
result.append(" :always-stack-singleton\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -277,6 +277,7 @@ struct StructureDefResult {
|
||||
bool pack_me = false;
|
||||
bool allow_misaligned = false;
|
||||
bool final = false;
|
||||
bool always_stack_singleton = false;
|
||||
};
|
||||
|
||||
StructureDefResult parse_structure_def(StructureType* type,
|
||||
@@ -347,6 +348,8 @@ StructureDefResult parse_structure_def(StructureType* type,
|
||||
result.allow_misaligned = true;
|
||||
} else if (opt_name == ":final") {
|
||||
result.final = true;
|
||||
} else if (opt_name == ":always-stack-singleton") {
|
||||
result.always_stack_singleton = true;
|
||||
} else {
|
||||
throw std::runtime_error("Invalid option in field specification: " + opt_name);
|
||||
}
|
||||
@@ -572,6 +575,13 @@ DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts) {
|
||||
name);
|
||||
throw std::runtime_error("invalid pack option on basic");
|
||||
}
|
||||
if (sr.always_stack_singleton) {
|
||||
fmt::print(
|
||||
"[TypeSystem] :always-stack-singleton was set on {}, which is a basic and cannot "
|
||||
"be a stack singleton\n",
|
||||
name);
|
||||
throw std::runtime_error("invalid stack singleton option on basic");
|
||||
}
|
||||
new_type->set_heap_base(result.flags.heap_base);
|
||||
if (sr.final) {
|
||||
new_type->set_final();
|
||||
@@ -592,6 +602,9 @@ DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts) {
|
||||
if (sr.allow_misaligned) {
|
||||
new_type->set_allow_misalign(true);
|
||||
}
|
||||
if (sr.always_stack_singleton) {
|
||||
new_type->set_always_stack_singleton();
|
||||
}
|
||||
if (sr.final) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("[TypeSystem] :final option cannot be used on structure type {}", name));
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include "common/util/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
class BinaryReader {
|
||||
public:
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
* Write raw data like a stream.
|
||||
*/
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include "common/util/assert.h"
|
||||
|
||||
struct BinaryWriterRef {
|
||||
size_t offset;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include "common/util/assert.h"
|
||||
#include "common/util/Range.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
constexpr int BITS_PER_BYTE = 8;
|
||||
template <typename T>
|
||||
@@ -93,4 +93,4 @@ inline u32 count_leading_zeros_u32(u32 in) {
|
||||
_BitScanReverse(&result, in);
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <cstdio> /* defines FILENAME_MAX */
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "common/util/assert.h"
|
||||
#include <cstdlib>
|
||||
#include "common/util/BinaryReader.h"
|
||||
#include "BinaryWriter.h"
|
||||
@@ -24,6 +23,7 @@
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#endif
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace file_util {
|
||||
std::filesystem::path get_user_home_dir() {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/util/Timer.h"
|
||||
|
||||
class FrameLimiter {
|
||||
public:
|
||||
void run(double target_fps, bool experimental_accurate_lag, double engine_time) {
|
||||
double target_seconds;
|
||||
if (experimental_accurate_lag) {
|
||||
target_seconds = round_to_nearest_60fps(engine_time);
|
||||
} else {
|
||||
target_seconds = 1.f / target_fps;
|
||||
}
|
||||
double remaining_time = target_seconds - m_timer.getSeconds();
|
||||
while (remaining_time > 0) {
|
||||
if (remaining_time > 0.003) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(int(remaining_time * 1e6 * 0.5)));
|
||||
}
|
||||
remaining_time = target_seconds - m_timer.getSeconds();
|
||||
}
|
||||
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
private:
|
||||
double round_to_nearest_60fps(double current) {
|
||||
double one_frame = 1.f / 60.f;
|
||||
int frames_missed = (current / one_frame); // rounds down
|
||||
if (frames_missed > 4) {
|
||||
frames_missed = 4;
|
||||
}
|
||||
return (frames_missed + 1) * one_frame;
|
||||
}
|
||||
|
||||
Timer m_timer;
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/util/assert.h"
|
||||
|
||||
/*!
|
||||
* The Serializer is a tool to load or save data from a buffer.
|
||||
@@ -216,4 +216,4 @@ class Serializer {
|
||||
size_t m_size = 0;
|
||||
size_t m_offset = 0;
|
||||
bool m_writing = false;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "assert.h"
|
||||
|
||||
namespace cu {
|
||||
// This might seem stupid, but compiling an empty file with #include <algorithm> takes 0.5 seconds.
|
||||
|
||||
+1
-6
@@ -1,11 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef JAK_V2_TIMER_H
|
||||
#define JAK_V2_TIMER_H
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include "common/util/assert.h"
|
||||
|
||||
/*!
|
||||
* Timer for measuring time elapsed with clock_monotonic
|
||||
@@ -45,5 +42,3 @@ class Timer {
|
||||
|
||||
struct timespec _startTime = {};
|
||||
};
|
||||
|
||||
#endif // JAK_V2_TIMER_H
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "common/util/assert.h"
|
||||
|
||||
/*!
|
||||
* A simple prefix tree. It works similarly to a map, but also supports fast lookups by prefix with
|
||||
@@ -182,4 +182,4 @@ T* Trie<T>::operator[](const std::string& str) {
|
||||
template <typename T>
|
||||
std::vector<T*> Trie<T>::lookup_prefix(const std::string& str) const {
|
||||
return m_root.lookup_prefix(str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
/*!
|
||||
* @file assert.h
|
||||
* Wrapper around <cassert>.
|
||||
* Make sure this file is always the last one included.
|
||||
*/
|
||||
|
||||
#if defined NDEBUG && defined _WIN32
|
||||
|
||||
#pragma push_macro("NDEBUG")
|
||||
#if defined NDEBUG
|
||||
|
||||
#undef NDEBUG
|
||||
#undef assert
|
||||
#include <cassert>
|
||||
|
||||
#pragma pop_macro("NDEBUG")
|
||||
#define NDEBUG 1
|
||||
|
||||
#else
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#endif
|
||||
|
||||
#define ASSERT assert
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "common/util/assert.h"
|
||||
#include <cstring>
|
||||
#include "dgo_util.h"
|
||||
#include "common/versions.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
/*!
|
||||
* Assert false if the char[] has non-null data after the null terminated string.
|
||||
@@ -50,4 +50,4 @@ std::string get_object_file_name(const std::string& original_name, u8* data, int
|
||||
}
|
||||
|
||||
return original_name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/assert.h"
|
||||
#include "json_util.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
/*!
|
||||
* Strip out // and / * comments
|
||||
@@ -107,4 +107,4 @@ Range<int> parse_json_optional_integer_range(const nlohmann::json& json) {
|
||||
} else {
|
||||
throw std::runtime_error("Invalid json as input to parse_json_optional_integer_range");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/goal_constants.h"
|
||||
#include "third-party/dragonbox.h"
|
||||
#include "print_float.h"
|
||||
#include "common/util/assert.h"
|
||||
@@ -19,6 +19,14 @@ std::string float_to_string(float value, bool append_trailing_decimal) {
|
||||
return {buff};
|
||||
}
|
||||
|
||||
/*!
|
||||
* Wrapper around float_to_string, for printing meters. Unlike float_to_string, it does not append
|
||||
* decimals by default.
|
||||
*/
|
||||
std::string meters_to_string(float value, bool append_trailing_decimal) {
|
||||
return float_to_string(value / METER_LENGTH, append_trailing_decimal);
|
||||
}
|
||||
|
||||
int float_to_cstr(float value, char* buffer, bool append_trailing_decimal) {
|
||||
assert(std::isfinite(value));
|
||||
// dragonbox gives us:
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
#include <string>
|
||||
|
||||
std::string float_to_string(float value, bool append_trailing_decimal = true);
|
||||
int float_to_cstr(float value, char* buffer, bool append_trailing_decimal = true);
|
||||
std::string meters_to_string(float value, bool append_trailing_decimal = false);
|
||||
int float_to_cstr(float value, char* buffer, bool append_trailing_decimal = true);
|
||||
|
||||
@@ -6,6 +6,7 @@ add_library(
|
||||
analysis/cfg_builder.cpp
|
||||
analysis/expression_build.cpp
|
||||
analysis/final_output.cpp
|
||||
analysis/find_defpartgroup.cpp
|
||||
analysis/find_defstates.cpp
|
||||
analysis/find_skelgroups.cpp
|
||||
analysis/inline_asm_rewrite.cpp
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
#include "InstructionDecode.h"
|
||||
#include "common/util/assert.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
// utility class to extract fields of an opcode.
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Utilities for checking if an instruction matches some criteria.
|
||||
*/
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include "InstructionMatching.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
/*!
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "common/util/assert.h"
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
#include "common/common_types.h"
|
||||
#include "InstructionParser.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
InstructionParser::InstructionParser() {
|
||||
@@ -487,4 +487,4 @@ std::string ParsedProgram::print() {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*/
|
||||
|
||||
#include "Register.h"
|
||||
#include "common/util/assert.h"
|
||||
#include <stdexcept>
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
namespace Reg {
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include "common/util/assert.h"
|
||||
#include <string>
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
// Namespace for register name constants
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <algorithm>
|
||||
#include "common/util/assert.h"
|
||||
#include "BasicBlocks.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
#include "decompiler/Disasm/InstructionMatching.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
/*!
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "common/util/assert.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "decompiler/Disasm/InstructionMatching.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
#include "CfgVtx.h"
|
||||
#include "Function.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
/////////////////////////////////////////
|
||||
@@ -1247,6 +1247,43 @@ bool ControlFlowGraph::clean_up_asm_branches() {
|
||||
old_seq->parent_claim(seq);
|
||||
bds->parent_claim(seq);
|
||||
|
||||
return false;
|
||||
} else if (b0_seq && !b1_seq) {
|
||||
replaced = true;
|
||||
m_blocks.at(bds->succ_branch->get_first_block_id())->needs_label = true;
|
||||
|
||||
auto* seq = dynamic_cast<SequenceVtx*>(b0);
|
||||
assert(seq);
|
||||
|
||||
if (b0->succ_branch) {
|
||||
b0->succ_branch->replace_preds_with_and_check({b0}, nullptr);
|
||||
}
|
||||
|
||||
if (bds->succ_branch) {
|
||||
// likely delay slots "branch" in this graph.
|
||||
bds->succ_branch->replace_preds_with_and_check({bds}, nullptr);
|
||||
}
|
||||
|
||||
seq->seq.push_back(bds);
|
||||
|
||||
seq->seq.push_back(b1);
|
||||
|
||||
for (auto* x : b1->succs()) {
|
||||
// printf("fix preds of %s\n", x->to_string().c_str());
|
||||
x->replace_pred_and_check(b1, seq);
|
||||
}
|
||||
seq->succ_branch = b1->succ_branch;
|
||||
seq->succ_ft = b1->succ_ft;
|
||||
seq->end_branch = b1->end_branch;
|
||||
seq->next = b1->next;
|
||||
if (seq->next) {
|
||||
seq->next->prev = seq;
|
||||
}
|
||||
|
||||
// todo - proper trash?
|
||||
b1->parent_claim(seq);
|
||||
bds->parent_claim(seq);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef JAK_DISASSEMBLER_CFGVTX_H
|
||||
#define JAK_DISASSEMBLER_CFGVTX_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/util/assert.h"
|
||||
@@ -394,4 +391,3 @@ std::shared_ptr<ControlFlowGraph> build_cfg(const LinkedObjectFile& file,
|
||||
const CondWithElseLengthHack& cond_with_else_hack,
|
||||
const std::unordered_set<int>& blocks_ending_in_asm_br);
|
||||
} // namespace decompiler
|
||||
#endif // JAK_DISASSEMBLER_CFGVTX_H
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "common/util/assert.h"
|
||||
#include <vector>
|
||||
#include "Function.h"
|
||||
#include "common/log/log.h"
|
||||
@@ -9,6 +8,7 @@
|
||||
#include "decompiler/IR/IR.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "common/util/BitUtils.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
namespace {
|
||||
@@ -88,7 +88,8 @@ void Function::analyze_prologue(const LinkedObjectFile& file) {
|
||||
|
||||
// storing s7 on the stack is done by interrupt handlers, which we probably don't want to
|
||||
// support
|
||||
if (instr.kind == InstructionKind::SD && instr.get_src(0).get_reg() == make_gpr(Reg::S7)) {
|
||||
if (instr.kind == InstructionKind::SD && instr.get_src(0).get_reg() == make_gpr(Reg::S7) &&
|
||||
instr.get_src(2).get_reg() == make_gpr(Reg::SP)) {
|
||||
lg::warn(
|
||||
"Function {} was flagged as asm due to this instruction: {}. Consider flagging as asm "
|
||||
"in config!",
|
||||
@@ -765,4 +766,4 @@ BlockTopologicalSort Function::bb_topo_sort() {
|
||||
std::string Function::name() const {
|
||||
return guessed_name.to_string();
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include "common/util/assert.h"
|
||||
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
class DecompWarnings {
|
||||
@@ -110,4 +109,4 @@ class DecompWarnings {
|
||||
std::vector<Warning> m_warnings;
|
||||
bool m_used_lq_sq = false;
|
||||
};
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
+3
-1
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef JAK_IR_H
|
||||
#define JAK_IR_H
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
@@ -10,6 +11,7 @@
|
||||
#include "common/type_system/TypeSpec.h"
|
||||
#include "decompiler/util/DecompilerTypeSystem.h"
|
||||
#include "decompiler/util/TP_Type.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace goos {
|
||||
class Object;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "common/util/assert.h"
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include "common/goal_constants.h"
|
||||
@@ -8,6 +7,7 @@
|
||||
#include "AtomicOp.h"
|
||||
#include "OpenGoalMapping.h"
|
||||
#include "Form.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
/////////////////////////////
|
||||
@@ -306,6 +306,9 @@ std::string get_simple_expression_op_name(SimpleExpression::Kind kind) {
|
||||
return "vec3dot";
|
||||
case SimpleExpression::Kind::VECTOR_4_DOT:
|
||||
return "vec4dot";
|
||||
case SimpleExpression::Kind::SET_ON_LESS_THAN:
|
||||
case SimpleExpression::Kind::SET_ON_LESS_THAN_IMM:
|
||||
return "set-on-less-than";
|
||||
default:
|
||||
assert(false);
|
||||
return {};
|
||||
@@ -367,6 +370,9 @@ int get_simple_expression_arg_count(SimpleExpression::Kind kind) {
|
||||
case SimpleExpression::Kind::VECTOR_3_DOT:
|
||||
case SimpleExpression::Kind::VECTOR_4_DOT:
|
||||
return 2;
|
||||
case SimpleExpression::Kind::SET_ON_LESS_THAN:
|
||||
case SimpleExpression::Kind::SET_ON_LESS_THAN_IMM:
|
||||
return 2;
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
@@ -512,7 +518,10 @@ AsmOp::AsmOp(Instruction instr, int my_idx) : AtomicOp(my_idx), m_instr(std::mov
|
||||
if (src.is_reg()) {
|
||||
auto reg = src.get_reg();
|
||||
if (reg.get_kind() == Reg::FPR || reg.get_kind() == Reg::GPR || reg.get_kind() == Reg::VF) {
|
||||
m_src[i] = RegisterAccess(AccessMode::READ, reg, my_idx, true);
|
||||
if (reg != Register(Reg::GPR, Reg::R0) ||
|
||||
(m_instr.kind == InstructionKind::PCPYUD || m_instr.kind == InstructionKind::PEXTUW)) {
|
||||
m_src[i] = RegisterAccess(AccessMode::READ, reg, my_idx, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "common/util/assert.h"
|
||||
#include <utility>
|
||||
#include "common/goos/Object.h"
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
#include "decompiler/Disasm/Instruction.h"
|
||||
#include "decompiler/IR2/IR2_common.h"
|
||||
#include "Env.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
class FormElement;
|
||||
@@ -235,7 +235,9 @@ class SimpleExpression {
|
||||
VECTOR_CROSS,
|
||||
SUBU_L32_S7, // use SUBU X, src0, s7 to check if lower 32-bits are s7.
|
||||
VECTOR_3_DOT,
|
||||
VECTOR_4_DOT
|
||||
VECTOR_4_DOT,
|
||||
SET_ON_LESS_THAN,
|
||||
SET_ON_LESS_THAN_IMM
|
||||
};
|
||||
|
||||
// how many arguments?
|
||||
|
||||
@@ -437,7 +437,8 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
return TP_Type::make_from_ts(TypeSpec("int"));
|
||||
}
|
||||
|
||||
if (arg0_type.is_product_with(4) && tc(dts, TypeSpec("type"), arg1_type)) {
|
||||
if (arg0_type.is_product_with(4) && tc(dts, TypeSpec("type"), arg1_type) &&
|
||||
env.func->name() != "overrides-parent-method?") {
|
||||
// dynamic access into the method array with shift, add, offset-load
|
||||
// no need to track the type because we don't know the method index anyway.
|
||||
return TP_Type::make_partial_dyanmic_vtable_access();
|
||||
@@ -621,12 +622,12 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
return TP_Type::make_from_ts(arg0_type.typespec());
|
||||
}
|
||||
|
||||
if (m_kind == Kind::ADD && tc(dts, TypeSpec("structure"), arg0_type) &&
|
||||
if ((m_kind == Kind::ADD || m_kind == Kind::SUB) && tc(dts, TypeSpec("structure"), arg0_type) &&
|
||||
arg1_type.is_integer_constant()) {
|
||||
auto type_info = dts.ts.lookup_type(arg0_type.typespec());
|
||||
|
||||
// get next in memory, allow this as &+
|
||||
if ((u64)type_info->get_size_in_memory() == arg1_type.get_integer_constant()) {
|
||||
// get next in memory, allow this as &+/&-
|
||||
if ((s64)type_info->get_size_in_memory() == std::abs((s64)arg1_type.get_integer_constant())) {
|
||||
return TP_Type::make_from_ts(arg0_type.typespec());
|
||||
}
|
||||
|
||||
@@ -827,7 +828,8 @@ TypeState AsmOp::propagate_types_internal(const TypeState& input,
|
||||
}
|
||||
|
||||
// sllv out, in, r0
|
||||
if (m_instr.kind == InstructionKind::SLLV && m_src[1]->reg() == Register(Reg::GPR, Reg::R0)) {
|
||||
if (m_instr.kind == InstructionKind::SLLV &&
|
||||
instruction().src[1].is_reg(Register(Reg::GPR, Reg::R0))) {
|
||||
auto type = dts.ts.lookup_type(result.get(m_src[0]->reg()).typespec());
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
if (as_bitfield) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <stdexcept>
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
#include <decompiler/util/DecompilerTypeSystem.h>
|
||||
#include "decompiler/util/DecompilerTypeSystem.h"
|
||||
#include "Env.h"
|
||||
#include "Form.h"
|
||||
#include "decompiler/analysis/atomic_op_builder.h"
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/util/assert.h"
|
||||
#include <common/goos/Object.h>
|
||||
#include "common/goos/Object.h"
|
||||
#include "decompiler/util/TP_Type.h"
|
||||
#include "decompiler/util/StackSpillMap.h"
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
#include "decompiler/IR2/IR2_common.h"
|
||||
#include "decompiler/analysis/reg_usage.h"
|
||||
#include "decompiler/config.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
class LinkedObjectFile;
|
||||
@@ -234,4 +234,4 @@ class Env {
|
||||
|
||||
StackSpillMap m_stack_spill_map;
|
||||
};
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
+151
-10
@@ -7,6 +7,7 @@
|
||||
#include "common/type_system/TypeSystem.h"
|
||||
#include "decompiler/util/DecompilerTypeSystem.h"
|
||||
#include "decompiler/util/data_decompile.h"
|
||||
#include "decompiler/util/sparticle_decompile.h"
|
||||
#include "common/util/print_float.h"
|
||||
|
||||
namespace decompiler {
|
||||
@@ -2985,21 +2986,18 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
|
||||
|
||||
std::vector<goos::Object> lod_forms;
|
||||
for (const auto& e : m_info.lods) {
|
||||
auto f_dist = pretty_print::to_symbol(fmt::format(
|
||||
"(meters {})", float_to_string(e.lod_dist->to_form(env).as_float() / METER_LENGTH, false)));
|
||||
auto f_dist = pretty_print::to_symbol(
|
||||
fmt::format("(meters {})", meters_to_string(e.lod_dist->to_form(env).as_float())));
|
||||
lod_forms.push_back(pretty_print::build_list(e.mgeo->to_form(env), f_dist));
|
||||
}
|
||||
forms.push_back(pretty_print::build_list(lod_forms));
|
||||
|
||||
forms.push_back(pretty_print::to_symbol(fmt::format(
|
||||
":bounds (static-spherem {} {} {} {})", meters_to_string(m_static_info.bounds.x()),
|
||||
meters_to_string(m_static_info.bounds.y()), meters_to_string(m_static_info.bounds.z()),
|
||||
meters_to_string(m_static_info.bounds.w()))));
|
||||
forms.push_back(pretty_print::to_symbol(
|
||||
fmt::format(":bounds (static-spherem {} {} {} {})",
|
||||
float_to_string(m_static_info.bounds.x() / METER_LENGTH, false),
|
||||
float_to_string(m_static_info.bounds.y() / METER_LENGTH, false),
|
||||
float_to_string(m_static_info.bounds.z() / METER_LENGTH, false),
|
||||
float_to_string(m_static_info.bounds.w() / METER_LENGTH, false))));
|
||||
forms.push_back(pretty_print::to_symbol(
|
||||
fmt::format(":longest-edge (meters {})",
|
||||
float_to_string(m_static_info.longest_edge / METER_LENGTH, false))));
|
||||
fmt::format(":longest-edge (meters {})", meters_to_string(m_static_info.longest_edge))));
|
||||
|
||||
if (m_static_info.shadow != 0) {
|
||||
forms.push_back(pretty_print::to_symbol(fmt::format(":shadow {}", m_static_info.shadow)));
|
||||
@@ -3018,6 +3016,149 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
|
||||
return pretty_print::build_list(forms);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// DefpartgroupElement
|
||||
////////////////////////////////
|
||||
|
||||
DefpartgroupElement::DefpartgroupElement(const StaticInfo& data, int group_id)
|
||||
: m_static_info(data), m_group_id(group_id) {}
|
||||
|
||||
void DefpartgroupElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
f(this);
|
||||
}
|
||||
|
||||
void DefpartgroupElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void DefpartgroupElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
void DefpartgroupElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
goos::Object DefpartgroupElement::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> forms;
|
||||
forms.push_back(pretty_print::to_symbol(fmt::format("defpartgroup {}", name())));
|
||||
forms.push_back(pretty_print::to_symbol(fmt::format(":id {}", m_group_id)));
|
||||
if (m_static_info.duration != 3000) {
|
||||
forms.push_back(pretty_print::to_symbol(fmt::format(":duration {}", m_static_info.duration)));
|
||||
}
|
||||
if (m_static_info.linger != 1500) {
|
||||
forms.push_back(
|
||||
pretty_print::to_symbol(fmt::format(":linger-duration {}", m_static_info.linger)));
|
||||
}
|
||||
if (m_static_info.flags != 0) {
|
||||
auto things = decompile_bitfield_enum_from_int(TypeSpec("sp-group-flag"), env.dts->ts,
|
||||
m_static_info.flags);
|
||||
std::string result = ":flags (";
|
||||
for (auto& thing : things) {
|
||||
result += thing;
|
||||
result += ' ';
|
||||
}
|
||||
result.pop_back();
|
||||
result += ')';
|
||||
forms.push_back(pretty_print::to_symbol(result));
|
||||
}
|
||||
forms.push_back(pretty_print::to_symbol(fmt::format(
|
||||
":bounds (static-bspherem {} {} {} {})", meters_to_string(m_static_info.bounds.x()),
|
||||
meters_to_string(m_static_info.bounds.y()), meters_to_string(m_static_info.bounds.z()),
|
||||
meters_to_string(m_static_info.bounds.w()))));
|
||||
|
||||
std::vector<goos::Object> item_forms;
|
||||
for (const auto& e : m_static_info.elts) {
|
||||
s32 launcher = e.part_id;
|
||||
u16 flags = e.flags;
|
||||
u16 period = e.period;
|
||||
u16 length = e.length;
|
||||
u16 offset = e.offset;
|
||||
u32 hour_mask = e.hour_mask;
|
||||
u32 binding = e.binding;
|
||||
|
||||
std::string result =
|
||||
fmt::format("(sp-item {}", launcher); // use decimal, so it matches array idx
|
||||
|
||||
if (e.fade != 0.0) {
|
||||
result += fmt::format(" :fade-after (meters {})", meters_to_string(e.fade));
|
||||
}
|
||||
|
||||
if (e.falloff != 0.0) {
|
||||
result += fmt::format(" :falloff-to (meters {})", meters_to_string(e.falloff));
|
||||
}
|
||||
|
||||
if (flags) {
|
||||
auto things =
|
||||
decompile_bitfield_enum_from_int(TypeSpec("sp-group-item-flag"), env.dts->ts, flags);
|
||||
result += " :flags (";
|
||||
for (auto& thing : things) {
|
||||
result += thing;
|
||||
result += ' ';
|
||||
}
|
||||
result.pop_back();
|
||||
result += ')';
|
||||
}
|
||||
|
||||
if (period) {
|
||||
result += fmt::format(" :period {}", period);
|
||||
}
|
||||
|
||||
if (length) {
|
||||
result += fmt::format(" :length {}", length);
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
result += fmt::format(" :offset {}", offset);
|
||||
}
|
||||
|
||||
if (hour_mask) {
|
||||
result += fmt::format(" :hour-mask #b{:b}", hour_mask);
|
||||
}
|
||||
|
||||
if (binding) {
|
||||
result += fmt::format(" :binding {}", binding);
|
||||
}
|
||||
|
||||
result += ')';
|
||||
|
||||
item_forms.push_back(pretty_print::to_symbol(result));
|
||||
}
|
||||
if (!item_forms.empty()) {
|
||||
forms.push_back(pretty_print::to_symbol(":parts"));
|
||||
forms.push_back(pretty_print::build_list(item_forms));
|
||||
}
|
||||
|
||||
return pretty_print::build_list(forms);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// DefpartElement
|
||||
////////////////////////////////
|
||||
|
||||
DefpartElement::DefpartElement(const StaticInfo& data, int id) : m_static_info(data), m_id(id) {}
|
||||
|
||||
void DefpartElement::apply(const std::function<void(FormElement*)>& f) {
|
||||
f(this);
|
||||
}
|
||||
|
||||
void DefpartElement::apply_form(const std::function<void(Form*)>&) {}
|
||||
void DefpartElement::collect_vars(RegAccessSet&, bool) const {}
|
||||
void DefpartElement::get_modified_regs(RegSet&) const {}
|
||||
|
||||
goos::Object DefpartElement::to_form_internal(const Env& env) const {
|
||||
std::vector<goos::Object> forms;
|
||||
forms.push_back(pretty_print::to_symbol("defpart"));
|
||||
forms.push_back(pretty_print::to_symbol(fmt::format("{}", m_id)));
|
||||
|
||||
std::vector<goos::Object> item_forms;
|
||||
for (const auto& e : m_static_info.fields) {
|
||||
if (e.field_id == 67) {
|
||||
// sp-end
|
||||
break;
|
||||
}
|
||||
item_forms.push_back(decompile_sparticle_field_init(e, env.dts->ts));
|
||||
}
|
||||
if (!item_forms.empty()) {
|
||||
forms.push_back(pretty_print::to_symbol(":init-specs"));
|
||||
forms.push_back(pretty_print::build_list(item_forms));
|
||||
}
|
||||
|
||||
return pretty_print::build_list(forms);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// ResLumpMacroElement
|
||||
////////////////////////////////
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "common/type_system/state.h"
|
||||
#include "decompiler/IR2/LabelDB.h"
|
||||
#include "common/math/Vector.h"
|
||||
#include "decompiler/ObjectFile/LinkedWord.h"
|
||||
|
||||
namespace decompiler {
|
||||
class Form;
|
||||
@@ -571,6 +572,10 @@ class ConditionElement : public FormElement {
|
||||
FormPool& pool,
|
||||
const std::vector<Form*>& source_forms,
|
||||
const std::vector<TypeSpec>& types);
|
||||
FormElement* make_geq_zero_unsigned_check_generic(const Env& env,
|
||||
FormPool& pool,
|
||||
const std::vector<Form*>& source_forms,
|
||||
const std::vector<TypeSpec>& types);
|
||||
FormElement* make_geq_zero_signed_check_generic(const Env& env,
|
||||
FormPool& pool,
|
||||
const std::vector<Form*>& source_forms,
|
||||
@@ -1674,6 +1679,77 @@ class DefskelgroupElement : public FormElement {
|
||||
Info m_info;
|
||||
};
|
||||
|
||||
class DefpartgroupElement : public FormElement {
|
||||
public:
|
||||
struct StaticInfo {
|
||||
u16 duration;
|
||||
u16 linger;
|
||||
u16 flags;
|
||||
std::string name;
|
||||
math::Vector4f bounds;
|
||||
|
||||
struct PartGroupItem {
|
||||
u32 part_id;
|
||||
float fade;
|
||||
float falloff;
|
||||
u16 flags;
|
||||
u16 period;
|
||||
u16 length;
|
||||
u16 offset;
|
||||
u32 hour_mask;
|
||||
u32 binding;
|
||||
};
|
||||
std::vector<PartGroupItem> elts;
|
||||
};
|
||||
DefpartgroupElement(const StaticInfo& data, int group_id);
|
||||
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
const std::string& name() const { return m_static_info.name; }
|
||||
|
||||
private:
|
||||
StaticInfo m_static_info;
|
||||
int m_group_id;
|
||||
};
|
||||
|
||||
class DefpartElement : public FormElement {
|
||||
public:
|
||||
struct StaticInfo {
|
||||
struct PartField {
|
||||
u16 field_id;
|
||||
u16 flags;
|
||||
std::vector<LinkedWord> data;
|
||||
goos::Object sound_spec;
|
||||
};
|
||||
std::vector<PartField> fields;
|
||||
};
|
||||
DefpartElement(const StaticInfo& data, int id);
|
||||
|
||||
goos::Object to_form_internal(const Env& env) const override;
|
||||
void apply(const std::function<void(FormElement*)>& f) override;
|
||||
void apply_form(const std::function<void(Form*)>& f) override;
|
||||
void collect_vars(RegAccessSet& vars, bool recursive) const override;
|
||||
void update_from_stack(const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) override;
|
||||
void get_modified_regs(RegSet& regs) const override;
|
||||
|
||||
private:
|
||||
StaticInfo m_static_info;
|
||||
int m_id;
|
||||
};
|
||||
|
||||
class ResLumpMacroElement : public FormElement {
|
||||
public:
|
||||
enum class Kind { DATA, STRUCT, VALUE, INVALID };
|
||||
|
||||
@@ -1065,7 +1065,8 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
|
||||
result->push_back(pool.alloc_element<DerefElement>(args.at(1), rd_ok.addr_of, tokens));
|
||||
return;
|
||||
} else {
|
||||
lg::error("Bad is {}\n", args.at(0)->to_string(env));
|
||||
// TODO - output error to IR
|
||||
lg::error("Bad {} at OP: {}\n", args.at(0)->to_string(env), m_my_idx);
|
||||
throw std::runtime_error("Failed to match product_with_constant inline array access 2.");
|
||||
}
|
||||
}
|
||||
@@ -3583,66 +3584,59 @@ FormElement* sc_to_handle_get_proc(ShortCircuitElement* elt,
|
||||
|
||||
void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
mark_popped();
|
||||
if (!used_as_value.value_or(false)) {
|
||||
throw std::runtime_error(
|
||||
"ShortCircuitElement::push_to_stack not implemented for result not used case.");
|
||||
|
||||
if (already_rewritten) {
|
||||
stack.push_form_element(this, true);
|
||||
} else {
|
||||
if (already_rewritten) {
|
||||
stack.push_form_element(this, true);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// the first condition is special
|
||||
auto first_condition = entries.front().condition;
|
||||
// lets evaluate in on the parent stack...
|
||||
for (auto x : first_condition->elts()) {
|
||||
x->push_to_stack(env, pool, stack);
|
||||
}
|
||||
// the first condition is special
|
||||
auto first_condition = entries.front().condition;
|
||||
// lets evaluate in on the parent stack...
|
||||
for (auto x : first_condition->elts()) {
|
||||
x->push_to_stack(env, pool, stack);
|
||||
}
|
||||
|
||||
for (int i = 0; i < int(entries.size()); i++) {
|
||||
auto& entry = entries.at(i);
|
||||
if (entry.condition == first_condition) {
|
||||
entry.condition->clear();
|
||||
entry.condition->push_back(stack.pop_back(pool));
|
||||
for (int i = 0; i < int(entries.size()); i++) {
|
||||
auto& entry = entries.at(i);
|
||||
if (entry.condition == first_condition) {
|
||||
entry.condition->clear();
|
||||
entry.condition->push_back(stack.pop_back(pool));
|
||||
} else {
|
||||
FormStack temp_stack(false);
|
||||
for (auto& elt : entry.condition->elts()) {
|
||||
elt->push_to_stack(env, pool, temp_stack);
|
||||
}
|
||||
|
||||
std::vector<FormElement*> new_entries;
|
||||
if (i == int(entries.size()) - 1) {
|
||||
new_entries = rewrite_to_get_var(temp_stack, pool, final_result, env);
|
||||
} else {
|
||||
FormStack temp_stack(false);
|
||||
for (auto& elt : entry.condition->elts()) {
|
||||
elt->push_to_stack(env, pool, temp_stack);
|
||||
}
|
||||
new_entries = temp_stack.rewrite(pool, env);
|
||||
}
|
||||
|
||||
std::vector<FormElement*> new_entries;
|
||||
if (i == int(entries.size()) - 1) {
|
||||
new_entries = rewrite_to_get_var(temp_stack, pool, final_result, env);
|
||||
} else {
|
||||
new_entries = temp_stack.rewrite(pool, env);
|
||||
}
|
||||
|
||||
entry.condition->clear();
|
||||
for (auto e : new_entries) {
|
||||
if (dynamic_cast<EmptyElement*>(e)) {
|
||||
continue;
|
||||
}
|
||||
entry.condition->push_back(e);
|
||||
}
|
||||
if (entry.condition->elts().empty()) {
|
||||
entry.condition->push_back(pool.alloc_element<EmptyElement>());
|
||||
entry.condition->clear();
|
||||
for (auto e : new_entries) {
|
||||
if (dynamic_cast<EmptyElement*>(e)) {
|
||||
continue;
|
||||
}
|
||||
entry.condition->push_back(e);
|
||||
}
|
||||
if (entry.condition->elts().empty()) {
|
||||
entry.condition->push_back(pool.alloc_element<EmptyElement>());
|
||||
}
|
||||
}
|
||||
|
||||
FormElement* to_push = this;
|
||||
auto as_handle_get = sc_to_handle_get_proc(this, env, pool, stack);
|
||||
if (as_handle_get) {
|
||||
to_push = as_handle_get;
|
||||
}
|
||||
|
||||
assert(used_as_value.has_value());
|
||||
stack.push_value_to_reg(final_result, pool.alloc_single_form(nullptr, to_push), true,
|
||||
env.get_variable_type(final_result, false));
|
||||
already_rewritten = true;
|
||||
}
|
||||
|
||||
FormElement* to_push = this;
|
||||
auto as_handle_get = sc_to_handle_get_proc(this, env, pool, stack);
|
||||
if (as_handle_get) {
|
||||
to_push = as_handle_get;
|
||||
}
|
||||
|
||||
assert(used_as_value.has_value());
|
||||
stack.push_value_to_reg(final_result, pool.alloc_single_form(nullptr, to_push), true,
|
||||
env.get_variable_type(final_result, false));
|
||||
already_rewritten = true;
|
||||
}
|
||||
|
||||
void ShortCircuitElement::update_from_stack(const Env& env,
|
||||
@@ -4029,6 +4023,31 @@ FormElement* ConditionElement::make_geq_zero_signed_check_generic(
|
||||
}
|
||||
}
|
||||
|
||||
FormElement* ConditionElement::make_geq_zero_unsigned_check_generic(
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
const std::vector<Form*>& source_forms,
|
||||
const std::vector<TypeSpec>& types) {
|
||||
assert(source_forms.size() == 1);
|
||||
// (>= (shl (the-as int iter) 62) 0) -> (not (pair? iter))
|
||||
|
||||
// match (shl [(the-as int [x]) | [x]] 62)
|
||||
auto shift_match =
|
||||
match(Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
|
||||
{
|
||||
Matcher::match_or({Matcher::cast("uint", Matcher::any(0)),
|
||||
Matcher::any(0)}), // the val
|
||||
Matcher::integer(62) // get the bit in the highest position.
|
||||
}),
|
||||
source_forms.at(0));
|
||||
|
||||
auto casted = make_casts_if_needed(source_forms, types, TypeSpec("uint"), pool, env);
|
||||
auto zero =
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, SimpleAtom::make_int_constant(0));
|
||||
casted.push_back(zero);
|
||||
return pool.alloc_element<GenericElement>(GenericOperator::make_fixed(FixedOperatorKind::GEQ),
|
||||
casted);
|
||||
}
|
||||
FormElement* ConditionElement::make_generic(const Env& env,
|
||||
FormPool& pool,
|
||||
const std::vector<Form*>& source_forms,
|
||||
@@ -4099,6 +4118,10 @@ FormElement* ConditionElement::make_generic(const Env& env,
|
||||
return make_geq_zero_signed_check_generic(env, pool, source_forms, types);
|
||||
}
|
||||
|
||||
case IR2_Condition::Kind::GEQ_ZERO_UNSIGNED: {
|
||||
return make_geq_zero_unsigned_check_generic(env, pool, source_forms, types);
|
||||
}
|
||||
|
||||
case IR2_Condition::Kind::GREATER_THAN_ZERO_UNSIGNED: {
|
||||
auto casted = make_casts_if_needed(source_forms, types, TypeSpec("uint"), pool, env);
|
||||
auto zero = pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
@@ -4359,13 +4382,10 @@ void push_asm_sllv_to_stack(const AsmOp* op,
|
||||
auto dst = op->dst();
|
||||
assert(dst.has_value());
|
||||
|
||||
auto sav = op->src(1);
|
||||
assert(sav.has_value());
|
||||
|
||||
auto arg0_type = env.get_variable_type(*var, true);
|
||||
auto type_info = env.dts->ts.lookup_type(arg0_type);
|
||||
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
||||
if (sav->reg() == Register(Reg::GPR, Reg::R0)) {
|
||||
if (op->instruction().src[1].is_reg(Register(Reg::GPR, Reg::R0))) {
|
||||
if (bitfield_info) {
|
||||
auto base = pop_to_forms({*var}, env, pool, stack, true).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
@@ -4881,6 +4901,8 @@ void ArrayFieldAccess::update_with_val(Form* new_val,
|
||||
{reg0_matcher, Matcher::integer(m_expected_stride)});
|
||||
mult_matcher = Matcher::match_or({Matcher::cast("uint", mult_matcher), mult_matcher});
|
||||
auto matcher = Matcher::fixed_op(FixedOperatorKind::ADDITION, {mult_matcher, reg1_matcher});
|
||||
matcher = Matcher::match_or({matcher, Matcher::fixed_op(FixedOperatorKind::ADDITION_PTR,
|
||||
{reg1_matcher, mult_matcher})});
|
||||
auto match_result = match(matcher, new_val);
|
||||
Form* idx = nullptr;
|
||||
Form* base = nullptr;
|
||||
@@ -5355,6 +5377,24 @@ void DefskelgroupElement::update_from_stack(const Env&,
|
||||
result->push_back(this);
|
||||
}
|
||||
|
||||
void DefpartgroupElement::update_from_stack(const Env&,
|
||||
FormPool&,
|
||||
FormStack&,
|
||||
std::vector<FormElement*>* result,
|
||||
bool) {
|
||||
mark_popped();
|
||||
result->push_back(this);
|
||||
}
|
||||
|
||||
void DefpartElement::update_from_stack(const Env&,
|
||||
FormPool&,
|
||||
FormStack&,
|
||||
std::vector<FormElement*>* result,
|
||||
bool) {
|
||||
mark_popped();
|
||||
result->push_back(this);
|
||||
}
|
||||
|
||||
void ResLumpMacroElement::update_from_stack(const Env&,
|
||||
FormPool&,
|
||||
FormStack&,
|
||||
|
||||
@@ -26,7 +26,7 @@ const std::map<InstructionKind, OpenGOALAsm::Function> MIPS_ASM_TO_OPEN_GOAL_FUN
|
||||
{InstructionKind::PAND, {".pand", {}}},
|
||||
|
||||
// Parallel Pack
|
||||
{InstructionKind::PPACH, {".ppach", {}}},
|
||||
{InstructionKind::PPACH, {".ppach", {MOD::QWORD_CAST}}},
|
||||
|
||||
// Parallel Compares
|
||||
{InstructionKind::PCEQB, {".pceqb", {}}},
|
||||
@@ -50,6 +50,11 @@ const std::map<InstructionKind, OpenGOALAsm::Function> MIPS_ASM_TO_OPEN_GOAL_FUN
|
||||
// lots of implicit logic in OpenGOAL depending on argument types!
|
||||
{InstructionKind::MFC1, {".mov", {}}},
|
||||
|
||||
{InstructionKind::MOVN, {"move-if-not-zero", {}}}, // s7 special case is handled elsewhere
|
||||
{InstructionKind::SLT, {"set-on-less-than", {}}},
|
||||
{InstructionKind::SLTI, {"set-on-less-than", {}}},
|
||||
{InstructionKind::SRA, {"shift-arith-right-32", {}}},
|
||||
|
||||
// ---- COP2 -----
|
||||
// TODO - VMOVE supports dest, but OpenGOAL does NOT yet!
|
||||
{InstructionKind::VMOVE, {".mov.vf", {MOD::DEST_MASK}}},
|
||||
@@ -104,9 +109,8 @@ const std::map<InstructionKind, OpenGOALAsm::Function> MIPS_ASM_TO_OPEN_GOAL_FUN
|
||||
{InstructionKind::VABS, {".abs.vf", {MOD::DEST_MASK}}},
|
||||
|
||||
// Outer-product
|
||||
// NOTE - currently it's assumed these groups of instructions will be replaced with 1
|
||||
{InstructionKind::VOPMULA, {"TODO.VOPMULA.vf", {}}},
|
||||
{InstructionKind::VOPMSUB, {".outer.product.vf", {MOD::SWAP_FIRST_TWO_SOURCE_ARGS}}},
|
||||
{InstructionKind::VOPMULA, {".outer.product.a.vf", {}}},
|
||||
{InstructionKind::VOPMSUB, {".outer.product.b.vf", {MOD::ACC_THIRD_SRC_ARG}}},
|
||||
|
||||
// Division
|
||||
{InstructionKind::VDIV, {".div.vf", {MOD::FTF, MOD::FSF}}},
|
||||
@@ -152,11 +156,11 @@ bool OpenGOALAsm::Function::allows_modifier(InstructionModifiers mod) {
|
||||
return std::find(modifiers.begin(), modifiers.end(), mod) != modifiers.end();
|
||||
}
|
||||
|
||||
OpenGOALAsm::OpenGOALAsm(Instruction _instr) : instr(_instr) {
|
||||
if (MIPS_ASM_TO_OPEN_GOAL_FUNCS.count(instr.kind) == 0) {
|
||||
OpenGOALAsm::OpenGOALAsm(Instruction _instr) : m_instr(_instr) {
|
||||
if (MIPS_ASM_TO_OPEN_GOAL_FUNCS.count(m_instr.kind) == 0) {
|
||||
valid = false;
|
||||
} else {
|
||||
func = MIPS_ASM_TO_OPEN_GOAL_FUNCS.at(instr.kind);
|
||||
func = MIPS_ASM_TO_OPEN_GOAL_FUNCS.at(m_instr.kind);
|
||||
if (func.funcTemplate.rfind("TODO", 0) == 0) {
|
||||
todo = true;
|
||||
}
|
||||
@@ -170,11 +174,11 @@ OpenGOALAsm::OpenGOALAsm(Instruction _instr) : instr(_instr) {
|
||||
OpenGOALAsm::OpenGOALAsm(Instruction _instr,
|
||||
std::optional<RegisterAccess> _dst,
|
||||
const std::vector<std::optional<RegisterAccess>>& _src)
|
||||
: instr(_instr), m_dst(_dst), m_src(_src) {
|
||||
if (MIPS_ASM_TO_OPEN_GOAL_FUNCS.count(instr.kind) == 0) {
|
||||
: m_instr(_instr), m_dst(_dst), m_src(_src) {
|
||||
if (MIPS_ASM_TO_OPEN_GOAL_FUNCS.count(m_instr.kind) == 0) {
|
||||
valid = false;
|
||||
} else {
|
||||
func = MIPS_ASM_TO_OPEN_GOAL_FUNCS.at(instr.kind);
|
||||
func = MIPS_ASM_TO_OPEN_GOAL_FUNCS.at(m_instr.kind);
|
||||
if (func.funcTemplate.rfind("TODO", 0) == 0) {
|
||||
todo = true;
|
||||
}
|
||||
@@ -189,8 +193,8 @@ std::string OpenGOALAsm::full_function_name() {
|
||||
std::string func_name = func.funcTemplate;
|
||||
// OpenGOAL uses the function name for broadcast specification
|
||||
if (func.allows_modifier(MOD::BROADCAST)) {
|
||||
if (instr.cop2_bc != 0xff) {
|
||||
std::string bc = std::string(1, instr.cop2_bc_to_char());
|
||||
if (m_instr.cop2_bc != 0xff) {
|
||||
std::string bc = std::string(1, m_instr.cop2_bc_to_char());
|
||||
func_name = fmt::format(func_name, bc);
|
||||
}
|
||||
}
|
||||
@@ -203,9 +207,9 @@ std::vector<goos::Object> OpenGOALAsm::get_args(const std::vector<DecompilerLabe
|
||||
std::vector<goos::Object> named_args;
|
||||
|
||||
bool got_fsf = false;
|
||||
for (int i = 0; i < instr.n_src; i++) {
|
||||
for (int i = 0; i < m_instr.n_src; i++) {
|
||||
auto v = m_src.at(i);
|
||||
InstructionAtom atom = instr.get_src(i);
|
||||
InstructionAtom atom = m_instr.get_src(i);
|
||||
|
||||
if (v.has_value()) {
|
||||
// Normal register / constant args
|
||||
@@ -236,7 +240,19 @@ std::vector<goos::Object> OpenGOALAsm::get_args(const std::vector<DecompilerLabe
|
||||
named_args.push_back(pretty_print::to_symbol(fmt::format(":offset {}", atom.get_imm())));
|
||||
}
|
||||
} else {
|
||||
args.push_back(pretty_print::to_symbol(atom.to_string(labels)));
|
||||
// if it's r0, replace it with a `0`
|
||||
// unless it is pextuw or pcpyud
|
||||
if (atom.is_reg() && atom.get_reg().get_kind() == decompiler::Reg::RegisterKind::GPR &&
|
||||
atom.get_reg().reg_id() == decompiler::Reg::R0 &&
|
||||
m_instr.kind != InstructionKind::PEXTUW && m_instr.kind != InstructionKind::PCPYUD) {
|
||||
if (func.allows_modifier(MOD::QWORD_CAST)) {
|
||||
args.push_back(pretty_print::to_symbol("(the-as uint128 0)"));
|
||||
} else {
|
||||
args.push_back(pretty_print::to_symbol("0"));
|
||||
}
|
||||
} else {
|
||||
args.push_back(pretty_print::to_symbol(atom.to_string(labels)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,9 +262,10 @@ std::vector<goos::Object> OpenGOALAsm::get_args(const std::vector<DecompilerLabe
|
||||
}
|
||||
|
||||
// Handle destination masks
|
||||
if (func.allows_modifier(MOD::DEST_MASK) && instr.cop2_dest != 0xff && instr.cop2_dest != 15) {
|
||||
if (func.allows_modifier(MOD::DEST_MASK) && m_instr.cop2_dest != 0xff &&
|
||||
m_instr.cop2_dest != 15) {
|
||||
named_args.push_back(
|
||||
pretty_print::to_symbol(fmt::format(":mask #b{:b}", instr.cop2_dest_mask_intel())));
|
||||
pretty_print::to_symbol(fmt::format(":mask #b{:b}", m_instr.cop2_dest_mask_intel())));
|
||||
}
|
||||
|
||||
// Some functions are configured, or its easiest to swap the source args
|
||||
@@ -257,6 +274,11 @@ std::vector<goos::Object> OpenGOALAsm::get_args(const std::vector<DecompilerLabe
|
||||
std::swap(args.at(0), args.at(1));
|
||||
}
|
||||
|
||||
if (m_instr.kind == InstructionKind::MOVZ || m_instr.kind == InstructionKind::MOVN) {
|
||||
RegisterAccess ra(AccessMode::READ, m_dst->reg(), m_dst->idx());
|
||||
args.push_back(ra.to_form(env));
|
||||
}
|
||||
|
||||
args.insert(args.end(), named_args.begin(), named_args.end());
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "common/util/assert.h"
|
||||
#include <utility>
|
||||
#include <map>
|
||||
#include "common/goos/Object.h"
|
||||
@@ -11,6 +10,7 @@
|
||||
#include "decompiler/IR2/IR2_common.h"
|
||||
#include "Env.h"
|
||||
#include "AtomicOp.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
@@ -23,6 +23,7 @@ struct OpenGOALAsm {
|
||||
OFFSET,
|
||||
SWAP_FIRST_TWO_SOURCE_ARGS,
|
||||
ACC_THIRD_SRC_ARG,
|
||||
QWORD_CAST,
|
||||
SKIP_IT
|
||||
};
|
||||
|
||||
@@ -42,7 +43,7 @@ struct OpenGOALAsm {
|
||||
bool valid = true;
|
||||
bool todo = false;
|
||||
bool skip = false;
|
||||
Instruction instr;
|
||||
Instruction m_instr;
|
||||
std::optional<RegisterAccess> m_dst;
|
||||
std::vector<std::optional<RegisterAccess>> m_src;
|
||||
OpenGOALAsm::Function func;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/util/assert.h"
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "decompiler/util/data_decompile.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
struct BitfieldManip {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/util/assert.h"
|
||||
#include <cstring>
|
||||
#include <numeric>
|
||||
#include "decompiler/IR/IR.h"
|
||||
@@ -15,6 +14,7 @@
|
||||
#include "third-party/json.hpp"
|
||||
#include "common/log/log.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
/*!
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
* This implements a decoder for the GOAL linking format.
|
||||
*/
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <cstring>
|
||||
#include "LinkedObjectFileCreation.h"
|
||||
#include "decompiler/config.h"
|
||||
#include "decompiler/util/DecompilerTypeSystem.h"
|
||||
#include "common/link_types.h"
|
||||
#include "common/util/BitUtils.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
// There are three link versions:
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include "common/util/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
class LinkedWord {
|
||||
|
||||
@@ -376,7 +376,7 @@ std::string pad_string(const std::string& in, size_t length) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string ObjectFileDB::generate_obj_listing() {
|
||||
std::string ObjectFileDB::generate_obj_listing(const std::unordered_set<std::string>& merged_objs) {
|
||||
std::string result = "[";
|
||||
std::set<std::string> all_unique_names;
|
||||
int unique_count = 0;
|
||||
@@ -391,23 +391,25 @@ std::string ObjectFileDB::generate_obj_listing() {
|
||||
dgos.pop_back();
|
||||
dgos.pop_back();
|
||||
dgos += "]";
|
||||
result += "[\"" + pad_string(x.to_unique_name() + "\", ", 50) + "\"" +
|
||||
auto name = x.to_unique_name();
|
||||
result += "[\"" + pad_string(name + "\", ", 50) + "\"" +
|
||||
pad_string(x.name_in_dgo + "\", ", 50) + std::to_string(x.obj_version) + ", " +
|
||||
dgos + ", \"\"],\n";
|
||||
unique_count++;
|
||||
if (all_unique_names.find(x.to_unique_name()) != all_unique_names.end()) {
|
||||
lg::error("Object file {} appears multiple times with the same name.", x.to_unique_name());
|
||||
if (all_unique_names.find(name) != all_unique_names.end() &&
|
||||
merged_objs.find(name) == merged_objs.end()) {
|
||||
lg::error("Object file {} appears multiple times with the same name.", name);
|
||||
}
|
||||
all_unique_names.insert(x.to_unique_name());
|
||||
}
|
||||
// this check is extremely important. It makes sure we don't have any repeat names. This could
|
||||
// be caused by two files with the same name, in the same DGOs, but different data.
|
||||
if (int(all_unique_names.size()) != unique_count) {
|
||||
lg::error("Object files are not named properly, data will be lost!");
|
||||
all_unique_names.insert(name);
|
||||
}
|
||||
}
|
||||
// this check is extremely important. It makes sure we don't have any repeat names. This could
|
||||
// be caused by two files with the same name, in the same DGOs, but different data.
|
||||
if (int(all_unique_names.size()) != unique_count) {
|
||||
lg::error("Object files are not named properly, data will be lost!");
|
||||
}
|
||||
|
||||
if (result.length() >= 2) {
|
||||
if (unique_count > 0) {
|
||||
result.pop_back(); // kill last new line
|
||||
result.pop_back(); // kill last comma
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
* (there may be different object files with the same name sometimes)
|
||||
*/
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -16,6 +15,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "decompiler/data/TextureDB.h"
|
||||
#include "decompiler/analysis/symbol_def_map.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
/*!
|
||||
@@ -54,7 +54,7 @@ class ObjectFileDB {
|
||||
const std::vector<std::string>& str_files,
|
||||
const Config& config);
|
||||
std::string generate_dgo_listing();
|
||||
std::string generate_obj_listing();
|
||||
std::string generate_obj_listing(const std::unordered_set<std::string>& merged_objs);
|
||||
void process_link_data(const Config& config);
|
||||
void process_labels();
|
||||
void find_code(const Config& config);
|
||||
@@ -81,7 +81,7 @@ class ObjectFileDB {
|
||||
void ir2_register_usage_pass(int seg, ObjectFileData& data);
|
||||
void ir2_variable_pass(int seg, ObjectFileData& data);
|
||||
void ir2_cfg_build_pass(int seg, ObjectFileData& data);
|
||||
void ir2_store_current_forms(int seg);
|
||||
// void ir2_store_current_forms(int seg);
|
||||
void ir2_build_expressions(int seg, const Config& config, ObjectFileData& data);
|
||||
void ir2_insert_lets(int seg, ObjectFileData& data);
|
||||
void ir2_rewrite_inline_asm_instructions(int seg, ObjectFileData& data);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "decompiler/analysis/static_refs.h"
|
||||
#include "decompiler/analysis/symbol_def_map.h"
|
||||
#include "decompiler/analysis/find_skelgroups.h"
|
||||
#include "decompiler/analysis/find_defpartgroup.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "decompiler/analysis/mips2c.h"
|
||||
@@ -60,14 +61,21 @@ void ObjectFileDB::analyze_functions_ir2(
|
||||
ir2_do_segment_analysis_phase2(TOP_LEVEL_SEGMENT, config, data);
|
||||
try {
|
||||
if (data.linked_data.functions_by_seg.size() == 3) {
|
||||
run_defstate(data.linked_data.functions_by_seg.at(2).front(), skip_states);
|
||||
run_defpartgroup(data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).front());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
lg::error("Failed to find defpartgroups: {}", e.what());
|
||||
}
|
||||
try {
|
||||
if (data.linked_data.functions_by_seg.size() == 3) {
|
||||
run_defstate(data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).front(), skip_states);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
lg::error("Failed to find defstates: {}", e.what());
|
||||
}
|
||||
try {
|
||||
if (data.linked_data.functions_by_seg.size() == 3) {
|
||||
run_defskelgroups(data.linked_data.functions_by_seg.at(2).front());
|
||||
run_defskelgroups(data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).front());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
lg::error("Failed to find defskelgroups: {}", e.what());
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include "VuDisassembler.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/util/assert.h"
|
||||
#include "common/util/print_float.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
@@ -733,4 +733,4 @@ void VuDisassembler::name_labels() {
|
||||
m_label_names.at(label_idx) = fmt::format("L{}", idx++);
|
||||
}
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "common/util/assert.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
#include "VuInstruction.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
VuInstructionAtom VuInstructionAtom::make_vf(int idx) {
|
||||
@@ -89,4 +88,4 @@ VuInstruction VuInstruction::make_fp_constant(u32 value) {
|
||||
result.kind = VuInstrK::FP_CONSTANT;
|
||||
return result;
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -387,7 +387,7 @@ IR2_BranchDelay get_branch_delay(const Instruction& i0, int idx) {
|
||||
return IR2_BranchDelay(IR2_BranchDelay::Kind::NOP);
|
||||
} else if (is_gpr_3(i0, InstructionKind::OR, {}, rs7(), rr0())) {
|
||||
return IR2_BranchDelay(IR2_BranchDelay::Kind::SET_REG_FALSE, make_dst_var(i0, idx));
|
||||
} else if (is_gpr_3(i0, InstructionKind::OR, {}, {}, rr0())) {
|
||||
} else if (is_gpr_3(i0, InstructionKind::OR, {}, {}, rr0()) && !i0.get_src(0).is_reg(rr0())) {
|
||||
return IR2_BranchDelay(IR2_BranchDelay::Kind::SET_REG_REG, make_dst_var(i0, idx),
|
||||
make_src_var(i0.get_src(0).get_reg(), idx));
|
||||
} else if (i0.kind == InstructionKind::DADDIU && i0.get_src(0).is_reg(rs7()) &&
|
||||
@@ -2201,4 +2201,4 @@ FunctionAtomicOps convert_function_to_atomic_ops(
|
||||
assert(func.basic_blocks.size() == result.block_id_to_first_atomic_op.size());
|
||||
return result;
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "find_defpartgroup.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "decompiler/IR2/GenericElementMatcher.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
#include "decompiler/util/data_decompile.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
namespace {
|
||||
|
||||
const goos::Object& car(const goos::Object* x) {
|
||||
return x->as_pair()->car;
|
||||
}
|
||||
|
||||
const goos::Object* cdr(const goos::Object* x) {
|
||||
return &x->as_pair()->cdr;
|
||||
}
|
||||
|
||||
void read_static_group_data(DecompiledDataElement* src,
|
||||
const Env& env,
|
||||
DefpartgroupElement::StaticInfo& group) {
|
||||
auto lab = src->label();
|
||||
// looks like:
|
||||
/*
|
||||
.type sparticle-launch-group
|
||||
L81:
|
||||
.word 0xbb80042
|
||||
.word 0x405dc
|
||||
.word L83
|
||||
.word L82
|
||||
.word 0x0
|
||||
.word 0x0
|
||||
.word 0x0
|
||||
.word 0x0
|
||||
.word 0x0
|
||||
.word 0x0
|
||||
.word 0x47800000
|
||||
L82:
|
||||
*/
|
||||
|
||||
int start_word_idx = (lab.offset / 4) - 1;
|
||||
auto& words = env.file->words_by_seg.at(lab.target_segment);
|
||||
|
||||
auto& first_word = words.at(start_word_idx);
|
||||
if (first_word.kind() != LinkedWord::TYPE_PTR ||
|
||||
first_word.symbol_name() != "sparticle-launch-group") {
|
||||
env.func->warnings.warn_and_throw(
|
||||
"Reference to sparticle-launch-group bad: invalid type pointer");
|
||||
}
|
||||
|
||||
auto& word_1 = words.at(start_word_idx + 1);
|
||||
s16 len = word_1.data & 0xffff;
|
||||
group.duration = (word_1.data >> 16) & 0xffff;
|
||||
auto& word_2 = words.at(start_word_idx + 2);
|
||||
group.linger = word_2.data & 0xffff;
|
||||
group.flags = (word_2.data >> 16) & 0xffff;
|
||||
|
||||
auto& string_word = words.at(start_word_idx + 3);
|
||||
if (string_word.kind() != LinkedWord::PTR) {
|
||||
env.func->warnings.warn_and_throw(
|
||||
"Reference to sparticle-launch-group bad: invalid name label");
|
||||
}
|
||||
group.name = env.file->get_goal_string_by_label(
|
||||
env.file->get_label_by_name(env.file->get_label_name(string_word.label_id())));
|
||||
|
||||
auto& array_word = words.at(start_word_idx + 4);
|
||||
if (array_word.kind() != LinkedWord::PTR) {
|
||||
env.func->warnings.warn_and_throw(
|
||||
"Reference to sparticle-launch-group bad: invalid array label");
|
||||
}
|
||||
auto& array_lab = env.file->get_label_by_name(env.file->get_label_name(array_word.label_id()));
|
||||
auto& array_words = env.file->words_by_seg.at(array_lab.target_segment);
|
||||
int array_start_word_idx = array_lab.offset / 4;
|
||||
group.elts.clear();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
int item_idx = i * 8 + array_start_word_idx;
|
||||
auto& item = group.elts.emplace_back();
|
||||
item.part_id = array_words.at(item_idx + 0).data;
|
||||
item.fade = *reinterpret_cast<float*>(&array_words.at(item_idx + 1).data);
|
||||
item.falloff = *reinterpret_cast<float*>(&array_words.at(item_idx + 2).data);
|
||||
item.flags = array_words.at(item_idx + 3).data & 0xffff;
|
||||
item.period = (array_words.at(item_idx + 3).data >> 16) & 0xffff;
|
||||
item.length = array_words.at(item_idx + 4).data & 0xffff;
|
||||
item.offset = (array_words.at(item_idx + 4).data >> 16) & 0xffff;
|
||||
item.hour_mask = array_words.at(item_idx + 5).data;
|
||||
item.binding = array_words.at(item_idx + 6).data;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto& word = words.at(start_word_idx + 8 + i);
|
||||
if (word.kind() != LinkedWord::PLAIN_DATA) {
|
||||
env.func->warnings.warn_and_throw("Reference to sparticle-launch-group bad: invalid bounds");
|
||||
}
|
||||
group.bounds[i] = *reinterpret_cast<float*>(&word.data);
|
||||
}
|
||||
}
|
||||
|
||||
void read_static_part_data(DecompiledDataElement* src,
|
||||
const Env& env,
|
||||
DefpartElement::StaticInfo& part) {
|
||||
auto lab = src->label();
|
||||
// looks like:
|
||||
/*
|
||||
.type sparticle-launcher
|
||||
L79:
|
||||
.word 0x0
|
||||
.word 0x0
|
||||
.word L80
|
||||
L80:
|
||||
.word 0x1
|
||||
.word 0x201200
|
||||
.word 0x0
|
||||
.word 0x0
|
||||
.word 0x10006
|
||||
.word 0x3dcccccd
|
||||
.word 0x0
|
||||
.word 0x3f800000
|
||||
*/
|
||||
|
||||
int start_word_idx = (lab.offset / 4) - 1;
|
||||
auto& words = env.file->words_by_seg.at(lab.target_segment);
|
||||
|
||||
auto& first_word = words.at(start_word_idx);
|
||||
if (first_word.kind() != LinkedWord::TYPE_PTR ||
|
||||
first_word.symbol_name() != "sparticle-launcher") {
|
||||
env.func->warnings.warn_and_throw("Reference to sparticle-launcher bad: invalid type pointer");
|
||||
}
|
||||
|
||||
auto& empty1 = words.at(start_word_idx + 1);
|
||||
auto& empty2 = words.at(start_word_idx + 2);
|
||||
if (empty1.kind() != LinkedWord::PLAIN_DATA || empty1.data != 0 ||
|
||||
empty2.kind() != LinkedWord::PLAIN_DATA || empty2.data != 0) {
|
||||
env.func->warnings.warn_and_throw("Reference to sparticle-launcher bad: accums not empty");
|
||||
}
|
||||
|
||||
auto& array_word = words.at(start_word_idx + 3);
|
||||
if (array_word.kind() != LinkedWord::PTR) {
|
||||
env.func->warnings.warn_and_throw("Reference to sparticle-launcher bad: invalid array label");
|
||||
}
|
||||
auto& array_lab = env.file->get_label_by_name(env.file->get_label_name(array_word.label_id()));
|
||||
auto& array_words = env.file->words_by_seg.at(array_lab.target_segment);
|
||||
int array_start_word_idx = array_lab.offset / 4;
|
||||
part.fields.clear();
|
||||
src->do_decomp(env, env.file);
|
||||
auto obj = src->to_form(env);
|
||||
obj = car(cdr(cdr(&obj)));
|
||||
auto cur_field = cdr(&obj);
|
||||
for (int i = 0; true; ++i) {
|
||||
int field_idx = i * 4 + array_start_word_idx;
|
||||
auto& item = part.fields.emplace_back();
|
||||
item.field_id = array_words.at(field_idx + 0).data & 0xffff;
|
||||
item.flags = (array_words.at(field_idx + 0).data >> 16) & 0xffff;
|
||||
item.data.push_back(array_words.at(field_idx + 0));
|
||||
item.data.push_back(array_words.at(field_idx + 1));
|
||||
item.data.push_back(array_words.at(field_idx + 2));
|
||||
item.data.push_back(array_words.at(field_idx + 3));
|
||||
if (item.field_id == 7) {
|
||||
auto& fld = car(cur_field);
|
||||
item.sound_spec = cdr(cdr(cdr(cdr(&fld))))->as_pair()->car;
|
||||
}
|
||||
if (item.field_id == 67) {
|
||||
// sp-end
|
||||
break;
|
||||
}
|
||||
cur_field = cdr(cur_field);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void run_defpartgroup(Function& top_level_func) {
|
||||
auto& env = top_level_func.ir2.env;
|
||||
auto& pool = *top_level_func.ir2.form_pool;
|
||||
if (!top_level_func.ir2.top_form) {
|
||||
return;
|
||||
}
|
||||
top_level_func.ir2.top_form->apply_form([&](Form* form) {
|
||||
for (auto& fe : form->elts()) {
|
||||
auto as_set = dynamic_cast<SetFormFormElement*>(fe);
|
||||
if (as_set) {
|
||||
/* Looks something like this:
|
||||
(set! (-> *part-group-id-table* 188) (new 'static 'sparticle-launch-group
|
||||
*/
|
||||
if (as_set->dst()->elts().size() != 1) {
|
||||
continue;
|
||||
}
|
||||
auto dest = dynamic_cast<DerefElement*>(as_set->dst()->elts().at(0));
|
||||
if (!dest)
|
||||
continue;
|
||||
if (dest->tokens().size() != 1)
|
||||
continue;
|
||||
if (dest->tokens().at(0).kind() != DerefToken::Kind::INTEGER_CONSTANT)
|
||||
continue;
|
||||
if (dest->base()->elts().size() != 1)
|
||||
continue;
|
||||
auto dest_base = dynamic_cast<SimpleExpressionElement*>(dest->base()->elts().at(0));
|
||||
if (!dest_base || !dest_base->expr().is_identity() || dest_base->expr().args() < 1)
|
||||
continue;
|
||||
auto src = dynamic_cast<DecompiledDataElement*>(as_set->src()->elts().at(0));
|
||||
if (!src)
|
||||
continue;
|
||||
auto& sym = dest_base->expr().get_arg(0);
|
||||
if (!sym.is_sym_val())
|
||||
continue;
|
||||
|
||||
int id = dest->tokens().at(0).int_constant();
|
||||
if (sym.get_str() == "*part-group-id-table*") {
|
||||
DefpartgroupElement::StaticInfo group;
|
||||
read_static_group_data(src, env, group);
|
||||
auto rewritten = pool.alloc_element<DefpartgroupElement>(group, id);
|
||||
if (rewritten) {
|
||||
fe = rewritten;
|
||||
}
|
||||
} else if (sym.get_str() == "*part-id-table*") {
|
||||
DefpartElement::StaticInfo part;
|
||||
read_static_part_data(src, env, part);
|
||||
auto rewritten = pool.alloc_element<DefpartElement>(part, id);
|
||||
if (rewritten) {
|
||||
fe = rewritten;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} // namespace decompiler
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "decompiler/Function/Function.h"
|
||||
|
||||
namespace decompiler {
|
||||
void run_defpartgroup(Function& top_level_func);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ bool rewrite_inline_asm_instructions(Form* top_level_form,
|
||||
/*lg::warn("[ASM Re-Write] - Unsupported inline assembly instruction kind - [{}]",
|
||||
asmOp.instr.kind);*/
|
||||
f.warnings.general_warning("Unsupported inline assembly instruction kind - [{}]",
|
||||
asmOp.instr.to_string(f.ir2.env.file->labels));
|
||||
asmOp.m_instr.to_string(f.ir2.env.file->labels));
|
||||
new_entries.push_back(entry);
|
||||
continue;
|
||||
} else if (asmOp.skip) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "mips2c.h"
|
||||
|
||||
#include "common/symbols.h"
|
||||
#include "common/util/print_float.h"
|
||||
#include "decompiler/Disasm/InstructionMatching.h"
|
||||
#include "decompiler/Function/Function.h"
|
||||
@@ -91,6 +92,8 @@ std::string goal_to_c_function_name(const FunctionName& name) {
|
||||
switch (name.kind) {
|
||||
case FunctionName::FunctionKind::GLOBAL:
|
||||
return goal_to_c_name(name.function_name);
|
||||
case FunctionName::FunctionKind::METHOD:
|
||||
return fmt::format("method_{}_{}", name.method_id, goal_to_c_name(name.type_name));
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@@ -568,8 +571,29 @@ Mips2C_Line handle_generic_op2_u16(const Instruction& i0, const std::string& ins
|
||||
instr_str};
|
||||
}
|
||||
|
||||
Mips2C_Line handle_daddiu(Mips2C_Output& out, const Instruction& i0, const std::string& instr_str) {
|
||||
if (i0.get_src(1).is_label()) {
|
||||
return {instr_str, instr_str};
|
||||
} else if (i0.get_src(0).is_reg(rs7()) && i0.get_src(1).is_sym("#t")) {
|
||||
return {fmt::format("c->{}({}, {}, {});", i0.op_name_to_string(), reg_to_name(i0.get_dst(0)),
|
||||
reg_to_name(i0.get_src(0)), FIX_SYM_TRUE),
|
||||
instr_str};
|
||||
} else if (i0.get_src(0).is_reg(rs7()) && i0.get_src(1).is_sym()) {
|
||||
out.require_symbol(i0.get_src(1).get_sym());
|
||||
return {fmt::format("c->load_symbol_addr({}, cache.{});", reg_to_name(i0.get_dst(0)),
|
||||
goal_to_c_name(i0.get_src(1).get_sym())),
|
||||
instr_str};
|
||||
} else {
|
||||
return handle_generic_op2_u16(i0, instr_str);
|
||||
}
|
||||
}
|
||||
|
||||
Mips2C_Line handle_sw(Mips2C_Output& out, const Instruction& i0, const std::string& instr_str) {
|
||||
if (i0.get_src(1).is_sym() && i0.get_src(2).is_reg(rs7())) {
|
||||
out.require_symbol(i0.get_src(1).get_sym());
|
||||
return {fmt::format("c->store_symbol({}, cache.{});", reg_to_name(i0.get_src(0)),
|
||||
goal_to_c_name(i0.get_src(1).get_sym())),
|
||||
instr_str};
|
||||
return handle_unknown(instr_str);
|
||||
// auto name = i0.get_src(1).get_sym();
|
||||
// // store into symbol table!
|
||||
@@ -745,12 +769,22 @@ Mips2C_Line handle_likely_branch_bc(const Instruction& i0, const std::string& in
|
||||
switch (i0.kind) {
|
||||
case InstructionKind::BLTZL:
|
||||
return {fmt::format("((s64){}) < 0", reg64_or_zero(i0.get_src(0))), instr_str};
|
||||
case InstructionKind::BGEZL:
|
||||
return {fmt::format("((s64){}) >= 0", reg64_or_zero(i0.get_src(0))), instr_str};
|
||||
case InstructionKind::BGTZL:
|
||||
return {fmt::format("((s64){}) > 0", reg64_or_zero(i0.get_src(0))), instr_str};
|
||||
case InstructionKind::BNEL:
|
||||
return {fmt::format("((s64){}) != ((s64){})", reg64_or_zero(i0.get_src(0)),
|
||||
reg64_or_zero(i0.get_src(1))),
|
||||
instr_str};
|
||||
case InstructionKind::BEQL:
|
||||
return {fmt::format("((s64){}) == ((s64){})", reg64_or_zero(i0.get_src(0)),
|
||||
reg64_or_zero(i0.get_src(1))),
|
||||
instr_str};
|
||||
case InstructionKind::BC1TL:
|
||||
return {"cop1_bc", instr_str};
|
||||
case InstructionKind::BC1FL:
|
||||
return {"!cop1_bc", instr_str};
|
||||
default:
|
||||
return handle_unknown(instr_str);
|
||||
}
|
||||
@@ -826,6 +860,18 @@ Mips2C_Line handle_clts(const Instruction& i0, const std::string& instr_string)
|
||||
instr_string};
|
||||
}
|
||||
|
||||
Mips2C_Line handle_cles(const Instruction& i0, const std::string& instr_string) {
|
||||
return {fmt::format("cop1_bc = c->fprs[{}] <= c->fprs[{}];", reg_to_name(i0.get_src(0)),
|
||||
reg_to_name(i0.get_src(1))),
|
||||
instr_string};
|
||||
}
|
||||
|
||||
Mips2C_Line handle_ceqs(const Instruction& i0, const std::string& instr_string) {
|
||||
return {fmt::format("cop1_bc = c->fprs[{}] == c->fprs[{}];", reg_to_name(i0.get_src(0)),
|
||||
reg_to_name(i0.get_src(1))),
|
||||
instr_string};
|
||||
}
|
||||
|
||||
Mips2C_Line handle_pmfhl_lh(const Instruction& i0, const std::string& instr_string) {
|
||||
return {fmt::format("c->pmfhl_lh({});", reg_to_name(i0.get_dst(0))), instr_string};
|
||||
}
|
||||
@@ -884,12 +930,16 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
|
||||
return handle_generic_op2_mask(i0, instr_str, "vmove");
|
||||
case InstructionKind::VITOF0:
|
||||
return handle_generic_op2_mask(i0, instr_str, "vitof0");
|
||||
case InstructionKind::VITOF12:
|
||||
return handle_generic_op2_mask(i0, instr_str, "vitof12");
|
||||
case InstructionKind::VFTOI0:
|
||||
return handle_generic_op2_mask(i0, instr_str, "vftoi0");
|
||||
case InstructionKind::VFTOI4:
|
||||
return handle_generic_op2_mask(i0, instr_str, "vftoi4");
|
||||
case InstructionKind::VFTOI12:
|
||||
return handle_generic_op2_mask(i0, instr_str, "vftoi12");
|
||||
case InstructionKind::VABS:
|
||||
return handle_generic_op2_mask(i0, instr_str, "vabs");
|
||||
case InstructionKind::VADDQ:
|
||||
return handle_generic_op2_mask(i0, instr_str, "vaddq");
|
||||
case InstructionKind::ANDI:
|
||||
@@ -915,7 +965,9 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
|
||||
case InstructionKind::PEXTLB:
|
||||
case InstructionKind::MOVN:
|
||||
case InstructionKind::PEXTUW:
|
||||
case InstructionKind::PEXTLW:
|
||||
case InstructionKind::PCPYUD:
|
||||
case InstructionKind::PCPYLD:
|
||||
case InstructionKind::PPACH:
|
||||
case InstructionKind::PINTEH:
|
||||
case InstructionKind::PCGTW:
|
||||
@@ -946,6 +998,7 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
|
||||
case InstructionKind::AND:
|
||||
return handle_generic_op3(i0, instr_str, "and_"); // and isn't allowed in C++
|
||||
case InstructionKind::DADDIU:
|
||||
return handle_daddiu(output, i0, instr_str);
|
||||
case InstructionKind::ADDIU:
|
||||
return handle_generic_op2_u16(i0, instr_str);
|
||||
case InstructionKind::QMTC2:
|
||||
@@ -986,6 +1039,8 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
|
||||
return handle_generic_op2(i0, instr_str, "mtc1");
|
||||
case InstructionKind::NEGS:
|
||||
return handle_generic_op2(i0, instr_str, "negs");
|
||||
case InstructionKind::MOVS:
|
||||
return handle_generic_op2(i0, instr_str, "movs");
|
||||
case InstructionKind::CVTWS:
|
||||
return handle_generic_op2(i0, instr_str, "cvtws");
|
||||
case InstructionKind::CVTSW:
|
||||
@@ -1001,6 +1056,12 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
|
||||
case InstructionKind::CLTS:
|
||||
output.needs_cop1_bc = true;
|
||||
return handle_clts(i0, instr_str);
|
||||
case InstructionKind::CLES:
|
||||
output.needs_cop1_bc = true;
|
||||
return handle_cles(i0, instr_str);
|
||||
case InstructionKind::CEQS:
|
||||
output.needs_cop1_bc = true;
|
||||
return handle_ceqs(i0, instr_str);
|
||||
case InstructionKind::VWAITQ:
|
||||
return handle_plain_op(i0, instr_str, "vwaitq");
|
||||
case InstructionKind::VOPMULA:
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
#include "decompiler/IR2/IR2_common.h"
|
||||
#include "decompiler/util/TP_Type.h"
|
||||
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
class Function;
|
||||
|
||||
@@ -202,6 +202,12 @@ Config read_config_file(const std::string& path_to_config_file) {
|
||||
|
||||
config.bad_format_strings =
|
||||
hacks_json.at("bad_format_strings").get<std::unordered_map<std::string, int>>();
|
||||
|
||||
auto merged = hacks_json.at("expected_merged_objs").get<std::vector<std::string>>();
|
||||
for (const auto& x : merged) {
|
||||
config.merged_objects.insert(x);
|
||||
}
|
||||
|
||||
config.levels_to_extract = cfg.at("levels_to_extract").get<std::vector<std::string>>();
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ struct Config {
|
||||
|
||||
std::unordered_set<std::string> allowed_objects;
|
||||
std::unordered_set<std::string> banned_objects;
|
||||
std::unordered_set<std::string> merged_objects;
|
||||
std::unordered_map<std::string, std::unordered_map<int, std::vector<RegisterTypeCast>>>
|
||||
register_type_casts_by_function_by_atomic_op_idx;
|
||||
std::unordered_map<std::string, std::unordered_map<int, StackTypeCast>>
|
||||
|
||||
+1314
-6563
File diff suppressed because it is too large
Load Diff
@@ -233,35 +233,26 @@
|
||||
"collide-probe-node", // CFG
|
||||
|
||||
// collide-edge-grab
|
||||
"(method 13 collide-edge-work)", // CFG
|
||||
"(method 17 collide-edge-work)", // CFG
|
||||
// CFG
|
||||
// CFG
|
||||
"(method 15 collide-edge-work)", // CFG
|
||||
"(method 16 collide-edge-work)", // CFG
|
||||
"(method 9 edge-grab-info)", // CFG
|
||||
"(method 18 collide-edge-work)", // CFG
|
||||
"(method 10 collide-edge-hold-list)", // CFG
|
||||
// CFG
|
||||
// CFG
|
||||
// CFG
|
||||
// CFG
|
||||
|
||||
// collide-shape
|
||||
"(method 15 collide-shape-prim-mesh)", // CFG
|
||||
"(method 15 collide-shape-prim-sphere)", // CFG
|
||||
"(method 16 collide-shape-prim)", // CFG
|
||||
"(method 15 collide-shape-prim-group)", // CFG
|
||||
"(method 18 collide-shape-prim-sphere)",
|
||||
"(method 23 collide-shape-prim-sphere)", // CFG
|
||||
"(method 23 collide-shape-prim-mesh)", // BUG - crash in variable pass
|
||||
"(method 24 collide-shape-prim)", // CFG
|
||||
"(method 23 collide-shape-prim-group)", // CFG
|
||||
"(method 42 collide-shape)", // CFG
|
||||
|
||||
"(method 12 collide-mesh)",
|
||||
|
||||
// process-drawable BUG
|
||||
"cspace-inspect-tree",
|
||||
"(method 19 process-drawable)",
|
||||
//"(method 19 process-drawable)",
|
||||
|
||||
// ambient
|
||||
"ambient-inspect",
|
||||
|
||||
// target BUG
|
||||
"target-falling-anim-trans", // CFG resolution
|
||||
//"target-falling-anim-trans", // CFG resolution
|
||||
|
||||
// target2 BUG
|
||||
"look-for-points-of-interest", // Failed to split nested sc - looks like dead code to me
|
||||
@@ -269,29 +260,20 @@
|
||||
// collide-cache
|
||||
"(method 10 collide-puss-work)", // CFG
|
||||
"(method 9 collide-puss-work)", // decompiler crash
|
||||
"(method 19 collide-cache)", // decompiler crash
|
||||
"(method 10 collide-cache-prim)", // CFG
|
||||
"(method 9 collide-cache-prim)", // CFG
|
||||
"(method 30 collide-cache)", // unsupported asm - c.le.s
|
||||
"(method 13 collide-shape-prim-group)", // CFG
|
||||
"(method 13 collide-shape-prim-mesh)", // CFG
|
||||
"(method 14 collide-shape-prim-group)", // CFG
|
||||
"(method 14 collide-shape-prim-mesh)", // CFG
|
||||
"(method 12 collide-shape-prim-group)", // CFG
|
||||
"(method 12 collide-shape-prim-mesh)", // CFG
|
||||
"(method 27 collide-cache)", // CFG
|
||||
"(method 14 collide-cache)", // CFG
|
||||
"(method 28 collide-cache)", // CFG
|
||||
"(method 26 collide-cache)", // CFG
|
||||
"(method 21 collide-cache)", // CFG
|
||||
// decompiler crash
|
||||
|
||||
// CFG
|
||||
// CFG
|
||||
// CFG
|
||||
// "(method 14 collide-cache)", // CFG
|
||||
// CFG
|
||||
// "(method 26 collide-cache)", // CFG
|
||||
//"(method 21 collide-cache)", // CFG
|
||||
"(method 32 collide-cache)", // CFG
|
||||
|
||||
// memory-usage BUG
|
||||
//"(method 14 level)",
|
||||
|
||||
// navigate BUG
|
||||
"(method 32 nav-control)",
|
||||
|
||||
// ocean
|
||||
"draw-large-polygon-ocean", // CFG
|
||||
|
||||
@@ -305,10 +287,7 @@
|
||||
// all unchecked and in level DGO code
|
||||
"(anon-function 21 plant-boss)", // CFG
|
||||
"target-flut-falling-anim-trans", // CFG failure
|
||||
"(anon-function 2 target-tube)",
|
||||
"(anon-function 5 orbit-plat)", // CFG
|
||||
"(anon-function 2 ogreboss)"
|
||||
|
||||
"(anon-function 5 orbit-plat)" // CFG
|
||||
],
|
||||
|
||||
// these functions use pairs and the decompiler
|
||||
@@ -394,7 +373,8 @@
|
||||
"ERROR: <asg> ~A in spool anim loop for ~A ~D, but not loaded.~": 3,
|
||||
"~0k~5d/~d ~6d/~d ~6d/~d ": 6,
|
||||
"~0k~s~%": 1,
|
||||
"money ~A was killed in pickup~%": 0
|
||||
"money ~A was killed in pickup~%": 0,
|
||||
" id address name aid tsk lev status x y z address name state heap flags~%": 3
|
||||
},
|
||||
|
||||
"blocks_ending_in_asm_branch": {
|
||||
@@ -478,7 +458,48 @@
|
||||
"birth-pickup-at-point": [0],
|
||||
"draw-bones": [0, 1, 2, 8, 81],
|
||||
"draw-bones-hud": [7, 8],
|
||||
"(method 16 drawable-tree)": [7, 9, 10]
|
||||
"(method 16 drawable-tree)": [7, 9, 10],
|
||||
"(method 21 collide-cache)" : [3, 5, 19, 20,24,25,28,29],
|
||||
"(method 14 collide-cache)" : [0, 1,2, 3, 4, 5],
|
||||
"(method 9 collide-mesh-cache)" : [0, 1, 2, 5],
|
||||
"(method 42 collide-shape)" : [0, 1, 2, 3, 4, 7],
|
||||
"(method 23 collide-shape-prim-group)" : [1, 2, 3, 4, 5],
|
||||
"(method 23 collide-shape-prim-mesh)" : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
|
||||
"(method 23 collide-shape-prim-sphere)" : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
|
||||
"(method 18 collide-shape-prim-sphere)" : [1, 3,4, 5, 7],
|
||||
"(method 45 collide-shape)" : [0, 16, 42, 67, 92],
|
||||
"(method 24 collide-shape-prim)" : [2, 3, 4, 5, 1],
|
||||
"(method 20 collide-shape-prim-group)" : [11],
|
||||
"(method 28 collide-shape-prim-mesh)" : [10],
|
||||
"(method 40 collide-shape)": [0, 2,5,6,7, 11,12, 28, 43, 58, 63],
|
||||
"(method 15 collide-shape-prim-group)" : [1, 2, 3, 4, 5, 6],
|
||||
"(method 16 collide-shape-prim)" : [1, 2, 3, 4, 5, 6],
|
||||
"(method 15 collide-shape-prim-sphere)" : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
|
||||
"(method 15 collide-shape-prim-mesh)" : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 29],
|
||||
"(method 35 collide-shape)" : [1],
|
||||
"(method 22 collide-cache)":[2, 3, 4, 13, 14, 15, 23, 24, 25, 33, 34, 35],
|
||||
"(method 12 collide-shape-prim-sphere)" : [0, 1],
|
||||
"(method 12 collide-shape-prim-group)" : [1, 2, 3, 4],
|
||||
"(method 24 collide-cache)" : [2, 3, 4, 13, 14, 15, 23, 24, 25, 33, 34, 35],
|
||||
"(method 14 collide-shape-prim-sphere)" : [0, 1, 2, 3],
|
||||
"(method 14 collide-shape-prim-group)" : [0, 1, 2, 3, 4],
|
||||
"(method 23 collide-cache)" : [2, 3, 4, 13, 14, 15, 23, 24, 25, 33, 34, 35],
|
||||
"(method 13 collide-shape-prim-sphere)" : [0, 1, 2],
|
||||
"(method 13 collide-shape-prim-group)" : [0, 1, 2,3,4],
|
||||
"(method 19 collide-cache)" : [0, 1, 3, 4, 5, 18, 19],
|
||||
"(method 10 collide-mesh)" : [1, 2, 4, 5],
|
||||
"target-falling-anim-trans" : [5, 6],
|
||||
"(method 19 process-drawable)" : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
|
||||
"(anon-function 9 racer)" : [75],
|
||||
"(method 13 collide-edge-work)" : [0, 2],
|
||||
"(method 17 collide-edge-work)" : [0, 1, 2, 3, 4],
|
||||
"(method 9 edge-grab-info)" : [15, 16, 18, 19, 21, 22, 24],
|
||||
// "(method 18 collide-edge-work)" : [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24],
|
||||
"target-falling-anim-trans" : [5, 6],
|
||||
"(method 27 nav-mesh)" : [8],
|
||||
"(method 32 nav-control)": [12, 21, 32],
|
||||
"start-collect-nav": [0],
|
||||
"end-collect-nav": [0]
|
||||
},
|
||||
|
||||
// Sometimes the game might use format strings that are fetched dynamically,
|
||||
@@ -526,13 +547,73 @@
|
||||
"time-of-day-interp-colors-scratch",
|
||||
"normalize-frame-quaternions",
|
||||
"collide-do-primitives",
|
||||
"moving-sphere-triangle-intersect"
|
||||
"moving-sphere-triangle-intersect",
|
||||
"(method 12 collide-mesh)",
|
||||
"(method 11 collide-mesh)",
|
||||
"collide-probe-node",
|
||||
"collide-probe-instance-tie",
|
||||
"(method 32 collide-cache)",
|
||||
"(method 28 collide-cache)",
|
||||
"(method 26 collide-cache)",
|
||||
"(method 27 collide-cache)",
|
||||
"(method 29 collide-cache)",
|
||||
"(method 12 collide-shape-prim-mesh)",
|
||||
"(method 14 collide-shape-prim-mesh)",
|
||||
"(method 13 collide-shape-prim-mesh)",
|
||||
"(method 30 collide-cache)",
|
||||
"(method 9 collide-cache-prim)",
|
||||
"(method 10 collide-cache-prim)",
|
||||
"(method 9 collide-puss-work)",
|
||||
"(method 10 collide-puss-work)",
|
||||
|
||||
// these could easily be goal, but probably faster/easier this way.
|
||||
"(method 14 collide-mesh)",
|
||||
"(method 15 collide-mesh)",
|
||||
|
||||
"(method 16 collide-edge-work)",
|
||||
"(method 10 collide-edge-hold-list)",
|
||||
"(method 15 collide-edge-work)",
|
||||
"(method 18 collide-edge-work)"
|
||||
],
|
||||
|
||||
// there are some missing textures. I don't know what the game actually does here.
|
||||
// the format for entries is [level, tpage, index]
|
||||
"missing_textures": [
|
||||
["finalboss", 1419, 3]
|
||||
],
|
||||
|
||||
// some object files have garbage pad data at the end which makes the decompiler
|
||||
// assume they must be different files, such as the art group for orb-cache-top.
|
||||
// this just suppresses a message.
|
||||
"expected_merged_objs": [
|
||||
"orb-cache-top-ag",
|
||||
"ecovalve-ag",
|
||||
"barrel-ag",
|
||||
"sack-ag",
|
||||
"sharkey-ag",
|
||||
"warp-gate-switch-ag",
|
||||
"baby-spider-ag",
|
||||
"cavetrapdoor-ag",
|
||||
"spider-egg-ag",
|
||||
"darkvine-ag",
|
||||
"jng-iris-door-ag",
|
||||
"eichar-fish+0-ag",
|
||||
"launcherdoor-ag",
|
||||
"plat-eco-ag",
|
||||
"eichar-tube+0-ag",
|
||||
"eichar-pole+0-ag",
|
||||
"crate-darkeco-cluster-ag",
|
||||
"ef-plane-ag",
|
||||
"racer-ag",
|
||||
"flut-saddle-ag",
|
||||
"shover-ag",
|
||||
"steam-cap-ag",
|
||||
"sunkencam-ag",
|
||||
"swampcam-ag",
|
||||
"pontoonfive-ag",
|
||||
"oracle-ag",
|
||||
"village-cam-ag",
|
||||
"plat-ag"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -1609,11 +1609,17 @@
|
||||
|
||||
"rolling-lightning-mole": [
|
||||
["L181", "vector"],
|
||||
["L185", "rgba", true],
|
||||
["L186", "rgba", true],
|
||||
["L187", "rgba", true],
|
||||
["L189", "rgba", true],
|
||||
["L195", "vector"]
|
||||
["L185", "vector4w"],
|
||||
["L186", "vector4w"],
|
||||
["L187", "vector4w"],
|
||||
["L189", "vector4w"],
|
||||
["L195", "vector"],
|
||||
["L201", "vector4w"],
|
||||
["L202", "vector4w"],
|
||||
["L203", "vector4w"],
|
||||
["L204", "vector4w"],
|
||||
["L205", "vector4w"],
|
||||
["L206", "vector4w"]
|
||||
],
|
||||
|
||||
"rolling-robber": [
|
||||
@@ -1624,7 +1630,95 @@
|
||||
],
|
||||
|
||||
"ogreboss": [
|
||||
["L525", "uint64", true],
|
||||
["L359", "attack-info"],
|
||||
["L367", "attack-info"],
|
||||
["L370", "attack-info"],
|
||||
["L371", "attack-info"],
|
||||
["L384", "(pointer float)", 1],
|
||||
["L384", "(pointer float)", 1],
|
||||
["L385", "(pointer float)", 1],
|
||||
["L386", "(pointer float)", 1],
|
||||
["L387", "(pointer float)", 1],
|
||||
["L388", "(pointer float)", 1],
|
||||
["L389", "(pointer float)", 1],
|
||||
["L390", "float", true],
|
||||
["L391", "float", true],
|
||||
["L392", "float", true],
|
||||
["L393", "float", true],
|
||||
["L394", "float", true],
|
||||
["L395", "float", true],
|
||||
["L396", "float", true],
|
||||
["L397", "float", true],
|
||||
["L398", "float", true],
|
||||
["L399", "float", true],
|
||||
["L400", "float", true],
|
||||
["L401", "float", true],
|
||||
["L402", "float", true],
|
||||
["L403", "float", true],
|
||||
["L404", "float", true],
|
||||
["L405", "float", true],
|
||||
["L406", "float", true],
|
||||
["L407", "float", true],
|
||||
["L408", "float", true],
|
||||
["L409", "float", true],
|
||||
["L410", "float", true],
|
||||
["L411", "float", true],
|
||||
["L412", "float", true],
|
||||
["L413", "float", true],
|
||||
["L414", "float", true],
|
||||
["L415", "float", true],
|
||||
["L416", "float", true],
|
||||
["L417", "float", true],
|
||||
["L418", "float", true],
|
||||
["L419", "float", true],
|
||||
["L420", "float", true],
|
||||
["L421", "float", true],
|
||||
["L422", "float", true],
|
||||
["L423", "float", true],
|
||||
["L424", "float", true],
|
||||
["L425", "float", true],
|
||||
["L426", "float", true],
|
||||
["L427", "float", true],
|
||||
["L428", "float", true],
|
||||
["L429", "float", true],
|
||||
["L430", "float", true],
|
||||
["L431", "float", true],
|
||||
["L432", "float", true],
|
||||
["L433", "float", true],
|
||||
["L434", "float", true],
|
||||
["L435", "float", true],
|
||||
["L436", "float", true],
|
||||
["L437", "float", true],
|
||||
["L438", "float", true],
|
||||
["L439", "float", true],
|
||||
["L440", "float", true],
|
||||
["L441", "float", true],
|
||||
["L442", "float", true],
|
||||
["L443", "float", true],
|
||||
["L444", "float", true],
|
||||
["L445", "float", true],
|
||||
["L446", "float", true],
|
||||
["L447", "float", true],
|
||||
["L448", "float", true],
|
||||
["L449", "float", true],
|
||||
["L450", "float", true],
|
||||
["L451", "float", true],
|
||||
["L452", "float", true],
|
||||
["L453", "float", true],
|
||||
["L454", "float", true],
|
||||
["L455", "float", true],
|
||||
["L456", "float", true],
|
||||
["L457", "float", true],
|
||||
["L458", "float", true],
|
||||
["L459", "float", true],
|
||||
["L460", "(pointer float)", 1],
|
||||
["L461", "rgba", true],
|
||||
["L462", "uint64", true],
|
||||
["L463", "uint64", true],
|
||||
["L464", "uint64", true],
|
||||
["L465", "uint64", true],
|
||||
["L466", "uint64", true],
|
||||
["L525", "float", true],
|
||||
["L526", "uint64", true],
|
||||
["L527", "uint64", true],
|
||||
["L528", "uint64", true],
|
||||
@@ -1632,11 +1726,6 @@
|
||||
["L530", "uint64", true]
|
||||
],
|
||||
|
||||
"mother-spider": [
|
||||
["L301", "(inline-array mother-spider-leg-info)", 8],
|
||||
["L302", "(inline-array mother-spider-thread)", 9]
|
||||
],
|
||||
|
||||
"target-flut": [
|
||||
["L399", "attack-info"],
|
||||
["L406", "float", true],
|
||||
@@ -1674,8 +1763,8 @@
|
||||
["L438", "float", true],
|
||||
["L439", "float", true],
|
||||
["L440", "float", true],
|
||||
["L441", "float", true],
|
||||
["L442", "float", true],
|
||||
["L441", "(pointer float)", 1],
|
||||
["L442", "(pointer float)", 1],
|
||||
["L443", "float", true],
|
||||
["L444", "float", true],
|
||||
["L445", "float", true],
|
||||
@@ -1850,7 +1939,7 @@
|
||||
["L414", "attack-info"],
|
||||
["L415", "attack-info"],
|
||||
["L416", "attack-info"],
|
||||
["L417", "attack-info"],
|
||||
["L417", "vector"],
|
||||
["L418", "attack-info"],
|
||||
["L419", "attack-info"],
|
||||
["L420", "vector"],
|
||||
@@ -1878,7 +1967,8 @@
|
||||
],
|
||||
|
||||
"collide-cache": [
|
||||
["L304", "vector"]
|
||||
["L304", "vector"],
|
||||
["L303", "vector4w"]
|
||||
],
|
||||
|
||||
"load-boundary-data": [
|
||||
@@ -1996,6 +2086,31 @@
|
||||
["L38", "vector"]
|
||||
],
|
||||
|
||||
"depth-cue": [
|
||||
["L17", "depth-cue-work"]
|
||||
],
|
||||
|
||||
"navigate": [
|
||||
["L402", "vector"],
|
||||
["L403", "vector"],
|
||||
["L404", "vector"],
|
||||
["L405", "vector"],
|
||||
["L406", "vector"],
|
||||
["L422", "vector"],
|
||||
["L419", "(pointer uint8)", 4],
|
||||
["L425", "float", true],
|
||||
["L426", "float", true],
|
||||
["L429", "float", true],
|
||||
["L430", "float", true],
|
||||
["L436", "float", true],
|
||||
["L438", "float", true],
|
||||
["L444", "float", true],
|
||||
["L442", "float", true],
|
||||
["L520", "vector"],
|
||||
["L522", "float", true], // TODO - meters
|
||||
["L523", "float", true] // TODO - meters
|
||||
],
|
||||
|
||||
"shrubbery": [
|
||||
["L133", "vu-function"]
|
||||
],
|
||||
|
||||
@@ -696,7 +696,7 @@
|
||||
[48, "collide-tri-result"]
|
||||
],
|
||||
|
||||
"(method 20 collide-cache)": [[16, "vector"]],
|
||||
"(method 20 collide-cache)": [[16, "collide-puyp-work"]],
|
||||
|
||||
"(method 12 wobbler)": [[16, "vector"]],
|
||||
|
||||
@@ -1802,7 +1802,7 @@
|
||||
[160, "vector"]
|
||||
],
|
||||
|
||||
"(method 18 collide-cache)": [[16, "collide-cache-prim"]],
|
||||
"(method 18 collide-cache)": [[16, "collide-puls-work"]],
|
||||
|
||||
"kill-current-level-hint": [[16, "event-message-block"]],
|
||||
"(exit level-hint-sidekick)": [[16, "event-message-block"]],
|
||||
@@ -4139,7 +4139,7 @@
|
||||
],
|
||||
|
||||
"(method 9 touching-list)": [
|
||||
[16, "touching-shapes-entry"]
|
||||
[16, "add-prims-touching-work"]
|
||||
],
|
||||
|
||||
"(method 11 touching-prims-entry)": [
|
||||
@@ -4147,7 +4147,7 @@
|
||||
],
|
||||
|
||||
"(method 35 collide-shape)": [
|
||||
[16, "pull-rider-info"],
|
||||
[16, "collide-overlap-result"],
|
||||
[128, "matrix"],
|
||||
[192, "event-message-block"],
|
||||
[272, "collide-overlap-result"],
|
||||
@@ -4196,11 +4196,11 @@
|
||||
|
||||
"(method 59 collide-shape-moving)": [
|
||||
[16, "collide-tri-result"],
|
||||
[112, "touching-shapes-entry"]
|
||||
[112, "overlaps-others-params"]
|
||||
],
|
||||
|
||||
"(method 58 collide-shape-moving)": [
|
||||
[16, "touching-shapes-entry"]
|
||||
[16, "overlaps-others-params"]
|
||||
],
|
||||
|
||||
"simple-collision-reaction": [
|
||||
@@ -4256,16 +4256,16 @@
|
||||
],
|
||||
|
||||
"(method 45 collide-shape)": [
|
||||
[16, "collide-work"],
|
||||
[16, "collide-overlap-result"],
|
||||
[128, "vector"],
|
||||
[144, "vector"],
|
||||
[160, "collide-work"],
|
||||
[160, "collide-overlap-result"],
|
||||
[272, "vector"],
|
||||
[288, "vector"],
|
||||
[304, "collide-work"],
|
||||
[304, "collide-overlap-result"],
|
||||
[416, "vector"],
|
||||
[432, "vector"],
|
||||
[448, "collide-work"],
|
||||
[448, "collide-overlap-result"],
|
||||
[560, "vector"],
|
||||
[576, "vector"]
|
||||
],
|
||||
@@ -4366,7 +4366,7 @@
|
||||
"target-collision-reaction": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"],
|
||||
[48, "matrix"],
|
||||
[112, "vector"],
|
||||
[128, "vector"],
|
||||
[144, "vector"],
|
||||
@@ -4415,12 +4415,12 @@
|
||||
|
||||
"find-ground-point": [
|
||||
[16, "vector"],
|
||||
[32, "collide-mesh-cache-tri"],
|
||||
[32, "collide-tri-result"],
|
||||
[128, "bounding-box"],
|
||||
[160, "vector"]
|
||||
],
|
||||
|
||||
"(method 19 collide-shape-prim-sphere)": [[16, "collide-mesh-cache-tri"]],
|
||||
"(method 19 collide-shape-prim-sphere)": [[16, "collide-tri-result"]],
|
||||
"(method 37 collide-shape)": [[16, "vector"]],
|
||||
|
||||
"starts": [
|
||||
@@ -6017,5 +6017,341 @@
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(trans joint-exploder-shatter)": [
|
||||
[16, "bounding-box"]
|
||||
],
|
||||
|
||||
"(method 22 joint-exploder)": [
|
||||
[16, "vector"],
|
||||
[32, "collide-tri-result"]
|
||||
],
|
||||
|
||||
"(enter target-tube-hit)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(event slide-control-ride slide-control)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(code target-tube-death)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
|
||||
"(code target-tube-hit)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"],
|
||||
[64, "vector"],
|
||||
[80, "vector"]
|
||||
],
|
||||
|
||||
"find-target-point": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"]
|
||||
],
|
||||
|
||||
"(trans slide-control-watch slide-control)": [
|
||||
[16, "vector"],
|
||||
[32, "event-message-block"]
|
||||
],
|
||||
|
||||
"distance-from-tangent": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"]
|
||||
],
|
||||
|
||||
"(method 14 collide-cache)" : [
|
||||
[16, "bounding-box"]
|
||||
],
|
||||
|
||||
"(method 23 collide-shape-prim-mesh)" :[
|
||||
[16, "collide-tri-result"]
|
||||
],
|
||||
|
||||
"(method 23 collide-shape-prim-sphere)" : [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "collide-tri-result"],
|
||||
[144, "vector"],
|
||||
[160, "vector"]
|
||||
],
|
||||
|
||||
"(method 18 collide-shape-prim-sphere)" : [
|
||||
[16, "collide-tri-result"]
|
||||
],
|
||||
"target-collision-low-coverage" : [
|
||||
[64, "collide-tri-result"],
|
||||
[176, "vector"],
|
||||
[192, "vector"],
|
||||
[224, "vector"],
|
||||
[240, "vector"],
|
||||
[256, "vector"],
|
||||
[288, "vector"]
|
||||
],
|
||||
|
||||
"(code ogreboss-missile-idle)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "collide-tri-result"]
|
||||
],
|
||||
|
||||
"(code ogreboss-missile-seek)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "collide-tri-result"]
|
||||
],
|
||||
|
||||
"ogreboss-rock-explosion-effect": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(code ogreboss-dead)": [
|
||||
[16, "event-message-block"],
|
||||
[96, "vector"]
|
||||
],
|
||||
|
||||
"ogreboss-shoot-boulder": [
|
||||
[16, "ogreboss-missile-init-data"],
|
||||
[48, "vector"]
|
||||
],
|
||||
|
||||
"(code ogreboss-die)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(code ogreboss-stage3-hit)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"ogreboss-trigger-steps": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(code ogreboss-stage3-throw)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"ogreboss-attack-event-handler": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(exit ogreboss-stage3-shuffle)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(trans ogreboss-stage3-shuffle)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"ogreboss-submerge": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"ogreboss-post": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"ogreboss-emerge": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(code ogreboss-intro)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"ogreboss-bounce-boulder-event-handler": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(enter ogreboss-idle)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"ogreboss-super-boulder-event-handler": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(code ogreboss-super-boulder-roll)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(code ogreboss-missile-impact)": [
|
||||
[16, "overlaps-others-params"]
|
||||
],
|
||||
|
||||
"(event ogreboss-missile-impact)": [
|
||||
[16, "event-message-block"],
|
||||
[96, "vector"],
|
||||
[112, "vector"],
|
||||
[128, "vector"],
|
||||
[224, "vector"]
|
||||
],
|
||||
|
||||
"(method 18 collide-edge-work)": [
|
||||
[16, "pbhp-stack-vars"]
|
||||
],
|
||||
|
||||
"(method 9 edge-grab-info)": [
|
||||
[16, "collide-using-spheres-params"],
|
||||
[48, "event-message-block"]
|
||||
],
|
||||
|
||||
"(method 20 nav-mesh)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"]
|
||||
],
|
||||
|
||||
"nav-ray-test": [
|
||||
[16, "vector"],
|
||||
[32, "vector"]
|
||||
],
|
||||
|
||||
"circle-tangent-directions": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"],
|
||||
[64, "vector"]
|
||||
],
|
||||
|
||||
"(method 18 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 9 nav-control)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"],
|
||||
[64, "vector"],
|
||||
[80, "vector"],
|
||||
[96, "vector"],
|
||||
[112, "vector"],
|
||||
[128, "vector"],
|
||||
[144, "vector"],
|
||||
[160, "vector"],
|
||||
[176, "vector"]
|
||||
],
|
||||
"(method 11 nav-control)": [
|
||||
[16, "vector"],
|
||||
[32, "nav-gap-info"],
|
||||
[64, "event-message-block"]
|
||||
],
|
||||
"(method 12 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 13 nav-mesh)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 18 nav-mesh)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 24 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 24 nav-mesh)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"]
|
||||
],
|
||||
"(method 22 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 17 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 19 nav-control)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"]
|
||||
],
|
||||
"(method 17 nav-mesh)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, ["array", "int8", 256]]
|
||||
],
|
||||
"(method 25 nav-mesh)": [
|
||||
[16, "vector"],
|
||||
[32, "matrix"]
|
||||
],
|
||||
"debug-nav-validate-current-poly": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 13 nav-control)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"],
|
||||
[64, "nav-route-portal"], // nav-poly | nav-route-portal | nav-route-portal
|
||||
[112, "vector"],
|
||||
[128, "clip-travel-vector-to-mesh-return-info"],
|
||||
[288, "vector"]
|
||||
],
|
||||
|
||||
"(method 28 nav-mesh)": [
|
||||
[16, ["inline-array", "nav-vertex", 3]]
|
||||
],
|
||||
|
||||
"choose-travel-portal-vertex": [
|
||||
[16, "nav-route-portal"]
|
||||
],
|
||||
|
||||
"(method 33 nav-control)": [
|
||||
[16, "event-message-block"]
|
||||
],
|
||||
|
||||
"(method 27 nav-control)": [
|
||||
[16, "nav-ray"]
|
||||
],
|
||||
"(method 16 nav-mesh)": [
|
||||
[16, "nav-ray"]
|
||||
],
|
||||
|
||||
"(method 29 nav-mesh)": [
|
||||
[16, ["inline-array", "nav-vertex", 6]]
|
||||
],
|
||||
|
||||
"find-closest-circle-ray-intersection": [
|
||||
[16, "vector"]
|
||||
],
|
||||
|
||||
"(method 20 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 21 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 23 nav-control)": [
|
||||
[16, "vector"],
|
||||
[32, "vector"],
|
||||
[48, "vector"]
|
||||
],
|
||||
"(method 16 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 25 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
"(method 28 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
|
||||
"(method 35 nav-control)": [
|
||||
[16, "vector"]
|
||||
],
|
||||
|
||||
"(method 15 nav-mesh)": [
|
||||
[16, "nav-ray"]
|
||||
],
|
||||
|
||||
"nav-ray-test-local?": [
|
||||
[16, "nav-ray"]
|
||||
],
|
||||
|
||||
"find-adjacent-bounds": [
|
||||
[16, "vector"]
|
||||
],
|
||||
|
||||
"(method 32 nav-control)": [
|
||||
[16, "nav-control-cfs-work"]
|
||||
],
|
||||
|
||||
"placeholder-do-not-add-below!": []
|
||||
}
|
||||
|
||||
@@ -811,30 +811,10 @@
|
||||
[[115, 154], "s3", "continue-point"]
|
||||
],
|
||||
"(method 20 level)": [[[43, 45], "s3", "ramdisk-rpc-fill"]],
|
||||
"(anon-function 29 process-drawable)": [[[0, 999], "s6", "process-drawable"]],
|
||||
|
||||
"ja-done?": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-min?": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-max?": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-num-frames": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-frame-num": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-aframe-num": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-aframe": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-step": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-channel-set!": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-channel-push!": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-group-size": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-eval": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-blend-eval": [[[0, 999], "s6", "process-drawable"]],
|
||||
"ja-post": [
|
||||
[[0, 999], "s6", "process-drawable"],
|
||||
[54, "a1", "process"]
|
||||
],
|
||||
"transform-post": [[[0, 999], "s6", "process-drawable"]],
|
||||
"rider-trans": [[[0, 999], "s6", "process-drawable"]],
|
||||
"rider-post": [[[0, 999], "s6", "process-drawable"]],
|
||||
"pusher-post": [[[0, 999], "s6", "process-drawable"]],
|
||||
"process-drawable-delay-player": [[[0, 999], "s6", "process-drawable"]],
|
||||
|
||||
"upload-generic-shrub": [
|
||||
[[3, 13], "t0", "dma-packet"],
|
||||
@@ -1494,45 +1474,34 @@
|
||||
],
|
||||
|
||||
"cam-standard-event-handler": [
|
||||
[[0, 999], "s6", "camera-slave"],
|
||||
[[16, 30], "s5", "state"],
|
||||
[41, "a0", "vector"],
|
||||
[[5, 8], "t9", "(function object)"],
|
||||
[[19, 22], "t9", "(function object)"],
|
||||
[[30, 32], "t9", "(function object)"]
|
||||
],
|
||||
"cam-curve-pos": [[[0, 224], "s6", "camera-slave"]],
|
||||
"cam-combiner-init": [[[0, 999], "s6", "camera-combiner"]],
|
||||
|
||||
"(code cam-combiner-active)": [[[0, 999], "s6", "camera-combiner"]],
|
||||
|
||||
"(event cam-combiner-active)": [
|
||||
[10, "a0", "vector"],
|
||||
[[0, 20], "s6", "camera-slave"],
|
||||
[[20, 231], "s6", "camera-combiner"],
|
||||
[[99, 127], "gp", "camera-slave"],
|
||||
[[187, 231], "gp", "camera-slave"]
|
||||
],
|
||||
|
||||
"cam-master-init": [[[0, 999], "s6", "camera-master"]],
|
||||
"cam-curve-setup": [[[0, 82], "s6", "camera-slave"]],
|
||||
"(method 15 tracking-spline)": [
|
||||
[[57, 59], "a2", "vector"],
|
||||
[[57, 59], "a3", "vector"]
|
||||
],
|
||||
|
||||
"(method 16 tracking-spline)": [
|
||||
[[40, 42], "a0", "vector"],
|
||||
[[40, 42], "a1", "vector"]
|
||||
],
|
||||
|
||||
"cam-slave-init-vars": [[[0, 999], "s6", "camera-slave"]],
|
||||
|
||||
"cam-slave-get-vector-with-offset": [[[52, 65], "s3", "vector"]],
|
||||
|
||||
"cam-slave-go": [[[3, 6], "t9", "(function object)"]],
|
||||
|
||||
"cam-slave-init": [
|
||||
[[0, 999], "s6", "camera-slave"],
|
||||
[[47, 50], "t9", "(function object object)"],
|
||||
[[54, 58], "t9", "(function object object)"]
|
||||
],
|
||||
@@ -2314,6 +2283,8 @@
|
||||
|
||||
"(method 14 level-group)": [
|
||||
[[54, 164], "s1", "process-drawable"],
|
||||
[[107, 127], "s0", "(pointer int32)"],
|
||||
[[153, 162], "v0", "symbol"],
|
||||
[[319, 342], "s0", "process-drawable"],
|
||||
[368, "v1", "(pointer process-drawable)"],
|
||||
[[384, 494], "s5", "process-drawable"]
|
||||
@@ -2327,8 +2298,6 @@
|
||||
|
||||
"(method 27 entity-ambient)": [[[15, 250], "s5", "symbol"]],
|
||||
|
||||
"cam-master-effect": [[[0, 999], "s6", "camera-master"]],
|
||||
|
||||
"birth-func-vector-orient": [[[7, 24], "s3", "sprite-vec-data-2d"]],
|
||||
|
||||
"process-drawable-burn-effect": [
|
||||
@@ -4002,23 +3971,26 @@
|
||||
|
||||
"(method 32 sage-finalboss)": [
|
||||
[[241, 245], "v1", "manipy"],
|
||||
[[309, 313], "v1", "manipy"]
|
||||
[[309, 313], "v1", "manipy"],
|
||||
[313, "v1", "silodoor"]
|
||||
],
|
||||
|
||||
"(trans play-anim sage-finalboss)": [
|
||||
[[179, 183], "a0", "manipy"],
|
||||
[[216, 220], "a0", "manipy"],
|
||||
[[295, 299], "a1", "manipy"],
|
||||
[[334, 338], "a1", "manipy"],
|
||||
[[371, 375], "a1", "manipy"],
|
||||
[391, "v0", "final-door"],
|
||||
[396, "v0", "final-door"]
|
||||
],
|
||||
|
||||
"(method 7 sage-finalboss)": [
|
||||
[2, "v1", "(inline-array sage-finalboss-particle)"],
|
||||
[6, "v1", "(inline-array sage-finalboss-particle)"],
|
||||
[10, "v1", "(inline-array sage-finalboss-particle)"]
|
||||
[186, "v1", "process-drawable"],
|
||||
[223, "v1", "process-drawable"],
|
||||
[300, "v1", "process-drawable"],
|
||||
[339, "v1", "process-drawable"],
|
||||
[376, "v1", "process-drawable"],
|
||||
[399, "gp", "final-door"],
|
||||
[401, "a0", "final-door"]
|
||||
// [[179, 183], "a0", "manipy"],
|
||||
// [[182, 187], "v1", "manipy"],
|
||||
// [[216, 220], "a0", "manipy"],
|
||||
// [[295, 299], "a1", "manipy"],
|
||||
// [[334, 338], "a1", "manipy"],
|
||||
// [[371, 375], "a1", "manipy"],
|
||||
// [391, "v0", "final-door"],
|
||||
// [396, "v0", "final-door"]
|
||||
],
|
||||
|
||||
"(trans fisher-done)": [[[41, 46], "v1", "dma-packet"]],
|
||||
@@ -4222,10 +4194,6 @@
|
||||
[63, "t9", "(function cspace basic basic int)"]
|
||||
],
|
||||
|
||||
"process-grab?": [
|
||||
[18, "s6", "camera-tracker"]
|
||||
],
|
||||
|
||||
"joint-control-copy!": [
|
||||
[8, "a0", "pointer"],
|
||||
[8, "a2", "pointer"]
|
||||
@@ -5655,19 +5623,19 @@
|
||||
],
|
||||
|
||||
"(method 14 touching-list)": [
|
||||
[5, "s5", "touching-shapes-entry"],
|
||||
[10, "s5", "touching-shapes-entry"]
|
||||
[[0,11], "s5", "touching-shapes-entry"]
|
||||
],
|
||||
|
||||
"(method 13 touching-list)": [
|
||||
[5, "v0", "touching-shapes-entry"],
|
||||
[10, "v0", "touching-shapes-entry"],
|
||||
[17, "v0", "touching-shapes-entry"],
|
||||
[26, "v0", "touching-shapes-entry"],
|
||||
[46, "v0", "touching-shapes-entry"],
|
||||
[47, "v0", "touching-shapes-entry"],
|
||||
[48, "v0", "touching-shapes-entry"],
|
||||
[50, "v0", "touching-shapes-entry"]
|
||||
[[0, 51], "v0", "touching-shapes-entry"]
|
||||
// [5, "v0", "touching-shapes-entry"],
|
||||
// [10, "v0", "touching-shapes-entry"],
|
||||
// [17, "v0", "touching-shapes-entry"],
|
||||
// [26, "v0", "touching-shapes-entry"],
|
||||
// [46, "v0", "touching-shapes-entry"],
|
||||
// [47, "v0", "touching-shapes-entry"],
|
||||
// [48, "v0", "touching-shapes-entry"],
|
||||
// [50, "v0", "touching-shapes-entry"]
|
||||
],
|
||||
|
||||
"(method 11 touching-list)": [
|
||||
@@ -5729,17 +5697,15 @@
|
||||
],
|
||||
|
||||
"(method 28 collide-shape-prim-mesh)": [
|
||||
[27, "s4", "collide-shape-prim-group"]
|
||||
[[22,45], "s4", "(array collide-mesh)"]
|
||||
],
|
||||
|
||||
"(method 53 collide-shape)": [
|
||||
[26, "a1", "collide-shape-prim-group"],
|
||||
[36, "v1", "collide-shape-prim-group"]
|
||||
[[24, 40], "v1", "collide-shape-prim-group"]
|
||||
],
|
||||
|
||||
"(method 54 collide-shape)": [
|
||||
[22, "a1", "collide-shape-prim-group"],
|
||||
[29, "v1", "collide-shape-prim-group"]
|
||||
[[18, 33], "v1", "collide-shape-prim-group"]
|
||||
],
|
||||
|
||||
"(method 45 collide-shape)": [
|
||||
@@ -5772,16 +5738,14 @@
|
||||
],
|
||||
|
||||
"(method 9 collide-edge-work)": [
|
||||
[10, "s3", "collide-edge-edge"],
|
||||
[16, "s4", "collide-edge-hold-item"],
|
||||
[46, "s4", "(inline-array collide-edge-hold-item)"],
|
||||
[48, "s3", "(inline-array collide-edge-edge)"]
|
||||
[[5, 52], "s3", "collide-edge-edge"],
|
||||
[[5, 52], "s4", "collide-edge-hold-item"]
|
||||
],
|
||||
|
||||
"(method 19 collide-edge-work)": [
|
||||
[150, "a1", "int"],
|
||||
[150, "v1", "int"],
|
||||
[[149, 162], "a0", "collide-shape-prim-group"]
|
||||
[150, "v1", "int"]
|
||||
//[[149, 162], "a0", "collide-shape-prim-group"]
|
||||
],
|
||||
|
||||
"collide-probe-make-list": [
|
||||
@@ -5829,16 +5793,13 @@
|
||||
],
|
||||
|
||||
"(method 9 collide-cache)": [
|
||||
[5, "gp", "collide-cache-tri"],
|
||||
[19, "gp", "collide-cache-tri"],
|
||||
[20, "gp", "collide-cache-tri"],
|
||||
[21, "gp", "collide-cache-tri"],
|
||||
[23, "gp", "(inline-array collide-cache-tri)"],
|
||||
[33, "gp", "collide-cache-prim"],
|
||||
[[1,29], "gp", "collide-cache-tri"],
|
||||
[[29,56], "gp", "collide-cache-prim"],
|
||||
[35, "gp", "collide-cache-prim"],
|
||||
[50, "gp", "collide-cache-prim"],
|
||||
[51, "gp", "collide-cache-prim"],
|
||||
[55, "gp", "(inline-array collide-cache-prim)"]
|
||||
[55, "gp", "collide-cache-prim"],
|
||||
[36, "v1", "collide-shape-prim-sphere"]
|
||||
],
|
||||
|
||||
"(method 9 collide-mesh)": [
|
||||
@@ -5847,7 +5808,8 @@
|
||||
],
|
||||
|
||||
"(method 22 collide-shape-prim-mesh)": [
|
||||
[10, "s4", "collide-shape-prim-group"]
|
||||
[10, "s4", "collide-shape-prim-group"],
|
||||
[41, "s4", "collide-shape-prim-group"]
|
||||
],
|
||||
|
||||
"(method 44 collide-shape)": [
|
||||
@@ -7393,6 +7355,473 @@
|
||||
[31, "s4", "energyarm"]
|
||||
],
|
||||
|
||||
"(method 0 joint-exploder-tuning)": [
|
||||
[[6, 50], "v0", "joint-exploder-tuning"]
|
||||
],
|
||||
|
||||
"(method 23 joint-exploder)": [
|
||||
[[12, 102], "s3", "joint-exploder-joint"],
|
||||
[[144, 146], "v1", "joint-exploder-list"],
|
||||
[148, "v1", "matrix"],
|
||||
[152, "v1", "matrix"]
|
||||
],
|
||||
|
||||
"(method 20 joint-exploder)": [
|
||||
[[8, 10], "a3", "joint-exploder-joint"],
|
||||
[15, "v1", "joint-exploder-joint"]
|
||||
],
|
||||
|
||||
"(method 27 joint-exploder)": [
|
||||
[41, "s0", "joint-exploder-joint"],
|
||||
[90, "s0", "joint-exploder-joint"],
|
||||
[139, "s0", "joint-exploder-joint"]
|
||||
],
|
||||
|
||||
"(method 25 joint-exploder)": [
|
||||
[[16, 54], "s2", "joint-exploder-joint"]
|
||||
],
|
||||
|
||||
"(method 22 joint-exploder)": [
|
||||
[[18, 78], "s5", "joint-exploder-joint"]
|
||||
],
|
||||
|
||||
"joint-exploder-joint-callback": [
|
||||
[[10, 18], "v1", "joint-exploder-joint"]
|
||||
],
|
||||
|
||||
"(method 24 joint-exploder)": [
|
||||
[[12, 19], "v1", "joint-exploder-joint"]
|
||||
],
|
||||
|
||||
"(method 26 joint-exploder)": [
|
||||
[[5, 8], "a2", "joint-exploder-joint"],
|
||||
[18, "v1", "joint-exploder-joint"],
|
||||
[28, "v1", "joint-exploder-joint"]
|
||||
],
|
||||
|
||||
"racer-effects": [
|
||||
[739, "v0", "sound-rpc-set-param"]
|
||||
],
|
||||
|
||||
"(code target-tube)": [
|
||||
[31, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(event slide-control-ride slide-control)": [
|
||||
[24, "gp", "process-drawable"],
|
||||
[31, "v1", "vector"],
|
||||
[35, "v1", "vector"],
|
||||
[39, "v1", "vector"]
|
||||
],
|
||||
|
||||
"(code target-tube-start)": [
|
||||
[110, "v1", "float"]
|
||||
],
|
||||
|
||||
"depth-cue-set-stencil": [
|
||||
[[1, 7], "t1", "dma-packet"],
|
||||
[[10, 16], "t1", "gs-gif-tag"],
|
||||
[27, "t1", "(pointer gs-xy-offset)"],
|
||||
[29, "t1", "(pointer gs-reg64)"],
|
||||
[34, "t1", "(pointer gs-frame)"],
|
||||
[36, "t1", "(pointer gs-reg64)"],
|
||||
[38, "t1", "(pointer gs-test)"],
|
||||
[40, "t1", "(pointer gs-reg64)"],
|
||||
[[43, 53], "a3", "(inline-array vector4w)"],
|
||||
[[52, 80], "v0", "(inline-array vector4w)"]
|
||||
],
|
||||
|
||||
"depth-cue-draw-front": [
|
||||
[[26, 32], "t6", "dma-packet"],
|
||||
[[33, 41], "t6", "gs-gif-tag"],
|
||||
[49, "t6", "(pointer gs-xy-offset)"],
|
||||
[51, "t6", "(pointer gs-reg64)"],
|
||||
[56, "t6", "(pointer gs-frame)"],
|
||||
[58, "t6", "(pointer gs-reg64)"],
|
||||
[64, "t6", "(pointer gs-tex0)"],
|
||||
[66, "t6", "(pointer gs-reg64)"],
|
||||
[68, "t6", "(pointer gs-test)"],
|
||||
[70, "t6", "(pointer gs-reg64)"],
|
||||
[71, "t6", "(pointer gs-alpha)"],
|
||||
[73, "t6", "(pointer gs-reg64)"],
|
||||
[[76, 109], "t5", "(inline-array vector4w)"],
|
||||
[112, "t5", "depth-cue-work"],
|
||||
[[115, 121], "t6", "dma-packet"],
|
||||
[[122, 130], "t6", "gs-gif-tag"],
|
||||
[137, "t6", "(pointer gs-xy-offset)"],
|
||||
[139, "t6", "(pointer gs-reg64)"],
|
||||
[144, "t6", "(pointer gs-frame)"],
|
||||
[146, "t6", "(pointer gs-reg64)"],
|
||||
[148, "t6", "(pointer gs-texa)"],
|
||||
[150, "t6", "(pointer gs-reg64)"],
|
||||
[156, "t6", "(pointer gs-tex0)"],
|
||||
[158, "t6", "(pointer gs-reg64)"],
|
||||
[160, "t6", "(pointer gs-alpha)"],
|
||||
[162, "t6", "(pointer gs-reg64)"],
|
||||
[[165, 190], "t5", "(inline-array vector4w)"],
|
||||
[[191, 201], "t5", "vector4w"],
|
||||
[201, "t5", "depth-cue-work"]
|
||||
],
|
||||
|
||||
"depth-cue-draw-depth": [
|
||||
[[26, 32], "t6", "dma-packet"],
|
||||
[[33, 41], "t6", "gs-gif-tag"],
|
||||
[49, "t6", "(pointer gs-xy-offset)"],
|
||||
[51, "t6", "(pointer gs-reg64)"],
|
||||
[56, "t6", "(pointer gs-frame)"],
|
||||
[58, "t6", "(pointer gs-reg64)"],
|
||||
[64, "t6", "(pointer gs-tex0)"],
|
||||
[66, "t6", "(pointer gs-reg64)"],
|
||||
[68, "t6", "(pointer gs-test)"],
|
||||
[70, "t6", "(pointer gs-reg64)"],
|
||||
[[73, 106], "t5", "(inline-array vector4w)"],
|
||||
[109, "t5", "depth-cue-work"],
|
||||
[[112, 118], "t6", "dma-packet"],
|
||||
[[121, 127], "t6", "gs-gif-tag"],
|
||||
[134, "t6", "(pointer gs-xy-offset)"],
|
||||
[136, "t6", "(pointer gs-reg64)"],
|
||||
[141, "t6", "(pointer gs-frame)"],
|
||||
[143, "t6", "(pointer gs-reg64)"],
|
||||
[149, "t6", "(pointer gs-tex0)"],
|
||||
[151, "t6", "(pointer gs-reg64)"],
|
||||
[153, "t6", "(pointer gs-test)"],
|
||||
[155, "t6", "(pointer gs-reg64)"],
|
||||
[[158, 183], "t5", "(inline-array vector4w)"],
|
||||
[[184, 193], "t5", "vector4w"],
|
||||
[194, "t5", "depth-cue-work"]
|
||||
],
|
||||
|
||||
"depth-cue": [
|
||||
[[22, 28], "a2", "dma-packet"],
|
||||
[[31, 37], "a2", "gs-gif-tag"],
|
||||
[42, "a2", "(pointer gs-test)"],
|
||||
[44, "a2", "(pointer gs-reg64)"],
|
||||
[46, "a2", "(pointer gs-zbuf)"],
|
||||
[48, "a2", "(pointer gs-reg64)"],
|
||||
[50, "a2", "(pointer gs-reg64)"],
|
||||
[52, "a2", "(pointer gs-reg64)"],
|
||||
[53, "a2", "(pointer gs-tex1)"],
|
||||
[55, "a2", "(pointer gs-reg64)"],
|
||||
[62, "a2", "(pointer gs-clamp)"],
|
||||
[64, "a2", "(pointer gs-reg64)"],
|
||||
[66, "a2", "(pointer gs-reg64)"],
|
||||
[68, "a2", "(pointer gs-reg64)"],
|
||||
[[94, 100], "a0", "dma-packet"],
|
||||
[[103, 109], "a0", "gs-gif-tag"],
|
||||
[120, "a0", "(pointer gs-xy-offset)"],
|
||||
[122, "a0", "(pointer gs-reg64)"],
|
||||
[127, "a0", "(pointer gs-frame)"],
|
||||
[129, "a0", "(pointer gs-reg64)"],
|
||||
[[133, 138], "v1", "dma-packet"]
|
||||
],
|
||||
|
||||
"collide-probe-collide-fragment-tree-make-list": [
|
||||
[5, "v1", "drawable-inline-array-node"]
|
||||
],
|
||||
|
||||
"collide-probe-instance-tie-tree-make-list": [
|
||||
[[5,7], "v1", "drawable-inline-array-node"],
|
||||
[[18,20], "v1", "drawable-inline-array-instance-tie"]
|
||||
],
|
||||
|
||||
"collide-upload-vu0": [
|
||||
[16, "a0", "dma-packet"],
|
||||
[17, "a0", "(pointer uint64)"]
|
||||
],
|
||||
|
||||
"collide-probe-make-list": [
|
||||
[[20, 22], "v1", "drawable-inline-array-node"],
|
||||
[[31, 33], "v1", "drawable-inline-array-instance-tie"],
|
||||
[[47, 49], "v1", "drawable-inline-array-node"]
|
||||
],
|
||||
|
||||
"(method 21 collide-cache)": [
|
||||
[114, "a0", "(pointer int32)"],
|
||||
[156, "t0", "(pointer int32)"],
|
||||
[190, "v1", "(pointer int32)"],
|
||||
[147, "v1", "collide-list-item"],
|
||||
[148, "v1", "collide-list-item"],
|
||||
[[91, 95], "v1", "dma-packet"],
|
||||
[[112, 141], "v1", "dma-bank-spr"],
|
||||
[[154, 188], "a2", "dma-bank-spr"],
|
||||
[[217, 227], "s3", "collide-list-item"]
|
||||
],
|
||||
|
||||
"(method 23 collide-shape-prim-sphere)": [
|
||||
[[74,114], "s4", "collide-shape-prim-mesh"]
|
||||
],
|
||||
|
||||
"(method 13 collide-mesh)" : [
|
||||
[[0, 60], "a3", "(inline-array vector)"],
|
||||
[[61, 123], "v1", "collide-mesh-tri"]
|
||||
],
|
||||
|
||||
"(method 20 collide-shape-prim-group)": [
|
||||
[5, "gp", "pointer"],
|
||||
[6, "v1", "(pointer collide-shape-prim)"],
|
||||
[[7,14], "a0", "collide-shape-prim"],
|
||||
[32, "gp", "pointer"],
|
||||
[33, "v1", "(pointer collide-shape-prim)"],
|
||||
[[34,40], "a0", "collide-shape-prim"],
|
||||
[[40, 46], "a0", "collide-shape-prim-group"]
|
||||
],
|
||||
|
||||
"(method 29 collide-shape-prim-group)" : [
|
||||
[5, "gp", "pointer"],
|
||||
[6, "v1", "(pointer collide-shape-prim)"],
|
||||
[[13, 19], "a0", "collide-shape-prim-group"]
|
||||
],
|
||||
|
||||
"(method 40 collide-shape)" : [
|
||||
[21, "a0", "connection"],
|
||||
[[22,40], "a0", "collide-shape-moving"],
|
||||
[85, "a0", "connection"],
|
||||
[[86, 104], "a0", "collide-shape-moving"],
|
||||
[147, "a0", "connection"],
|
||||
[[148, 166], "a0", "collide-shape-moving"],
|
||||
[209, "a0", "connection"],
|
||||
[[210, 228], "a0", "collide-shape-moving"]
|
||||
],
|
||||
|
||||
"(method 15 collide-shape-prim-sphere)" : [
|
||||
[[16, 55], "gp", "collide-shape-prim-mesh"]
|
||||
],
|
||||
|
||||
"(method 25 collide-cache)" : [
|
||||
[[83, 104], "a2", "(inline-array collide-cache-tri)"]
|
||||
],
|
||||
|
||||
"(method 22 collide-cache)" : [
|
||||
[14, "v1", "connection"],
|
||||
[[15,31], "v1", "collide-shape"],
|
||||
[74, "v1", "connection"],
|
||||
[[75, 91], "v1", "collide-shape"],
|
||||
[130, "v1", "connection"],
|
||||
[[131, 148], "v1", "collide-shape"],
|
||||
[187, "v1", "connection"],
|
||||
[[188, 205], "v1", "collide-shape"]
|
||||
],
|
||||
|
||||
"(method 12 collide-shape-prim-sphere)" : [
|
||||
[[13, 23], "t0", "collide-cache-prim"]
|
||||
],
|
||||
|
||||
"(method 24 collide-cache)" : [
|
||||
[14, "v1", "connection"],
|
||||
[[15,31], "v1", "collide-shape"],
|
||||
[74, "v1", "connection"],
|
||||
[[75, 91], "v1", "collide-shape"],
|
||||
[130, "v1", "connection"],
|
||||
[[131, 148], "v1", "collide-shape"],
|
||||
[187, "v1", "connection"],
|
||||
[[188, 205], "v1", "collide-shape"]
|
||||
],
|
||||
|
||||
"(method 14 collide-shape-prim-sphere)" : [
|
||||
[[11, 23], "t0", "collide-cache-prim"]
|
||||
],
|
||||
|
||||
"(method 23 collide-cache)" : [
|
||||
[20, "v1", "connection"],
|
||||
[[21,43], "v1", "collide-shape"],
|
||||
[86, "v1", "connection"],
|
||||
[[87,109], "v1", "collide-shape"],
|
||||
[148, "v1", "connection"],
|
||||
[[149, 174], "v1", "collide-shape"],
|
||||
[211, "v1", "connection"],
|
||||
[[212, 235], "v1", "collide-shape"]
|
||||
],
|
||||
|
||||
"(method 13 collide-shape-prim-sphere)" : [
|
||||
[[11, 23], "t0", "collide-cache-prim"]
|
||||
],
|
||||
|
||||
"(method 31 collide-cache)" : [
|
||||
[22, "v1", "collide-shape-prim-sphere"]
|
||||
],
|
||||
|
||||
"(method 19 collide-cache)" : [
|
||||
[[52, 94], "s4", "collide-cache-prim"],
|
||||
[[1, 100], "s5", "collide-puss-work"]
|
||||
],
|
||||
|
||||
"ogreboss-rock-explosion-effect": [
|
||||
[83, "v1", "manipy"]
|
||||
],
|
||||
|
||||
"ogreboss-missile-scale-explosion": [
|
||||
[11, "gp", "process-drawable"],
|
||||
[22, "gp", "process-drawable"]
|
||||
],
|
||||
|
||||
"(event ogreboss-missile-impact)": [
|
||||
[76, "t1", "target"]
|
||||
],
|
||||
|
||||
"(code ogreboss-super-boulder-throw)": [
|
||||
[16, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"ogreboss-emerge": [
|
||||
[47, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ogreboss-die)": [
|
||||
[35, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"ogreboss-super-boulder-play-hit-anim": [
|
||||
[15, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ogreboss-stage3-hit)": [
|
||||
[47, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ogreboss-stage3-throw)": [
|
||||
[33, "v1", "art-joint-anim"],
|
||||
[89, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"ogreboss-shoot-boulder": [
|
||||
[41, "a1", "process-drawable"]
|
||||
],
|
||||
|
||||
"(method 7 ogreboss-super-boulder)": [
|
||||
[14, "t9", "(function process-drawable int process-drawable)"]
|
||||
],
|
||||
|
||||
"ogreboss-bounce-boulder-init-by-other": [
|
||||
[112, "v1", "float"]
|
||||
],
|
||||
|
||||
"(code ogreboss-stage3-shuffle)": [
|
||||
[33, "v1", "art-joint-anim"],
|
||||
[121, "v1", "art-joint-anim"],
|
||||
[177, "v1", "art-joint-anim"],
|
||||
[247, "v1", "art-joint-anim"],
|
||||
[299, "v1", "art-joint-anim"],
|
||||
[355, "v1", "art-joint-anim"],
|
||||
[425, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ogreboss-stage2)": [
|
||||
[26, "v1", "art-joint-anim"],
|
||||
[104, "v1", "art-joint-anim"],
|
||||
[158, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"ogreboss-update-super-boulder": [
|
||||
[12, "a1", "ogreboss-super-boulder"]
|
||||
],
|
||||
|
||||
"(trans ogreboss-stage3-shuffle)": [
|
||||
[13, "v1", "ogreboss-super-boulder"]
|
||||
],
|
||||
|
||||
"(code ogreboss-stage1)": [
|
||||
[36, "v1", "art-joint-anim"],
|
||||
[93, "v1", "art-joint-anim"],
|
||||
[172, "v1", "art-joint-anim"],
|
||||
[273, "v1", "art-joint-anim"],
|
||||
[329, "v1", "art-joint-anim"],
|
||||
[386, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ogreboss-bounce-boulder-idle)": [
|
||||
[81, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"ogreboss-idle-loop": [
|
||||
[145, "v1", "art-joint-anim"],
|
||||
[206, "v1", "art-joint-anim"],
|
||||
[261, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ogreboss-super-boulder-roll)": [
|
||||
[123, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"(code ogreboss-intro)": [
|
||||
[92, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"ogreboss-submerge": [
|
||||
[130, "v1", "art-joint-anim"]
|
||||
],
|
||||
|
||||
"ogreboss-pick-target": [
|
||||
[31, "s3", "process-drawable"]
|
||||
],
|
||||
|
||||
"(method 29 progress)": [
|
||||
[290, "a0", "(pointer symbol)"],
|
||||
[299, "v1", "(pointer symbol)"],
|
||||
[308, "a0", "(pointer symbol)"],
|
||||
[317, "v1", "(pointer symbol)"],
|
||||
[326, "a0", "(pointer symbol)"],
|
||||
[589, "a0", "(pointer symbol)"],
|
||||
[599, "v1", "(pointer symbol)"],
|
||||
[608, "a1", "(pointer symbol)"],
|
||||
[617, "v1", "(pointer symbol)"],
|
||||
[626, "a1", "(pointer symbol)"],
|
||||
[894, "a0", "(pointer symbol)"],
|
||||
[921, "a0", "(pointer symbol)"]
|
||||
],
|
||||
|
||||
"(method 9 edge-grab-info)": [
|
||||
[23, "a0", "int"],
|
||||
[[24,31], "s5", "collide-shape-prim"],
|
||||
[29, "a0", "process-drawable"],
|
||||
[156, "s5", "collide-shape-prim"]
|
||||
],
|
||||
"circle-triangle-intersection-proc?": [
|
||||
[[113, 134], "v1", "vector"]
|
||||
],
|
||||
|
||||
"(method 28 nav-control)": [
|
||||
[170, "v1", "connection"],
|
||||
[[170, 245], "s0", "collide-shape"]
|
||||
],
|
||||
|
||||
"(method 29 nav-mesh)": [
|
||||
[38, "v1", "int"],
|
||||
[40, "v1", "int"],
|
||||
[41, "v1", "int"],
|
||||
[64, "f1", "float"],
|
||||
[63, "v1", "float"]
|
||||
],
|
||||
|
||||
"nav-mesh-update-route-table": [
|
||||
[19, "a3", "(pointer uint8)"],
|
||||
[24, "a0", "(pointer uint8)"]
|
||||
],
|
||||
|
||||
"nav-mesh-lookup-route": [
|
||||
[6, "a0", "(pointer uint8)"]
|
||||
],
|
||||
|
||||
"(method 11 nav-mesh)": [
|
||||
[12, "a2", "(pointer uint8)"]
|
||||
],
|
||||
|
||||
"(method 12 nav-mesh)": [
|
||||
[13, "a2", "(pointer uint8)"]
|
||||
],
|
||||
|
||||
"recursive-inside-poly": [
|
||||
[16, "a0", "(pointer nav-node)"],
|
||||
[29, "v1", "(pointer nav-node)"]
|
||||
],
|
||||
|
||||
"entity-nav-login": [
|
||||
["_stack_", 16, "res-tag"]
|
||||
],
|
||||
|
||||
"(method 18 nav-mesh)": [
|
||||
[34, "v1", "nav-poly"]
|
||||
],
|
||||
|
||||
"test-func": [
|
||||
[7, "f1", "float"]
|
||||
],
|
||||
|
||||
@@ -3355,7 +3355,7 @@
|
||||
|
||||
"(method 18 bsp-header)": {
|
||||
"vars": {
|
||||
"a2-0": "existing-actor-count",
|
||||
"a2-0": "actor-count",
|
||||
"s4-0": "birth-idx",
|
||||
"a0-4": "idx-to-birth",
|
||||
"v1-25": "actor-to-birth",
|
||||
@@ -3530,7 +3530,9 @@
|
||||
|
||||
"(method 14 level-group)": {
|
||||
"vars": {
|
||||
"s1-1": ["s1-1", "process-drawable"]
|
||||
"s0-1": ["s0-1", "(pointer int32)"],
|
||||
"s1-1": ["s1-1", "process-drawable"],
|
||||
"v0-10": ["v0-10", "symbol"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3607,12 +3609,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
"(method 7 sage-finalboss)": {
|
||||
"vars": {
|
||||
"v1-0": ["v1-0", "(inline-array sage-finalboss-particle)"]
|
||||
}
|
||||
},
|
||||
|
||||
"(code robotboss-white-eco-movie)": {
|
||||
"vars": {
|
||||
"gp-1": ["gp-1", "handle"]
|
||||
@@ -3936,5 +3932,45 @@
|
||||
}
|
||||
},
|
||||
|
||||
"(method 13 touching-list)": {
|
||||
"vars": {
|
||||
"v0-0": ["v0-0", "touching-shapes-entry"]
|
||||
}
|
||||
},
|
||||
|
||||
"(method 11 touching-list)": {
|
||||
"vars": {
|
||||
"s5-0": ["s5-0", "touching-shapes-entry"]
|
||||
}
|
||||
},
|
||||
|
||||
"recursive-inside-poly": {
|
||||
"vars": {
|
||||
"a1-2": ["a1-2", "nav-node"]
|
||||
}
|
||||
},
|
||||
|
||||
"vu-point-triangle-intersection?": {
|
||||
"vars": {
|
||||
"v1-0": ["v1-0", "int"],
|
||||
"a0-1": ["a0-1", "int"],
|
||||
"a1-1": ["a1-1", "int"]
|
||||
}
|
||||
},
|
||||
|
||||
"point-inside-poly?": {
|
||||
"vars": {
|
||||
"v1-6": ["v1-6", "int"],
|
||||
"a0-3": ["a0-3", "int"],
|
||||
"a1-6": ["a1-6", "int"]
|
||||
}
|
||||
},
|
||||
|
||||
"(method 29 nav-mesh)": {
|
||||
"vars": {
|
||||
"v1-10": ["v1-10", "int"]
|
||||
}
|
||||
},
|
||||
|
||||
"aaaaaaaaaaaaaaaaaaaaaaa": {}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
#include "common/util/assert.h"
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include "common/common_types.h"
|
||||
#include "decompiler/ObjectFile/LinkedWord.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
class LinkedWordReader {
|
||||
@@ -41,4 +41,4 @@ class LinkedWordReader {
|
||||
const std::vector<LinkedWord>* m_words = nullptr;
|
||||
u32 m_offset = 0;
|
||||
};
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
* Utility class to read a .STR file and extract the full file name.
|
||||
*/
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include <cstring>
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "game/common/overlord_common.h"
|
||||
#include "game/common/str_rpc_types.h"
|
||||
#include "StrFileReader.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
StrFileReader::StrFileReader(const std::string& file_path) {
|
||||
@@ -180,4 +180,4 @@ std::string StrFileReader::get_full_name(const std::string& short_name) const {
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "TextureDB.h"
|
||||
|
||||
#include "common/util/assert.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
@@ -37,4 +37,4 @@ void TextureDB::add_texture(u32 tpage,
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -107,7 +107,7 @@ GameTextResult process_game_text(ObjectFileData& data, GameTextVersion version)
|
||||
auto string_start = (text_label.offset / 4) - 1;
|
||||
// 8 for type tag and length fields, 1 for null char.
|
||||
for (int j = 0, m = align16(8 + 1 + (int)text.length()) / 4;
|
||||
j < m && string_start + j < read_words.size(); j++) {
|
||||
j < m && string_start + j < (int)read_words.size(); j++) {
|
||||
read_words.at(string_start + j)++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* check duplicate names
|
||||
*/
|
||||
|
||||
#include <common/util/FileUtil.h>
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "tpage.h"
|
||||
#include "common/versions.h"
|
||||
#include "decompiler/ObjectFile/ObjectFileDB.h"
|
||||
@@ -703,4 +703,4 @@ TPageResultStats process_tpage(ObjectFileData& data, TextureDB& texture_db) {
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -1041,7 +1041,7 @@ void ProxyPrototypeArrayTie::read_from_file(TypedRef ref,
|
||||
prototype_array_tie.read_from_file(
|
||||
get_and_check_ref_to_basic(ref, "prototype-array-tie", "prototype-array-tie", dts), dts,
|
||||
stats);
|
||||
// TODO wind
|
||||
wind_vectors = deref_label(get_field_ref(ref, "wind-vectors", dts));
|
||||
}
|
||||
|
||||
std::string ProxyPrototypeArrayTie::print(const PrintSettings& settings, int indent) const {
|
||||
|
||||
@@ -352,7 +352,7 @@ struct ProxyPrototypeArrayTie {
|
||||
std::string print(const PrintSettings& settings, int indent) const;
|
||||
|
||||
PrototypeArrayTie prototype_array_tie;
|
||||
// todo wind vectors.
|
||||
Ref wind_vectors;
|
||||
};
|
||||
|
||||
struct DrawableTreeInstanceTie : public DrawableTree {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "decompiler/level_extractor/BspHeader.h"
|
||||
#include "decompiler/level_extractor/extract_tfrag.h"
|
||||
#include "decompiler/level_extractor/extract_tie.h"
|
||||
#include "common/util/compress.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
namespace decompiler {
|
||||
@@ -107,8 +108,12 @@ void extract_from_level(ObjectFileDB& db,
|
||||
|
||||
Serializer ser;
|
||||
tfrag_level.serialize(ser);
|
||||
auto compressed =
|
||||
compression::compress_zstd(ser.get_save_result().first, ser.get_save_result().second);
|
||||
fmt::print("compressed: {} -> {} ({:.2f}%)\n", ser.get_save_result().second, compressed.size(),
|
||||
100.f * compressed.size() / ser.get_save_result().second);
|
||||
file_util::write_binary_file(file_util::get_file_path({fmt::format(
|
||||
"assets/{}.fr3", dgo_name.substr(0, dgo_name.length() - 4))}),
|
||||
ser.get_save_result().first, ser.get_save_result().second);
|
||||
compressed.data(), compressed.size());
|
||||
}
|
||||
} // namespace decompiler
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "extract_tfrag.h"
|
||||
#include "common/dma/dma.h"
|
||||
#include "common/util/assert.h"
|
||||
#include "decompiler/util/Error.h"
|
||||
#include "decompiler/ObjectFile/LinkedObjectFile.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/dma/gs.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
namespace {
|
||||
@@ -117,6 +117,7 @@ VisNodeTree extract_vis_data(const level_tools::DrawableTreeTfrag* tree, u16 fir
|
||||
}
|
||||
vis.num_kids = elt.child_count;
|
||||
vis.flags = elt.flags;
|
||||
vis.my_id = elt.id;
|
||||
assert(vis.flags == expecting_leaves ? 0 : 1);
|
||||
assert(vis.num_kids > 0);
|
||||
assert(vis.num_kids <= 8);
|
||||
@@ -2036,8 +2037,8 @@ void make_tfrag3_data(std::map<u32, std::vector<GroupedDraw>>& draws,
|
||||
|
||||
for (auto& strip : draw.strips) {
|
||||
tfrag3::StripDraw::VisGroup vgroup;
|
||||
vgroup.vis_idx = strip.tfrag_id; // associate with the tfrag for culling
|
||||
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
|
||||
vgroup.vis_idx_in_pc_bvh = strip.tfrag_id; // associate with the tfrag for culling
|
||||
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
|
||||
|
||||
tdraw.num_triangles += strip.verts.size() - 2;
|
||||
for (auto& vert : strip.verts) {
|
||||
@@ -2114,6 +2115,19 @@ void extract_time_of_day(const level_tools::DrawableTreeTfrag* tree, tfrag3::Tfr
|
||||
}
|
||||
}
|
||||
|
||||
void merge_groups(std::vector<tfrag3::StripDraw::VisGroup>& grps) {
|
||||
std::vector<tfrag3::StripDraw::VisGroup> result;
|
||||
result.push_back(grps.at(0));
|
||||
for (size_t i = 1; i < grps.size(); i++) {
|
||||
if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh) {
|
||||
result.back().num += grps[i].num;
|
||||
} else {
|
||||
result.push_back(grps[i]);
|
||||
}
|
||||
}
|
||||
std::swap(result, grps);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void extract_tfrag(const level_tools::DrawableTreeTfrag* tree,
|
||||
@@ -2183,13 +2197,14 @@ void extract_tfrag(const level_tools::DrawableTreeTfrag* tree,
|
||||
|
||||
for (auto& draw : this_tree.draws) {
|
||||
for (auto& str : draw.vis_groups) {
|
||||
auto it = tfrag_parents.find(str.vis_idx);
|
||||
auto it = tfrag_parents.find(str.vis_idx_in_pc_bvh);
|
||||
if (it == tfrag_parents.end()) {
|
||||
str.vis_idx = UINT32_MAX;
|
||||
str.vis_idx_in_pc_bvh = UINT32_MAX;
|
||||
} else {
|
||||
str.vis_idx = it->second;
|
||||
str.vis_idx_in_pc_bvh = it->second;
|
||||
}
|
||||
}
|
||||
merge_groups(draw.vis_groups);
|
||||
}
|
||||
out.tfrag_trees.push_back(this_tree);
|
||||
}
|
||||
|
||||
@@ -20,15 +20,6 @@ struct VisNodeTree {
|
||||
bool only_children = false;
|
||||
};
|
||||
|
||||
// The final result
|
||||
struct ExtractedTFragmentTree {
|
||||
// TFragmentKind kind = TFragmentKind::INVALID;
|
||||
VisNodeTree vis_nodes;
|
||||
|
||||
u16 num_tfrags = 0;
|
||||
u16 tfrag_base_idx = 0;
|
||||
};
|
||||
|
||||
// will pool textures with others already in out.
|
||||
void extract_tfrag(const level_tools::DrawableTreeTfrag* tree,
|
||||
const std::string& debug_name,
|
||||
|
||||
@@ -126,6 +126,7 @@ void extract_vis_data(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
}
|
||||
vis.num_kids = elt.child_count;
|
||||
vis.flags = elt.flags;
|
||||
vis.my_id = elt.id;
|
||||
assert(vis.flags == expecting_leaves ? 0 : 1);
|
||||
assert(vis.num_kids > 0);
|
||||
assert(vis.num_kids <= 8);
|
||||
@@ -167,32 +168,28 @@ void extract_vis_data(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
}
|
||||
}
|
||||
|
||||
// Each TIE prototype is broken up into "fragments". These "fragments" have some maximum size based
|
||||
// on the VU memory limit, so an instance may have multiple fragments, depending on how many
|
||||
// vertices are in the model.
|
||||
|
||||
// Each instance has different set of time of day colors per fragment in the prototype.
|
||||
// this type contains the indicies of these colors.
|
||||
// For the PC port we combine all colors into a single "big palette".
|
||||
// this stores the indices as indices into the original game's per fragment palette.
|
||||
// and an offset for where this palette is located in the big palette.
|
||||
struct TieInstanceFragInfo {
|
||||
// the color index table uploaded to VU.
|
||||
// this contains indices into the shared palette.
|
||||
std::vector<u8> color_indices;
|
||||
|
||||
// in the PC port format, we upload a single giant time of day color. this points to the offset
|
||||
// of the colors from this frag instance.
|
||||
u16 color_index_offset_in_big_palette = -1;
|
||||
|
||||
math::Vector<u32, 4> lq_colors_ui(u32 qw) const {
|
||||
// note: this includes the unpack
|
||||
assert(qw >= 204);
|
||||
qw -= 204;
|
||||
qw *= 4;
|
||||
assert(qw + 4 <= color_indices.size());
|
||||
math::Vector<u32, 4> result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result[i] = color_indices.at(qw + i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Each TIE instance has one of these. This is reorganized/unpacked data from the instance-tie type.
|
||||
struct TieInstanceInfo {
|
||||
// The index of the prototype (the geometry) that is used by this instance
|
||||
// note: we're going to trust that this lines up with bucket.
|
||||
// if this assumption is wrong, we'll be drawing with the wrong model and it will be super
|
||||
// obvious.
|
||||
u16 prototype_idx = 0;
|
||||
|
||||
// our bsphere's index in the BVH tree
|
||||
@@ -202,33 +199,44 @@ struct TieInstanceInfo {
|
||||
// actually cull using the tree)
|
||||
math::Vector4f bsphere;
|
||||
|
||||
// the transformation matrix, unpacked from the weird TIE format.
|
||||
// this can be used to transform points directly to world-space points that work
|
||||
// with the normal math camera stuff.
|
||||
std::array<math::Vector4f, 4> mat;
|
||||
|
||||
// this value is stashed inside the above matrix. It tells which "wind" we should use
|
||||
// we just need to pass this along to the C++ rendering code.
|
||||
u16 wind_index = 0;
|
||||
float unknown_wind_related_value = 0.f; // w of the first mat vec.
|
||||
|
||||
std::vector<TieInstanceFragInfo> frags; // per-instance per-fragment info
|
||||
std::vector<TieInstanceFragInfo> frags; // per-instance per-fragment info (just colors)
|
||||
};
|
||||
|
||||
// The 5 qw of adgif data contains draw settings, and they also snuck in some extra data.
|
||||
struct AdgifInfo {
|
||||
u32 first_w;
|
||||
u32 second_w;
|
||||
u32 third_w;
|
||||
u32 combo_tex;
|
||||
u64 alpha_val;
|
||||
u64 clamp_val;
|
||||
// secret stuff they snuck in
|
||||
u32 first_w; // VU memory offset
|
||||
u32 second_w; // some size
|
||||
u32 third_w; // unused, at least for not-near TIE
|
||||
|
||||
// the draw settings we care about:
|
||||
u32 combo_tex; // PC texture ID
|
||||
u64 alpha_val; // alpha blend settings
|
||||
u64 clamp_val; // texture clamp settings
|
||||
};
|
||||
|
||||
// When the prototype is uploaded, it places a bunch of strgif tags in VU memory.
|
||||
// we'll need to remember where these are.
|
||||
struct StrGifInfo {
|
||||
u16 address;
|
||||
u16 nloop;
|
||||
u16 mode; // not yet fully understood, but can allow the use of other templates.
|
||||
bool eop;
|
||||
u16 address; // vu memory address
|
||||
u16 nloop; // the nloop field of this strgif (how much to send)
|
||||
u16 mode; // not yet fully understood, but can allow the use of other templates
|
||||
bool eop; // end of packet flag
|
||||
};
|
||||
|
||||
// data per vertex in a tie prototype
|
||||
struct TieProtoVertex {
|
||||
math::Vector<float, 3> pos;
|
||||
math::Vector<float, 3> tex;
|
||||
math::Vector<float, 3> pos; // position
|
||||
math::Vector<float, 3> tex; // texture coordinate
|
||||
|
||||
// NOTE: this is a double lookup.
|
||||
// first you look up the index in the _instance_ color table
|
||||
@@ -236,26 +244,34 @@ struct TieProtoVertex {
|
||||
u32 color_index_index;
|
||||
};
|
||||
|
||||
// a tie fragment is made up of strips. Each strip has a single adgif info, and vertices
|
||||
// the vertices make up a triangle strip
|
||||
struct TieStrip {
|
||||
AdgifInfo adgif;
|
||||
std::vector<TieProtoVertex> verts;
|
||||
};
|
||||
|
||||
// the tie fragment
|
||||
// this is a per-prototype (all instances share the same TieFrags)
|
||||
struct TieFrag {
|
||||
bool has_magic_tex0_bit = false;
|
||||
std::vector<AdgifInfo> adgifs;
|
||||
bool has_magic_tex0_bit = false; // use decal mode (todo)
|
||||
std::vector<AdgifInfo>
|
||||
adgifs; // the adgifs that come with this tiefrag (different strips can hve different)
|
||||
|
||||
std::vector<u8> other_gif_data;
|
||||
std::vector<u8> points_data;
|
||||
std::vector<u32> point_sizes;
|
||||
std::vector<u8> other_gif_data; // data sent from EE asm code, sizes/offsets/metadata
|
||||
std::vector<u8> points_data; // data sent from EE asm code, actual vertex data
|
||||
|
||||
// number of "dverts" expected from game's metadata. we check our extraction from this.
|
||||
u32 expected_dverts = 0;
|
||||
|
||||
// all the strips in this fragment
|
||||
std::vector<TieStrip> strips;
|
||||
|
||||
// this contains vertices, key is the start of the actual xyzf/st/rgbaq data for it.
|
||||
// this contains vertices, key is the address of the actual xyzf/st/rgbaq data in VU1 memory
|
||||
// after the prototype program runs
|
||||
std::unordered_map<u32, TieProtoVertex> vertex_by_dest_addr;
|
||||
|
||||
// simulate a load in the points data (using vu mem addr)
|
||||
math::Vector<float, 4> lq_points(u32 qw) const {
|
||||
assert(qw >= 50);
|
||||
qw -= 50;
|
||||
@@ -265,6 +281,8 @@ struct TieFrag {
|
||||
return result;
|
||||
}
|
||||
|
||||
// simulate a load from points, but don't die if we load past the end
|
||||
// this can happen when pipelining.
|
||||
math::Vector<float, 4> lq_points_allow_past_end(u32 qw) const {
|
||||
assert(qw >= 50);
|
||||
qw -= 50;
|
||||
@@ -277,6 +295,8 @@ struct TieFrag {
|
||||
}
|
||||
}
|
||||
|
||||
// store data into points. annoyingly the points have to be unpacked
|
||||
// and they are modified in place.
|
||||
void sq_points(u32 qw, const math::Vector4f& data) {
|
||||
assert(qw >= 50);
|
||||
qw -= 50;
|
||||
@@ -284,6 +304,7 @@ struct TieFrag {
|
||||
memcpy(points_data.data() + (qw * 16), data.data(), 16);
|
||||
}
|
||||
|
||||
// do a ilw from the other gif data.
|
||||
u16 ilw_other_gif(u32 qw, u32 offset) const {
|
||||
// unpacked with v8.
|
||||
int qwi = qw;
|
||||
@@ -292,6 +313,7 @@ struct TieFrag {
|
||||
return other_gif_data.at(qwi * 4 + offset);
|
||||
}
|
||||
|
||||
// reg values from the prototype program that are used by the instance program.
|
||||
struct ProgramInfo {
|
||||
std::vector<u16> adgif_offset_in_gif_buf_qw;
|
||||
std::vector<StrGifInfo> str_gifs;
|
||||
@@ -310,16 +332,21 @@ struct TieFrag {
|
||||
} prog_info;
|
||||
};
|
||||
|
||||
// main instance type
|
||||
// unlike the GOAL type, we store all instances info in here too.
|
||||
struct TieProtoInfo {
|
||||
std::string name;
|
||||
std::vector<TieInstanceInfo> instances;
|
||||
bool uses_generic = false;
|
||||
float stiffness = 0;
|
||||
float stiffness = 0; // wind
|
||||
u32 generic_flag;
|
||||
std::vector<tfrag3::TimeOfDayColor> time_of_day_colors;
|
||||
std::vector<TieFrag> frags;
|
||||
std::vector<tfrag3::TimeOfDayColor> time_of_day_colors; // c++ type for time of day data
|
||||
std::vector<TieFrag> frags; // the fragments of the prototype
|
||||
};
|
||||
|
||||
/*!
|
||||
* Convert TIE packed matrix to normal one. this was figured out from the EE asm.
|
||||
*/
|
||||
std::array<math::Vector4f, 4> extract_tie_matrix(const u16* data) {
|
||||
std::array<math::Vector4f, 4> result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -341,27 +368,52 @@ std::array<math::Vector4f, 4> extract_tie_matrix(const u16* data) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// geometry we use (todo, should really look at this)
|
||||
constexpr int GEOM_IDX = 1; // todo 0 or 1??
|
||||
|
||||
/*!
|
||||
* Confirm that the initial value of all wind vectors is 0.
|
||||
* If this is true, we don't have to actually save them to the fr3 file, we can just create
|
||||
* a bunch of 0 vectors in the TIE setup.
|
||||
*/
|
||||
void check_wind_vectors_zero(const std::vector<TieProtoInfo>& protos, Ref wind_ref) {
|
||||
u16 max_wind = 0;
|
||||
for (auto& proto : protos) {
|
||||
for (auto& inst : proto.instances) {
|
||||
max_wind = std::max(inst.wind_index, max_wind);
|
||||
}
|
||||
}
|
||||
u32 wind_words = max_wind;
|
||||
wind_words *= 4;
|
||||
for (size_t i = 0; i < wind_words; i++) {
|
||||
auto& word = wind_ref.data->words_by_seg.at(wind_ref.seg).at(wind_ref.byte_offset / 4 + i);
|
||||
assert(word.kind() == LinkedWord::PLAIN_DATA);
|
||||
assert(word.data == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// get per-instance info from the level data
|
||||
std::vector<TieProtoInfo> collect_instance_info(
|
||||
const level_tools::DrawableInlineArrayInstanceTie* instances,
|
||||
const std::vector<level_tools::PrototypeBucketTie>* protos) {
|
||||
std::vector<TieProtoInfo> result;
|
||||
|
||||
// loop over instances in level
|
||||
for (auto& instance : instances->instances) {
|
||||
// copy basic data.
|
||||
TieInstanceInfo info;
|
||||
info.prototype_idx = instance.bucket_index;
|
||||
info.vis_id = instance.id;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
info.bsphere[i] = instance.bsphere.data[i];
|
||||
}
|
||||
// from ee asm
|
||||
info.mat = extract_tie_matrix(instance.origin.data);
|
||||
info.mat[3][0] += info.bsphere[0];
|
||||
info.mat[3][1] += info.bsphere[1];
|
||||
info.mat[3][2] += info.bsphere[2];
|
||||
info.wind_index = instance.wind_index;
|
||||
// there's a value stashed here that we can get rid of
|
||||
// it is related to wind.
|
||||
info.unknown_wind_related_value = info.mat[0][3];
|
||||
|
||||
info.mat[0][3] = 0.f;
|
||||
|
||||
// each fragment has its own color data (3 dmatags)
|
||||
@@ -374,10 +426,15 @@ std::vector<TieProtoInfo> collect_instance_info(
|
||||
// and this is only the indices.... there's yet another lookup on the VU
|
||||
auto& proto = protos->at(info.prototype_idx);
|
||||
u32 offset_bytes = proto.base_qw[GEOM_IDX] * 16;
|
||||
// loop over frags. this is only the per-instance info so only colors indices. We know the
|
||||
// location/layout of the color data from the EE asm code.
|
||||
for (int frag_idx = 0; frag_idx < proto.frag_count[GEOM_IDX]; frag_idx++) {
|
||||
TieInstanceFragInfo frag_info;
|
||||
// read the number of quadwords
|
||||
u32 num_color_qwc = proto.color_index_qwc.at(proto.index_start[GEOM_IDX] + frag_idx);
|
||||
// loop over 4-byte words
|
||||
for (u32 i = 0; i < num_color_qwc * 4; i++) {
|
||||
// loop over bytes in word
|
||||
for (u32 j = 0; j < 4; j++) {
|
||||
frag_info.color_indices.push_back(
|
||||
instance.color_indices.data->words_by_seg.at(instance.color_indices.seg)
|
||||
@@ -387,6 +444,7 @@ std::vector<TieProtoInfo> collect_instance_info(
|
||||
}
|
||||
info.frags.push_back(std::move(frag_info));
|
||||
assert(info.frags.back().color_indices.size() > 0);
|
||||
|
||||
offset_bytes += num_color_qwc * 16;
|
||||
}
|
||||
|
||||
@@ -399,6 +457,10 @@ std::vector<TieProtoInfo> collect_instance_info(
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* adgif shader texture id's can be "remapped". I think it allows textures to be shared.
|
||||
* So far we haven't seen this feature used, but we do have the texture map and we check it here.
|
||||
*/
|
||||
u32 remap_texture(u32 original, const std::vector<level_tools::TextureRemap>& map) {
|
||||
auto masked = original & 0xffffff00;
|
||||
for (auto& t : map) {
|
||||
@@ -411,6 +473,9 @@ u32 remap_texture(u32 original, const std::vector<level_tools::TextureRemap>& ma
|
||||
return original;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Update per-proto information.
|
||||
*/
|
||||
void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
const TextureDB& tdb,
|
||||
@@ -419,12 +484,18 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
for (size_t i = 0; i < protos.size(); i++) {
|
||||
const auto& proto = protos[i];
|
||||
auto& info = out->at(i);
|
||||
// the flags can either be 0 or 2.
|
||||
assert(proto.flags == 0 || proto.flags == 2);
|
||||
// flag of 2 means it should use the generic renderer (determined from EE asm)
|
||||
// for now, we ignore this and use TIE on everything.
|
||||
info.uses_generic = (proto.flags == 2);
|
||||
// for debug, remember the name
|
||||
info.name = proto.name;
|
||||
// wind "stiffness" nonzero value means it has the wind effect
|
||||
info.stiffness = proto.stiffness;
|
||||
info.generic_flag = proto.flags & 2;
|
||||
|
||||
// the actual colors (rgba) used by time of day interpolation
|
||||
// there are "height" colors. Each color is actually 8 colors that are interpolated.
|
||||
info.time_of_day_colors.resize(proto.time_of_day.height);
|
||||
for (int k = 0; k < (int)proto.time_of_day.height; k++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
@@ -432,20 +503,41 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
}
|
||||
}
|
||||
|
||||
// loop over fragments in the proto. This is the actual mesh data data and drawing settings
|
||||
for (int frag_idx = 0; frag_idx < proto.frag_count[GEOM_IDX]; frag_idx++) {
|
||||
TieFrag frag_info;
|
||||
|
||||
// loop over adgif shaders
|
||||
for (int tex_idx = 0;
|
||||
tex_idx < proto.geometry[GEOM_IDX].tie_fragments.at(frag_idx).tex_count / 5; tex_idx++) {
|
||||
// this adgif shader data is modified in the real game by the login methods.
|
||||
// all TIE things have pretty normal adgif shaders
|
||||
|
||||
// all the useful adgif data will be saved into this AdgifInfo
|
||||
AdgifInfo adgif;
|
||||
|
||||
// pointer to the level data
|
||||
auto& gif_data = proto.geometry[GEOM_IDX].tie_fragments[frag_idx].gif_data;
|
||||
|
||||
// address for the first adgif shader qw.
|
||||
u8 ra_tex0 = gif_data.at(16 * (tex_idx * 5 + 0) + 8);
|
||||
// data for the first adgif shader qw.
|
||||
u64 ra_tex0_val;
|
||||
memcpy(&ra_tex0_val, &gif_data.at(16 * (tex_idx * 5 + 0)), 8);
|
||||
|
||||
// always expecting TEX0_1
|
||||
assert(ra_tex0 == (u8)GsRegisterAddress::TEX0_1);
|
||||
|
||||
// the value is overwritten by the login function. We don't care about this value, it's
|
||||
// specific to the PS2's texture system.
|
||||
assert(ra_tex0_val == 0 || ra_tex0_val == 0x800000000); // note: decal
|
||||
// the original value is a flag. this means to use decal texture mode (todo)
|
||||
frag_info.has_magic_tex0_bit = ra_tex0_val == 0x800000000;
|
||||
// there's also a hidden value in the unused bits of the a+d data. it'll be used by the
|
||||
// VU program.
|
||||
memcpy(&adgif.first_w, &gif_data.at(16 * (tex_idx * 5 + 0) + 12), 4);
|
||||
|
||||
// Second adgif. Similar to the first, except the original data value is a texture ID.
|
||||
u8 ra_tex1 = gif_data.at(16 * (tex_idx * 5 + 1) + 8);
|
||||
u64 ra_tex1_val;
|
||||
memcpy(&ra_tex1_val, &gif_data.at(16 * (tex_idx * 5 + 1)), 8);
|
||||
@@ -453,34 +545,41 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
assert(ra_tex1_val == 0x120); // some flag
|
||||
u32 original_tex;
|
||||
memcpy(&original_tex, &gif_data.at(16 * (tex_idx * 5 + 1) + 8), 4);
|
||||
// try remapping it
|
||||
u32 new_tex = remap_texture(original_tex, map);
|
||||
if (original_tex != new_tex) {
|
||||
fmt::print("map from 0x{:x} to 0x{:x}\n", original_tex, new_tex);
|
||||
}
|
||||
// texture the texture page/texture index, and convert to a PC port texture ID
|
||||
u32 tpage = new_tex >> 20;
|
||||
u32 tidx = (new_tex >> 8) & 0b1111'1111'1111;
|
||||
u32 tex_combo = (((u32)tpage) << 16) | tidx;
|
||||
// look up the texture to make sure it's valid
|
||||
auto tex = tdb.textures.find(tex_combo);
|
||||
assert(tex != tdb.textures.end());
|
||||
// remember the texture id
|
||||
adgif.combo_tex = tex_combo;
|
||||
// and the hidden value in the unused a+d
|
||||
memcpy(&adgif.second_w, &gif_data.at(16 * (tex_idx * 5 + 1) + 12), 4);
|
||||
|
||||
// todo: figure out if this matters
|
||||
if (ra_tex0_val == 0x800000000) {
|
||||
fmt::print("texture {} in {} has weird tex setting\n", tex->second.name, proto.name);
|
||||
}
|
||||
|
||||
// mipmap settings. we ignore, but get the hidden value
|
||||
u8 ra_mip = gif_data.at(16 * (tex_idx * 5 + 2) + 8);
|
||||
assert(ra_mip == (u8)GsRegisterAddress::MIPTBP1_1);
|
||||
memcpy(&adgif.third_w, &gif_data.at(16 * (tex_idx * 5 + 2) + 12), 4);
|
||||
|
||||
// who cares about the value
|
||||
|
||||
// clamp settings. we care about these. no hidden value.
|
||||
u8 ra_clamp = gif_data.at(16 * (tex_idx * 5 + 3) + 8);
|
||||
assert(ra_clamp == (u8)GsRegisterAddress::CLAMP_1);
|
||||
u64 clamp;
|
||||
memcpy(&clamp, &gif_data.at(16 * (tex_idx * 5 + 3)), 8);
|
||||
adgif.clamp_val = clamp;
|
||||
|
||||
// alpha settings. we care about these, but no hidden value
|
||||
u8 ra_alpha = gif_data.at(16 * (tex_idx * 5 + 4) + 8);
|
||||
assert(ra_alpha == (u8)GsRegisterAddress::ALPHA_1);
|
||||
u64 alpha;
|
||||
@@ -488,7 +587,12 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
adgif.alpha_val = alpha;
|
||||
frag_info.adgifs.push_back(adgif);
|
||||
}
|
||||
|
||||
// they store a vertex count. we later use this to sanity check out mesh extraction
|
||||
frag_info.expected_dverts = proto.geometry[GEOM_IDX].tie_fragments[frag_idx].num_dverts;
|
||||
|
||||
// each frag also has "other" data. This is some index data that the VU program uses.
|
||||
// it comes in gif_data, after tex_qwc (determined from EE program)
|
||||
int tex_qwc = proto.geometry[GEOM_IDX].tie_fragments.at(frag_idx).tex_count;
|
||||
int other_qwc = proto.geometry[GEOM_IDX].tie_fragments.at(frag_idx).gif_count;
|
||||
frag_info.other_gif_data.resize(16 * other_qwc);
|
||||
@@ -496,6 +600,8 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
proto.geometry[GEOM_IDX].tie_fragments[frag_idx].gif_data.data() + (16 * tex_qwc),
|
||||
16 * other_qwc);
|
||||
|
||||
// each frag's "point" data. These are stored as int16's, but get unpacked to 32-bit ints by
|
||||
// the VIF. (determined from EE program)
|
||||
const auto& pr = proto.geometry[GEOM_IDX].tie_fragments[frag_idx].point_ref;
|
||||
int in_qw = pr.size() / 16;
|
||||
int out_qw = in_qw * 2;
|
||||
@@ -508,16 +614,15 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
}
|
||||
}
|
||||
|
||||
// just for debug
|
||||
for (int g = 0; g < 4; g++) {
|
||||
frag_info.point_sizes.push_back(proto.geometry[g].tie_fragments[frag_idx].point_ref.size());
|
||||
}
|
||||
|
||||
info.frags.push_back(std::move(frag_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// List of dma tags from the EE code.
|
||||
// upload-palette/upload-model happen per prototype.
|
||||
// (palette may happen per prototype, model per geometry, but we only use 1 geom)
|
||||
|
||||
// upload-palette-0: just a flusha
|
||||
// no data
|
||||
|
||||
@@ -538,9 +643,12 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
// points
|
||||
|
||||
// upload-model-3
|
||||
// mscal 6
|
||||
// mscal 6 <- this runs a VU program that unpacks the model data
|
||||
// call the models!
|
||||
|
||||
// These upload-color's happen per instance. They only happen after the upload-palette/model's
|
||||
// happen for the given model.
|
||||
|
||||
// upload-color-0
|
||||
// 6 qw of matrix plus flag stuff
|
||||
// to 198 (relative to TOP)
|
||||
@@ -549,9 +657,13 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
// to 204 unsigned (relative to TOP)
|
||||
|
||||
// upload-color-2/ret
|
||||
// mscal 0
|
||||
// mscal 0 <- this runs a VU program that generates GS data to draw the instance.
|
||||
|
||||
// MEMORY MAP of TIE
|
||||
// these are quadword addresses.
|
||||
// some things are double/triple buffered.
|
||||
// we ignore this for the most part and by convention use the lower address.
|
||||
|
||||
// 0 gif tags
|
||||
// extra gifs
|
||||
// 32 model
|
||||
@@ -574,6 +686,9 @@ void update_proto_info(std::vector<TieProtoInfo>* out,
|
||||
// 973 atest-tra
|
||||
// 974 atest-def
|
||||
|
||||
// the vu program emulation will fill out the vertex positions/draw settings for each instance.
|
||||
|
||||
// helper functions for the vu programs
|
||||
math::Vector4f itof0(const math::Vector4f& vec) {
|
||||
math::Vector4f result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -1561,38 +1676,49 @@ void emulate_tie_instance_program(std::vector<TieProtoInfo>& protos) {
|
||||
}
|
||||
}
|
||||
|
||||
// makes per-prototype meshes
|
||||
// the final step of the VU program emulation is the "xgkick" instruction.
|
||||
// there is a signal xgkick per fragment and it goes through the entire gif buf, hitting
|
||||
// strgifs and adgifs. We look at the memory map for each frag and figure out which strips
|
||||
// go with which adgifs, then copy vertices
|
||||
void emulate_kicks(std::vector<TieProtoInfo>& protos) {
|
||||
for (auto& proto : protos) {
|
||||
for (auto& frag : proto.frags) {
|
||||
// we iterate over both adgifs/stgifs. sometimes you can have multiple strgifs that use the
|
||||
// same adgif. But we never expect to see multiple adgifs in a row.
|
||||
auto adgif_it = frag.prog_info.adgif_offset_in_gif_buf_qw.begin();
|
||||
auto adgif_end = frag.prog_info.adgif_offset_in_gif_buf_qw.end();
|
||||
auto str_it = frag.prog_info.str_gifs.begin();
|
||||
auto str_end = frag.prog_info.str_gifs.end();
|
||||
|
||||
// but, we should always start with an adgif (otherwise we'd use the draw settings from
|
||||
// the last model, which we don't know)
|
||||
assert(frag.prog_info.adgif_offset_in_gif_buf_qw.at(0) == 0);
|
||||
// and we expect that the VU program placed all adgifs somewhere
|
||||
assert(frag.prog_info.adgif_offset_in_gif_buf_qw.size() == frag.adgifs.size());
|
||||
|
||||
const AdgifInfo* adgif_info = nullptr;
|
||||
int expected_next_tag = 0;
|
||||
|
||||
// loop over strgifs
|
||||
while (str_it != str_end) {
|
||||
// try advance adgif
|
||||
// try to see if we got a adgif here
|
||||
if (adgif_it != adgif_end && (*adgif_it) == expected_next_tag) {
|
||||
// yep
|
||||
int idx = adgif_it - frag.prog_info.adgif_offset_in_gif_buf_qw.begin();
|
||||
adgif_info = &frag.adgifs.at(idx);
|
||||
// fmt::print("using adgif {}\n", *adgif_it);
|
||||
// the next strgif should come 6 qw's after
|
||||
expected_next_tag += 6;
|
||||
adgif_it++;
|
||||
}
|
||||
assert(adgif_info);
|
||||
|
||||
// fmt::print("strip: {}\n", str_it->address);
|
||||
// make sure the next str is where we expect
|
||||
assert(expected_next_tag == str_it->address);
|
||||
// the next tag (either str/adgif) should be located at the end of this tag's data.
|
||||
expected_next_tag += 3 * str_it->nloop + 1;
|
||||
// here we have the right str and adgif.
|
||||
|
||||
// kinda stupid, but we have to guess the base address of the gifbuf
|
||||
// kinda stupid, but we have to guess the base address of the gifbuf we're using.
|
||||
// 286 gifbuf
|
||||
// 470 gifbuf again
|
||||
// 654 ??
|
||||
@@ -1605,12 +1731,15 @@ void emulate_kicks(std::vector<TieProtoInfo>& protos) {
|
||||
base_address = 470;
|
||||
}
|
||||
|
||||
// now, vertices!
|
||||
// now, we can add the vertices!
|
||||
frag.strips.emplace_back();
|
||||
auto& strip = frag.strips.back();
|
||||
strip.adgif = *adgif_info;
|
||||
// loop over all the vertices the strgif says we'll have
|
||||
for (int vtx = 0; vtx < str_it->nloop; vtx++) {
|
||||
// compute the address of this vertex (stored after the strgif)
|
||||
u32 vtx_addr = str_it->address + 1 + (3 * vtx) + base_address;
|
||||
// and grab it from the vertex map we made earlier.
|
||||
strip.verts.push_back(frag.vertex_by_dest_addr.at(vtx_addr));
|
||||
}
|
||||
|
||||
@@ -1622,6 +1751,11 @@ void emulate_kicks(std::vector<TieProtoInfo>& protos) {
|
||||
}
|
||||
}
|
||||
|
||||
// from here on, we are mostly converting the "info" formats to the C++ renderer format (tfrag3)
|
||||
|
||||
/*!
|
||||
* Just used to debug, save a proto as an .obj mesh file.
|
||||
*/
|
||||
std::string debug_dump_proto_to_obj(const TieProtoInfo& proto) {
|
||||
std::vector<math::Vector<float, 3>> verts;
|
||||
std::vector<math::Vector<float, 2>> tcs;
|
||||
@@ -1678,16 +1812,12 @@ std::string debug_dump_proto_to_obj(const TieProtoInfo& proto) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Transform a point in a prototype to the actual point location in the game world.
|
||||
*/
|
||||
math::Vector<float, 3> transform_tie(const std::array<math::Vector4f, 4> mat,
|
||||
const math::Vector3f& pt) {
|
||||
auto temp = mat[0] * pt.x() + mat[1] * pt.y() + mat[2] * pt.z() + mat[3];
|
||||
|
||||
// math::Vector4f temp;
|
||||
// temp.x() = pt.x();
|
||||
// temp.y() = pt.y();
|
||||
// temp.z() = pt.z();
|
||||
// temp += mat[3];
|
||||
|
||||
math::Vector3f result;
|
||||
result.x() = temp.x();
|
||||
result.y() = temp.y();
|
||||
@@ -1695,6 +1825,10 @@ math::Vector<float, 3> transform_tie(const std::array<math::Vector4f, 4> mat,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Dump the entire tie tree to an obj. Used to debug the transform_tie function. If we get this
|
||||
* right, it should fit in with .obj's produced from the tfrag debug.
|
||||
*/
|
||||
std::string dump_full_to_obj(const std::vector<TieProtoInfo>& protos) {
|
||||
std::vector<math::Vector<float, 3>> verts;
|
||||
std::vector<math::Vector<float, 2>> tcs;
|
||||
@@ -1774,6 +1908,7 @@ struct BigPalette {
|
||||
std::vector<tfrag3::TimeOfDayColor> colors;
|
||||
};
|
||||
|
||||
// combine all individual time of day palettes into one giant one.
|
||||
BigPalette make_big_palette(std::vector<TieProtoInfo>& protos) {
|
||||
BigPalette result;
|
||||
|
||||
@@ -1800,6 +1935,9 @@ BigPalette make_big_palette(std::vector<TieProtoInfo>& protos) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Given a current draw mode, update the alpha settings from a gs-alpha register value.
|
||||
*/
|
||||
void update_mode_from_alpha1(u64 val, DrawMode& mode) {
|
||||
GsAlpha reg(val);
|
||||
if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && reg.b_mode() == GsAlpha::BlendMode::DEST &&
|
||||
@@ -1837,13 +1975,19 @@ void update_mode_from_alpha1(u64 val, DrawMode& mode) {
|
||||
fmt::print("unsupported blend: a {} b {} c {} d {}\n", (int)reg.a_mode(), (int)reg.b_mode(),
|
||||
(int)reg.c_mode(), (int)reg.d_mode());
|
||||
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
||||
// assert(false);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert adgif info into a C++ renderer DrawMode.
|
||||
*/
|
||||
DrawMode process_draw_mode(const AdgifInfo& info, bool use_atest, bool use_decal) {
|
||||
DrawMode mode;
|
||||
// some of these are set up once as part of tie initialization
|
||||
mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL);
|
||||
|
||||
// the atest giftag is set up at the end of the VU program.
|
||||
if (use_atest) {
|
||||
mode.enable_at();
|
||||
mode.set_aref(0x26);
|
||||
@@ -1855,13 +1999,17 @@ DrawMode process_draw_mode(const AdgifInfo& info, bool use_atest, bool use_decal
|
||||
if (use_decal) {
|
||||
mode.enable_decal();
|
||||
}
|
||||
// set up once.
|
||||
mode.enable_depth_write();
|
||||
mode.enable_zt(); // :zte #x1
|
||||
mode.set_depth_test(GsTest::ZTest::GEQUAL); // :ztst (gs-ztest greater-equal))
|
||||
mode.disable_ab();
|
||||
mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
||||
|
||||
// the alpha matters
|
||||
update_mode_from_alpha1(info.alpha_val, mode);
|
||||
|
||||
// the clamp matters
|
||||
if (!(info.clamp_val == 0b101 || info.clamp_val == 0 || info.clamp_val == 1 ||
|
||||
info.clamp_val == 0b100)) {
|
||||
fmt::print("clamp: 0x{:x}\n", info.clamp_val);
|
||||
@@ -1874,27 +2022,49 @@ DrawMode process_draw_mode(const AdgifInfo& info, bool use_atest, bool use_decal
|
||||
return mode;
|
||||
}
|
||||
|
||||
// we need the lev to pool textures with tfrag.
|
||||
/*!
|
||||
* Convert TieProtoInfo's to C++ renderer format
|
||||
*/
|
||||
void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
tfrag3::Level& lev,
|
||||
const TextureDB& tdb,
|
||||
const std::vector<TieProtoInfo>& protos) {
|
||||
// our current approach for static draws is just to flatten to giant mesh.
|
||||
|
||||
std::unordered_map<u32, std::vector<u32>> draws_by_tex;
|
||||
|
||||
std::unordered_map<u32, u32> interp_hack_colors;
|
||||
// our current approach for static draws is just to flatten to giant mesh, except for wind stuff.
|
||||
// this map sorts these two types of draws by texture.
|
||||
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
|
||||
std::unordered_map<u32, std::vector<u32>> wind_draws_by_tex;
|
||||
|
||||
// loop over all prototypes
|
||||
for (auto& proto : protos) {
|
||||
// bool using_wind = true; // hack, for testing
|
||||
bool using_wind = proto.stiffness != 0.f;
|
||||
|
||||
// loop over instances of the prototypes
|
||||
for (auto& inst : proto.instances) {
|
||||
// if we're using wind, we use the instanced renderer, which requires some extra info
|
||||
// and we should remember which instance ID we are.
|
||||
// Note: this is different from the game's instance index - we don't draw everything instanced
|
||||
// so the non-instanced models don't get a C++ renderer instance ID
|
||||
u32 wind_instance_idx = tree.instance_info.size();
|
||||
if (using_wind) {
|
||||
tfrag3::TieWindInstance wind_instance_info;
|
||||
wind_instance_info.wind_idx = inst.wind_index; // which wind value to apply in the table
|
||||
wind_instance_info.stiffness = proto.stiffness; // wind stiffness (how much we move)
|
||||
wind_instance_info.matrix = inst.mat; // instance transformation matrix.
|
||||
tree.instance_info.push_back(wind_instance_info);
|
||||
}
|
||||
|
||||
// loop over fragments of the prototype
|
||||
for (size_t frag_idx = 0; frag_idx < proto.frags.size(); frag_idx++) {
|
||||
auto& frag = proto.frags[frag_idx];
|
||||
auto& ifrag = inst.frags.at(frag_idx);
|
||||
auto& frag = proto.frags[frag_idx]; // shared info for all instances of this frag
|
||||
auto& ifrag = inst.frags.at(frag_idx); // color info for this instance of the frag
|
||||
// loop over triangle strips within the fragment
|
||||
for (auto& strip : frag.strips) {
|
||||
// what texture are we using?
|
||||
u32 combo_tex = strip.adgif.combo_tex;
|
||||
|
||||
// try looking it up in the existing textures
|
||||
// try looking it up in the existing textures that we have in the C++ renderer data.
|
||||
// (this is shared with tfrag)
|
||||
u32 idx_in_lev_data = UINT32_MAX;
|
||||
for (u32 i = 0; i < lev.textures.size(); i++) {
|
||||
if (lev.textures[i].combo_id == combo_tex) {
|
||||
@@ -1904,10 +2074,10 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
}
|
||||
|
||||
if (idx_in_lev_data == UINT32_MAX) {
|
||||
// didn't find it, have to add a new one
|
||||
// didn't find it, have to add a new one texture.
|
||||
auto tex_it = tdb.textures.find(combo_tex);
|
||||
if (tex_it == tdb.textures.end()) {
|
||||
bool ok_to_miss = false; // TODO
|
||||
bool ok_to_miss = false; // for TIE, there's no missing textures.
|
||||
if (ok_to_miss) {
|
||||
// we're missing a texture, just use the first one.
|
||||
tex_it = tdb.textures.begin();
|
||||
@@ -1922,6 +2092,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
// add a new texture to the level data
|
||||
idx_in_lev_data = lev.textures.size();
|
||||
lev.textures.emplace_back();
|
||||
auto& new_tex = lev.textures.back();
|
||||
@@ -1937,68 +2108,162 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
DrawMode mode =
|
||||
process_draw_mode(strip.adgif, frag.prog_info.misc_x == 0, frag.has_magic_tex0_bit);
|
||||
|
||||
// okay, we now have a texture and draw mode, let's see if we can add to an existing...
|
||||
auto existing_draws_in_tex = draws_by_tex.find(idx_in_lev_data);
|
||||
tfrag3::StripDraw* draw_to_add_to = nullptr;
|
||||
if (existing_draws_in_tex != draws_by_tex.end()) {
|
||||
for (auto idx : existing_draws_in_tex->second) {
|
||||
if (tree.static_draws.at(idx).mode == mode) {
|
||||
draw_to_add_to = &tree.static_draws[idx];
|
||||
if (using_wind) {
|
||||
// okay, we now have a texture and draw mode, let's see if we can add to an existing...
|
||||
auto existing_draws_in_tex = wind_draws_by_tex.find(idx_in_lev_data);
|
||||
tfrag3::InstancedStripDraw* draw_to_add_to = nullptr;
|
||||
if (existing_draws_in_tex != wind_draws_by_tex.end()) {
|
||||
for (auto idx : existing_draws_in_tex->second) {
|
||||
if (tree.instanced_wind_draws.at(idx).mode == mode) {
|
||||
draw_to_add_to = &tree.instanced_wind_draws[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!draw_to_add_to) {
|
||||
// nope, need to create a new draw
|
||||
tree.static_draws.emplace_back();
|
||||
draws_by_tex[idx_in_lev_data].push_back(tree.static_draws.size() - 1);
|
||||
draw_to_add_to = &tree.static_draws.back();
|
||||
draw_to_add_to->mode = mode;
|
||||
draw_to_add_to->tree_tex_id = idx_in_lev_data;
|
||||
}
|
||||
|
||||
// now we have a draw, time to add vertices
|
||||
tfrag3::StripDraw::VisGroup vgroup;
|
||||
vgroup.vis_idx = inst.vis_id; // associate with the tfrag for culling
|
||||
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
|
||||
draw_to_add_to->num_triangles += strip.verts.size() - 2;
|
||||
for (auto& vert : strip.verts) {
|
||||
tfrag3::PreloadedVertex vtx;
|
||||
// todo fields
|
||||
auto tf = transform_tie(inst.mat, vert.pos);
|
||||
vtx.x = tf.x();
|
||||
vtx.y = tf.y();
|
||||
vtx.z = tf.z();
|
||||
vtx.s = vert.tex.x();
|
||||
vtx.t = vert.tex.y();
|
||||
vtx.q = vert.tex.z();
|
||||
// if this is true, we can remove a divide in the shader
|
||||
assert(vtx.q == 1.f);
|
||||
if (vert.color_index_index == UINT32_MAX) {
|
||||
vtx.color_index = 0;
|
||||
} else {
|
||||
vtx.color_index = ifrag.color_indices.at(vert.color_index_index);
|
||||
assert(vert.color_index_index < ifrag.color_indices.size());
|
||||
vtx.color_index += ifrag.color_index_offset_in_big_palette;
|
||||
if (!draw_to_add_to) {
|
||||
// nope no existing draw for these settings, need to create a new draw
|
||||
tree.instanced_wind_draws.emplace_back();
|
||||
wind_draws_by_tex[idx_in_lev_data].push_back(tree.instanced_wind_draws.size() - 1);
|
||||
draw_to_add_to = &tree.instanced_wind_draws.back();
|
||||
draw_to_add_to->mode = mode;
|
||||
draw_to_add_to->tree_tex_id = idx_in_lev_data;
|
||||
}
|
||||
|
||||
size_t vert_idx = tree.vertices.size();
|
||||
tree.vertices.push_back(vtx);
|
||||
draw_to_add_to->vertex_index_stream.push_back(vert_idx);
|
||||
// now we have a draw, time to add vertices. We make a vertex "group" which is a group
|
||||
// of vertices that the renderer can decide to not draw based on visibility data.
|
||||
tfrag3::InstancedStripDraw::InstanceGroup igroup;
|
||||
// needs to be associated with this instance.
|
||||
igroup.vis_idx = inst.vis_id; // associate with the instance for culling
|
||||
// number of vertices. The +1 is for the primitive restart index, which tells opengl
|
||||
// that the triangle strip is done.
|
||||
igroup.num = strip.verts.size() + 1;
|
||||
// groups for instances also need the instance idx to grab the appropriate wind/matrix
|
||||
// data.
|
||||
igroup.instance_idx = wind_instance_idx;
|
||||
draw_to_add_to->num_triangles += strip.verts.size() - 2;
|
||||
// note: this is a bit wasteful to duplicate the xyz/stq.
|
||||
for (auto& vert : strip.verts) {
|
||||
tfrag3::PreloadedVertex vtx;
|
||||
vtx.x = vert.pos.x();
|
||||
vtx.y = vert.pos.y();
|
||||
vtx.z = vert.pos.z();
|
||||
vtx.s = vert.tex.x();
|
||||
vtx.t = vert.tex.y();
|
||||
vtx.q = vert.tex.z();
|
||||
// if this is true, we can remove a divide in the shader
|
||||
assert(vtx.q == 1.f);
|
||||
if (vert.color_index_index == UINT32_MAX) {
|
||||
vtx.color_index = 0;
|
||||
} else {
|
||||
vtx.color_index = ifrag.color_indices.at(vert.color_index_index);
|
||||
assert(vert.color_index_index < ifrag.color_indices.size());
|
||||
vtx.color_index += ifrag.color_index_offset_in_big_palette;
|
||||
}
|
||||
|
||||
size_t vert_idx = tree.vertices.size();
|
||||
tree.vertices.push_back(vtx);
|
||||
draw_to_add_to->vertex_index_stream.push_back(vert_idx);
|
||||
}
|
||||
// the primitive restart index
|
||||
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
|
||||
draw_to_add_to->instance_groups.push_back(igroup);
|
||||
} else {
|
||||
// okay, we now have a texture and draw mode, let's see if we can add to an existing...
|
||||
auto existing_draws_in_tex = static_draws_by_tex.find(idx_in_lev_data);
|
||||
tfrag3::StripDraw* draw_to_add_to = nullptr;
|
||||
if (existing_draws_in_tex != static_draws_by_tex.end()) {
|
||||
for (auto idx : existing_draws_in_tex->second) {
|
||||
if (tree.static_draws.at(idx).mode == mode) {
|
||||
draw_to_add_to = &tree.static_draws[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!draw_to_add_to) {
|
||||
// nope, need to create a new draw
|
||||
tree.static_draws.emplace_back();
|
||||
static_draws_by_tex[idx_in_lev_data].push_back(tree.static_draws.size() - 1);
|
||||
draw_to_add_to = &tree.static_draws.back();
|
||||
draw_to_add_to->mode = mode;
|
||||
draw_to_add_to->tree_tex_id = idx_in_lev_data;
|
||||
}
|
||||
|
||||
// now we have a draw, time to add vertices
|
||||
tfrag3::StripDraw::VisGroup vgroup;
|
||||
vgroup.vis_idx_in_pc_bvh = inst.vis_id; // associate with the instance for culling
|
||||
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
|
||||
draw_to_add_to->num_triangles += strip.verts.size() - 2;
|
||||
for (auto& vert : strip.verts) {
|
||||
tfrag3::PreloadedVertex vtx;
|
||||
// todo fields
|
||||
auto tf = transform_tie(inst.mat, vert.pos);
|
||||
vtx.x = tf.x();
|
||||
vtx.y = tf.y();
|
||||
vtx.z = tf.z();
|
||||
vtx.s = vert.tex.x();
|
||||
vtx.t = vert.tex.y();
|
||||
vtx.q = vert.tex.z();
|
||||
// if this is true, we can remove a divide in the shader
|
||||
assert(vtx.q == 1.f);
|
||||
if (vert.color_index_index == UINT32_MAX) {
|
||||
vtx.color_index = 0;
|
||||
} else {
|
||||
vtx.color_index = ifrag.color_indices.at(vert.color_index_index);
|
||||
assert(vert.color_index_index < ifrag.color_indices.size());
|
||||
vtx.color_index += ifrag.color_index_offset_in_big_palette;
|
||||
}
|
||||
|
||||
size_t vert_idx = tree.vertices.size();
|
||||
tree.vertices.push_back(vtx);
|
||||
draw_to_add_to->vertex_index_stream.push_back(vert_idx);
|
||||
}
|
||||
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
|
||||
draw_to_add_to->vis_groups.push_back(vgroup);
|
||||
}
|
||||
draw_to_add_to->vertex_index_stream.push_back(UINT32_MAX);
|
||||
draw_to_add_to->vis_groups.push_back(vgroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort draws by texture. no idea if this really matters, but will reduce the number of
|
||||
// times the renderer changes textures. it at least makes the rendererdoc debugging easier.
|
||||
std::stable_sort(tree.static_draws.begin(), tree.static_draws.end(),
|
||||
[](const tfrag3::StripDraw& a, const tfrag3::StripDraw& b) {
|
||||
return a.tree_tex_id < b.tree_tex_id;
|
||||
});
|
||||
}
|
||||
|
||||
/*!
|
||||
* The groups are created per-fragment, but usually you have a few fragments per instance, so there
|
||||
* are often consecutive groups that can be merged.
|
||||
*/
|
||||
void merge_groups(std::vector<tfrag3::InstancedStripDraw::InstanceGroup>& grps) {
|
||||
std::vector<tfrag3::InstancedStripDraw::InstanceGroup> result;
|
||||
result.push_back(grps.at(0));
|
||||
for (size_t i = 1; i < grps.size(); i++) {
|
||||
if (grps[i].vis_idx == result.back().vis_idx &&
|
||||
grps[i].instance_idx == result.back().instance_idx) {
|
||||
result.back().num += grps[i].num;
|
||||
} else {
|
||||
result.push_back(grps[i]);
|
||||
}
|
||||
}
|
||||
std::swap(result, grps);
|
||||
}
|
||||
|
||||
void merge_groups(std::vector<tfrag3::StripDraw::VisGroup>& grps) {
|
||||
std::vector<tfrag3::StripDraw::VisGroup> result;
|
||||
result.push_back(grps.at(0));
|
||||
for (size_t i = 1; i < grps.size(); i++) {
|
||||
if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh) {
|
||||
result.back().num += grps[i].num;
|
||||
} else {
|
||||
result.push_back(grps[i]);
|
||||
}
|
||||
}
|
||||
std::swap(result, grps);
|
||||
}
|
||||
|
||||
void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
const std::string& debug_name,
|
||||
const std::vector<level_tools::TextureRemap>& tex_map,
|
||||
@@ -2028,7 +2293,9 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
// parent of between 1 and 8 instances.
|
||||
extract_vis_data(tree, as_instance_array->instances.front().id, this_tree);
|
||||
|
||||
// map of instance ID to its parent. We'll need this later.
|
||||
// we use the index of the instance in the instance list as its index. But this is different
|
||||
// from its visibility index. This map goes from instance index to the parent node in the vis
|
||||
// tree. later, we can use this to remap from instance idx to the visiblity node index.
|
||||
std::unordered_map<int, int> instance_parents;
|
||||
for (size_t node_idx = 0; node_idx < this_tree.bvh.vis_nodes.size(); node_idx++) {
|
||||
const auto& node = this_tree.bvh.vis_nodes[node_idx];
|
||||
@@ -2039,31 +2306,49 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
}
|
||||
}
|
||||
|
||||
// convert level format data to a nicer format
|
||||
auto info = collect_instance_info(as_instance_array, &tree->prototypes.prototype_array_tie.data);
|
||||
update_proto_info(&info, tex_map, tex_db, tree->prototypes.prototype_array_tie.data);
|
||||
// debug_print_info(info);
|
||||
check_wind_vectors_zero(info, tree->prototypes.wind_vectors);
|
||||
// determine draws from VU program
|
||||
emulate_tie_prototype_program(info);
|
||||
emulate_tie_instance_program(info);
|
||||
emulate_kicks(info);
|
||||
|
||||
// debug save to .obj
|
||||
if (dump_level) {
|
||||
auto dir = file_util::get_file_path({fmt::format("debug_out/tie-{}/", debug_name)});
|
||||
file_util::create_dir_if_needed(dir);
|
||||
for (auto& proto : info) {
|
||||
auto data = debug_dump_proto_to_obj(proto);
|
||||
file_util::write_text_file(fmt::format("{}/{}.obj", dir, proto.name), data);
|
||||
// file_util::create_dir_if_needed()
|
||||
}
|
||||
|
||||
auto full = dump_full_to_obj(info);
|
||||
file_util::write_text_file(fmt::format("{}/ALL.obj", dir), full);
|
||||
}
|
||||
|
||||
// create time of day data.
|
||||
auto full_palette = make_big_palette(info);
|
||||
|
||||
// create draws
|
||||
add_vertices_and_static_draw(this_tree, out, tex_db, info);
|
||||
|
||||
// remap vis indices and merge
|
||||
for (auto& draw : this_tree.static_draws) {
|
||||
for (auto& str : draw.vis_groups) {
|
||||
auto it = instance_parents.find(str.vis_idx_in_pc_bvh);
|
||||
if (it == instance_parents.end()) {
|
||||
str.vis_idx_in_pc_bvh = UINT32_MAX;
|
||||
} else {
|
||||
str.vis_idx_in_pc_bvh = it->second;
|
||||
}
|
||||
}
|
||||
merge_groups(draw.vis_groups);
|
||||
}
|
||||
|
||||
for (auto& draw : this_tree.instanced_wind_draws) {
|
||||
for (auto& str : draw.instance_groups) {
|
||||
auto it = instance_parents.find(str.vis_idx);
|
||||
if (it == instance_parents.end()) {
|
||||
str.vis_idx = UINT32_MAX;
|
||||
@@ -2071,6 +2356,8 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
str.vis_idx = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
merge_groups(draw.instance_groups);
|
||||
}
|
||||
|
||||
this_tree.colors = full_palette.colors;
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ int main(int argc, char** argv) {
|
||||
db.generate_dgo_listing());
|
||||
// write out object file map (used for future decompilations, if desired)
|
||||
file_util::write_text_file(file_util::combine_path(out_folder, "obj.txt"),
|
||||
db.generate_obj_listing());
|
||||
db.generate_obj_listing(config.merged_objects));
|
||||
|
||||
// dump raw objs
|
||||
if (config.dump_objs) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <stdexcept>
|
||||
#include "common/util/assert.h"
|
||||
#include "DataParser.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
/*
|
||||
* Allowable lines:
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "common/util/assert.h"
|
||||
#include <stdexcept>
|
||||
#include "common/log/log.h"
|
||||
#include "common/type_system/TypeSpec.h"
|
||||
#include "common/common_types.h"
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
#include "common/util/assert.h"
|
||||
|
||||
namespace decompiler {
|
||||
/*!
|
||||
|
||||
@@ -336,8 +336,9 @@ goos::Object decomp_ref_to_inline_array_guess_size(
|
||||
|
||||
// verify the stride matches the type system
|
||||
auto elt_type_info = ts.lookup_type(array_elt_type);
|
||||
assert(stride == align(elt_type_info->get_size_in_memory(),
|
||||
elt_type_info->get_inline_array_stride_alignment()));
|
||||
int ye = align(elt_type_info->get_size_in_memory(),
|
||||
elt_type_info->get_inline_array_stride_alignment());
|
||||
assert(stride == ye);
|
||||
|
||||
// the input is the location of the data field.
|
||||
// we expect that to be a label:
|
||||
@@ -450,6 +451,39 @@ goos::Object sp_field_init_spec_decompile(const std::vector<LinkedWord>& words,
|
||||
file, TypeSpec("sp-field-init-spec"), 16);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_vertex_arr_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("nav-vertex"), 16);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_poly_arr_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("nav-poly"), 8);
|
||||
}
|
||||
|
||||
goos::Object nav_mesh_route_arr_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
int field_location,
|
||||
const TypeSystem& ts,
|
||||
const std::vector<std::vector<LinkedWord>>& all_words,
|
||||
const LinkedObjectFile* file) {
|
||||
return decomp_ref_to_inline_array_guess_size(words, labels, my_seg, field_location, ts, all_words,
|
||||
file, TypeSpec("vector4ub"), 4);
|
||||
}
|
||||
|
||||
goos::Object sp_launch_grp_launcher_decompile(const std::vector<LinkedWord>& words,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
int my_seg,
|
||||
@@ -676,6 +710,18 @@ goos::Object decompile_structure(const TypeSpec& type,
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), sp_field_init_spec_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file));
|
||||
} else if (field.name() == "vertex" && type.print() == "nav-mesh") {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), nav_mesh_vertex_arr_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file));
|
||||
} else if (field.name() == "poly" && type.print() == "nav-mesh") {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), nav_mesh_poly_arr_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file));
|
||||
} else if (field.name() == "route" && type.print() == "nav-mesh") {
|
||||
field_defs_out.emplace_back(
|
||||
field.name(), nav_mesh_route_arr_decompile(obj_words, labels, label.target_segment,
|
||||
field_start, ts, words, file));
|
||||
} else if (field.name() == "launcher" && type.print() == "sparticle-launch-group") {
|
||||
field_defs_out.emplace_back(field.name(), sp_launch_grp_launcher_decompile(
|
||||
obj_words, labels, label.target_segment,
|
||||
|
||||
@@ -104,6 +104,7 @@ enum class FieldKind {
|
||||
FUNCTION,
|
||||
USERDATA,
|
||||
ROT_X,
|
||||
SOUND_SPEC,
|
||||
INVALID
|
||||
};
|
||||
|
||||
@@ -120,12 +121,12 @@ const SparticleFieldDecomp field_kinds[68] = {
|
||||
{true, FieldKind::FUNCTION}, // SPT_BIRTH_FUNC = 4
|
||||
{false}, // SPT_JOINT/REFPOINT = 5
|
||||
{true, FieldKind::FLOAT_WITH_RAND}, // SPT_NUM = 6
|
||||
{true, FieldKind::NO_FANCY_DECOMP}, // SPT_SOUND = 7
|
||||
{true, FieldKind::SOUND_SPEC}, // SPT_SOUND = 7
|
||||
{false}, // MISC_FIELDS_END = 8
|
||||
{false}, // SPRITE_FIELDS_START = 9
|
||||
{true, FieldKind::METER_WITH_RAND}, // SPT_X = 10
|
||||
{true, FieldKind::METER_WITH_RAND}, // SPT_Y = 11
|
||||
{true, FieldKind::FLOAT_WITH_RAND}, // SPT_Z = 12
|
||||
{true, FieldKind::METER_WITH_RAND}, // SPT_Z = 12
|
||||
{true, FieldKind::METER_WITH_RAND}, // SPT_SCALE_X = 13
|
||||
{true, FieldKind::ROT_X}, // SPT_ROT_X = 14
|
||||
{true, FieldKind::DEGREES_WITH_RAND}, // SPT_ROT_Y = 15
|
||||
@@ -386,10 +387,10 @@ goos::Object decompile_sparticle_float_meters_with_rand_init(const std::vector<L
|
||||
const std::string& field_name,
|
||||
const std::string& flag_name) {
|
||||
if (flag_name == "int-with-rand") {
|
||||
return pretty_print::to_symbol(
|
||||
fmt::format("(sp-rnd-int-flt {} (meters {}) {} {})", field_name,
|
||||
float_to_string(word_as_float(words.at(1)) / METER_LENGTH),
|
||||
word_as_s32(words.at(2)), float_to_string(word_as_float(words.at(3)))));
|
||||
return pretty_print::to_symbol(fmt::format("(sp-rnd-int-flt {} (meters {}) {} {})", field_name,
|
||||
meters_to_string(word_as_float(words.at(1))),
|
||||
word_as_s32(words.at(2)),
|
||||
float_to_string(word_as_float(words.at(3)))));
|
||||
}
|
||||
assert(flag_name == "float-with-rand");
|
||||
|
||||
@@ -397,15 +398,13 @@ goos::Object decompile_sparticle_float_meters_with_rand_init(const std::vector<L
|
||||
float mult = word_as_float(words.at(3));
|
||||
|
||||
if (range == 0.f && mult == 1.f) {
|
||||
return pretty_print::to_symbol(
|
||||
fmt::format("(sp-flt {} (meters {}))", field_name,
|
||||
float_to_string(word_as_float(words.at(1)) / METER_LENGTH)));
|
||||
return pretty_print::to_symbol(fmt::format("(sp-flt {} (meters {}))", field_name,
|
||||
meters_to_string(word_as_float(words.at(1)))));
|
||||
} else {
|
||||
return pretty_print::to_symbol(
|
||||
fmt::format("(sp-rnd-flt {} (meters {}) (meters {}) {})", field_name,
|
||||
float_to_string(word_as_float(words.at(1)) / METER_LENGTH),
|
||||
float_to_string(word_as_float(words.at(2)) / METER_LENGTH),
|
||||
float_to_string(word_as_float(words.at(3)))));
|
||||
return pretty_print::to_symbol(fmt::format(
|
||||
"(sp-rnd-flt {} (meters {}) (meters {}) {})", field_name,
|
||||
meters_to_string(word_as_float(words.at(1))), meters_to_string(word_as_float(words.at(2))),
|
||||
float_to_string(word_as_float(words.at(3)))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,6 +433,15 @@ goos::Object decompile_sparticle_float_degrees_with_rand_init(const std::vector<
|
||||
}
|
||||
}
|
||||
|
||||
goos::Object decompile_sparticle_sound_spec(const std::vector<LinkedWord>& /*words*/,
|
||||
const std::string& field_name,
|
||||
const std::string& flag_name,
|
||||
const goos::Object& original) {
|
||||
assert(field_name == "spt-sound");
|
||||
assert(flag_name == "plain-v2");
|
||||
return pretty_print::build_list("sp-sound", original);
|
||||
}
|
||||
|
||||
goos::Object decompile_sparticle_group_item(const TypeSpec& type,
|
||||
const DecompilerLabel& label,
|
||||
const std::vector<DecompilerLabel>& labels,
|
||||
@@ -466,8 +474,8 @@ goos::Object decompile_sparticle_group_item(const TypeSpec& type,
|
||||
// binding
|
||||
|
||||
s32 launcher = word_as_s32(obj_words.at(0));
|
||||
float fade_after_meters = word_as_float(obj_words.at(1)) / METER_LENGTH;
|
||||
float falloff_to_meters = word_as_float(obj_words.at(2)) / METER_LENGTH;
|
||||
float fade_after = word_as_float(obj_words.at(1));
|
||||
float falloff_to = word_as_float(obj_words.at(2));
|
||||
u32 fp = word_as_s32(obj_words.at(3));
|
||||
u16 flags = fp & 0xffff;
|
||||
u16 period = fp >> 16;
|
||||
@@ -480,12 +488,12 @@ goos::Object decompile_sparticle_group_item(const TypeSpec& type,
|
||||
std::string result =
|
||||
fmt::format("(sp-item {}", launcher); // use decimal, so it matches array idx
|
||||
|
||||
if (fade_after_meters != 0.0) {
|
||||
result += fmt::format(" :fade-after (meters {})", float_to_string(fade_after_meters));
|
||||
if (fade_after != 0.0) {
|
||||
result += fmt::format(" :fade-after (meters {})", meters_to_string(fade_after));
|
||||
}
|
||||
|
||||
if (falloff_to_meters != 0.0) {
|
||||
result += fmt::format(" :falloff-to (meters {})", float_to_string(falloff_to_meters));
|
||||
if (falloff_to != 0.0) {
|
||||
result += fmt::format(" :falloff-to (meters {})", meters_to_string(falloff_to));
|
||||
}
|
||||
|
||||
if (flags) {
|
||||
@@ -595,6 +603,7 @@ goos::Object decompile_sparticle_field_init(const TypeSpec& type,
|
||||
case FieldKind::LAUNCHER_BY_ID:
|
||||
result = decompile_sparticle_launcher_by_id(obj_words, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::SOUND_SPEC:
|
||||
case FieldKind::NO_FANCY_DECOMP:
|
||||
result = normal;
|
||||
break;
|
||||
@@ -615,6 +624,91 @@ goos::Object decompile_sparticle_field_init(const TypeSpec& type,
|
||||
// fmt::print("Result: {}\n\n", result.print());
|
||||
return result;
|
||||
}
|
||||
|
||||
goos::Object decompile_sparticle_userdata_assert(const std::vector<LinkedWord>& words,
|
||||
const std::string& field_name,
|
||||
const std::string& flag_name) {
|
||||
if (flag_name == "int-with-rand" || flag_name == "float-with-rand") {
|
||||
return decompile_sparticle_float_with_rand_init(words, field_name, flag_name);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
goos::Object decompile_sparticle_field_init(const DefpartElement::StaticInfo::PartField& field,
|
||||
const TypeSystem& ts) {
|
||||
auto field_id = field.field_id;
|
||||
auto flags = field.flags;
|
||||
|
||||
assert(field_id <= (u32)FieldId::SPT_END);
|
||||
auto field_name = decompile_int_enum_from_int(TypeSpec("sp-field-id"), ts, field_id);
|
||||
const auto& field_info = field_kinds[field_id];
|
||||
if (!field_info.known) {
|
||||
throw std::runtime_error("Unknown sparticle field: " + field_name);
|
||||
}
|
||||
|
||||
auto flag_name = decompile_int_enum_from_int(TypeSpec("sp-flag"), ts, flags);
|
||||
goos::Object result;
|
||||
|
||||
if (flag_name == "copy-from-other-field") {
|
||||
result = decompile_sparticle_from_other(field.data, field_name, flag_name);
|
||||
} else {
|
||||
switch (field_info.kind) {
|
||||
case FieldKind::TEXTURE_ID:
|
||||
result = decompile_sparticle_tex_field_init(field.data, ts, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::FLOAT_WITH_RAND:
|
||||
result = decompile_sparticle_float_with_rand_init(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::METER_WITH_RAND:
|
||||
result = decompile_sparticle_float_meters_with_rand_init(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::DEGREES_WITH_RAND:
|
||||
result =
|
||||
decompile_sparticle_float_degrees_with_rand_init(field.data, field_name, flag_name);
|
||||
break;
|
||||
// case FieldKind::INT_WITH_RAND:
|
||||
// result = decompile_sparticle_int_with_rand_init(field.data, field_name,
|
||||
// flag_name); break;
|
||||
case FieldKind::PLAIN_INT_WITH_RANDS:
|
||||
result = decompile_sparticle_int_with_rand_init(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::PLAIN_INT:
|
||||
result = decompile_sparticle_int_init(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::CPUINFO_FLAGS:
|
||||
result = decompile_sparticle_flags(field.data, ts, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::END_FLAG:
|
||||
result = decompile_sparticle_end(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::LAUNCHER_BY_ID:
|
||||
result = decompile_sparticle_launcher_by_id(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::NO_FANCY_DECOMP:
|
||||
assert(false);
|
||||
break;
|
||||
case FieldKind::FUNCTION:
|
||||
result = decompile_sparticle_func(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::USERDATA:
|
||||
result = decompile_sparticle_userdata_assert(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::ROT_X:
|
||||
result = decompile_sparticle_rot_x(field.data, field_name, flag_name);
|
||||
break;
|
||||
case FieldKind::SOUND_SPEC:
|
||||
result =
|
||||
decompile_sparticle_sound_spec(field.data, field_name, flag_name, field.sound_spec);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
// fmt::print("Result: {}\n\n", result.print());
|
||||
return result;
|
||||
}
|
||||
} // namespace decompiler
|
||||
|
||||
/*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user