11 ms·
Zelda Screen Transitions Are Undefined Behaviour
- daniel5151 7y agoI actually had to wrestle with this exact effect while working on wideNES [1]. By saving a screenshot of the screen at each frame alongside with it's PPUSCROLL value, it's possible to gradually build-up a map of the level as it's explored. Moreover, on subsequent playthroughs of the same level, it's possible to sync the map with the on-screen action, effectively enabling a "widescreen" mode for old NES games (with certain limitations). Lots of games used funky scrolling mechanics, typically to create status bars, but of all the different games I tested with, TLOZ was by-far the weirdest, requiring an entire special case to get working! I don't have any screenshots of my own, but some japanese website recently covered wideNES, posting screenshots of it working with the original Legent of Zelda.[2] [1] http://prilik.com/blog/2018/08/24/wideNES.html http://prilik.com/blog/2018/08/24/wideNES.html [2] https://emulog.net/fc-nes-emulator-anese-how-to-use-widenes/ https://emulog.net/fc-nes-emulator-anese-how-to-use-widenes/
- anon_cow1111 7y ago*Note to mobile/metered internet users: first link contains 30MB+ of gif images, click at own risk.
- Avamander 7y agoI got flashbacks of 2000s with this comment
- OJFord 7y agoWhy isn't there an HTTP request header like 'Accept-Content-Length' to limit maximum response size?
- tenebrisalietum 7y agoSometimes is really expensive for the server to determine the size of the response before actually responding, e.g. some database lookups where it may not be known how many rows are returnable until the lookup is actually done. Then there are situations where response content length is not known, such as streaming over HTTP. Last, if a certain "Accept-Content-Length" became standard, like 8MB, developers (such as those for the ad industry) would just create javascript libraries that would download large files in 8MB chunks and sidestep it.
- soulofmischief 7y agoThat was a great write-up. Thanks for sharing. You could probably run an async loop which slices up painted frames and compares hashes of the slices to find identical slices to anchor and stitch similar frames together, still maintaining separate layers in case a better match is found later on. Something like that should solve for games like SMB.
- klodolph 7y agoThere are a few games that do diagonal scrolling. In general it's very difficult to do well on the NES, and you will likely have to live with some amount of glitching--unless you have extra name table RAM on the cartridge, which is fairly rare. See http://bootgod.dyndns.org:7777/ http://bootgod.dyndns.org:7777/ for a database of the hardware inside each cartridge.
- einr 7y agoThere are a few games that do diagonal scrolling. Paperboy comes to mind. It's smooth and looks good without any noticable glitching, and without using custom chips, too. Not sure how they did it.
- klodolph 7y agoPaperboy draws a bunch of black sprites along the left side of the screen to cover up the glitches. Depending on the game this can be acceptable, but you only have a budget of 8 sprites per scanline and 64 total sprites, and this technique can eat up a lot of that budget. Edit: as sibling comment noted, Paperboy does have custom logic on the cartridge, a 74HC161 4-bit counter. I think this is just used to switch between CHR banks.
- coldpie 7y agoThere's an interesting parallel in Atari 2600 development here. When the screen is being drawn, the program must update the GPU registers in real-time with the progress of the electron beam across the screen. If the program doesn't update these registers quickly enough, graphic glitches will occur. Most games will poll the game state and prep for updating registers during each HBLANK period, but often this would take too long for certain scanlines and you'd end up with short black lines along the left margin. This was a very common issue, you can see it in lots of screenshots here: https://videogamecritic.com/2600tt.htm?e=85998#rev459 https://videogamecritic.com/2600tt.htm?e=85998#rev459 This wasn't a big problem, because TVs of the time often had big overscan areas (areas that were rendered, but covered by the TV's physical bezel). However, it was visible on many TVs, and today it is very visible under emulation. Activision's programmers found this unacceptable. Rather than perform the very difficult, or even impossible, task of making their code run faster than the HBLANK period, they instead chose to render the first cm or so of each scanline intentionally black! Notice the width of the screen in this screenshot compared to other nearby games: https://videogamecritic.com/2600ff.htm#rev203 https://videogamecritic.com/2600ff.htm#rev203 More crazy tricks like this are described in the excellent "Racing the Beam" book by Nick Montfort and Ian Bogost.
- Bluecobra 7y agoThanks for posting this... as a non-programmer, I really enjoy reading how the games I grew up with worked. If you enjoyed reading this, there's a great Youtube channel called Retro Game Mechanics Explained: https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g/videos https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g/vid...
- cableshaft 7y agoI didn't know this channel existed and it's very interesting. Thanks for sharing it.
- coldpie 7y agoThis is a great description of a commonly-used technique for splitting the screen in NES games that scroll smoothly. It may or may not have been intended, but this is a common technique for games that have a "status bar". Super Mario Bros 3 is another obvious example, but even Super Mario Bros uses it long before then for its top status bar. I first read about it in the excellent "I Am Error" book by Nathan Altice, but googling around for "nes sprite zero split" turns up plenty of other articles, too.
- einr 7y agoNitpicking, but SMB3 uses the MMC3 chip which "adds an IRQ timer to allow split screen scrolling without the sacrifice of sprite 0" (Wikipedia) so it does not use this technique. SMB1 actually also does not use the sprite zero split technique because it never scrolls vertically. Its status bar is just a bunch of fixed background tiles.
- coldpie 7y agoAh, didn't know that about the MMC3! Regarding SMB1, I'm quite sure it uses the sprite 0 thing to keep the status bar stationary while the level scrolls smoothly beneath it by setting the scroll register only after when the status bar is done drawing. See more thorough description here: https://retrocomputing.stackexchange.com/questions/1898/how-can-i-create-a-split-scroll-effect-in-an-nes-game https://retrocomputing.stackexchange.com/questions/1898/how-...
- papln 7y agoThe article is confusing. The headline/lede claim is about partial vertical scrolling. The middle is a long detour to partial horizontal scrolling (well documented, including SMB1), and then the end goes back to talk about partial vertical scrolling (Zelda).
- penagwin 7y agoThanks for the great visuals!
- baruchthescribe 7y agoThis reminds me a lot of Mode X which, although a funky 320x240 mode with square pixels built in to standard VGA, only became popular after Michael Abrash popularized it in Dr Dobbs. And then there was the utterly gorgeous mode Q - 256x256 with 256 colors. No muls or shifts - high byte is Y and low byte is X.
- bloopernova 7y agoThat "Graphics Programming Black Book" is available online here: http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919 http://www.drdobbs.com/parallel/graphics-programming-black-b... Mode X or Q reminds me of the amazing Mode 7 SNES graphics used to great smooth effect in F-Zero and many other titles.
- raverbashing 7y agoIt's funny, you get Mode X by not picking a mode "the easy way" (like mode 0x13 for 320x200x256) but by setting the lower level registries in the VGA controller, it's an unofficial mode
- jedberg 7y agoIt feels like programming used to be a much harder job in the past. You not only had to figure out the program logic, but you had to work within very tight hardware constraints. Reading articles like this, or about the Atari and how the code would double as a sprite in pac-man, or how 3D was rendered in Wolfenstein, makes me think one had to be much more clever back then.
- red75prime 7y agoOn the other hand you had all the hardware under your direct control. And right now I'm trying to find why kernel stashed 17MB of RAM, I really need.
- overcast 7y agoHarder to do tasks we take for granted now, sure. But today's games are EXTREMELY complex in comparison. Old games were intentionally made extremely difficult, to counter their simplicity in design. Else you'd be done with the whole game in 15 minutes.
- im_down_w_otp 7y agoYou still have to be clever like that today depending on what kind of problems you're working on. Which was also true back then. Not all programmers back then had to derive arcanely clever tricks to get their job done. There's also a part of it that is underappreciated, which is that sometimes the cool effect wasn't necessarily an original design goal, but instead was sometimes something that was stumbled upon one way or another, and then it was having that little trick in one's pocket which informed how the design would be.
- jdsully 7y agoThere were quite a few “professional” software packages written in BASIC at the time. Of course most software needed assembly in the early days.
- Qwertystop 7y agoOne good example of this: Space Invaders was, AFAIK, the first game to feature escalating difficulty over time (because the aliens speed up the more of them you shoot). This wasn't originally part of the design; the system just couldn't run at the same framerate while managing 30 sprites as it could at 5, and there weren't any enforced timing checks.
- tinus_hn 7y agoWeird to have this limitation that you can’t vertically scroll mid-frame, when it turns out you can if you just circumvent the blockade.
- llao 7y agoWarning, 33 megabytes of (great) GIFs.
- chungy 7y agoIt's probably about time that WebP should get promoted, especially instead of animated GIF. the libwebp library comes with a gif2webp program to make the conversion especially easy. Just doing it now, converting all the animations to WebP makes it 1.6MB. and it works in all current browsers.
- yc-kraln 7y agoI don't think I would call this undefined behavior... the behavior is defined by what happens on the hardware when it's executed! There are many, many classical effects on raster hardware which are accomplished by changing registers within the horizontal blanking period... copper bars, mode 7, certain paralax scrolling. When you're on a resource limited system it becomes an art to get the most out of the platform. Look at the difference between Mario 64 and Conker's Bad Fur Day... or Genji: Days of the Blade (PS3) vs Persona 5 (PS3) Even with modern consoles, there is a marked improvement in the apparent visual quality over the lifetime of the device, as developers learn how to squeeze more and more out of the platform.
- dllthomas 7y ago> developers learn how to squeeze more and more out of the platform That's a part of it, to be sure, but another dynamic is that developers have to squeeze more out of the system. Dropping old techniques on new hardware will probably give you a game that looks "better" than what's already out. Once everyone has done that, to look "better" you need something new other than hardware.
- furyofantares 7y agoThat’s another part of it, to be sure, but yet another dynamic is that it being a mostly fixed system, rather than a wide array of target hardware, is what makes it feasible to implement these tricks and accumulate knowledge in the first place. It all kind of goes hand-in-hand — the fixed nature of the hardware makes it so you have to find these tricks in order to compete with games that play on newer hardware, and also makes it so that it’s possible to do so. I find it fascinating. But I suppose the market would have just found different stabilizing points were this not the case.
- dllthomas 7y agoAgreed.
- papln 7y ago"Unefined" refers to the spec, not the hardware. https://en.wikipedia.org/wiki/Undefined_behavior https://en.wikipedia.org/wiki/Undefined_behavior This case appears to be "undocumented scenario" or "unsupported use-case", though.
- EGreg 7y agometa-irony: "in a manor likely that was unintended by its designers"
- duxup 7y agoIt's always interesting how the NES cartridges had their own hardware that could expand the system's capability. Allowing for simple cartridges for simple games and more expensive cartridges for more advanced games.
- jordanmorgan10 7y agoThe same idea extended to the SNES too if I recall, a quick dig up on Wikipedia: "The system was designed to accommodate the ongoing development of a variety of enhancement chips integrated in game cartridges to be competitive into the next generation."
- duxup 7y agoI wonder if we'll ever get back to that sort of thing... I guess with digital downloads not so much, but i really like the idea.
- jordanmorgan10 7y agoWell with xCloud coming up from Microsoft, and Sony partnering with them on cloud gaming - we appear to be going in the opposite direction, for better or worse.
- toast0 7y agoWe have some sorts of similar things. EyeToy and Kinect were additional hardware added to the system for games; not on the same media as the games though. The difference is expansion hardware today is always going to be subordinate to the main system --- the economics and data transfer realities don't work out to put a polygon processing enhancement in a USB add-on; but the cartridge slot has immense potential and it could also be cheaper to use the base system with enhancements than to release a whole new enhanced system (although, it's not clear to me how much the base genesis/megadrive benefits the 32x)
- whermans 7y agoGoing as far as co-processors for 3D rendering[0] - image buying a game today that comes with its own GPU! [0] https://en.wikipedia.org/wiki/Super_FX https://en.wikipedia.org/wiki/Super_FX
- pubby 7y agoThe NES designers goofed and made the size of the view window (nametable) 240 pixels tall. This makes vertical scrolling awkward as it throws a non-power-of-two divisor into the math. The NES doesn't have a division instruction - only bit shifts, so having to divide by 240 is a real pain! Also, Y-scrolling wasn't completely figured out until late in the NES's life. The register writes needed to do so are very strange, and Zelda certainly doesn't do it correctly!
- simcop2387 7y agoI believe that's one of the reasons that games such as Super Mario Bros 3 used additional hardware in the cartridge to do the y scrolling. The memory mapper had special support for just y scrolling and scanline counting. http://wiki.nesdev.com/w/index.php/MMC3 http://wiki.nesdev.com/w/index.php/MMC3
- pubby 7y agoOh, you don't need special hardware to do y-scrolling correctly. It's just a strange set of writes: $2006, $2005, $2005, $2006. MMC3 is for the scanline counter, which allowed SMB3 to have the score bar on the bottom of the screen.
- kgabis 7y agoThe way this scanline counter was implemented is quite clever. From nesdev wiki (https://wiki.nesdev.com/w/index.php/MMC3 https://wiki.nesdev.com/w/index.php/MMC3): The counter is based on the following trick: whenever rendering is turned on in the PPU, it fetches nametable and BG pattern tiles from dots 0-255 and 320-340 of a scanline and fetches sprite patterns from dots 256-319, even if no sprites are visible. Because of this, if BG uses the left pattern table ($0000), and if sprites always use the right pattern table ($1000), A12 will remain low during all nametable and BG pattern fetches, and high during all sprite pattern fetches, causing it to oscillate exactly one time per scanline and 241 times per frame.
- bonzini 7y agoYou can probably do it without divisions if you use the name table creatively... You can place line 720 of the input at line 192 of the name table (720 modulo 256 is 192) as long as everything above and below it is displayed correctly.
- and0 7y agoVertical scrolling, and emulating the weird side-effects of the registers being written to, was the hardest part of recreating the NES using 3D meshes. It took me a few weekends to get Zelda 2's intro working reliably. I wrote about it a bit myself (probably got a few details wrong or simplified them) here: http://n3s.io/index.php?title=How_It_Works http://n3s.io/index.php?title=How_It_Works
- maaaats 7y agoWhat a cool project!
- msla 7y agoIs anyone else getting a blank white page?
- MobiusHorizons 7y agoUndefined behavior in C or C++ is possible because the language specification is built to deal with different hardware architectures, so it's not possible to build portable code. In the case of something like NES game development, there is only one hardware target, so the actual observed hardware behavior can be relied upon when doing things that aren't explicitly documented. In this case it is possible to know before hand exactly what will happen because there is only one hardware target. Undefined behavior in a language like C is unknowable at compile time because its behavior has not been specified by the language, and it can't be specified by the hardware. Technically I guess you are correct that it is undefined behavior, but in practice it's pretty different IMO.
- codebje 7y agoI'm not sure it's really true that the NES represents a single hardware target. There's two families of CPUs (2A03, 2A07) with different clock speeds depending on whether the device is NTSC or PAL, within each family there's a half dozen or more revisions, DRAM controller chips changed frequently causing many interesting variations in how and when the object attribute memory could be read (or not read, as the case may be). And that's just the NES devices! The Famicoms were different again, there were at least two licensed clones, and dozens of unlicensed clones (if you, eg, wanted your game to sell in Russia, you'd care about being compatible with the Dendy as well as the genuine NES).
- shultays 7y agoIt is not really undefined behavior when you have single hardware that will behave in a very well defined way. Old console games have all sort of hacks that allows them to do stuff that the system is not designed for. Having such a basic hardware with no security checks allows a lot of potential! Also isn't vertical split quite common? I would assume this is something the hardware designera thought of, not a game company figuring it out. They even put stuff like sprite 0 hit bit for this kind of tricks