I have been playing A Link to the Past on my Old 3DS XL through EstebanPdN's native 3DS port, and one thing kept nagging me. The console has a 3D slider, and the game ignored it. A Link Between Worlds proved how good Hyrule looks with depth, so I decided to add it.
The result is three features, sent to Esteban as one pull request. It is not merged and not released, so I will tell you plainly how to try it today further down.
What it does
- Stereoscopic 3D with the slider. Push the slider up and the world gets depth. Settings > Screen > 3D DEPTH picks OFF, LOW, MID or HIGH.
- Depth that follows the terrain. Plateaus, ledges and stairs sit at different heights, and statues, trees and walls stand up from their own base instead of being flat paint.
- An A Link Between Worlds style bottom screen. Wood frame, parchment map, gold item slots, one status bar with hearts, magic, rupees and counters, and stone tablets for tabs.
- A GUIDE tab. A fifth tab that reads a walkthrough from your SD card, with chapter and place buttons and drag scrolling.
Fair warning: 3D only works on the Old 3DS and Old 3DS XL. On those the PICA200 GPU path draws every frame twice, once per eye. New 3DS and 2DS use the port's CPU renderer and stay in 2D. I only tested on my Old 3DS XL, so the new bottom screen is untested on those too.
The hard problem: Link floating over the ground
My first version was simple. Each background layer got a fixed depth and the sprites got another. It worked, but Link and the enemies floated above a flat ground like cardboard cut-outs.
The next step was to read depth from the SNES layer order. The game already stacks things in a useful way: the HUD on top, tall things, the floor, and the lower level behind it, and Link's sprite priority tells you which floor he is standing on. That fixed the floating, but not the objects. On the Dark World pyramid the statues split in two, because only the head tiles carry the "in front" priority. The bodies are plain solid tiles, so layer order alone cannot know they belong together.
So I stopped asking the graphics and asked the collision data instead. The game knows which tiles are walkable, which are ledges and which are walls. I feed that into a small solver that builds a height field: a ledge steps toward the side you jump to, a wall band steps by its number of rows, a stair row climbs one step. Each tile corner carries its own depth and neighbours share their edge depth, so the per-eye shift does not tear cracks into cliffs. Sprites then stand on whatever ground is under their feet.
The performance bit
The solver is the expensive part. On my Old 3DS XL outdoors:
| Setup | Frame rate |
|---|---|
| 3D on, terrain off | about 45 fps |
| terrain solver on the render thread (first attempt) | 15 to 25 fps |
| terrain solver on the second CPU core | about 40 fps |
These are my own measurements on my own console. The fix was to move it to core 1 as a background job, so the render thread only picks up the latest result. If core 1 has no spare time, it falls back to a quick solve every eighth frame.
How to try it
You need your own copy of the game. Like the upstream port, this needs you to bring your own ROM: dump your own cartridge and put the unheadered USA ROM on your SD card. Nothing in the patches contains game data, and the bottom-screen icons are drawn from code, not taken from any Nintendo art.
- Wait for the pull request to be merged and released. That is the easy route, and I will update this post when it happens.
- Or build it yourself from my fork at github.com/djaysan/zelda-alttp-3ds, whose main branch is the pull request. The build is the upstream one: devkitARM,
makeromandbannertool, thenplatform/3ds/build.sh. One note: with the stock devkitPro curl package the link needs-lzadded, which I mention in the pull request.
I am not publishing test builds. The port has no licence file for its own code and I want Esteban's blessing first. I asked him in the pull request.
The guide tab
The GUIDE tab reads guide.txt from sdmc:/3ds/Zelda 3DS/. The text is a 44-column bitmap font (the public-domain X11 6x9 face), you drag to scroll, tap the top or bottom half to turn a page, and your reading position is saved.
The walkthrough text is not in the repository. GameFAQs guides belong to their authors, so you make your own copy with a converter script from the repo. I built and tested it with Devin Morgan's FAQ and walkthrough. If you want help matching games to guides, the tool at guides.retromodlab.com is the one I use for the other handhelds.
Known limits
- Statues can still split across depth levels in some places. It is much better than before, but not perfect.
- I tuned the terrain on the overworld and early dungeons. Death Mountain and the late dungeons are untested in 3D.
- New 3DS and 2DS hardware is untested for the new bottom screen.
- Stereo needs the Old 3DS GPU path, as above.
Credits
All the hard work of the port is Esteban's: EstebanPdN/zelda-alttp-3ds. It sits on the shoulders of the zelda3 reimplementation by snesrev. The port repository itself has no LICENSE file, which is why this is a pull request to Esteban and not a separate release from me.
The pull request is here: #52. As I write this it is open, with no review comments yet. If you also want a real 3D Hyrule, that is the place to say so.
I also build in-game guides for other handhelds. The 3DS plugin version is in 3DS in-game guides plugin.