mirror of
https://github.com/open-goal/jak-project.git
synced 2026-11-07 09:26:09 -10:00
Compare commits
129
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48cb9bb787 | ||
|
|
d5590ab638 | ||
|
|
710f3ac117 | ||
|
|
23b86d95c3 | ||
|
|
7348e6a4ff | ||
|
|
98d6618a8b | ||
|
|
3ee2b4423c | ||
|
|
341f6117d5 | ||
|
|
ee0600cdbf | ||
|
|
a29fca982b | ||
|
|
9c9af5b488 | ||
|
|
f6fad0630f | ||
|
|
434484e5b5 | ||
|
|
6f093f98ff | ||
|
|
e836f09212 | ||
|
|
f883b075fd | ||
|
|
fe648ac7c5 | ||
|
|
b2c163999d | ||
|
|
79e4e36878 | ||
|
|
e30dc9ecc7 | ||
|
|
e0acc2d15f | ||
|
|
2b226fedea | ||
|
|
266b423efa | ||
|
|
ea61985e21 | ||
|
|
e5a35f6ba0 | ||
|
|
d81b60736a | ||
|
|
0e55ff6108 | ||
|
|
0e5aed329e | ||
|
|
a3e8f0f91a | ||
|
|
b3cdcf3a67 | ||
|
|
0edb88dc69 | ||
|
|
c476b84182 | ||
|
|
5458d865d4 | ||
|
|
51d008f9ab | ||
|
|
a2f9d36332 | ||
|
|
6e4e5d2bf7 | ||
|
|
1029516f6d | ||
|
|
8690104ba0 | ||
|
|
e18dbb6256 | ||
|
|
477cefb6a5 | ||
|
|
8feb46dc45 | ||
|
|
620168c45a | ||
|
|
4c2e1a8a90 | ||
|
|
ef719d2ab7 | ||
|
|
7848ba05b8 | ||
|
|
f6c55eba9f | ||
|
|
6a06291e6e | ||
|
|
9b393e2ddb | ||
|
|
3f7aca3c72 | ||
|
|
c263bc2114 | ||
|
|
2ff49b9905 | ||
|
|
8f445bda3e | ||
|
|
24ad5515f8 | ||
|
|
7543acfb8a | ||
|
|
5e3cb8faa6 | ||
|
|
321a113dd7 | ||
|
|
63676c70a5 | ||
|
|
2c6d41c87a | ||
|
|
2a41bc615e | ||
|
|
7553877e57 | ||
|
|
af5cb9b1cb | ||
|
|
b55a918902 | ||
|
|
f8058f2138 | ||
|
|
e3efede029 | ||
|
|
4604636593 | ||
|
|
8930141b72 | ||
|
|
1e530714b7 | ||
|
|
cbb8add81c | ||
|
|
10d7dabfd7 | ||
|
|
ba9085fee0 | ||
|
|
5e8ea23c30 | ||
|
|
2f0a90b693 | ||
|
|
348bf83b89 | ||
|
|
dff9ac163a | ||
|
|
1962fbfb51 | ||
|
|
5bc61c5854 | ||
|
|
510b23163f | ||
|
|
cb51bd3f5b | ||
|
|
e76a4399e5 | ||
|
|
e144406c16 | ||
|
|
d82b6209b6 | ||
|
|
eac11b5b93 | ||
|
|
a6680cc26d | ||
|
|
7dbacc72d3 | ||
|
|
b50652ce54 | ||
|
|
c623190bff | ||
|
|
a7a7110550 | ||
|
|
10008caad1 | ||
|
|
452f1329dd | ||
|
|
b8c77c65f5 | ||
|
|
eb544bcfc0 | ||
|
|
cb4f7772bb | ||
|
|
03cae68c7d | ||
|
|
6b7dd7ae22 | ||
|
|
07c224b966 | ||
|
|
66c455225d | ||
|
|
5b8bb8fe23 | ||
|
|
614c5a663c | ||
|
|
fedfb6fd09 | ||
|
|
7de5eb9fc0 | ||
|
|
f60a155c0f | ||
|
|
4e33746634 | ||
|
|
58467c50fc | ||
|
|
b6f25bf6d6 | ||
|
|
8d9966fd2c | ||
|
|
fe29eae395 | ||
|
|
431508aab1 | ||
|
|
69d879f901 | ||
|
|
d82bb3fde8 | ||
|
|
a39af394fb | ||
|
|
7053090541 | ||
|
|
bc66d416b4 | ||
|
|
d46e9fb8bb | ||
|
|
ebd02b28a4 | ||
|
|
4fd0a57046 | ||
|
|
7b7885e7a8 | ||
|
|
8c71827974 | ||
|
|
6c63a396c0 | ||
|
|
8a6348594a | ||
|
|
4c10b42841 | ||
|
|
9426683ae5 | ||
|
|
f2e7606f1b | ||
|
|
b0cd59e6ba | ||
|
|
9d2a23effe | ||
|
|
1ba3fa7cda | ||
|
|
a7d1336899 | ||
|
|
879f8cb5a2 | ||
|
|
8b7e0bde53 | ||
|
|
a13b0dce45 |
No files matched your search
@@ -1,6 +1,7 @@
|
||||
name: "\U0001F41B Jak 1 Bug Report"
|
||||
description: Create a bug report for Jak 1.
|
||||
labels: ["bug", "jak1"]
|
||||
labels: ["jak1"]
|
||||
type: 'bug'
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
name: "\U0001F41B Jak 2 Bug Report"
|
||||
description: Create a bug report for Jak 2.
|
||||
labels: ["bug", "jak2"]
|
||||
labels: ["jak2"]
|
||||
type: 'bug'
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"3990": {
|
||||
"msg": "Provided invalid or missing arguments"
|
||||
},
|
||||
"3991": {
|
||||
"msg": "Input path(s) do not exist"
|
||||
},
|
||||
"4000": {
|
||||
"msg": "Validation Failed: Cannot locate ELF"
|
||||
},
|
||||
|
||||
@@ -49,14 +49,12 @@ jobs:
|
||||
name: "🍎 MacOS"
|
||||
uses: ./.github/workflows/macos-build.yaml
|
||||
with:
|
||||
cmakePreset: "Release-macos-clang"
|
||||
cmakePreset: "Release-macos-x86_64-clang"
|
||||
cachePrefix: ""
|
||||
|
||||
# Q4 2023 there will hopefully be native arm64 runners
|
||||
# https://github.com/github/roadmap/issues/528
|
||||
# build_macos_arm:
|
||||
# name: "🍎 MacOS"
|
||||
# uses: ./.github/workflows/macos-build-arm.yaml
|
||||
# with:
|
||||
# cmakePreset: "Release-macos-clang"
|
||||
# cachePrefix: ""
|
||||
build_macos_arm:
|
||||
name: "🍎 MacOS"
|
||||
uses: ./.github/workflows/macos-build-arm.yaml
|
||||
with:
|
||||
cmakePreset: "Release-macos-x86_64-clang"
|
||||
cachePrefix: ""
|
||||
@@ -0,0 +1,98 @@
|
||||
name: Compilation Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Compare
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: master
|
||||
|
||||
- name: Install Package Dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install build-essential cmake \
|
||||
clang gcc g++ lcov make nasm libxrandr-dev \
|
||||
libxinerama-dev libxcursor-dev libpulse-dev \
|
||||
libxi-dev zip ninja-build libgl1-mesa-dev libssl-dev
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]
|
||||
with:
|
||||
variant: sccache
|
||||
key: linux-ubuntu-20.04--Release-linux-clang-static-${{ github.sha }}
|
||||
restore-keys: linux-ubuntu-20.04--Release-linux-clang-static
|
||||
max-size: 1000M
|
||||
|
||||
- name: CMake Generation (master)
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
run: |
|
||||
cmake -B build --preset=Release-linux-clang-static \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
|
||||
|
||||
- name: Build goalc (master)
|
||||
run: |
|
||||
cmake --build build --parallel $((`nproc`)) --target goalc
|
||||
mv ./build ./build.master
|
||||
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
clean: "false"
|
||||
|
||||
- name: CMake Generation (PR)
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
run: |
|
||||
cmake -B build --preset=Release-linux-clang-static \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
|
||||
|
||||
- name: Build goalc (PR)
|
||||
run: cmake --build build --parallel $((`nproc`)) --target goalc
|
||||
|
||||
- name: Compile and preserve (master)
|
||||
run: |
|
||||
./build.master/goalc/goalc --game jak1 --cmd "(make-group \"all-code\")"
|
||||
./build.master/goalc/goalc --game jak2 --cmd "(make-group \"all-code\")"
|
||||
./build.master/goalc/goalc --game jak3 --cmd "(make-group \"all-code\")"
|
||||
mv ./out/jak1/obj ./out/jak1/obj.master
|
||||
mv ./out/jak2/obj ./out/jak2/obj.master
|
||||
mv ./out/jak3/obj ./out/jak3/obj.master
|
||||
|
||||
- name: Compile and preserve (PR)
|
||||
run: |
|
||||
./build/goalc/goalc --game jak1 --cmd "(make-group \"all-code\")"
|
||||
./build/goalc/goalc --game jak2 --cmd "(make-group \"all-code\")"
|
||||
./build/goalc/goalc --game jak3 --cmd "(make-group \"all-code\")"
|
||||
mv ./out/jak1/obj ./out/jak1/obj.pr
|
||||
mv ./out/jak2/obj ./out/jak2/obj.pr
|
||||
mv ./out/jak3/obj ./out/jak3/obj.pr
|
||||
|
||||
- name: Compare Results and Produce Report
|
||||
run: |
|
||||
ls -l ./out/jak1
|
||||
ls -l ./out/jak2
|
||||
ls -l ./out/jak3
|
||||
set +e
|
||||
python ./scripts/gsrc/compare-compilation-outputs.py --base "./out/jak1/obj.master,./out/jak2/obj.master,./out/jak3/obj.master" --compare "./out/jak1/obj.pr,./out/jak2/obj.pr,./out/jak3/obj.pr" --markdown
|
||||
SCRIPT_EXIT_CODE=$?
|
||||
cat ./comp-diff-report.md >> $GITHUB_STEP_SUMMARY
|
||||
if [ "$SCRIPT_EXIT_CODE" -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
name: 🏭 Draft Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
bump:
|
||||
description: 'Semver Bump Type'
|
||||
required: true
|
||||
default: 'patch'
|
||||
type: choice
|
||||
options:
|
||||
- patch
|
||||
- minor
|
||||
- major
|
||||
|
||||
jobs:
|
||||
cut-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Docs - https://github.com/mathieudutour/github-tag-action
|
||||
# Workflows cannot trigger other workflows implicitly
|
||||
# - https://github.community/t/github-actions-workflow-not-triggering-with-tag-push/17053/7
|
||||
- name: Bump Version and Push Tag
|
||||
if: github.repository == 'open-goal/jak-project'
|
||||
id: tag_version
|
||||
uses: mathieudutour/[email protected]
|
||||
with:
|
||||
github_token: ${{ secrets.BOT_PAT }}
|
||||
tag_prefix: v
|
||||
default_bump: ${{ github.event.inputs.bump }}
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
|
||||
run: gh release create ${{ steps.tag_version.outputs.new_tag }} --generate-notes --draft --repo open-goal/jak-project
|
||||
@@ -21,9 +21,19 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
# minimal checkout if we're NOT uploading artifacts
|
||||
- name: Checkout Repository
|
||||
if: ${{ ! inputs.uploadArtifacts }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# full checkout with tags if we ARE uploading artifacts
|
||||
- name: Checkout Repository with Tags
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Install Package Dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -33,7 +43,7 @@ jobs:
|
||||
libxi-dev zip ninja-build libgl1-mesa-dev libssl-dev
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
uses: hendrikmuhs/[email protected]6
|
||||
with:
|
||||
variant: sccache
|
||||
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
sudo update-alternatives --set g++ /usr/bin/g++-10
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
uses: hendrikmuhs/[email protected]6
|
||||
with:
|
||||
variant: sccache
|
||||
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -13,25 +13,22 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: ARM
|
||||
runs-on: macos-12
|
||||
runs-on: macos-15
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up ARM64 environment
|
||||
run: sudo softwareupdate --install-rosetta --agree-to-license
|
||||
|
||||
- name: Install Package Dependencies
|
||||
run: arch -arm64 brew install cmake ninja
|
||||
run: brew install cmake ninja nasm
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
uses: hendrikmuhs/[email protected]6
|
||||
with:
|
||||
variant: sccache
|
||||
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
restore-keys: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
|
||||
key: macos-15-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
restore-keys: macos-15-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
|
||||
max-size: 1000M
|
||||
|
||||
- name: CMake Generation
|
||||
@@ -52,7 +49,7 @@ jobs:
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: opengoal-macos-${{ inputs.cachePrefix }}
|
||||
name: opengoal-macos-arm-${{ inputs.cachePrefix }}
|
||||
if-no-files-found: error
|
||||
path: |
|
||||
./build/goalc/goalc
|
||||
|
||||
@@ -17,22 +17,32 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Intel
|
||||
runs-on: macos-12
|
||||
runs-on: macos-13
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
# minimal checkout if we're NOT uploading artifacts
|
||||
- name: Checkout Repository
|
||||
if: ${{ ! inputs.uploadArtifacts }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# full checkout with tags if we ARE uploading artifacts
|
||||
- name: Checkout Repository with Tags
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Install Package Dependencies
|
||||
run: brew install cmake nasm ninja
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
uses: hendrikmuhs/[email protected]6
|
||||
with:
|
||||
variant: sccache
|
||||
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
restore-keys: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
|
||||
key: macos-13-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
restore-keys: macos-13-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
|
||||
max-size: 1000M
|
||||
|
||||
- name: CMake Generation
|
||||
|
||||
@@ -1,13 +1,52 @@
|
||||
name: 🏭 Release Pipeline
|
||||
name: 🏭 Draft Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
bump:
|
||||
description: 'Semver Bump Type'
|
||||
required: true
|
||||
default: 'patch'
|
||||
type: choice
|
||||
options:
|
||||
- patch
|
||||
- minor
|
||||
- major
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
cut_release:
|
||||
name: Cut Release
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
new_tag: ${{ steps.set_tag.outputs.new_tag }}
|
||||
steps:
|
||||
# Docs - https://github.com/mathieudutour/github-tag-action
|
||||
- name: Bump Version and Push Tag
|
||||
if: github.repository == 'open-goal/jak-project'
|
||||
id: tag_version
|
||||
uses: mathieudutour/[email protected]
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag_prefix: v
|
||||
default_bump: ${{ github.event.inputs.bump }}
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: gh release create ${{ steps.tag_version.outputs.new_tag }} --generate-notes --draft --repo ${{ github.repository }}
|
||||
|
||||
- name: Output new tag
|
||||
id: set_tag
|
||||
run: |
|
||||
echo "new_tag=${{ steps.tag_version.outputs.new_tag }}" >> $GITHUB_OUTPUT
|
||||
|
||||
# Windows
|
||||
build_windows_clang:
|
||||
needs:
|
||||
- cut_release
|
||||
name: "🖥️ Windows"
|
||||
uses: ./.github/workflows/windows-build-clang.yaml
|
||||
with:
|
||||
@@ -18,6 +57,8 @@ jobs:
|
||||
|
||||
# Linux
|
||||
build_linux_clang:
|
||||
needs:
|
||||
- cut_release
|
||||
name: "🐧 Linux"
|
||||
uses: ./.github/workflows/linux-build-clang.yaml
|
||||
with:
|
||||
@@ -28,25 +69,42 @@ jobs:
|
||||
|
||||
# macOS
|
||||
build_macos_intel:
|
||||
needs:
|
||||
- cut_release
|
||||
name: "🍎 MacOS"
|
||||
uses: ./.github/workflows/macos-build.yaml
|
||||
with:
|
||||
cmakePreset: "Release-macos-clang-static"
|
||||
cmakePreset: "Release-macos-x86_64-clang-static"
|
||||
cachePrefix: "static"
|
||||
uploadArtifacts: true
|
||||
secrets: inherit
|
||||
|
||||
build_macos_arm:
|
||||
needs:
|
||||
- cut_release
|
||||
name: "🍎 MacOS"
|
||||
uses: ./.github/workflows/macos-build.yaml
|
||||
with:
|
||||
cmakePreset: "Release-macos-x86_64-clang-static"
|
||||
cachePrefix: "static-arm"
|
||||
uploadArtifacts: true
|
||||
secrets: inherit
|
||||
|
||||
# Upload the Artifacts
|
||||
upload_artifacts:
|
||||
if: github.repository == 'open-goal/jak-project'
|
||||
needs:
|
||||
- cut_release
|
||||
- build_windows_clang
|
||||
- build_linux_clang
|
||||
- build_macos_intel
|
||||
- build_macos_arm
|
||||
name: "Upload Artifacts"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.cut_release.outputs.new_tag }}
|
||||
|
||||
- name: Prepare Artifact Folder
|
||||
run: mkdir -p ./ci-artifacts/final
|
||||
@@ -64,7 +122,7 @@ jobs:
|
||||
mkdir -p ./ci-artifacts/linux
|
||||
./.github/scripts/releases/extract_build_unix.sh ./ci-artifacts/linux ./ci-artifacts/opengoal-linux-static ./
|
||||
pushd ci-artifacts/linux
|
||||
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
|
||||
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
|
||||
tar czf ../final/opengoal-linux-${TAG_VAL}.tar.gz .
|
||||
popd
|
||||
chmod +x ./ci-artifacts/opengoal-linux-static/lsp/lsp
|
||||
@@ -74,31 +132,42 @@ jobs:
|
||||
run: |
|
||||
mkdir -p ./ci-artifacts/windows
|
||||
./.github/scripts/releases/extract_build_windows.sh ./ci-artifacts/windows ./ci-artifacts/opengoal-windows-static ./
|
||||
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
|
||||
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
|
||||
7z a -tzip ./ci-artifacts/final/opengoal-windows-${TAG_VAL}.zip ./ci-artifacts/windows/*
|
||||
cp ./ci-artifacts/opengoal-windows-static/lsp.exe ./ci-artifacts/final/opengoal-lsp-windows-${TAG_VAL}.exe
|
||||
|
||||
- name: Prepare macOS Build Assets
|
||||
- name: Prepare Intel macOS Build Assets
|
||||
run: |
|
||||
mkdir -p ./ci-artifacts/macos
|
||||
./.github/scripts/releases/extract_build_unix.sh ./ci-artifacts/macos ./ci-artifacts/opengoal-macos-static ./
|
||||
pushd ci-artifacts/macos
|
||||
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
|
||||
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
|
||||
tar czf ../final/opengoal-macos-intel-${TAG_VAL}.tar.gz .
|
||||
popd
|
||||
chmod +x ./ci-artifacts/opengoal-macos-static/lsp/lsp
|
||||
cp ./ci-artifacts/opengoal-macos-static/lsp/lsp ./ci-artifacts/final/opengoal-lsp-macos-intel-${TAG_VAL}.bin
|
||||
|
||||
- name: Prepare ARM macOS Build Assets
|
||||
run: |
|
||||
mkdir -p ./ci-artifacts/macos-arm
|
||||
./.github/scripts/releases/extract_build_unix.sh ./ci-artifacts/macos-arm ./ci-artifacts/opengoal-macos-static-arm ./
|
||||
pushd ci-artifacts/macos-arm
|
||||
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
|
||||
tar czf ../final/opengoal-macos-arm-${TAG_VAL}.tar.gz .
|
||||
popd
|
||||
chmod +x ./ci-artifacts/opengoal-macos-static-arm/lsp/lsp
|
||||
cp ./ci-artifacts/opengoal-macos-static-arm/lsp/lsp ./ci-artifacts/final/opengoal-lsp-macos-arm-${TAG_VAL}.bin
|
||||
|
||||
- name: Upload Assets
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
|
||||
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
|
||||
gh release upload "${TAG_VAL}" ${{ github.WORKSPACE }}/ci-artifacts/final/* --repo open-goal/jak-project --clobber
|
||||
|
||||
- name: Publish Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
|
||||
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
|
||||
gh release edit ${TAG_VAL} --draft=false --repo open-goal/jak-project
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
wget -O ./game/assets/sdl_controller_db.txt https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.BOT_PAT }}
|
||||
author: 'OpenGOALBot <[email protected]>'
|
||||
|
||||
@@ -22,9 +22,19 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
# minimal checkout if we're NOT uploading artifacts
|
||||
- name: Checkout Repository
|
||||
if: ${{ ! inputs.uploadArtifacts }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# full checkout with tags if we ARE uploading artifacts
|
||||
- name: Checkout Repository with Tags
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Install NASM
|
||||
# TODO - Simplify this with just the first command once choco 2.0 rolls out everywhere
|
||||
run: |
|
||||
@@ -36,7 +46,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
uses: hendrikmuhs/[email protected]6
|
||||
with:
|
||||
variant: sccache
|
||||
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
uses: hendrikmuhs/[email protected]6
|
||||
with:
|
||||
variant: sccache
|
||||
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
+5
-2
@@ -1,6 +1,7 @@
|
||||
# logs
|
||||
/log
|
||||
prof.json
|
||||
/gpu-test.json
|
||||
|
||||
# for CMake
|
||||
/Testing
|
||||
@@ -9,7 +10,8 @@ prof.json
|
||||
cmake-build-debug/*
|
||||
cmake-build-debug--o0/*
|
||||
.idea/*
|
||||
build/*
|
||||
build/
|
||||
build.master/
|
||||
/decompiler_out*
|
||||
logs/*
|
||||
profile_data/*
|
||||
@@ -32,6 +34,7 @@ linux-default/
|
||||
*.bin
|
||||
*.log
|
||||
*.p2s
|
||||
out/
|
||||
savestate-out/
|
||||
savestate_out/
|
||||
failures/
|
||||
@@ -39,6 +42,7 @@ ee-results*.json
|
||||
search-results.json
|
||||
.env
|
||||
/search-results.json
|
||||
comp-diff-report.md
|
||||
|
||||
# graphics debug
|
||||
debug_out/
|
||||
@@ -67,7 +71,6 @@ custom_assets/jak3/merc_replacements/*
|
||||
svnrev.h
|
||||
common/versions/revision.h
|
||||
ci-artifacts/
|
||||
out/build/
|
||||
__pycache__/
|
||||
|
||||
# sqlite stuff
|
||||
|
||||
@@ -138,6 +138,19 @@
|
||||
"-debug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Game - GPU Test",
|
||||
"args": [
|
||||
"-v",
|
||||
"--gpu-test",
|
||||
"opengl",
|
||||
"--gpu-test-out-path",
|
||||
"./gpu-test.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
|
||||
+10
-1
@@ -2,6 +2,7 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
project(jak)
|
||||
include(CTest)
|
||||
|
||||
@@ -43,6 +44,10 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
-Wall \
|
||||
-Wno-c++11-narrowing \
|
||||
-Wno-c++98-compat \
|
||||
-Wno-deprecated-this-capture \
|
||||
-Wno-missing-field-initializers \
|
||||
-Wno-sign-compare \
|
||||
-Wno-ignored-qualifiers \
|
||||
-O3 \
|
||||
-D_CRT_SECURE_NO_WARNINGS")
|
||||
|
||||
@@ -52,7 +57,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# Note: this is only _reserved_ memory, not necessarily _committed_ memory
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LDFLAGS} -Xlinker /STACK:16000000")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -g -Wextra")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -g")
|
||||
endif()
|
||||
|
||||
# additional c++ and linker flags for release mode for our projects
|
||||
@@ -283,6 +288,10 @@ include(test/CMakeLists.txt)
|
||||
build_third_party_lib(lzokay lzokay)
|
||||
|
||||
build_third_party_lib(stb_image stb_image)
|
||||
# build draco library for tinygltf compression support
|
||||
include_directories(third-party/draco/src)
|
||||
add_subdirectory(third-party/draco)
|
||||
add_compile_definitions(TINYGLTF_ENABLE_DRACO)
|
||||
build_third_party_lib(tiny_gltf tiny_gltf)
|
||||
build_third_party_lib(xdelta3 xdelta3)
|
||||
|
||||
|
||||
+40
-8
@@ -78,6 +78,22 @@
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install/${presetName}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "base-macos-arm64",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_APPLE_SILICON_PROCESSOR": "arm64",
|
||||
"CMAKE_OSX_ARCHITECTURES": "arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "base-macos-x86_64",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_APPLE_SILICON_PROCESSOR": "x86_64",
|
||||
"CMAKE_OSX_ARCHITECTURES": "x86_64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "base-clang",
|
||||
"hidden": true,
|
||||
@@ -159,16 +175,32 @@
|
||||
"inherits": ["base-linux-release", "base-clang"]
|
||||
},
|
||||
{
|
||||
"name": "Release-macos-clang",
|
||||
"displayName": "MacOS Release (clang)",
|
||||
"description": "Build with Clang as Release without Debug Symbols",
|
||||
"inherits": ["base-macos-release", "base-clang"]
|
||||
"name": "Release-macos-arm64-clang",
|
||||
"displayName": "MacOS ARM64 Release (clang)",
|
||||
"description": "Build for ARM64 with Clang as Release without Debug Symbols",
|
||||
"inherits": ["base-macos-release", "base-macos-arm64", "base-clang"]
|
||||
},
|
||||
{
|
||||
"name": "Release-macos-clang-static",
|
||||
"displayName": "MacOS Static Release (clang)",
|
||||
"description": "Build with Clang as Release without Debug Symbols but statically linked",
|
||||
"inherits": ["base-macos-release", "base-clang"],
|
||||
"name": "Release-macos-x86_64-clang",
|
||||
"displayName": "MacOS x86_64 Release (clang)",
|
||||
"description": "Build for x86_64 with Clang as Release without Debug Symbols",
|
||||
"inherits": ["base-macos-release", "base-macos-x86_64", "base-clang"]
|
||||
},
|
||||
{
|
||||
"name": "Release-macos-arm64-clang-static",
|
||||
"displayName": "MacOS ARM64 Static Release (clang)",
|
||||
"description": "Build for ARM64 with Clang as Release without Debug Symbols but statically linked",
|
||||
"inherits": ["base-macos-release", "base-macos-arm64", "base-clang"],
|
||||
"cacheVariables": {
|
||||
"STATICALLY_LINK": "true",
|
||||
"ZYDIS_BUILD_SHARED_LIB": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Release-macos-x86_64-clang-static",
|
||||
"displayName": "MacOS x86_64 Static Release (clang)",
|
||||
"description": "Build for x86_64 with Clang as Release without Debug Symbols but statically linked, requires MacOS Sequoia",
|
||||
"inherits": ["base-macos-release", "base-macos-x86_64", "base-clang"],
|
||||
"cacheVariables": {
|
||||
"STATICALLY_LINK": "true",
|
||||
"ZYDIS_BUILD_SHARED_LIB": "OFF"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2020-2022 OpenGOAL Team
|
||||
Copyright (c) 2020-2025 OpenGOAL Team
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
||||
@@ -72,7 +72,7 @@ Our objectives are:
|
||||
|
||||
We support both Linux and Windows on x86-64.
|
||||
|
||||
> We do not support, or plan to support the ARM architecture. This means that this will not run on devices such as an M1 Mac or a mobile device.
|
||||
> We do not support, or plan to support the ARM architecture. This means that this will not run on devices such as a mobile device.
|
||||
|
||||
### Current Status
|
||||
|
||||
@@ -127,7 +127,7 @@ Unfortunately you'll still need task runner on your local machine to run the gam
|
||||
Install packages and init repository:
|
||||
|
||||
```sh
|
||||
sudo apt install gcc make cmake build-essential g++ nasm clang-format libxrandr-dev libxinerama-dev libxcursor-dev libpulse-dev libxi-dev python libgl1-mesa-dev libssl-dev
|
||||
sudo apt install gcc make cmake ninja-build build-essential g++ nasm clang-format libxrandr-dev libxinerama-dev libxcursor-dev libpulse-dev libxi-dev python libgl1-mesa-dev libssl-dev
|
||||
sudo sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
|
||||
```
|
||||
|
||||
@@ -235,7 +235,7 @@ Then build the entire project as `Windows Release (clang)`. You can also press C
|
||||
|
||||
### MacOS
|
||||
|
||||
> NOTE: At this time you can only run the game on macOS if you have an Intel processor.
|
||||
> NOTE: Running the game requires an Apple Silicon Mac running macOS Sequoia, or an Intel Mac.
|
||||
|
||||
Ensure that you have Xcode command line tools installed (this installs things like Apple Clang). If you don't, you can run the following command:
|
||||
|
||||
@@ -243,23 +243,25 @@ Ensure that you have Xcode command line tools installed (this installs things li
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
#### Intel Based
|
||||
On Apple Silicon, Rosetta 2 also must be installed:
|
||||
|
||||
```bash
|
||||
softwareupdate --install-rosetta
|
||||
```
|
||||
|
||||
#### Building for x86_64
|
||||
|
||||
```bash
|
||||
brew install go-task/tap/go-task
|
||||
brew install cmake nasm ninja go-task clang-format
|
||||
cmake -B build --preset=Release-macos-clang
|
||||
cmake -B build --preset=Release-macos-x86_64-clang
|
||||
cmake --build build --parallel $((`sysctl -n hw.logicalcpu`))
|
||||
```
|
||||
|
||||
#### Apple Silicon
|
||||
|
||||
**Not Supported at This Time**
|
||||
#### Building for ARM64 (experimental, unsupported)
|
||||
|
||||
```bash
|
||||
brew install go-task/tap/go-task
|
||||
brew install cmake ninja go-task clang-format
|
||||
cmake -B build --preset=Release-macos-clang
|
||||
cmake -B build --preset=Release-macos-arm64-clang
|
||||
cmake --build build --parallel $((`sysctl -n hw.logicalcpu`))
|
||||
```
|
||||
|
||||
|
||||
+44
-29
@@ -10,33 +10,33 @@ dotenv:
|
||||
tasks:
|
||||
# SETTINGS / CONFIGURATION
|
||||
settings:
|
||||
- 'python ./scripts/tasks/update-env.py --info'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --info'
|
||||
set-game-jak1:
|
||||
- 'python ./scripts/tasks/update-env.py --game jak1'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --game jak1'
|
||||
set-game-jak2:
|
||||
- 'python ./scripts/tasks/update-env.py --game jak2'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --game jak2'
|
||||
set-game-jak3:
|
||||
- 'python ./scripts/tasks/update-env.py --game jak3'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --game jak3'
|
||||
set-decomp-ntscv1:
|
||||
desc: "aka black label"
|
||||
cmds:
|
||||
- 'python ./scripts/tasks/update-env.py --decomp_config ntscv1'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscv1'
|
||||
set-decomp-ntscv2:
|
||||
desc: "aka red label"
|
||||
cmds:
|
||||
- 'python ./scripts/tasks/update-env.py --decomp_config ntscv2'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscv2'
|
||||
set-decomp-pal:
|
||||
desc: "PAL region version"
|
||||
cmds:
|
||||
- 'python ./scripts/tasks/update-env.py --decomp_config pal'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config pal'
|
||||
set-decomp-ntscjp:
|
||||
desc: "NTSC-J region version"
|
||||
cmds:
|
||||
- 'python ./scripts/tasks/update-env.py --decomp_config ntscjp'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscjp'
|
||||
set-decomp-ntscko:
|
||||
desc: "NTSC-K region version"
|
||||
cmds:
|
||||
- 'python ./scripts/tasks/update-env.py --decomp_config ntscko'
|
||||
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscko'
|
||||
# GENERAL
|
||||
extract:
|
||||
desc: "Extracts the game's assets from './iso_data' with the set decompiler config"
|
||||
@@ -67,6 +67,14 @@ tasks:
|
||||
cmds:
|
||||
- "{{.GK_BIN_RELEASE_DIR}}/gk -v --game {{.GAME}} -- -fakeiso -debug"
|
||||
# DEVELOPMENT
|
||||
gen-cmake:
|
||||
desc: "Generate the CMake"
|
||||
cmds:
|
||||
- "cmake -B build --preset={{.CMAKE_PRESET}}"
|
||||
build:
|
||||
desc: "Build the project using the generated CMake"
|
||||
cmds:
|
||||
- "cmake --build build --parallel {{.CMAKE_NUM_THREADS}}"
|
||||
repl:
|
||||
desc: "Start the REPL"
|
||||
preconditions:
|
||||
@@ -83,9 +91,9 @@ tasks:
|
||||
format:
|
||||
desc: "Format code"
|
||||
cmds:
|
||||
- cmd: python ./scripts/cpp/format-includes.py
|
||||
- cmd: python ./scripts/ci/lint-trailing-whitespace.py --fix
|
||||
- cmd: python ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp -i
|
||||
- cmd: '{{.PYTHON}} ./scripts/cpp/format-includes.py'
|
||||
- cmd: '{{.PYTHON}} ./scripts/ci/lint-trailing-whitespace.py --fix'
|
||||
- cmd: '{{.PYTHON}} ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp -i'
|
||||
- task: format-json
|
||||
format-gsrc:
|
||||
desc: "Run formatter on gsrc file"
|
||||
@@ -103,28 +111,28 @@ tasks:
|
||||
- "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler \"./decompiler/config/{{.DECOMP_CONFIG}}\" \"./iso_data\" \"./decompiler_out\" --version \"{{.DECOMP_CONFIG_VERSION}}\" --config-override '{\"decompile_code\": true, \"levels_extract\": false, \"allowed_objects\": [\"{{.FILE}}\"]}'"
|
||||
decomp-clean:
|
||||
cmds:
|
||||
- python ./scripts/tasks/clean-decomp.py --game "{{.GAME}}"
|
||||
- '{{.PYTHON}} ./scripts/tasks/clean-decomp.py --game "{{.GAME}}"'
|
||||
lint-gsrc-file:
|
||||
cmds:
|
||||
- python ./scripts/gsrc/lint-gsrc-file.py --game {{.GAME}} --file "{{.FILE}}"
|
||||
- '{{.PYTHON}} ./scripts/gsrc/lint-gsrc-file.py --game {{.GAME}} --file "{{.FILE}}"'
|
||||
update-gsrc:
|
||||
cmds:
|
||||
- python ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}
|
||||
- '{{.PYTHON}} ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}'
|
||||
update-gsrc-glob:
|
||||
cmds:
|
||||
- python ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --file_pattern "{{.GLOB}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}
|
||||
- '{{.PYTHON}} ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --file_pattern "{{.GLOB}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}'
|
||||
update-gsrc-file:
|
||||
cmds:
|
||||
- task: decomp-file
|
||||
- python ./scripts/gsrc/update-from-decomp.py --game "{{.GAME}}" --file "{{.FILE}}"
|
||||
- '{{.PYTHON}} ./scripts/gsrc/update-from-decomp.py --game "{{.GAME}}" --file "{{.FILE}}"'
|
||||
- task: lint-gsrc-file
|
||||
copy-common-naming:
|
||||
cmds:
|
||||
- python ./scripts/gsrc/copy-common-naming.py --file "{{.FILE}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"
|
||||
- '{{.PYTHON}} ./scripts/gsrc/copy-common-naming.py --file "{{.FILE}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"'
|
||||
- task: format-json
|
||||
copy-common-naming-from-refs:
|
||||
cmds:
|
||||
- python ./scripts/gsrc/copy-common-naming.py --update-names-from-refs --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"
|
||||
- '{{.PYTHON}} ./scripts/gsrc/copy-common-naming.py --update-names-from-refs --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"'
|
||||
- task: format-json
|
||||
# ASSET RIPPING
|
||||
rip-textures:
|
||||
@@ -139,10 +147,10 @@ tasks:
|
||||
# TOOLS
|
||||
analyze-ee-memory:
|
||||
cmds:
|
||||
- python ./scripts/tasks/extract-zip.py --file "{{.FILE}}" --out ./savestate_out/
|
||||
- '{{.PYTHON}} ./scripts/tasks/extract-zip.py --file "{{.FILE}}" --out ./savestate_out/'
|
||||
- '{{.MEMDUMP_BIN_RELEASE_DIR}}/memory_dump_tool ./savestate_out/eeMemory.bin --output-path ./ --game {{.GAME}} > ee-analysis.log'
|
||||
watch-pcsx2:
|
||||
# python -m pip install -U "watchdog[watchmedo]"
|
||||
# {{.PYTHON}} -m pip install -U "watchdog[watchmedo]"
|
||||
cmds:
|
||||
- watchmedo shell-command --drop --patterns="*.p2s" --recursive --command='task analyze-ee-memory FILE="${watch_src_path}"' "{{.SAVESTATE_DIR}}"
|
||||
vars:
|
||||
@@ -155,15 +163,22 @@ tasks:
|
||||
desc: Updates locally built tree-sitter rules
|
||||
cmds:
|
||||
- cd ../tree-sitter-opengoal && yarn gen
|
||||
- python ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/src/*" --dest "./third-party/tree-sitter/tree-sitter-opengoal"
|
||||
- python ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/grammar.js" --dest "./third-party/tree-sitter/tree-sitter-opengoal"
|
||||
- '{{.PYTHON}} ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/src/*" --dest "./third-party/tree-sitter/tree-sitter-opengoal"'
|
||||
- '{{.PYTHON}} ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/grammar.js" --dest "./third-party/tree-sitter/tree-sitter-opengoal"'
|
||||
fix-translations:
|
||||
desc: Finds and tries to fix invalid translation Characters
|
||||
cmds:
|
||||
- python ./scripts/ci/lint-characters.py --fix
|
||||
- '{{.PYTHON}} ./scripts/ci/lint-characters.py --fix'
|
||||
lint:
|
||||
cmds:
|
||||
- python ./scripts/ci/lint-trailing-whitespace.py
|
||||
- '{{.PYTHON}} ./scripts/ci/lint-trailing-whitespace.py'
|
||||
run-gpu-test:
|
||||
desc: "Runs the game's built in GPU test"
|
||||
preconditions:
|
||||
- sh: test -f {{.GK_BIN_RELEASE_DIR}}/gk{{.EXE_FILE_EXTENSION}}
|
||||
msg: "Couldn't locate runtime executable in '{{.GK_BIN_RELEASE_DIR}}/gk'"
|
||||
cmds:
|
||||
- "{{.GK_BIN_RELEASE_DIR}}/gk -v --gpu-test opengl --gpu-test-out-path ./gpu-test.json"
|
||||
# TESTS
|
||||
offline-tests: # ran by jenkins
|
||||
cmds:
|
||||
@@ -177,17 +192,17 @@ tasks:
|
||||
# TODO - amalgamate offline-tests and this task, run twice if the previous step fails
|
||||
update-ref-tests:
|
||||
cmds:
|
||||
- cmd: python ./scripts/tasks/delete-file-or-folder.py --path failures
|
||||
- cmd: '{{.PYTHON}} ./scripts/tasks/delete-file-or-folder.py --path failures'
|
||||
- cmd: '{{.OFFLINETEST_BIN_RELEASE_DIR}}/offline-test --iso_data_path "./iso_data/{{.GAME}}" --game {{.GAME}} --pretty-print --num_threads 32 --dump_current_output --fail-on-cmp'
|
||||
ignore_error: true
|
||||
- python ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}
|
||||
- '{{.PYTHON}} ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}'
|
||||
- task: offline-tests-fast
|
||||
update-ref-file:
|
||||
cmds:
|
||||
- cmd: python ./scripts/tasks/delete-file-or-folder.py --path failures
|
||||
- cmd: '{{.PYTHON}} ./scripts/tasks/delete-file-or-folder.py --path failures'
|
||||
- cmd: '{{.OFFLINETEST_BIN_RELEASE_DIR}}/offline-test --iso_data_path "./iso_data/{{.GAME}}" --file {{.FILE}} --game {{.GAME}} --dump_current_output --fail-on-cmp'
|
||||
ignore_error: true
|
||||
- python ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}
|
||||
- '{{.PYTHON}} ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}'
|
||||
- task: offline-test-file
|
||||
type-test:
|
||||
cmds:
|
||||
|
||||
@@ -15,6 +15,13 @@ function(write_revision_h)
|
||||
OUTPUT_VARIABLE GIT_TAG
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
# To support being on a commit with mutiple tags
|
||||
if(${GIT_TAG} MATCHES "\n")
|
||||
string(REPLACE "\n" ";" GIT_TAG_LIST "${GIT_TAG}")
|
||||
list(LENGTH GIT_TAG_LIST GIT_TAG_LIST_LENGTH)
|
||||
math(EXPR GIT_TAG_LAST_INDEX "${GIT_TAG_LIST_LENGTH} - 1")
|
||||
list(GET GIT_TAG_LIST ${GIT_TAG_LAST_INDEX} GIT_TAG)
|
||||
endif()
|
||||
endif()
|
||||
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/versions/revision.h "#define BUILT_TAG \"${GIT_TAG}\"\n#define BUILT_SHA \"${GIT_SHORT_SHA}\"\n")
|
||||
endfunction()
|
||||
@@ -88,6 +95,7 @@ add_library(common
|
||||
util/Timer.cpp
|
||||
util/unicode_util.cpp
|
||||
util/gltf_util.cpp
|
||||
util/image_resize.cpp
|
||||
versions/versions.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -304,13 +304,15 @@ void TieTree::unpack() {
|
||||
|
||||
for (auto& draw : static_draws) {
|
||||
draw.unpacked.idx_of_first_idx_in_full_buffer = unpacked.indices.size();
|
||||
ASSERT(draw.plain_indices.empty());
|
||||
// indices can come from either runs or already in plain indices.
|
||||
for (auto& run : draw.runs) {
|
||||
for (u32 ri = 0; ri < run.length; ri++) {
|
||||
unpacked.indices.push_back(run.vertex0 + ri);
|
||||
}
|
||||
unpacked.indices.push_back(UINT32_MAX);
|
||||
}
|
||||
unpacked.indices.insert(unpacked.indices.end(), draw.plain_indices.begin(),
|
||||
draw.plain_indices.end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,6 +408,8 @@ void TieTree::serialize(Serializer& ser) {
|
||||
colors.serialize(ser);
|
||||
bvh.serialize(ser);
|
||||
|
||||
ser.from_ptr(&use_strips);
|
||||
|
||||
ser.from_ptr(&has_per_proto_visibility_toggle);
|
||||
ser.from_string_vector(&proto_names);
|
||||
}
|
||||
@@ -850,4 +854,11 @@ std::size_t PreloadedVertex::hash::operator()(const PreloadedVertex& v) const {
|
||||
std::hash<float>()(v.s) ^ std::hash<float>()(v.t) ^ std::hash<u16>()(v.color_index);
|
||||
}
|
||||
|
||||
std::size_t PackedTieVertices::Vertex::hash::operator()(const Vertex& v) const {
|
||||
return std::hash<float>()(v.x) ^ std::hash<float>()(v.y) ^ std::hash<float>()(v.z) ^
|
||||
std::hash<float>()(v.r) ^ std::hash<float>()(v.g) ^ std::hash<float>()(v.b) ^
|
||||
std::hash<float>()(v.a) ^ std::hash<float>()(v.s) ^ std::hash<float>()(v.t) ^
|
||||
std::hash<float>()(v.nx) ^ std::hash<float>()(v.ny) ^ std::hash<float>()(v.nz);
|
||||
}
|
||||
|
||||
} // namespace tfrag3
|
||||
@@ -18,7 +18,7 @@ namespace tfrag3 {
|
||||
// - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage
|
||||
// - if adding a new category to the memory usage, update extract_level to print it.
|
||||
|
||||
constexpr int TFRAG3_VERSION = 41;
|
||||
constexpr int TFRAG3_VERSION = 43;
|
||||
|
||||
enum MemoryUsageCategory {
|
||||
TEXTURE,
|
||||
@@ -116,6 +116,16 @@ struct PackedTieVertices {
|
||||
float s, t;
|
||||
s8 nx, ny, nz;
|
||||
u8 r, g, b, a;
|
||||
|
||||
struct hash {
|
||||
std::size_t operator()(const Vertex& x) const;
|
||||
};
|
||||
|
||||
bool operator==(const Vertex& other) const {
|
||||
return x == other.x && y == other.y && z == other.z && s == other.s && t == other.t &&
|
||||
nx == other.nx && ny == other.ny && nz == other.nz && r == other.r && g == other.g &&
|
||||
b == other.b && a == other.a;
|
||||
}
|
||||
};
|
||||
|
||||
struct MatrixGroup {
|
||||
@@ -231,7 +241,7 @@ struct ShrubDraw {
|
||||
|
||||
struct InstancedStripDraw {
|
||||
DrawMode mode; // the OpenGL draw settings.
|
||||
u32 tree_tex_id = 0; // the texture that should be bound for the draw
|
||||
s32 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.
|
||||
@@ -420,6 +430,8 @@ struct TieTree {
|
||||
bool has_per_proto_visibility_toggle = false;
|
||||
std::vector<std::string> proto_names;
|
||||
|
||||
bool use_strips = true;
|
||||
|
||||
struct {
|
||||
std::vector<PreloadedVertex> vertices; // mesh vertices
|
||||
std::vector<u32> indices;
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ struct DmaTag {
|
||||
DmaTag(u64 value) {
|
||||
spr = (value >> 63);
|
||||
addr = (value >> 32) & 0x7fffffff;
|
||||
qwc = value & 0xfff;
|
||||
qwc = value & 0xffff;
|
||||
kind = Kind((value >> 28) & 0b111);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
|
||||
}
|
||||
for (size_t i = 0; i < ts_node_child_count(curr_node); i++) {
|
||||
const auto child_node = ts_node_child(curr_node, i);
|
||||
auto debug_child = ts_node_string(child_node);
|
||||
[[maybe_unused]] auto debug_child = ts_node_string(child_node);
|
||||
const auto contents = get_source_code(source, child_node);
|
||||
bool skip_node = false;
|
||||
for (const auto& skippable_content : skippable_nodes) {
|
||||
|
||||
@@ -168,6 +168,39 @@ static FormFormattingConfig new_deftype_rule(
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_defproc_rule(
|
||||
int start_index,
|
||||
int num_columns_to_compute_widths,
|
||||
const std::vector<int>& inlining_preventation_indices) {
|
||||
FormFormattingConfig cfg;
|
||||
cfg.has_constant_pairs = true;
|
||||
cfg.config_set = true;
|
||||
cfg.hang_forms = false;
|
||||
cfg.inline_until_index = [start_index](std::vector<std::string> curr_lines) {
|
||||
// if (curr_lines.size() >= 4 && curr_lines.at(3) == "()") {
|
||||
// return 4;
|
||||
// }
|
||||
return start_index;
|
||||
};
|
||||
for (const auto& index : inlining_preventation_indices) {
|
||||
auto temp_config = std::make_shared<FormFormattingConfig>();
|
||||
temp_config->config_set = true;
|
||||
temp_config->prevent_inlining = true;
|
||||
temp_config->hang_forms = false;
|
||||
temp_config->indentation_width = 1;
|
||||
auto temp_list_config = std::make_shared<FormFormattingConfig>();
|
||||
temp_list_config->force_inline = false;
|
||||
temp_list_config->hang_forms = false;
|
||||
temp_config->default_index_config = temp_list_config;
|
||||
if (index == 3) {
|
||||
temp_config->determine_column_widths_for_list_elements = true;
|
||||
temp_config->num_columns_to_compute_widths = num_columns_to_compute_widths;
|
||||
}
|
||||
cfg.index_configs.emplace(index, temp_config);
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_binding_rule(int form_head_width) {
|
||||
FormFormattingConfig cfg;
|
||||
cfg.config_set = true;
|
||||
@@ -253,12 +286,16 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
|
||||
{"defmethod", new_defmethod_rule(3)},
|
||||
{"lambda", new_lambda_rule(2)},
|
||||
{"deftype", new_deftype_rule(3, 1, {3, 4, 5, 6})},
|
||||
{"defproc", new_defproc_rule(3, 1, {3, 4, 5, 6})},
|
||||
{"suspend-for", new_flow_rule(2)},
|
||||
{"spawn-proc", new_flow_rule(2)},
|
||||
{"defun", new_flow_rule(3)},
|
||||
{"defun-recursive", new_flow_rule(4)},
|
||||
{"defun-debug-recursive", new_flow_rule(4)},
|
||||
{"defun-debug", new_flow_rule(3)},
|
||||
{"defbehavior", new_flow_rule(4)},
|
||||
{"if", new_inlineable_flow_rule(2)},
|
||||
{"aif", new_inlineable_flow_rule(2)},
|
||||
{"#if", new_inlineable_flow_rule(2)},
|
||||
{"define", new_permissive_flow_rule()},
|
||||
{"def-mips2c", new_permissive_flow_rule()},
|
||||
@@ -269,10 +306,14 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
|
||||
{"declare-type", new_permissive_flow_rule()},
|
||||
{"defmacro", new_function_rule(3)},
|
||||
{"desfun", new_function_rule(3)},
|
||||
{"def-actor", new_flow_rule(2, true)},
|
||||
{"defskelgroup", new_flow_rule(2, true)},
|
||||
{"defpartgroup", new_flow_rule(2, true)},
|
||||
{"defpart", new_flow_rule(2, true)},
|
||||
{"defstate", new_defstate_rule(3, true)},
|
||||
{"defevent", new_flow_rule(2)},
|
||||
{"event", new_flow_rule(1)},
|
||||
{"defpost", new_flow_rule(2)},
|
||||
{"behavior", new_flow_rule(2)},
|
||||
{"dotimes", new_flow_rule(2)},
|
||||
{"dolist", new_flow_rule(2)},
|
||||
@@ -281,12 +322,15 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
|
||||
{"protect", new_binding_rule(4)},
|
||||
{"let*", new_binding_rule(5)},
|
||||
{"rlet", new_binding_rule(5)},
|
||||
{"mlet", new_binding_rule(5)},
|
||||
{"when", new_flow_rule(2)},
|
||||
{"awhen", new_flow_rule(2)},
|
||||
{"unless", new_flow_rule(2)},
|
||||
{"with-profiler", new_flow_rule(2)},
|
||||
{"with-pc", new_flow_rule(0)},
|
||||
{"#unless", new_flow_rule(2)},
|
||||
{"#when", new_flow_rule(2)},
|
||||
{"#when-game", new_flow_rule(2)},
|
||||
{"countdown", new_flow_rule(2)},
|
||||
{"until", new_flow_rule(2)},
|
||||
{"loop", new_flow_rule(0)},
|
||||
|
||||
+15
-1
@@ -57,6 +57,8 @@
|
||||
#include "common/util/Assert.h"
|
||||
#include "common/util/crc32.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
/*!
|
||||
@@ -234,10 +236,14 @@ class Object {
|
||||
|
||||
ObjectType type = ObjectType::INVALID;
|
||||
|
||||
private:
|
||||
bool disallow_hex_for_int = false;
|
||||
|
||||
public:
|
||||
std::string print() const {
|
||||
switch (type) {
|
||||
case ObjectType::INTEGER:
|
||||
return integer_obj.print();
|
||||
return disallow_hex_for_int ? fmt::format("{}", integer_obj.value) : integer_obj.print();
|
||||
case ObjectType::FLOAT:
|
||||
return float_obj.print();
|
||||
case ObjectType::CHAR:
|
||||
@@ -278,6 +284,14 @@ class Object {
|
||||
return o;
|
||||
}
|
||||
|
||||
static Object make_integer_no_hex(IntType value) {
|
||||
Object o;
|
||||
o.type = ObjectType::INTEGER;
|
||||
o.integer_obj.value = value;
|
||||
o.disallow_hex_for_int = true;
|
||||
return o;
|
||||
}
|
||||
|
||||
static Object make_float(FloatType value) {
|
||||
Object o;
|
||||
o.type = ObjectType::FLOAT;
|
||||
|
||||
@@ -295,7 +295,7 @@ void break_list(Node* node) {
|
||||
}
|
||||
} else if (name == "until" || name == "while" || name == "dotimes" || name == "countdown" ||
|
||||
name == "when" || name == "behavior" || name == "lambda" || name == "defpart" ||
|
||||
name == "define") {
|
||||
name == "define" || name == "suspend-for") {
|
||||
node->top_line_count = 2;
|
||||
} else if (name == "let" || name == "let*" || name == "rlet" ||
|
||||
name == "with-dma-buffer-add-bucket") {
|
||||
@@ -341,9 +341,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", "behavior", "defpart", "loop", "let*"};
|
||||
"when", "defun-debug", "countdown", "case", "defun", "defmethod", "let", "until",
|
||||
"while", "if", "dotimes", "cond", "else", "defbehavior", "with-pp", "rlet",
|
||||
"defstate", "behavior", "defpart", "loop", "let*", "suspend-for"};
|
||||
for (auto node : bfs_order) {
|
||||
if (!node->break_list && node->kind == Node::Kind::LIST &&
|
||||
node->child_nodes.at(0).kind == Node::Kind::ATOM) {
|
||||
|
||||
@@ -369,6 +369,17 @@ struct Matrix {
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix<T, Rows, Cols> transposed() const {
|
||||
static_assert(Rows == Cols);
|
||||
Matrix<T, Rows, Cols> ret;
|
||||
for (int i = 0; i < Rows; i++) {
|
||||
for (int j = 0; j < Cols; j++) {
|
||||
ret(i, j) = operator()(j, i);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <int OtherCols>
|
||||
Matrix<T, Rows, OtherCols> operator*(const Matrix<T, Cols, OtherCols>& y) const {
|
||||
Matrix<T, Rows, OtherCols> result;
|
||||
|
||||
@@ -49,6 +49,7 @@ struct Config {
|
||||
{KeyBind::Modifier::CTRL, "N", "Full build of the game", "(mi)"}};
|
||||
bool per_game_history = true;
|
||||
bool permissive_redefinitions = false;
|
||||
std::string iso_path;
|
||||
|
||||
int get_nrepl_port() {
|
||||
if (temp_nrepl_port != -1) {
|
||||
|
||||
@@ -43,6 +43,15 @@ void Wrapper::print_welcome_message(const std::vector<std::string>& loaded_proje
|
||||
fmt::format(" Project Path: {}\n",
|
||||
fmt::format(fg(fmt::color::gray), file_util::get_jak_project_dir().string()));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " - :===: -");
|
||||
std::string effective_iso_path;
|
||||
if (repl_config.iso_path.empty()) {
|
||||
effective_iso_path = file_util::get_file_path({"iso_data"});
|
||||
} else {
|
||||
effective_iso_path = repl_config.iso_path;
|
||||
}
|
||||
message +=
|
||||
fmt::format(" ISO Data Path: {}\n", fmt::format(fg(fmt::color::gray), effective_iso_path));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " --. .--: :--. .--");
|
||||
message += " nREPL:";
|
||||
if (!nrepl_alive) {
|
||||
message += fmt::format(fg(fmt::color::red), "DISABLED\n");
|
||||
@@ -50,22 +59,21 @@ void Wrapper::print_welcome_message(const std::vector<std::string>& loaded_proje
|
||||
message += fmt::format(fg(fmt::color::light_green), " Listening on {}\n",
|
||||
repl_config.get_nrepl_port());
|
||||
}
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " --. .--: :--. .--");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .=======. =======.");
|
||||
message += " Source File Search Dirs: ";
|
||||
const auto search_dir_string =
|
||||
fmt::format("{}", fmt::join(repl_config.asm_file_search_dirs, ","));
|
||||
message += fmt::format("[{}]\n", fmt::format(fg(fmt::color::gray), search_dir_string));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .=======. =======.");
|
||||
message += fmt::format(" {} or {} for basic help and usage\n",
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-=====-. .-=====-");
|
||||
message += fmt::format(" {} or {} for basic help and usage\n",
|
||||
fmt::format(fg(fmt::color::cyan), "(repl-help)"),
|
||||
fmt::format(fg(fmt::color::cyan), "(repl-keybinds)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-=====-. .-=====-");
|
||||
message +=
|
||||
fmt::format(" {} to connect to the game\n", fmt::format(fg(fmt::color::cyan), "(lt)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===========-.");
|
||||
message += fmt::format(" {} to recompile the active project.\n",
|
||||
message +=
|
||||
fmt::format(" {} to connect to the game\n", fmt::format(fg(fmt::color::cyan), "(lt)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===-.");
|
||||
message += fmt::format(" {} to recompile the active project.\n",
|
||||
fmt::format(fg(fmt::color::cyan), "(mi)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===-.\n");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .\n");
|
||||
fmt::print("{}", message);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,10 @@ const std::unordered_map<GameVersion, std::vector<std::string>> locale_lookup =
|
||||
{GameVersion::Jak1,
|
||||
{"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "jp-JP", "en-GB", "pt-PT", "fi-FI", "sv-SE",
|
||||
"da-DK", "no-NO", "nl-NL", "pt-BR", "hu-HU", "ca-ES", "is-IS"}},
|
||||
{GameVersion::Jak2, {"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "jp-JP", "ko-KR", "en-GB"}}};
|
||||
{GameVersion::Jak2, {"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "jp-JP", "ko-KR", "en-GB"}},
|
||||
{GameVersion::Jak3,
|
||||
{"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "cm-CM", "jp-JP", "ko-KR", "ru-RU", "pt-PT",
|
||||
"nl-NL", "en-GB"}}};
|
||||
|
||||
std::string lookup_locale_code(const GameVersion game_version, const int language_id) {
|
||||
if (locale_lookup.find(game_version) == locale_lookup.end() ||
|
||||
@@ -73,7 +76,8 @@ std::string lookup_locale_code(const GameVersion game_version, const int languag
|
||||
|
||||
const std::unordered_map<GameVersion, std::vector<int>> language_ids_with_audio = {
|
||||
{GameVersion::Jak1, {0, 1, 2, 3, 4, 5, 6}},
|
||||
{GameVersion::Jak2, {0, 1, 2, 3, 4, 5, 6, 7}}};
|
||||
{GameVersion::Jak2, {0, 1, 2, 3, 4, 5, 6, 7}},
|
||||
{GameVersion::Jak3, {0, 1, 2, 3, 4, 5, 11}}};
|
||||
|
||||
bool dump_language_with_duplicates_from_base(const GameVersion game_version,
|
||||
const int language_id) {
|
||||
|
||||
@@ -93,6 +93,57 @@ const std::unordered_map<std::string, u16> jak2_speaker_name_to_enum_val = {
|
||||
{"metalkor-before-consite", 35},
|
||||
{"metalkor-intro", 36}};
|
||||
|
||||
// matches enum in `subtitle3-h.gc` with "none" (first) and "max" (last and removed)
|
||||
const std::unordered_map<std::string, u16> jak3_speaker_name_to_enum_val = {
|
||||
{"none", 0},
|
||||
{"jak", 1},
|
||||
{"darkjak", 2},
|
||||
{"daxter", 3},
|
||||
{"pecker", 4},
|
||||
{"ashelin", 5},
|
||||
{"veger", 6},
|
||||
{"samos", 7},
|
||||
{"damas", 8},
|
||||
{"kleiver", 9},
|
||||
{"seem", 10},
|
||||
{"errol", 11},
|
||||
{"errol-hologram", 12},
|
||||
{"sig", 13},
|
||||
{"torn", 14},
|
||||
{"tess", 15},
|
||||
{"guard", 16},
|
||||
{"guard-a", 17},
|
||||
{"guard-b", 18},
|
||||
{"keira", 19},
|
||||
{"vin", 20},
|
||||
{"onin", 21},
|
||||
{"jinx", 22},
|
||||
{"wastelander-male", 23},
|
||||
{"wastelander-female", 24},
|
||||
{"citizen-male", 25},
|
||||
{"citizen-female", 26},
|
||||
{"marauder", 27},
|
||||
{"oracle", 28},
|
||||
{"precursor", 29},
|
||||
{"ottsel-leader", 30},
|
||||
{"ottsel-surfer", 31},
|
||||
{"ottsel-dummy", 32},
|
||||
{"ottsel-veger", 33},
|
||||
{"ottsel-tess", 34},
|
||||
{"computer", 35},
|
||||
{"ottsel-voice-before-outro", 36},
|
||||
{"ottsel-voice", 37},
|
||||
{"krew", 38},
|
||||
{"baron", 39},
|
||||
{"scherr", 40},
|
||||
{"arey", 41},
|
||||
{"baldwin", 42},
|
||||
{"schimpf", 43},
|
||||
{"martinsen", 44},
|
||||
{"phillips", 45},
|
||||
{"yates", 46},
|
||||
};
|
||||
|
||||
GameSubtitlePackage read_json_files_v2(const GameSubtitleDefinitionFile& file_info) {
|
||||
GameSubtitlePackage package;
|
||||
SubtitleFile lang_lines;
|
||||
@@ -256,11 +307,21 @@ void GameSubtitleBank::add_scenes_from_files(const GameSubtitlePackage& package)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - for jak 3+, this needs some game version context info (could infer from text version)
|
||||
std::vector<std::string> GameSubtitleBank::speaker_names_ordered_by_enum_value() {
|
||||
// Create a temporary vector of pairs (key, value)
|
||||
std::vector<std::pair<std::string, u16>> temp_vec(jak2_speaker_name_to_enum_val.begin(),
|
||||
jak2_speaker_name_to_enum_val.end());
|
||||
std::vector<std::pair<std::string, u16>> temp_vec;
|
||||
switch (m_text_version) {
|
||||
case GameTextVersion::JAK2:
|
||||
temp_vec = {jak2_speaker_name_to_enum_val.begin(), jak2_speaker_name_to_enum_val.end()};
|
||||
break;
|
||||
case GameTextVersion::JAK3:
|
||||
temp_vec = {jak3_speaker_name_to_enum_val.begin(), jak3_speaker_name_to_enum_val.end()};
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("GameSubtitleBank: invalid game text version {} ({})",
|
||||
(int)m_text_version,
|
||||
get_text_version_name(m_text_version)));
|
||||
}
|
||||
// Sort the temporary vector based on the enum value in ascending order
|
||||
std::sort(temp_vec.begin(), temp_vec.end(),
|
||||
[](const auto& a, const auto& b) { return a.second < b.second; });
|
||||
@@ -279,13 +340,25 @@ std::vector<std::string> GameSubtitleBank::speaker_names_ordered_by_enum_value()
|
||||
}
|
||||
|
||||
u16 GameSubtitleBank::speaker_enum_value_from_name(const std::string& speaker_id) {
|
||||
if (jak2_speaker_name_to_enum_val.find(speaker_id) == jak2_speaker_name_to_enum_val.end()) {
|
||||
std::unordered_map<std::string, u16> enum_map;
|
||||
switch (m_text_version) {
|
||||
case GameTextVersion::JAK2:
|
||||
enum_map = jak2_speaker_name_to_enum_val;
|
||||
break;
|
||||
case GameTextVersion::JAK3:
|
||||
enum_map = jak3_speaker_name_to_enum_val;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error(fmt::format("GameSubtitleBank: invalid game text version {}",
|
||||
get_text_version_name(m_text_version)));
|
||||
}
|
||||
if (enum_map.find(speaker_id) == enum_map.end()) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("'{}' speaker could not be found in the enum value mapping, update it or fix "
|
||||
"the invalid speaker!",
|
||||
speaker_id));
|
||||
}
|
||||
return u16(jak2_speaker_name_to_enum_val.at(speaker_id));
|
||||
return u16(enum_map.at(speaker_id));
|
||||
}
|
||||
|
||||
SubtitleMetadataFile dump_bank_meta_v2(const GameVersion game_version,
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "BinaryWriter.h"
|
||||
#include "FileUtil.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
|
||||
void build_dgo(const DgoDescription& description, const std::string& output_prefix) {
|
||||
BinaryWriter writer;
|
||||
// dgo header
|
||||
@@ -15,8 +17,14 @@ void build_dgo(const DgoDescription& description, const std::string& output_pref
|
||||
writer.add_cstr_len(description.dgo_name.c_str(), 60);
|
||||
|
||||
for (auto& obj : description.entries) {
|
||||
auto obj_data = file_util::read_binary_file(file_util::get_jak_project_dir() / "out" /
|
||||
output_prefix / "obj" / obj.file_name);
|
||||
// Ensure the directory exists
|
||||
const auto file_path =
|
||||
file_util::get_jak_project_dir() / "out" / output_prefix / "obj" / obj.file_name;
|
||||
if (!file_util::file_exists(file_path.string())) {
|
||||
lg::warn("tried to build a DGO with a file that doesn't exist: {}", file_path.string());
|
||||
continue;
|
||||
}
|
||||
auto obj_data = file_util::read_binary_file(file_path);
|
||||
// size
|
||||
writer.add<uint32_t>(obj_data.size());
|
||||
// name
|
||||
@@ -29,6 +37,9 @@ void build_dgo(const DgoDescription& description, const std::string& output_pref
|
||||
}
|
||||
}
|
||||
|
||||
writer.write_to_file(file_util::get_jak_project_dir() / "out" / output_prefix / "iso" /
|
||||
description.dgo_name);
|
||||
// Ensure the output directory exists
|
||||
const auto dgo_path =
|
||||
file_util::get_jak_project_dir() / "out" / output_prefix / "iso" / description.dgo_name;
|
||||
file_util::create_dir_if_needed_for_file(dgo_path);
|
||||
writer.write_to_file(dgo_path);
|
||||
}
|
||||
@@ -559,6 +559,8 @@ static std::vector<ReplaceInfo> s_replace_info_jak1 = {
|
||||
{"U~Y~-13H~+2V,~Z", "Ų"},
|
||||
{"U~Y~-18H~-10V-~Z", "Ū"},
|
||||
{"I~Y~-8H~+1V,~Z", "Į"},
|
||||
// czech specific
|
||||
{"U~Y~-23H~-5Vº~Z", "Ů"},
|
||||
|
||||
// tildes
|
||||
{"N~Y~-22H~-4V<TIL>~Z", "Ñ"},
|
||||
@@ -575,6 +577,8 @@ static std::vector<ReplaceInfo> s_replace_info_jak1 = {
|
||||
{"N~Y~-21H~-5V'~Z", "Ń"},
|
||||
{"S~Y~-21H~-5V'~Z", "Ś"},
|
||||
{"Z~Y~-21H~-5V'~Z", "Ź"},
|
||||
// czech specific
|
||||
{"Y~Y~-25H~-4V'~Z", "Ý"},
|
||||
|
||||
// double acute accents
|
||||
{"O~Y~-28H~-4V'~-9H'~Z", "Ő"}, // custom
|
||||
@@ -602,6 +606,22 @@ static std::vector<ReplaceInfo> s_replace_info_jak1 = {
|
||||
{"O~Y~-22H~-3V¨~Z", "ö"}, // dumb
|
||||
{"U~Y~-22H~-3V¨~Z", "Ü"},
|
||||
|
||||
// caron - Ǎ ǎ Ě ě Ǧ ǧ Ǐ ǐ Ǒ ǒ Ǔ ǔ Y̌ y̌
|
||||
{"A~Y~-20H~-4Vˇ~Z", "Ǎ"},
|
||||
{"E~Y~-20H~-5Vˇ~Z", "Ě"},
|
||||
{"G~Y~-20H~-5Vˇ~Z", "Ǧ"},
|
||||
{"I~Y~-19H~-5Vˇ~Z", "Ǐ"},
|
||||
{"O~Y~-20H~-4Vˇ~Z", "Ǒ"},
|
||||
{"U~Y~-24H~-3Vˇ~Z", "Ǔ"},
|
||||
{"Y~Y~-24H~-3Vˇ~Z", "Y̌"},
|
||||
// czech specific - Č Ň Ř Š Ž Ť
|
||||
{"C~Y~-25H~-9Vˇ~Z", "Č"},
|
||||
{"N~Y~-23H~-5Vˇ~Z", "Ň"},
|
||||
{"R~Y~-24H~-5Vˇ~Z", "Ř"},
|
||||
{"S~Y~-24H~-5Vˇ~Z", "Š"},
|
||||
{"T~Y~-23H~-5Vˇ~Z", "Ť"},
|
||||
{"Z~Y~-23H~-5Vˇ~Z", "Ž"},
|
||||
|
||||
// dakuten katakana
|
||||
{"~Yウ~Z゛", "ヴ"},
|
||||
{"~Yカ~Z゛", "ガ"},
|
||||
@@ -966,6 +986,10 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
|
||||
{"u~Y~-18H~-15V-~Z", "ū"},
|
||||
{"I~Y~-8H~+4V,~Z", "Į"},
|
||||
{"i~Y~-8H~+4V,~Z", "į"},
|
||||
// czech specific
|
||||
{"U~Y~-24H~-7Vº~Z", "Ů"},
|
||||
{"u~Y~-23H~-5Vº~Z", "ů"},
|
||||
{"t~Y~-7H~-21V,~Z", "ť"},
|
||||
|
||||
// tildes
|
||||
{"N~Y~-22H~-4V<TIL>~Z", "Ñ"},
|
||||
@@ -987,6 +1011,9 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
|
||||
{"u~Y~-24H~-3V'~Z", "ú"},
|
||||
{"Z~Y~-24H~-3V'~Z", "Ź"},
|
||||
{"z~Y~-24H~-3V'~Z", "ź"},
|
||||
// czech specific
|
||||
{"Y~Y~-26H~-5V'~Z", "Ý"},
|
||||
{"~+7Vy~-7V~Y~-24H~-3V'~Z", "ý"},
|
||||
|
||||
// circumflex
|
||||
{"A~Y~-20H~-4V^~Z", "Â"},
|
||||
@@ -1023,6 +1050,34 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
|
||||
{"U~Y~-25H~-8V¨~Z", "Ü"},
|
||||
{"u~Y~-24H~-3V¨~Z", "ü"},
|
||||
|
||||
// caron - Ǎ ǎ Ě ě Ǧ ǧ Ǐ ǐ Ǒ ǒ Ǔ ǔ Y̌ y̌
|
||||
{"A~Y~-25H~-9Vˇ~Z", "Ǎ"},
|
||||
{"a~Y~-24H~-5Vˇ~Z", "ǎ"},
|
||||
{"E~Y~-22H~-8Vˇ~Z", "Ě"},
|
||||
{"e~Y~-25H~-4Vˇ~Z", "ě"},
|
||||
{"G~Y~-24H~-8Vˇ~Z", "Ǧ"},
|
||||
{"~+7Vg~-7V~Y~-25H~-4Vˇ~Z", "ǧ"},
|
||||
{"I~Y~-19H~-8Vˇ~Z", "Ǐ"},
|
||||
{"i~Y~-19H~-8Vˇ~Z", "ǐ"},
|
||||
{"O~Y~-25H~-7Vˇ~Z", "Ǒ"},
|
||||
{"o~Y~-25H~-4Vˇ~Z", "ǒ"},
|
||||
{"U~Y~-25H~-6Vˇ~Z", "Ǔ"},
|
||||
{"u~Y~-24H~-3Vˇ~Z", "ǔ"},
|
||||
{"Y~Y~-25H~-5Vˇ~Z", "Y̌"},
|
||||
{"~+7Vy~-7V~Y~-25H~-3Vˇ~Z", "y̌"},
|
||||
// czech specific - Č č Ň ň Ř ř Š š Ž ž Ť
|
||||
{"C~Y~-25H~-9Vˇ~Z", "Č"},
|
||||
{"c~Y~-24H~-5Vˇ~Z", "č"},
|
||||
{"N~Y~-25H~-9Vˇ~Z", "Ň"},
|
||||
{"n~Y~-24H~-5Vˇ~Z", "ň"},
|
||||
{"R~Y~-25H~-9Vˇ~Z", "Ř"},
|
||||
{"r~Y~-22H~-5Vˇ~Z", "ř"},
|
||||
{"S~Y~-25H~-9Vˇ~Z", "Š"},
|
||||
{"s~Y~-22H~-5Vˇ~Z", "š"},
|
||||
{"T~Y~-24H~-7Vˇ~Z", "Ť"},
|
||||
{"Z~Y~-25H~-9Vˇ~Z", "Ž"},
|
||||
{"z~Y~-24H~-5Vˇ~Z", "ž"},
|
||||
|
||||
// dakuten katakana
|
||||
{"~Yウ~Z゛", "ヴ"},
|
||||
{"~Yカ~Z゛", "ガ"},
|
||||
@@ -1156,6 +1211,25 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
|
||||
"<FLAG_KOREA>"},
|
||||
{"~Y~1L<FLAG_PART_FILL>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~-11H~3L<FLAG_PART_JAPAN_SUN>~Z~+26H",
|
||||
"<FLAG_JAPAN>"},
|
||||
{"~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~7L<FLAG_PART_VERT_STRIPE_RIGHT>~]"
|
||||
"~-1H~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~+26H",
|
||||
"<FLAG_FINLAND>"},
|
||||
{"~Y~7L<FLAG_PART_FILL>~Z~5L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~5L<FLAG_PART_VERT_STRIPE_RIGHT>~]"
|
||||
"~-1H~Y~7L<FLAG_PART_FILL>~Z~5L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~+26H",
|
||||
"<FLAG_SWEDEN>"},
|
||||
{"~Y~3L<FLAG_PART_FILL>~Z~1L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~1L<FLAG_PART_VERT_STRIPE_RIGHT>~]"
|
||||
"~-1H~Y~3L<FLAG_PART_FILL>~Z~1L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~+26H",
|
||||
"<FLAG_DENMARK>"},
|
||||
{"~Y~1L<FLAG_PART_FILL>~Z~3L<FLAG_PART_TOP_BOTTOM_STRIPE>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~3L<FLAG_"
|
||||
"PART_TOP_BOTTOM_STRIPE>~Z~-19H~1L<FLAG_PART_VERT_STRIPE_MIDDLE>~Z~-23H~7L<FLAG_PART_VERT_"
|
||||
"STRIPE_RIGHT>~Z~-23H~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~"
|
||||
"+26H",
|
||||
"<FLAG_NORWAY>"},
|
||||
{"~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_PART_TOP_BOTTOM_STRIPE>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_"
|
||||
"PART_TOP_BOTTOM_STRIPE>~Z~-19H~1L<FLAG_PART_VERT_STRIPE_MIDDLE>~Z~-23H~3L<FLAG_PART_VERT_"
|
||||
"STRIPE_RIGHT>~Z~-23H~3L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~3L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~"
|
||||
"+26H",
|
||||
"<FLAG_ICELAND>"},
|
||||
|
||||
// weird stuff
|
||||
// - descenders
|
||||
|
||||
+399
-21
@@ -1,5 +1,7 @@
|
||||
#include "gltf_util.h"
|
||||
|
||||
#include "image_resize.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
|
||||
namespace gltf_util {
|
||||
@@ -44,6 +46,20 @@ std::vector<math::Vector<u8, 4>> extract_color_from_vec4_float(const u8* data,
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<math::Vector<u8, 4>> extract_color_from_vec3_float(const u8* data,
|
||||
u32 count,
|
||||
u32 stride) {
|
||||
std::vector<math::Vector<u8, 4>> result;
|
||||
result.reserve(count);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
math::Vector<float, 3> temp;
|
||||
memcpy(&temp, data, sizeof(math::Vector<float, 3>));
|
||||
data += stride;
|
||||
result.emplace_back(temp.x() * 255, temp.y() * 255, temp.z() * 255, 255);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert a GLTF color buffer (u16 format) to u8 colors.
|
||||
*/
|
||||
@@ -61,6 +77,16 @@ std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data,
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u8(const u8* data, u32 count, u32 stride) {
|
||||
std::vector<math::Vector<u8, 4>> result;
|
||||
result.reserve(count);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
result.push_back(math::Vector<u8, 4>(data[0], data[1], data[2], data[3]));
|
||||
data += stride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert a GLTF index buffer
|
||||
*/
|
||||
@@ -92,6 +118,74 @@ std::vector<u32> gltf_index_buffer(const tinygltf::Model& model,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<math::Matrix4f> extract_mat4(const tinygltf::Model& model, int accessor_idx) {
|
||||
const auto& accessor = model.accessors[accessor_idx];
|
||||
const auto& buffer_view = model.bufferViews[accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const u8* data_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
|
||||
const auto stride = accessor.ByteStride(buffer_view);
|
||||
const auto count = accessor.count;
|
||||
|
||||
// ASSERT(buffer_view.target == TINYGLTF_TARGET_ARRAY_BUFFER); // ??
|
||||
ASSERT(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
|
||||
ASSERT(accessor.type == TINYGLTF_TYPE_MAT4);
|
||||
|
||||
std::vector<math::Matrix4f> result(accessor.count);
|
||||
for (size_t x = 0; x < count; x++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
memcpy(&result[x](j, i), data_ptr + sizeof(float) * (i * 4 + j), sizeof(float));
|
||||
}
|
||||
}
|
||||
data_ptr += stride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JointsAndWeights convert_per_vertex_data(const math::Vector4f& weights,
|
||||
const math::Vector<u8, 4>& joints) {
|
||||
int discard_idx = -1;
|
||||
float discard_weight = 100;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (weights[i] < discard_weight) {
|
||||
discard_idx = i;
|
||||
discard_weight = weights[i];
|
||||
}
|
||||
}
|
||||
|
||||
JointsAndWeights ret;
|
||||
int dst = 0;
|
||||
float sum = 0;
|
||||
for (int src = 0; src < 4; src++) {
|
||||
if (src == discard_idx) {
|
||||
continue;
|
||||
}
|
||||
// this +1 is to account for align not existing in the gltf.
|
||||
ret.joints[dst] = joints[src] + 2;
|
||||
ret.weights[dst] = weights[src];
|
||||
sum += ret.weights[dst];
|
||||
dst++;
|
||||
}
|
||||
|
||||
ret.weights /= sum;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<JointsAndWeights> extract_and_flatten_joints_and_weights(
|
||||
const tinygltf::Model& model,
|
||||
const tinygltf::Primitive& prim) {
|
||||
auto weights =
|
||||
extract_vec<float, 4>(model, prim.attributes.at("WEIGHTS_0"), TINYGLTF_COMPONENT_TYPE_FLOAT);
|
||||
auto joints = extract_vec<u8, 4>(model, prim.attributes.at("JOINTS_0"),
|
||||
TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE);
|
||||
std::vector<JointsAndWeights> ret;
|
||||
ASSERT(weights.size() == joints.size());
|
||||
for (size_t i = 0; i < weights.size(); i++) {
|
||||
ret.push_back(convert_per_vertex_data(weights[i], joints[i]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Extract positions, colors, and normals from a mesh.
|
||||
*/
|
||||
@@ -148,19 +242,37 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
|
||||
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
|
||||
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
|
||||
const auto count = attrib_accessor.count;
|
||||
|
||||
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC4, "COLOR_0 wasn't vec4");
|
||||
std::vector<math::Vector<u8, 4>> colors;
|
||||
switch (attrib_accessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
colors = extract_color_from_vec4_float(data_ptr, count, byte_stride);
|
||||
|
||||
switch (attrib_accessor.type) {
|
||||
case TINYGLTF_TYPE_VEC4:
|
||||
switch (attrib_accessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
colors = extract_color_from_vec4_float(data_ptr, count, byte_stride);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
colors = extract_color_from_vec4_u8(data_ptr, count, byte_stride);
|
||||
break;
|
||||
default:
|
||||
lg::die("Unknown type for COLOR_0: {}", attrib_accessor.componentType);
|
||||
}
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride);
|
||||
case TINYGLTF_TYPE_VEC3:
|
||||
switch (attrib_accessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
colors = extract_color_from_vec3_float(data_ptr, count, byte_stride);
|
||||
break;
|
||||
default:
|
||||
lg::die("unkonwn component type for vec3 color {}", attrib_accessor.componentType);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
lg::die("Unknown component type for COLOR_0: {}", attrib_accessor.componentType);
|
||||
lg::die("unknown attribute type for color {}", attrib_accessor.type);
|
||||
}
|
||||
|
||||
vtx_colors.insert(vtx_colors.end(), colors.begin(), colors.end());
|
||||
}
|
||||
}
|
||||
@@ -213,7 +325,8 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
|
||||
normals = extract_vec3f(data_ptr, count, byte_stride);
|
||||
for (auto& nrm : normals) {
|
||||
math::Vector4f nrm4(nrm.x(), nrm.y(), nrm.z(), 0.f);
|
||||
nrm = (w_T_local * nrm4).xyz();
|
||||
// we found that normals aren't normalized if an object is scaled in blender.
|
||||
nrm = (w_T_local * nrm4).xyz().normalized();
|
||||
}
|
||||
ASSERT(normals.size() == result.size());
|
||||
} else {
|
||||
@@ -277,7 +390,7 @@ int texture_pool_debug_checker(TexturePool* pool) {
|
||||
}
|
||||
}
|
||||
|
||||
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex) {
|
||||
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex, int alpha_shift) {
|
||||
const auto& existing = pool->textures_by_name.find(tex.name);
|
||||
if (existing != pool->textures_by_name.end()) {
|
||||
lg::info("Reusing image: {}", tex.name);
|
||||
@@ -302,6 +415,72 @@ int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex) {
|
||||
tt.data.resize(tt.w * tt.h);
|
||||
ASSERT(tex.image.size() >= tt.data.size());
|
||||
memcpy(tt.data.data(), tex.image.data(), tt.data.size() * 4);
|
||||
|
||||
// adjust alpha colors for PS2/PC difference
|
||||
for (auto& color : tt.data) {
|
||||
u32 alpha = color >> 24;
|
||||
alpha >>= alpha_shift;
|
||||
color &= 0xff'ff'ff;
|
||||
color |= (alpha << 24);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
int texture_pool_add_envmap_control_texture(TexturePool* pool,
|
||||
const tinygltf::Model& model,
|
||||
int rgb_image_id,
|
||||
int mr_image_id,
|
||||
bool wrap_w,
|
||||
bool wrap_h) {
|
||||
const auto& existing = pool->envmap_textures_by_gltf_id.find({rgb_image_id, mr_image_id});
|
||||
if (existing != pool->envmap_textures_by_gltf_id.end()) {
|
||||
lg::info("Reusing envmap textures");
|
||||
return existing->second;
|
||||
}
|
||||
const auto& rgb_tex = model.images.at(rgb_image_id);
|
||||
const auto& mr_tex = model.images.at(mr_image_id);
|
||||
lg::info("new envmap texture {} {}", rgb_tex.name, mr_tex.name);
|
||||
ASSERT(rgb_tex.bits == 8);
|
||||
ASSERT(rgb_tex.component == 4);
|
||||
ASSERT(rgb_tex.pixel_type == TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE);
|
||||
|
||||
ASSERT(mr_tex.bits == 8);
|
||||
ASSERT(mr_tex.pixel_type == TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE);
|
||||
ASSERT(mr_tex.component == 4);
|
||||
|
||||
std::vector<u8> resized_mr_tex;
|
||||
const u8* mr_src;
|
||||
if (rgb_tex.width == mr_tex.width && rgb_tex.height == mr_tex.height) {
|
||||
mr_src = mr_tex.image.data();
|
||||
} else {
|
||||
resized_mr_tex.resize(rgb_tex.width * rgb_tex.height * 4);
|
||||
resize_rgba_image(resized_mr_tex.data(), rgb_tex.width, rgb_tex.height, mr_tex.image.data(),
|
||||
mr_tex.width, mr_tex.height, wrap_w, wrap_h);
|
||||
mr_src = resized_mr_tex.data();
|
||||
}
|
||||
|
||||
size_t idx = pool->textures_by_idx.size();
|
||||
pool->envmap_textures_by_gltf_id[{rgb_image_id, mr_image_id}] = idx;
|
||||
auto& tt = pool->textures_by_idx.emplace_back();
|
||||
tt.w = rgb_tex.width;
|
||||
tt.h = rgb_tex.height;
|
||||
tt.debug_name = rgb_tex.name;
|
||||
tt.debug_tpage_name = "custom-level";
|
||||
tt.load_to_pool = false;
|
||||
tt.combo_id = 0; // doesn't matter, not a pool tex
|
||||
tt.data.resize(tt.w * tt.h);
|
||||
ASSERT(rgb_tex.image.size() >= tt.data.size());
|
||||
memcpy(tt.data.data(), rgb_tex.image.data(), tt.data.size() * 4);
|
||||
|
||||
// adjust alpha from metallic channel
|
||||
for (size_t i = 0; i < tt.data.size(); i++) {
|
||||
u32 rgb = tt.data[i];
|
||||
u32 metal = mr_src[4 * i + 2] / 4;
|
||||
rgb &= 0xff'ff'ff;
|
||||
rgb |= (metal << 24);
|
||||
tt.data[i] = rgb;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -348,6 +527,15 @@ math::Vector4f vector4f_from_gltf(const std::vector<double>& in) {
|
||||
return math::Vector4f{in[0], in[1], in[2], in[3]};
|
||||
}
|
||||
|
||||
math::Matrix4f matrix_from_trs(const math::Vector3f& trans,
|
||||
const math::Vector4f& quat,
|
||||
const math::Vector3f& scale) {
|
||||
math::Matrix4f t = affine_translation(trans);
|
||||
math::Matrix4f r = affine_rot_qxyzw(quat);
|
||||
math::Matrix4f s = affine_scale(scale);
|
||||
return t * r * s;
|
||||
}
|
||||
|
||||
math::Matrix4f matrix_from_node(const tinygltf::Node& node) {
|
||||
if (!node.matrix.empty()) {
|
||||
math::Matrix4f result;
|
||||
@@ -430,22 +618,38 @@ void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
|
||||
}
|
||||
}
|
||||
|
||||
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler) {
|
||||
DrawMode mode = make_default_draw_mode();
|
||||
void setup_alpha_from_material(const tinygltf::Material& material, DrawMode* mode) {
|
||||
if (material.alphaMode == "OPAQUE") {
|
||||
mode->disable_ab();
|
||||
} else if (material.alphaMode == "MASK") {
|
||||
mode->enable_at();
|
||||
mode->set_alpha_test(DrawMode::AlphaTest::GEQUAL);
|
||||
mode->set_alpha_fail(GsTest::AlphaFail::KEEP);
|
||||
mode->set_aref(material.alphaCutoff * 127);
|
||||
} else if (material.alphaMode == "BLEND") {
|
||||
mode->enable_ab();
|
||||
mode->set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
|
||||
mode->set_depth_write_enable(false);
|
||||
} else {
|
||||
lg::die("Unknown GLTF alphaMode {}", material.alphaMode);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_draw_mode_from_sampler(const tinygltf::Sampler& sampler, DrawMode* mode) {
|
||||
if (sampler.magFilter == TINYGLTF_TEXTURE_FILTER_NEAREST) {
|
||||
ASSERT(sampler.minFilter == TINYGLTF_TEXTURE_FILTER_NEAREST);
|
||||
mode.set_filt_enable(false);
|
||||
ASSERT(sampler.minFilter == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST);
|
||||
mode->set_filt_enable(false);
|
||||
} else {
|
||||
ASSERT(sampler.minFilter != TINYGLTF_TEXTURE_FILTER_NEAREST);
|
||||
mode.set_filt_enable(true);
|
||||
mode->set_filt_enable(true);
|
||||
}
|
||||
|
||||
switch (sampler.wrapS) {
|
||||
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
|
||||
mode.set_clamp_s_enable(true);
|
||||
mode->set_clamp_s_enable(true);
|
||||
break;
|
||||
case TINYGLTF_TEXTURE_WRAP_REPEAT:
|
||||
mode.set_clamp_s_enable(false);
|
||||
mode->set_clamp_s_enable(false);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
@@ -453,15 +657,189 @@ DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler) {
|
||||
|
||||
switch (sampler.wrapT) {
|
||||
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
|
||||
mode.set_clamp_t_enable(true);
|
||||
mode->set_clamp_t_enable(true);
|
||||
break;
|
||||
case TINYGLTF_TEXTURE_WRAP_REPEAT:
|
||||
mode.set_clamp_t_enable(false);
|
||||
mode->set_clamp_t_enable(false);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
EnvmapSettings envmap_settings_from_gltf(const tinygltf::Material& mat) {
|
||||
EnvmapSettings settings;
|
||||
|
||||
ASSERT(mat.extensions.contains("KHR_materials_specular"));
|
||||
const auto& specular_extension = mat.extensions.at("KHR_materials_specular");
|
||||
ASSERT(specular_extension.Has("specularColorTexture"));
|
||||
|
||||
auto& texture = specular_extension.Get("specularColorTexture");
|
||||
ASSERT(texture.Has("index"));
|
||||
settings.texture_idx = texture.Get("index").Get<int>();
|
||||
return settings;
|
||||
}
|
||||
|
||||
bool material_has_envmap(const tinygltf::Material& mat) {
|
||||
return mat.extensions.contains("KHR_materials_specular");
|
||||
}
|
||||
|
||||
bool envmap_is_valid(const tinygltf::Material& mat) {
|
||||
auto envmap = material_has_envmap(mat);
|
||||
if (envmap && mat.pbrMetallicRoughness.metallicRoughnessTexture.index < 0) {
|
||||
lg::warn(fmt::format(
|
||||
"Material \"{}\" has specular property set, but is missing a metallic roughness texture, "
|
||||
"ignoring envmap!",
|
||||
mat.name));
|
||||
return false;
|
||||
}
|
||||
return envmap;
|
||||
}
|
||||
|
||||
std::optional<int> find_single_skin(const tinygltf::Model& model,
|
||||
const std::vector<NodeWithTransform>& all_nodes) {
|
||||
std::optional<int> skin_index;
|
||||
for (const auto& n : all_nodes) {
|
||||
const auto& node = model.nodes.at(n.node_idx);
|
||||
if (node.skin >= 0) {
|
||||
if (skin_index && *skin_index != node.skin) {
|
||||
lg::die("GLTF contains multiple skins, but only one skin per actor is supported.");
|
||||
}
|
||||
skin_index = node.skin;
|
||||
}
|
||||
}
|
||||
return skin_index;
|
||||
}
|
||||
|
||||
int get_joint_count(const tinygltf::Model& model, int skin_idx) {
|
||||
const auto& skin = model.skins.at(skin_idx);
|
||||
return skin.joints.size();
|
||||
}
|
||||
|
||||
std::vector<float> extract_floats(const tinygltf::Model& model, int accessor_idx) {
|
||||
const auto& accessor = model.accessors[accessor_idx];
|
||||
const auto& buffer_view = model.bufferViews[accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const u8* data_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
|
||||
const auto stride = accessor.ByteStride(buffer_view);
|
||||
const auto count = accessor.count;
|
||||
|
||||
// ASSERT(buffer_view.target == TINYGLTF_TARGET_ARRAY_BUFFER); // ??
|
||||
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
|
||||
lg::die("mismatched format, wanted {} but got {}", TINYGLTF_COMPONENT_TYPE_FLOAT,
|
||||
accessor.componentType);
|
||||
}
|
||||
ASSERT(accessor.type == TINYGLTF_TYPE_SCALAR);
|
||||
|
||||
std::vector<float> result(accessor.count);
|
||||
for (size_t x = 0; x < count; x++) {
|
||||
memcpy(&result[x], data_ptr, sizeof(float));
|
||||
data_ptr += stride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::size_t TieFullVertex::hash::operator()(const TieFullVertex& x) const {
|
||||
return tfrag3::PackedTieVertices::Vertex::hash()(x.vertex) ^ std::hash<u16>()(x.color_index);
|
||||
}
|
||||
|
||||
tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>& color_palette) {
|
||||
tfrag3::PackedTimeOfDay colors;
|
||||
colors.color_count = (color_palette.size() + 3) & (~3);
|
||||
colors.data.resize(colors.color_count * 8 * 4);
|
||||
for (u32 color_index = 0; color_index < color_palette.size(); color_index++) {
|
||||
for (u32 palette = 0; palette < 8; palette++) {
|
||||
for (u32 channel = 0; channel < 4; channel++) {
|
||||
colors.read(color_index, palette, channel) = color_palette[color_index][channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
void process_normal_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (tex_idx == -1) {
|
||||
lg::warn("Material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& tex = model.textures[tex_idx];
|
||||
ASSERT(tex.sampler >= 0);
|
||||
ASSERT(tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
|
||||
const auto& img = model.images[tex.source];
|
||||
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
|
||||
};
|
||||
|
||||
void process_envmap_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Envmap draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
int base_tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (base_tex_idx == -1) {
|
||||
lg::warn("Envmap material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& base_tex = model.textures[base_tex_idx];
|
||||
ASSERT(base_tex.sampler >= 0);
|
||||
ASSERT(base_tex.source >= 0);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(base_tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
const auto& roughness_tex =
|
||||
model.textures.at(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
|
||||
ASSERT(roughness_tex.sampler >= 0);
|
||||
ASSERT(roughness_tex.source >= 0);
|
||||
|
||||
draw.tree_tex_id =
|
||||
tex_offset + gltf_util::texture_pool_add_envmap_control_texture(
|
||||
&out.tex_pool, model, base_tex.source, roughness_tex.source,
|
||||
!draw.mode.get_clamp_s_enable(), !draw.mode.get_clamp_t_enable());
|
||||
|
||||
// now, setup envmap draw:
|
||||
auto envmap_settings = gltf_util::envmap_settings_from_gltf(mat);
|
||||
const auto& envmap_tex = model.textures[envmap_settings.texture_idx];
|
||||
ASSERT(envmap_tex.sampler >= 0);
|
||||
ASSERT(envmap_tex.source >= 0);
|
||||
auto env_mode = gltf_util::make_default_draw_mode();
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(envmap_tex.sampler), &env_mode);
|
||||
eff.envmap_texture = tex_offset + gltf_util::texture_pool_add_texture(
|
||||
&out.tex_pool, model.images[envmap_tex.source]);
|
||||
env_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
||||
env_mode.enable_ab();
|
||||
eff.envmap_mode = env_mode;
|
||||
};
|
||||
|
||||
} // namespace gltf_util
|
||||
+148
-5
@@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/custom_data/Tfrag3Data.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/math/Vector.h"
|
||||
|
||||
#include "third-party/tiny_gltf/tiny_gltf.h"
|
||||
@@ -28,10 +30,19 @@ std::vector<u32> index_list_to_u32(const u8* data, u32 num_verts, u32 offset, u3
|
||||
return result;
|
||||
}
|
||||
|
||||
struct JointsAndWeights {
|
||||
math::Vector<u8, 3> joints = math::Vector<u8, 3>::zero();
|
||||
math::Vector<float, 3> weights = math::Vector<float, 3>::zero();
|
||||
};
|
||||
|
||||
std::vector<math::Vector3f> extract_vec3f(const u8* data, u32 count, u32 stride);
|
||||
std::vector<math::Vector2f> extract_vec2f(const u8* data, u32 count, u32 stride);
|
||||
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data, u32 count, u32 stride);
|
||||
std::vector<u32> gltf_index_buffer(const tinygltf::Model& model, int indices_idx, u32 index_offset);
|
||||
std::vector<math::Matrix4f> extract_mat4(const tinygltf::Model& model, int accessor_idx);
|
||||
std::vector<JointsAndWeights> extract_and_flatten_joints_and_weights(
|
||||
const tinygltf::Model& model,
|
||||
const tinygltf::Primitive& prim);
|
||||
|
||||
struct ExtractedVertices {
|
||||
std::vector<tfrag3::PreloadedVertex> vtx;
|
||||
@@ -50,9 +61,16 @@ DrawMode make_default_draw_mode();
|
||||
struct TexturePool {
|
||||
std::unordered_map<std::string, int> textures_by_name;
|
||||
std::vector<tfrag3::Texture> textures_by_idx;
|
||||
std::map<std::pair<int, int>, int> envmap_textures_by_gltf_id;
|
||||
};
|
||||
|
||||
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex);
|
||||
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex, int alpha_shift = 1);
|
||||
int texture_pool_add_envmap_control_texture(TexturePool* pool,
|
||||
const tinygltf::Model& model,
|
||||
int rgb_image_id,
|
||||
int mr_image_id,
|
||||
bool wrap_w,
|
||||
bool wrap_h);
|
||||
int texture_pool_debug_checker(TexturePool* pool);
|
||||
|
||||
struct NodeWithTransform {
|
||||
@@ -60,12 +78,137 @@ struct NodeWithTransform {
|
||||
math::Matrix4f w_T_node;
|
||||
};
|
||||
|
||||
void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
|
||||
std::vector<tfrag3::PreloadedVertex>& vertices_out,
|
||||
std::vector<u32>& old_to_new_out);
|
||||
struct TieFullVertex {
|
||||
tfrag3::PackedTieVertices::Vertex vertex;
|
||||
u16 color_index = 0;
|
||||
struct hash {
|
||||
std::size_t operator()(const TieFullVertex& x) const;
|
||||
};
|
||||
|
||||
bool operator==(const TieFullVertex& other) const {
|
||||
return vertex == other.vertex && color_index == other.color_index;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void dedup_vertices(const std::vector<T>& vertices_in,
|
||||
std::vector<T>& vertices_out,
|
||||
std::vector<u32>& old_to_new_out) {
|
||||
ASSERT(vertices_out.empty());
|
||||
ASSERT(old_to_new_out.empty());
|
||||
old_to_new_out.resize(vertices_in.size(), -1);
|
||||
|
||||
std::unordered_map<T, u32, typename T::hash> vtx_to_new;
|
||||
|
||||
for (size_t in_idx = 0; in_idx < vertices_in.size(); in_idx++) {
|
||||
auto& vtx = vertices_in[in_idx];
|
||||
const auto& lookup = vtx_to_new.find(vtx);
|
||||
if (lookup == vtx_to_new.end()) {
|
||||
// first time seeing this one
|
||||
size_t new_idx = vertices_out.size();
|
||||
vertices_out.push_back(vtx);
|
||||
old_to_new_out[in_idx] = new_idx;
|
||||
vtx_to_new[vtx] = new_idx;
|
||||
} else {
|
||||
old_to_new_out[in_idx] = lookup->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NodeWithTransform> flatten_nodes_from_all_scenes(const tinygltf::Model& model);
|
||||
|
||||
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler);
|
||||
void setup_alpha_from_material(const tinygltf::Material& material, DrawMode* mode);
|
||||
void setup_draw_mode_from_sampler(const tinygltf::Sampler& sampler, DrawMode* mode);
|
||||
|
||||
struct EnvmapSettings {
|
||||
int texture_idx = -1;
|
||||
};
|
||||
|
||||
EnvmapSettings envmap_settings_from_gltf(const tinygltf::Material& mat);
|
||||
bool material_has_envmap(const tinygltf::Material& mat);
|
||||
bool envmap_is_valid(const tinygltf::Material& mat);
|
||||
|
||||
/*!
|
||||
* Find the index of the skin for this model. Returns nullopt if there is no skin, the index of the
|
||||
* skin if there is a single skin used, or fatal error if there are multiple skins.
|
||||
*/
|
||||
std::optional<int> find_single_skin(const tinygltf::Model& model,
|
||||
const std::vector<NodeWithTransform>& all_nodes);
|
||||
int get_joint_count(const tinygltf::Model& model, int skin_idx);
|
||||
|
||||
template <typename T, int n>
|
||||
std::vector<math::Vector<T, n>> extract_vec(const tinygltf::Model& model,
|
||||
int accessor_idx,
|
||||
int format) {
|
||||
const auto& accessor = model.accessors[accessor_idx];
|
||||
const auto& buffer_view = model.bufferViews[accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const u8* data_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
|
||||
const auto stride = accessor.ByteStride(buffer_view);
|
||||
const auto count = accessor.count;
|
||||
|
||||
// ASSERT(buffer_view.target == TINYGLTF_TARGET_ARRAY_BUFFER); // ??
|
||||
if (accessor.componentType != format) {
|
||||
lg::die("mismatched format, wanted {} but got {}", format, accessor.componentType);
|
||||
}
|
||||
ASSERT(accessor.componentType == format);
|
||||
switch (n) {
|
||||
case 3:
|
||||
ASSERT(accessor.type == TINYGLTF_TYPE_VEC3);
|
||||
break;
|
||||
case 4:
|
||||
ASSERT(accessor.type == TINYGLTF_TYPE_VEC4);
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
std::vector<math::Vector<T, n>> result(accessor.count);
|
||||
for (size_t x = 0; x < count; x++) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
memcpy(&result[x][i], data_ptr + sizeof(T) * i, sizeof(T));
|
||||
}
|
||||
data_ptr += stride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<float> extract_floats(const tinygltf::Model& model, int accessor_idx);
|
||||
math::Matrix4f matrix_from_trs(const math::Vector3f& trans,
|
||||
const math::Vector4f& quat,
|
||||
const math::Vector3f& scale);
|
||||
|
||||
tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>& color_palette);
|
||||
|
||||
struct MercExtractData {
|
||||
TexturePool tex_pool;
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::PreloadedVertex> new_vertices;
|
||||
std::vector<math::Vector<u8, 4>> new_colors;
|
||||
std::vector<math::Vector3f> normals;
|
||||
std::vector<JointsAndWeights> joints_and_weights;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
// Data produced by loading a replacement model
|
||||
struct MercSwapData {
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::MercVertex> new_vertices;
|
||||
std::vector<tfrag3::Texture> new_textures;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
void process_normal_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_);
|
||||
void process_envmap_merc_draw(const tinygltf::Model& model,
|
||||
MercExtractData& out,
|
||||
u32 tex_offset,
|
||||
tfrag3::MercEffect& eff,
|
||||
int mat_idx,
|
||||
const tfrag3::MercDraw& d_);
|
||||
|
||||
} // namespace gltf_util
|
||||
@@ -0,0 +1,101 @@
|
||||
#include "image_resize.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "common/math/Vector.h"
|
||||
|
||||
namespace {
|
||||
struct BilinearSample {
|
||||
int i0, i1;
|
||||
double w0, w1;
|
||||
};
|
||||
|
||||
BilinearSample bilinear(int src_i, double sample, bool wrap) {
|
||||
BilinearSample result;
|
||||
|
||||
const double px_size = 1. / double(src_i);
|
||||
const double px_center_f = (sample - 0.5 * px_size) / px_size;
|
||||
const int px_floor = std::floor(px_center_f);
|
||||
const double frac = px_center_f - double(px_floor);
|
||||
|
||||
if (px_center_f < 0) { // off the bottom
|
||||
if (wrap) {
|
||||
// wrap around!
|
||||
result.i0 = 0;
|
||||
result.i1 = src_i - 1;
|
||||
result.w1 = -px_center_f;
|
||||
result.w0 = 1. - result.w1;
|
||||
} else {
|
||||
// clamp to edge
|
||||
result.i0 = 0;
|
||||
result.i1 = 0;
|
||||
result.w0 = 1;
|
||||
result.w1 = 0;
|
||||
}
|
||||
} else if (px_floor >= (src_i - 1)) { // off the top
|
||||
if (wrap) {
|
||||
result.i0 = src_i - 1;
|
||||
result.i1 = 0;
|
||||
result.w0 = 1. - frac;
|
||||
result.w1 = frac;
|
||||
} else {
|
||||
// clamp
|
||||
result.i0 = src_i - 1;
|
||||
result.i1 = src_i - 1;
|
||||
result.w0 = 1;
|
||||
result.w1 = 0;
|
||||
}
|
||||
} else {
|
||||
result.i0 = px_floor;
|
||||
result.i1 = px_floor + 1;
|
||||
result.w0 = 1. - frac;
|
||||
result.w1 = frac;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
math::Vector4<u8> sample1(const u8* src, int w, int h, int x, int y) {
|
||||
(void)h;
|
||||
int offset = 4 * (y * w + x);
|
||||
return math::Vector4<u8>(src[offset], src[offset + 1], src[offset + 2], src[offset + 3]);
|
||||
}
|
||||
|
||||
math::Vector4<u8> sample_bilinear(const u8* src,
|
||||
int w,
|
||||
int h,
|
||||
const BilinearSample& x,
|
||||
const BilinearSample& y) {
|
||||
auto p00 = sample1(src, w, h, x.i0, y.i0).cast<double>();
|
||||
auto p01 = sample1(src, w, h, x.i0, y.i1).cast<double>();
|
||||
auto p10 = sample1(src, w, h, x.i1, y.i0).cast<double>();
|
||||
auto p11 = sample1(src, w, h, x.i1, y.i1).cast<double>();
|
||||
auto p_interp = (p00 * x.w0 * y.w0 + p01 * x.w0 * y.w1 + p10 * x.w1 * y.w0 + p11 * x.w1 * y.w1);
|
||||
return p_interp.cast<u8>();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void resize_rgba_image(u8* dst,
|
||||
int dst_w,
|
||||
int dst_h,
|
||||
const u8* src,
|
||||
int src_w,
|
||||
int src_h,
|
||||
bool wrap_w,
|
||||
bool wrap_h) {
|
||||
const double dst_px_h = 1. / dst_h;
|
||||
const double dst_px_w = 1. / dst_w;
|
||||
for (int h = 0; h < dst_h; h++) {
|
||||
const float h_pos = (double(h) + 0.5) * dst_px_h;
|
||||
const auto h_sample = bilinear(src_h, h_pos, wrap_h);
|
||||
for (int w = 0; w < dst_w; w++) {
|
||||
const float w_pos = (double(w) + 0.5) * dst_px_w;
|
||||
const auto w_sample = bilinear(src_w, w_pos, wrap_w);
|
||||
auto result = sample_bilinear(src, src_w, src_h, w_sample, h_sample);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
*dst = result[i];
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
void resize_rgba_image(u8* dst,
|
||||
int dst_w,
|
||||
int dst_h,
|
||||
const u8* src,
|
||||
int src_w,
|
||||
int src_h,
|
||||
bool wrap_w,
|
||||
bool wrap_h);
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/string_util.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// clang-format off
|
||||
@@ -104,3 +112,27 @@ void setup_cpu_info() {
|
||||
CpuInfo& get_cpu_info() {
|
||||
return gCpuInfo;
|
||||
}
|
||||
|
||||
std::optional<double> get_macos_major_version() {
|
||||
#ifndef __APPLE__
|
||||
return {};
|
||||
#else
|
||||
char buffer[128];
|
||||
size_t bufferlen = 128;
|
||||
auto ok = sysctlbyname("kern.osproductversion", &buffer, &bufferlen, NULL, 0);
|
||||
if (ok != 0) {
|
||||
lg::warn("Unable to check for `kern.osproductversion` to determine macOS version");
|
||||
return {};
|
||||
}
|
||||
try {
|
||||
std::string macos_major_version = buffer;
|
||||
if (str_util::contains(buffer, ".")) {
|
||||
macos_major_version = str_util::split_string(macos_major_version, ".")[0];
|
||||
}
|
||||
return std::stod(macos_major_version);
|
||||
} catch (std::exception& e) {
|
||||
lg::error("Error occured when attempting to convert sysctl value {} to number", buffer);
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
size_t get_peak_rss();
|
||||
@@ -16,3 +17,5 @@ struct CpuInfo {
|
||||
};
|
||||
|
||||
CpuInfo& get_cpu_info();
|
||||
|
||||
std::optional<double> get_macos_major_version();
|
||||
@@ -90,6 +90,9 @@ def draw_func_ob(self, context):
|
||||
layout = self.layout
|
||||
ob = context.object
|
||||
layout.prop(ob, "set_invisible")
|
||||
layout.prop(ob, "enable_custom_weights")
|
||||
layout.prop(ob, "copy_eye_draws")
|
||||
layout.prop(ob, "copy_mod_draws")
|
||||
layout.prop(ob, "set_collision")
|
||||
if (ob.set_collision):
|
||||
layout.prop(ob, "ignore")
|
||||
@@ -116,6 +119,9 @@ def register():
|
||||
|
||||
bpy.types.Object.set_invisible = bpy.props.BoolProperty(name="Invisible")
|
||||
bpy.types.Object.set_collision = bpy.props.BoolProperty(name="Apply Collision Properties")
|
||||
bpy.types.Object.enable_custom_weights = bpy.props.BoolProperty(name="Use Custom Bone Weights")
|
||||
bpy.types.Object.copy_eye_draws = bpy.props.BoolProperty(name="Copy Eye Draws")
|
||||
bpy.types.Object.copy_mod_draws = bpy.props.BoolProperty(name="Copy Mod Draws")
|
||||
bpy.types.Object.ignore = bpy.props.BoolProperty(name="ignore")
|
||||
bpy.types.Object.noedge = bpy.props.BoolProperty(name="No-Edge")
|
||||
bpy.types.Object.noentity = bpy.props.BoolProperty(name="No-Entity")
|
||||
|
||||
@@ -67,21 +67,60 @@
|
||||
"custom_models": ["test-actor"],
|
||||
|
||||
// Any textures you want to include in your custom level. This is mainly useful for things such as the zoomer HUD,
|
||||
// which is not in the common level files and has no art group associated with it.
|
||||
// sky textures and cases where you want to use objects drawn with the generic renderer,
|
||||
// which also requires you to set a texture remap table and a list of tpages.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
// The format is ["tpage-name", "texture-name1", "texture-name2", ...].
|
||||
// If you want all textures from a tpage, you can just do ["tpage-name"].
|
||||
"textures": [
|
||||
// all textures required for the zoomer HUD
|
||||
// "zoomerhud",
|
||||
// "zoomerhud-dial",
|
||||
// "zoomerhud-main-02",
|
||||
// "zoomerhud-main-03",
|
||||
// "zoomerhud-pieslice",
|
||||
// "zoomerhud-heatbg-01",
|
||||
// "zoomerhud-main-03arrow",
|
||||
// "zoomerhud-main-03knob"
|
||||
// Zoomer HUD textures
|
||||
// ["zoomerhud"],
|
||||
// Sandover sky textures
|
||||
["village1-vis-alpha"]
|
||||
],
|
||||
|
||||
// Which vanilla level's texture remap table to use.
|
||||
// This is needed if you want to have proper textures for objects that are drawn using generic, such as
|
||||
// dark eco pools or dying enemies. If you choose to use this,
|
||||
// the order of art groups and tpages in your level's .gd MUST match the vanilla level's for the textures to work.
|
||||
"tex_remap": "village1",
|
||||
|
||||
// Which sky to use for your custom level. This needs to be the name of a vanilla level with sky textures.
|
||||
// Your level's mood update needs to be set up to copy the sky texture (update-mood-default already handles this as an example).
|
||||
// You also need to add a specific tpage to your level .gd depending on the level you chose:
|
||||
// training: tpage-1308.go
|
||||
// village1: tpage-401.go
|
||||
// beach: tpage-215.go
|
||||
// jungle: tpage-388.go
|
||||
// misty: tpage-520.go
|
||||
// firecanyon: tpage-1123.go
|
||||
// village2: tpage-921.go
|
||||
// rolling: tpage-925.go
|
||||
// sunkenb: tpage-162.go
|
||||
// swamp: tpage-630.go
|
||||
// ogre: tpage-1117.go
|
||||
// village3: tpage-1194.go
|
||||
// snow: tpage-712.go
|
||||
// finalboss: tpage-1418.go
|
||||
// The tpage you choose also has to be in the alpha (4th) slot in the "tpages" list below.
|
||||
"sky": "village1",
|
||||
|
||||
// Any texture pages that are added to the level's "texture-ids" array.
|
||||
// These will be logged in and linked as part of level loading.
|
||||
// There are five tpage categories, in this order:
|
||||
// - tfrag
|
||||
// - pris
|
||||
// - shrub
|
||||
// - alpha
|
||||
// - water
|
||||
// This is also (with the exception of levels that use the zoomer) the order that the tpages are listed in in the vanilla .gd files.
|
||||
// You need to also add these to your level .gd as well.
|
||||
// Sky textures use the alpha slot.
|
||||
// If this is empty and "tex_remap" and "sky" are the same level, this will be auto-filled with the tpages from the
|
||||
// corresponding level (check its .gd file for the art group/tpage order to copy over).
|
||||
"tpages": [],
|
||||
|
||||
// Ambients you want to use in your custom level. Ambients can be used for various things like changing the music variation (flava),
|
||||
// adding ambient sounds, level name hints, etc.
|
||||
"ambients": [
|
||||
@@ -97,10 +136,10 @@
|
||||
}
|
||||
],
|
||||
|
||||
"actors" : [
|
||||
"actors": [
|
||||
{
|
||||
"trans": [-21.6238, 20.0496, 17.1191], // translation
|
||||
"etype": "fuel-cell", // actor type
|
||||
"etype": "fuel-cell", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-21.6238, 19.3496, 17.1191, 10], // bounding sphere
|
||||
@@ -111,11 +150,11 @@
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-15.2818, 15.2461, 17.1360], // translation
|
||||
"etype": "crate", // actor type
|
||||
"trans": [-15.2818, 15.2461, 17.136], // translation
|
||||
"etype": "crate", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"bsphere": [-15.2818, 15.2461, 17.136, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"crate-type": "'steel",
|
||||
@@ -124,18 +163,18 @@
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"trans": [-5.463, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"bsphere": [-5.463, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-eco"
|
||||
}
|
||||
},
|
||||
{
|
||||
"trans": [-5.41, 3.5, 28.42], // translation
|
||||
"etype": "test-actor", // actor type
|
||||
"etype": "test-actor", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-7.41, 3.5, 28.42, 10], // bounding sphere
|
||||
@@ -154,4 +193,4 @@
|
||||
// }
|
||||
// }
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,14 @@
|
||||
|
||||
;; the actual file name still needs to be 8.3
|
||||
("TSZ.DGO"
|
||||
("static-screen.o"
|
||||
"test-zone-obs.o"
|
||||
("test-zone-obs.o"
|
||||
"tpage-398.go"
|
||||
"tpage-400.go"
|
||||
"tpage-399.go"
|
||||
"tpage-401.go"
|
||||
"tpage-1470.go"
|
||||
"plat-ag.go"
|
||||
"test-actor-ag.go"
|
||||
"test-zone.go"
|
||||
))
|
||||
)
|
||||
)
|
||||
@@ -49,27 +49,33 @@
|
||||
// adds a 'type' tag (using the "symbol" and "string" lump types works the same way):
|
||||
// "spawn-types": ["type", "spyder", "juicer"]
|
||||
|
||||
// The base actor id for your custom level. If you have multiple levels, this should be unique!
|
||||
"base_id": 100,
|
||||
// The base actor id for your custom level. If you have multiple levels, this should be unique!
|
||||
"base_id": 100,
|
||||
|
||||
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
|
||||
// Removed so that the release builds don't have to double-decompile the game
|
||||
// "art_groups": ["prsn-torture-ag"],
|
||||
|
||||
// Any textures you want to include in your custom level.
|
||||
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
"textures": [],
|
||||
// If you have any custom models in the "custom_assets/jak2/models/custom_levels" folder that you want to use in your level, add them to this list.
|
||||
// Note: Like with art groups, these should also be added to your level's .gd file.
|
||||
"custom_models": ["test-actor"],
|
||||
|
||||
"actors" : [
|
||||
// Any textures you want to include in your custom level.
|
||||
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
// The format is ["tpage-name", "texture-name1", "texture-name2", ...].
|
||||
// If you want all textures from a tpage, you can just do ["tpage-name"].
|
||||
"textures": [],
|
||||
|
||||
"actors": [
|
||||
{
|
||||
"trans": [-15.2818, 15.2461, 17.1360], // translation
|
||||
"etype": "crate", // actor type
|
||||
"trans": [-15.2818, 15.2461, 17.136], // translation
|
||||
"etype": "crate", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"kill_mask": 0,
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"bsphere": [-15.2818, 15.2461, 17.136, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"eco-info": ["eco-info", "(pickup-type health)", 2]
|
||||
@@ -77,12 +83,12 @@
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"trans": [-5.463, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"kill_mask": 0,
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"bsphere": [-5.463, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-eco"
|
||||
}
|
||||
@@ -90,13 +96,24 @@
|
||||
|
||||
{
|
||||
"trans": [-7.41, 13.5, 28.42], // translation
|
||||
"etype": "prsn-torture", // actor type
|
||||
"etype": "prsn-torture", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-7.41, 13.5, 28.42, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-torture"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [5.41, 3.5, 28.42], // translation
|
||||
"etype": "test-actor", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [5.41, 3.5, 28.42, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-actor"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,7 @@
|
||||
("TSZ.DGO"
|
||||
(
|
||||
"prison-obs.o"
|
||||
"test-zone-obs.o"
|
||||
"test-actor-ag.go"
|
||||
"test-zone.go"
|
||||
))
|
||||
Binary file not shown.
@@ -49,26 +49,32 @@
|
||||
// adds a 'type' tag (using the "symbol" and "string" lump types works the same way):
|
||||
// "spawn-types": ["type", "spyder", "juicer"]
|
||||
|
||||
// The base actor id for your custom level. If you have multiple levels, this should be unique!
|
||||
"base_id": 100,
|
||||
// The base actor id for your custom level. If you have multiple levels, this should be unique!
|
||||
"base_id": 100,
|
||||
|
||||
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
|
||||
// "art_groups": [],
|
||||
|
||||
// Any textures you want to include in your custom level.
|
||||
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
// "textures": [],
|
||||
// If you have any custom models in the "custom_assets/jak3/models/custom_levels" folder that you want to use in your level, add them to this list.
|
||||
// Note: Like with art groups, these should also be added to your level's .gd file.
|
||||
"custom_models": ["test-actor"],
|
||||
|
||||
"actors" : [
|
||||
// Any textures you want to include in your custom level.
|
||||
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
// The format is ["tpage-name", "texture-name1", "texture-name2", ...].
|
||||
// If you want all textures from a tpage, you can just do ["tpage-name"].
|
||||
"textures": [],
|
||||
|
||||
"actors": [
|
||||
{
|
||||
"trans": [-15.2818, 15.2461, 17.1360], // translation
|
||||
"etype": "crate", // actor type
|
||||
"trans": [-15.2818, 15.2461, 17.136], // translation
|
||||
"etype": "crate", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"kill_mask": 0,
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"bsphere": [-15.2818, 15.2461, 17.136, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"eco-info": ["eco-info", "(pickup-type gem)", 1]
|
||||
@@ -76,15 +82,26 @@
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"trans": [-5.463, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"kill_mask": 0,
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"bsphere": [-5.463, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-eco"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [5.41, 3.5, 28.42], // translation
|
||||
"etype": "test-actor", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [5.41, 3.5, 28.42, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-actor"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
;; the actual file name still needs to be 8.3
|
||||
("TSZ.DGO"
|
||||
("test-zone.go"
|
||||
)
|
||||
)
|
||||
(
|
||||
"test-zone-obs.o"
|
||||
"test-actor-ag.go"
|
||||
"test-zone.go"
|
||||
))
|
||||
Binary file not shown.
@@ -149,6 +149,11 @@ SimpleAtom SimpleAtom::make_static_address(int static_label_id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void SimpleAtom::mark_as_no_hex() {
|
||||
ASSERT(is_int() && !is_integer_promoted_to_float());
|
||||
m_no_display_int_as_hex = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Mark this atom as a float. It will be printed as a float.
|
||||
* This can only be applied to an "integer" atom.
|
||||
@@ -194,6 +199,8 @@ goos::Object SimpleAtom::to_form(const std::vector<DecompilerLabel>& labels, con
|
||||
if (std::abs(m_int) > INT32_MAX) {
|
||||
u64 v = m_int;
|
||||
return pretty_print::to_symbol(fmt::format("#x{:x}", v));
|
||||
} else if (m_no_display_int_as_hex) {
|
||||
return goos::Object::make_integer_no_hex(m_int);
|
||||
} else {
|
||||
return goos::Object::make_integer(m_int);
|
||||
}
|
||||
@@ -346,6 +353,8 @@ std::string get_simple_expression_op_name(SimpleExpression::Kind kind) {
|
||||
return "pcypld";
|
||||
case SimpleExpression::Kind::VECTOR_PLUS:
|
||||
return "vector+!2";
|
||||
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
|
||||
return "vector-xyz-product!";
|
||||
case SimpleExpression::Kind::VECTOR_MINUS:
|
||||
return "vector-!2";
|
||||
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
|
||||
@@ -420,6 +429,7 @@ int get_simple_expression_arg_count(SimpleExpression::Kind kind) {
|
||||
case SimpleExpression::Kind::VECTOR_MINUS:
|
||||
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
|
||||
case SimpleExpression::Kind::VECTOR_CROSS:
|
||||
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
|
||||
return 3;
|
||||
case SimpleExpression::Kind::SUBU_L32_S7:
|
||||
return 1;
|
||||
|
||||
@@ -190,6 +190,7 @@ class SimpleAtom {
|
||||
ASSERT(is_sym_ptr() || is_sym_val() || is_sym_val_ptr());
|
||||
return m_string;
|
||||
}
|
||||
void mark_as_no_hex();
|
||||
void mark_as_float();
|
||||
bool is_integer_promoted_to_float() const;
|
||||
float get_integer_promoted_to_float() const;
|
||||
@@ -200,6 +201,7 @@ class SimpleAtom {
|
||||
s64 m_int = -1; // for integer constant and static address label id
|
||||
RegisterAccess m_variable;
|
||||
bool m_display_int_as_float = false;
|
||||
bool m_no_display_int_as_hex = false;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -254,6 +256,7 @@ class SimpleExpression {
|
||||
VECTOR_PLUS,
|
||||
VECTOR_MINUS,
|
||||
VECTOR_FLOAT_PRODUCT,
|
||||
VECTOR_XYZ_PRODUCT, // vector*!, elementwise xyz, jak3 only
|
||||
VECTOR_CROSS,
|
||||
SUBU_L32_S7, // use SUBU X, src0, s7 to check if lower 32-bits are s7.
|
||||
VECTOR_3_DOT,
|
||||
|
||||
@@ -238,6 +238,7 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
|
||||
case Kind::VECTOR_PLUS:
|
||||
case Kind::VECTOR_MINUS:
|
||||
case Kind::VECTOR_CROSS:
|
||||
case Kind::VECTOR_XYZ_PRODUCT:
|
||||
return TP_Type::make_from_ts("vector");
|
||||
case Kind::VECTOR_FLOAT_PRODUCT:
|
||||
return TP_Type::make_from_ts("vector");
|
||||
|
||||
+20
-2
@@ -281,12 +281,19 @@ void LoadSourceElement::get_modified_regs(RegSet& regs) const {
|
||||
/////////////////////////////
|
||||
|
||||
SimpleAtomElement::SimpleAtomElement(const SimpleAtom& atom, bool omit_var_cast)
|
||||
: m_atom(atom), m_omit_var_cast(omit_var_cast) {
|
||||
: m_atom(atom), m_omit_var_cast(omit_var_cast), m_no_hex(false) {
|
||||
if (m_omit_var_cast) {
|
||||
ASSERT(atom.is_var());
|
||||
}
|
||||
}
|
||||
|
||||
SimpleAtomElement::SimpleAtomElement(int int_val, bool no_hex)
|
||||
: m_atom(SimpleAtom::make_int_constant(int_val)), m_omit_var_cast(false), m_no_hex(no_hex) {
|
||||
if (m_no_hex) {
|
||||
m_atom.mark_as_no_hex();
|
||||
}
|
||||
}
|
||||
|
||||
goos::Object SimpleAtomElement::to_form_internal(const Env& env) const {
|
||||
if (m_omit_var_cast) {
|
||||
return m_atom.var().to_form(env, RegisterAccess::Print::AS_VARIABLE_NO_CAST);
|
||||
@@ -1851,6 +1858,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
|
||||
return "vector-!";
|
||||
case FixedOperatorKind::VECTOR_PLUS:
|
||||
return "vector+!";
|
||||
case FixedOperatorKind::VECTOR_XYZ_PRODUCT:
|
||||
return "vector*!";
|
||||
case FixedOperatorKind::VECTOR_CROSS:
|
||||
return "vector-cross!";
|
||||
case FixedOperatorKind::VECTOR_FLOAT_PRODUCT:
|
||||
@@ -2139,6 +2148,15 @@ DerefToken to_token(const FieldReverseLookupOutput::Token& in) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DerefToken> to_tokens(const std::vector<FieldReverseLookupOutput::Token>& in) {
|
||||
std::vector<DerefToken> ret;
|
||||
ret.reserve(in.size());
|
||||
for (auto& x : in) {
|
||||
ret.push_back(to_token(x));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
DerefElement::DerefElement(Form* base, bool is_addr_of, DerefToken token)
|
||||
: m_base(base), m_is_addr_of(is_addr_of), m_tokens({std::move(token)}) {
|
||||
m_base->parent_element = this;
|
||||
@@ -3175,7 +3193,7 @@ goos::Object DefskelgroupElement::ClothParams::to_list(const std::string& ag_nam
|
||||
pretty_print::to_symbol(std::to_string(timestep_freq))}));
|
||||
}
|
||||
if (secret != 0) {
|
||||
auto bits = decompile_bitfield_enum_from_int(TypeSpec("game-secrets"), env.dts->ts, flags);
|
||||
auto bits = decompile_bitfield_enum_from_int(TypeSpec("game-secrets"), env.dts->ts, secret);
|
||||
result.push_back(pretty_print::build_list(
|
||||
{pretty_print::to_symbol("secret-disable"),
|
||||
pretty_print::to_symbol(fmt::format("(game-secrets {})", fmt::join(bits, " ")))}));
|
||||
|
||||
@@ -309,6 +309,7 @@ class LoadSourceElement : public FormElement {
|
||||
class SimpleAtomElement : public FormElement {
|
||||
public:
|
||||
explicit SimpleAtomElement(const SimpleAtom& var, bool omit_var_cast = false);
|
||||
SimpleAtomElement(int int_val, bool no_hex = false);
|
||||
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;
|
||||
@@ -324,6 +325,7 @@ class SimpleAtomElement : public FormElement {
|
||||
private:
|
||||
SimpleAtom m_atom;
|
||||
bool m_omit_var_cast;
|
||||
bool m_no_hex;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -1272,6 +1274,7 @@ class DerefToken {
|
||||
};
|
||||
|
||||
DerefToken to_token(const FieldReverseLookupOutput::Token& in);
|
||||
std::vector<DerefToken> to_tokens(const std::vector<FieldReverseLookupOutput::Token>& in);
|
||||
|
||||
class DerefElement : public FormElement {
|
||||
public:
|
||||
|
||||
@@ -489,6 +489,38 @@ Form* cast_form(Form* in,
|
||||
return pool.form<CastElement>(new_type, in);
|
||||
}
|
||||
|
||||
Form* cast_form_from(Form* in,
|
||||
const TypeSpec& old_type,
|
||||
const TypeSpec& new_type,
|
||||
FormPool& pool,
|
||||
const Env& env,
|
||||
bool tc_pass = false) {
|
||||
auto& ts = env.dts->ts;
|
||||
|
||||
// sometimes, accessing a field is a no-op but changes the type. For example, accessing an inlined
|
||||
// structure at the start of a structure. To detect this, look up all the possible derefs with no
|
||||
// deref or offset, then find the highest scoring one that is the right type.
|
||||
FieldReverseLookupInput lookup_input;
|
||||
lookup_input.deref = std::nullopt;
|
||||
lookup_input.offset = 0;
|
||||
lookup_input.stride = 0;
|
||||
lookup_input.base_type = old_type;
|
||||
auto lookup_result = ts.reverse_field_multi_lookup(lookup_input);
|
||||
if (lookup_result.success) {
|
||||
for (auto& result : lookup_result.results) {
|
||||
if (result.result_type == new_type) {
|
||||
// it's a match!
|
||||
auto form = pool.form<DerefElement>(in, result.addr_of, to_tokens(result.tokens));
|
||||
form->try_as_element<DerefElement>()->inline_nested();
|
||||
return form;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to normal casts.
|
||||
return cast_form(in, new_type, pool, env, tc_pass);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Pop each variable in the input list into a form. The variables should be given in the order
|
||||
* they are evaluated in the source. It is safe to put the result of these in the same expression.
|
||||
@@ -660,7 +692,7 @@ Form* make_cast_if_needed(Form* in,
|
||||
return try_cast_simplify(in, TypeSpec("time-frame"), pool, env, true);
|
||||
}
|
||||
|
||||
return cast_form(in, out_type, pool, env);
|
||||
return cast_form_from(in, in_type, out_type, pool, env);
|
||||
}
|
||||
|
||||
std::vector<Form*> make_casts_if_needed(const std::vector<Form*>& in,
|
||||
@@ -965,7 +997,7 @@ FormElement* make_and_compact_math_op(Form* arg0,
|
||||
/*!
|
||||
* Update a two-argument form that uses two floats.
|
||||
* This is for operations like * and + that can be nested
|
||||
* (* (* a b)) -> (* a b c)
|
||||
* (* (* a b) c) -> (* a b c)
|
||||
* Note that we only apply this to the _first_ argument to keep the order of operations the same.
|
||||
*/
|
||||
void SimpleExpressionElement::update_from_stack_float_2_nestable(const Env& env,
|
||||
@@ -1605,7 +1637,8 @@ void SimpleExpressionElement::update_from_stack_vector_plus_minus_cross(
|
||||
for (int i = 0; i < 3; i++) {
|
||||
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
|
||||
if (arg_type.typespec() != TypeSpec("vector")) {
|
||||
popped_args.at(i) = cast_form(popped_args.at(i), TypeSpec("vector"), pool, env);
|
||||
popped_args.at(i) =
|
||||
cast_form_from(popped_args.at(i), arg_type.typespec(), TypeSpec("vector"), pool, env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1629,7 +1662,8 @@ void SimpleExpressionElement::update_from_stack_vector_plus_float_times(
|
||||
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
|
||||
TypeSpec desired_type(i == 3 ? "float" : "vector");
|
||||
if (arg_type.typespec() != desired_type) {
|
||||
popped_args.at(i) = cast_form(popped_args.at(i), desired_type, pool, env);
|
||||
popped_args.at(i) =
|
||||
cast_form_from(popped_args.at(i), arg_type.typespec(), desired_type, pool, env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1654,7 +1688,8 @@ void SimpleExpressionElement::update_from_stack_vector_float_product(
|
||||
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
|
||||
TypeSpec desired_type(i == 2 ? "float" : "vector");
|
||||
if (arg_type.typespec() != desired_type) {
|
||||
popped_args.at(i) = cast_form(popped_args.at(i), desired_type, pool, env);
|
||||
popped_args.at(i) =
|
||||
cast_form_from(popped_args.at(i), arg_type.typespec(), desired_type, pool, env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1680,7 +1715,8 @@ void SimpleExpressionElement::update_from_stack_vectors_in_common(FixedOperatorK
|
||||
for (int i = 0; i < m_expr.args(); i++) {
|
||||
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
|
||||
if (arg_type.typespec() != TypeSpec("vector")) {
|
||||
popped_args.at(i) = cast_form(popped_args.at(i), TypeSpec("vector"), pool, env);
|
||||
popped_args.at(i) =
|
||||
cast_form_from(popped_args.at(i), arg_type.typespec(), TypeSpec("vector"), pool, env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2527,6 +2563,10 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
|
||||
update_from_stack_vector_plus_minus_cross(FixedOperatorKind::VECTOR_CROSS, env, pool, stack,
|
||||
result, allow_side_effects);
|
||||
break;
|
||||
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
|
||||
update_from_stack_vector_plus_minus_cross(FixedOperatorKind::VECTOR_XYZ_PRODUCT, env, pool,
|
||||
stack, result, allow_side_effects);
|
||||
break;
|
||||
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
|
||||
update_from_stack_vector_float_product(env, pool, stack, result, allow_side_effects);
|
||||
break;
|
||||
@@ -2624,6 +2664,71 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (* 0.125 b) -> (/ b 8)
|
||||
// adds explicit cast b to float if necessary
|
||||
auto src_as_ge = dynamic_cast<GenericElement*>(m_src->back());
|
||||
if (src_as_ge) {
|
||||
auto mr = match(Matcher::op_fixed(FixedOperatorKind::MULTIPLICATION,
|
||||
{Matcher::any_single(0), Matcher::any(1)}),
|
||||
m_src);
|
||||
if (mr.matched && std::abs(mr.maps.floats.at(0)) < 1 && mr.maps.floats.at(0) != 0) {
|
||||
auto inverse_mult = mr.maps.floats.at(0);
|
||||
float divisor_num = 1.0f / inverse_mult;
|
||||
|
||||
// note: float inaccuracies lead to convergent values, so we can do this safely
|
||||
if ((int)divisor_num != divisor_num && 1.0f / std::roundf(divisor_num) == inverse_mult) {
|
||||
lg::debug("managed to round divisor - cool !! {} -> {} ({})", divisor_num,
|
||||
std::roundf(divisor_num), inverse_mult);
|
||||
divisor_num = std::roundf(divisor_num);
|
||||
}
|
||||
|
||||
int divisor_int = (int)divisor_num;
|
||||
bool integer = divisor_int == divisor_num;
|
||||
if (integer) {
|
||||
auto elt = mr.maps.forms.at(1)->try_as_single_element();
|
||||
auto b_as_simple = dynamic_cast<SimpleExpressionElement*>(elt);
|
||||
// WARNING : there is an assumption here that derefs DO NOT have implicit casts!
|
||||
auto b_as_deref = dynamic_cast<DerefElement*>(elt);
|
||||
if (b_as_deref ||
|
||||
(b_as_simple && b_as_simple->expr().kind() == SimpleExpression::Kind::IDENTITY)) {
|
||||
// TODO check if op is float, cast if so
|
||||
Form* divisor = nullptr;
|
||||
if (divisor_num == 4096.0f) {
|
||||
divisor = pool.form<ConstantTokenElement>("METER_LENGTH");
|
||||
} else if (integer && divisor_int % 4096 == 0) {
|
||||
divisor = pool.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("meters")),
|
||||
pool.form<SimpleAtomElement>(divisor_int / 4096, true));
|
||||
} else if (integer && divisor_int % 2048 == 0) {
|
||||
divisor = pool.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("meters")),
|
||||
pool.form<ConstantFloatElement>(divisor_num / (float)METER_LENGTH));
|
||||
} else if (integer) {
|
||||
divisor = pool.form<SimpleAtomElement>(divisor_int, true);
|
||||
} else {
|
||||
// this shouldn't run because of the checks before.
|
||||
divisor = pool.form<ConstantFloatElement>(divisor_num);
|
||||
}
|
||||
if (divisor) {
|
||||
if (b_as_deref || (b_as_simple->expr().is_var() &&
|
||||
env.get_types_before_op(b_as_simple->expr().var().idx())
|
||||
.get(b_as_simple->expr().var().reg())
|
||||
.typespec() == TypeSpec("float"))) {
|
||||
*m_src->back_ref() = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::DIVISION), mr.maps.forms.at(1),
|
||||
divisor);
|
||||
} else {
|
||||
*m_src->back_ref() = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::DIVISION),
|
||||
pool.form<CastElement>(TypeSpec("float"), mr.maps.forms.at(1), true), divisor);
|
||||
}
|
||||
m_src->back()->parent_form = m_src;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack.push_value_to_reg(m_dst, m_src, true, m_src_type, m_var_info);
|
||||
@@ -2899,6 +3004,121 @@ bool try_to_rewrite_vector_inline_ctor(const Env& env,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_to_rewrite_matrix_inline_copy(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
if (env.func->name() == "(method 63 collide-shape-moving)") {
|
||||
return false;
|
||||
}
|
||||
auto matrix_entries =
|
||||
stack.try_getting_active_stack_entries({true, true, true, true, false, false, false, false});
|
||||
if (matrix_entries) {
|
||||
// first, check the loads. they should be something like source = (-> MAT vec quad)
|
||||
// MAT should always be a variable
|
||||
const char* names[] = {"rvec", "uvec", "fvec", "trans"};
|
||||
|
||||
std::vector<RegisterAccess> load_src_ras, store_dest_ras, store_src_ras;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto deref_matcher =
|
||||
Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string(names[i]), DerefTokenMatcher::string("quad")});
|
||||
auto mr = match(deref_matcher, matrix_entries->at(i).source, &env);
|
||||
if (!mr.matched) {
|
||||
return false;
|
||||
}
|
||||
load_src_ras.push_back(mr.maps.regs.at(0).value());
|
||||
}
|
||||
|
||||
// check the stores
|
||||
for (int i = 4; i < 8; i++) {
|
||||
Matcher matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string(names[i - 4]),
|
||||
DerefTokenMatcher::string("quad")}),
|
||||
Matcher::any_reg(1));
|
||||
auto mr = match(matcher, matrix_entries->at(i).elt, &env);
|
||||
if (!mr.matched) {
|
||||
return false;
|
||||
}
|
||||
store_dest_ras.push_back(mr.maps.regs.at(0).value());
|
||||
store_src_ras.push_back(mr.maps.regs.at(1).value());
|
||||
}
|
||||
|
||||
// check loads are all loading from the same matrix
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (load_src_ras.at(i).reg() != load_src_ras.at(0).reg()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check stores are all storing to the same matrix
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (store_dest_ras.at(i).reg() != store_dest_ras.at(0).reg()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check temps are consistent
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (store_src_ras.at(i).reg() != matrix_entries->at(i).destination.value().reg()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check types
|
||||
if (env.get_variable_type(load_src_ras.at(0), true) != TypeSpec("matrix")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (env.get_variable_type(store_dest_ras.at(0), true) != TypeSpec("matrix")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
stack.pop(8);
|
||||
auto* menv = const_cast<Env*>(&env);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
menv->disable_use(store_dest_ras.at(i));
|
||||
}
|
||||
|
||||
auto src_repopped = stack.pop_reg(load_src_ras.at(0), {}, env, true);
|
||||
if (!src_repopped) {
|
||||
// lg::info("repop src failed!!");
|
||||
src_repopped = var_to_form(load_src_ras.at(0), pool);
|
||||
} else {
|
||||
// lg::info(" popped src: {}", src_repopped->to_string(env));
|
||||
}
|
||||
|
||||
// src_repopped = matrix_entries->at(0).source;
|
||||
bool found = false;
|
||||
RegisterAccess ra;
|
||||
auto dst_repopped = stack.pop_reg(store_dest_ras.at(0).reg(), {}, env, true, -1, &ra, &found);
|
||||
if (!dst_repopped) {
|
||||
// lg::info("repop dst failed!!");
|
||||
dst_repopped = var_to_form(store_dest_ras.at(0), pool);
|
||||
} else {
|
||||
ASSERT(found);
|
||||
// lg::info(" popped dst: {} {} {}", dst_repopped->to_string(env), ra.reg().to_string(),
|
||||
// ra.mode() == AccessMode::WRITE);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
stack.push_value_to_reg(
|
||||
ra,
|
||||
pool.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("matrix-copy!")),
|
||||
std::vector<Form*>{dst_repopped, src_repopped}),
|
||||
true, TypeSpec("matrix"));
|
||||
} else {
|
||||
stack.push_form_element(
|
||||
pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("matrix-copy!")),
|
||||
std::vector<Form*>{dst_repopped, src_repopped}),
|
||||
true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
// now, let's check for a matrix initialization.
|
||||
auto matrix_entries = stack.try_getting_active_stack_entries({true, false, false, false, false});
|
||||
@@ -2918,54 +3138,79 @@ bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack
|
||||
|
||||
// zeroing the rows:
|
||||
std::vector<RegisterAccess> write_vars;
|
||||
if (env.version == GameVersion::Jak1) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto elt = matrix_entries->at(i + 1).elt;
|
||||
switch (env.version) {
|
||||
case GameVersion::Jak1: {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto elt = matrix_entries->at(i + 1).elt;
|
||||
|
||||
auto matcher = Matcher::set(
|
||||
Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i),
|
||||
DerefTokenMatcher::string("quad")}),
|
||||
Matcher::cast("uint128", Matcher::integer(0)));
|
||||
|
||||
auto mr = match(matcher, elt);
|
||||
if (mr.matched) {
|
||||
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
|
||||
return false;
|
||||
}
|
||||
write_vars.push_back(*mr.maps.regs.at(0));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto elt = matrix_entries->at(i + 1).elt;
|
||||
|
||||
Matcher matcher;
|
||||
if (i == 3) {
|
||||
matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string("trans"),
|
||||
DerefTokenMatcher::string("quad")}),
|
||||
Matcher::cast("uint128", Matcher::integer(0)));
|
||||
|
||||
} else {
|
||||
matcher = Matcher::set(
|
||||
auto matcher = Matcher::set(
|
||||
Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string("quad"), DerefTokenMatcher::integer(i)}),
|
||||
{DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i),
|
||||
DerefTokenMatcher::string("quad")}),
|
||||
Matcher::cast("uint128", Matcher::integer(0)));
|
||||
}
|
||||
|
||||
auto mr = match(matcher, elt);
|
||||
if (mr.matched) {
|
||||
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
|
||||
auto mr = match(matcher, elt);
|
||||
if (mr.matched) {
|
||||
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
|
||||
return false;
|
||||
}
|
||||
write_vars.push_back(*mr.maps.regs.at(0));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
write_vars.push_back(*mr.maps.regs.at(0));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case GameVersion::Jak2: {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto elt = matrix_entries->at(i + 1).elt;
|
||||
|
||||
Matcher matcher;
|
||||
if (i == 3) {
|
||||
matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string("trans"),
|
||||
DerefTokenMatcher::string("quad")}),
|
||||
Matcher::cast("uint128", Matcher::integer(0)));
|
||||
|
||||
} else {
|
||||
matcher = Matcher::set(
|
||||
Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string("quad"), DerefTokenMatcher::integer(i)}),
|
||||
Matcher::cast("uint128", Matcher::integer(0)));
|
||||
}
|
||||
|
||||
auto mr = match(matcher, elt);
|
||||
if (mr.matched) {
|
||||
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
|
||||
return false;
|
||||
}
|
||||
write_vars.push_back(*mr.maps.regs.at(0));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case GameVersion::Jak3: {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto elt = matrix_entries->at(i + 1).elt;
|
||||
|
||||
const char* names[] = {"rvec", "uvec", "fvec", "trans"};
|
||||
|
||||
Matcher matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string(names[i]),
|
||||
DerefTokenMatcher::string("quad")}),
|
||||
Matcher::cast("uint128", Matcher::integer(0)));
|
||||
|
||||
auto mr = match(matcher, elt);
|
||||
if (mr.matched) {
|
||||
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
|
||||
return false;
|
||||
}
|
||||
write_vars.push_back(*mr.maps.regs.at(0));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
// success!
|
||||
@@ -2985,6 +3230,70 @@ bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_deref_to_quad(DerefElement* deref) {
|
||||
return deref && !deref->is_addr_of() && !deref->tokens().empty() &&
|
||||
deref->tokens().back().is_field_name("quad");
|
||||
}
|
||||
|
||||
Form* pop_last_deref_token(Form* form) {
|
||||
auto deref = form->try_as_element<DerefElement>();
|
||||
ASSERT(deref);
|
||||
if (deref->tokens().size() == 1) {
|
||||
return deref->base();
|
||||
} else {
|
||||
deref->tokens().pop_back();
|
||||
return form;
|
||||
}
|
||||
}
|
||||
|
||||
FormElement* try_to_rewrite_vector_copy(Form* dst,
|
||||
const TypeSpec& dst_type,
|
||||
Form* src,
|
||||
const TypeSpec& src_type,
|
||||
FormPool& pool,
|
||||
const Env& env) {
|
||||
if (env.func->name() == "vector-copy!") {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (dst && src) {
|
||||
// check types
|
||||
if (dst_type != TypeSpec("vector")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// kinda sus - we really want to check the place where this was loaded...
|
||||
if (src_type != TypeSpec("uint128")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* dst_deref = dst->try_as_element<DerefElement>();
|
||||
auto* src_deref = src->try_as_element<DerefElement>();
|
||||
if (!dst_deref) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!src_deref) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!is_deref_to_quad(dst_deref)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!is_deref_to_quad(src_deref)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ret = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("vector-copy!")),
|
||||
std::vector<Form*>{pop_last_deref_token(dst), pop_last_deref_token(src)});
|
||||
// lg::info("success: {}\n", ret->to_string(env));
|
||||
return ret;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
@@ -3001,14 +3310,27 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s
|
||||
if (size() == 16) {
|
||||
std::swap(popped.at(0), popped.at(1));
|
||||
}
|
||||
m_dst->try_as_element<DerefElement>()->set_base(
|
||||
make_optional_cast(m_dst_cast_type, popped.at(1), pool, env));
|
||||
auto dst_deref = m_dst->try_as_element<DerefElement>();
|
||||
dst_deref->set_base(make_optional_cast(m_dst_cast_type, popped.at(1), pool, env));
|
||||
m_dst->mark_popped();
|
||||
m_dst->try_as_element<DerefElement>()->inline_nested();
|
||||
auto fr = pool.alloc_element<SetFormFormElement>(
|
||||
m_dst, make_optional_cast(m_src_cast_type, popped.at(0), pool, env));
|
||||
// so the bitfield set check can run
|
||||
fr->mark_popped();
|
||||
dst_deref->inline_nested();
|
||||
|
||||
FormElement* fr = nullptr;
|
||||
|
||||
// hack: for now only do this on Jak 3
|
||||
if (size() == 16 && env.version == GameVersion::Jak3) {
|
||||
fr = try_to_rewrite_vector_copy(
|
||||
m_dst, env.get_variable_type(m_base_var, true), popped.at(0),
|
||||
m_src_cast_type.value_or(env.get_variable_type(m_expr.var(), true)), pool, env);
|
||||
}
|
||||
|
||||
if (!fr) {
|
||||
fr = pool.alloc_element<SetFormFormElement>(
|
||||
m_dst, make_optional_cast(m_src_cast_type, popped.at(0), pool, env));
|
||||
// so the bitfield set check can run
|
||||
fr->mark_popped();
|
||||
}
|
||||
|
||||
fr->push_to_stack(env, pool, stack);
|
||||
} else {
|
||||
auto vars = std::vector<RegisterAccess>({m_base_var});
|
||||
@@ -3027,7 +3349,9 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s
|
||||
|
||||
if (!try_to_rewrite_matrix_inline_ctor(env, pool, stack)) {
|
||||
if (!try_to_rewrite_vector_inline_ctor(env, pool, stack, "vector")) {
|
||||
try_to_rewrite_vector_inline_ctor(env, pool, stack, "quaternion");
|
||||
if (!try_to_rewrite_vector_inline_ctor(env, pool, stack, "quaternion")) {
|
||||
try_to_rewrite_matrix_inline_copy(env, pool, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3266,8 +3590,8 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
||||
|
||||
auto desired_arg_type = function_type.get_arg(arg_id);
|
||||
if (env.dts->should_attempt_cast_simplify(desired_arg_type, actual_arg_type)) {
|
||||
arg_forms.push_back(cast_form(val, desired_arg_type, pool, env,
|
||||
env.dts->ts.tc(desired_arg_type, actual_arg_type)));
|
||||
arg_forms.push_back(cast_form_from(val, actual_arg_type, desired_arg_type, pool, env,
|
||||
env.dts->ts.tc(desired_arg_type, actual_arg_type)));
|
||||
} else {
|
||||
arg_forms.push_back(val);
|
||||
}
|
||||
@@ -4161,11 +4485,11 @@ void DerefElement::update_from_stack(const Env& env,
|
||||
}
|
||||
|
||||
void DerefElement::inline_nested() {
|
||||
auto as_deref = dynamic_cast<DerefElement*>(m_base->try_as_single_element());
|
||||
if (as_deref) {
|
||||
if (!m_is_addr_of && !as_deref->is_addr_of()) {
|
||||
m_tokens.insert(m_tokens.begin(), as_deref->tokens().begin(), as_deref->tokens().end());
|
||||
m_base = as_deref->m_base;
|
||||
auto inner = dynamic_cast<DerefElement*>(m_base->try_as_single_element());
|
||||
if (inner) {
|
||||
if (!inner->is_addr_of()) {
|
||||
m_tokens.insert(m_tokens.begin(), inner->tokens().begin(), inner->tokens().end());
|
||||
m_base = inner->m_base;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4314,6 +4638,67 @@ Form* try_rewrite_as_process_to_ppointer(CondNoElseElement* value,
|
||||
GenericOperator::make_fixed(FixedOperatorKind::PROCESS_TO_PPOINTER), repopped);
|
||||
}
|
||||
|
||||
/*!
|
||||
* (if (type? foo bar)
|
||||
* foo
|
||||
* )
|
||||
*/
|
||||
Form* try_rewrite_as_as_type(CondNoElseElement* value,
|
||||
FormStack& stack,
|
||||
FormPool& pool,
|
||||
const Env& env,
|
||||
const TypeSpec& resulting_type) {
|
||||
if (value->entries.size() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto condition = value->entries.at(0).condition;
|
||||
auto body = value->entries[0].body;
|
||||
|
||||
auto condition_matcher = Matcher::op(
|
||||
GenericOpMatcher::condition(IR2_Condition::Kind::TRUTHY),
|
||||
{Matcher::func(Matcher::symbol("type?"), {Matcher::any_reg(0), Matcher::any_symbol(1)})});
|
||||
|
||||
auto condition_mr = match(condition_matcher, condition);
|
||||
if (!condition_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto body_matcher = Matcher::any_reg(0);
|
||||
auto body_mr = match(body_matcher, body);
|
||||
if (!body_mr.matched) {
|
||||
body_mr = match(Matcher::cast_to_any(1, body_matcher), body);
|
||||
if (!body_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
auto body_var = body_mr.maps.regs.at(0).value();
|
||||
auto condition_var = condition_mr.maps.regs.at(0).value();
|
||||
auto* menv = const_cast<Env*>(&env);
|
||||
menv->disable_use(body_var);
|
||||
auto repopped = stack.pop_reg(condition_var, {}, env, true);
|
||||
if (!repopped) {
|
||||
repopped = var_to_form(condition_var, pool);
|
||||
}
|
||||
auto new_type = condition_mr.maps.strings.at(1);
|
||||
|
||||
auto result = pool.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("as-type")),
|
||||
std::vector<Form*>{repopped, pool.form<ConstantTokenElement>(new_type)});
|
||||
|
||||
// silly cast situation:
|
||||
// sometimes there is something dumb like (the specific (as-type foo general))
|
||||
// we have to make sure that we keep the leading cast.
|
||||
// HACK: inserting casts more aggressively in Jak 2 because I am too lazy to fix up all the
|
||||
// slightly wrong casts that matter now.
|
||||
if (resulting_type != TypeSpec(new_type) &&
|
||||
(env.version == GameVersion::Jak2 || env.dts->ts.tc(TypeSpec(new_type), resulting_type))) {
|
||||
return pool.form<CastElement>(resulting_type, result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// (if x (-> x 0 self)) -> (ppointer->process x)
|
||||
Form* try_rewrite_as_pppointer_to_process(CondNoElseElement* value,
|
||||
FormStack& stack,
|
||||
@@ -4486,11 +4871,18 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
|
||||
stack.push_value_to_reg(write_as_value, as_ja_group, true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
} else {
|
||||
// lg::print("func {} final destination {} type {}\n", env.func->name(),
|
||||
// final_destination.to_string(env),
|
||||
// env.get_variable_type(final_destination, false).print());
|
||||
stack.push_value_to_reg(write_as_value, pool.alloc_single_form(nullptr, this), true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
auto as_as_type = try_rewrite_as_as_type(this, stack, pool, env,
|
||||
env.get_variable_type(final_destination, true));
|
||||
if (as_as_type) {
|
||||
stack.push_value_to_reg(write_as_value, as_as_type, true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
} else {
|
||||
// lg::print("func {} final destination {} type {}\n", env.func->name(),
|
||||
// final_destination.to_string(env),
|
||||
// env.get_variable_type(final_destination, false).print());
|
||||
stack.push_value_to_reg(write_as_value, pool.alloc_single_form(nullptr, this), true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5713,7 +6105,7 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||
as_cast->set_type(func_type);
|
||||
return_code->push_back(as_cast);
|
||||
} else {
|
||||
return_code = cast_form(return_code, func_type, pool, env);
|
||||
return_code = cast_form_from(return_code, *return_type, func_type, pool, env);
|
||||
return_code->parent_element = this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,14 @@ Matcher Matcher::cast(const std::string& type, Matcher value) {
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::numeric_cast(const std::string& type, Matcher value) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::NUMERIC_CAST;
|
||||
m.m_str = type;
|
||||
m.m_sub_matchers = {value};
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::cast_to_any(int type_out, Matcher value) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::CAST_TO_ANY;
|
||||
@@ -127,6 +135,13 @@ Matcher Matcher::single(std::optional<float> value) {
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::any_single(int match_id) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::ANY_FLOAT;
|
||||
m.m_float_out_id = match_id;
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::any_quoted_symbol(int match_id) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::ANY_QUOTED_SYMBOL;
|
||||
@@ -211,6 +226,13 @@ Matcher Matcher::while_loop(const Matcher& condition, const Matcher& body) {
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::until_loop(const Matcher& condition, const Matcher& body) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::UNTIL_LOOP;
|
||||
m.m_sub_matchers = {condition, body};
|
||||
return m;
|
||||
}
|
||||
|
||||
Matcher Matcher::any_constant_token(int match_id) {
|
||||
Matcher m;
|
||||
m.m_kind = Kind::ANY_CONSTANT_TOKEN;
|
||||
@@ -398,6 +420,16 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
|
||||
return false;
|
||||
} break;
|
||||
|
||||
case Kind::NUMERIC_CAST: {
|
||||
auto as_cast = dynamic_cast<CastElement*>(input->try_as_single_active_element());
|
||||
if (as_cast && as_cast->numeric()) {
|
||||
if (as_cast->type().print() == m_str) {
|
||||
return m_sub_matchers.at(0).do_match(as_cast->source(), maps_out, env);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} break;
|
||||
|
||||
case Kind::CAST_TO_ANY: {
|
||||
auto as_cast = dynamic_cast<CastElement*>(input->try_as_single_active_element());
|
||||
if (as_cast) {
|
||||
@@ -470,6 +502,30 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
|
||||
return false;
|
||||
} break;
|
||||
|
||||
case Kind::ANY_FLOAT: {
|
||||
auto as_const_float =
|
||||
dynamic_cast<ConstantFloatElement*>(input->try_as_single_active_element());
|
||||
if (as_const_float) {
|
||||
if (m_float_out_id != -1) {
|
||||
maps_out->floats[m_float_out_id] = as_const_float->value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto as_expr = dynamic_cast<SimpleExpressionElement*>(input->try_as_single_active_element());
|
||||
if (as_expr && as_expr->expr().is_identity()) {
|
||||
const auto& atom = as_expr->expr().get_arg(0);
|
||||
if (atom.is_integer_promoted_to_float()) {
|
||||
if (m_float_out_id != -1) {
|
||||
maps_out->floats[m_float_out_id] = atom.get_integer_promoted_to_float();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} break;
|
||||
|
||||
case Kind::ANY_QUOTED_SYMBOL: {
|
||||
auto as_simple_atom = dynamic_cast<SimpleAtomElement*>(input->try_as_single_active_element());
|
||||
if (as_simple_atom) {
|
||||
@@ -671,6 +727,22 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
|
||||
return true;
|
||||
} break;
|
||||
|
||||
case Kind::UNTIL_LOOP: {
|
||||
auto as_until = dynamic_cast<UntilElement*>(input->try_as_single_active_element());
|
||||
if (!as_until) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_sub_matchers.at(0).do_match(as_until->condition, maps_out, env)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_sub_matchers.at(1).do_match(as_until->body, maps_out, env)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} break;
|
||||
|
||||
case Kind::BEGIN: {
|
||||
if ((int)m_sub_matchers.size() != input->size()) {
|
||||
return false;
|
||||
|
||||
@@ -21,6 +21,7 @@ struct MatchResult {
|
||||
std::unordered_map<int, Form*> forms;
|
||||
std::unordered_map<int, s64> label;
|
||||
std::unordered_map<int, s64> ints;
|
||||
std::unordered_map<int, float> floats;
|
||||
} maps;
|
||||
|
||||
Form* int_or_form_to_form(FormPool& pool, int key_idx) {
|
||||
@@ -51,11 +52,13 @@ class Matcher {
|
||||
static Matcher set_var(const Matcher& src, int dst_match_id); // var-form
|
||||
static Matcher match_or(const std::vector<Matcher>& args);
|
||||
static Matcher cast(const std::string& type, Matcher value);
|
||||
static Matcher numeric_cast(const std::string& type, Matcher value);
|
||||
static Matcher cast_to_any(int type_out, Matcher value);
|
||||
static Matcher any(int match_id = -1);
|
||||
static Matcher integer(std::optional<int> value);
|
||||
static Matcher any_integer(int match_id = -1);
|
||||
static Matcher single(std::optional<float> value);
|
||||
static Matcher any_single(int match_id = -1);
|
||||
static Matcher any_reg_cast_to_int_or_uint(int match_id = -1);
|
||||
static Matcher any_quoted_symbol(int match_id = -1);
|
||||
static Matcher any_symbol(int match_id = -1);
|
||||
@@ -69,6 +72,7 @@ class Matcher {
|
||||
const Matcher& false_case);
|
||||
static Matcher if_no_else(const Matcher& condition, const Matcher& true_case);
|
||||
static Matcher while_loop(const Matcher& condition, const Matcher& body);
|
||||
static Matcher until_loop(const Matcher& condition, const Matcher& body);
|
||||
static Matcher any_constant_token(int match_id = -1);
|
||||
static Matcher constant_token(const std::string& name);
|
||||
static Matcher or_expression(const std::vector<Matcher>& elts);
|
||||
@@ -85,11 +89,13 @@ class Matcher {
|
||||
GENERIC_OP_WITH_REST,
|
||||
OR,
|
||||
CAST,
|
||||
NUMERIC_CAST,
|
||||
CAST_TO_ANY,
|
||||
ANY,
|
||||
INT,
|
||||
ANY_INT,
|
||||
FLOAT,
|
||||
ANY_FLOAT,
|
||||
ANY_QUOTED_SYMBOL,
|
||||
ANY_SYMBOL,
|
||||
DEREF_OP,
|
||||
@@ -100,6 +106,7 @@ class Matcher {
|
||||
IF_WITH_ELSE,
|
||||
IF_NO_ELSE,
|
||||
WHILE_LOOP,
|
||||
UNTIL_LOOP,
|
||||
ANY_CONSTANT_TOKEN,
|
||||
CONSTANT_TOKEN,
|
||||
SC_OR,
|
||||
@@ -130,6 +137,7 @@ class Matcher {
|
||||
int m_form_match;
|
||||
int m_label_out_id;
|
||||
int m_int_out_id;
|
||||
int m_float_out_id;
|
||||
};
|
||||
std::optional<int> m_int_match;
|
||||
std::optional<float> m_float_match;
|
||||
|
||||
@@ -162,6 +162,7 @@ enum class FixedOperatorKind {
|
||||
VECTOR_MINUS,
|
||||
VECTOR_CROSS,
|
||||
VECTOR_FLOAT_PRODUCT,
|
||||
VECTOR_XYZ_PRODUCT,
|
||||
L32_NOT_FALSE_CBOOL,
|
||||
VECTOR_3_DOT,
|
||||
PROCESS_TO_PPOINTER,
|
||||
|
||||
@@ -207,6 +207,13 @@ std::string OpenGOALAsm::full_function_name() {
|
||||
func_name = fmt::format(fmt::runtime(func_name), bc);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle destination masks
|
||||
if (func.allows_modifier(MOD::DEST_MASK) && m_instr.cop2_dest != 0xff &&
|
||||
m_instr.cop2_dest != 15) {
|
||||
func_name += m_instr.cop2_dest_to_char();
|
||||
}
|
||||
|
||||
return func_name;
|
||||
}
|
||||
|
||||
@@ -270,13 +277,6 @@ std::vector<goos::Object> OpenGOALAsm::get_args(const std::vector<DecompilerLabe
|
||||
args.push_back(pretty_print::to_symbol("acc"));
|
||||
}
|
||||
|
||||
// Handle destination masks
|
||||
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}", m_instr.cop2_dest_mask_intel())));
|
||||
}
|
||||
|
||||
// Some functions are configured, or its easiest to swap the source args
|
||||
// NOTE - this currently assumes it is the first two args that must be swapped
|
||||
if (func.allows_modifier(MOD::SWAP_FIRST_TWO_SOURCE_ARGS)) {
|
||||
|
||||
@@ -231,10 +231,11 @@ ObjectFileDB::ObjectFileDB(const std::vector<fs::path>& _dgos,
|
||||
StrFileReader reader(obj, version());
|
||||
// name from the file name
|
||||
std::string base_name = obj_filename_to_name(obj.string());
|
||||
ASSERT(reader.chunk_count() == 1);
|
||||
auto name = reader.get_texture_name();
|
||||
add_obj_from_dgo(name, name, reader.get_chunk(0).data(), reader.get_chunk(0).size(),
|
||||
"TEXSPOOL", config, name);
|
||||
for (int i = 0; i < reader.chunk_count(); i++) {
|
||||
auto name = reader.get_chunk_texture_name(i);
|
||||
add_obj_from_dgo(name, name, reader.get_chunk(i).data(), reader.get_chunk(i).size(),
|
||||
"TEXSPOOL", config, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,12 +79,15 @@ struct LetRewriteStats {
|
||||
int with_dma_buf_add_bucket = 0;
|
||||
int dma_buffer_add_gs_set = 0;
|
||||
int launch_particles = 0;
|
||||
int call_parent_state_handler = 0;
|
||||
int suspend_for = 0;
|
||||
int font_method = 0;
|
||||
|
||||
int total() const {
|
||||
return dotimes + countdown + abs + abs2 + unused + ja + case_no_else + case_with_else +
|
||||
set_vector + set_vector2 + send_event + font_context_meth + proc_new + attack_info +
|
||||
vector_dot + rand_float_gen + set_let + with_dma_buf_add_bucket + dma_buffer_add_gs_set +
|
||||
launch_particles;
|
||||
launch_particles + call_parent_state_handler + suspend_for + font_method;
|
||||
}
|
||||
|
||||
std::string print() const {
|
||||
@@ -111,6 +114,9 @@ struct LetRewriteStats {
|
||||
out += fmt::format(" with_dma_buf_add_bucket: {}\n", with_dma_buf_add_bucket);
|
||||
out += fmt::format(" dma_buffer_add_gs_set: {}\n", dma_buffer_add_gs_set);
|
||||
out += fmt::format(" launch_particles: {}\n", launch_particles);
|
||||
out += fmt::format(" call_parent_state_handler: {}\n", call_parent_state_handler);
|
||||
out += fmt::format(" suspend_for: {}\n", suspend_for);
|
||||
out += fmt::format(" font_method: {}\n", font_method);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -135,6 +141,8 @@ struct LetRewriteStats {
|
||||
result.set_let = rand_float_gen + other.set_let;
|
||||
result.with_dma_buf_add_bucket = rand_float_gen + other.with_dma_buf_add_bucket;
|
||||
result.launch_particles = launch_particles + other.launch_particles;
|
||||
result.call_parent_state_handler = call_parent_state_handler + other.call_parent_state_handler;
|
||||
result.suspend_for = suspend_for + other.suspend_for;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -158,6 +166,8 @@ struct LetRewriteStats {
|
||||
set_let += other.set_let;
|
||||
with_dma_buf_add_bucket += other.with_dma_buf_add_bucket;
|
||||
launch_particles += other.launch_particles;
|
||||
call_parent_state_handler += other.call_parent_state_handler;
|
||||
suspend_for += other.suspend_for;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1689,6 +1689,62 @@ std::unique_ptr<AtomicOp> convert_vector_plus(const Instruction& i0,
|
||||
idx);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_vector_xyz_product(const Instruction& i0,
|
||||
const Instruction& i1,
|
||||
const Instruction& i2,
|
||||
const Instruction& i3,
|
||||
const Instruction& i4,
|
||||
int idx) {
|
||||
/*
|
||||
lqc2 vf4, 0(a1)
|
||||
lqc2 vf5, 0(a2)
|
||||
vaddx.w vf6, vf0, vf0
|
||||
vmul.xyz vf6, vf4, vf5
|
||||
sqc2 vf6, 0(a0)
|
||||
*/
|
||||
|
||||
// lqc2 vf4, 0(a1) (src1)
|
||||
if (i0.kind != InstructionKind::LQC2 || i0.get_dst(0).get_reg() != make_vf(4) ||
|
||||
!i0.get_src(0).is_imm(0)) {
|
||||
return nullptr;
|
||||
}
|
||||
Register src1 = i0.get_src(1).get_reg();
|
||||
|
||||
// lqc2 vf5, 0(a2) (src2)
|
||||
if (i1.kind != InstructionKind::LQC2 || i1.get_dst(0).get_reg() != make_vf(5) ||
|
||||
!i1.get_src(0).is_imm(0)) {
|
||||
return nullptr;
|
||||
}
|
||||
Register src2 = i1.get_src(1).get_reg();
|
||||
|
||||
// vaddx.w vf6, vf0, vf0
|
||||
if (i2.kind != InstructionKind::VADD_BC || i2.get_dst(0).get_reg() != make_vf(6) ||
|
||||
i2.get_src(0).get_reg() != make_vf(0) || i2.get_src(1).get_reg() != make_vf(0) ||
|
||||
i2.cop2_dest != 1 || i2.cop2_bc != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// vmul.xyz vf6, vf4, vf5
|
||||
if (i3.kind != InstructionKind::VMUL || i3.get_dst(0).get_reg() != make_vf(6) ||
|
||||
i3.get_src(0).get_reg() != make_vf(4) || i3.get_src(1).get_reg() != make_vf(5) ||
|
||||
i3.cop2_dest != 14) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// sqc2 vf6, 0(a0) (dst)
|
||||
if (i4.kind != InstructionKind::SQC2 || i4.get_src(0).get_reg() != make_vf(6) ||
|
||||
!i4.get_src(1).is_imm(0)) {
|
||||
return nullptr;
|
||||
}
|
||||
Register dst = i4.get_src(2).get_reg();
|
||||
|
||||
return std::make_unique<SetVarOp>(
|
||||
make_dst_var(dst, idx),
|
||||
SimpleExpression(SimpleExpression::Kind::VECTOR_XYZ_PRODUCT, make_src_atom(dst, idx),
|
||||
make_src_atom(src1, idx), make_src_atom(src2, idx)),
|
||||
idx);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_vector_minus(const Instruction& i0,
|
||||
const Instruction& i1,
|
||||
const Instruction& i2,
|
||||
@@ -1819,6 +1875,11 @@ std::unique_ptr<AtomicOp> convert_5(const Instruction& i0,
|
||||
return as_vector_plus;
|
||||
}
|
||||
|
||||
auto as_vector_xyz = convert_vector_xyz_product(i0, i1, i2, i3, i4, idx);
|
||||
if (as_vector_xyz) {
|
||||
return as_vector_xyz;
|
||||
}
|
||||
|
||||
auto as_vector_minus = convert_vector_minus(i0, i1, i2, i3, i4, idx);
|
||||
if (as_vector_minus) {
|
||||
return as_vector_minus;
|
||||
|
||||
@@ -1673,6 +1673,99 @@ FormElement* rewrite_part_tracker_new(const std::string& type,
|
||||
->try_as_single_element();
|
||||
}
|
||||
|
||||
FormElement* rewrite_call_parent_state_handler(LetElement* in, const Env& env, FormPool& pool) {
|
||||
// (let ((t9-3 (-> (find-parent-state) code)))
|
||||
// (if t9-3
|
||||
// ((the-as (function none) t9-3))
|
||||
// )
|
||||
// )
|
||||
auto mr =
|
||||
Matcher::let(false,
|
||||
{LetEntryMatcher::any(Matcher::deref(Matcher::func("find-parent-state", {}),
|
||||
false, {DerefTokenMatcher::any_string(1)}),
|
||||
0)},
|
||||
{Matcher::if_no_else(Matcher::any(), Matcher::any(2))});
|
||||
auto let_mr = match(mr, in);
|
||||
if (!let_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
auto handler = let_mr.maps.strings.at(1);
|
||||
auto valid_handlers = {"enter", "trans", "code", "post"};
|
||||
if (std::find(valid_handlers.begin(), valid_handlers.end(), handler) != valid_handlers.end()) {
|
||||
std::vector<Form*> macro_args;
|
||||
macro_args.push_back(pool.form<ConstantTokenElement>(handler));
|
||||
// there are no examples of this being used with args, so that is not handled for now...
|
||||
// auto func = let_mr.maps.forms.at(2);
|
||||
return pool
|
||||
.form<GenericElement>(GenericOperator::make_function(
|
||||
pool.form<ConstantTokenElement>("call-parent-state-handler")),
|
||||
macro_args)
|
||||
->try_as_single_element();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FormElement* rewrite_suspend_for(LetElement* in, const Env& env, FormPool& pool) {
|
||||
// (let ((gp-1 (current-time)))
|
||||
// (until (time-elapsed? gp-1 (seconds 0.5))
|
||||
// (suspend)
|
||||
// )
|
||||
// )
|
||||
// ->
|
||||
// (suspend-for (seconds 0.5))
|
||||
auto until = dynamic_cast<UntilElement*>(in->body()->at(0));
|
||||
if (!until) {
|
||||
return nullptr;
|
||||
}
|
||||
auto mr = Matcher::let(
|
||||
false, {LetEntryMatcher::any(Matcher::func("current-time", {}), 0)},
|
||||
{Matcher::until_loop(Matcher::func("time-elapsed?", {Matcher::any_reg(1), Matcher::any(2)}),
|
||||
Matcher::any(3))});
|
||||
auto let_mr = match(mr, in);
|
||||
if (!let_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
auto var = let_mr.maps.regs.at(1);
|
||||
auto time = let_mr.maps.forms.at(2);
|
||||
auto body = let_mr.maps.forms.at(3);
|
||||
std::vector<Form*> macro_args;
|
||||
std::vector<FormElement*> macro_elts;
|
||||
macro_args.push_back(time);
|
||||
for (auto& elt : body->elts()) {
|
||||
auto op = dynamic_cast<AtomicOpElement*>(elt);
|
||||
auto suspend = op && op->op() && dynamic_cast<SpecialOp*>(op->op()) &&
|
||||
dynamic_cast<SpecialOp*>(op->op())->kind() == SpecialOp::Kind::SUSPEND;
|
||||
if (!suspend || elt != body->elts().back()) {
|
||||
elt->apply_form([&](Form* form) {
|
||||
for (auto& e : form->elts()) {
|
||||
auto as_expr = dynamic_cast<SimpleExpressionElement*>(e);
|
||||
if (as_expr) {
|
||||
RegAccessSet regs;
|
||||
as_expr->collect_vars(regs, false);
|
||||
for (auto reg : regs) {
|
||||
if (reg.to_string(env, RegisterAccess::Print::AS_VARIABLE) ==
|
||||
var.value().to_string(env, RegisterAccess::Print::AS_VARIABLE)) {
|
||||
e = pool.alloc_element<ConstantTokenElement>("time");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
macro_elts.push_back(elt);
|
||||
}
|
||||
}
|
||||
if (!macro_elts.empty()) {
|
||||
for (auto elt : macro_elts) {
|
||||
macro_args.push_back(pool.alloc_single_form(nullptr, elt));
|
||||
}
|
||||
}
|
||||
return pool
|
||||
.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("suspend-for")),
|
||||
macro_args)
|
||||
->try_as_single_element();
|
||||
}
|
||||
|
||||
FormElement* rewrite_proc_new(LetElement* in, const Env& env, FormPool& pool) {
|
||||
// this function checks for the process-spawn macros.
|
||||
// it uses recursive form scanning to wrap the macro inside a potential "shell"
|
||||
@@ -2119,6 +2212,50 @@ FormElement* rewrite_attack_info(LetElement* in, const Env& env, FormPool& pool)
|
||||
return elt;
|
||||
}
|
||||
|
||||
FormElement* rewrite_set_font_single(LetElement* in,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
const char* deref_name,
|
||||
const char* op_name,
|
||||
bool cast_to_float) {
|
||||
/*
|
||||
(let ((v1-10 gp-0))
|
||||
(set! (-> v1-10 scale) 0.6)
|
||||
)
|
||||
*/
|
||||
|
||||
if (in->entries().size() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
if (in->body()->elts().size() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Form* font_obj_expr = in->entries().at(0).src;
|
||||
RegisterAccess font_obj_reg = in->entries().at(0).dest;
|
||||
|
||||
if (env.get_variable_type(font_obj_reg, true) != TypeSpec("font-context")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto src_matcher =
|
||||
cast_to_float ? Matcher::numeric_cast("float", Matcher::any(0)) : Matcher::any(0);
|
||||
Matcher set_matcher = Matcher::set(Matcher::deref(Matcher::reg(font_obj_reg.reg()), false,
|
||||
{DerefTokenMatcher::string(deref_name)}),
|
||||
src_matcher);
|
||||
auto set_mr = match(set_matcher, in->body()->at(0));
|
||||
|
||||
if (!set_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto elt = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>(op_name)),
|
||||
std::vector<Form*>{font_obj_expr, set_mr.maps.forms.at(0)});
|
||||
elt->parent_form = in->parent_form;
|
||||
return elt;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Attempt to rewrite a let as another form. If it cannot be rewritten, this will return nullptr.
|
||||
*/
|
||||
@@ -2185,6 +2322,12 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool, LetRewr
|
||||
return as_set_vector3;
|
||||
}
|
||||
|
||||
auto suspend_for = rewrite_suspend_for(in, env, pool);
|
||||
if (suspend_for) {
|
||||
stats.suspend_for++;
|
||||
return suspend_for;
|
||||
}
|
||||
|
||||
auto as_abs_2 = fix_up_abs_2(in, env, pool);
|
||||
if (as_abs_2) {
|
||||
stats.abs2++;
|
||||
@@ -2215,6 +2358,30 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool, LetRewr
|
||||
return as_attack_info;
|
||||
}
|
||||
|
||||
auto as_call_parent_state = rewrite_call_parent_state_handler(in, env, pool);
|
||||
if (as_call_parent_state) {
|
||||
stats.call_parent_state_handler++;
|
||||
return as_call_parent_state;
|
||||
}
|
||||
|
||||
auto as_font_scale = rewrite_set_font_single(in, env, pool, "scale", "set-scale!", false);
|
||||
if (as_font_scale) {
|
||||
stats.font_method++;
|
||||
return as_font_scale;
|
||||
}
|
||||
|
||||
auto as_font_width = rewrite_set_font_single(in, env, pool, "width", "set-width!", true);
|
||||
if (as_font_width) {
|
||||
stats.font_method++;
|
||||
return as_font_width;
|
||||
}
|
||||
|
||||
auto as_font_height = rewrite_set_font_single(in, env, pool, "height", "set-height!", true);
|
||||
if (as_font_height) {
|
||||
stats.font_method++;
|
||||
return as_font_height;
|
||||
}
|
||||
|
||||
// nothing matched.
|
||||
return nullptr;
|
||||
}
|
||||
@@ -2582,6 +2749,59 @@ FormElement* rewrite_with_dma_buf_add_bucket(LetElement* in, const Env& env, For
|
||||
return elt;
|
||||
}
|
||||
|
||||
FormElement* rewrite_set_font_origin(LetElement* in, const Env& env, FormPool& pool) {
|
||||
/*
|
||||
(let ((v1-9 gp-0)
|
||||
(a1-1 36)
|
||||
(a0-4 140)
|
||||
)
|
||||
(set! (-> v1-9 origin x) (the float a1-1))
|
||||
(set! (-> v1-9 origin y) (the float a0-4))
|
||||
)
|
||||
*/
|
||||
if (in->entries().size() != 3) {
|
||||
return nullptr;
|
||||
}
|
||||
if (in->body()->elts().size() != 2) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Form* font_obj_expr = in->entries().at(0).src;
|
||||
RegisterAccess font_obj_reg = in->entries().at(0).dest;
|
||||
|
||||
if (env.get_variable_type(font_obj_reg, true) != TypeSpec("font-context")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Form* x_val = in->entries().at(1).src;
|
||||
Form* y_val = in->entries().at(2).src;
|
||||
|
||||
Matcher x_matcher = Matcher::set(
|
||||
Matcher::deref(Matcher::reg(font_obj_reg.reg()), false,
|
||||
{DerefTokenMatcher::string("origin"), DerefTokenMatcher::string("x")}),
|
||||
Matcher::numeric_cast("float", Matcher::reg(in->entries().at(1).dest.reg())));
|
||||
auto x_mr = match(x_matcher, in->body()->at(0));
|
||||
|
||||
Matcher y_matcher = Matcher::set(
|
||||
Matcher::deref(Matcher::reg(font_obj_reg.reg()), false,
|
||||
{DerefTokenMatcher::string("origin"), DerefTokenMatcher::string("y")}),
|
||||
Matcher::numeric_cast("float", Matcher::reg(in->entries().at(2).dest.reg())));
|
||||
auto y_mr = match(y_matcher, in->body()->at(1));
|
||||
|
||||
if (!x_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!y_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto elt = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("set-origin!")),
|
||||
std::vector<Form*>{font_obj_expr, x_val, y_val});
|
||||
elt->parent_form = in->parent_form;
|
||||
return elt;
|
||||
}
|
||||
|
||||
FormElement* rewrite_launch_particles(LetElement* in, const Env& env, FormPool& pool) {
|
||||
/*
|
||||
* (let ((t9-0 sp-launch-particles-var)
|
||||
@@ -2611,8 +2831,12 @@ FormElement* rewrite_launch_particles(LetElement* in, const Env& env, FormPool&
|
||||
}
|
||||
|
||||
auto set_elt = dynamic_cast<SetFormFormElement*>(in->body()->at(0));
|
||||
GenericElement* vector_copy_elt = nullptr;
|
||||
if (!set_elt) {
|
||||
return nullptr;
|
||||
vector_copy_elt = dynamic_cast<GenericElement*>(in->body()->at(0));
|
||||
if (!vector_copy_elt || vector_copy_elt->op().to_form(env).print() != "vector-copy!") {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto func_elt = dynamic_cast<GenericElement*>(in->body()->at(1));
|
||||
@@ -2642,19 +2866,24 @@ FormElement* rewrite_launch_particles(LetElement* in, const Env& env, FormPool&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto origin = dynamic_cast<DerefElement*>(set_elt->src()->elts().at(0));
|
||||
if (!origin) {
|
||||
return nullptr;
|
||||
}
|
||||
auto tokens = origin->tokens().size();
|
||||
Form* origin_form;
|
||||
// remove only the quad if there are multiple derefs
|
||||
if (tokens > 1) {
|
||||
origin_form = pool.form<DerefElement>(origin->base(), false, origin->tokens());
|
||||
auto orig = dynamic_cast<DerefElement*>(origin_form->elts().at(0));
|
||||
orig->tokens().pop_back();
|
||||
Form* origin_form = nullptr;
|
||||
if (set_elt) {
|
||||
auto origin = dynamic_cast<DerefElement*>(set_elt->src()->elts().at(0));
|
||||
auto tokens = origin->tokens().size();
|
||||
// remove only the quad if there are multiple derefs
|
||||
if (tokens > 1) {
|
||||
origin_form = pool.form<DerefElement>(origin->base(), false, origin->tokens());
|
||||
auto orig = dynamic_cast<DerefElement*>(origin_form->elts().at(0));
|
||||
orig->tokens().pop_back();
|
||||
} else {
|
||||
origin_form = origin->base();
|
||||
}
|
||||
} else {
|
||||
origin_form = origin->base();
|
||||
// the vector copy rewrite already did the logic above.
|
||||
origin_form = vector_copy_elt->elts().at(1);
|
||||
}
|
||||
if (!origin_form) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto launch_state = func_elt->elts().at(func_elt->elts().size() - 3);
|
||||
@@ -2732,6 +2961,12 @@ FormElement* rewrite_multi_let(LetElement* in,
|
||||
}
|
||||
}
|
||||
|
||||
auto as_font_set_origin = rewrite_set_font_origin(in, env, pool);
|
||||
if (as_font_set_origin) {
|
||||
stats.font_method++;
|
||||
return as_font_set_origin;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
@@ -287,25 +287,41 @@
|
||||
)
|
||||
|
||||
(defenum pad-buttons
|
||||
:bitfield #t
|
||||
:type uint32
|
||||
(select 0)
|
||||
(l3 1)
|
||||
(r3 2)
|
||||
(start 3)
|
||||
(up 4)
|
||||
(right 5)
|
||||
(down 6)
|
||||
(left 7)
|
||||
(l2 8)
|
||||
(r2 9)
|
||||
(l1 10)
|
||||
(r1 11)
|
||||
(triangle 12)
|
||||
(circle 13)
|
||||
(x 14)
|
||||
(square 15)
|
||||
)
|
||||
:bitfield #t
|
||||
:type uint32
|
||||
(select 0)
|
||||
(l3 1)
|
||||
(r3 2)
|
||||
(start 3)
|
||||
(up 4)
|
||||
(right 5)
|
||||
(down 6)
|
||||
(left 7)
|
||||
(l2 8)
|
||||
(r2 9)
|
||||
(l1 10)
|
||||
(r1 11)
|
||||
(triangle 12)
|
||||
(circle 13)
|
||||
(x 14)
|
||||
(square 15)
|
||||
)
|
||||
|
||||
(defenum abutton-idx
|
||||
:type uint8
|
||||
(right 0)
|
||||
(left 1)
|
||||
(up 2)
|
||||
(down 3)
|
||||
(triangle 4)
|
||||
(circle 5)
|
||||
(x 6)
|
||||
(square 7)
|
||||
(l1 8)
|
||||
(r1 9)
|
||||
(l2 10)
|
||||
(r2 11)
|
||||
)
|
||||
|
||||
(defenum gs-psm
|
||||
:bitfield #f
|
||||
@@ -19612,6 +19628,57 @@
|
||||
(wt31)
|
||||
)
|
||||
|
||||
(defenum water-look
|
||||
(water-anim-sunken-big-room 0)
|
||||
(water-anim-sunken-first-room-from-entrance 1)
|
||||
(water-anim-sunken-qbert-room 2)
|
||||
(water-anim-sunken-first-right-branch 3)
|
||||
(water-anim-sunken-circular-with-bullys 4)
|
||||
(water-anim-sunken-hall-with-one-whirlpool 5)
|
||||
(water-anim-sunken-hall-with-three-whirlpools 6)
|
||||
(water-anim-sunken-start-of-helix-slide 7)
|
||||
(water-anim-sunken-room-above-exit-chamber 8)
|
||||
(water-anim-sunken-hall-before-big-room 9)
|
||||
(water-anim-sunken-dark-eco-qbert 10)
|
||||
(water-anim-sunken-short-piece 11)
|
||||
(water-anim-sunken-big-room-upper-water 12)
|
||||
(water-anim-sunken-dark-eco-platform-room 13)
|
||||
(water-anim-maincave-water-with-crystal 14)
|
||||
(water-anim-maincave-center-pool 15)
|
||||
(water-anim-maincave-lower-right-pool 16)
|
||||
(water-anim-maincave-mid-right-pool 17)
|
||||
(water-anim-maincave-lower-left-pool 18)
|
||||
(water-anim-maincave-mid-left-pool 19)
|
||||
(water-anim-robocave-main-pool 20)
|
||||
(water-anim-misty-mud-by-arena 21)
|
||||
(water-anim-misty-mud-above-skeleton 22)
|
||||
(water-anim-misty-mud-behind-skeleton 23)
|
||||
(water-anim-misty-mud-above-skull-back 24)
|
||||
(water-anim-misty-mud-above-skull-front 25)
|
||||
(water-anim-misty-mud-other-near-skull 26)
|
||||
(water-anim-misty-mud-near-skull 27)
|
||||
(water-anim-misty-mud-under-spine 28)
|
||||
(water-anim-misty-mud-by-dock 29)
|
||||
(water-anim-misty-mud-island-near-dock 30)
|
||||
(water-anim-misty-mud-lonely-island 31)
|
||||
(water-anim-misty-dark-eco-pool 32)
|
||||
(water-anim-ogre-lava 33)
|
||||
(water-anim-jungle-river 34)
|
||||
(water-anim-village3-lava 35)
|
||||
(water-anim-training-lake 36)
|
||||
(water-anim-darkcave-water-with-crystal 37)
|
||||
(water-anim-rolling-water-back 38)
|
||||
(water-anim-rolling-water-front 39)
|
||||
(water-anim-sunken-dark-eco-helix-room 40)
|
||||
(water-anim-finalboss-dark-eco-pool 41)
|
||||
(water-anim-lavatube-energy-lava 42)
|
||||
(water-anim-village1-rice-paddy 43)
|
||||
(water-anim-village1-fountain 44)
|
||||
(water-anim-village1-rice-paddy-mid 45)
|
||||
(water-anim-village1-rice-paddy-top 46)
|
||||
(water-anim-village2-bucket 47)
|
||||
)
|
||||
|
||||
(deftype water-control (basic)
|
||||
((flags water-flags :offset-assert 4)
|
||||
(process process-drawable :offset-assert 8)
|
||||
|
||||
@@ -1 +1 @@
|
||||
[]
|
||||
[[2147418112,{"idx":0,"name":"placeholder-white","tpage_name":"placeholder"}],[105447426,{"idx":2,"name":"demo5cj","tpage_name":"demo5j"}],[105447425,{"idx":1,"name":"demo5bj","tpage_name":"demo5j"}],[105447424,{"idx":0,"name":"demo5aj","tpage_name":"demo5j"}],[105316354,{"idx":2,"name":"demo4cs","tpage_name":"demo4s"}],[105316353,{"idx":1,"name":"demo4bs","tpage_name":"demo4s"}],[105316352,{"idx":0,"name":"demo4as","tpage_name":"demo4s"}],[105250818,{"idx":2,"name":"demo4ci","tpage_name":"demo4i"}],[105250817,{"idx":1,"name":"demo4bi","tpage_name":"demo4i"}],[105250816,{"idx":0,"name":"demo4ai","tpage_name":"demo4i"}],[105119746,{"idx":2,"name":"demo4cf","tpage_name":"demo4f"}],[105119745,{"idx":1,"name":"demo4bf","tpage_name":"demo4f"}],[105119744,{"idx":0,"name":"demo4af","tpage_name":"demo4f"}],[104988674,{"idx":2,"name":"demo2cs","tpage_name":"demo2s"}],[104988673,{"idx":1,"name":"demo2bs","tpage_name":"demo2s"}],[104988672,{"idx":0,"name":"demo2as","tpage_name":"demo2s"}],[104923138,{"idx":2,"name":"demo2ci","tpage_name":"demo2i"}],[104923137,{"idx":1,"name":"demo2bi","tpage_name":"demo2i"}],[104923136,{"idx":0,"name":"demo2ai","tpage_name":"demo2i"}],[100401161,{"idx":9,"name":"sk-eye-lid","tpage_name":"sidekick-lod0"}],[100401160,{"idx":8,"name":"e-white-alpha","tpage_name":"sidekick-lod0"}],[100401159,{"idx":7,"name":"sk-armfur","tpage_name":"sidekick-lod0"}],[98238464,{"idx":0,"name":"logo-flare","tpage_name":"title-vis-water"}],[97386498,{"idx":2,"name":"demo3c","tpage_name":"demo3"}],[97386497,{"idx":1,"name":"demo3b","tpage_name":"demo3"}],[97320962,{"idx":2,"name":"demo2c","tpage_name":"demo2"}],[97320961,{"idx":1,"name":"demo2b","tpage_name":"demo2"}],[97320960,{"idx":0,"name":"demo2a","tpage_name":"demo2"}],[96927748,{"idx":4,"name":"vil1-sky-03","tpage_name":"demo-vis-alpha"}],[96927747,{"idx":3,"name":"vil1-sky-02","tpage_name":"demo-vis-alpha"}],[96927746,{"idx":2,"name":"vil1-sky-01","tpage_name":"demo-vis-alpha"}],[96927745,{"idx":1,"name":"vil1-sky-00","tpage_name":"demo-vis-alpha"}],[96927744,{"idx":0,"name":"vil1-clouds","tpage_name":"demo-vis-alpha"}],[96731136,{"idx":0,"name":"cv-water","tpage_name":"village2-vis-water"}],[95485988,{"idx":36,"name":"vest-01","tpage_name":"intro-vis-pris"}],[95485987,{"idx":35,"name":"hair-01","tpage_name":"intro-vis-pris"}],[95485986,{"idx":34,"name":"farmer-teeth","tpage_name":"intro-vis-pris"}],[95485985,{"idx":33,"name":"esskin","tpage_name":"intro-vis-pris"}],[95485984,{"idx":32,"name":"espants-02","tpage_name":"intro-vis-pris"}],[95485983,{"idx":31,"name":"espants-01","tpage_name":"intro-vis-pris"}],[95485981,{"idx":29,"name":"eseyebrow","tpage_name":"intro-vis-pris"}],[95485980,{"idx":28,"name":"eseye","tpage_name":"intro-vis-pris"}],[95485979,{"idx":27,"name":"evilbro-eyelid","tpage_name":"intro-vis-pris"}],[95485978,{"idx":26,"name":"esbelly-01","tpage_name":"intro-vis-pris"}],[95485977,{"idx":25,"name":"es-precursor-metal-01","tpage_name":"intro-vis-pris"}],[95485976,{"idx":24,"name":"es-green-metal","tpage_name":"intro-vis-pris"}],[95485975,{"idx":23,"name":"ogre-envmap","tpage_name":"intro-vis-pris"}],[95485974,{"idx":22,"name":"evilbro-wrap","tpage_name":"intro-vis-pris"}],[95485973,{"idx":21,"name":"evilbro-teeth","tpage_name":"intro-vis-pris"}],[95485972,{"idx":20,"name":"evilbro-strap","tpage_name":"intro-vis-pris"}],[95485971,{"idx":19,"name":"evilbro-rings","tpage_name":"intro-vis-pris"}],[95485970,{"idx":18,"name":"evilbro-redcape","tpage_name":"intro-vis-pris"}],[95485969,{"idx":17,"name":"evilbro-pipes","tpage_name":"intro-vis-pris"}],[95485968,{"idx":16,"name":"evilbro-pants","tpage_name":"intro-vis-pris"}],[95485967,{"idx":15,"name":"evilbro-mechglove-02","tpage_name":"intro-vis-pris"}],[95485966,{"idx":14,"name":"evilbro-mechglove-01","tpage_name":"intro-vis-pris"}],[95485965,{"idx":13,"name":"evilbro-mecharm-03","tpage_name":"intro-vis-pris"}],[95485964,{"idx":12,"name":"evilbro-mecharm-02","tpage_name":"intro-vis-pris"}],[95485962,{"idx":10,"name":"evilbro-hair-01","tpage_name":"intro-vis-pris"}],[95485961,{"idx":9,"name":"evilbro-flesh","tpage_name":"intro-vis-pris"}],[95485959,{"idx":7,"name":"evilbro-envmap","tpage_name":"intro-vis-pris"}],[95485958,{"idx":6,"name":"evilbro-chin","tpage_name":"intro-vis-pris"}],[95485957,{"idx":5,"name":"evilbro-brownleather","tpage_name":"intro-vis-pris"}],[95485956,{"idx":4,"name":"evilbro-blueleather-02","tpage_name":"intro-vis-pris"}],[95485955,{"idx":3,"name":"evilbro-blueleather-01","tpage_name":"intro-vis-pris"}],[95485954,{"idx":2,"name":"evilbro-belt","tpage_name":"intro-vis-pris"}],[95485953,{"idx":1,"name":"evilbro-beard","tpage_name":"intro-vis-pris"}],[95485952,{"idx":0,"name":"evilbro-balls","tpage_name":"intro-vis-pris"}],[95354886,{"idx":6,"name":"mis-rockwall-trim","tpage_name":"intro-vis-tfrag"}],[95354885,{"idx":5,"name":"mis-ground","tpage_name":"intro-vis-tfrag"}],[95354884,{"idx":4,"name":"mis-tree","tpage_name":"intro-vis-tfrag"}],[95354883,{"idx":3,"name":"mis-boLine truncated
|
||||
@@ -52,14 +52,28 @@
|
||||
|
||||
(defenum language-enum
|
||||
:type int64
|
||||
(english)
|
||||
(french)
|
||||
(german)
|
||||
(spanish)
|
||||
(italian)
|
||||
(japanese)
|
||||
(korean)
|
||||
(uk-english)
|
||||
(english 0)
|
||||
(french 1)
|
||||
(german 2)
|
||||
(spanish 3)
|
||||
(italian 4)
|
||||
(japanese 5)
|
||||
(korean 6)
|
||||
(uk-english 7)
|
||||
;; custom
|
||||
(portuguese 8)
|
||||
(finnish 9)
|
||||
(swedish 10)
|
||||
(danish 11)
|
||||
(norwegian 12)
|
||||
(dutch 13)
|
||||
(br-portuguese 14)
|
||||
(hungarian 15)
|
||||
(catalan 16)
|
||||
(icelandic 17)
|
||||
(russian 18)
|
||||
(polish 19)
|
||||
(lithuanian 20)
|
||||
)
|
||||
|
||||
(defenum runtime-exit-status
|
||||
@@ -4188,6 +4202,22 @@ and the state of the VU memory buffers at the end of the bucket."
|
||||
(confirm 24)
|
||||
)
|
||||
|
||||
(defenum abutton-idx
|
||||
:type uint8
|
||||
(right 0)
|
||||
(left 1)
|
||||
(up 2)
|
||||
(down 3)
|
||||
(triangle 4)
|
||||
(circle 5)
|
||||
(x 6)
|
||||
(square 7)
|
||||
(l1 8)
|
||||
(r1 9)
|
||||
(l2 10)
|
||||
(r2 11)
|
||||
)
|
||||
|
||||
(defenum mouse-buttons
|
||||
:bitfield #t
|
||||
:type uint32
|
||||
@@ -8787,6 +8817,8 @@ Unlike [[engine]], users can use [[engine-pers]] as a parent class."
|
||||
(progress-graphics-ps2-lod-dist #x1337)
|
||||
(progress-graphics-msaa-off #x1338)
|
||||
(progress-graphics-display #x1339)
|
||||
(language-name-finnish #x133a)
|
||||
(progress-hint-subtitles #x133b)
|
||||
)
|
||||
;; ---text-id-h:text-id
|
||||
|
||||
@@ -9433,18 +9465,6 @@ Unlike [[engine]], users can use [[engine-pers]] as a parent class."
|
||||
;; settings-h ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defenum language-enum
|
||||
:type int64
|
||||
(english)
|
||||
(french)
|
||||
(german)
|
||||
(spanish)
|
||||
(italian)
|
||||
(japanese)
|
||||
(korean)
|
||||
(uk-english)
|
||||
)
|
||||
|
||||
(defenum game-feature
|
||||
:type uint64
|
||||
:bitfield #t
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
"rip_collision": false,
|
||||
// save game textures as .png files to decompiler_out/<game>/textures
|
||||
"save_texture_pngs": false,
|
||||
|
||||
|
||||
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
|
||||
"rip_streamed_audio": false,
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
[]
|
||||
[[232521729,{"idx":1,"name":"dig-shrub-pebbles","tpage_name":"dig3b-vis-shrub"}],[232521728,{"idx":0,"name":"dig-rock-shrubs","tpage_name":"dig3b-vis-shrub"}],[230227972,{"idx":4,"name":"firework-mini-glow-orange","tpage_name":"outrocst-sprite"}],[230227971,{"idx":3,"name":"firework-dust-grey","tpage_name":"outrocst-sprite"}],[230227970,{"idx":2,"name":"firework-mini-glow-grey","tpage_name":"outrocst-sprite"}],[230227969,{"idx":1,"name":"firework-mini-glow","tpage_name":"outrocst-sprite"}],[230227968,{"idx":0,"name":"firework-dust","tpage_name":"outrocst-sprite"}],[229244928,{"idx":0,"name":"cpad-grass-fringe","tpage_name":"caspad-vis-alpha"}],[227999746,{"idx":2,"name":"sew-mar-ruby-env","tpage_name":"sewer-warp"}],[226623489,{"idx":1,"name":"explosion","tpage_name":"casboss-sprite"}],[226623488,{"idx":0,"name":"cboss-green-lightning-01","tpage_name":"casboss-sprite"}],[226164805,{"idx":69,"name":"stdmc-yellow-light-02","tpage_name":"stadiumb-vis-tfrag"}],[226164804,{"idx":68,"name":"stdmc-yellow-light-01","tpage_name":"stadiumb-vis-tfrag"}],[226164803,{"idx":67,"name":"stdmb-redlight-02","tpage_name":"stadiumb-vis-tfrag"}],[226164801,{"idx":65,"name":"race-hatch-side-01","tpage_name":"stadiumb-vis-tfrag"}],[226164800,{"idx":64,"name":"stdmb-pipe-04a","tpage_name":"stadiumb-vis-tfrag"}],[226164799,{"idx":63,"name":"stdmb-blastdoors-ramp","tpage_name":"stadiumb-vis-tfrag"}],[226164798,{"idx":62,"name":"stdmb-green-grill-light-02","tpage_name":"stadiumb-vis-tfrag"}],[226164797,{"idx":61,"name":"stdmb-floor-01","tpage_name":"stadiumb-vis-tfrag"}],[226164796,{"idx":60,"name":"stdmb-startline","tpage_name":"stadiumb-vis-tfrag"}],[226164795,{"idx":59,"name":"stdmb-green-grill-light-01-hitweak","tpage_name":"stadiumb-vis-tfrag"}],[226164794,{"idx":58,"name":"stdmb-pillar-01-hitweak","tpage_name":"stadiumb-vis-tfrag"}],[226164793,{"idx":57,"name":"stdmb-trim-02","tpage_name":"stadiumb-vis-tfrag"}],[226164792,{"idx":56,"name":"stdmb-arena-floor","tpage_name":"stadiumb-vis-tfrag"}],[226164791,{"idx":55,"name":"stdmb-forcefield-light-02","tpage_name":"stadiumb-vis-tfrag"}],[226164790,{"idx":54,"name":"stdmb-panel-10","tpage_name":"stadiumb-vis-tfrag"}],[226164789,{"idx":53,"name":"stdmb-honeycomb-glow-01","tpage_name":"stadiumb-vis-tfrag"}],[226164788,{"idx":52,"name":"stdmb-road-side-02","tpage_name":"stadiumb-vis-tfrag"}],[226164787,{"idx":51,"name":"stdmb-redstripe","tpage_name":"stadiumb-vis-tfrag"}],[226164786,{"idx":50,"name":"stdmb-shaft-rim-01","tpage_name":"stadiumb-vis-tfrag"}],[226164785,{"idx":49,"name":"stdmb-wall-01","tpage_name":"stadiumb-vis-tfrag"}],[226164784,{"idx":48,"name":"stdmb-track-01","tpage_name":"stadiumb-vis-tfrag"}],[226164783,{"idx":47,"name":"stdmb-track-02","tpage_name":"stadiumb-vis-tfrag"}],[226164782,{"idx":46,"name":"stdmb-roof-01","tpage_name":"stadiumb-vis-tfrag"}],[226164781,{"idx":45,"name":"stdmb-slope-metal","tpage_name":"stadiumb-vis-tfrag"}],[226164780,{"idx":44,"name":"stdmb-tech-walls","tpage_name":"stadiumb-vis-tfrag"}],[226164779,{"idx":43,"name":"stdmb-sign-glow-blue","tpage_name":"stadiumb-vis-tfrag"}],[226164778,{"idx":42,"name":"stdmb-rail-02","tpage_name":"stadiumb-vis-tfrag"}],[226164777,{"idx":41,"name":"stdmb-pipe-04","tpage_name":"stadiumb-vis-tfrag"}],[226164776,{"idx":40,"name":"stdmb-pipe-ring-02","tpage_name":"stadiumb-vis-tfrag"}],[226164775,{"idx":39,"name":"stdmb-pipe-ring-03","tpage_name":"stadiumb-vis-tfrag"}],[226164774,{"idx":38,"name":"stdmb-floor-plate-01","tpage_name":"stadiumb-vis-tfrag"}],[226164773,{"idx":37,"name":"stdmb-arrow-gradient","tpage_name":"stadiumb-vis-tfrag"}],[226164772,{"idx":36,"name":"stdmb-pipe-01","tpage_name":"stadiumb-vis-tfrag"}],[226164771,{"idx":35,"name":"stdmb-track-side-01","tpage_name":"stadiumb-vis-tfrag"}],[226164770,{"idx":34,"name":"stdmb-panel-05","tpage_name":"stadiumb-vis-tfrag"}],[226164769,{"idx":33,"name":"stdmb-panel-11","tpage_name":"stadiumb-vis-tfrag"}],[226164768,{"idx":32,"name":"stdmb-panel-09","tpage_name":"stadiumb-vis-tfrag"}],[226164767,{"idx":31,"name":"stdmb-wall-03","tpage_name":"stadiumb-vis-tfrag"}],[226164766,{"idx":30,"name":"stdmb-stone-trim-01","tpage_name":"stadiumb-vis-tfrag"}],[226164765,{"idx":29,"name":"stdmb-panel-08","tpage_name":"stadiumb-vis-tfrag"}],[226164764,{"idx":28,"name":"stdmb-yellowstripe","tpage_name":"stadiumb-vis-tfrag"}],[226164763,{"idx":27,"name":"stdmb-wall-detail-04","tpage_name":"stadiumb-vis-tfrag"}],[226164762,{"idx":26,"name":"stdmb-pipe-02","tpage_name":"stadiumb-vis-tfrag"}],[226164761,{"idx":25,"name":"stdmb-wall-detail-02","tpage_name":"stadiumb-vis-tfrag"}],[226164760,{"idx":24,"name":"stdmb-pipe-ring-01","tpage_name":"stadiumb-vis-tfrag"}],[226164759,{"idx":23,"name":"stdmb-wall-detail-05","tpage_name":"stadiumb-vis-tfrag"}],[226164758,{"idx":22,"name":"stdmb-panel-06","tpage_name":"stadiumb-vis-tfrag"}],[226164757,{"idx":21,"name":"stdmb-pillar-blue-light-01","tpage_name":"stadiumb-vis-tfrag"}],[226164756,{"idx":20,"name":"stdmb-pillar-01","tpage_naLine truncated
|
||||
+336
-259
@@ -219,31 +219,6 @@
|
||||
:flag-assert #xe00000010
|
||||
)
|
||||
|
||||
#|
|
||||
(deftype array (UNKNOWN)
|
||||
((allocated-length int32 :offset-assert 4)
|
||||
(length int32 :offset-assert 0)
|
||||
(content-type type :offset-assert 8) ;; guessed by decompiler
|
||||
(data uint8 :dynamic :offset-assert 12) ;; guessed by decompiler
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
|
||||
)
|
||||
:method-count-assert 0
|
||||
:size-assert #x0
|
||||
:flag-assert #x0
|
||||
)
|
||||
|#
|
||||
|
||||
(define-extern identity
|
||||
"The identity function."
|
||||
(function object object))
|
||||
@@ -557,9 +532,9 @@
|
||||
(new "Allocate a process-tree with the kernel clock." (symbol type string) _type_) ;; 0
|
||||
(activate "Move a process from dead to active, moving it to the given tree." (_type_ process-tree string pointer) process-tree) ;; 9
|
||||
(deactivate "Make a process dead, clean it up, remove it from the active pool, and return to dead pool." (_type_) none) ;; 10
|
||||
(init-from-entity! (_type_ entity-actor) object) ;; 11
|
||||
(init-from-entity! "Set up a newly created process from the entity that created it." (_type_ entity-actor) object) ;; 11
|
||||
(run-logic? "Should this process be run? Checked by execute-process-tree." (_type_) symbol) ;; 12
|
||||
(process-tree-method-13 () none) ;; 13
|
||||
(entity-info-slot "Not a method. This vtable slot stores entity-info for this type." () none) ;; 13
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1971,6 +1946,8 @@
|
||||
)
|
||||
|
||||
(deftype lissajous (structure)
|
||||
"A curve where the x and y position are set by two different sinusoids.
|
||||
This stores the parameters and state for evaluating this curve."
|
||||
((x-mag float :offset-assert 0)
|
||||
(y-mag float :offset-assert 4)
|
||||
(theta float :offset-assert 8)
|
||||
@@ -1984,11 +1961,14 @@
|
||||
:size-assert #x1c
|
||||
:flag-assert #xa0000001c
|
||||
(:methods
|
||||
(lissajous-method-9 (_type_ vector) vector) ;; 9
|
||||
(evaluate! "Set the x and y component of the vector to the current point on the curve."
|
||||
(_type_ vector) vector) ;; 9
|
||||
)
|
||||
)
|
||||
|
||||
(deftype lissajous-interp (structure)
|
||||
"Handles interpolating between two different lissajous parameters, and also
|
||||
stepping forward the dynamics."
|
||||
((current lissajous :inline :offset-assert 0)
|
||||
(dest lissajous :inline :offset-assert 28)
|
||||
(rate lissajous :inline :offset-assert 56)
|
||||
@@ -1997,8 +1977,10 @@
|
||||
:size-assert #x54
|
||||
:flag-assert #xb00000054
|
||||
(:methods
|
||||
(lissajous-interp-method-9 (_type_ vector) vector) ;; 9
|
||||
(lissajous-interp-method-10 (_type_) float) ;; 10
|
||||
(evaluate! "Set the x and y component of the vector to the current point on the curve."
|
||||
(_type_ vector) vector) ;; 9
|
||||
(update! "Update both the interpolation, and the curves themselves."
|
||||
(_type_) float) ;; 10
|
||||
)
|
||||
)
|
||||
|
||||
@@ -2012,6 +1994,7 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(deftype transformq (transform)
|
||||
"A transform, but the rotation is represented with a quaternion."
|
||||
((quat quaternion :inline :offset 16 :score 1)
|
||||
)
|
||||
:method-count-assert 9
|
||||
@@ -2020,6 +2003,7 @@
|
||||
)
|
||||
|
||||
(deftype trsq (trs)
|
||||
"A trs, but the rotation is represented with a quaternion."
|
||||
((quat quaternion :inline :offset 32 :score 1)
|
||||
)
|
||||
:method-count-assert 9
|
||||
@@ -2296,8 +2280,6 @@
|
||||
;; quaternion ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; quaternion is already defined!
|
||||
|
||||
(define-extern quaternion-axis-angle!
|
||||
"Construct a quaternion from an axis and angle. The axis should be normalized."
|
||||
(function quaternion float float float float quaternion))
|
||||
@@ -4603,6 +4585,24 @@
|
||||
)
|
||||
;; ---pad:pad-buttons
|
||||
|
||||
;; +++pad:abutton-idx
|
||||
(defenum abutton-idx
|
||||
:type uint8
|
||||
(right 0)
|
||||
(left 1)
|
||||
(up 2)
|
||||
(down 3)
|
||||
(triangle 4)
|
||||
(circle 5)
|
||||
(x 6)
|
||||
(square 7)
|
||||
(l1 8)
|
||||
(r1 9)
|
||||
(l2 10)
|
||||
(r2 11)
|
||||
)
|
||||
;; ---pad:abutton-idx
|
||||
|
||||
;; +++pad:mouse-buttons
|
||||
(defenum mouse-buttons
|
||||
:bitfield #t
|
||||
@@ -5843,7 +5843,7 @@
|
||||
(define-extern matrix-remove-z-rot "Remove the z rotation component of a rotation." (function matrix vector matrix))
|
||||
(define-extern matrix-rot-diff!
|
||||
"Get the difference of rotation between two matrices, expressed as a quaternion."
|
||||
(function vector matrix matrix float))
|
||||
(function quaternion matrix matrix float))
|
||||
(define-extern quaternion-seek
|
||||
"Strange quaternion rotate toward function. arg3 is ignored. arg4 is the max seek amount."
|
||||
(function quaternion quaternion quaternion float float quaternion))
|
||||
@@ -7523,27 +7523,27 @@
|
||||
;; +++level-h:bigmap-id
|
||||
(defenum bigmap-id
|
||||
:type uint32
|
||||
(bigmap-id-0 0)
|
||||
(bigmap-id-1 1)
|
||||
(city 0)
|
||||
(comb 1)
|
||||
(desert 2)
|
||||
(factory 3)
|
||||
(forest 4)
|
||||
(mhcity 5)
|
||||
(mine 6)
|
||||
(nest 7)
|
||||
(bigmap-id-8 8)
|
||||
(no-map 9)
|
||||
(precursor 10)
|
||||
(bigmap-id-11 11)
|
||||
(nest2 8)
|
||||
(none 9)
|
||||
(precursor1 10)
|
||||
(precursor2 11)
|
||||
(rubble 12)
|
||||
(sewer0 13)
|
||||
(sewer1 14)
|
||||
(sewer2 15)
|
||||
(sewer-hum-kg 13)
|
||||
(sewer-kg-met 14)
|
||||
(sewer-met-hum 15)
|
||||
(stadium 16)
|
||||
(temple 17)
|
||||
(bigmap-id-18 18)
|
||||
(bigmap-id-19 19)
|
||||
(bigmap-id-20 20)
|
||||
(temple1 17)
|
||||
(temple2 18)
|
||||
(temple3 19)
|
||||
(temple4 20)
|
||||
(tower 21)
|
||||
(volcano 22)
|
||||
(wascity 23)
|
||||
@@ -7885,7 +7885,7 @@
|
||||
(update-vis-volumes (_type_) none) ;; 23 ;; (art-group-get-by-name (_type_ string (pointer uint32)) art-group)
|
||||
(level-group-method-24 (_type_) none) ;; 24 ;; (alt-load-command-get-index (_type_ symbol int) pair)
|
||||
(print-volume-sizes (_type_) none) ;; 25
|
||||
(status-of-level-and-borrows "Get the combined status of a level and borrow levels." (_type_ symbol symbol) symbol) ;; 26 ;; (update-vis-volumes-from-nav-mesh (_type_) none)
|
||||
(level-status? "Get the combined status of a level and borrow levels." (_type_ symbol symbol) symbol) ;; 26 ;; (update-vis-volumes-from-nav-mesh (_type_) none)
|
||||
(do-nothing "Empty method." (_type_) none) ;; 27
|
||||
(load-in-progress? "Is there a load happening now?" (_type_) symbol) ;; 28 ;; (level-status (_type_ symbol) symbol)
|
||||
(is-load-allowed? "Does the exclusive-load setting allow us to load this level?" (_type_ (pointer symbol)) symbol) ;; 29
|
||||
@@ -8288,7 +8288,7 @@
|
||||
(define-extern *font-default-matrix* matrix)
|
||||
(define-extern *font-work* font-work)
|
||||
(define-extern font-set-tex0 (function (pointer gs-tex0) texture int int int none))
|
||||
(define-extern set-font-color (function font-color int rgba rgba rgba int))
|
||||
(define-extern set-font-color (function font-color rgba rgba rgba rgba int))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; decomp-h ;;
|
||||
@@ -10724,16 +10724,55 @@
|
||||
:flag-assert #x900000180
|
||||
)
|
||||
|
||||
;; +++bigmap-h:bigmap-flag
|
||||
(defenum bigmap-flag
|
||||
:type uint32
|
||||
:bitfield #t
|
||||
(bf00 0)
|
||||
(bf01 1)
|
||||
(bf02 2)
|
||||
(bf03 3)
|
||||
(bf04 4)
|
||||
(bf05 5)
|
||||
(bf06 6)
|
||||
(bf07 7)
|
||||
(bf08 8)
|
||||
(bf09 9)
|
||||
(bf10 10)
|
||||
(bf11 11)
|
||||
(bf12 12)
|
||||
(bf13 13)
|
||||
(bf14 14)
|
||||
(bf15 15)
|
||||
(bf16 16)
|
||||
(bf17 17)
|
||||
(ctywide 18)
|
||||
(waswide 19)
|
||||
(wasall 20)
|
||||
(desert 21)
|
||||
(bf22 22)
|
||||
(bf23 23)
|
||||
(bf24 24)
|
||||
(bf25 25)
|
||||
(bf26 26)
|
||||
(bf27 27)
|
||||
(bf28 28)
|
||||
(bf29 29)
|
||||
(bf30 30)
|
||||
(bf31 31)
|
||||
)
|
||||
;; ---bigmap-h:bigmap-flag
|
||||
|
||||
(deftype bigmap (basic)
|
||||
((drawing-flag symbol :offset-assert 4) ;; guessed by decompiler
|
||||
(loading-flag symbol :offset-assert 8) ;; guessed by decompiler
|
||||
(bigmap-index uint32 :offset-assert 12)
|
||||
(bigmap-index bigmap-id :offset-assert 12)
|
||||
(bigmap-image external-art-buffer :offset-assert 16) ;; guessed by decompiler
|
||||
(tpage external-art-buffer :offset-assert 20) ;; guessed by decompiler
|
||||
(tpage2 basic :offset-assert 24)
|
||||
(tpage2 external-art-buffer :offset-assert 24)
|
||||
(progress-minimap texture-page :offset-assert 28) ;; guessed by decompiler
|
||||
(progress-minimap2 texture-page :offset-assert 32)
|
||||
(load-index uint32 :offset-assert 36)
|
||||
(load-index bigmap-id :offset-assert 36)
|
||||
(x0 int32 :offset-assert 40)
|
||||
(y0 int32 :offset-assert 44)
|
||||
(x1 int32 :offset-assert 48)
|
||||
@@ -10748,29 +10787,29 @@
|
||||
(scroll vector :inline :offset-assert 176)
|
||||
(pos vector4w :inline :offset-assert 192)
|
||||
(color vector4w :inline :offset-assert 208)
|
||||
(corner vector 4 :inline :offset-assert 224) ;; guessed by decompiler
|
||||
(corner vector 4 :inline :offset-assert 224) ;; guessed by decompiler
|
||||
(auto-save-icon-flag symbol :offset-assert 288) ;; guessed by decompiler
|
||||
(global-flags uint32 :offset-assert 292)
|
||||
(global-flags bigmap-flag :offset-assert 292)
|
||||
)
|
||||
:method-count-assert 23
|
||||
:size-assert #x128
|
||||
:flag-assert #x1700000128
|
||||
(:methods
|
||||
(new (symbol type) _type_) ;; 0 ;; (new (symbol type) _type_)
|
||||
(bigmap-method-9 () none) ;; 9 ;; (initialize (_type_) none)
|
||||
(new (symbol type) _type_) ;; 0
|
||||
(initialize (_type_) none) ;; 9
|
||||
(update (_type_) none) ;; 10
|
||||
(bigmap-method-11 (_type_) symbol) ;; 11
|
||||
(bigmap-method-12 () none) ;; 12 ;; (handle-cpad-inputs (_type_) int)
|
||||
(bigmap-method-13 () none) ;; 13 ;; (compress-all (_type_) int)
|
||||
(loaded? (_type_) symbol) ;; 11
|
||||
(draw! (_type_ int int int int) none) ;; 12 ;; (handle-cpad-inputs (_type_) int)
|
||||
(handle-cpad-input (_type_) none) ;; 13 ;; (compress-all (_type_) int)
|
||||
(enable-drawing (_type_) none) ;; 14
|
||||
(disable-drawing (_type_) int) ;; 15
|
||||
(bigmap-method-16 (_type_) none) ;; 16 ;; (dump-to-file (_type_) file-stream)
|
||||
(bigmap-method-17 () none) ;; 17 ;; (set-pos! (_type_ vector) int)
|
||||
(bigmap-method-18 () none) ;; 18 ;; (decompress-current-masks! (_type_) int)
|
||||
(bigmap-method-19 () none) ;; 19 ;; (compress-current-masks! (_type_) int)
|
||||
(bigmap-method-20 () none) ;; 20 ;; (set-enable-from-position! (_type_) int)
|
||||
(bigmap-method-21 () none) ;; 21 ;; (maybe-fill-for-position (_type_ int int) int)
|
||||
(bigmap-method-22 () none) ;; 22 ;; (texture-upload-dma (_type_ dma-buffer (pointer uint32) int int int gs-psm) none)
|
||||
(set-map-indices! (_type_) none) ;; 16 ;; (dump-to-file (_type_) file-stream)
|
||||
(set-pos! (_type_ vector) none) ;; 17
|
||||
(bigmap-method-18 (_type_ (pointer int32)) none) ;; 18 ;; (decompress-current-masks! (_type_) int)
|
||||
(texture-upload-dma (_type_ dma-buffer (pointer uint32) int int int gs-psm) none) ;; 19 ;; (compress-current-masks! (_type_) int)
|
||||
(bigmap-method-20 (_type_ dma-buffer) symbol) ;; 20 ;; (set-enable-from-position! (_type_) int)
|
||||
(sprite-dma (_type_ dma-buffer int int int int int int) object) ;; 21 ;; (maybe-fill-for-position (_type_ int int) int)
|
||||
(draw-from-minimap (_type_ dma-buffer connection-minimap) none) ;; 22
|
||||
)
|
||||
)
|
||||
|
||||
@@ -11485,13 +11524,13 @@
|
||||
(scan-tmpl dma-gif-packet :inline :offset-assert 192)
|
||||
(color vector4w :inline :offset-assert 224)
|
||||
(line-color uint64 :offset-assert 240)
|
||||
(scan-colors vector4w 15 :inline :offset-assert 256) ;; guessed by decompiler
|
||||
(scan-colors vector4w 15 :inline :offset-assert 256) ;; guessed by decompiler
|
||||
(zoom-blur-pos vector :inline :offset-assert 496)
|
||||
(zoom-blur-count int32 :offset-assert 512)
|
||||
(zoom-blur-texels int32 :offset-assert 516)
|
||||
(zoom-blur-alpha-target float :offset-assert 520)
|
||||
(zoom-blur-alpha-current float :offset-assert 524)
|
||||
(zoom-blur-2d basic :offset-assert 528)
|
||||
(zoom-blur-2d symbol :offset-assert 528)
|
||||
(menu-mode symbol :offset-assert 532) ;; guessed by decompiler
|
||||
(screen-copied symbol :offset-assert 536) ;; guessed by decompiler
|
||||
(vu1-enable-user-menu vu1-renderer-mask :offset-assert 544)
|
||||
@@ -11509,18 +11548,18 @@
|
||||
:size-assert #x24c
|
||||
:flag-assert #x1b0000024c
|
||||
(:methods
|
||||
(blit-displays-work-method-9 () none) ;; 9
|
||||
(blit-displays-work-method-10 () none) ;; 10
|
||||
(blit-displays-work-method-11 () none) ;; 11
|
||||
(blit-displays-work-method-12 () none) ;; 12
|
||||
(blit-displays-work-method-13 () none) ;; 13
|
||||
(blit-displays-work-method-14 () none) ;; 14
|
||||
(blit-displays-work-method-15 () none) ;; 15
|
||||
(blit-displays-work-method-16 () none) ;; 16
|
||||
(blit-displays-work-method-17 (_type_ vector int float symbol) none) ;; 17
|
||||
(blit-displays-work-method-18 () none) ;; 18
|
||||
(blit-displays-work-method-19 (_type_) none) ;; 19 (called from main.gc)
|
||||
(blit-displays-work-method-20 (_type_) none) ;; 20
|
||||
(blit-displays-work-method-9 (_type_ dma-buffer int int int) none) ;; 9
|
||||
(blit-displays-work-method-10 (_type_ dma-buffer int int int) none) ;; 10
|
||||
(blit-displays-work-method-11 (_type_ dma-buffer int) none) ;; 11
|
||||
(draw-letterbox (_type_ dma-buffer float int float) none) ;; 12
|
||||
(blit-displays-work-method-13 (_type_ dma-buffer int int int) none) ;; 13
|
||||
(blit-displays-work-method-14 (_type_ dma-buffer vector) none) ;; 14
|
||||
(blit-displays-work-method-15 (_type_ dma-buffer) none) ;; 15
|
||||
(draw-zoom-blur (_type_ dma-buffer int) none) ;; 16
|
||||
(setup-zoom-blur-2d (_type_ vector int float symbol) none) ;; 17
|
||||
(setup-brightness-and-contrast (_type_ dma-buffer float float) none) ;; 18
|
||||
(do-blit-displays (_type_) none) ;; 19 (called from main.gc)
|
||||
(draw-sky (_type_ dma-buffer) none) ;; 20
|
||||
(get-menu-mode (_type_) symbol) ;; 21
|
||||
(get-screen-copied (_type_) symbol) ;; 22
|
||||
(get-horizontal-flip-flag (_type_) symbol) ;; 23
|
||||
@@ -17273,7 +17312,7 @@
|
||||
(task-node-commands (array game-task-node-command) :offset-assert 416)
|
||||
(task-node-exclusive (array uint16) :offset-assert 420)
|
||||
(task-counter uint32 :offset-assert 424)
|
||||
(unknown-arr4 (array uint16) :offset-assert 428)
|
||||
(talker-state (array uint16) :offset-assert 428)
|
||||
(level-opened uint8 32 :offset-assert 432)
|
||||
(total-deaths int32 :offset-assert 464)
|
||||
(continue-deaths int32 :offset-assert 468)
|
||||
@@ -17510,20 +17549,25 @@
|
||||
(defenum talker-flags
|
||||
:type uint16
|
||||
:bitfield #t
|
||||
(tf0 0)
|
||||
(tf1 1)
|
||||
(tf2 2)
|
||||
(tf3 3)
|
||||
(tf4 4)
|
||||
(tf5 5)
|
||||
(tf6 6)
|
||||
(tf7 7)
|
||||
(tf8 8)
|
||||
(play-only-once 0)
|
||||
(reduce-volume 1)
|
||||
(auto-save-on-each-start 2)
|
||||
(auto-save-once-on-exit 3)
|
||||
(only-play-in-region 4)
|
||||
(fade-in 5)
|
||||
(slide-in 6)
|
||||
(bigger-font 7)
|
||||
(long-timeout 8)
|
||||
)
|
||||
;; ---ambient-h:talker-flags
|
||||
|
||||
(deftype talker-speech-class (structure)
|
||||
"Contains metadata about a voice line or hint text being played/displayed."
|
||||
"Contains metadata about a voice line or hint text being played/displayed.
|
||||
In the talker state, there's a pos-state and neg-state.
|
||||
Calling yes-play! adjusts the pos-state and no-play! adjusts the neg-state.
|
||||
Playback is only allowed if the pos-state is less than or equal to pos
|
||||
and neg-state is greater than or equal to neg.
|
||||
"
|
||||
((name string :offset-assert 0)
|
||||
(channel gui-channel :offset-assert 4)
|
||||
(flags talker-flags :offset-assert 6)
|
||||
@@ -17542,11 +17586,11 @@
|
||||
:flag-assert #xe00000020
|
||||
;; field on-close uses ~A with a signed load.
|
||||
(:methods
|
||||
(talker-speech-class-method-9 (_type_) symbol) ;; 9
|
||||
(play-communicator-speech! (_type_) none) ;; 10
|
||||
(talker-speech-class-method-11 (_type_) none) ;; 11
|
||||
(talker-speech-class-method-12 (_type_ int) none) ;; 12
|
||||
(talker-speech-class-method-13 (_type_ int) none) ;; 13
|
||||
(should-play? "Return if the talker is in a state where it should play." (_type_) symbol) ;; 9
|
||||
(mark-played! "Mark something as played by making its state UINT16_MAX" (_type_) none) ;; 10
|
||||
(reset-state! "Reset the state of this talker to 0 (the initial value)" (_type_) none) ;; 11
|
||||
(yes-play! (_type_ int) none) ;; 12
|
||||
(no-play! (_type_ int) none) ;; 13
|
||||
)
|
||||
)
|
||||
|
||||
@@ -19409,11 +19453,6 @@
|
||||
:bitfield #t
|
||||
:type uint32
|
||||
(disabled) ;; keep object velocity
|
||||
(af01)
|
||||
(af02)
|
||||
(af03)
|
||||
(af04)
|
||||
(af05)
|
||||
)
|
||||
;; ---aligner-h:align-flags
|
||||
|
||||
@@ -19599,9 +19638,9 @@
|
||||
(sf23 23)
|
||||
(sf24 24)
|
||||
(sf25 25)
|
||||
(sf26 26)
|
||||
(hang 26)
|
||||
(sf27 27)
|
||||
(sf28 28)
|
||||
(invisible 28)
|
||||
(sf29 29)
|
||||
(sf30 30)
|
||||
(sf31 31)
|
||||
@@ -21960,8 +21999,8 @@
|
||||
(unknown-float37 float :offset 5636)
|
||||
(unknown-vector37 vector :inline :offset 5648)
|
||||
(unknown-vector38 vector :inline :offset 5664)
|
||||
(unknown-vector39 vector :inline :offset 5680)
|
||||
(unknown-vector40 vector :inline :offset 5696)
|
||||
(unknown-quat39 quaternion :inline :offset 5680)
|
||||
(unknown-quat40 quaternion :inline :offset 5696)
|
||||
(sliding-start-time time-frame :offset 5712)
|
||||
(unknown-time-frame18 time-frame :offset 5720)
|
||||
(unknown-sound-id00 sound-id :offset 5776)
|
||||
@@ -22409,12 +22448,12 @@
|
||||
:size-assert #xd0
|
||||
:flag-assert #x1c005000d0
|
||||
(:methods
|
||||
(process-mask->search-info-flag (_type_) search-info-flag) ;; 20
|
||||
(get-search-info-flag "Get search-info-flag for this process." (_type_) search-info-flag) ;; 20
|
||||
(get-trans "Get the `trans` for this process." (_type_ int) vector) ;; 21
|
||||
(get-quat "Get the quaternion for this process." (_type_ int) quaternion) ;; 22
|
||||
(get-transv "Get the `transv` for this process." (_type_) vector) ;; 23
|
||||
(time-to-apex-or-ground (_type_ int) int) ;; 24
|
||||
(get-water-height (_type_) meters) ;; 25
|
||||
(get-water-height "Get the height of the water that we're in." (_type_) meters) ;; 25
|
||||
(get-notice-time (_type_) time-frame) ;; 26
|
||||
(get-inv-mass (_type_) float) ;; 27
|
||||
)
|
||||
@@ -22494,7 +22533,7 @@
|
||||
check that the [[collide-spec]] of the focus and the process match."
|
||||
(_type_ process-focusable) object) ;; 10
|
||||
(reset-to-collide-spec "Reset this focus with the given [[collide-spec]]." (_type_ collide-spec) none) ;; 11
|
||||
(try-update-focus "Try to set the `handle` of this focus to the given process." (_type_ process-focusable) symbol) ;; 12
|
||||
(focus-on! "Set the `handle` of this focus to the given process. Return if the handle changed." (_type_ process-focusable) symbol) ;; 12
|
||||
)
|
||||
)
|
||||
|
||||
@@ -23068,7 +23107,7 @@
|
||||
(disable-for-duration (_type_ time-frame) none) ;; 16
|
||||
(ragdoll-proc-method-17 (_type_ ragdoll-edit-info) none) ;; 17
|
||||
(ragdoll-proc-method-18 (_type_ ragdoll-edit-info) none) ;; 18
|
||||
(ragdoll-proc-method-19 (_type_) none) ;; 19
|
||||
(ragdoll-proc-method-19 (_type_) symbol) ;; 19
|
||||
)
|
||||
)
|
||||
|
||||
@@ -25737,7 +25776,7 @@
|
||||
(bit-4 4)
|
||||
(bit-5 5)
|
||||
(subtask-complete 6)
|
||||
(bit-7 7)
|
||||
(special 7)
|
||||
(complete 8)
|
||||
(bit-9 9)
|
||||
(bit-10 10)
|
||||
@@ -29075,7 +29114,7 @@
|
||||
(clamp-vector-to-mesh-no-gaps (_type_ vector nav-poly vector clamp-travel-vector-to-mesh-return-info) none) ;; 21
|
||||
(find-first-sphere-and-update-avoid-params (_type_ vector nav-avoid-spheres-params) float) ;; 22
|
||||
(set-spheres-from-nav-ids (_type_) none) ;; 23
|
||||
(add-root-sphere-to-hash! (_type_ vector int) symbol) ;; 24
|
||||
(check-sphere-blocked! (_type_ vector int) symbol) ;; 24
|
||||
(get-max-rotation-rate (_type_) float) ;; 25
|
||||
(get-sphere-mask (_type_) uint) ;; 26
|
||||
(get-target-speed (_type_) meters) ;; 27
|
||||
@@ -29229,7 +29268,7 @@
|
||||
(add-a-sphere-with-flag (_type_ vector int) int) ;; 27
|
||||
(update-from-spheres (_type_) none) ;; 28
|
||||
(sphere-hash-method-29 (_type_ find-nav-sphere-ids-params) none) ;; 29
|
||||
(find-nav-sphere-ids (_type_ find-nav-sphere-ids-params int int) symbol) ;; 30
|
||||
(check-sphere-blocked (_type_ vector int int) symbol) ;; 30
|
||||
(add-sphere-with-mask-and-id (_type_ vector vector float int) symbol) ;; 31
|
||||
(sphere-hash-method-32 (_type_ sphere int) symbol) ;; 32
|
||||
)
|
||||
@@ -31064,7 +31103,7 @@
|
||||
|
||||
(define-extern *blit-displays-work* blit-displays-work)
|
||||
(define-extern draw-color-bars (function blit-displays-work none))
|
||||
(define-extern draw-raw-image (function bucket-id art-group int vector vector level int none))
|
||||
(define-extern draw-raw-image (function blit-displays-work bucket-id art-group vector vector level int none))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; font-data ;;
|
||||
@@ -39229,7 +39268,7 @@
|
||||
;; bigmap ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; (define-extern *bigmap-info-array* object) ;; bigmap-info-array
|
||||
(define-extern *bigmap-info-array* bigmap-info-array)
|
||||
(define-extern *bigmap* bigmap)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@@ -41282,11 +41321,11 @@
|
||||
;; +++enemy-h:enemy-aware
|
||||
(defenum enemy-aware
|
||||
:type uint64
|
||||
(ea0 0)
|
||||
(ea1 1)
|
||||
(ea2 2)
|
||||
(ea3 3)
|
||||
(ea4 4)
|
||||
(unaware 0)
|
||||
(aware1 1)
|
||||
(aware2 2)
|
||||
(hostile 3)
|
||||
(flee 4)
|
||||
)
|
||||
;; ---enemy-h:enemy-aware
|
||||
|
||||
@@ -41331,6 +41370,7 @@
|
||||
(death-start 34)
|
||||
(auto-death-phase-out 35)
|
||||
(has-gem 36)
|
||||
;; these seem to be an extension of the flags for nav-enemy.
|
||||
(ef37 37)
|
||||
(ef38 38)
|
||||
(ef39 39)
|
||||
@@ -41351,8 +41391,10 @@
|
||||
:size-assert #x20
|
||||
:flag-assert #xe00000020
|
||||
(:methods
|
||||
(try-update-focus (_type_ process-focusable enemy) symbol :replace) ;; 12
|
||||
(enemy-focus-method-13 (_type_ process-focusable enemy-aware) symbol) ;; 13
|
||||
(focus-on! "Make this enemy focus on the process-focusable. If already focused, update awareness."
|
||||
(_type_ process-focusable enemy) symbol :replace) ;; 12
|
||||
(focus-on-with-awareness! "Focus on the process-focusable, updating the aware."
|
||||
(_type_ process-focusable enemy-aware) symbol) ;; 13
|
||||
)
|
||||
)
|
||||
|
||||
@@ -41406,34 +41448,34 @@
|
||||
(jump-height-min meters :offset-assert 244)
|
||||
(jump-height-factor float :offset-assert 248)
|
||||
(knocked-seek-ry-clamp float :offset-assert 252)
|
||||
(knocked-soft-vxz-lo float :offset-assert 256)
|
||||
(knocked-soft-vxz-hi float :offset-assert 260)
|
||||
(knocked-soft-vy-lo float :offset-assert 264)
|
||||
(knocked-soft-vy-hi float :offset-assert 268)
|
||||
(knocked-medium-vxz-lo float :offset-assert 272)
|
||||
(knocked-medium-vxz-hi float :offset-assert 276)
|
||||
(knocked-medium-vy-lo float :offset-assert 280)
|
||||
(knocked-medium-vy-hi float :offset-assert 284)
|
||||
(knocked-hard-vxz-lo float :offset-assert 288)
|
||||
(knocked-hard-vxz-hi float :offset-assert 292)
|
||||
(knocked-hard-vy-lo float :offset-assert 296)
|
||||
(knocked-hard-vy-hi float :offset-assert 300)
|
||||
(knocked-huge-vxz-lo float :offset-assert 304)
|
||||
(knocked-huge-vxz-hi float :offset-assert 308)
|
||||
(knocked-huge-vy-lo float :offset-assert 312)
|
||||
(knocked-huge-vy-hi float :offset-assert 316)
|
||||
(knocked-yellow-vxz-lo float :offset-assert 320)
|
||||
(knocked-yellow-vxz-hi float :offset-assert 324)
|
||||
(knocked-yellow-vy-lo float :offset-assert 328)
|
||||
(knocked-yellow-vy-hi float :offset-assert 332)
|
||||
(knocked-red-vxz-lo float :offset-assert 336)
|
||||
(knocked-red-vxz-hi float :offset-assert 340)
|
||||
(knocked-red-vy-lo float :offset-assert 344)
|
||||
(knocked-red-vy-hi float :offset-assert 348)
|
||||
(knocked-blue-vxz-lo float :offset-assert 352)
|
||||
(knocked-blue-vxz-hi float :offset-assert 356)
|
||||
(knocked-blue-vy-lo float :offset-assert 360)
|
||||
(knocked-blue-vy-hi float :offset-assert 364)
|
||||
(knocked-soft-vxz-lo meters :offset-assert 256)
|
||||
(knocked-soft-vxz-hi meters :offset-assert 260)
|
||||
(knocked-soft-vy-lo meters :offset-assert 264)
|
||||
(knocked-soft-vy-hi meters :offset-assert 268)
|
||||
(knocked-medium-vxz-lo meters :offset-assert 272)
|
||||
(knocked-medium-vxz-hi meters :offset-assert 276)
|
||||
(knocked-medium-vy-lo meters :offset-assert 280)
|
||||
(knocked-medium-vy-hi meters :offset-assert 284)
|
||||
(knocked-hard-vxz-lo meters :offset-assert 288)
|
||||
(knocked-hard-vxz-hi meters :offset-assert 292)
|
||||
(knocked-hard-vy-lo meters :offset-assert 296)
|
||||
(knocked-hard-vy-hi meters :offset-assert 300)
|
||||
(knocked-huge-vxz-lo meters :offset-assert 304)
|
||||
(knocked-huge-vxz-hi meters :offset-assert 308)
|
||||
(knocked-huge-vy-lo meters :offset-assert 312)
|
||||
(knocked-huge-vy-hi meters :offset-assert 316)
|
||||
(knocked-yellow-vxz-lo meters :offset-assert 320)
|
||||
(knocked-yellow-vxz-hi meters :offset-assert 324)
|
||||
(knocked-yellow-vy-lo meters :offset-assert 328)
|
||||
(knocked-yellow-vy-hi meters :offset-assert 332)
|
||||
(knocked-red-vxz-lo meters :offset-assert 336)
|
||||
(knocked-red-vxz-hi meters :offset-assert 340)
|
||||
(knocked-red-vy-lo meters :offset-assert 344)
|
||||
(knocked-red-vy-hi meters :offset-assert 348)
|
||||
(knocked-blue-vxz-lo meters :offset-assert 352)
|
||||
(knocked-blue-vxz-hi meters :offset-assert 356)
|
||||
(knocked-blue-vy-lo meters :offset-assert 360)
|
||||
(knocked-blue-vy-hi meters :offset-assert 364)
|
||||
(ragdoll-info ragdoll-setup :offset-assert 368)
|
||||
(shadow-size meters :offset-assert 372)
|
||||
(shadow-max-y meters :offset-assert 376)
|
||||
@@ -41477,6 +41519,16 @@
|
||||
(ejf6 6)
|
||||
(ejf7 7)
|
||||
)
|
||||
|
||||
(defenum jump-stage
|
||||
:type int32
|
||||
(init 0)
|
||||
(winding-up 1)
|
||||
(takeoff 2)
|
||||
(in-air 3)
|
||||
(touchdown 4)
|
||||
(landing 5)
|
||||
)
|
||||
;; ---enemy-h:enemy-jump-flags
|
||||
|
||||
(deftype enemy-jump-info (structure)
|
||||
@@ -41601,109 +41653,125 @@
|
||||
gun-dark-2-stretch ;; 49
|
||||
)
|
||||
(:methods
|
||||
(enemy-method-50 (_type_ int) none) ;; 50
|
||||
(accelerate-fall! (_type_ vector) float) ;; 51
|
||||
(damage-enemy! (_type_ object event-message-block) float) ;; 52
|
||||
(reset-penetrate! (_type_) none) ;; 53
|
||||
(get-knockback-dir! (_type_ vector) vector) ;; 54
|
||||
(get-knockback-angle (_type_) degrees) ;; 55
|
||||
(knocked-handler (_type_ vector) object) ;; 56
|
||||
(can-collide-with-focus? (_type_ process-focusable) object) ;; 57
|
||||
(check-water (_type_) object) ;; 58
|
||||
(enemy-common-post (_type_) none) ;; 59
|
||||
(lerp-damage (_type_ float) float) ;; 60
|
||||
(scale-impact-vel-y! (_type_ vector vector float) vector) ;; 61
|
||||
(get-damage-from-attack (_type_ object event-message-block) float) ;; 62
|
||||
(enemy-method-63 (_type_ float) float) ;; 63
|
||||
(update-awareness! (_type_ process-focusable enemy-best-focus) enemy-aware) ;; 64
|
||||
(penetrate->next-state (_type_ process event-message-block float) symbol) ;; 65
|
||||
(get-penetrated-by (_type_) penetrate) ;; 66
|
||||
(coin-flip? (_type_) symbol) ;; 67
|
||||
(get-enemy-aware (_type_ enemy-aware) enemy-aware) ;; 68
|
||||
(enemy-method-69 (_type_) none) ;; 69
|
||||
(enemy-method-70 (_type_ process-focusable enemy-aware) none) ;; 70
|
||||
(go-dormant (_type_) object) ;; 71
|
||||
(go-dormant-aware (_type_) object) ;; 72
|
||||
(go-idle (_type_) object) ;; 73
|
||||
(go-ambush-delay (_type_) object) ;; 74
|
||||
(update-collision-action "Change the collision for certain conditions (knocked, etc)" (_type_ int) none) ;; 50
|
||||
(adjust-transv-under-water! "Modify the velocity as needed if the enemy is underwater." (_type_ vector) float) ;; 51
|
||||
(damage-enemy-from-attack! "Given an attack message, apply damage." (_type_ object event-message-block) float) ;; 52
|
||||
(reset-penetrate-later! "After a little bit, reset the penetrate flags back to default." (_type_) none) ;; 53
|
||||
(get-knockback-dir! "Compute the knockback direction for an incoming attack." (_type_ vector) vector) ;; 54
|
||||
(get-knockback-angle "Get the yaw angle for the current knock." (_type_) degrees) ;; 55
|
||||
(knocked-handler "Called when this enemy is knocked." (_type_ vector) object) ;; 56
|
||||
(can-focus-on? "Check that this enemy can focus on the given focusable.
|
||||
This reuses the collide bitmask, but isn't actually a collision." (_type_ process-focusable) object) ;; 57
|
||||
(check-water "Respond to possibly being in water." (_type_) object) ;; 58
|
||||
(enemy-common-post "Common implementation of post. Runs ja-post." (_type_) none) ;; 59
|
||||
(impact-velocity-to-hit-points "Given an impact velocity, compute hit points." (_type_ float) float) ;; 60
|
||||
(attack-direction-from-impact-vel "Compute the direction of an attack given an impact velocity.
|
||||
This reduces the vertical component, probably to avoid sending the enemy into the air too much." (_type_ vector vector float) vector) ;; 61
|
||||
(get-damage-from-attack "Compute hit point damage for an attack message." (_type_ object event-message-block) float) ;; 62
|
||||
(apply-incoming-hitpoint-mods "Modify the hitpoints from an incoming attack.
|
||||
Keeps enemy alive for a bit while being shot with a blue gun.
|
||||
This looks cool because you can shoot them many times." (_type_ float) float) ;; 63
|
||||
(get-awareness-of-proc "Check what the enemies awareness of this pfoc would be. Optionally return more awareness stats in enemy-best-focus." (_type_ process-focusable enemy-best-focus) enemy-aware) ;; 64
|
||||
(msg-for-incoming-attack "Given an attack message, what do we do next? Returns a message name that should be sent to self." (_type_ process event-message-block float) symbol) ;; 65
|
||||
(get-penetrated-by "Figure out the penetrated-by mask for this process." (_type_) penetrate) ;; 66
|
||||
(coin-flip? "Return #t half the time, #f the other." (_type_) symbol) ;; 67
|
||||
(modify-awareness "Apply modifications to awareness based on the reaction time of an enemy and other settings." (_type_ enemy-aware) enemy-aware) ;; 68
|
||||
(focus-on-attacker! "If possible, update this enemies focus to the attacker." (_type_) none) ;; 69
|
||||
(set-focus! "Change our focus to the given process. Optionally, specify awareness." (_type_ process-focusable enemy-aware) none) ;; 70
|
||||
(go-dormant "Go to the dormant state. This disables drawing/processing/collision, and runs no logic." (_type_) object) ;; 71
|
||||
(go-dormant-aware "Go to the dormat aware state.
|
||||
Similar to dormant, drawing/collision are disabled, but enemies can exit dormant-aware." (_type_) object) ;; 72
|
||||
(go-idle "Go to an idle state." (_type_) object) ;; 73
|
||||
(go-ambush "May go to ambush-delay first, if set in the res-lump." (_type_) object) ;; 74
|
||||
(go-stare (_type_) object) ;; 75
|
||||
(go-stare2 (_type_) object) ;; 76
|
||||
(go-directed (_type_) object) ;; 77
|
||||
(go-hostile (_type_) object) ;; 78
|
||||
(go-flee (_type_) object) ;; 79
|
||||
(go-best-state (_type_) object) ;; 80
|
||||
(go-die (_type_) object) ;; 81
|
||||
(event-handler (_type_ process int symbol event-message-block) object :behavior enemy) ;; 82
|
||||
(enemy-touch-handler (_type_ process event-message-block) object) ;; 83
|
||||
(send-attack-on-jump-or-knocked (_type_ process event-message-block) object) ;; 84
|
||||
(knocked-anim (_type_ enemy-knocked-info) symbol) ;; 85
|
||||
(knocked-land-anim (_type_ enemy-knocked-info) symbol) ;; 86
|
||||
(knocked-anim-handler (_type_ int enemy-knocked-info) symbol) ;; 87
|
||||
(enemy-method-88 (_type_ enemy-knocked-info) symbol) ;; 88
|
||||
(within-gspot-range? (_type_) symbol) ;; 89
|
||||
(enemy-method-90 (_type_ ragdoll-proc) none) ;; 90
|
||||
(enemy-method-91 (_type_ enemy-jump-info) object) ;; 91
|
||||
(init-jump-info! (_type_ enemy-jump-info) none) ;; 92
|
||||
(setup-jump! (_type_ enemy-jump-info) none) ;; 93
|
||||
(move-to-gspot! (_type_) float) ;; 94
|
||||
(on-ground? (_type_ enemy-jump-info) symbol) ;; 95
|
||||
(jump-in-air-anim (_type_ enemy-jump-info) symbol) ;; 96
|
||||
(jump-land-anim (_type_ enemy-jump-info) symbol) ;; 97
|
||||
(jump-wind-up-anim (_type_ enemy-jump-info) symbol) ;; 98
|
||||
(jump-anim-handler (_type_ int enemy-jump-info) symbol) ;; 99
|
||||
(in-jump-handler (_type_ int enemy-jump-info) none) ;; 100
|
||||
(enemy-method-101 (_type_ int enemy-jump-info) none) ;; 101
|
||||
(go-directed2 (_type_) object) ;; 102
|
||||
(enemy-method-103 (_type_ vector float) symbol) ;; 103
|
||||
(enemy-method-104 (_type_ vector float) symbol) ;; 104
|
||||
(enemy-method-105 (_type_ float symbol) symbol) ;; 105
|
||||
(find-best-focus (_type_) process) ;; 106
|
||||
(is-pfoc-in-mesh? (_type_ process-focusable vector) symbol) ;; 107
|
||||
(enemy-method-108 (_type_ process-focusable) symbol) ;; 108
|
||||
(enemy-method-109 (_type_) symbol) ;; 109
|
||||
(send-attack (_type_ process touching-shapes-entry uint) symbol) ;; 110
|
||||
(on-attack (_type_ process-focusable) none) ;; 111
|
||||
(get-incoming-attack! (_type_ process-drawable event-message-block penetrate attack-info touching-shapes-entry) none) ;; 112
|
||||
(get-focus! (_type_) process-focusable) ;; 113
|
||||
(send-attack-to-all-tshapes (_type_ process-focusable event-message-block) int) ;; 114
|
||||
(set-look-at-mode! (_type_ int) none) ;; 115
|
||||
(stop-look-at! (_type_) none) ;; 116
|
||||
(apply-friction (_type_) none) ;; 117
|
||||
(init-enemy-info! (_type_ enemy-info) none) ;; 118
|
||||
(init-enemy-defaults! (_type_ enemy-info) none) ;; 119
|
||||
(init-enemy-collision! (_type_) none) ;; 120
|
||||
(init-enemy! (_type_) none) ;; 121
|
||||
(go-idle2 (_type_) object) ;; 122
|
||||
(enemy-method-123 (_type_) symbol) ;; 123
|
||||
(disable-ragdoll (_type_) none) ;; 124
|
||||
(ragdoll-settled? (_type_) object) ;; 125
|
||||
(ragdoll-spawn! (_type_ symbol symbol) vector) ;; 126
|
||||
(deactivate-ragdoll! (_type_) none) ;; 127
|
||||
(rnd-float (_type_) float) ;; 128
|
||||
(rnd-float-range (_type_ float float) float) ;; 129
|
||||
(rnd-int (_type_ int) int) ;; 130
|
||||
(enemy-method-131 (_type_ int int) int) ;; 131
|
||||
(set-reaction-time! (_type_ time-frame time-frame) time-frame) ;; 132
|
||||
(rnd-chance? (_type_ float) symbol) ;; 133
|
||||
(enemy-method-134 (_type_ float) symbol) ;; 134
|
||||
(go-directed "Go to the directed state which assumes that something else will control the enemy." (_type_) object) ;; 77
|
||||
(go-hostile "Go to the hostile state, actively trying to attack the target." (_type_) object) ;; 78
|
||||
(go-flee "Go to the flee state, running away." (_type_) object) ;; 79
|
||||
(go-state-for-focused "Go to the appropriate state for the current awareness of the focused process." (_type_) object) ;; 80
|
||||
(go-die "Go to the die state." (_type_) object) ;; 81
|
||||
(event-handler "Commmon handler for events." (_type_ process int symbol event-message-block) object :behavior enemy) ;; 82
|
||||
(enemy-touch-handler "General handler for an event when a process intentionally sends a touch event." (_type_ process event-message-block) object) ;; 83
|
||||
(enemy-touched-handler "General handler for when anything touches an enemy (automatic response)." (_type_ process event-message-block) object) ;; 84
|
||||
(knocked-anim "start the knocked animation." (_type_ enemy-knocked-info) symbol) ;; 85
|
||||
(knocked-land-anim "start the knocked-land animation." (_type_ enemy-knocked-info) symbol) ;; 86
|
||||
(knocked-anim-handler "start or play the approriate animation for an enemy being knocked." (_type_ int enemy-knocked-info) symbol) ;; 87
|
||||
(done-being-knocked? "has the enemy hit the ground or stopped after being knocked back?" (_type_ enemy-knocked-info) symbol) ;; 88
|
||||
(invalid-height? "Return #t if the enemy is too high in the air, or below the ground." (_type_) symbol) ;; 89
|
||||
(copy-ragdoll-orientation-to-root "Apply rotational offset from ragdolling back to the enemy.
|
||||
Used when disabling a ragdoll to update the enemy
|
||||
orientation to match the end of ragdoll orientation." (_type_ ragdoll-proc) none) ;; 90
|
||||
(check-jump-blocked? "Is this jump blocked by something?" (_type_ enemy-jump-info) object) ;; 91
|
||||
(init-jump-info! "Populate an enemy-jump-info for jumping to this enemy's event-param-point" (_type_ enemy-jump-info) none) ;; 92
|
||||
(setup-jump-trajectory! "Compute jump trajectory." (_type_ enemy-jump-info) none) ;; 93
|
||||
(move-to-gspot! "Snap the enemy down onto the cached ground spot (gspot)." (_type_) float) ;; 94
|
||||
(landed-jump-yet? "Is this on, or close to, the ground?" (_type_ enemy-jump-info) symbol) ;; 95
|
||||
(jump-in-air-anim "Start playing the in-air anim" (_type_ enemy-jump-info) symbol) ;; 96
|
||||
(jump-land-anim "Play the landing anim" (_type_ enemy-jump-info) symbol) ;; 97
|
||||
(jump-wind-up-anim "Start playing the wind-up anim" (_type_ enemy-jump-info) symbol) ;; 98
|
||||
(jump-anim-handler (_type_ jump-stage enemy-jump-info) symbol) ;; 99
|
||||
(move-along-ballistic-trajectory-for-jump "Adjust trans, transv for the jump, if we're airborne." (_type_ jump-stage enemy-jump-info) none) ;; 100
|
||||
(adjust-heading-for-jump "Can be overriden. Yaw the enemy in response to an ongoing jump." (_type_ jump-stage enemy-jump-info) none) ;; 101
|
||||
(go-next-state-auto "Pick the next state automatically. Will enter directed state if this enemy is directed, or pick based on focus/aware." (_type_) object) ;; 102
|
||||
(heading-matches-direction? "Does this enemy's heading match the given heading? Threshold in degrees." (_type_ vector float) symbol) ;; 103
|
||||
(pointing-toward? "Is this enemy pointing toward the given point? Threshold in degrees." (_type_ vector float) symbol) ;; 104
|
||||
(pointing-toward-focus? "Is this enemy pointing toward its focused process?" (_type_ float symbol) symbol) ;; 105
|
||||
(find-best-focus "Search for the best thing to focus on." (_type_) process) ;; 106
|
||||
(can-become-hostile-to? "Return if this enemy can become hostile to the process." (_type_ process-focusable vector) symbol) ;; 107
|
||||
(should-flee-from? "Return if this enemy should flee from the process." (_type_ process-focusable) symbol) ;; 108
|
||||
(out-of-bounds? "Has the enemy gone somewhere it shouldn't?
|
||||
Used to kill some enemies that can be knocked of regions." (_type_) symbol) ;; 109
|
||||
(send-attack-from-tshape "Send an attack from this enemy to something else." (_type_ process touching-shapes-entry uint) symbol) ;; 110
|
||||
(on-attack "Handler after this enemy attacks something. By default focuses on the attacked, but could be overriden." (_type_ process-focusable) none) ;; 111
|
||||
(handle-incoming-attack! "Set up this enemy to handle an incoming attack event." (_type_ process-drawable event-message-block penetrate attack-info touching-shapes-entry) none) ;; 112
|
||||
(get-focus! "If we're focusing on something alive, return it." (_type_) process-focusable) ;; 113
|
||||
(find-and-damage-attackers "Find things that have attacked us, then deal damage back.
|
||||
This is used for attacks that damage both the player and the enemy,
|
||||
like hitting a guard with a jetboard." (_type_ process-focusable event-message-block) int) ;; 114
|
||||
(set-look-at-mode! "Pick between 1: look at the focus, or 2: look at where you're going." (_type_ int) none) ;; 115
|
||||
(stop-look-at! "Stop looking at something. Disables neck joint mod." (_type_) none) ;; 116
|
||||
(apply-friction "Slow down the enemy due to friction with the ground." (_type_) none) ;; 117
|
||||
(set-enemy-info! "Set the enemy-info" (_type_ enemy-info) none) ;; 118
|
||||
(setup-enemy! "Initialize the enemy by setting all the enemy-specific fields." (_type_ enemy-info) none) ;; 119
|
||||
(init-enemy-collision! "Typical place to construct collision shapes" (_type_) none) ;; 120
|
||||
(init-enemy! "Typical place for shared init code. Runs from entity or process style init." (_type_) none) ;; 121
|
||||
(go-fallback-init "If there's no specific settings for initial state, go to this state after spawning." (_type_) object) ;; 122
|
||||
(allow-ragdoll? "Can this enemy ragdoll now?" (_type_) symbol) ;; 123
|
||||
(disable-ragdoll "Smoothly disable the ragdoll and transition back to normal control." (_type_) none) ;; 124
|
||||
(ragdoll-settled? "Has the ragdoll stopped moving?" (_type_) object) ;; 125
|
||||
(ragdoll-spawn! "If possible, spawn ragdoll and start using it." (_type_ symbol symbol) vector) ;; 126
|
||||
(deactivate-ragdoll! "Deactivate the ragdoll process." (_type_) none) ;; 127
|
||||
(rnd-float "Get a random number from 0 to 1" (_type_) float) ;; 128
|
||||
(rnd-float-range "Get a random float in the range" (_type_ float float) float) ;; 129
|
||||
(rnd-int "Get a random int from to to the specified int" (_type_ int) int) ;; 130
|
||||
(rnd-int-excluding-masked "Get a random int in the range. Exclude a value n by setting the n-th bit of the mask."(_type_ int int) int) ;; 131
|
||||
(rnd-time-frame "Get a random time frame." (_type_ time-frame time-frame) time-frame) ;; 132
|
||||
(rnd-chance? "Returns true with the given probability." (_type_ float) symbol) ;; 133
|
||||
(rnd-chance-for-idle?
|
||||
"Like rnd-chance, but is more likely to return true when the game is close to not fitting in frame rate.
|
||||
This makes enemies start idling more if the game isn't running fast enough." (_type_ float) symbol) ;; 134
|
||||
(enemy-method-135 (_type_) none) ;; 135
|
||||
(set-ground-pat! (_type_ collide-query collide-spec float float float process) pat-surface) ;; 136
|
||||
(enemy-above-ground? (_type_ collide-query vector collide-spec float float float) symbol) ;; 137
|
||||
(try-locate-ground (_type_ meters meters symbol collide-spec) symbol) ;; 138
|
||||
(move-above-ground! (_type_ vector move-above-ground-params) none) ;; 139
|
||||
(update-focus (_type_) process) ;; 140
|
||||
(enemy-method-141 (_type_ float) symbol) ;; 141
|
||||
(penetrate->knocked-type (_type_ penetrate) knocked-type) ;; 142
|
||||
(find-ground-and-set-pat! "Figure out what ground we're standing on and update the ground-pat.
|
||||
Usually this will be done automatically by the collision system.
|
||||
This method should be called after manually repositioning an enemy." (_type_ collide-query collide-spec float float float process) pat-surface) ;; 136
|
||||
(enemy-above-ground? "Is this enemy above the ground?" (_type_ collide-query vector collide-spec float float float) symbol) ;; 137
|
||||
(move-to-ground "Snap the enemy to the ground below." (_type_ meters meters symbol collide-spec) symbol) ;; 138
|
||||
(move-above-ground! "Move the enemy. May keep the enemy snapped to the ground depending on flags." (_type_ vector move-above-ground-params) none) ;; 139
|
||||
(update-focus "Potentially update the focus, if there is something better to focus on." (_type_) process) ;; 140
|
||||
(check-awareness-trigger "Check triggering logic for awareness to see if this enemy can become aware yet." (_type_ float) symbol) ;; 141
|
||||
(penetrate->knocked-type "Based on the penetrate of an attacker, pick the knocked-type." (_type_ penetrate) knocked-type) ;; 142
|
||||
(on-dying (_type_) none) ;; 143
|
||||
(falling? (_type_) symbol) ;; 144
|
||||
(find-offending-pfoc (_type_ process attack-info) process-focusable) ;; 145
|
||||
(play-damage-sound (_type_ int) sound-id) ;; 146
|
||||
(check-victory (_type_) none) ;; 147
|
||||
(go-gun-dark-2-stretch (_type_) object) ;; 148
|
||||
(have-more-than-10-joints? (_type_) object) ;; 149
|
||||
(enemy-method-150 (_type_) symbol) ;; 150
|
||||
(should-move-to-ground? (_type_) symbol) ;; 151
|
||||
(enemy-method-152 (_type_) float) ;; 152
|
||||
(find-offending-pfoc "Figure out the attacker process from the attack message sender and attack-info.
|
||||
This is to handle cases where the attacker process is a non-focusable subprocess,
|
||||
or the attacker is driving a vehicle."(_type_ process attack-info) process-focusable) ;; 145
|
||||
(play-damage-sound "Pick and play the damage/death sound." (_type_ int) sound-id) ;; 146
|
||||
(clear-stale-victory "Remove victory flag if needed." (_type_) none) ;; 147
|
||||
(go-gun-dark-2-stretch "Go to the gun-dark-2-stretch state." (_type_) object) ;; 148
|
||||
(have-more-than-10-joints? "Does what it says, unused" (_type_) object) ;; 149
|
||||
(can-be-nuked? "Can this enemy be instantly destroyed by the nuke?" (_type_) symbol) ;; 150
|
||||
(should-move-to-ground? "Should this enemy be moved to the ground while moving?" (_type_) symbol) ;; 151
|
||||
(gem-chance "The chance of this enemy having a gem." (_type_) float) ;; 152
|
||||
(get-gem-pool-idx (_type_) int) ;; 153
|
||||
(mark-as-dead (_type_) none) ;; 154
|
||||
)
|
||||
@@ -41777,8 +41845,8 @@
|
||||
debug-control ;; 159
|
||||
)
|
||||
(:methods
|
||||
(init-enemy-info! (_type_ nav-enemy-info) none :replace) ;; 118
|
||||
(init-enemy-defaults! (_type_ nav-enemy-info) object :replace) ;; 125
|
||||
(set-enemy-info! (_type_ nav-enemy-info) none :replace) ;; 118
|
||||
(setup-enemy! (_type_ nav-enemy-info) object :replace) ;; 125
|
||||
(normalize-heading! (_type_ nav-control) none) ;; 160
|
||||
(nav-enemy-method-161 (_type_ nav-control) none) ;; 161
|
||||
(nav-enemy-method-162 (_type_) none) ;; 162
|
||||
@@ -41827,13 +41895,16 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define-extern *enemy-dummy-shadow-control* shadow-control)
|
||||
(define-extern get-penetrate-using-from-attack-event (function process-drawable event-message-block penetrate))
|
||||
(define-extern enemy-setup-gem (function object :behavior enemy))
|
||||
(define-extern enemy-init-by-other (function process-drawable enemy-init-by-other-params object :behavior enemy))
|
||||
(define-extern enemy-event-handler (function process int symbol event-message-block object :behavior enemy))
|
||||
(define-extern enemy-simple-post (function none :behavior enemy))
|
||||
(define-extern enemy-falling-post (function none :behavior enemy))
|
||||
(define-extern enemy-die-falling-post (function none :behavior enemy))
|
||||
(define-extern get-penetrate-using-from-attack-event "Given an attack event to an enemy, return the penetrate that should be applied to the enemy"
|
||||
(function process-drawable event-message-block penetrate))
|
||||
(define-extern enemy-setup-gem "Determine if the enemy should have a gem and set drawing masks/particles as needed." (function object :behavior enemy))
|
||||
(define-extern enemy-init-by-other "Function to initialize an enemy from a parent process." (function process-drawable enemy-init-by-other-params object :behavior enemy))
|
||||
(define-extern enemy-event-handler "Default event handler for enemy." (function process int symbol event-message-block object :behavior enemy))
|
||||
(define-extern enemy-simple-post "Default post for enemy." (function none :behavior enemy))
|
||||
(define-extern enemy-falling-post "Post function that simply makes the enemy go down.
|
||||
Collision is enabled, so enemy will bounce off of walls or similar." (function none :behavior enemy))
|
||||
(define-extern enemy-die-falling-post "Post function that causes the enemy to go down until it hits the ground.
|
||||
Doesn't use full collision system - enemy will stop moving as soon as it hits any ground."(function none :behavior enemy))
|
||||
(define-extern *shockwave-knock-scalar* curve2d-fast)
|
||||
(define-extern ja-group-index? (function int symbol :behavior enemy))
|
||||
|
||||
@@ -42123,6 +42194,12 @@
|
||||
;; rigid-body ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(deftype rigid-body-stack (structure)
|
||||
((vec vector :inline)
|
||||
(mat matrix :inline)
|
||||
)
|
||||
)
|
||||
|
||||
(deftype rigid-body-work (structure)
|
||||
((max-ang-momentum float :offset-assert 0)
|
||||
(max-ang-velocity float :offset-assert 4)
|
||||
@@ -44394,9 +44471,9 @@
|
||||
(within-outer-ring symbol :offset-assert 136)
|
||||
(within-inner-ring symbol :offset-assert 140)
|
||||
(ouched symbol :offset-assert 144)
|
||||
(bound-cam basic :offset-assert 148)
|
||||
(bound-cam string :offset-assert 148)
|
||||
(trans vector :inline :offset-assert 160)
|
||||
(state-time uint64 :offset-assert 176)
|
||||
(state-time time-frame :offset-assert 176)
|
||||
(jak-in-hint-region symbol :offset-assert 184)
|
||||
(watchers-vulnerable symbol :offset-assert 188)
|
||||
)
|
||||
@@ -44429,7 +44506,7 @@
|
||||
standing-down ;; 31
|
||||
)
|
||||
(:methods
|
||||
(tpl-watcher-method-32 (_type_) none) ;; 32
|
||||
(init-collision! (_type_) none) ;; 32
|
||||
)
|
||||
)
|
||||
|
||||
@@ -49308,7 +49385,7 @@
|
||||
in-ditch ;; 192
|
||||
)
|
||||
(:methods
|
||||
(init-enemy-defaults! (_type_ nav-enemy-info) none :replace)
|
||||
;(init-enemy-defaults! (_type_ nav-enemy-info) none :replace)
|
||||
(set-squad (_type_) none) ;; 193
|
||||
(citizen-method-194 (_type_) none) ;; 194
|
||||
(citizen-method-195 (_type_) none) ;; 195
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
"write_hex_near_instructions": false,
|
||||
|
||||
// to write out "scripts", which are currently just all the linked lists found. mostly a jak 2/3 thing
|
||||
"write_scripts": true,
|
||||
"write_scripts": false,
|
||||
|
||||
// hex dump of code/data files.
|
||||
"hexdump_code": false,
|
||||
|
||||
@@ -1000,5 +1000,10 @@
|
||||
[12, "(function none :behavior scene-player)"],
|
||||
[13, "(function none :behavior scene-player)"],
|
||||
[14, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"bigmap": [
|
||||
[15, "(function external-art-buffer object)"],
|
||||
[16, "(function external-art-buffer object)"],
|
||||
[17, "(function external-art-buffer object)"]
|
||||
]
|
||||
}
|
||||
@@ -735,10 +735,6 @@
|
||||
// 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": [
|
||||
["lfac", 0, 0],
|
||||
["ltow", 0, 0],
|
||||
["lcit", 0, 0],
|
||||
["pow", 0, 0],
|
||||
["wasintro", 0, 0],
|
||||
["lfacctyb", 0, 0],
|
||||
["intpfall", 0, 0],
|
||||
|
||||
@@ -186,18 +186,18 @@
|
||||
"DGO/PRECA.DGO",
|
||||
"DGO/PRECB.DGO",
|
||||
"DGO/PRECC.DGO",
|
||||
// "DGO/PRECD.DGO",
|
||||
// // title/intro
|
||||
"DGO/PRECD.DGO",
|
||||
// title/intro
|
||||
"DGO/WIN.DGO", // wasintro
|
||||
"DGO/TITLE.DGO",
|
||||
"DGO/INTTITLE.DGO",
|
||||
"DGO/INTPALRF.DGO", // intro-palace-roof
|
||||
"DGO/IPF.DGO", // intro-palace-fall
|
||||
"DGO/INTROCST.DGO",
|
||||
// // outro
|
||||
// outro
|
||||
"DGO/OUTCAST3.DGO",
|
||||
"DGO/OUTROCST.DGO",
|
||||
// // museum
|
||||
// museum
|
||||
"DGO/MUSEUM.DGO",
|
||||
"DGO/MUSEUM2.DGO",
|
||||
"DGO/MUSEUM3.DGO",
|
||||
@@ -311,8 +311,245 @@
|
||||
"DGO/LWSTDPCK.DGO"
|
||||
],
|
||||
|
||||
// STR files containing a texture that should be used by
|
||||
// FR3 creation.
|
||||
"str_texture_file_names": ["STR/PRMINIMA.STR"],
|
||||
|
||||
// some objects are part of STR files (streaming data).
|
||||
"str_file_names": [],
|
||||
"str_file_names": [
|
||||
"STR/ARF1INTR.STR",
|
||||
"STR/ARF1RES.STR",
|
||||
"STR/ARF2INTR.STR",
|
||||
"STR/ARF2RES.STR",
|
||||
"STR/ARF3INTR.STR",
|
||||
"STR/ARF3RES.STR",
|
||||
"STR/AROUTRO.STR",
|
||||
"STR/ART1INTR.STR",
|
||||
"STR/CAGSHIEL.STR",
|
||||
"STR/CATRES.STR",
|
||||
"STR/CAWRRES.STR",
|
||||
"STR/CIATIDES.STR",
|
||||
"STR/CIATOUT.STR",
|
||||
"STR/CIBBINTR.STR",
|
||||
"STR/CIBBRES.STR",
|
||||
"STR/CIBTINTR.STR",
|
||||
"STR/CIDGRES.STR",
|
||||
"STR/CIFCEINT.STR",
|
||||
"STR/CIGC1RES.STR",
|
||||
"STR/CIGC2INT.STR",
|
||||
"STR/CIGC2RES.STR",
|
||||
"STR/CIGCINTR.STR",
|
||||
"STR/CIGDPUNC.STR",
|
||||
"STR/CIGTCINT.STR",
|
||||
"STR/CIHVRES.STR",
|
||||
"STR/CIPAIB.STR",
|
||||
"STR/CIPAINTR.STR",
|
||||
"STR/CIPARES.STR",
|
||||
"STR/CIPFINTR.STR",
|
||||
"STR/CIPGINTR.STR",
|
||||
"STR/CIPGRES.STR",
|
||||
"STR/CIPHINTR.STR",
|
||||
"STR/CIPHRES.STR",
|
||||
"STR/CISFINTR.STR",
|
||||
"STR/COETEMPL.STR",
|
||||
"STR/COEXIT.STR",
|
||||
"STR/DAD06.STR",
|
||||
"STR/DAD07.STR",
|
||||
"STR/DAD10.STR",
|
||||
"STR/DAD12.STR",
|
||||
"STR/DAD13.STR",
|
||||
"STR/DAD14.STR",
|
||||
"STR/DAD16.STR",
|
||||
"STR/DAD17.STR",
|
||||
"STR/DAD18.STR",
|
||||
"STR/DAD20.STR",
|
||||
"STR/DAD21.STR",
|
||||
"STR/DAD24.STR",
|
||||
"STR/DAD31.STR",
|
||||
"STR/DAD35.STR",
|
||||
"STR/DAD38.STR",
|
||||
"STR/DAD57.STR",
|
||||
"STR/DAD58.STR",
|
||||
"STR/DAD61.STR",
|
||||
"STR/DAMOLE.STR",
|
||||
"STR/DEAR1INT.STR",
|
||||
"STR/DEAR1RES.STR",
|
||||
"STR/DEAR2INT.STR",
|
||||
"STR/DEATIN.STR",
|
||||
"STR/DEATOUT.STR",
|
||||
"STR/DEBBINTR.STR",
|
||||
"STR/DECLINTR.STR",
|
||||
"STR/DECRINTR.STR",
|
||||
"STR/DECWIN.STR",
|
||||
"STR/DEFBIA.STR",
|
||||
"STR/DEFBINTR.STR",
|
||||
"STR/DEFBRB.STR",
|
||||
"STR/DEFBRES.STR",
|
||||
"STR/DEGRES.STR",
|
||||
"STR/DEHINTRO.STR",
|
||||
"STR/DEHRES.STR",
|
||||
"STR/DEJGOTA.STR",
|
||||
"STR/DEJGOTB.STR",
|
||||
"STR/DEJGOTC.STR",
|
||||
"STR/DEJMINTR.STR",
|
||||
"STR/DELC2.STR",
|
||||
"STR/DELC3.STR",
|
||||
"STR/DELCATCH.STR",
|
||||
"STR/DEODRB.STR",
|
||||
"STR/DEODRES.STR",
|
||||
"STR/DERINTRO.STR",
|
||||
"STR/DERRA.STR",
|
||||
// "STR/DESCREEN.STR",
|
||||
"STR/DPBTURRE.STR",
|
||||
"STR/FABINTRO.STR",
|
||||
"STR/FABRES.STR",
|
||||
"STR/FAI1INTR.STR",
|
||||
"STR/FAI2INTR.STR",
|
||||
"STR/FAI3INTR.STR",
|
||||
"STR/FAI4INTR.STR",
|
||||
"STR/FASBIB.STR",
|
||||
"STR/FASBINTR.STR",
|
||||
"STR/FASBRES.STR",
|
||||
"STR/FORB.STR",
|
||||
"STR/FORCRES.STR",
|
||||
"STR/FOTOMRES.STR",
|
||||
"STR/FOTOWER.STR",
|
||||
"STR/GRMANIMS.STR",
|
||||
"STR/INDROP.STR",
|
||||
"STR/INFFHQ.STR",
|
||||
"STR/INLOST.STR",
|
||||
"STR/INPALACE.STR",
|
||||
"STR/INRESCUE.STR",
|
||||
"STR/INTIRED.STR",
|
||||
"STR/INTRAINI.STR",
|
||||
"STR/JAA1.STR",
|
||||
"STR/JAA2.STR",
|
||||
"STR/JAA3.STR",
|
||||
"STR/JAA4.STR",
|
||||
"STR/JAA5.STR",
|
||||
"STR/JAA6.STR",
|
||||
"STR/JAA7.STR",
|
||||
"STR/JABOARD.STR",
|
||||
"STR/JACARRY.STR",
|
||||
"STR/JAD1.STR",
|
||||
"STR/JAD2.STR",
|
||||
"STR/JAD3.STR",
|
||||
"STR/JAD4.STR",
|
||||
"STR/JAD5.STR",
|
||||
"STR/JADARK.STR",
|
||||
"STR/JADON.STR",
|
||||
"STR/JADUMMY.STR",
|
||||
"STR/JAEBOARD.STR",
|
||||
"STR/JAEDARK.STR",
|
||||
"STR/JAEGC.STR",
|
||||
"STR/JAEGNORM.STR",
|
||||
"STR/JAEGOLD.STR",
|
||||
"STR/JAELIGHT.STR",
|
||||
"STR/JAENORMA.STR",
|
||||
// "STR/JAEXTERN.STR",
|
||||
"STR/JAFLDAX.STR",
|
||||
"STR/JAFLUT.STR",
|
||||
"STR/JAGUN.STR",
|
||||
"STR/JAICE.STR",
|
||||
"STR/JAINDAX.STR",
|
||||
"STR/JAKANGA.STR",
|
||||
"STR/JALADDER.STR",
|
||||
"STR/JALIGHT.STR",
|
||||
"STR/JAMECH.STR",
|
||||
"STR/JAPEGASU.STR",
|
||||
"STR/JAPGLIDE.STR",
|
||||
"STR/JAPGUN.STR",
|
||||
"STR/JAPHCAR.STR",
|
||||
"STR/JAPIDAX.STR",
|
||||
"STR/JAPILOT.STR",
|
||||
"STR/JAPOLE.STR",
|
||||
"STR/JAPWCAR.STR",
|
||||
"STR/JARACER.STR",
|
||||
"STR/JASWIM.STR",
|
||||
"STR/JATENTAC.STR",
|
||||
"STR/JATUBE.STR",
|
||||
"STR/JATURRET.STR",
|
||||
"STR/KRWB1.STR",
|
||||
"STR/KRWB2.STR",
|
||||
"STR/KRWB3.STR",
|
||||
"STR/MIBINTRO.STR",
|
||||
"STR/MIBRES.STR",
|
||||
"STR/MIERES.STR",
|
||||
"STR/MIGEXIT.STR",
|
||||
"STR/MITINTRO.STR",
|
||||
"STR/MITRES.STR",
|
||||
"STR/MU2ANIMS.STR",
|
||||
"STR/MU3ANIMS.STR",
|
||||
"STR/MU4ANIMS.STR",
|
||||
"STR/MUANIMS.STR",
|
||||
"STR/NEDBARRI.STR",
|
||||
"STR/NEEINTRO.STR",
|
||||
"STR/NEHINTRO.STR",
|
||||
"STR/NEHRES.STR",
|
||||
"STR/NSB1BREA.STR",
|
||||
"STR/NSB2BREA.STR",
|
||||
"STR/PARAINTR.STR",
|
||||
"STR/PARARA.STR",
|
||||
"STR/PARARES.STR",
|
||||
"STR/PARPINTR.STR",
|
||||
"STR/PEFLY.STR",
|
||||
"STR/POAINTRO.STR",
|
||||
"STR/PRDSERES.STR",
|
||||
"STR/PRDSLOSE.STR",
|
||||
"STR/PRDSRES.STR",
|
||||
"STR/PRHA.STR",
|
||||
"STR/PRHB.STR",
|
||||
"STR/PRHC.STR",
|
||||
"STR/PRHFINAL.STR",
|
||||
// "STR/PRMINIMA.STR",
|
||||
"STR/PRTRES.STR",
|
||||
"STR/RATA1INT.STR",
|
||||
"STR/RATA2INT.STR",
|
||||
// "STR/SCBOOK.STR",
|
||||
"STR/SEEINTRO.STR",
|
||||
"STR/SEGENTRA.STR",
|
||||
"STR/SEHKENTR.STR",
|
||||
"STR/SEHKRES.STR",
|
||||
"STR/SEKENTRA.STR",
|
||||
"STR/SEKEXIT.STR",
|
||||
"STR/SEKMINTR.STR",
|
||||
"STR/SEMEXIT.STR",
|
||||
"STR/SEMHINTR.STR",
|
||||
"STR/SEPEXIT.STR",
|
||||
"STR/SESGRUNT.STR",
|
||||
"STR/SEWATERS.STR",
|
||||
"STR/TECINTRO.STR",
|
||||
"STR/TECRES.STR",
|
||||
"STR/TEDINTRO.STR",
|
||||
"STR/TEDRES.STR",
|
||||
"STR/TEEANIMS.STR",
|
||||
"STR/TEELAANI.STR",
|
||||
"STR/TEELODS.STR",
|
||||
"STR/TEJGLGLI.STR",
|
||||
"STR/TEOINTRO.STR",
|
||||
"STR/TEORES.STR",
|
||||
"STR/TETINTRO.STR",
|
||||
"STR/TETRA.STR",
|
||||
"STR/TETRB.STR",
|
||||
"STR/TEWDESER.STR",
|
||||
"STR/TODINTRO.STR",
|
||||
"STR/TODRB.STR",
|
||||
"STR/TODRES.STR",
|
||||
"STR/VODRES.STR",
|
||||
"STR/VOI1INTR.STR",
|
||||
"STR/VOI1RES.STR",
|
||||
"STR/VOI2INTR.STR",
|
||||
"STR/VOI2RES.STR",
|
||||
"STR/WACINTRO.STR",
|
||||
"STR/WADRES.STR",
|
||||
"STR/WAGINTRO.STR",
|
||||
"STR/WAGRES.STR",
|
||||
"STR/WALRINTR.STR",
|
||||
"STR/WALRRES.STR",
|
||||
"STR/WAPGINTR.STR",
|
||||
"STR/WAPGRES.STR"
|
||||
// "STR/WOMAP.STR"
|
||||
],
|
||||
|
||||
// streaming "art" that should be added to GAME.FR3.
|
||||
"str_art_file_names": ["STR/JAEXTERN.STR"],
|
||||
@@ -343,6 +580,12 @@
|
||||
"VAGWAD.INT"
|
||||
],
|
||||
|
||||
// tpages that should always be possible to access.
|
||||
"common_tpages": [
|
||||
17, // PRMINIMA progress-minimap
|
||||
3349 // PRMINIMA progress-minimap2
|
||||
],
|
||||
|
||||
"animated_textures": [
|
||||
// dark jak
|
||||
"jakc-arm",
|
||||
|
||||
@@ -1046,7 +1046,7 @@
|
||||
"desertf-obs": [["L99", "(inline-array vector)", 2]],
|
||||
"desert-dust-storm": [["L89", "vector"]],
|
||||
"artifact-race": [
|
||||
["L162", "(inline-array talker-speech-class)", 16],
|
||||
["L162", "(inline-array talker-speech-class)", 32],
|
||||
["L160", "vector"],
|
||||
["L159", "vector"],
|
||||
["L158", "vector"],
|
||||
|
||||
@@ -429,7 +429,7 @@
|
||||
"(method 22 rigid-body-control)": [[16, ["inline-array", "vector", 2]]],
|
||||
"(method 23 rigid-body-control)": [[16, ["inline-array", "vector", 2]]],
|
||||
"(method 24 rigid-body-control)": [[16, ["inline-array", "vector", 2]]],
|
||||
"(method 28 rigid-body-control)": [[16, "rigid-body-impact"]],
|
||||
"(method 28 rigid-body-control)": [[16, "rigid-body-stack"]],
|
||||
"(method 50 rigid-body-object)": [[16, "rigid-body-impact"]],
|
||||
"(method 51 rigid-body-object)": [[16, "rigid-body-impact"]],
|
||||
"ptest": [[16, "vector"]],
|
||||
@@ -1067,7 +1067,7 @@
|
||||
[208, ["array", "uint32", 1]]
|
||||
],
|
||||
"(method 35 was-squad-control)": [
|
||||
[16, ["inline-array", "matrix", 2]],
|
||||
[16, ["inline-array", "matrix", 4]],
|
||||
[240, "cquery-with-5vec"]
|
||||
],
|
||||
"(method 39 vehicle-wheel)": [[16, "rigid-body-move-work"]],
|
||||
@@ -2513,5 +2513,12 @@
|
||||
[80, "matrix"],
|
||||
[144, "matrix"],
|
||||
[208, "matrix"]
|
||||
],
|
||||
"(method 12 bigmap)": [[32, "matrix"]],
|
||||
"(method 22 bigmap)": [
|
||||
[16, "vector4w"],
|
||||
[32, "vector"],
|
||||
[48, "vector"],
|
||||
[64, "vector"]
|
||||
]
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
[[224067587,{"idx":3,"name":"common-gray-dark","tpage_name":"museum4-water"}],[224067586,{"idx":2,"name":"common-glass","tpage_name":"museum4-water"}],[223936522,{"idx":10,"name":"bab-skin","tpage_name":"museum4b-pris"}],[223936521,{"idx":9,"name":"bab-shoulderstrap","tpage_name":"museum4b-pris"}],[223936520,{"idx":8,"name":"bab-pendant","tpage_name":"museum4b-pris"}],[223936519,{"idx":7,"name":"bab-nail-01","tpage_name":"museum4b-pris"}],[223936518,{"idx":6,"name":"bab-longfur","tpage_name":"museum4b-pris"}],[223936517,{"idx":5,"name":"bab-furtrans","tpage_name":"museum4b-pris"}],[223936516,{"idx":4,"name":"bab-furskin-trans","tpage_name":"museum4b-pris"}],[223936515,{"idx":3,"name":"bab-fur","tpage_name":"museum4b-pris"}],[223936514,{"idx":2,"name":"bab-eye","tpage_name":"museum4b-pris"}],[223936513,{"idx":1,"name":"bab-diaper","tpage_name":"museum4b-pris"}],[223936512,{"idx":0,"name":"bab-allfur","tpage_name":"museum4b-pris"}],[223871035,{"idx":59,"name":"environment-oldmetal","tpage_name":"museum3b-pris2"}],[223871034,{"idx":58,"name":"daxter-furhilite","tpage_name":"museum3b-pris2"}],[223871033,{"idx":57,"name":"charHOLD","tpage_name":"museum3b-pris2"}],[223871032,{"idx":56,"name":"brut-toenails","tpage_name":"museum3b-pris2"}],[223871031,{"idx":55,"name":"brut-ties","tpage_name":"museum3b-pris2"}],[223871030,{"idx":54,"name":"brut-teeth","tpage_name":"museum3b-pris2"}],[223871029,{"idx":53,"name":"brut-shirt","tpage_name":"museum3b-pris2"}],[223871028,{"idx":52,"name":"brut-metalrim","tpage_name":"museum3b-pris2"}],[223871027,{"idx":51,"name":"brut-lens","tpage_name":"museum3b-pris2"}],[223871026,{"idx":50,"name":"brut-legfur","tpage_name":"museum3b-pris2"}],[223871025,{"idx":49,"name":"brut-jaw","tpage_name":"museum3b-pris2"}],[223871024,{"idx":48,"name":"brut-jacket","tpage_name":"museum3b-pris2"}],[223871023,{"idx":47,"name":"brut-headtop","tpage_name":"museum3b-pris2"}],[223871022,{"idx":46,"name":"brut-handpalm","tpage_name":"museum3b-pris2"}],[223871021,{"idx":45,"name":"brut-hair","tpage_name":"museum3b-pris2"}],[223871020,{"idx":44,"name":"brut-foottop","tpage_name":"museum3b-pris2"}],[223871019,{"idx":43,"name":"brut-footstrap","tpage_name":"museum3b-pris2"}],[223871018,{"idx":42,"name":"brut-footbottom","tpage_name":"museum3b-pris2"}],[223871017,{"idx":41,"name":"brut-finger","tpage_name":"museum3b-pris2"}],[223871016,{"idx":40,"name":"brut-feather","tpage_name":"museum3b-pris2"}],[223871015,{"idx":39,"name":"brut-eyelid","tpage_name":"museum3b-pris2"}],[223871014,{"idx":38,"name":"brut-eye","tpage_name":"museum3b-pris2"}],[223871013,{"idx":37,"name":"brut-diaper","tpage_name":"museum3b-pris2"}],[223871012,{"idx":36,"name":"brut-cloaktop","tpage_name":"museum3b-pris2"}],[223871011,{"idx":35,"name":"brut-cloaktail","tpage_name":"museum3b-pris2"}],[223871010,{"idx":34,"name":"brut-button","tpage_name":"museum3b-pris2"}],[223871009,{"idx":33,"name":"brut-armsleeve","tpage_name":"museum3b-pris2"}],[223805572,{"idx":132,"name":"krew-rteye","tpage_name":"museum3b-pris"}],[223805571,{"idx":131,"name":"krew-lfteye","tpage_name":"museum3b-pris"}],[223805570,{"idx":130,"name":"krew-eyelid","tpage_name":"museum3b-pris"}],[223805569,{"idx":129,"name":"vin-waistband","tpage_name":"museum3b-pris"}],[223805568,{"idx":128,"name":"vin-teeth-01","tpage_name":"museum3b-pris"}],[223805567,{"idx":127,"name":"vin-suspendercenter","tpage_name":"museum3b-pris"}],[223805566,{"idx":126,"name":"vin-shoe-02","tpage_name":"museum3b-pris"}],[223805565,{"idx":125,"name":"vin-shoe-01","tpage_name":"museum3b-pris"}],[223805564,{"idx":124,"name":"vin-shirt-02","tpage_name":"museum3b-pris"}],[223805563,{"idx":123,"name":"vin-shirt-01","tpage_name":"museum3b-pris"}],[223805562,{"idx":122,"name":"vin-pants","tpage_name":"museum3b-pris"}],[223805561,{"idx":121,"name":"vin-metal","tpage_name":"museum3b-pris"}],[223805560,{"idx":120,"name":"vin-ltbrownstrap","tpage_name":"museum3b-pris"}],[223805559,{"idx":119,"name":"vin-lens","tpage_name":"museum3b-pris"}],[223805558,{"idx":118,"name":"vin-hair-02","tpage_name":"museum3b-pris"}],[223805557,{"idx":117,"name":"vin-hair-01","tpage_name":"museum3b-pris"}],[223805556,{"idx":116,"name":"vin-gunhandle-01","tpage_name":"museum3b-pris"}],[223805555,{"idx":115,"name":"vin-gunbarrel-02","tpage_name":"museum3b-pris"}],[223805554,{"idx":114,"name":"vin-gunbarrel","tpage_name":"museum3b-pris"}],[223805553,{"idx":113,"name":"vin-glove-02","tpage_name":"museum3b-pris"}],[223805552,{"idx":112,"name":"vin-glove-01","tpage_name":"museum3b-pris"}],[223805551,{"idx":111,"name":"vin-finger-01","tpage_name":"museum3b-pris"}],[223805550,{"idx":110,"name":"vin-face-01","tpage_name":"museum3b-pris"}],[223805549,{"idx":109,"name":"vin-emblem","tpage_name":"museum3b-pris"}],[223805548,{"idx":108,"name":"vin-ear","tpage_name":"museum3b-pris"}],[223805547,{"idx":107,"name":"vin-clip","tpage_name":"museum3b-pris"}],[223805546,{"idx":106,"name":"vin-blackstrap","tpage_name":"museum3b-pris"}],[223805545,{"idx"Line truncated
|
||||
[[1114251,{"idx":139,"name":"arena-04","tpage_name":"progress-minimap"}],[1114250,{"idx":138,"name":"arena-03","tpage_name":"progress-minimap"}],[1114246,{"idx":134,"name":"precursor-03","tpage_name":"progress-minimap"}],[1114245,{"idx":133,"name":"precursor-02","tpage_name":"progress-minimap"}],[1114238,{"idx":126,"name":"rubble-03","tpage_name":"progress-minimap"}],[1114235,{"idx":123,"name":"comb-04","tpage_name":"progress-minimap"}],[1114220,{"idx":108,"name":"factory-01","tpage_name":"progress-minimap"}],[1114150,{"idx":38,"name":"hud-bronzecup","tpage_name":"progress-minimap"}],[1114144,{"idx":32,"name":"forest-04","tpage_name":"progress-minimap"}],[1114143,{"idx":31,"name":"forest-03","tpage_name":"progress-minimap"}],[1114142,{"idx":30,"name":"forest-02","tpage_name":"progress-minimap"}],[1114141,{"idx":29,"name":"forest-01","tpage_name":"progress-minimap"}],[1114132,{"idx":20,"name":"default-jak-04","tpage_name":"progress-minimap"}],[1114131,{"idx":19,"name":"default-jak-03","tpage_name":"progress-minimap"}],[1114130,{"idx":18,"name":"default-jak-02","tpage_name":"progress-minimap"}],[1114129,{"idx":17,"name":"default-jak-01","tpage_name":"progress-minimap"}],[1114124,{"idx":12,"name":"city-04","tpage_name":"progress-minimap"}],[1114123,{"idx":11,"name":"city-03","tpage_name":"progress-minimap"}],[1114122,{"idx":10,"name":"city-02","tpage_name":"progress-minimap"}],[1114121,{"idx":9,"name":"city-01","tpage_name":"progress-minimap"}],[1114116,{"idx":4,"name":"big-map-icons","tpage_name":"progress-minimap"}],[1114113,{"idx":1,"name":"map-target-marker","tpage_name":"progress-minimap"}],[1114112,{"idx":0,"name":"hud-race-vehicle-01","tpage_name":"progress-minimap"}],[116916234,{"idx":10,"name":"sewcurved-door-06","tpage_name":"sewk-vis-pris"}],[99483714,{"idx":66,"name":"dp-bipedal-power-hose","tpage_name":"lformach-vis-pris"}],[106954794,{"idx":42,"name":"vola-rising-step-base","tpage_name":"volcanoa-vis-tfrag"}],[116916233,{"idx":9,"name":"sewcurved-door-05","tpage_name":"sewk-vis-pris"}],[99483713,{"idx":65,"name":"dp-bipedal-nose-01","tpage_name":"lformach-vis-pris"}],[106954793,{"idx":41,"name":"vola-cable","tpage_name":"volcanoa-vis-tfrag"}],[116916232,{"idx":8,"name":"sewcurved-door-04","tpage_name":"sewk-vis-pris"}],[99483712,{"idx":64,"name":"dp-bipedal-finger-plate-01","tpage_name":"lformach-vis-pris"}],[106954792,{"idx":40,"name":"vola-slide-metal","tpage_name":"volcanoa-vis-tfrag"}],[116916231,{"idx":7,"name":"sewcurved-door-01","tpage_name":"sewk-vis-pris"}],[99483711,{"idx":63,"name":"dp-bipedal-eye-01","tpage_name":"lformach-vis-pris"}],[116916230,{"idx":6,"name":"airlock-door-cog1","tpage_name":"sewk-vis-pris"}],[99483710,{"idx":62,"name":"dp-bipedal-dk-stomach-plate-01","tpage_name":"lformach-vis-pris"}],[106954790,{"idx":38,"name":"vola-grass-fringe-05-HI","tpage_name":"volcanoa-vis-tfrag"}],[116916228,{"idx":4,"name":"airlockl-door-metalframe","tpage_name":"sewk-vis-pris"}],[99483708,{"idx":60,"name":"dp-bipedal-dk-plate-04","tpage_name":"lformach-vis-pris"}],[116916227,{"idx":3,"name":"airlock-door-metal2","tpage_name":"sewk-vis-pris"}],[99483707,{"idx":59,"name":"dp-bipedal-dk-plate-03","tpage_name":"lformach-vis-pris"}],[116916226,{"idx":2,"name":"airlock-door-main","tpage_name":"sewk-vis-pris"}],[99483706,{"idx":58,"name":"dp-bipedal-dk-plate-02","tpage_name":"lformach-vis-pris"}],[106954786,{"idx":34,"name":"vola-rock-side-wall","tpage_name":"volcanoa-vis-tfrag"}],[116916225,{"idx":1,"name":"airlock-door-cog","tpage_name":"sewk-vis-pris"}],[99483705,{"idx":57,"name":"dp-bipedal-dk-plate-01","tpage_name":"lformach-vis-pris"}],[116916224,{"idx":0,"name":"airlock-door-bolt","tpage_name":"sewk-vis-pris"}],[99483704,{"idx":56,"name":"dp-bipedal-dk-hose-01","tpage_name":"lformach-vis-pris"}],[106954784,{"idx":32,"name":"vol-metal-01","tpage_name":"volcanoa-vis-tfrag"}],[116850690,{"idx":2,"name":"sewer-shrub-pitting-01","tpage_name":"sewk-vis-shrub"}],[99418170,{"idx":58,"name":"tpl-glider-metal02","tpage_name":"volcanox-pris"}],[111869970,{"idx":18,"name":"stadiumb-hud-ord-rd","tpage_name":"wasleapr-minimap"}],[116850689,{"idx":1,"name":"sewer-nut","tpage_name":"sewk-vis-shrub"}],[99418169,{"idx":57,"name":"tpl-glider-metal01","tpage_name":"volcanox-pris"}],[111869969,{"idx":17,"name":"stadiumb-hud-ord-o","tpage_name":"wasleapr-minimap"}],[116850688,{"idx":0,"name":"sewer-pipe-small-01","tpage_name":"sewk-vis-shrub"}],[99418168,{"idx":56,"name":"tpl-glider-grip01","tpage_name":"volcanox-pris"}],[111869968,{"idx":16,"name":"stadiumb-hud-ord-nd","tpage_name":"wasleapr-minimap"}],[115867650,{"idx":2,"name":"nst-spiderweb","tpage_name":"lnstcst-water"}],[115867649,{"idx":1,"name":"desert-nest-egg-piping","tpage_name":"lnstcst-water"}],[115867648,{"idx":0,"name":"sig-flatfangs","tpage_name":"lnstcst-water"}],[115802142,{"idx":30,"name":"vin-teeth-01","tpage_name":"lnstcst-pris2"}],[103350342,{"idx":70,"name":"jakchires-shoeteop","tpage_name":"comba-pris"}],[115802141,{"idx":29,"name":"sLine truncated
|
||||
@@ -3160,6 +3160,9 @@
|
||||
[27, "a0", "process-focusable"],
|
||||
[30, "a0", "process-focusable"]
|
||||
],
|
||||
"(method 20 enemy)": [
|
||||
[[0, 30], "v0", "search-info-flag"]
|
||||
],
|
||||
"(method 59 enemy)": [
|
||||
[57, "a0", "process-focusable"],
|
||||
[60, "a0", "process-focusable"]
|
||||
@@ -3191,8 +3194,20 @@
|
||||
[93, "a1", "process-focusable"],
|
||||
[140, "a1", "process-focusable"]
|
||||
],
|
||||
"(method 106 bot)": [
|
||||
[[16, 31], "v1", "process-focusable"],
|
||||
[[40, 58], "v1", "process-focusable"],
|
||||
[[92, 95], "v1", "process-focusable"]
|
||||
],
|
||||
"(method 106 ashelin)": [
|
||||
[[16, 21], "v1", "process-focusable"],
|
||||
[[40, 57], "v1", "process-focusable"],
|
||||
[[92, 95], "v1", "process-focusable"]
|
||||
],
|
||||
"(method 140 enemy)": [[18, "a1", "process-focusable"]],
|
||||
"(method 142 enemy)": [[[0, 40], "v0", "knocked-type"]],
|
||||
"get-penetrate-using-from-attack-event": [
|
||||
[[20, 40], "v0", "penetrate"],
|
||||
[2, "v1", "attack-info"],
|
||||
[5, "v1", "attack-info"],
|
||||
[25, "v1", "collide-shape"]
|
||||
@@ -3202,6 +3217,9 @@
|
||||
[67, "s3", "process-drawable"],
|
||||
[68, "a1", "collide-shape"]
|
||||
],
|
||||
"(method 68 enemy)": [
|
||||
[[0, 50], "v0", "enemy-aware"]
|
||||
],
|
||||
"(method 82 enemy)": [
|
||||
[80, "v1", "process-drawable"],
|
||||
[122, "v1", "attack-info"],
|
||||
@@ -4910,14 +4928,8 @@
|
||||
[96, "s5", "collide-shape-moving"]
|
||||
],
|
||||
"(anon-function 74 target-flut)": [
|
||||
[6, "gp", "target"],
|
||||
[10, "gp", "target"],
|
||||
[16, "gp", "target"],
|
||||
[24, "gp", "target"],
|
||||
[33, "gp", "target"],
|
||||
[42, "a0", "target"],
|
||||
[49, "gp", "target"],
|
||||
[56, "gp", "target"]
|
||||
[[0, 56], "gp", "target"],
|
||||
[42, "a0", "target"]
|
||||
],
|
||||
"(anon-function 21 target-flut)": [[58, "v1", "art-joint-anim"]],
|
||||
"(code target-flut-death)": [
|
||||
@@ -6605,8 +6617,7 @@
|
||||
[40, "a0", "process-focusable"]
|
||||
],
|
||||
"(method 26 task-manager-temple-climb)": [
|
||||
[126, "s5", "process-focusable"],
|
||||
[130, "s5", "process-focusable"]
|
||||
[[0, 148], "s5", "process-focusable"]
|
||||
],
|
||||
"(method 26 task-manager-desert-beast-battle)": [
|
||||
[39, "a0", "process-focusable"]
|
||||
@@ -9788,12 +9799,7 @@
|
||||
[319, "a1", "ff-squad-control"]
|
||||
],
|
||||
"(method 252 crimson-guard)": [
|
||||
[74, "s5", "process-focusable"],
|
||||
[69, "s5", "process-focusable"],
|
||||
[126, "s5", "process-focusable"],
|
||||
[146, "s5", "process-focusable"],
|
||||
[202, "s5", "process-focusable"],
|
||||
[205, "s5", "process-focusable"]
|
||||
[[0, 223], "s5", "process-focusable"]
|
||||
],
|
||||
"(method 51 ff-squad-control)": [
|
||||
[13, "v1", "connection"],
|
||||
@@ -10857,7 +10863,6 @@
|
||||
["_stack_", 76, "float"],
|
||||
["_stack_", 100, "float"]
|
||||
],
|
||||
"real-wang-texture-anim-func": [[[3, 31], "v1", "mood-context"]],
|
||||
"(method 24 sky-work)": [
|
||||
[256, "s4", "(pointer int32)"],
|
||||
[261, "s4", "(pointer int32)"]
|
||||
@@ -11266,5 +11271,80 @@
|
||||
[[191, 249], "gp", "shadow-dcache"],
|
||||
[96, "v1", "shadow-dcache"]
|
||||
],
|
||||
"real-fog-texture-anim-func": [[[6, 160], "s2", "(pointer uint32)"]]
|
||||
"real-fog-texture-anim-func": [[[6, 160], "s2", "(pointer uint32)"]],
|
||||
"(method 22 bigmap)": [
|
||||
[22, "s3", "process-drawable"],
|
||||
[[46, 49], "v1", "entity-actor"],
|
||||
[58, "a0", "process-drawable"],
|
||||
[65, "a0", "entity-actor"],
|
||||
[42, "v1", "entity-actor"],
|
||||
[55, "s3", "process-drawable"],
|
||||
[[201, 243], "a1", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 20 bigmap)": [
|
||||
[[3, 95], "s4", "(pointer uint32)"],
|
||||
[99, "a2", "(pointer uint32)"],
|
||||
[54, "a2", "(pointer uint32)"]
|
||||
],
|
||||
"(method 12 bigmap)": [
|
||||
[85, "v1", "(pointer uint32)"],
|
||||
[100, "v1", "(pointer uint32)"],
|
||||
[[142, 145], "s0", "(pointer uint128)"],
|
||||
["_stack_", 96, "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 21 bigmap)": [[[10, 38], "v1", "(inline-array vector4w)"]],
|
||||
"(method 19 blit-displays-work)": [
|
||||
[764, "v1", "float"],
|
||||
[759, "v1", "float"],
|
||||
[[935, 954], "a1", "(inline-array vector4w)"],
|
||||
[[857, 875], "a1", "(inline-array vector4w)"],
|
||||
[[844, 847], "a0", "dma-gif-packet"],
|
||||
[[921, 924], "v1", "dma-gif-packet"]
|
||||
],
|
||||
"(method 9 blit-displays-work)": [[[2, 36], "v1", "(inline-array vector4w)"]],
|
||||
"(method 10 blit-displays-work)": [
|
||||
[[2, 141], "v1", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 11 blit-displays-work)": [
|
||||
[[2, 30], "v1", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 12 blit-displays-work)": [
|
||||
[[4, 41], "v1", "(inline-array vector4w)"],
|
||||
[[60, 112], "v1", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 13 blit-displays-work)": [
|
||||
[[41, 44], "v1", "(inline-array vector4w)"],
|
||||
[[53, 71], "a0", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 18 blit-displays-work)": [
|
||||
[[28, 33], "v1", "dma-gif-packet"],
|
||||
[[174, 177], "v1", "dma-gif-packet"],
|
||||
[[186, 202], "a0", "(inline-array vector4w)"]
|
||||
],
|
||||
"draw-raw-image": [[[104, 154], "v1", "(inline-array vector4w)"]],
|
||||
"draw-color-bars": [
|
||||
[[11, 16], "v1", "dma-gif-packet"],
|
||||
[[28, 54], "v1", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 20 blit-displays-work)": [
|
||||
[[57, 89], "a3", "(inline-array vector4w)"],
|
||||
[[102, 134], "t1", "(inline-array vector4w)"],
|
||||
[[176, 209], "t1", "(inline-array vector4w)"],
|
||||
[[310, 338], "t2", "(inline-array vector4w)"],
|
||||
[[385, 422], "v1", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 14 blit-displays-work)": [
|
||||
[[88, 91], "v1", "dma-gif-packet"],
|
||||
[[100, 120], "a0", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 16 blit-displays-work)": [
|
||||
[[35, 79], "s2", "(inline-array vector4w)"],
|
||||
[[134, 178], "s2", "(inline-array vector4w)"]
|
||||
],
|
||||
"(method 15 blit-displays-work)": [
|
||||
[[60, 63], "v1", "dma-gif-packet"],
|
||||
[[81, 99], "a0", "(inline-array vector4w)"],
|
||||
[[165, 190], "a0", "(inline-array vector4w)"]
|
||||
],
|
||||
"(event idle progress)": [[[10, 80], "v1", "mc-status-code"]]
|
||||
}
|
||||
@@ -173,12 +173,27 @@
|
||||
"(method 9 process-tree)": {
|
||||
"args": ["this", "active-tree", "name", "stack-pointer"]
|
||||
},
|
||||
"(method 9 align-control)": {
|
||||
"vars": {
|
||||
"s5-0":"num-chans",
|
||||
"s4-0":"chan-idx",
|
||||
"a0-4":"chan",
|
||||
"v1-7":"frame-group",
|
||||
"a0-9":"root-chan",
|
||||
"v1-18":"root-frame-group",
|
||||
"f0-0":"root-frame-num",
|
||||
"a0-10":"disable?"
|
||||
}
|
||||
},
|
||||
"(method 9 process)": {
|
||||
"args": ["this", "active-tree", "name", "stack-pointer"]
|
||||
},
|
||||
"(method 10 process-tree)": {
|
||||
"args": ["this", "ent"]
|
||||
},
|
||||
"(method 106 bot)": {
|
||||
"vars": {"v1-3": ["v1-3", "process-focusable"]}
|
||||
},
|
||||
"(method 0 clock)": {
|
||||
"args": ["allocation", "type-to-make", "index"]
|
||||
},
|
||||
@@ -1903,6 +1918,11 @@
|
||||
"v1-8": "ii"
|
||||
}
|
||||
},
|
||||
"(method 20 enemy)": {
|
||||
"vars": {
|
||||
"v0-0": ["flag", "search-info-flag"]
|
||||
}
|
||||
},
|
||||
"(method 119 enemy)": {
|
||||
"vars": {
|
||||
"a1-5": ["cspec", "collide-spec"]
|
||||
@@ -2135,5 +2155,14 @@
|
||||
"vars": {
|
||||
"v0-0": ["type", "assault-target-type"]
|
||||
}
|
||||
},
|
||||
"(method 22 bigmap)": {
|
||||
"vars": {
|
||||
"a2-1": ["a2-1", "uint"],
|
||||
"a3-0": ["a3-0", "uint"]
|
||||
}
|
||||
},
|
||||
"set-font-color": {
|
||||
"args": ["idx", "clr0", "clr1", "clr2", "clr3"]
|
||||
}
|
||||
}
|
||||
@@ -166,7 +166,7 @@ FullName extract_name(const std::string& file_info_name) {
|
||||
name.name = name.name.substr(0, name.name.length() - 6);
|
||||
int chunk_id = 0;
|
||||
int place = 0;
|
||||
for (int i = 2; i-- > 0;) {
|
||||
for (int i = 3; i-- > 0;) {
|
||||
char c = name.name.back();
|
||||
if (c >= '0' && c <= '9') {
|
||||
int val = (c - '0');
|
||||
@@ -258,9 +258,8 @@ std::string StrFileReader::get_full_name(const std::string& short_name) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string StrFileReader::get_texture_name() const {
|
||||
ASSERT(m_chunks.size() == 1);
|
||||
const auto& chunk = m_chunks[0];
|
||||
std::string StrFileReader::get_chunk_texture_name(int idx) const {
|
||||
const auto& chunk = m_chunks[idx];
|
||||
auto find_string = get_texture_page_file_info_string();
|
||||
int offset;
|
||||
if (find_string_in_data(chunk.data(), int(chunk.size()), find_string, &offset)) {
|
||||
|
||||
@@ -22,7 +22,7 @@ class StrFileReader {
|
||||
std::string get_chunk_art_name(int idx) const;
|
||||
|
||||
std::string get_full_name(const std::string& short_name) const;
|
||||
std::string get_texture_name() const;
|
||||
std::string get_chunk_texture_name(int idx) const;
|
||||
|
||||
private:
|
||||
void init_jak1(const fs::path& file_path);
|
||||
@@ -46,8 +46,9 @@ class StrFileReader {
|
||||
std::string get_texture_page_file_info_string() const {
|
||||
switch (m_version) {
|
||||
case GameVersion::Jak2:
|
||||
case GameVersion::Jak3:
|
||||
return "/src/jak2/final/texture-page8/";
|
||||
case GameVersion::Jak3:
|
||||
return "/src/jak3/final/texture-page8/";
|
||||
default:
|
||||
ASSERT_MSG(false, "NYI get_file_info_string version");
|
||||
break;
|
||||
|
||||
@@ -454,7 +454,7 @@ std::string write_spool_subtitles(
|
||||
bool has_spools = false;
|
||||
for (auto& [spool_name, subs] : data) {
|
||||
result += " \"" + spool_name + "\": {\n";
|
||||
result += " \"scene\": true,\n";
|
||||
// result += " \"scene\": true,\n";
|
||||
result += " \"lines\": [\n";
|
||||
bool has_subs = false;
|
||||
for (auto& sub : subs) {
|
||||
@@ -463,20 +463,20 @@ std::string write_spool_subtitles(
|
||||
continue;
|
||||
}
|
||||
result += " {\n";
|
||||
result += " \"end\": " + float_to_string(sub.end_frame) + ",\n";
|
||||
result += " \"frame_end\": " + float_to_string(sub.end_frame) + ",\n";
|
||||
result += " \"frame_start\": " + float_to_string(sub.start_frame) + ",\n";
|
||||
if (dump_text) {
|
||||
result += " \"merge\": false,\n";
|
||||
} else {
|
||||
result += " \"merge\": true,\n";
|
||||
}
|
||||
result += " \"offscreen\": false,\n";
|
||||
result += " \"speaker\": \"none\",\n";
|
||||
result += " \"start\": " + float_to_string(sub.start_frame) + ",\n";
|
||||
if (dump_text) {
|
||||
result += " \"text\": \"" + msg.text + "\"\n";
|
||||
result += " \"text\": \"" + msg.text + "\",\n";
|
||||
} else {
|
||||
result += " \"text\": \"\"\n";
|
||||
// result += " \"text\": \"\",\n";
|
||||
}
|
||||
result += " \"speaker\": \"none\"\n";
|
||||
result += " },\n";
|
||||
has_subs = true;
|
||||
}
|
||||
|
||||
@@ -164,13 +164,16 @@ AudioDir read_audio_dir(const decompiler::Config& config, const fs::path& path)
|
||||
u64 data;
|
||||
struct {
|
||||
u64 name : 42;
|
||||
bool stereo : 1;
|
||||
bool international : 1;
|
||||
u8 param : 4;
|
||||
u64 stereo : 1;
|
||||
u64 international : 1;
|
||||
u64 param : 4;
|
||||
u64 offset : 16;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(DirEntryJak3) == sizeof(u64));
|
||||
|
||||
dir = reader.read<VagDirJak3>();
|
||||
ASSERT(dir.id[0] == 0x41574756);
|
||||
ASSERT(dir.id[1] == 0x52494444);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
enum class ExtractorErrorCode {
|
||||
SUCCESS = 0,
|
||||
INVALID_CLI_INPUT = 3990,
|
||||
INVALID_CLI_INPUT_MISSING_FOLDER = 3991,
|
||||
VALIDATION_CANT_LOCATE_ELF = 4000,
|
||||
VALIDATION_SERIAL_MISSING_FROM_DB = 4001,
|
||||
VALIDATION_ELF_MISSING_FROM_DB = 4002,
|
||||
|
||||
@@ -225,7 +225,7 @@ int main(int argc, char** argv) {
|
||||
if (!project_path_override.empty()) {
|
||||
if (!fs::exists(project_path_override)) {
|
||||
lg::error("Error: project path override '{}' does not exist", project_path_override.string());
|
||||
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT);
|
||||
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT_MISSING_FOLDER);
|
||||
}
|
||||
auto ok = file_util::setup_project_path(project_path_override);
|
||||
if (!ok) {
|
||||
@@ -255,7 +255,7 @@ int main(int argc, char** argv) {
|
||||
// - INPUT VALIDATION
|
||||
if (!fs::exists(input_file_path)) {
|
||||
lg::error("Error: input game file path '{}' does not exist", input_file_path.string());
|
||||
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT);
|
||||
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT_MISSING_FOLDER);
|
||||
}
|
||||
if (data_subfolders.count(game_name) == 0) {
|
||||
lg::error("Error: input game name '{}' is not valid", game_name);
|
||||
@@ -325,7 +325,7 @@ int main(int argc, char** argv) {
|
||||
} else if (fs::is_directory(input_file_path)) {
|
||||
if (!flag_folder) {
|
||||
// if we didn't request a folder explicitly, but we got one, assume something went wrong.
|
||||
lg::error("got a folder, but didn't get folder flag");
|
||||
lg::error("got a folder, but didn't provide the folder flag");
|
||||
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT);
|
||||
}
|
||||
iso_data_path = input_file_path;
|
||||
|
||||
@@ -1017,7 +1017,8 @@ void PrototypeBucketTie::read_from_file(TypedRef ref,
|
||||
for (int i = 0; i < 4; i++) {
|
||||
u32 start = index_start[i];
|
||||
u32 end = start + frag_count[i];
|
||||
ASSERT(num_color_qwcs <= end);
|
||||
// precd tie has a bug where geo 3's
|
||||
// ASSERT(num_color_qwcs <= end);
|
||||
num_color_qwcs = std::max(end, num_color_qwcs);
|
||||
}
|
||||
|
||||
@@ -1987,6 +1988,13 @@ void HFragment::read_from_file(TypedRef ref, const decompiler::DecompilerTypeSys
|
||||
size = read_plain_data_field<u32>(ref, "size", dts);
|
||||
}
|
||||
|
||||
void AdgifShaderArray::read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts) {
|
||||
auto length = read_plain_data_field<s32>(ref, "length", dts);
|
||||
adgifs.resize(length);
|
||||
memcpy_plain_data((u8*)adgifs.data(), get_field_ref(ref, "data", dts),
|
||||
sizeof(AdGifData) * length);
|
||||
}
|
||||
|
||||
void BspHeader::read_from_file(const decompiler::LinkedObjectFile& file,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
GameVersion version,
|
||||
@@ -2001,6 +2009,19 @@ void BspHeader::read_from_file(const decompiler::LinkedObjectFile& file,
|
||||
bsphere.read_from_file(get_field_ref(ref, "bsphere", dts));
|
||||
name = read_symbol_field(ref, "name", dts);
|
||||
|
||||
if (version == GameVersion::Jak1) {
|
||||
adgifs.read_from_file(get_and_check_ref_to_basic(ref, "adgifs", "adgif-shader-array", dts),
|
||||
dts);
|
||||
}
|
||||
|
||||
texture_page_count = read_plain_data_field<s32>(ref, "texture-page-count", dts);
|
||||
if (texture_page_count > 0) {
|
||||
auto tex_id_ptr = deref_label(get_field_ref(ref, "texture-ids", dts));
|
||||
for (int i = 0; i < texture_page_count; i++) {
|
||||
texture_ids.push_back(deref_u32(tex_id_ptr, i));
|
||||
}
|
||||
}
|
||||
|
||||
texture_remap_table.clear();
|
||||
s32 tex_remap_len = read_plain_data_field<s32>(ref, "texture-remap-table-len", dts);
|
||||
if (tex_remap_len > 0) {
|
||||
|
||||
@@ -840,6 +840,12 @@ struct DrawableTreeArray {
|
||||
std::vector<std::unique_ptr<DrawableTree>> trees;
|
||||
};
|
||||
|
||||
struct AdgifShaderArray {
|
||||
std::vector<AdGifData> adgifs;
|
||||
|
||||
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts);
|
||||
};
|
||||
|
||||
// The "file info"
|
||||
struct FileInfo {
|
||||
std::string file_type;
|
||||
@@ -884,7 +890,9 @@ struct BspHeader {
|
||||
u16 texture_flags[kNumTextureFlags]; // jak 2 only
|
||||
//
|
||||
// (texture-ids (pointer texture-id) :offset-assert 60)
|
||||
std::vector<u32> texture_ids;
|
||||
// (texture-page-count int32 :offset-assert 64)
|
||||
s32 texture_page_count;
|
||||
//
|
||||
// (unk-zero-0 basic :offset-assert 68)
|
||||
//
|
||||
@@ -907,6 +915,7 @@ struct BspHeader {
|
||||
// (unk-data-4 float :offset-assert 160)
|
||||
// (unk-data-5 float :offset-assert 164)
|
||||
// (adgifs adgif-shader-array :offset-assert 168)
|
||||
AdgifShaderArray adgifs;
|
||||
// (actor-birth-order (pointer uint32) :offset-assert 172)
|
||||
// (split-box-indices (pointer uint16) :offset-assert 176)
|
||||
// (unk-data-8 uint32 55 :offset-assert 180)
|
||||
|
||||
@@ -19,4 +19,5 @@ void extract_collide_frags(const level_tools::CollideHash& chash,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
tfrag3::Level& out);
|
||||
|
||||
void set_vertices_for_tri(tfrag3::CollisionMesh::Vertex* out, const math::Vector4f* in);
|
||||
} // namespace decompiler
|
||||
@@ -112,10 +112,22 @@ void extract_art_groups_from_level(const ObjectFileDB& db,
|
||||
std::map<std::string, level_tools::ArtData>& art_group_data) {
|
||||
if (db.obj_files_by_dgo.count(dgo_name)) {
|
||||
const auto& files = db.obj_files_by_dgo.at(dgo_name);
|
||||
MercSwapInfo swapped_info;
|
||||
// build list of models to replace
|
||||
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[db.version()] / "merc_replacements";
|
||||
if (file_util::file_exists(merc_replacements_path.string())) {
|
||||
auto custom_models =
|
||||
file_util::find_files_in_dir(merc_replacements_path, std::regex(".*\\.glb"));
|
||||
for (auto& mdl : custom_models) {
|
||||
swapped_info.add_to_swap_list(mdl.stem().string());
|
||||
}
|
||||
}
|
||||
for (const auto& file : files) {
|
||||
if (file.name.length() > 3 && !file.name.compare(file.name.length() - 3, 3, "-ag")) {
|
||||
const auto& ag_file = db.lookup_record(file);
|
||||
extract_merc(ag_file, tex_db, db.dts, tex_remap, level_data, false, db.version());
|
||||
extract_merc(ag_file, tex_db, db.dts, tex_remap, level_data, false, db.version(),
|
||||
swapped_info);
|
||||
extract_joint_group(ag_file, db.dts, db.version(), art_group_data);
|
||||
}
|
||||
}
|
||||
@@ -279,20 +291,25 @@ void extract_common(const ObjectFileDB& db,
|
||||
extract_art_groups_from_level(db, tex_db, {}, "ARTSPOOL", tfrag_level, art_group_data);
|
||||
|
||||
std::set<std::string> textures_we_have;
|
||||
std::set<u32> textures_we_have_id;
|
||||
|
||||
// put _all_ index textures in common.
|
||||
for (const auto& [id, tex] : tex_db.index_textures_by_combo_id) {
|
||||
tfrag_level.index_textures.push_back(tex);
|
||||
}
|
||||
|
||||
// remember which textures we already added.
|
||||
// textures with the same name or the same ID always have the same data.
|
||||
for (const auto& t : tfrag_level.textures) {
|
||||
textures_we_have.insert(t.debug_name);
|
||||
textures_we_have_id.insert(t.combo_id);
|
||||
}
|
||||
|
||||
// for common textures, add if the ID isn't there - common textures are looked up by ID.
|
||||
for (const auto& [id, normal_texture] : tex_db.textures) {
|
||||
if (config.common_tpages.count(normal_texture.page) &&
|
||||
!textures_we_have.count(normal_texture.name)) {
|
||||
if (config.common_tpages.count(normal_texture.page) && !textures_we_have_id.count(id)) {
|
||||
textures_we_have.insert(normal_texture.name);
|
||||
textures_we_have_id.insert(id);
|
||||
tfrag_level.textures.push_back(
|
||||
make_texture(id, normal_texture, tex_db.tpage_names.at(normal_texture.page), true));
|
||||
}
|
||||
@@ -323,8 +340,7 @@ void extract_common(const ObjectFileDB& db,
|
||||
|
||||
if (config.rip_levels) {
|
||||
auto file_path = file_util::get_jak_project_dir() / "glb_out" /
|
||||
game_version_names[config.game_version] / "common.glb";
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
game_version_names[config.game_version] / "common";
|
||||
save_level_foreground_as_gltf(tfrag_level, art_group_data, file_path);
|
||||
}
|
||||
}
|
||||
@@ -361,14 +377,12 @@ void extract_from_level(const ObjectFileDB& db,
|
||||
|
||||
if (config.rip_levels) {
|
||||
auto back_file_path = file_util::get_jak_project_dir() / "glb_out" /
|
||||
game_version_names[config.game_version] /
|
||||
game_version_names[config.game_version] / level_data.level_name /
|
||||
fmt::format("{}-background.glb", level_data.level_name);
|
||||
file_util::create_dir_if_needed_for_file(back_file_path);
|
||||
save_level_background_as_gltf(level_data, back_file_path);
|
||||
auto fore_file_path = file_util::get_jak_project_dir() / "glb_out" /
|
||||
game_version_names[config.game_version] /
|
||||
fmt::format("{}-foreground.glb", level_data.level_name);
|
||||
file_util::create_dir_if_needed_for_file(fore_file_path);
|
||||
game_version_names[config.game_version] / level_data.level_name;
|
||||
save_level_foreground_as_gltf(level_data, art_group_data, fore_file_path);
|
||||
}
|
||||
file_util::write_text_file(entities_folder / fmt::format("{}-actors.json", level_data.level_name),
|
||||
|
||||
@@ -10,6 +10,47 @@
|
||||
|
||||
namespace decompiler {
|
||||
|
||||
// info about what models have been replaced/added per level
|
||||
struct MercSwapInfo {
|
||||
std::vector<std::string> swap_list;
|
||||
std::map<std::string, std::vector<std::string>> per_level_merc_swaps;
|
||||
std::map<std::string, std::vector<std::string>> per_level_custom_mdls;
|
||||
|
||||
bool should_swap(const std::string& model) {
|
||||
return std::find(swap_list.begin(), swap_list.end(), model) != swap_list.end();
|
||||
}
|
||||
|
||||
bool already_swapped(const std::string& model, const std::string& level) {
|
||||
auto mdls_it = per_level_merc_swaps.find(level);
|
||||
if (mdls_it != per_level_merc_swaps.end()) {
|
||||
auto& mdls = mdls_it->second;
|
||||
auto mdl = std::find(mdls.begin(), mdls.end(), model);
|
||||
return mdl != mdls.end();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool already_added(const std::string& model, const std::string& level) {
|
||||
auto mdls_it = per_level_custom_mdls.find(level);
|
||||
if (mdls_it != per_level_custom_mdls.end()) {
|
||||
auto& mdls = mdls_it->second;
|
||||
auto mdl = std::find(mdls.begin(), mdls.end(), model);
|
||||
return mdl != mdls.end();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void add_to_swap_list(const std::string& model) { swap_list.push_back(model); }
|
||||
|
||||
void add_to_swapped_list(const std::string& model, const std::string& level) {
|
||||
per_level_merc_swaps[level].push_back(model);
|
||||
}
|
||||
|
||||
void add_to_custom_list(const std::string& model, const std::string& level) {
|
||||
per_level_custom_mdls[level].push_back(model);
|
||||
}
|
||||
};
|
||||
|
||||
// extract everything
|
||||
void extract_all_levels(const ObjectFileDB& db,
|
||||
const TextureDB& tex_db,
|
||||
@@ -26,4 +67,7 @@ tfrag3::Texture make_texture(u32 id,
|
||||
bool pool_load);
|
||||
std::vector<level_tools::TextureRemap> extract_tex_remap(const ObjectFileDB& db,
|
||||
const std::string& dgo_name);
|
||||
std::optional<ObjectFileRecord> get_bsp_file(const std::vector<ObjectFileRecord>& records,
|
||||
const std::string& dgo_name);
|
||||
bool is_valid_bsp(const LinkedObjectFile& file);
|
||||
} // namespace decompiler
|
||||
@@ -853,12 +853,19 @@ ConvertedMercEffect convert_merc_effect(const MercEffect& input_effect,
|
||||
u32 tidx = (env >> 8) & 0b1111'1111'1111;
|
||||
tex_combo = (((u32)tpage) << 16) | tidx;
|
||||
} break;
|
||||
case GameVersion::Jak2:
|
||||
case GameVersion::Jak3: {
|
||||
case GameVersion::Jak2: {
|
||||
u32 tpage = 0x1f;
|
||||
u32 tidx = 2;
|
||||
tex_combo = (((u32)tpage) << 16) | tidx;
|
||||
} break;
|
||||
case GameVersion::Jak3: {
|
||||
// (define *generic-envmap-texture* (get-texture pal-environment-front environment-generic))
|
||||
// (defconstant environment-generic 2) tpage
|
||||
// (def-tex pal-environment-front environment-generic 1) texture
|
||||
u32 tpage = 2;
|
||||
u32 tidx = 1;
|
||||
tex_combo = (((u32)tpage) << 16) | tidx;
|
||||
} break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
@@ -1617,7 +1624,7 @@ void replace_model(tfrag3::Level& lvl, tfrag3::MercModel& model, const fs::path&
|
||||
}
|
||||
}
|
||||
|
||||
auto swap_info = load_replacement_merc_model(model.name, lvl.merc_data.indices.size(),
|
||||
auto swap_info = load_replacement_merc_model(model, lvl.merc_data.indices.size(),
|
||||
lvl.merc_data.vertices.size(), lvl.textures.size(),
|
||||
mdl_path.string(), old_verts, false);
|
||||
model = swap_info.new_model;
|
||||
@@ -1640,8 +1647,8 @@ void add_custom_model_to_level(tfrag3::Level& lvl,
|
||||
auto lvl_name = lvl.level_name == "" ? "common" : lvl.level_name;
|
||||
lg::info("Adding custom model {} to {}", name, lvl_name);
|
||||
auto merc_data =
|
||||
load_replacement_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
|
||||
lvl.textures.size(), mdl_path.string(), {}, true);
|
||||
load_custom_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
|
||||
lvl.textures.size(), mdl_path.string(), {}, true);
|
||||
for (auto& idx : merc_data.new_indices) {
|
||||
lvl.merc_data.indices.push_back(idx);
|
||||
}
|
||||
@@ -1662,7 +1669,8 @@ void extract_merc(const ObjectFileData& ag_data,
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level,
|
||||
GameVersion version) {
|
||||
GameVersion version,
|
||||
MercSwapInfo& swapped_info) {
|
||||
if (dump_level) {
|
||||
file_util::create_dir_if_needed(file_util::get_file_path({"debug_out/merc"}));
|
||||
}
|
||||
@@ -1788,31 +1796,45 @@ void extract_merc(const ObjectFileData& ag_data,
|
||||
}
|
||||
}
|
||||
|
||||
// do model replacements if present
|
||||
auto merc_replacement_folder = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[version] / "merc_replacements";
|
||||
if (file_util::file_exists(merc_replacement_folder.string())) {
|
||||
auto merc_replacements =
|
||||
file_util::find_files_in_dir(merc_replacement_folder, std::regex(".*\\.glb"));
|
||||
for (auto& path : merc_replacements) {
|
||||
auto name = path.stem().string();
|
||||
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
|
||||
[&](const auto& m) { return m.name == name; });
|
||||
if (it != out.merc_data.models.end()) {
|
||||
auto& model = *it;
|
||||
replace_model(out, model, path);
|
||||
// do model replacement if present
|
||||
for (auto& ctrl : ctrls) {
|
||||
if (swapped_info.should_swap(ctrl.name)) {
|
||||
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[version] / "merc_replacements";
|
||||
if (!swapped_info.already_swapped(ctrl.name, out.level_name)) {
|
||||
if (file_util::file_exists(merc_replacements_path.string())) {
|
||||
std::string file_name(ctrl.name + ".glb");
|
||||
auto mdl_path = merc_replacements_path / file_name;
|
||||
if (file_util::file_exists(mdl_path.string())) {
|
||||
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
|
||||
[&](const auto& m) { return m.name == ctrl.name; });
|
||||
if (it != out.merc_data.models.end()) {
|
||||
auto& model = *it;
|
||||
replace_model(out, model, mdl_path);
|
||||
swapped_info.add_to_swapped_list(ctrl.name, out.level_name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lg::info("{} in level {} was already swapped, skipping", ctrl.name, out.level_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add custom models if present
|
||||
auto lvl_name = out.level_name == "" ? "common" : out.level_name;
|
||||
auto models_folder = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[version] / "models" / lvl_name;
|
||||
if (file_util::file_exists(models_folder.string())) {
|
||||
auto custom_models = file_util::find_files_in_dir(models_folder, std::regex(".*\\.glb"));
|
||||
for (auto& mdl : custom_models) {
|
||||
add_custom_model_to_level(out, mdl.stem().string(), mdl);
|
||||
// add custom models if present
|
||||
auto lvl_name = out.level_name == "" ? "common" : out.level_name;
|
||||
auto models_folder = file_util::get_jak_project_dir() / "custom_assets" /
|
||||
game_version_names[version] / "models" / lvl_name;
|
||||
if (file_util::file_exists(models_folder.string())) {
|
||||
auto custom_models = file_util::find_files_in_dir(models_folder, std::regex(".*\\.glb"));
|
||||
for (auto& mdl : custom_models) {
|
||||
auto name = mdl.stem().string();
|
||||
if (!swapped_info.already_added(name, lvl_name)) {
|
||||
add_custom_model_to_level(out, name, mdl);
|
||||
swapped_info.add_to_custom_list(name, lvl_name);
|
||||
} else {
|
||||
lg::info("custom model {} was already added to level {}, skipping", name, lvl_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "extract_level.h"
|
||||
|
||||
#include "common/custom_data/Tfrag3Data.h"
|
||||
|
||||
#include "decompiler/ObjectFile/ObjectFileDB.h"
|
||||
@@ -14,5 +16,6 @@ void extract_merc(const ObjectFileData& ag_data,
|
||||
const std::vector<level_tools::TextureRemap>& map,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level,
|
||||
GameVersion version);
|
||||
GameVersion version,
|
||||
MercSwapInfo& swapped_info);
|
||||
} // namespace decompiler
|
||||
@@ -2032,6 +2032,20 @@ s32 find_or_add_texture_to_level(u32 combo_tex_id,
|
||||
if (ok_to_miss) {
|
||||
// we're missing a texture, just use the first one.
|
||||
tex_it = tdb.textures.begin();
|
||||
// some tfrags in jak 3 are missing textures, so we use some suitable
|
||||
// replacements instead of the default eye texture
|
||||
static std::map<std::string, std::string> per_level_tex_hacks = {
|
||||
{"wasintro", "des-rock-01"},
|
||||
{"intpfall", "common-black"},
|
||||
{"powergd", "common-black"},
|
||||
};
|
||||
auto it = std::find_if(tdb.textures.begin(), tdb.textures.end(),
|
||||
[&](const std::pair<u32, TextureDB::TextureData> val) {
|
||||
return val.second.name == per_level_tex_hacks[level_name];
|
||||
});
|
||||
if (it != tdb.textures.end()) {
|
||||
tex_it = it;
|
||||
}
|
||||
} else {
|
||||
ASSERT_MSG(
|
||||
false,
|
||||
|
||||
@@ -2339,7 +2339,7 @@ TieCategoryInfo get_jak1_tie_category(u32 flags) {
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) {
|
||||
s32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) {
|
||||
if (combo_tex == 0) {
|
||||
// untextured
|
||||
combo_tex = (((u32)TextureDB::kPlaceholderWhiteTexturePage) << 16) |
|
||||
@@ -2348,7 +2348,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
|
||||
|
||||
// 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;
|
||||
s32 idx_in_lev_data = INT32_MAX;
|
||||
for (u32 i = 0; i < lev.textures.size(); i++) {
|
||||
if (lev.textures[i].combo_id == combo_tex) {
|
||||
idx_in_lev_data = i;
|
||||
@@ -2356,7 +2356,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
|
||||
}
|
||||
}
|
||||
|
||||
if (idx_in_lev_data == UINT32_MAX) {
|
||||
if (idx_in_lev_data == INT32_MAX) {
|
||||
// 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()) {
|
||||
@@ -2378,14 +2378,20 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
|
||||
new_tex.debug_tpage_name = tdb.tpage_names.at(tex_it->second.page);
|
||||
new_tex.data = tex_it->second.rgba_bytes;
|
||||
}
|
||||
const auto& level_tex = lev.textures.at(idx_in_lev_data);
|
||||
const auto& it = tdb.animated_tex_output_to_anim_slot.find(level_tex.debug_name);
|
||||
if (it != tdb.animated_tex_output_to_anim_slot.end()) {
|
||||
// lg::warn("TIE animated texture: {}", level_tex.debug_name);
|
||||
return -int(it->second) - 1;
|
||||
}
|
||||
return idx_in_lev_data;
|
||||
}
|
||||
|
||||
void handle_wind_draw_for_strip(
|
||||
tfrag3::TieTree& tree,
|
||||
std::unordered_map<u32, std::vector<u32>>& wind_draws_by_tex,
|
||||
std::unordered_map<s32, std::vector<u32>>& wind_draws_by_tex,
|
||||
const std::vector<std::vector<std::pair<int, int>>>& packed_vert_indices,
|
||||
u32 idx_in_lev_data,
|
||||
s32 idx_in_lev_data,
|
||||
DrawMode mode,
|
||||
const TieStrip& strip,
|
||||
const TieInstanceInfo& inst,
|
||||
@@ -2452,7 +2458,7 @@ void handle_wind_draw_for_strip(
|
||||
}
|
||||
|
||||
void handle_draw_for_strip(tfrag3::TieTree& tree,
|
||||
std::unordered_map<u32, std::vector<u32>>& static_draws_by_tex,
|
||||
std::unordered_map<s32, std::vector<u32>>& static_draws_by_tex,
|
||||
std::vector<tfrag3::StripDraw>& category_draws,
|
||||
const std::vector<std::vector<std::pair<int, int>>>& packed_vert_indices,
|
||||
DrawMode mode,
|
||||
@@ -2542,8 +2548,8 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
GameVersion version) {
|
||||
// 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;
|
||||
std::unordered_map<s32, std::vector<u32>> static_draws_by_tex;
|
||||
std::unordered_map<s32, std::vector<u32>> wind_draws_by_tex;
|
||||
|
||||
std::array<std::vector<tfrag3::StripDraw>, tfrag3::kNumTieCategories> draws_by_category;
|
||||
|
||||
@@ -2632,7 +2638,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
for (size_t strip_idx = 0; strip_idx < frag.strips.size(); strip_idx++) {
|
||||
auto& strip = frag.strips[strip_idx];
|
||||
|
||||
u32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb);
|
||||
s32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb);
|
||||
// determine the draw mode
|
||||
DrawMode mode = process_draw_mode(strip.adgif, frag.prog_info.misc_x == 0,
|
||||
frag.has_magic_tex0_bit, version, info.category);
|
||||
@@ -2649,7 +2655,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
|
||||
draws_by_category.at((int)info.category), packed_vert_indices,
|
||||
mode, idx_in_lev_data, strip, inst, ifrag, proto_idx, frag_idx,
|
||||
strip_idx, matrix_idx);
|
||||
u32 envmap_tex_idx =
|
||||
s32 envmap_tex_idx =
|
||||
get_or_add_texture(proto.envmap_adgif.value().combo_tex, lev, tdb);
|
||||
|
||||
// second pass envmap draw mode, in envmap bucket, envmap-specific draw list
|
||||
@@ -2747,6 +2753,10 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
|
||||
bool dump_level,
|
||||
GameVersion version) {
|
||||
for (int geo = 0; geo < GEOM_MAX; ++geo) {
|
||||
// as far as I can tell, this one has bad colors
|
||||
if (debug_name == "PRECD.DGO-2-tie" && geo == 3) {
|
||||
continue;
|
||||
}
|
||||
tfrag3::TieTree this_tree;
|
||||
|
||||
// sanity check the vis tree (not a perfect check, but this is used in game and should be right)
|
||||
|
||||
@@ -93,36 +93,33 @@ void unstrip_tie_wind(std::vector<u32>& unstripped,
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert merc strips. Doesn't assume anything about strips. Output is [model][effect][draw] format
|
||||
* Convert merc strips. Doesn't assume anything about strips. Output is [effect][draw] format (done
|
||||
* for each model)
|
||||
*/
|
||||
void unstrip_merc_draws(const std::vector<u32>& stripped_indices,
|
||||
const std::vector<tfrag3::MercModel>& models,
|
||||
const tfrag3::MercModel& model,
|
||||
std::vector<u32>& unstripped,
|
||||
std::vector<std::vector<std::vector<u32>>>& draw_to_start,
|
||||
std::vector<std::vector<std::vector<u32>>>& draw_to_count) {
|
||||
for (auto& model : models) {
|
||||
auto& model_dts = draw_to_start.emplace_back();
|
||||
auto& model_dtc = draw_to_count.emplace_back();
|
||||
for (auto& effect : model.effects) {
|
||||
auto& effect_dts = model_dts.emplace_back();
|
||||
auto& effect_dtc = model_dtc.emplace_back();
|
||||
for (auto& draw : effect.all_draws) {
|
||||
effect_dts.push_back(unstripped.size());
|
||||
std::vector<std::vector<u32>>& draw_to_start,
|
||||
std::vector<std::vector<u32>>& draw_to_count) {
|
||||
for (auto& effect : model.effects) {
|
||||
auto& effect_dts = draw_to_start.emplace_back();
|
||||
auto& effect_dtc = draw_to_count.emplace_back();
|
||||
for (auto& draw : effect.all_draws) {
|
||||
effect_dts.push_back(unstripped.size());
|
||||
|
||||
for (size_t i = 2; i < draw.index_count; i++) {
|
||||
int idx = i + draw.first_index;
|
||||
u32 a = stripped_indices[idx];
|
||||
u32 b = stripped_indices[idx - 1];
|
||||
u32 c = stripped_indices[idx - 2];
|
||||
if (a == UINT32_MAX || b == UINT32_MAX || c == UINT32_MAX) {
|
||||
continue;
|
||||
}
|
||||
unstripped.push_back(a);
|
||||
unstripped.push_back(b);
|
||||
unstripped.push_back(c);
|
||||
for (size_t i = 2; i < draw.index_count; i++) {
|
||||
int idx = i + draw.first_index;
|
||||
u32 a = stripped_indices[idx];
|
||||
u32 b = stripped_indices[idx - 1];
|
||||
u32 c = stripped_indices[idx - 2];
|
||||
if (a == UINT32_MAX || b == UINT32_MAX || c == UINT32_MAX) {
|
||||
continue;
|
||||
}
|
||||
effect_dtc.push_back(unstripped.size() - effect_dts.back());
|
||||
unstripped.push_back(a);
|
||||
unstripped.push_back(b);
|
||||
unstripped.push_back(c);
|
||||
}
|
||||
effect_dtc.push_back(unstripped.size() - effect_dts.back());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -485,12 +482,12 @@ int make_shrub_index_buffer_view(const std::vector<u32>& indices,
|
||||
}
|
||||
|
||||
int make_merc_index_buffer_view(const std::vector<u32>& indices,
|
||||
const std::vector<tfrag3::MercModel>& models,
|
||||
const tfrag3::MercModel& mmodel,
|
||||
tinygltf::Model& model,
|
||||
std::vector<std::vector<std::vector<u32>>>& draw_to_start,
|
||||
std::vector<std::vector<std::vector<u32>>>& draw_to_count) {
|
||||
std::vector<std::vector<u32>>& draw_to_start,
|
||||
std::vector<std::vector<u32>>& draw_to_count) {
|
||||
std::vector<u32> unstripped;
|
||||
unstrip_merc_draws(indices, models, unstripped, draw_to_start, draw_to_count);
|
||||
unstrip_merc_draws(indices, mmodel, unstripped, draw_to_start, draw_to_count);
|
||||
|
||||
// first create a buffer:
|
||||
int buffer_idx = (int)model.buffers.size();
|
||||
@@ -884,6 +881,7 @@ int make_inv_matrix_bind_poses(const std::vector<level_tools::Joint>& joints,
|
||||
|
||||
void add_merc(const tfrag3::Level& level,
|
||||
const std::map<std::string, level_tools::ArtData>& art_data,
|
||||
const tfrag3::MercModel& mmodel,
|
||||
tinygltf::Model& model,
|
||||
std::unordered_map<int, int>& tex_image_map) {
|
||||
const auto& mverts = level.merc_data.vertices;
|
||||
@@ -892,92 +890,89 @@ void add_merc(const tfrag3::Level& level,
|
||||
int position_buffer_accessor = make_position_buffer_accessor(mverts, model);
|
||||
int texture_buffer_accessor = make_tex_buffer_accessor(mverts, model, 1.f);
|
||||
|
||||
std::vector<std::vector<std::vector<u32>>> draw_to_start, draw_to_count;
|
||||
int index_buffer_view = make_merc_index_buffer_view(
|
||||
level.merc_data.indices, level.merc_data.models, model, draw_to_start, draw_to_count);
|
||||
std::vector<std::vector<u32>> draw_to_start, draw_to_count;
|
||||
int index_buffer_view = make_merc_index_buffer_view(level.merc_data.indices, mmodel, model,
|
||||
draw_to_start, draw_to_count);
|
||||
int colors = make_color_buffer_accessor(mverts, model);
|
||||
|
||||
auto joints_accessor = make_bones_accessor(mverts, model);
|
||||
auto weights_accessor = make_weights_accessor(mverts, model);
|
||||
|
||||
for (size_t model_idx = 0; model_idx < level.merc_data.models.size(); model_idx++) {
|
||||
const auto& mmodel = level.merc_data.models[model_idx];
|
||||
const auto& art = art_data.find(mmodel.name);
|
||||
int node_idx = (int)model.nodes.size();
|
||||
auto& node = model.nodes.emplace_back();
|
||||
model.scenes.at(0).nodes.push_back(node_idx);
|
||||
node.name = mmodel.name;
|
||||
int mesh_idx = (int)model.meshes.size();
|
||||
auto& mesh = model.meshes.emplace_back();
|
||||
mesh.name = node.name;
|
||||
node.mesh = mesh_idx;
|
||||
const auto& art = art_data.find(mmodel.name);
|
||||
int node_idx = (int)model.nodes.size();
|
||||
auto& node = model.nodes.emplace_back();
|
||||
model.scenes.at(0).nodes.push_back(node_idx);
|
||||
node.name = mmodel.name;
|
||||
int mesh_idx = (int)model.meshes.size();
|
||||
auto& mesh = model.meshes.emplace_back();
|
||||
mesh.name = node.name;
|
||||
node.mesh = mesh_idx;
|
||||
|
||||
if (art != art_data.end() && !art->second.joint_group.empty()) {
|
||||
node.skin = model.skins.size();
|
||||
auto& skin = model.skins.emplace_back();
|
||||
const auto& game_bones = art->second.joint_group;
|
||||
int n_bones = game_bones.size();
|
||||
std::vector<std::vector<int>> children(n_bones);
|
||||
for (size_t i = 0; i < game_bones.size(); i++) {
|
||||
if (game_bones[i].parent_idx >= 0) {
|
||||
children.at(game_bones[i].parent_idx).push_back(i);
|
||||
}
|
||||
if (art != art_data.end() && !art->second.joint_group.empty()) {
|
||||
node.skin = model.skins.size();
|
||||
auto& skin = model.skins.emplace_back();
|
||||
const auto& game_bones = art->second.joint_group;
|
||||
int n_bones = game_bones.size();
|
||||
std::vector<std::vector<int>> children(n_bones);
|
||||
for (size_t i = 0; i < game_bones.size(); i++) {
|
||||
if (game_bones[i].parent_idx >= 0) {
|
||||
children.at(game_bones[i].parent_idx).push_back(i);
|
||||
}
|
||||
skin.skeleton = model.nodes.size();
|
||||
for (int i = 0; i < n_bones; i++) {
|
||||
const auto& gbone = game_bones[i];
|
||||
skin.joints.push_back(skin.skeleton + i);
|
||||
auto& snode = model.nodes.emplace_back();
|
||||
snode.name = gbone.name;
|
||||
}
|
||||
skin.skeleton = model.nodes.size();
|
||||
for (int i = 0; i < n_bones; i++) {
|
||||
const auto& gbone = game_bones[i];
|
||||
skin.joints.push_back(skin.skeleton + i);
|
||||
auto& snode = model.nodes.emplace_back();
|
||||
snode.name = gbone.name;
|
||||
|
||||
// bind pose is bind_T_w
|
||||
// for glb we want bind_parent_T_bind_child
|
||||
// so bindp_T_w * inverse(bindc_T_w)
|
||||
math::Matrix4f matrix;
|
||||
if (gbone.parent_idx >= 0) {
|
||||
matrix = unscale_translation(game_bones.at(gbone.parent_idx).bind_pose_T_w) *
|
||||
inverse(unscale_translation(gbone.bind_pose_T_w));
|
||||
|
||||
} else {
|
||||
// I think this value is ignored anyway.
|
||||
for (int r = 0; r < 4; r++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
matrix(r, c) = (r == c) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// bind pose is bind_T_w
|
||||
// for glb we want bind_parent_T_bind_child
|
||||
// so bindp_T_w * inverse(bindc_T_w)
|
||||
math::Matrix4f matrix;
|
||||
if (gbone.parent_idx >= 0) {
|
||||
matrix = unscale_translation(game_bones.at(gbone.parent_idx).bind_pose_T_w) *
|
||||
inverse(unscale_translation(gbone.bind_pose_T_w));
|
||||
|
||||
} else {
|
||||
// I think this value is ignored anyway.
|
||||
for (int r = 0; r < 4; r++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
snode.matrix.push_back(matrix(c, r));
|
||||
matrix(r, c) = (r == c) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
for (auto child : children.at(i)) {
|
||||
snode.children.push_back(skin.skeleton + child);
|
||||
}
|
||||
|
||||
for (int r = 0; r < 4; r++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
snode.matrix.push_back(matrix(c, r));
|
||||
}
|
||||
}
|
||||
ASSERT(skin.skeleton + n_bones == (int)model.nodes.size());
|
||||
skin.inverseBindMatrices = make_inv_matrix_bind_poses(game_bones, model);
|
||||
}
|
||||
|
||||
for (size_t effect_idx = 0; effect_idx < mmodel.effects.size(); effect_idx++) {
|
||||
const auto& effect = mmodel.effects[effect_idx];
|
||||
for (size_t draw_idx = 0; draw_idx < effect.all_draws.size(); draw_idx++) {
|
||||
const auto& draw = effect.all_draws[draw_idx];
|
||||
auto& prim = mesh.primitives.emplace_back();
|
||||
prim.material =
|
||||
add_material_for_tex(level, model, draw.tree_tex_id, tex_image_map, draw.mode);
|
||||
prim.indices = make_index_buffer_accessor(
|
||||
model, draw_to_start[model_idx][effect_idx][draw_idx],
|
||||
draw_to_count[model_idx][effect_idx][draw_idx], index_buffer_view);
|
||||
prim.attributes["POSITION"] = position_buffer_accessor;
|
||||
prim.attributes["TEXCOORD_0"] = texture_buffer_accessor;
|
||||
prim.attributes["COLOR_0"] = colors;
|
||||
prim.attributes["JOINTS_0"] = joints_accessor;
|
||||
prim.attributes["WEIGHTS_0"] = weights_accessor;
|
||||
prim.mode = TINYGLTF_MODE_TRIANGLES;
|
||||
for (auto child : children.at(i)) {
|
||||
snode.children.push_back(skin.skeleton + child);
|
||||
}
|
||||
}
|
||||
ASSERT(skin.skeleton + n_bones == (int)model.nodes.size());
|
||||
skin.inverseBindMatrices = make_inv_matrix_bind_poses(game_bones, model);
|
||||
}
|
||||
|
||||
for (size_t effect_idx = 0; effect_idx < mmodel.effects.size(); effect_idx++) {
|
||||
const auto& effect = mmodel.effects[effect_idx];
|
||||
for (size_t draw_idx = 0; draw_idx < effect.all_draws.size(); draw_idx++) {
|
||||
const auto& draw = effect.all_draws[draw_idx];
|
||||
auto& prim = mesh.primitives.emplace_back();
|
||||
prim.material =
|
||||
add_material_for_tex(level, model, draw.tree_tex_id, tex_image_map, draw.mode);
|
||||
prim.indices =
|
||||
make_index_buffer_accessor(model, draw_to_start[effect_idx][draw_idx],
|
||||
draw_to_count[effect_idx][draw_idx], index_buffer_view);
|
||||
prim.attributes["POSITION"] = position_buffer_accessor;
|
||||
prim.attributes["TEXCOORD_0"] = texture_buffer_accessor;
|
||||
prim.attributes["COLOR_0"] = colors;
|
||||
prim.attributes["JOINTS_0"] = joints_accessor;
|
||||
prim.attributes["WEIGHTS_0"] = weights_accessor;
|
||||
prim.mode = TINYGLTF_MODE_TRIANGLES;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -1026,30 +1021,38 @@ void save_level_background_as_gltf(const tfrag3::Level& level, const fs::path& g
|
||||
|
||||
void save_level_foreground_as_gltf(const tfrag3::Level& level,
|
||||
const std::map<std::string, level_tools::ArtData>& art_data,
|
||||
const fs::path& glb_file) {
|
||||
// the top level container for everything is the model.
|
||||
tinygltf::Model model;
|
||||
const fs::path& glb_path) {
|
||||
for (size_t model_idx = 0; model_idx < level.merc_data.models.size(); model_idx++) {
|
||||
const auto& mmodel = level.merc_data.models[model_idx];
|
||||
|
||||
// a "scene" is a traditional scene graph, made up of Nodes.
|
||||
// sadly, attempting to nest stuff makes the blender importer unhappy, so we just dump
|
||||
// everything into the top level.
|
||||
model.scenes.emplace_back();
|
||||
// the top level container for everything is the model.
|
||||
tinygltf::Model model;
|
||||
|
||||
// hack, add a default material.
|
||||
tinygltf::Material mat;
|
||||
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
|
||||
mat.doubleSided = true;
|
||||
model.materials.push_back(mat);
|
||||
// a "scene" is a traditional scene graph, made up of Nodes.
|
||||
// sadly, attempting to nest stuff makes the blender importer unhappy, so we just dump
|
||||
// everything into the top level.
|
||||
model.scenes.emplace_back();
|
||||
|
||||
std::unordered_map<int, int> tex_image_map;
|
||||
// hack, add a default material.
|
||||
tinygltf::Material mat;
|
||||
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
|
||||
mat.doubleSided = true;
|
||||
model.materials.push_back(mat);
|
||||
|
||||
add_merc(level, art_data, model, tex_image_map);
|
||||
std::unordered_map<int, int> tex_image_map;
|
||||
|
||||
model.asset.generator = "opengoal";
|
||||
tinygltf::TinyGLTF gltf;
|
||||
gltf.WriteGltfSceneToFile(&model, glb_file.string(),
|
||||
true, // embedImages
|
||||
true, // embedBuffers
|
||||
true, // pretty print
|
||||
true); // write binary
|
||||
add_merc(level, art_data, mmodel, model, tex_image_map);
|
||||
|
||||
model.asset.generator = "opengoal";
|
||||
|
||||
auto glb_file = glb_path / fmt::format("{}.glb", mmodel.name);
|
||||
file_util::create_dir_if_needed_for_file(glb_file);
|
||||
|
||||
tinygltf::TinyGLTF gltf;
|
||||
gltf.WriteGltfSceneToFile(&model, glb_file.string(),
|
||||
true, // embedImages
|
||||
true, // embedBuffers
|
||||
true, // pretty print
|
||||
true); // write binary
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,4 @@
|
||||
void save_level_background_as_gltf(const tfrag3::Level& level, const fs::path& glb_file);
|
||||
void save_level_foreground_as_gltf(const tfrag3::Level& level,
|
||||
const std::map<std::string, level_tools::ArtData>& art_data,
|
||||
const fs::path& glb_file);
|
||||
const fs::path& glb_path);
|
||||
@@ -3,18 +3,27 @@
|
||||
using namespace gltf_util;
|
||||
|
||||
namespace decompiler {
|
||||
void extract(const std::string& name,
|
||||
|
||||
void extract(tfrag3::MercModel& mdl,
|
||||
MercExtractData& out,
|
||||
const tinygltf::Model& model,
|
||||
const std::vector<NodeWithTransform>& all_nodes,
|
||||
u32 index_offset,
|
||||
u32 vertex_offset,
|
||||
u32 tex_offset) {
|
||||
u32 tex_offset,
|
||||
bool& has_custom_weights) {
|
||||
ASSERT(out.new_vertices.empty());
|
||||
|
||||
std::map<int, tfrag3::MercDraw> draw_by_material;
|
||||
int mesh_count = 0;
|
||||
int prim_count = 0;
|
||||
int joints = 3;
|
||||
auto skin_idx = find_single_skin(model, all_nodes);
|
||||
if (skin_idx) {
|
||||
joints += get_joint_count(model, *skin_idx);
|
||||
}
|
||||
bool copy_eye_draws = false;
|
||||
bool copy_mod_draws = false;
|
||||
|
||||
for (const auto& n : all_nodes) {
|
||||
const auto& node = model.nodes[n.node_idx];
|
||||
@@ -24,6 +33,12 @@ void extract(const std::string& name,
|
||||
if (node.mesh >= 0) {
|
||||
const auto& mesh = model.meshes[node.mesh];
|
||||
mesh_count++;
|
||||
has_custom_weights = node.extras.Has("enable_custom_weights") &&
|
||||
node.extras.Get("enable_custom_weights").Get<int>();
|
||||
copy_eye_draws =
|
||||
node.extras.Has("copy_eye_draws") && node.extras.Get("copy_eye_draws").Get<int>();
|
||||
copy_mod_draws =
|
||||
node.extras.Has("copy_mod_draws") && node.extras.Get("copy_mod_draws").Get<int>();
|
||||
for (const auto& prim : mesh.primitives) {
|
||||
prim_count++;
|
||||
// extract index buffer
|
||||
@@ -39,6 +54,21 @@ void extract(const std::string& name,
|
||||
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
|
||||
ASSERT(out.new_colors.size() == out.new_vertices.size());
|
||||
|
||||
if (prim.attributes.count("JOINTS_0") && prim.attributes.count("WEIGHTS_0")) {
|
||||
auto joints_and_weights = gltf_util::extract_and_flatten_joints_and_weights(model, prim);
|
||||
ASSERT(joints_and_weights.size() == verts.vtx.size());
|
||||
out.joints_and_weights.insert(out.joints_and_weights.end(), joints_and_weights.begin(),
|
||||
joints_and_weights.end());
|
||||
} else {
|
||||
// add fake data for vertices without this data
|
||||
gltf_util::JointsAndWeights dummy;
|
||||
dummy.joints[0] = 3;
|
||||
dummy.weights[0] = 1.f;
|
||||
for (size_t i = 0; i < out.new_vertices.size(); i++) {
|
||||
out.joints_and_weights.push_back(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: just putting it all in one material
|
||||
auto& draw = draw_by_material[prim.material];
|
||||
draw.mode = gltf_util::make_default_draw_mode(); // todo rm
|
||||
@@ -54,42 +84,176 @@ void extract(const std::string& name,
|
||||
}
|
||||
|
||||
tfrag3::MercEffect e;
|
||||
out.new_model.name = name;
|
||||
out.new_model.max_bones = 120;
|
||||
out.new_model.max_draws = 200;
|
||||
tfrag3::MercEffect envmap_eff;
|
||||
envmap_eff.has_envmap = false;
|
||||
out.new_model.name = mdl.name;
|
||||
// if we have a skeleton, use that joint count, otherwise use a high default value since the model
|
||||
// we replace can have more
|
||||
out.new_model.max_bones = joints != 3 ? joints : 100;
|
||||
out.new_model.max_draws = 0;
|
||||
|
||||
for (const auto& [mat_idx, d_] : draw_by_material) {
|
||||
e.all_draws.push_back(d_);
|
||||
auto& draw = e.all_draws.back();
|
||||
draw.mode = make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = 0;
|
||||
continue;
|
||||
}
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (tex_idx == -1) {
|
||||
lg::warn("Material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = 0;
|
||||
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
|
||||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
|
||||
gltf_util::process_normal_merc_draw(model, out, tex_offset, e, mat_idx, d_);
|
||||
} else {
|
||||
envmap_eff.has_envmap = true;
|
||||
gltf_util::process_envmap_merc_draw(model, out, tex_offset, envmap_eff, mat_idx, d_);
|
||||
}
|
||||
}
|
||||
|
||||
// in case a model only has envmap draws, we don't push the normal merc effect
|
||||
if (!e.all_draws.empty()) {
|
||||
out.new_model.effects.push_back(e);
|
||||
}
|
||||
if (envmap_eff.has_envmap) {
|
||||
out.new_model.effects.push_back(envmap_eff);
|
||||
}
|
||||
|
||||
// copy any effects from the old model that used mod or eye draws
|
||||
if (copy_eye_draws || copy_mod_draws) {
|
||||
for (auto& old_eff : mdl.effects) {
|
||||
tfrag3::MercEffect eff;
|
||||
bool has_eye_draw = false;
|
||||
if (copy_eye_draws) {
|
||||
for (auto& draw : old_eff.all_draws) {
|
||||
if (draw.eye_id != 0xff) {
|
||||
has_eye_draw = true;
|
||||
eff.all_draws.push_back(draw);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (copy_mod_draws && old_eff.has_mod_draw) {
|
||||
eff.has_mod_draw = true;
|
||||
eff.mod = old_eff.mod;
|
||||
eff.mod.fix_draw.clear();
|
||||
}
|
||||
if ((copy_eye_draws || copy_mod_draws) && (eff.has_mod_draw || has_eye_draw)) {
|
||||
lg::info("adding old effect for {} (mod draw {}, eye draw {})", mdl.name,
|
||||
old_eff.has_mod_draw, has_eye_draw);
|
||||
out.new_model.effects.push_back(eff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& effect : out.new_model.effects) {
|
||||
out.new_model.max_draws += effect.all_draws.size();
|
||||
}
|
||||
|
||||
lg::info("total of {} unique materials ({} normal, {} envmap)", out.new_model.max_draws,
|
||||
e.all_draws.size(), envmap_eff.all_draws.size());
|
||||
lg::info("Merged {} meshes and {} prims into {} vertices", mesh_count, prim_count,
|
||||
out.new_vertices.size());
|
||||
}
|
||||
|
||||
void extract(const std::string& name,
|
||||
MercExtractData& out,
|
||||
const tinygltf::Model& model,
|
||||
const std::vector<NodeWithTransform>& all_nodes,
|
||||
u32 index_offset,
|
||||
u32 vertex_offset,
|
||||
u32 tex_offset,
|
||||
bool& has_custom_weights) {
|
||||
ASSERT(out.new_vertices.empty());
|
||||
|
||||
std::map<int, tfrag3::MercDraw> draw_by_material;
|
||||
int mesh_count = 0;
|
||||
int prim_count = 0;
|
||||
int joints = 3;
|
||||
auto skin_idx = find_single_skin(model, all_nodes);
|
||||
if (skin_idx) {
|
||||
joints += get_joint_count(model, *skin_idx);
|
||||
}
|
||||
|
||||
for (const auto& n : all_nodes) {
|
||||
const auto& node = model.nodes[n.node_idx];
|
||||
if (node.extras.Has("set_invisible") && node.extras.Get("set_invisible").Get<int>()) {
|
||||
continue;
|
||||
}
|
||||
if (node.mesh >= 0) {
|
||||
const auto& mesh = model.meshes[node.mesh];
|
||||
mesh_count++;
|
||||
has_custom_weights = node.extras.Has("enable_custom_weights") &&
|
||||
node.extras.Get("enable_custom_weights").Get<int>();
|
||||
for (const auto& prim : mesh.primitives) {
|
||||
prim_count++;
|
||||
// extract index buffer
|
||||
std::vector<u32> prim_indices = gltf_util::gltf_index_buffer(
|
||||
model, prim.indices, out.new_vertices.size() + vertex_offset);
|
||||
ASSERT_MSG(prim.mode == TINYGLTF_MODE_TRIANGLES, "Unsupported triangle mode");
|
||||
// extract vertices
|
||||
auto verts =
|
||||
gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name);
|
||||
out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end());
|
||||
out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(),
|
||||
verts.vtx_colors.end());
|
||||
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
|
||||
ASSERT(out.new_colors.size() == out.new_vertices.size());
|
||||
|
||||
const auto& tex = model.textures[tex_idx];
|
||||
ASSERT(tex.sampler >= 0);
|
||||
ASSERT(tex.source >= 0);
|
||||
draw.mode = draw_mode_from_sampler(model.samplers.at(tex.sampler));
|
||||
if (prim.attributes.count("JOINTS_0") && prim.attributes.count("WEIGHTS_0")) {
|
||||
auto joints_and_weights = gltf_util::extract_and_flatten_joints_and_weights(model, prim);
|
||||
ASSERT(joints_and_weights.size() == verts.vtx.size());
|
||||
out.joints_and_weights.insert(out.joints_and_weights.end(), joints_and_weights.begin(),
|
||||
joints_and_weights.end());
|
||||
} else {
|
||||
// add fake data for vertices without this data
|
||||
gltf_util::JointsAndWeights dummy;
|
||||
dummy.joints[0] = 3;
|
||||
dummy.weights[0] = 1.f;
|
||||
for (size_t i = 0; i < out.new_vertices.size(); i++) {
|
||||
out.joints_and_weights.push_back(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
const auto& img = model.images[tex.source];
|
||||
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
|
||||
// TODO: just putting it all in one material
|
||||
auto& draw = draw_by_material[prim.material];
|
||||
draw.mode = gltf_util::make_default_draw_mode(); // todo rm
|
||||
draw.tree_tex_id = 0; // todo rm
|
||||
draw.num_triangles += prim_indices.size() / 3;
|
||||
draw.no_strip = true;
|
||||
draw.index_count = prim_indices.size();
|
||||
draw.first_index = index_offset + out.new_indices.size();
|
||||
|
||||
out.new_indices.insert(out.new_indices.end(), prim_indices.begin(), prim_indices.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
lg::info("total of {} unique materials", e.all_draws.size());
|
||||
e.has_mod_draw = false;
|
||||
out.new_model.effects.push_back(e);
|
||||
out.new_model.effects.push_back(e);
|
||||
out.new_model.effects.push_back(e);
|
||||
out.new_model.effects.push_back(e);
|
||||
|
||||
tfrag3::MercEffect e;
|
||||
tfrag3::MercEffect envmap_eff;
|
||||
envmap_eff.has_envmap = false;
|
||||
out.new_model.name = name;
|
||||
// if we have a skeleton, use that joint count, otherwise use a high default value since the model
|
||||
// we replace can have more
|
||||
out.new_model.max_bones = joints != 3 ? joints : 100;
|
||||
out.new_model.max_draws = 0;
|
||||
|
||||
for (const auto& [mat_idx, d_] : draw_by_material) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
|
||||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
|
||||
gltf_util::process_normal_merc_draw(model, out, tex_offset, e, mat_idx, d_);
|
||||
} else {
|
||||
envmap_eff.has_envmap = true;
|
||||
gltf_util::process_envmap_merc_draw(model, out, tex_offset, envmap_eff, mat_idx, d_);
|
||||
}
|
||||
}
|
||||
|
||||
// in case a model only has envmap draws, we don't push the normal merc effect
|
||||
if (!e.all_draws.empty()) {
|
||||
out.new_model.effects.push_back(e);
|
||||
}
|
||||
if (envmap_eff.has_envmap) {
|
||||
out.new_model.effects.push_back(envmap_eff);
|
||||
}
|
||||
|
||||
for (auto& effect : out.new_model.effects) {
|
||||
out.new_model.max_draws += effect.all_draws.size();
|
||||
}
|
||||
|
||||
lg::info("total of {} unique materials ({} normal, {} envmap)", out.new_model.max_draws,
|
||||
e.all_draws.size(), envmap_eff.all_draws.size());
|
||||
lg::info("Merged {} meshes and {} prims into {} vertices", mesh_count, prim_count,
|
||||
out.new_vertices.size());
|
||||
}
|
||||
@@ -99,9 +263,9 @@ const tfrag3::MercVertex& find_closest(const std::vector<tfrag3::MercVertex>& ol
|
||||
float y,
|
||||
float z) {
|
||||
float best_dist = 1e10;
|
||||
int best_idx = 0;
|
||||
size_t best_idx = 0;
|
||||
|
||||
for (int i = 0; i < old.size(); i++) {
|
||||
for (size_t i = 0; i < old.size(); i++) {
|
||||
auto& v = old[i];
|
||||
float dx = v.pos[0] - x;
|
||||
float dy = v.pos[1] - y;
|
||||
@@ -118,7 +282,8 @@ const tfrag3::MercVertex& find_closest(const std::vector<tfrag3::MercVertex>& ol
|
||||
|
||||
void merc_convert_replacement(MercSwapData& out,
|
||||
const MercExtractData& in,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts) {
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool use_custom_weights) {
|
||||
out.new_model = in.new_model;
|
||||
out.new_indices = in.new_indices;
|
||||
out.new_textures = in.tex_pool.textures_by_idx;
|
||||
@@ -126,26 +291,36 @@ void merc_convert_replacement(MercSwapData& out,
|
||||
// convert vertices
|
||||
for (size_t i = 0; i < in.new_vertices.size(); i++) {
|
||||
const auto& y = in.new_vertices[i];
|
||||
|
||||
const auto& copy_from = find_closest(old_verts, y.x, y.y, y.z);
|
||||
auto& x = out.new_vertices.emplace_back();
|
||||
x.pos[0] = y.x;
|
||||
x.pos[1] = y.y;
|
||||
x.pos[2] = y.z;
|
||||
x.normal[0] = copy_from.normal[0];
|
||||
x.normal[1] = copy_from.normal[1];
|
||||
x.normal[2] = copy_from.normal[2];
|
||||
x.weights[0] = copy_from.weights[0];
|
||||
x.weights[1] = copy_from.weights[1];
|
||||
x.weights[2] = copy_from.weights[2];
|
||||
x.normal[0] = in.normals.at(i).x();
|
||||
x.normal[1] = in.normals.at(i).y();
|
||||
x.normal[2] = in.normals.at(i).z();
|
||||
if (use_custom_weights) {
|
||||
x.weights[0] = in.joints_and_weights.at(i).weights[0];
|
||||
x.weights[1] = in.joints_and_weights.at(i).weights[1];
|
||||
x.weights[2] = in.joints_and_weights.at(i).weights[2];
|
||||
x.mats[0] = in.joints_and_weights.at(i).joints[0];
|
||||
x.mats[1] = in.joints_and_weights.at(i).joints[1];
|
||||
x.mats[2] = in.joints_and_weights.at(i).joints[2];
|
||||
} else {
|
||||
x.weights[0] = copy_from.weights[0];
|
||||
x.weights[1] = copy_from.weights[1];
|
||||
x.weights[2] = copy_from.weights[2];
|
||||
x.mats[0] = copy_from.mats[0];
|
||||
x.mats[1] = copy_from.mats[1];
|
||||
x.mats[2] = copy_from.mats[2];
|
||||
}
|
||||
x.st[0] = y.s;
|
||||
x.st[1] = y.t;
|
||||
x.rgba[0] = in.new_colors[i][0];
|
||||
x.rgba[1] = in.new_colors[i][1];
|
||||
x.rgba[2] = in.new_colors[i][2];
|
||||
x.rgba[3] = in.new_colors[i][3];
|
||||
x.mats[0] = copy_from.mats[0];
|
||||
x.mats[1] = copy_from.mats[1];
|
||||
x.mats[2] = copy_from.mats[2];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,22 +339,22 @@ void merc_convert_custom(MercSwapData& out, const MercExtractData& in) {
|
||||
x.normal[0] = in.normals.at(i).x();
|
||||
x.normal[1] = in.normals.at(i).y();
|
||||
x.normal[2] = in.normals.at(i).z();
|
||||
x.weights[0] = 1.0f;
|
||||
x.weights[1] = 0.0f;
|
||||
x.weights[2] = 0.0f;
|
||||
x.weights[0] = in.joints_and_weights.at(i).weights[0];
|
||||
x.weights[1] = in.joints_and_weights.at(i).weights[1];
|
||||
x.weights[2] = in.joints_and_weights.at(i).weights[2];
|
||||
x.st[0] = y.s;
|
||||
x.st[1] = y.t;
|
||||
x.rgba[0] = in.new_colors[i][0];
|
||||
x.rgba[1] = in.new_colors[i][1];
|
||||
x.rgba[2] = in.new_colors[i][2];
|
||||
x.rgba[3] = in.new_colors[i][3];
|
||||
x.mats[0] = 3;
|
||||
x.mats[1] = 0;
|
||||
x.mats[2] = 0;
|
||||
x.mats[0] = in.joints_and_weights.at(i).joints[0];
|
||||
x.mats[1] = in.joints_and_weights.at(i).joints[1];
|
||||
x.mats[2] = in.joints_and_weights.at(i).joints[2];
|
||||
}
|
||||
}
|
||||
|
||||
MercSwapData load_replacement_merc_model(const std::string& name,
|
||||
MercSwapData load_replacement_merc_model(tfrag3::MercModel& mdl,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
@@ -198,12 +373,44 @@ MercSwapData load_replacement_merc_model(const std::string& name,
|
||||
auto all_nodes = flatten_nodes_from_all_scenes(model);
|
||||
|
||||
MercExtractData extract_data;
|
||||
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
|
||||
current_tex_count);
|
||||
auto has_custom_weights = false;
|
||||
extract(mdl, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
|
||||
current_tex_count, has_custom_weights);
|
||||
if (custom_mdl) {
|
||||
merc_convert_custom(result, extract_data);
|
||||
} else {
|
||||
merc_convert_replacement(result, extract_data, old_verts);
|
||||
merc_convert_replacement(result, extract_data, old_verts, has_custom_weights);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MercSwapData load_custom_merc_model(const std::string& name,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl) {
|
||||
MercSwapData result;
|
||||
lg::info("Reading gltf mesh: {}", path);
|
||||
tinygltf::TinyGLTF loader;
|
||||
tinygltf::Model model;
|
||||
std::string err, warn;
|
||||
bool res = loader.LoadBinaryFromFile(&model, &err, &warn, path);
|
||||
ASSERT_MSG(warn.empty(), warn.c_str());
|
||||
ASSERT_MSG(err.empty(), err.c_str());
|
||||
ASSERT_MSG(res, "Failed to load GLTF file!");
|
||||
auto all_nodes = flatten_nodes_from_all_scenes(model);
|
||||
|
||||
MercExtractData extract_data;
|
||||
auto has_custom_weights = false;
|
||||
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
|
||||
current_tex_count, has_custom_weights);
|
||||
if (custom_mdl) {
|
||||
merc_convert_custom(result, extract_data);
|
||||
} else {
|
||||
merc_convert_replacement(result, extract_data, old_verts, has_custom_weights);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -4,29 +4,21 @@
|
||||
#include "common/util/gltf_util.h"
|
||||
|
||||
namespace decompiler {
|
||||
struct MercExtractData {
|
||||
gltf_util::TexturePool tex_pool;
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::PreloadedVertex> new_vertices;
|
||||
std::vector<math::Vector<u8, 4>> new_colors;
|
||||
std::vector<math::Vector3f> normals;
|
||||
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
gltf_util::MercSwapData load_replacement_merc_model(
|
||||
tfrag3::MercModel& mdl,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl);
|
||||
|
||||
// Data produced by loading a replacement model
|
||||
struct MercSwapData {
|
||||
std::vector<u32> new_indices;
|
||||
std::vector<tfrag3::MercVertex> new_vertices;
|
||||
std::vector<tfrag3::Texture> new_textures;
|
||||
tfrag3::MercModel new_model;
|
||||
};
|
||||
|
||||
MercSwapData load_replacement_merc_model(const std::string& name,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl);
|
||||
gltf_util::MercSwapData load_custom_merc_model(const std::string& name,
|
||||
u32 current_idx_count,
|
||||
u32 current_vtx_count,
|
||||
u32 current_tex_count,
|
||||
const std::string& path,
|
||||
const std::vector<tfrag3::MercVertex>& old_verts,
|
||||
bool custom_mdl);
|
||||
} // namespace decompiler
|
||||
@@ -1616,6 +1616,7 @@ void types2_for_expr(types2::Type& type_out,
|
||||
case SimpleExpression::Kind::VECTOR_CROSS:
|
||||
case SimpleExpression::Kind::VECTOR_MINUS:
|
||||
case SimpleExpression::Kind::VECTOR_PLUS:
|
||||
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
|
||||
types2_for_vector_in_and_out(type_out, expr, input_types, dts, extras);
|
||||
break;
|
||||
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
|
||||
|
||||
Loaded 100 of 3774 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user