Magical Pop'n Recomp

Magical Pop'n Recomp is a native Windows port of Magical Pop'n for the Super Nintendo Entertainment System with native 16:9 widescreen support.

README

Magical Pop'n Recomp

Latest release Total downloads Open issues Windows 10 or 11

Quick start   Playing   Widescreen   How it works   Credits


A static recompilation of the SNES game Magical Pop'n (Pack-In-Video / Polestar, 1995). The game's 65816 code is translated into C ahead of time and compiled into a native Windows program, with a small menu for window size, fullscreen, smoothing, FPS, volume, controls and language.

Important

This repository contains no game code, graphics data or ROM contents. You need your own copy of the game as a ROM file. The builder reads it on your PC and produces MagicalPopn.exe.

Note

This is version 0.9.7, so there is a slight chance of bugs. If you find one, please open an issue, ideally with a save state (F5) or a screenshot (F12).

Native 16:9 widescreen

The start of stage 4 in the original 4:3 and in native 16:9

Levels are rendered wider rather than stretched, so the pixels keep their shape and the extra columns on each side show the real level and its enemies.

Tip

16:9 is now tested room by room: every area of the game was walked from end to end, and each side column was compared pixel by pixel with what the original 4:3 picture shows at the same spot. A few small glitches remain.

Quick start

  1. Download MagicalPopn-Builder.zip from the latest release and extract it anywhere.
  2. Drag your ROM onto Builder.exe (or onto the builder window).
  3. Wait about a minute and a half while it builds, then press Play.

Tip

That's all: nothing to install. You need Windows 10 or 11 (64-bit) and a Magical Pop'n ROM. Any dump works: .sfc, .smc or .zip, with or without a copier header, the original Japanese release or a translated/patched version.

Note

Linux support is planned, once the game is in a comfortable state on Windows.

The game is built into the same folder as the builder (choose another under Install to), and you can move MagicalPopn.exe with its states folder and settings.ini anywhere. The download includes its own C compiler (llvm-mingw, clang + lld, trimmed to 64-bit Windows) in the toolchain folder, so the builder never needs Visual Studio or Python.

Building from the source instead

With Python 3 and either a toolchain folder holding llvm-mingw in the repository root or the Microsoft C++ Build Tools, run Builder.bat or:

python tools/pipeline.py ROM [--out DIR]

To package the builder yourself:

python -m PyInstaller builder/Builder.spec

The whole game is compiled before it starts. There's nothing to configure:

  • The repository ships a code map (data/codemap.txt): the addresses of every routine found by many hours of automated play, plus a checksum of the code bytes at each one, and no game data. Every entry whose code matches your ROM is used. The map covers the original Japanese release, the FastROM v1.1 patch (Japanese and English) and the English translation patch, so all of these build straight away.
  • Static analysis adds everything reachable from those routines, including routines referenced through pointer tables in the code.
  • After compiling, the builder test-plays the finished game and recompiles once more if that test found anything new.

As a safety net, any code the build still missed runs through a built-in interpreter instead of stopping, and building again includes it.

Playing

KeyboardSNESXboxPlayStationSwitch
Arrow keysD-padD-pad / left stickD-pad / left stickD-pad / left stick
Z / XB / AA / BCross / CircleB / A
A / SY / XX / YSquare / TriangleY / X
Q / WL / RLB / RBL1 / R1L / R
Enter / Right ShiftStart / SelectStart / BackOptions / Share+ / −
KeyAction
F1 or Escmenu (on a controller: click a stick, press Home / PS, or hold Select + Start)
F5 / F9save state / load state (current slot)
F6 / F7previous / next save slot (9 slots)
Ppause
F11 or Alt+Enterfullscreen
F12screenshot (saved to screenshots\)
Tab (hold) / right triggerfast-forward
Controllers

Plug in or pair any controller, before or during play, and it works straight away. You can use several at once. Buttons go by position, as on a Super Famicom pad: bottom = B, right = A, left = Y, top = X. The game reads:

  • Xbox-style controllers (XInput): all four slots. This also covers most modern third-party pads, 8BitDo pads in X mode, Steam Input and DS4Windows.
  • Every other controller: read directly through Windows (HID), so any USB or Bluetooth gamepad or joystick gives its buttons, sticks and d-pad.
  • Built-in layouts:
    • DualShock 4 and DualSense, over USB and Bluetooth.
    • Switch Pro Controller and the Nintendo Switch Online SNES controller, which the game wakes up and switches to their full report.
    • 8BitDo pads in D-input mode, common USB SNES-style pads, and the usual PC gamepad layout.

Tip

If a controller's buttons end up in the wrong places, open Set up controller on the Controls page of the F1 menu and press each button when asked. Esc skips a button and Backspace stops. The layout is saved for that kind of controller ([pad VVVV-PPPP] in settings.ini). Reset to defaults puts every controller back to its built-in layout.

The F1 menu

The F1 menu, styled after the Super Famicom cover art, is a single list on a pink panel, with the selected row highlighted. Use Up and Down to pick a row, Left and Right to change it, and Enter to activate. Esc goes back, and closes the menu from the main page. The mouse works too: hover to select, left-click to change or activate, right-click to change the other way. A note under the list explains the selected setting, and settings are saved automatically.

PageSettings
Mainresume, save/load state, save slot, continue on launch, remove slowdown, language (English / 日本語), check for updates, screenshot, reset (press twice), quit (press twice), and the three pages below
Videowindow size, display mode, VSync, low latency, motion smoothing (60 / 120 fps), widescreen (off / 16:9 / 16:10 / 21:9), pixel shape (square / TV 8:7 / stretch), integer scaling, smoothing, scanlines, sprite limit, FPS counter
Soundvolume, mute, mute in background, pause in background
Controlsthe controller in use, controller setup, rebind every key, fast-forward speed, reset to defaults

Sprite limit is off by default. The SNES can only draw so many sprites on one line (32 sprites or 34 eight-pixel slices), and anything past that is cut off. The game hits the limit in a few busy moments, such as the heroine running past the dust cloud on the title screen. With the setting off, every sprite is drawn. Turn it on for the original look. Only the picture changes: the game still sees the hardware's overflow flags as before, so it plays the same.

Check for updates (on by default): when the game starts it looks for a newer release on this repository. If there is one, a box offers to update. Choose Yes and the game downloads the new builder (about 90 MB), rebuilds itself from the ROM it was made from (a minute or two) and starts again, with your saves and settings kept. Nothing about you or your game is sent. Updating this way works from version 0.9.4.1 onwards.

Remove slowdown (on by default): when the game can't finish a frame in time, as in busy scenes, it gets extra processor time instead of slowing down like the original. Only the game's own work gets the extra time; the picture, timers and music stay exactly on time. About three quarters of the slowdown is gone; very long loading moments can still slow down briefly. Turn it off for the original timing, slowdown included.

Continue on launch (off by default) saves your exact place when you quit and resumes it the next time you start. Settings are saved in settings.ini next to the game, and save states in states\.

Smoothness and latency

Tip

On a monitor faster than 75 Hz, set motion smoothing to 120 under Video for the smoothest motion. For the lowest delay, keep it at 60 and turn on low latency.

How smoothing, pacing and audio work
  • Motion smoothing (off by default; set it to 120 under Video, for screens faster than 75 Hz): the game still runs at its native 60 fps, and an in-between picture is drawn after every game frame. On a 240 Hz monitor each picture stays up for exactly two refreshes, on a 120 Hz one for one. A 144 Hz monitor can't divide 120 evenly, so it gets a new picture on 5 refreshes out of every 6. A display thread redraws the frame with the console's own graphics chip, with each layer's scroll position and every sprite placed where they are at that exact moment between the last two frames. Pixel art stays crisp: nothing is blended or smeared. In-between pictures are drawn at half-pixel precision, across and down, so a background that scrolls one pixel per frame still gets a step in between. Sprites move with the game objects they belong to, the camera follows a steady path instead of the game's uneven whole-pixel steps, and brightness fades pass through in-between levels. Pictures are timed by a clock locked to the monitor's real refresh signal, so each one stays on screen for exactly the same number of refreshes (two each at 120 fps on a 240 Hz screen). Each picture is drawn a few milliseconds before its refresh and presented just after it, so a slow moment in the graphics driver doesn't make it miss its refresh. It uses VSync and adds about 1.5 frames (~28 ms) of delay. Set it to 60 under Video for the lowest latency.
  • With motion smoothing at 60 (or on a 60 Hz screen), each game frame is shown as it is. On a 120 Hz or 240 Hz monitor each frame stays for exactly 2 or 4 refreshes, so motion stays perfectly even, and the wait for the next refresh shrinks to about 8 ms or 4 ms. Other refresh rates (such as 144 Hz) use timer pacing.
  • Low latency (applies with motion smoothing at 60): the frame is shown the moment the console finishes drawing it. Controller input is then read as late as possible, just before the game's own read, about 3 ms before the next frame is due. Together this removes more than a frame of delay compared with ordinary emulation.
  • Audio runs on its own WASAPI thread. Gentle rate control (at most ±1% pitch, inaudible) keeps about 20 ms of sound buffered, so it never crackles or drifts.
Widescreen

The start of stage 4 in native 16:9

Widescreen (off by default; choose it under Video) is rendered natively, not stretched: the game shows more of the level at both sides. Magical Pop'n only keeps one screen-and-a-bit of the level in video memory, but it holds a much wider strip of the decoded level map in WRAM. Each frame, the renderer finds where the visible picture sits in that map and draws the extra columns from it, so they show the real level.

  • The status bar stays centred.
  • Screens that don't scroll (logos, title, story scenes, menus) are pillarboxed in black, since they were only ever drawn 256 pixels wide.
  • Each area is wide from its very first frame, and nothing is drawn beyond the area's own edges.
  • Narrow castle rooms, which the game streams into video memory a column at a time, are drawn from video memory as it fills, so their sides match the real room. So are small rooms whose picture can't be found in the level map.
  • Back layers that the game streams a column at a time, such as the dark forest's far trees, are drawn from the game's own copy of the whole layer.
  • Nothing is drawn that the original game doesn't have: where there is no level, the sides stay black.
  • Enemies, items, doors and effects are drawn in the extra columns too: the game's sprite-drawing helpers are patched (found by code signature, so this works for any version of the game) to cull against the wide screen instead of the 4:3 one. Enemies stay active from 128 px left of the original screen to 112 px right of it, which covers 16:9 and 16:10.
  • Bosses that roam the screen, such as the stone giant's head, use the full width, up to the ends of their arena.

Note

At 21:9, enemies can still appear a few pixels inside the far right edge.

The game's own text comes from the ROM you build from, so a translated ROM gives an English game.

How it works

flowchart LR
    A[Your ROM] --> B[Trace profiler<br>emulator + input bot]
    B --> C[65816 tracer<br>pointer harvesting]
    D[(Code map)] --> C
    C --> E[C emitter<br>about 2 million lines]
    E --> F[clang or MSVC]
    F --> G[MagicalPopn.exe]
  1. A trace profiler (emulator and input bot) plays your ROM and records code entry points with their register widths.
  2. A 65816 tracer with pointer harvesting finds every routine from those entries.
  3. A C emitter turns the routines into about 2 million lines of C.
  4. The bundled clang (or MSVC) compiles them into MagicalPopn.exe, with the ROM embedded as a resource.
Repository layout
Path
builder/builder.pywthe builder window
tools/toolchain.pybundled clang or MSVC: compile, resources, link
tools/pipeline.pybuild steps; also usable from the command line: python tools/pipeline.py ROM [--out DIR] [--force]
tools/snes.pyreads any dump format and identifies the game
tools/disasm65816.pyrecursive-descent tracer that tracks the M/X register-width flags; pointer and pointer-table harvesting
data/codemap.txtshipped code entry points (addresses + code checksums, no game data); regenerate with tools/make_codemap.py
tools/emit_c.pyturns each routine into C with fixed register widths, and applies the widescreen sprite patches
runtime/trace_main.cbuild-time profiler: plays the game with a bot and records code entry points
runtime/rt.*65816 semantics, call/return handling (unwinds games' stack tricks), interpreter fallback, save-state capture
runtime/hw.cSNES hardware (PPU, SPC700 + DSP, DMA) via LakeSnes, the widescreen level-map source, and motion smoothing (per-line PPU records, in-between pictures)
runtime/main.cgame loop, plus the env-gated test harness that walks every room and checks the widescreen picture
runtime/platform_win32.c, audio_wasapi.c, menu.c, settings.cOpenGL window with vsync (and the motion-smoothing display thread), WASAPI audio, input, F1 menu, settings

Note

Nothing is tied to one particular dump. Every address the game uses is found by analysing the ROM you provide.

Credits

  • Contributor: Claude by Anthropic, on the recompiler, runtime and builder.
  • Hardware emulation: LakeSnes by angelo_wf, MIT licence (third_party/LakeSnes/LICENSE.txt). Only its snes/ core is included; its PPU is extended for widescreen rendering and motion smoothing (changes marked [widescreen] and [recomp]).
  • Icon and README picture: the heroine's sprite from Magical Pop'n (assets/, rebuilt by tools/make_icon.py).
  • Menu font: Mochiy Pop P One by Fontworks, SIL Open Font License (runtime/fonts/OFL.txt); tools/subset_font.py cuts it down to the menu's characters.
  • Compiler in the release download: llvm-mingw by Martin Storsjö (LLVM, Apache 2.0 with LLVM exception; mingw-w64 runtime, see toolchain/LICENSE.TXT).

Caution

Magical Pop'n © 1995 Pack-In-Video / Polestar. This project is not affiliated with them and includes none of their data apart from the heroine's sprite used as the icon and the crop of the cover art in the builder window.