This is a work-in-progress decompilation of Mario Artist: Paint Studio (1999) for the 64DD
It is built directly on top of LuigiBlood's original decompilation of the game.
Required base ROM file:
dmpj.d64with MD53546bc6d93928a28285a91478bc41b68
Convert a Mario Artist Paint Studio NDD dump to D64 with LuigiBlood's leo64dd_python tool.
The RAM area should be only 0xFF.
You can create the dmpj.d64 file by taking a .ndd file (md5 8485643e5830cd67ed4c0a5fd49e2491) and running python3 leo64ddfile.py d64 <path-to-ndd-file> <path-to-repo>/dmpj.d64
This repository uses Git submodules. Make sure to either clone the repository with the --recurse-submodules flag or to run git submodule update --init --recursive after the initial clone.
When pulling updates, you can update all submodules with git submodule update --recursive.
If dependencies are already installed and dmpj.d64 is in the repo root:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txt
python3 -m pip install -r tools/splat/requirements.txt
make setup
make- Python 3
makegitcurlmd5sum- a MIPS binutils toolchain that provides one of these prefixes:
mips-linux-gnu-*mipsel-linux-gnu-*mips64-elf-*mips-elf-*
make setup will:
- initialize/update submodules
- download IDO 7.1 into
tools/ido_recomp/<host>/7.1 - run
tools/splatto regenerateasm/,bin/, andassets/fromdmpj.d64
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install -y \
binutils-mips-linux-gnu \
gcc \
git \
libc-dev \
libc6-dev \
make \
ninja-build \
openssl \
python3 \
python3-pip \
python3.12-venv \
curlInstall Xcode Command Line Tools first if they are not already installed:
xcode-select --installDownload Homebrew and install the required packages using it:
brew install \
coreutils \
git \
make \
mipsel-linux-gnu-binutils \
pythonBoth diffing tools below compare your current build's object files against a known-good baseline (expected/build), so the general workflow is:
make setup- only needed once, or after pulling changes that touchsplat.yaml/the base ROM. Regeneratesasm/,bin/, andassets/fromdmpj.d64.make- rebuilds the ROM from current source. If it succeeds,md5sum -c checksum.md5printsbuild/dmpj.d64: OK, confirming a bit-exact match against the original ROM regardless of which functions are matched yet (unmatched functions still compile to identical bytes via theirGLOBAL_ASMstubs).cp -r build expected/build- snapshot that known-good build as the baseline. Only needs to be redone after step 1/2 change what "known-good" looks like (e.g. aftermake setup, or after pulling other people's matches).- Diff a specific function with
asm-differorobjdiff(below) to see if your in-progress C matches.
asm-differ (tools/asm-differ, a submodule), is a tool used by default on decomp.me, to compare your current C output against the target assembly for a function.
Before diffing for the first time, snapshot a known-good build as the baseline to diff against:
make
cp -r build expected/buildThen diff a function by name (or address):
python3 tools/asm-differ/diff.py -mo func_80007D64-mrebuilds automatically viamakebefore diffing-odiffs the object file so symbol names resolve- add
-wto re-run automatically whenever the source file is saved
Run python3 tools/asm-differ/diff.py --help for the full list of options.
objdiff is an alternative diffing tool also used on decomp.me with a GUI, live rebuild-on-save, and a function/object browser - also the same diffing engine decomp.me uses under the hood, so a scratch that matches in the browser will match here too. The project's objdiff.json (repo root) is already configured with one unit per c-type source file.
Install it (either works):
# prebuilt binary - see https://github.com/encounter/objdiff/releases
# or, with Rust installed:
cargo install --locked --git https://github.com/encounter/objdiff.git objdiff-gui objdiff-cliLike asm-differ, it needs a known-good baseline to diff against:
make
cp -r build expected/buildThen launch the GUI, pointing it at the repo root (it won't auto-detect the current directory):
objdiff -p /path/to/PaintStudioDecomp- The sidebar lists every unit from
objdiff.json(one perc-type source file, e.g.src/gameboot.c). - Click a unit to open its diff view: target assembly on the left, your current build on the right, function by function. Matching lines are unhighlighted; mismatches are highlighted, similar to
asm-differ's output. - Each unit also shows a match percentage in the sidebar so you can see progress at a glance.
- With the window focused, save the source file you're working on and objdiff rebuilds and re-diffs automatically (via
watch_patternsinobjdiff.json) - no need to switch back to a terminal.
To check overall progress without the GUI, use the CLI instead:
objdiff-cli report generateFunctions can also be matched entirely in the browser using decomp.me, which doesn't require a local build environment. This is useful for getting help from others, or for working without a full local setup.
decomp.me uses asm-differ as its diff viewer, the same tool tools/asm-differ provides locally. Because both sides use the same diffing logic, the score and diff output you see on decomp.me are exactly what you'd get from tools/asm-differ/diff.py locally.
Go to decomp.me/new and create a new scratch:
- Platform: Nintendo 64
- Preset: Mario Paint Studio
- Compiler:
ido7.1 - Diff Label:
asm label from where function begins - Target assembly: paste the contents of the function's
.sfile - Context: paste the contents of
ctx.c