diff --git a/out/iatheory_scrapbook.pdf b/out/iatheory_scrapbook.pdf index 39fbaebe..fa3b3bd2 100644 Binary files a/out/iatheory_scrapbook.pdf and b/out/iatheory_scrapbook.pdf differ diff --git a/src/archaeo.tex b/src/archaeo.tex index 3265185c..80db90e8 100644 --- a/src/archaeo.tex +++ b/src/archaeo.tex @@ -52,7 +52,7 @@ \chapter{A Little Archaeology} and each long pulse by a pink pixel. Roughly speaking, gray is a shorthand for 0 bits and dark pixels for 1 bits.} \end{figure} -\subsection{The Madness Begins} +\section{The Madness Begins} This is what the start of the our \icode{iridis-alpha.tap} file looks like: @@ -256,7 +256,7 @@ \subsection{The Madness Begins} We have our first byte! It's \icode{89}! -\subsection{After Our First Real Byte} +\section{After Our First Real Byte} With this precious commodity in hand we now continue reading off bytes in the same manner from the tape. Eventually we encounter a signal that tells us we've reached the end of the data block, a 'Long-Short' sequence. When this happens we find we've read 202 bytes in total: @@ -436,7 +436,7 @@ \subsection{After Our First Real Byte} rest of the data from the tape. That's right: we've read all this data from the tape to get a program for reading data from the tape. This type of program is called a 'loader', or perhaps in an effort to justify it's existence, a 'turbo loader'. -\subsection{A Loader for your Loader} +\section{A Loader for your Loader} \begin{figure}[H] { \begin{adjustbox}{width=10cm,center} @@ -665,7 +665,7 @@ \subsection{A Loader for your Loader} }\caption[]{Where the different parts of the game end up in memory.} \end{figure} -\subsection{Putting an End to the Madness} +\section{Putting an End to the Madness} With all the data read in you might wonder how the loader knows what to do next (i.e. to run the game) and how it will know where to start running it from. The answer is given in the \icode{Header Data} for the final chunk of data: diff --git a/src/binary.tex b/src/binary.tex index b67918bb..b1d6e160 100644 --- a/src/binary.tex +++ b/src/binary.tex @@ -1,12 +1,3 @@ -\clearpage -\vspace*{\fill} -\begin{figure}[H] - \centering - \includegraphics[width=5cm]{src/cover/title_page.png}% -\end{figure} -\vspace*{\fill} -\thispagestyle{empty}% - \chapter{We Need to Talk About Binary} \lstset{style=6502Style} diff --git a/src/bonusphase.tex b/src/bonusphase.tex index de10f12c..8c5f6680 100644 --- a/src/bonusphase.tex +++ b/src/bonusphase.tex @@ -5,7 +5,7 @@ \chapter{Congoatulations Hotshot} This decidedly ropey mini-game has a few interesting features. -\subsection{Entry Sequence} +\section{Entry Sequence} \begin{figure}[H] \centering \includegraphics[width=10cm]{src/bonusphase/entry/bonus_entry_example.png}% @@ -120,7 +120,7 @@ \subsection{Entry Sequence} the raster interrupt in this way. Simply painting the screen with colored text would have been much slower. -\subsection{Generating Maps} +\section{Generating Maps} \begin{figure}[H] \centering \includegraphics[width=10cm]{src/bonusphase/bonus_phase.png}% @@ -627,7 +627,7 @@ \subsection{Generating Maps} two lines its writing by using the \icode{scrollLineOffset} variable to determine which one its writing. -\subsubsection{Choosing a Map} +\subsection{Choosing a Map} So now that we understand how the individual rows of the map are generated, the question arises: how do we procedurally generate entire maps? Do we just pick random rows and join them together? This wouldn't work well, since some rows aren't going to go well @@ -759,7 +759,7 @@ \subsubsection{Choosing a Map} -\subsection{Some Very Ugly Sprites} +\section{Some Very Ugly Sprites} For some reason the gilby sprite in the bonus phase is made impossibly ugly. \begin{figure}[H] @@ -843,7 +843,7 @@ \subsection{Some Very Ugly Sprites} }\caption{There is no excuse for this.} \end{figure} -\subsection{IBalls} +\section{IBalls} \begin{figure}[H] { diff --git a/src/bugs.tex b/src/bugs.tex index 6dc9565d..f91b20da 100644 --- a/src/bugs.tex +++ b/src/bugs.tex @@ -2,7 +2,7 @@ \chapter{Iridis Oops!} \label{sec:bugs} \lstset{style=6502Style} -\subsection{The Byte that Broke} +\section{The Byte that Broke} \begin{q}{Jeff Minter's Newsletter 'The Nature of the Beast' August 1986\cite{planner}} We must apologise to some of the earliest purchasers of IA, as well... it seems that some data was corrupted during the production phase of the @@ -60,7 +60,7 @@ \subsection{The Byte that Broke} $C003 8D F8 BF STA $BFF8 \end{lstlisting} -\subsection{Reappearing Enemies} +\section{Reappearing Enemies} When you start a new game, enemies from the previous game show up in the first wave. For most people starting out, this will take the form of a few residual @@ -99,7 +99,7 @@ \subsection{Reappearing Enemies} RTS \end{lstlisting} -\subsection{A Sort of Cheat} +\section{A Sort of Cheat} After a minute or two in the title screen, the game enters 'Attract Mode' and plays a random level on autopilot for a few seconds. If you press F1 during diff --git a/src/bumph.tex b/src/bumph.tex index 13bb5537..75cf7d4b 100644 --- a/src/bumph.tex +++ b/src/bumph.tex @@ -1,6 +1,6 @@ \chapter{Bumph} -\subsection{Cover} +\section{Cover} \begin{figure}[H] { \begin{adjustbox}{width=10cm,center} @@ -17,7 +17,7 @@ \subsection{Cover} }\caption[]{Back Cover} \end{figure} -\subsection{Manual} +\section{Manual} \begin{figure}[H] { diff --git a/src/disassembly.tex b/src/disassembly.tex index 4d0effbd..2510ac14 100644 --- a/src/disassembly.tex +++ b/src/disassembly.tex @@ -179,7 +179,7 @@ \chapter{Some Disassembly Required} STA $0318 ;Non-Maskable Interrupt \end{lstlisting} -\subsubsection{Important Concept Number One: High Bytes and Low Bytes} +\subsection{Important Concept Number One: High Bytes and Low Bytes} On the face of it these four instructions are doing something very simple. They are storing the value \$40 at address \$0319 and the value \$00 at \$0318. What they are actually doing is storing the address \$4000 in a place where the C64's 6502 CPU will be expected to look in a moment's time and take that as a command @@ -227,7 +227,7 @@ \subsubsection{Important Concept Number One: High Bytes and Low Bytes} you otherwise, but hopefully when we look at the use it is put to here you may begin to get a flavor of its utility. Let's do that by looking at our second important concept. -\subsubsection{Important Concept Number Two: Interrupts} +\subsection{Important Concept Number Two: Interrupts} \begin{lstlisting}[caption=It's an interrupt. And it's non-maskable.] LDA #$40 STA $0319 ;Non-Maskable Interrupt diff --git a/src/gfx.tex b/src/gfx.tex index 6f8ffd1d..af38af92 100644 --- a/src/gfx.tex +++ b/src/gfx.tex @@ -51,7 +51,7 @@ \section{Back in the Days}\index{Back in the days!GFX} -\subsection{Pen and Papers} +\section{Pen and Papers} The artistic direction was established by the planner of the game. Their goal was to produce concept art and pose outlines in order to capture the essence of a character, as well as establishing proportions and movements. After that, senior artists took over for fine tuning. \begin{q}{Eri Nakamura\cite{sf2devinterview}} @@ -82,7 +82,7 @@ \subsection{Pen and Papers} -\subsection{Non-square Grid Paper}\label{artists_par} +\section{Non-square Grid Paper}\label{artists_par} To draw both outlines and detailed versions of the sprites, artists used a special paper with a double grid system. There was a "light" grid which used non-square proportions to match the CP-system video aspect ratio of 10:7. Artists were able to draw normally without having to worry about distortion since rectangle elements would match the CPS-1's stretched pixels. @@ -93,7 +93,7 @@ \subsection{Non-square Grid Paper}\label{artists_par} -\subsection{OBJ Allocation} +\section{OBJ Allocation} If breaking free of the rectangular sprites was a blessing for the artists, it was a problem for Capcom project managers. In an era where ROM chips were very expensive, a game was allocated a ROM budget at its beginning which it could not be exceeded. @@ -152,7 +152,7 @@ \subsection{OBJ Allocation} As the project progressed, the team scraped the bottom of the barrel and started to allocate space on a per-tile basis. They sometimes spread a character pose across multiple sheets, like in Dhalsim's sheet where portions of Blanka can be found. -\subsection{The Sheet System} +\section{The Sheet System} Besides sparsely describing it, Capcom employees never elaborated on the sheet system. For which title and for how long it was used in total are questions that were never answered. Thanks to an understanding of the GFXROM format, it is possible to peek back in time. The digital structure is an imprint of what the paper sheet looked like. These reconstructed sheets can provide answers. @@ -176,7 +176,7 @@ \subsection{The Sheet System} \img{smc-70_ad.jpg} -\subsection{Digitizing Art}\index{Computers!SONY SMC-70} +\section{Digitizing Art}\index{Computers!SONY SMC-70} To digitize their drawings, Capcom employees used SMC-70 computers. Manufactured by Sony, the SMC-70 hit both the US and Japan market in the end of 1982. What is particularly noteworthy about this machine is that it is built around extensibility. @@ -192,7 +192,7 @@ \subsection{Digitizing Art}\index{Computers!SONY SMC-70} \caption*{A SMC-70 extended with a SMI-7012. Power supply at the very back} \end{figure} -\subsubsection{Sony, the big iron} +\subsection{Sony, the big iron} On one hand, the substantial list of extensions and peripherals, totaling nearly 40 pieces all made by Sony, is a testament to the company's commitment. On the other hand, it also embodies a desire to remain in control of the platform by keeping other manufacturers from contributing to the eco-system. \begin{figure}[H] @@ -223,7 +223,7 @@ \subsubsection{Sony, the big iron} \end{figure} -\subsubsection{Noteworthy capabilities} +\subsection{Noteworthy capabilities} The SMC-70 is notable for being the first computer to allow a 3.5" floppy reader (also invented by Sony in 1981) and its ability to display kanji characters via a ROM extension. However, it is really when it comes to graphic capabilities that the machine stood out. Four resolutions were available, ranging from low-resolution 320x200 using sixteen colors up to high-resolution 640x200 in two colors. @@ -231,7 +231,7 @@ \subsubsection{Noteworthy capabilities} The 16 colors mode was particularly interesting to Capcom artists since it was a perfect match to the CPS-1 pen system. -\subsection{Tiny Character Editor} +\section{Tiny Character Editor} The SMC-70 had no ability to use a scanner. The digitization process was entirely achieved by hand. To help them in their task, artists used a tool called TCE (Tiny Character Editor). Although no screenshot ever emerged, Capcom employees gave a rough description of its minimalist approach. @@ -240,7 +240,7 @@ \subsection{Tiny Character Editor} \end{q} -\subsection{Dotting} +\section{Dotting} For both SCROLL and OBJ elements, dotting was done on a tile basis. The artist's task was to look at their detailed graph paper drawing and decide, for each rectangular element in the tile, which color of the palette to use for it. Pixel-art was a tedious and repetitive process which required a sense of aesthetic creativity to deal with the cases where a line crossed a pixel. Drop the pixel, include it plain, or attempt to anti-alias with a color in the palette were difficult choices to make. @@ -269,7 +269,7 @@ \subsection{Dotting} \end{q} -\subsection{Saving Tiles} +\section{Saving Tiles} Artists attempted to reuse tiles as much as possible to reduce usage of the scarce ROM space available. In Street Fighter 2, there was only enough GFXROM for eleven challengers. Ken is a patchwork and a palette swap on top of Ryu tiles base. It "weighs" only 98,304 bytes. A remarkable achievement compared to characters such as Zangief (622,592 bytes), Honda (491,520 bytes), or Ryu (442,368 bytes). \begin{minipage}[t]{0.19\linewidth} @@ -336,7 +336,7 @@ \subsection{Saving Tiles} \pagebreak -\subsection{Team Structure and Culture} +\section{Team Structure and Culture} The art team had a strong hierarchy based on skills and seniority. @@ -352,7 +352,7 @@ \subsection{Team Structure and Culture} As layered as they were, operations were not set in stone and employees could climb the ladder quickly. Akiman was hired on "Dyn Side Arms" in 1986 as a SCROLL artist, the bottom of the artist ladder. Two years later, he was a Planner on Forgotten Worlds and went on to work on Final Fight and Street Fighter 2 in the same capacity. -\subsubsection{Work Ethic} +\subsection{Work Ethic} A strong working culture was established from the very top. @@ -366,7 +366,7 @@ \subsubsection{Work Ethic} By the way, even now that I'm freelance, I still sleep under my computer desk at home. \end{q} -\subsubsection{Poaching} +\subsection{Poaching} Retaining talent was a top priority. The credit screen of Street Fighter II illustrates Capcom's cautiousness. Artists were only credited by their nicknames. @@ -393,7 +393,7 @@ \subsubsection{Poaching} -\subsection{Inspiration} +\section{Inspiration} For Street Fighter II, artists' inspiration came from various outlets. Mangas such as "Yasunori Katō" helped to give birth to Dictator while Tao from "Harmagedon: Genma Wars" was part of the genesis of Chun-Li. @@ -446,7 +446,7 @@ \section{Shapes and Sprites} \end{figure} -\subsection{Sprite} +\section{Sprite} A sprite is a collection of tiles with rectangular boundaries. As we will see in the m68k programming section it can be rendered by issuing a single draw call mentioning the offset in the sheet, the width in tiles and the height in tiles. \begin{figure}[H] @@ -458,7 +458,7 @@ \subsection{Sprite} Another limitation (or advantage depending on how you look at it) is that a single palette is specified when placing the sprite draw command so all tiles must use it. -\subsection{Shape} +\section{Shape} A much more efficient and flexible method is to use a Shape where tile layout can be arbitrary. It takes several draw calls to draw (tiles have to be specified one by one) but they can be located anywhere in a GFXROM. diff --git a/src/hardware.tex b/src/hardware.tex index 8563c70b..cfa0c265 100644 --- a/src/hardware.tex +++ b/src/hardware.tex @@ -116,7 +116,7 @@ \section{Physical Architecture} The system was revised over the years. Approximately 229 variations are known to exist, including bootlegs\cite{mame_cps1_video}. The board which will be studied in this book is the one used to run "Street Fighter 2": board A "88617A-7B", board B "90629B", and board C "90628-C". -\subsection{Board A}\index{Board!Board A} +\section{Board A}\index{Board!Board A} Board "A" is the platform that never changes between games. It features all but one of the chips in charge of processing data, whether it is game logic, audio, or video. A summary look at page \pageref{fig:boarda} reveals the powerhouse of the whole system. Even an untrained eye will notice the size of the \textbf{A}pplication-\textbf{S}pecific \textbf{I}ntegrated \textbf{C}ircuit (ASIC) and the sheer number of bus lines leading to it. In the center left stands the "CPS-A", in charge of 50\% of the graphic system and its 16MHz oscillator. Just above is 384 KiB of VRAM to store a special kind of framebuffer studied in later pages. @@ -141,7 +141,7 @@ \subsection{Board A}\index{Board!Board A} \sdraw{0.94}{88617A} \label{fig:drawboarda} -\subsection{Board B}\index{Board!Board B} +\section{Board B}\index{Board!Board B} Board B is where the ROM chips containing all the assets and instructions specific to a game are attached via DIP sockets. The chips are not soldered but push-in mounted (and easily removable). Even though all ROM chips are located on the same board, they are not all part of an unified data system on an unified bus. @@ -178,7 +178,7 @@ \subsection{Board B}\index{Board!Board B} Observant readers will have noticed unexplained black chips. For now we'll say they are in charge of bus traffic management. In the drawing above, \icode{STF29} handles the GFX ROM and \icode{IOB1} handles the m68k ROM. As an exercise, go back to page \pageref{fig:drawboarda} and guess which chip handles which ROM/RAM group. Or don't, I am just a book. -\subsection{Board C}\index{Board!Board C} +\section{Board C}\index{Board!Board C} Board "C" hosts the "CPS-B" ASIC video chip. It is in charge of the remaining 50\% of the graphic pipeline, namely mixing data from the VRAM and the GFX ROMs towards the pixel generator. Capcom also concentrated its anti-piracy measures in this chip and as a result revised board "C" many more times than board A and board B. This will be discussed extensively in the copy-protection section of this chapter. @@ -193,7 +193,7 @@ \subsection{Board C}\index{Board!Board C} -\subsection{PALs} +\section{PALs} The black chips on the drawing are called \textbf{P}rogrammable \textbf{A}rray \textbf{L}ogic (PAL). They play a crucial role in the creation of the memory maps. They pack boolean logic (\&, \textbar, !) between their input and output lines which simplifies the board, allows tuning the logic without changing the PCB hardware lines, and reduces the number of components. @@ -236,7 +236,7 @@ \section{Control System}\index{Systems!Control} The control system oversees the platform. As a ruler it needs not to excel at a specific task but to be able to direct and keep tabs on many components. This is a task tailor-made for the Motorola 68000. -\subsection{Motorola 68000 CPU}\index{Processors!Motorola 68000} +\section{Motorola 68000 CPU}\index{Processors!Motorola 68000} Released in 1979 and clocked at 10 MHz (later upgraded to 12 MHz), the 68000 with its two stage pipeline\cite{M68000fv} (prefetch, exec) and no internal cache was not a particularly powerful chip by late 80s standards. Its 1.7 MIPS placed it on par with an Intel 286 10MHz (1.5 MIPS). By 1989 it was already two generations old behind the 1984 M68020 (3 MIPS) and the 1987 M68030 (5 MIPS)\cite{mips}. @@ -291,7 +291,7 @@ \subsection{Motorola 68000 CPU}\index{Processors!Motorola 68000} Perhaps the best testament to the quality of the 68000 design is that as of 2022, 43 years after its release, Motorola's immortal CPU is still in production. -\subsection{Motorola 68000 "work" RAM} +\section{Motorola 68000 "work" RAM} With 16-bit data bus processors it would be fair to expect a memory system built with 16-bit RAM chips. However these were expensive and a closer look reveals a bunch of \icode{65256BLSP-10} offering fast access time (100ns SRAM) and 32 KiB capacity but only 8 data lines. \sdraw{0.5}{65256BLSP-10} @@ -328,7 +328,7 @@ \subsection{Motorola 68000 "work" RAM} -\subsection{Motorola 68000 Program ROM} +\section{Motorola 68000 Program ROM} The 68000 instructions are provided by eight \icode{27C010} which are 128 Ki $\times$ 8-bit chips. They work like the \icode{65256BLSP-10} except that they have sixteen address lines instead of fifteen (and therefore higher capacity). @@ -354,7 +354,7 @@ \subsection{Motorola 68000 Program ROM} By now, it should be abundantly clear that the \icode{CE} / \icode{CS} lines are absolutely crucial to build a memory map. Even though they won't be mentioned again, keep in mind they impact every chip on the boards (except the CPUs). -\subsection{68000 Memory Map} +\section{68000 Memory Map} Thanks to the PAL chips enabling/disabling components, the 68000's memory space is partitioned. The result is summarized in a "memory map". @@ -384,7 +384,7 @@ \subsection{68000 Memory Map} }\caption*{Control system memory map} \end{figure} \label{m68k_mm} -\subsection{Putting it All Together} +\section{Putting it All Together} The details of the 68000's operations will be studied in-depth in the next chapters but we can already guess how the CPU operates based on what it can access. As the m68k boots, it starts to retrieve instructions from its ROM. For regular operations such as store/load, and also to keep track of its call stack, it uses its work RAM. @@ -413,7 +413,7 @@ \section{Audio System}\index{Systems!Audio} The component in charge is a surprisingly lightweight z80 running at 3.58 MHz. -\subsection{z80 CPU} +\section{z80 CPU} Released in July 1976 by Zilog, the z80 was intended as an Intel 8080 killer thanks to a compatible instruction set. It ended up becoming an icon of the 70s, sharing the scene with the equally legendary MOS 6502 well into the mid-80s. The z80 was widely used in home computers, notably featured in the Sinclair ZX Spectrum and the Amstrad CPC. It also found its way into military applications, musical equipment (Roland Jupiter-8), embedded systems, and multiple coin-op arcades. @@ -450,10 +450,10 @@ \subsection{z80 CPU} \pagebreak -\subsection{z80 Work RAM} +\section{z80 Work RAM} The amount of RAM provided to the z80 may appear scandalously small by today's standards. However because all it has to do is forward requests from the latches to the MSM6295 and feed the YM2151 music notes, the z80 needs few resources. Its bus is connected to a single 2Ki $\times$ 8-bit \icode{CXK5816SP} chip. -\subsection{z80 ROM} +\section{z80 ROM} The ROM is made of a simple 64Ki $\times$ 8-bit \icode{27C512} chip. It is much larger than the RAM in order to store YM2151 instructions alongside the z80 instructions. @@ -464,7 +464,7 @@ \subsection{z80 ROM} Hopefully the thought of this awful bank switch control register will leave no doubt with regards to the awesomeness of the m68k and its 24-bit flat addressing system. -\subsection{z80 Memory Map} +\section{z80 Memory Map} \begin{figure}[H] { @@ -491,7 +491,7 @@ \subsection{z80 Memory Map} -\subsection{YM2151}\index{Processors!Yamaha 2151} +\section{YM2151}\index{Processors!Yamaha 2151} Selecting the music chip was not a matter of shopping between vendors but rather picking one from Yamaha. Thanks to the licensing of Frequency Modulation (FM) patents from Stanford in 1975, the Japanese founder ruled the world of electronic music. @@ -554,14 +554,14 @@ \subsection{YM2151}\index{Processors!Yamaha 2151} The only drawback of this chip is that it does not feature a DAC (Digital to Analog Converter). It generates a signal on the Serial Output (\icode{SO}). -\subsection{YM3012}\index{Processors!Yamaha 3012} +\section{YM3012}\index{Processors!Yamaha 3012} The YM3012 is a DAC connected to the YM2151 digital output \icode{SO}. The analog signal it outputs on \icode{CH1} and \icode{CH2} is mixed with the signal from the OKI6295 towards JAMMA. \sdraw{0.95}{YM3012} -\subsection{MSM6295}\index{Processors!OKI MSM6295} +\section{MSM6295}\index{Processors!OKI MSM6295} For audio sample playback, Capcom spared no expense and selected a chip capable of 4-bit ADPCM audio decompression over four channels, the MSM6295 (a.k.a OKI). % capable chips by the past with the MSM5205 by OKI Semiconductor. For the CPS-1 they went with a steroids version, @@ -579,7 +579,7 @@ \subsection{MSM6295}\index{Processors!OKI MSM6295} ADPCM lossy compression is able to divide space consumption by three by converting 12-bit PCM samples into 4-bit nibbles. -\subsubsection{Making choices} +\subsection{Making choices} While the choice of the Yamaha music chip left little ambiguity to the hardware designer, the MSM6295 was a different story. First, the sampling rate expected in ROM is directly correlated to the clock rate of the MSM6295. Second, the OKI can operate in two modes via its \icode{SS} pin. In high quality (H), the divisor is 132 and in low quality (L) the divisor is 165. @@ -611,7 +611,7 @@ \subsubsection{Making choices} -\subsection{PCM 101} +\section{PCM 101} \index{ADPCM!Decompression} The MSM6295 input and output are respectively ADPCM and PCM streams. To deepen our understanding of the chip requires studying how \textbf{P}ulse-\textbf{C}ode \textbf{M}odulation works. @@ -647,7 +647,7 @@ \subsection{PCM 101} -\subsection{ADPCM Compression} +\section{ADPCM Compression} ADPCM is able to take 12-bit PCM samples and compress then as 4-bit nibbles by encoding only the difference between PCM samples. Decompressing an ADPCM stream consists of adding a delta value to the last decompressed sample, over and over again. The delta is encoded with a system of weighted offsets called "step", which is accurate for small variations but coarser when deltas increase. @@ -697,7 +697,7 @@ \section{Video System}\index{Systems!Video} \end{trivia} -\subsection{CRT 101} +\section{CRT 101} Because the timing of operations is propagated deep in the GFX system, it is important to understand how a CRT works. @@ -731,7 +731,7 @@ \subsection{CRT 101} With this duality of lines and signals, a CRT is both a digital and an analog system. The number of scanlines is finite (i.e: there is a set number of these elements) but there is no horizontal number of "dots", "points", or "pixels" since the three color intensity signals are analog. -\subsection{Syncing} +\section{Syncing} The RGB signals describe lines to be drawn but the CRT needs to know where to draw them. The control signal allows synchronization of the cannon orientation with the lines' color signal so they are rasterized where they should. Without syncing, the image appears distorted. \begin{figure}[H] @@ -748,7 +748,7 @@ \subsection{Syncing} HSYNC signal tells the CRT that a line has been drawn and the gun's horizontal position should be reset to the left of the screen. This motion is called horizontal retrace. Like the VBLANK, there is a HBLANK timespan. \pagebreak -\subsection{Fields} +\section{Fields} The process of drawing scanlines over the screen, also called "raster scan", is incomplete as described. If the gun draws a line and upon HSYNC goes back to the left, it would be drawing the same upper left line over and over again. @@ -784,7 +784,7 @@ \subsection{Fields} -\subsection{Making Choices} +\section{Making Choices} To craft a video system means building a signal generator and a color generator. We'll study the signal generator first. This circuit is built to take an oscillator ticks as input and to output three signals. One signal tells for how long the color generator should hold a color on the color lines, one signal triggers HSYNC, and one signal triggers VSYNC. @@ -836,7 +836,7 @@ \subsection{Making Choices} Keep in mind that these resolutions are not what programmers can count on. Because of overhead discussed in the next section, some lines and dots are unavailable. The resolutions presented here are called "overscan resolutions". -\subsubsection{Capcom video signal choices} +\subsection{Capcom video signal choices} The CPS-1 uses an overscan resolution of \icode{512x262}. The dot-clock is 8 Mhz which is obtained by halving the CPS-A/CPS-B 16 MHz clock (it spares an oscillator chip). @@ -859,7 +859,7 @@ \subsubsection{Capcom video signal choices} Besides these vertical and horizontal frequency "rules", Capcom engineers had additional constraints. Because the graphic system works with tiles (which we will study in the next section) using sizes of 8, 16, or 32 pens, both axis dimensions had to be multiples of eight. -\subsubsection{Blanking} +\subsection{Blanking} The CP-System overscan resolution of \icode{512x262} seems to indicate a very high resolution for the time. But not all lines and dots on a line can be used, some have to be sacrificed to solve three problems. @@ -872,7 +872,7 @@ \subsubsection{Blanking} The solution to these three problems is named blanking. By setting the color signals to zero, the cannon shoots no electrons. Blanking hides artifacts and create a window of time where the video system is inactive. There is a vertical blanking called VBLANK and an horizontal blanking called HBLANK. -\subsubsection{Capcom's second set of video signal choices} +\subsection{Capcom's second set of video signal choices} Out of the 262 total lines available, Capcom decided to use 224 and let VBLANK last for $\mathtt{262 - 224 = 38}$ lines. They used 384 dots per line out of 512 total leaving $\mathtt{512 - 384 = 128}$ dots to HBLANK. Developers can count on a resolution of \icode{384x224}. @@ -894,7 +894,7 @@ \subsubsection{Capcom's second set of video signal choices} \pagebreak -\subsubsection{Pixel Aspect Ratio} +\subsection{Pixel Aspect Ratio} The scanlines of a CRT have a fixed height but the width of the dots vary from machine to machine because of their dot-clock. The width/height dot ratio is called the Pixel Aspect Ratio (PAR). @@ -998,7 +998,7 @@ \subsubsection{Pixel Aspect Ratio} -\subsection{Color Space} \index{Colors!Space} +\section{Color Space} \index{Colors!Space} Before moving to the color generator, a characteristic to decide on was the color depth. The CPS-1 uses 16 bits to encode colors with 4 bits per RGB component for a total of 12 bits allowing 4,096 colors. @@ -1022,7 +1022,7 @@ \subsection{Color Space} \index{Colors!Space} \caption*{All darker shades of red using a \icode{\{0xF,0x0, 0x0\}} base.} \end{figure} -\subsection{Putting it All Together} +\section{Putting it All Together} Knowing how a CRT works and what decisions Capcom engineers made, we can now understand the video signal timings. @@ -1049,7 +1049,7 @@ \subsection{Putting it All Together} \end{figure} -\subsection{Color Generator} +\section{Color Generator} To generate color signals, the CPS-1 uses a palette system storing colors via 4 $\times$ 2Ki $\times$ 1B \icode{CXK5814P-35L} SRAM chips. @@ -1148,14 +1148,14 @@ \section{Graphic System}\index{Systems!Graphics} \end{figure} -\subsection{CPS-A and CPS-B: The ASICs powerhouse}\index{Processors!CPS-A}\index{Processors!CPS-B} +\section{CPS-A and CPS-B: The ASICs powerhouse}\index{Processors!CPS-A}\index{Processors!CPS-B} To build their rendering pipeline, Capcom did not rely on another company's product. They crafted their own \textbf{A}pplication-\textbf{S}pecific \textbf{I}ntegrated \textbf{C}ircuit (ASIC), tailored to their needs, the CPS-A (the brain) and CPS-B (the legs). -\subsection{Pens and Inks} +\section{Pens and Inks} The elementary unit of work is a 4-bit value which is an index into a 16 colors palette. Everything, from backgrounds to sprites, uses these 4-bit nibble indexes. A good analogy, and the terminology used in this book, is to picture the GFX manipulating "pens" (palette indexes). The color to appear on the screen is decided not by the pen but by the value at this index, which is called "ink". This division makes the GFX system unaware of the color that will appear to players on the CRT since it only manipulates pens. @@ -1173,11 +1173,11 @@ \subsection{Pens and Inks} -\subsection{Elements of drawing} +\section{Elements of drawing} Games are made of backgrounds on top of which are drawn sprites. The easiest to implement are the background circuits. They are studied first, followed by the sprite circuits. -\subsection{Drawing background} +\section{Drawing background} A background is described in terms of "tiles", whose arrangement is described in a map. The goal of the circuit is to "rasterize" the map of tiles (called "tilemap"). @@ -1191,14 +1191,14 @@ \subsection{Drawing background} Even though the machine uses the fastest type of memory (SRAM), its response time does not permit enough roundtrips. This problem is solved via caching, streaming, channeling, and a humongous (for the time) 32-bit GFXROM/CPS-B local data bus. -\subsubsection{Caching} +\subsection{Caching} The CPS-A only accesses the GFXRAM during the HBLANK interval. To eliminate memory read operations while a scanline is rasterized, a line's worth of tilemap is retrieved and stored in an internal cache of 256 entries. Each entry stores 16-bit tileID + 10-bit attributes. Notice the two parts on the die storing respectively 10 bits and 16 bits. -\subsubsection{Streaming} +\subsection{Streaming} Pen values are streamed from GFXROM to the CRT without intermediate storage. The GFXROM data is retrieved eight pens at a time thanks to a 32-bit data bus. The system works with the GFXROM address lines connected to the CPS-A (with intermediate PAL decoding). The data lines are connected to the CPS-B where pen values are selected/discarded before being sent to the video system. @@ -1208,7 +1208,7 @@ \subsubsection{Streaming} \end{figure}% -\subsubsection{Channels} +\subsection{Channels} To further improve response time, the GFXROM data uses a layout where 8 consecutive bytes are interleaved 16 bits at a time across four chips. Upon reading, an address is issued to two chips at the same time, but their data lines are enabled consecutively. Channeling avoids one "fetch time" every two reads. @@ -1216,7 +1216,7 @@ \subsubsection{Channels} \nbdraw{channels} -\subsection{CPS1 Tilemaps} +\section{CPS1 Tilemaps} The CPS-1 features three tilemap layers named SCROLL1, SCROLL2, and SCROLL3. They all rely on tilemaps made of 64x64 tiles. @@ -1247,7 +1247,7 @@ \subsection{CPS1 Tilemaps} \pagebreak -\subsubsection{Starfields} +\subsection{Starfields} Besides SCROLLs, the CPS-1 has two "STARfield" layers which are always behind the SCROLLs and always in order STAR1 then STAR2. Like the other layers, one full page of 32 palettes is available to each of them. To render the stars, the GFXROM contains no tiles but instead bytecode dictating the position of points as well as palette cycling timing. @@ -1267,7 +1267,7 @@ \subsubsection{Starfields} \end{figure}% \pagebreak -\subsubsection{Noir Black} +\subsection{Noir Black} @@ -1298,7 +1298,7 @@ \subsubsection{Noir Black} -\subsubsection{Draw order and Priority mask}\label{finalfight_trick} +\subsection{Draw order and Priority mask}\label{finalfight_trick} The drawing order (also called "priority") of SCROLLs and the sprite layer are entirely configurable (excluding the STARs which must remain behind). Any order can be requested but there is an extra feature available to the SCROLL drawn just behind the sprite layer. @@ -1350,7 +1350,7 @@ \subsubsection{Draw order and Priority mask}\label{finalfight_trick} \end{figure}% \pagebreak -\subsubsection{Rowscrolling} +\subsection{Rowscrolling} SCROLL 2 has the ability to horizontally offset rows based on their vertical position. This capability, commonly known as "rowscroll", is implemented via a table of 1024 10-bit integers (one for each line) in GFXRAM. @@ -1368,7 +1368,7 @@ \subsubsection{Rowscrolling} \end{figure}% \pagebreak -\subsubsection{Choosing features} +\subsection{Choosing features} The starfield and rowscroll features are good examples of how difficult it is to design hardware. Doing it well consists of accurately predicting what will be useful and what won't. @@ -1393,7 +1393,7 @@ \subsubsection{Choosing features} -\subsubsection{Pushing the Limits} +\subsection{Pushing the Limits} Besides priority mask, tiles can be flipped horizontally and/or vertically but there is no scaling or rotation. Moreover, the CPU has no access to the VRAM which forbids pixel "plotting". That did not prevent seemingly impossible effects from being achieved. @@ -1418,7 +1418,7 @@ \subsubsection{Pushing the Limits} To add rainfall, developers leveraged temporal blending on the same layer as the GUI.\label{gg_rain} Every five frames the GUI is not drawn. Instead a full screen of rain tiles is rendered, resulting in a convincing effect. Temporal blending is often used to fake translucency. -\subsubsection{Plotting Pixels} +\subsection{Plotting Pixels} The introduction sequence of the shoot'em up Carrier Air Wing (page \pageref{caw_color} and \pageref{caw_rgb}) is even more impressive. As a F-14 Tomcat takes off from its carrier, the jet leaves in its trail an exhaust that expands vertically one pixel line at a time. The gaze then disperses with a fizzlefade effect. @@ -1459,12 +1459,12 @@ \subsubsection{Plotting Pixels} \pagebreak -\subsection{Drawing Sprites} +\section{Drawing Sprites} Drawing sprites is more difficult than drawing tilemaps. It involves solving the same problems of bandwidth and latency, only sprites can appear anywhere on the screen and are not aligned on a grid. In order to fully appreciate how Capcom solved this problem, it is worth understanding how other platforms tackled it. -\subsubsection{Hardware sprites} +\subsection{Hardware sprites} A sprite circuit can be implemented using the same logic as a tilemap. It is a special case where the map features a single tile and no horizontal or vertical scrolling is allowed. Every HSYNC, the GFXRAM is read to know if a sprite appears on the next scanline. If it does, the circuit makes sure to intercept tilemap pens to issue sprite pens instead. @@ -1479,7 +1479,7 @@ \subsubsection{Hardware sprites} Likewise, by using built-in multiplexing, the Commodore Amiga placed an horizontal limit of 8 pixels for its sprites' width but allowed unlimited height.\index{Sprites Multiplexing!Amiga} -\subsubsection{Line buffer} +\subsection{Line buffer} To scale better and increase the number of sprites supported, hardware designers introduced the concept of line buffers. A line buffer system requires a buffer as wide as a visible line on the CRT. The buffer is populated with pen codes by a Pixel Processing Unit. The number of sprites, scale and rotation capabilities depends on how much work the PPU is able to do. @@ -1495,7 +1495,7 @@ \subsubsection{Line buffer} -\subsubsection{Double Line buffer} +\subsection{Double Line buffer} A straight forward way to make a GFX more powerful is to simply give it more time to do its jobs. The merciless pixel clock cannot be cheated but the pipeline can be made deeper. By using two line buffers alternately, the GFX pipeline is made deeper which increases its latency but also frees itself from rendering only during HBLANK. While a line buffer is fed to the video, another one is rendered. This allows drawing during one full scanline (64$\mu$s) and a GFX four times more capable than one using a single line buffer. @@ -1505,20 +1505,20 @@ \subsubsection{Double Line buffer} This technique is so powerful that the entire Neo-Geo rendering pipeline revolves around its double line buffer system. It needs no tilemap system. -\subsubsection{CPS1 Sprite FrameBuffer} +\subsection{CPS1 Sprite FrameBuffer} Capcom engineers wanted something even more powerful than a double line buffer. To allow more time than the 64$\mu$s granted by a double line buffer, the CPS-1 was built around a double sprite framebuffer (the same technology as Sega Super Scaler). To host these framebuffers, the machine uses a dedicated memory called VRAM. With a double sprite framebuffer, the PPU does not just draw a line in advance but a whole screen. This technique averages 16\% more time per line for the graphic chip to do its work, and more importantly it allows any number of tiles per line (even the powerful Neo-Geo has a limit of 96 tiles per line). The gain is massive but it comes with three drawbacks. -\subsubsection{Price tag} +\subsection{Price tag} First, the price of the machine goes up since it requires much more buffering capacity. At the resolution of 384$\times$224, 9 bits per pixel are stored (5-bit palette index + 4-bit color index) requiring 200 KiB of storage for two framebuffers. -\subsubsection{Bandwidth requirements} +\subsection{Bandwidth requirements} The second impact is on the bus. A massive amount of data is now written and read to/from the VRAM. It requires so much bandwidth that an especially large data bus connecting the GFX pipeline and the VRAM must be designed. -\subsubsection{De-synchronization} +\subsection{De-synchronization} Lastly, there is the problem of tilemap and sprite synchronization. When the m68k writes a layout in the GFXRAM, the graphic system picks it up but routes background tiles and sprite tiles to different locations. The tilemap is rasterized directly towards the video system while the sprite layer is rendered to the VRAM framebuffer where it will be picked up on the next frame. @@ -1552,7 +1552,7 @@ \subsubsection{De-synchronization} -\subsubsection{CPS1 Sprites Tile} +\subsection{CPS1 Sprites Tile} With its architecture based on a double sprite framebuffer, Capcom built a powerful system able to move an immense volume of sprites. But performance was only one part of the equation. They also had to come up with a flexible way for artists to use it. Up to that point, frustration arose from sprite dimensions (all sprites had to have the same sizes), shapes (mandatory rectangular), and colors (one palette per sprite). @@ -1607,7 +1607,7 @@ \subsubsection{CPS1 Sprites Tile} \pagebreak -\subsection{OBJ Limitations} +\section{OBJ Limitations} The sprite system has a hard limit of 256 tiles per frame. This is not an arbitrary number since the constraint is dictated by how many tiles the system is able to read from the GFXROM and write to the VRAM during a full CRT raster scan (16.7ms). Because OBJ tiles are the most versatile (they can be placed independently and anywhere on the screen), it was tempting to use them often. @@ -1640,7 +1640,7 @@ \subsection{OBJ Limitations} -\subsubsection{Going Too Far} \label{going_too_far} +\subsection{Going Too Far} \label{going_too_far} Games were tested to ensure the OBJ budget was not exceed but Final Fight's last level (Bay Area) managed to ship with that very problem. When the heroes encounter an unprecedented level of opposition, the list of sprites is as follows\cite{ffoverload}. \begin{itemize}[topsep=0pt] @@ -1828,7 +1828,7 @@ \subsubsection{Going Too Far} \label{going_too_far} -\subsubsection{The World Warrier} +\subsection{The World Warrier} The OBJ system was used in a creative way by Akiman to solve a show-stopper bug when he was working as a planner for Street Fighter 2. \begin{q}{Akiman} @@ -1916,7 +1916,7 @@ \subsubsection{The World Warrier} % Sometimes, in order to ship, you need to be pragmatic. -\subsection{Putting it All Together} +\section{Putting it All Together} We now have enough knowledge to fully understand how the CPS-A and CPS-B cooperate to render graphics. @@ -1950,7 +1950,7 @@ \subsection{Putting it All Together} -\subsubsection{VRAM} +\subsection{VRAM} The VRAM system is physically split via two independent blocks, A and B, to facilitate sprite buffer double buffering. This component also benefits from an exceptionally powerful chip compared to the rest of the machine. A quick glance at the \icode{HM53461P} shows the usual \icode{+5V}, \icode{GND}, \icode{CLK}, and address/data pins. However \icode{SD0}, \icode{SD1}, \icode{SD2}, and \icode{SD3} indicate this chip does more than the ones we have seen so far. @@ -1980,7 +1980,7 @@ \subsubsection{VRAM} % \end{trivia} -\subsubsection{GFX ROM} +\subsection{GFX ROM} To keep up with the much higher storage requirements, the GFX ROM system is not designed like the others. While other chips on the board-B are \icode{27C010} and \icode{27C512}, the GFXROM is made of \icode{MB834200B} (256 Ki $\times$ 16-bit). This type of ROM has a much higher capacity but also a slower access time (150ns). @@ -2027,7 +2027,7 @@ \section{Copy Protection System} \caption*{Capcom's disclaimer when a CPS-1 game boots} \end{figure} -\subsection{The Ever Changing CPS-B} +\section{The Ever Changing CPS-B} The heart of the protection system is the CPS-B. The core idea is to make it behave differently depending on the game it is supposed to run. To this effect, twenty-five versions the CPS-B exist\cite{mame_cps1_video}, sometimes differing between revision of the same game\cite{cpsBNumbers}. @@ -2103,22 +2103,22 @@ \subsection{The Ever Changing CPS-B} \end{figure} -\subsection{ID Check} +\section{ID Check} The simplest copy protection available is the chip ID check. By polling a register, the m68k prompts the CPS-B to return its version number. A version match lets the code know if it is running on the right PCB and resets the CPU if it isn't. To make instructions patching of the 68000 ROMs more difficult, calls to verify the chip ID are placed in several locations in the code. Motivated programmers tried anyway\cite{strider_conversion}! -\subsection{Multiplication Check} +\section{Multiplication Check} Starting with CPS-B v21, a slightly more robust feature gave the CPS-B the ability to perform multiplications. Two registers are written and a third can be read. The 68000 code checks that the returned multiplication result is the expected value. -\subsection{Moving Registers} +\section{Moving Registers} The CPS-B registers move between revisions. The offset and range do not change, but the offset of each register inside that mapping is different. Accessing the scroll control, scroll priority, and palette upload registers is done slightly differently for each game. Additionally, the meaning of each bit field inside each register is altered between versions. -\subsection{Unexpected Behavior Detection} +\section{Unexpected Behavior Detection} Protections described so far involved active software and passive hardware. The hardware can also actively monitor the software by leveraging the moving register policy. If the CPS-B detects incoherent values written to the wrong registers, it sets and locks all palettes of all layers to black. The game still runs in the background and the audio is played but the screen doesn't display anything. The only way to recover is to reboot the machine\cite{petitSecurity}... only for the screen to turn black again. @@ -2128,7 +2128,7 @@ \subsection{Unexpected Behavior Detection} -\subsection{Invalid Offset Detection} +\section{Invalid Offset Detection} Each game uses a different amount of assets for each of its SCROLL and OBJ layers. On the "B" board, PAL chips such as the \icode{STF29} discussed earlier are hard-coded with knowledge of the amount of GFX ROM attributed to each layer. @@ -2153,7 +2153,7 @@ \subsection{Invalid Offset Detection} -\subsection{Configuration Key} +\section{Configuration Key} Up to 1991, the behavior of a CPS-B was hard-coded in its silicon at the factory level. There was no way to alter or re-purpose them after they shipped. It was not only expensive to have to revise the hardware circuits for each game, it was also a logistic difficulty to provision enough chips for a success and not be stuck with inventory on an unappreciated game. To solve this issue, Capcom revised the CPS-B chip one last time and made it configurable via software. @@ -2166,12 +2166,12 @@ \subsection{Configuration Key} These batteries worked remarkably well since, thirty years later, one can find boards in working condition still using their original battery. \end{trivia} -\subsubsection{Suicide batteries} +\subsection{Suicide batteries} The infamous "suicide" nickname came from the effect of losing power. A CPS-B v21 without power lose its configuration and resets all its registers to "default" values that none of the games use. Capcom offered a battery replacement service to resurrect boards "C" which had committed seppuku but eventually discontinued it. As the reader will have guessed, passionate fans found a way to bring these games back to life. -\subsubsection{Phoenixing} +\subsection{Phoenixing} The first method is called "phoenix"-ing. It is a tedious process which consists of dumping a game ROM and patching the m68k instructions to replace CPS-B registers accesses to use the "default values"\cite{csp1_phoenix}. People phoenixing CPS-1 boards have such intimate knowledge of the CP-System that they even changed the game to display a "Phoenix Edition" splash upon startup. @@ -2182,7 +2182,7 @@ \subsubsection{Phoenixing} \end{figure} -\subsubsection{De-suiciding} +\subsection{De-suiciding} Eventually, passionate people figured out the process of accessing and writing the CPS-B RAM. Boards can be brought back to life by re-uploading the proper configuration bytes which essentially de-suicides them\cite{arcadeHackerCPS1Desuicide}. @@ -2209,7 +2209,7 @@ \section{Epilogue} As cracks appeared in its shield, Capcom did not give up on protecting its titles. As it had proved itself able to evolve and compete in the business of producing games, it embraced the challenge of embarking on an encryption crusade against bootleggers. -\subsection{CPS-1.5 Kabuki} +\section{CPS-1.5 Kabuki} \index{CP-System!CPS-1.5 Kabuki} In 1992, Capcom released the CP System Dash (a.k.a CPS-1.5). Fully encased in a gray plastic box, it introduced a fourth satellite "Qboard" PCB to handle playback of positional three-dimensional Qsound audio. Five games were produced until late 1993. @@ -2244,7 +2244,7 @@ \subsection{CPS-1.5 Kabuki} The protection provided by Kabuki held remarkably well over the years. It was only broken in the early 2000s\cite{mame_kabuki}. \end{trivia} -\subsection{CPS-2} +\section{CPS-2} \index{CP-System!CPS-2} With significantly improved capabilities thanks to its increased ROM capacity and higher processor clocks, the CPS-2 instantly became a smash-hit, in particular thanks to the Street Fighter Alpha series. @@ -2256,7 +2256,7 @@ \subsection{CPS-2} The graphic asset stored in the GFXROM were slightly obfuscated. However no encryption occurred, data was only shuffled. -\subsubsection{A strong protection} +\subsection{A strong protection} No bootlegs of CPS-2 titles are known to have ever been produced. Efforts to shed light on the CPS-2 internals started in 2000\cite{cps2rebirth} via the "CPS-2 Shock Group". diff --git a/src/introduction.tex b/src/introduction.tex index 4c5cc9b3..19e96a16 100644 --- a/src/introduction.tex +++ b/src/introduction.tex @@ -333,7 +333,7 @@ \section{Ode to CP-System} The goal of this work is to understand the CP-System, from the ground up. This will (hopefully) be achieved by first exposing the hardware and then progressively moving up, all the way to the programming and game engine architecture level. -\subsubsection{Hardware} +\subsection{Hardware} The CP-System is comprised of four hardware subsystems which are explored in the first chapter. \begin{itemize}[topsep=0pt] \item Control System @@ -344,7 +344,7 @@ \subsubsection{Hardware} Beyond the hard reality of silicon and bus lines, a discussion of the design choices and real-life examples of how games leveraged features is provided when relevant. -\subsubsection{Software} +\subsection{Software} The subsequent chapters study the software and how to build it. In particular the four ROM groups that make up a game are explained. \begin{itemize}[topsep=0pt] @@ -356,5 +356,5 @@ \subsubsection{Software} These chapters use modern tooling but also feature a "Back in the days" section which explores how Capcom used to work back in the '90s. -\subsubsection{Peopleware} +\subsection{Peopleware} People involved with either hardware or software are quoted in the relevant sections. However, Capcom was already a big company by the early '90s and many ended up participating in the history of the CPS-1. To help the reader keep track of all the actors, a list of people and their roles is available on page \pageref{people}. diff --git a/src/level_data.tex b/src/level_data.tex index 88adf47d..2c6aeba0 100644 --- a/src/level_data.tex +++ b/src/level_data.tex @@ -99,7 +99,7 @@ \chapter{Enemies and their Discontents} \end{figure} \clearpage -\subsection{Something Simple - Byte 0: The Enemy's Color} +\section{Something Simple - Byte 0: The Enemy's Color} To get an understanding of how the level data is used we can start with the very first byte of the data used for the first wave in the very first level. This is the wave of flying saucers you will already be familiar with if you have played the game (:)): @@ -179,7 +179,7 @@ \subsection{Something Simple - Byte 0: The Enemy's Color} STA upperPlanetAttackShipsColorArray + $01,X \end{lstlisting} -\subsection{Bytes 1-4: Sprite Animation} +\section{Bytes 1-4: Sprite Animation} \begin{q}{Jeff Minter's Development Diary in Zzap Magazine\cite{planner}} You pass the interpreter data, that describes exactly stuff like: what each alien looks like, how many frames of animation it uses, speed of that @@ -355,7 +355,7 @@ \subsection{Bytes 1-4: Sprite Animation} RTS \end{lstlisting} -\subsection{Bytes 18-21: Enemy Movement} +\section{Bytes 18-21: Enemy Movement} Enemy movement is controlled by two parameters in each direction: the number of pixels to move in one go and the number of cycles to wait between each movement. So for movement in the horizontal (or X direction) \icode{Byte 18} controls the number @@ -490,7 +490,7 @@ \subsection{Bytes 18-21: Enemy Movement} wave will accelerate out to the center before dialling back again. -\subsubsection{What is going on with Byte 6?} +\subsection{What is going on with Byte 6?} Byte 6 comes into play when setting the initial Y position of a new enemy. This initial vertical position is random, but subject to some adjustment: @@ -604,7 +604,7 @@ \subsubsection{What is going on with Byte 6?} enemy mode for some levels where the ship will supplement any dead ships with alternate enemy types and attack patterns periodically. -\subsection{Bytes 6-8: Alternate Enemy Waves} +\section{Bytes 6-8: Alternate Enemy Waves} This happens in \icode{MaybeSwitchToAlternateEnemyPattern} in \icode{UpdateAttackShipDataForNewShip}. \begin{lstlisting}[caption=Byte 6 is used to periodically switch to an enemy mode defined by Bytes 7-8 ] @@ -809,7 +809,7 @@ \subsection{Bytes 6-8: Alternate Enemy Waves} \end{table} -\subsection{Bytes 22-23: The Bytes of Death} +\section{Bytes 22-23: The Bytes of Death} \begin{figure}[H] { \setlength{\tabcolsep}{3.0pt} @@ -899,7 +899,7 @@ \subsection{Bytes 22-23: The Bytes of Death} TAX \end{lstlisting} -\subsection{Byte 35: Energy Multiplier} +\section{Byte 35: Energy Multiplier} When an enemy is struck this byte contains the multiplier applied to the player's energy boost: \begin{lstlisting} @@ -1012,7 +1012,7 @@ \subsection{Byte 35: Energy Multiplier} \end{lstlisting} -\subsection{Byte 34: Score for Hitting the Enemy} +\section{Byte 34: Score for Hitting the Enemy} This is used to augment the score received for hitting the enemy. \begin{lstlisting} ; Get the points for hitting enemies in this level diff --git a/src/level_data/level_data_appendix.tex b/src/level_data/level_data_appendix.tex index 7bd1a234..1eb76fa0 100644 --- a/src/level_data/level_data_appendix.tex +++ b/src/level_data/level_data_appendix.tex @@ -1,6 +1,6 @@ \clearpage -\subsubsection{Sheep Planet - Level 1 Data} +\subsection{Sheep Planet - Level 1 Data} \begin{figure}[H] \centering @@ -62,7 +62,7 @@ \subsubsection{Sheep Planet - Level 1 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 2 Data} +\subsection{Sheep Planet - Level 2 Data} \begin{figure}[H] \centering @@ -124,7 +124,7 @@ \subsubsection{Sheep Planet - Level 2 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 3 Data} +\subsection{Sheep Planet - Level 3 Data} \begin{figure}[H] \centering @@ -186,7 +186,7 @@ \subsubsection{Sheep Planet - Level 3 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 4 Data} +\subsection{Sheep Planet - Level 4 Data} \begin{figure}[H] \centering @@ -248,7 +248,7 @@ \subsubsection{Sheep Planet - Level 4 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 5 Data} +\subsection{Sheep Planet - Level 5 Data} \begin{figure}[H] \centering @@ -310,7 +310,7 @@ \subsubsection{Sheep Planet - Level 5 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 6 Data} +\subsection{Sheep Planet - Level 6 Data} \begin{figure}[H] \centering @@ -372,7 +372,7 @@ \subsubsection{Sheep Planet - Level 6 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 7 Data} +\subsection{Sheep Planet - Level 7 Data} \begin{figure}[H] { @@ -424,7 +424,7 @@ \subsubsection{Sheep Planet - Level 7 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 8 Data} +\subsection{Sheep Planet - Level 8 Data} \begin{figure}[H] \centering @@ -486,7 +486,7 @@ \subsubsection{Sheep Planet - Level 8 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 9 Data} +\subsection{Sheep Planet - Level 9 Data} \begin{figure}[H] \centering @@ -548,7 +548,7 @@ \subsubsection{Sheep Planet - Level 9 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 10 Data} +\subsection{Sheep Planet - Level 10 Data} \begin{figure}[H] \centering @@ -610,7 +610,7 @@ \subsubsection{Sheep Planet - Level 10 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 11 Data} +\subsection{Sheep Planet - Level 11 Data} \begin{figure}[H] \centering @@ -672,7 +672,7 @@ \subsubsection{Sheep Planet - Level 11 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 12 Data} +\subsection{Sheep Planet - Level 12 Data} \begin{figure}[H] \centering @@ -734,7 +734,7 @@ \subsubsection{Sheep Planet - Level 12 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 13 Data} +\subsection{Sheep Planet - Level 13 Data} \begin{figure}[H] \centering @@ -796,7 +796,7 @@ \subsubsection{Sheep Planet - Level 13 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 14 Data} +\subsection{Sheep Planet - Level 14 Data} \begin{figure}[H] \centering @@ -858,7 +858,7 @@ \subsubsection{Sheep Planet - Level 14 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 15 Data} +\subsection{Sheep Planet - Level 15 Data} \begin{figure}[H] \centering @@ -920,7 +920,7 @@ \subsubsection{Sheep Planet - Level 15 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 16 Data} +\subsection{Sheep Planet - Level 16 Data} \begin{figure}[H] \centering @@ -982,7 +982,7 @@ \subsubsection{Sheep Planet - Level 16 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 17 Data} +\subsection{Sheep Planet - Level 17 Data} \begin{figure}[H] \centering @@ -1044,7 +1044,7 @@ \subsubsection{Sheep Planet - Level 17 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 18 Data} +\subsection{Sheep Planet - Level 18 Data} \begin{figure}[H] \centering @@ -1106,7 +1106,7 @@ \subsubsection{Sheep Planet - Level 18 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 19 Data} +\subsection{Sheep Planet - Level 19 Data} \begin{figure}[H] { @@ -1158,7 +1158,7 @@ \subsubsection{Sheep Planet - Level 19 Data} \end{figure} \clearpage -\subsubsection{Sheep Planet - Level 20 Data} +\subsection{Sheep Planet - Level 20 Data} \begin{figure}[H] \centering @@ -1220,7 +1220,7 @@ \subsubsection{Sheep Planet - Level 20 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 1 Data} +\subsection{Tech Planet - Level 1 Data} \begin{figure}[H] { @@ -1272,7 +1272,7 @@ \subsubsection{Tech Planet - Level 1 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 2 Data} +\subsection{Tech Planet - Level 2 Data} \begin{figure}[H] \centering @@ -1334,7 +1334,7 @@ \subsubsection{Tech Planet - Level 2 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 3 Data} +\subsection{Tech Planet - Level 3 Data} \begin{figure}[H] \centering @@ -1396,7 +1396,7 @@ \subsubsection{Tech Planet - Level 3 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 4 Data} +\subsection{Tech Planet - Level 4 Data} \begin{figure}[H] \centering @@ -1458,7 +1458,7 @@ \subsubsection{Tech Planet - Level 4 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 5 Data} +\subsection{Tech Planet - Level 5 Data} \begin{figure}[H] \centering @@ -1520,7 +1520,7 @@ \subsubsection{Tech Planet - Level 5 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 6 Data} +\subsection{Tech Planet - Level 6 Data} \begin{figure}[H] \centering @@ -1582,7 +1582,7 @@ \subsubsection{Tech Planet - Level 6 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 7 Data} +\subsection{Tech Planet - Level 7 Data} \begin{figure}[H] \centering @@ -1644,7 +1644,7 @@ \subsubsection{Tech Planet - Level 7 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 8 Data} +\subsection{Tech Planet - Level 8 Data} \begin{figure}[H] \centering @@ -1706,7 +1706,7 @@ \subsubsection{Tech Planet - Level 8 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 9 Data} +\subsection{Tech Planet - Level 9 Data} \begin{figure}[H] \centering @@ -1768,7 +1768,7 @@ \subsubsection{Tech Planet - Level 9 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 10 Data} +\subsection{Tech Planet - Level 10 Data} \begin{figure}[H] \centering @@ -1830,7 +1830,7 @@ \subsubsection{Tech Planet - Level 10 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 11 Data} +\subsection{Tech Planet - Level 11 Data} \begin{figure}[H] \centering @@ -1892,7 +1892,7 @@ \subsubsection{Tech Planet - Level 11 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 12 Data} +\subsection{Tech Planet - Level 12 Data} \begin{figure}[H] \centering @@ -1954,7 +1954,7 @@ \subsubsection{Tech Planet - Level 12 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 13 Data} +\subsection{Tech Planet - Level 13 Data} \begin{figure}[H] \centering @@ -2016,7 +2016,7 @@ \subsubsection{Tech Planet - Level 13 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 14 Data} +\subsection{Tech Planet - Level 14 Data} \begin{figure}[H] \centering @@ -2078,7 +2078,7 @@ \subsubsection{Tech Planet - Level 14 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 15 Data} +\subsection{Tech Planet - Level 15 Data} \begin{figure}[H] { @@ -2130,7 +2130,7 @@ \subsubsection{Tech Planet - Level 15 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 16 Data} +\subsection{Tech Planet - Level 16 Data} \begin{figure}[H] \centering @@ -2192,7 +2192,7 @@ \subsubsection{Tech Planet - Level 16 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 17 Data} +\subsection{Tech Planet - Level 17 Data} \begin{figure}[H] \centering @@ -2254,7 +2254,7 @@ \subsubsection{Tech Planet - Level 17 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 18 Data} +\subsection{Tech Planet - Level 18 Data} \begin{figure}[H] \centering @@ -2316,7 +2316,7 @@ \subsubsection{Tech Planet - Level 18 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 19 Data} +\subsection{Tech Planet - Level 19 Data} \begin{figure}[H] \centering @@ -2378,7 +2378,7 @@ \subsubsection{Tech Planet - Level 19 Data} \end{figure} \clearpage -\subsubsection{Tech Planet - Level 20 Data} +\subsection{Tech Planet - Level 20 Data} \begin{figure}[H] \centering @@ -2440,7 +2440,7 @@ \subsubsection{Tech Planet - Level 20 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 1 Data} +\subsection{Brick Planet - Level 1 Data} \begin{figure}[H] { @@ -2492,7 +2492,7 @@ \subsubsection{Brick Planet - Level 1 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 2 Data} +\subsection{Brick Planet - Level 2 Data} \begin{figure}[H] \centering @@ -2554,7 +2554,7 @@ \subsubsection{Brick Planet - Level 2 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 3 Data} +\subsection{Brick Planet - Level 3 Data} \begin{figure}[H] \centering @@ -2616,7 +2616,7 @@ \subsubsection{Brick Planet - Level 3 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 4 Data} +\subsection{Brick Planet - Level 4 Data} \begin{figure}[H] \centering @@ -2678,7 +2678,7 @@ \subsubsection{Brick Planet - Level 4 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 5 Data} +\subsection{Brick Planet - Level 5 Data} \begin{figure}[H] \centering @@ -2740,7 +2740,7 @@ \subsubsection{Brick Planet - Level 5 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 6 Data} +\subsection{Brick Planet - Level 6 Data} \begin{figure}[H] \centering @@ -2802,7 +2802,7 @@ \subsubsection{Brick Planet - Level 6 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 7 Data} +\subsection{Brick Planet - Level 7 Data} \begin{figure}[H] \centering @@ -2864,7 +2864,7 @@ \subsubsection{Brick Planet - Level 7 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 8 Data} +\subsection{Brick Planet - Level 8 Data} \begin{figure}[H] { @@ -2916,7 +2916,7 @@ \subsubsection{Brick Planet - Level 8 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 9 Data} +\subsection{Brick Planet - Level 9 Data} \begin{figure}[H] \centering @@ -2978,7 +2978,7 @@ \subsubsection{Brick Planet - Level 9 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 10 Data} +\subsection{Brick Planet - Level 10 Data} \begin{figure}[H] \centering @@ -3040,7 +3040,7 @@ \subsubsection{Brick Planet - Level 10 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 11 Data} +\subsection{Brick Planet - Level 11 Data} \begin{figure}[H] \centering @@ -3102,7 +3102,7 @@ \subsubsection{Brick Planet - Level 11 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 12 Data} +\subsection{Brick Planet - Level 12 Data} \begin{figure}[H] \centering @@ -3164,7 +3164,7 @@ \subsubsection{Brick Planet - Level 12 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 13 Data} +\subsection{Brick Planet - Level 13 Data} \begin{figure}[H] \centering @@ -3226,7 +3226,7 @@ \subsubsection{Brick Planet - Level 13 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 14 Data} +\subsection{Brick Planet - Level 14 Data} \begin{figure}[H] \centering @@ -3288,7 +3288,7 @@ \subsubsection{Brick Planet - Level 14 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 15 Data} +\subsection{Brick Planet - Level 15 Data} \begin{figure}[H] \centering @@ -3350,7 +3350,7 @@ \subsubsection{Brick Planet - Level 15 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 16 Data} +\subsection{Brick Planet - Level 16 Data} \begin{figure}[H] \centering @@ -3412,7 +3412,7 @@ \subsubsection{Brick Planet - Level 16 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 17 Data} +\subsection{Brick Planet - Level 17 Data} \begin{figure}[H] \centering @@ -3474,7 +3474,7 @@ \subsubsection{Brick Planet - Level 17 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 18 Data} +\subsection{Brick Planet - Level 18 Data} \begin{figure}[H] \centering @@ -3536,7 +3536,7 @@ \subsubsection{Brick Planet - Level 18 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 19 Data} +\subsection{Brick Planet - Level 19 Data} \begin{figure}[H] \centering @@ -3598,7 +3598,7 @@ \subsubsection{Brick Planet - Level 19 Data} \end{figure} \clearpage -\subsubsection{Brick Planet - Level 20 Data} +\subsection{Brick Planet - Level 20 Data} \begin{figure}[H] \centering @@ -3660,7 +3660,7 @@ \subsubsection{Brick Planet - Level 20 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 1 Data} +\subsection{Mushroom Planet - Level 1 Data} \begin{figure}[H] \centering @@ -3722,7 +3722,7 @@ \subsubsection{Mushroom Planet - Level 1 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 2 Data} +\subsection{Mushroom Planet - Level 2 Data} \begin{figure}[H] \centering @@ -3784,7 +3784,7 @@ \subsubsection{Mushroom Planet - Level 2 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 3 Data} +\subsection{Mushroom Planet - Level 3 Data} \begin{figure}[H] \centering @@ -3846,7 +3846,7 @@ \subsubsection{Mushroom Planet - Level 3 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 4 Data} +\subsection{Mushroom Planet - Level 4 Data} \begin{figure}[H] \centering @@ -3908,7 +3908,7 @@ \subsubsection{Mushroom Planet - Level 4 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 5 Data} +\subsection{Mushroom Planet - Level 5 Data} \begin{figure}[H] \centering @@ -3970,7 +3970,7 @@ \subsubsection{Mushroom Planet - Level 5 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 6 Data} +\subsection{Mushroom Planet - Level 6 Data} \begin{figure}[H] \centering @@ -4032,7 +4032,7 @@ \subsubsection{Mushroom Planet - Level 6 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 7 Data} +\subsection{Mushroom Planet - Level 7 Data} \begin{figure}[H] \centering @@ -4094,7 +4094,7 @@ \subsubsection{Mushroom Planet - Level 7 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 8 Data} +\subsection{Mushroom Planet - Level 8 Data} \begin{figure}[H] \centering @@ -4156,7 +4156,7 @@ \subsubsection{Mushroom Planet - Level 8 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 9 Data} +\subsection{Mushroom Planet - Level 9 Data} \begin{figure}[H] \centering @@ -4218,7 +4218,7 @@ \subsubsection{Mushroom Planet - Level 9 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 10 Data} +\subsection{Mushroom Planet - Level 10 Data} \begin{figure}[H] \centering @@ -4280,7 +4280,7 @@ \subsubsection{Mushroom Planet - Level 10 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 11 Data} +\subsection{Mushroom Planet - Level 11 Data} \begin{figure}[H] \centering @@ -4342,7 +4342,7 @@ \subsubsection{Mushroom Planet - Level 11 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 12 Data} +\subsection{Mushroom Planet - Level 12 Data} \begin{figure}[H] \centering @@ -4404,7 +4404,7 @@ \subsubsection{Mushroom Planet - Level 12 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 13 Data} +\subsection{Mushroom Planet - Level 13 Data} \begin{figure}[H] \centering @@ -4466,7 +4466,7 @@ \subsubsection{Mushroom Planet - Level 13 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 14 Data} +\subsection{Mushroom Planet - Level 14 Data} \begin{figure}[H] \centering @@ -4528,7 +4528,7 @@ \subsubsection{Mushroom Planet - Level 14 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 15 Data} +\subsection{Mushroom Planet - Level 15 Data} \begin{figure}[H] \centering @@ -4590,7 +4590,7 @@ \subsubsection{Mushroom Planet - Level 15 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 16 Data} +\subsection{Mushroom Planet - Level 16 Data} \begin{figure}[H] \centering @@ -4652,7 +4652,7 @@ \subsubsection{Mushroom Planet - Level 16 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 17 Data} +\subsection{Mushroom Planet - Level 17 Data} \begin{figure}[H] \centering @@ -4714,7 +4714,7 @@ \subsubsection{Mushroom Planet - Level 17 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 18 Data} +\subsection{Mushroom Planet - Level 18 Data} \begin{figure}[H] \centering @@ -4776,7 +4776,7 @@ \subsubsection{Mushroom Planet - Level 18 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 19 Data} +\subsection{Mushroom Planet - Level 19 Data} \begin{figure}[H] \centering @@ -4838,7 +4838,7 @@ \subsubsection{Mushroom Planet - Level 19 Data} \end{figure} \clearpage -\subsubsection{Mushroom Planet - Level 20 Data} +\subsection{Mushroom Planet - Level 20 Data} \begin{figure}[H] \centering @@ -4900,7 +4900,7 @@ \subsubsection{Mushroom Planet - Level 20 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 1 Data} +\subsection{Om Planet - Level 1 Data} \begin{figure}[H] \centering @@ -4962,7 +4962,7 @@ \subsubsection{Om Planet - Level 1 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 2 Data} +\subsection{Om Planet - Level 2 Data} \begin{figure}[H] \centering @@ -5024,7 +5024,7 @@ \subsubsection{Om Planet - Level 2 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 3 Data} +\subsection{Om Planet - Level 3 Data} \begin{figure}[H] { @@ -5076,7 +5076,7 @@ \subsubsection{Om Planet - Level 3 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 4 Data} +\subsection{Om Planet - Level 4 Data} \begin{figure}[H] { @@ -5128,7 +5128,7 @@ \subsubsection{Om Planet - Level 4 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 5 Data} +\subsection{Om Planet - Level 5 Data} \begin{figure}[H] \centering @@ -5190,7 +5190,7 @@ \subsubsection{Om Planet - Level 5 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 6 Data} +\subsection{Om Planet - Level 6 Data} \begin{figure}[H] \centering @@ -5252,7 +5252,7 @@ \subsubsection{Om Planet - Level 6 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 7 Data} +\subsection{Om Planet - Level 7 Data} \begin{figure}[H] \centering @@ -5314,7 +5314,7 @@ \subsubsection{Om Planet - Level 7 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 8 Data} +\subsection{Om Planet - Level 8 Data} \begin{figure}[H] \centering @@ -5376,7 +5376,7 @@ \subsubsection{Om Planet - Level 8 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 9 Data} +\subsection{Om Planet - Level 9 Data} \begin{figure}[H] \centering @@ -5438,7 +5438,7 @@ \subsubsection{Om Planet - Level 9 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 10 Data} +\subsection{Om Planet - Level 10 Data} \begin{figure}[H] \centering @@ -5500,7 +5500,7 @@ \subsubsection{Om Planet - Level 10 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 11 Data} +\subsection{Om Planet - Level 11 Data} \begin{figure}[H] \centering @@ -5562,7 +5562,7 @@ \subsubsection{Om Planet - Level 11 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 12 Data} +\subsection{Om Planet - Level 12 Data} \begin{figure}[H] \centering @@ -5624,7 +5624,7 @@ \subsubsection{Om Planet - Level 12 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 13 Data} +\subsection{Om Planet - Level 13 Data} \begin{figure}[H] \centering @@ -5686,7 +5686,7 @@ \subsubsection{Om Planet - Level 13 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 14 Data} +\subsection{Om Planet - Level 14 Data} \begin{figure}[H] \centering @@ -5748,7 +5748,7 @@ \subsubsection{Om Planet - Level 14 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 15 Data} +\subsection{Om Planet - Level 15 Data} \begin{figure}[H] \centering @@ -5810,7 +5810,7 @@ \subsubsection{Om Planet - Level 15 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 17 Data} +\subsection{Om Planet - Level 17 Data} \begin{figure}[H] \centering @@ -5872,7 +5872,7 @@ \subsubsection{Om Planet - Level 17 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 18 Data} +\subsection{Om Planet - Level 18 Data} \begin{figure}[H] { @@ -5924,7 +5924,7 @@ \subsubsection{Om Planet - Level 18 Data} \end{figure} \clearpage -\subsubsection{Om Planet - Level 20 Data} +\subsection{Om Planet - Level 20 Data} \begin{figure}[H] \centering diff --git a/src/level_data_appendix_detail.tex b/src/level_data_appendix_detail.tex index 8c925209..580ee0a3 100644 --- a/src/level_data_appendix_detail.tex +++ b/src/level_data_appendix_detail.tex @@ -1,12 +1,12 @@ \chapter{Appendix: Enemy Data} -\subsubsection{Sprite Data for Each Level} +\subsection{Sprite Data for Each Level} \subfile{level_data/level_data_sprites} -\subsection{Enemy Pointer Data} +\section{Enemy Pointer Data} \subfile{level_data/level_data_pointers} -\subsection{Enemy Behaviour} +\section{Enemy Behaviour} \subfile{level_data/level_data_behaviour} -\subsection{Level Movement Data} +\section{Level Movement Data} \subfile{level_data/level_data_movement} diff --git a/src/main_game.tex b/src/main_game.tex index b16b79eb..c2ebfac8 100644 --- a/src/main_game.tex +++ b/src/main_game.tex @@ -89,7 +89,7 @@ \chapter{Blasting, Fast and Slow} it appears at a new position as well as the old one on which the raster has already painted it. We covered the mechanics of this in detail when we dissected the title screen in 'The First 16 Milliseconds'. -\subsection{Updating Enemy Sprite Positions} +\section{Updating Enemy Sprite Positions} We can get a better sense of how the labour is divided between the two routines if we isolate the position of the raster when the position of the enemy sprites on each planet is updated. @@ -190,7 +190,7 @@ \subsection{Updating Enemy Sprite Positions} \end{lstlisting} \end{minipage} -\subsection{Scrolling the Planets} +\section{Scrolling the Planets} We want scrolling to be smooth and fast. Moving swiftly or slowly across the planet surface depending on how much acceleration we apply is the fundamental dynamic of the game so will be important to get right. @@ -224,7 +224,7 @@ \subsection{Scrolling the Planets} occasion (notice how much the bush moves). At the same time we're applying a pixel movement to preserve the impression of smoothness. -\subsubsection{Pixel Movement} +\subsection{Pixel Movement} If we look at the code that looks after the pixel-grained movement in \icode{AnimateStar\-FieldAndScrollPlanets} we can see it is using a variable called \icode{planetScrollSpeed} to control the amount of offset to apply: @@ -355,7 +355,7 @@ \subsubsection{Pixel Movement} practice - it ensures we're avoiding the appearance of scrolling purely character-wise by guaranteeing we're nearly always displaying the surface offset by some small number of pixels. -\subsubsection{Character Movement} +\subsection{Character Movement} As a quick reminder from our chapter on generating the surfaces of the planets ('Making Planets for Nigel'), the data we came up with for the ever-so-randomly-generated planet was stored between \icode{\$8000} and \icode{\$8FFF}. @@ -631,7 +631,7 @@ \subsubsection{Character Movement} \end{lstlisting} -\subsection{Jumping Up and Down} +\section{Jumping Up and Down} \begin{lstlisting}[caption=The routines responsible for updating the Gilby's vertical position.] ;------------------------------------------------------- ; PerformMainGameUpdate @@ -745,7 +745,7 @@ \subsection{Jumping Up and Down} With a simple, consistent addition operation each time it comes to position the gilby we've managed to achieve a jumping and landing effect with a neat gravity effect built in! -\subsection{Sound Effects} +\section{Sound Effects} \begin{lstlisting} ;------------------------------------------------------- ; PerformMainGameUpdate @@ -772,7 +772,7 @@ \subsection{Sound Effects} will allow us to manage two different sound effects concurrently. Before we look at how this multiplexing is achieved lets look at how a single sound effect is managed in general. -\subsubsection{The Sound Effect Data Structure} +\subsection{The Sound Effect Data Structure} As ever, the key to managing complexity isn't the cleverness of our code but the simplicity of the data structure we choose. Iridis Alpha solves this with a remarkably compact solution where each frame in the sound effect is represented by a meagre 5 bytes and the whole sound effect is encoded by a sequence of these 5-byte records. In order to unpack @@ -1020,7 +1020,7 @@ \subsubsection{The Sound Effect Data Structure} }\caption*{} \end{figure} -\subsubsection{Multiplexing} +\subsection{Multiplexing} While playing the fairly dull component we cover above, Iridis Alpha plays a second sequence simultaneously that constitutes the one a player will know and recognize. @@ -1394,7 +1394,7 @@ \subsubsection{Multiplexing} \end{figure} -\subsubsection{Unused Sound Effects} +\subsection{Unused Sound Effects} The \icode{PlaySoundEffects} code has some leftover routines for record types that appear to have gone unused in the final game. These make slightly more complicated use of the \icode{soundEffectBuffer}. All they do is mutate the data in the buffer using the 5-byte record. They don't actually play any sounds or make any writes to the SID register. diff --git a/src/music.tex b/src/music.tex index 2f93d3b1..a56fcd50 100644 --- a/src/music.tex +++ b/src/music.tex @@ -129,7 +129,7 @@ \chapter{A Hundred Thousand Billion Theme Tunes} RTS \end{lstlisting} -\subsection{Some Basics} +\section{Some Basics} The rudiments of playing music on the Commodore 64 are simple. It has a powerful-for-its-time sound chip that has 3 tracks or 'voices'. You can play any note across 8 octaves on each of these voices together or separately. There are a whole bunch of settings you can apply @@ -327,7 +327,7 @@ \subsection{Some Basics} }\caption[]{The first title tune in Iridis Alpha.} \end{figure} -\subsubsection{Structure} +\subsection{Structure} Even if you can't read sheet music notation some structure should be evident. Voice 3 carries the main melody. @@ -510,7 +510,7 @@ \subsubsection{Structure} \end{tcolorbox}% -\subsubsection{Phrasing} +\subsection{Phrasing} Now that we've identified the underlying 4-bar structure of the arrangement. We can take a closer look at the phrasing of the invidividual parts. Voice 3 has a simple repetitive structure for each 4-bar phrase: @@ -788,7 +788,7 @@ \subsubsection{Phrasing} }\caption[]{The same patterns in Tunes 12 and 18.} \end{figure} -\subsubsection{Seeding the Random} +\subsection{Seeding the Random} We've established how each tune is built entirely off the same 4-byte sequence, all the way from selecting notes to play to filling out the larger structure of the tune at almost every level. What remains is diff --git a/src/planets.tex b/src/planets.tex index f648f0c5..4181270a 100644 --- a/src/planets.tex +++ b/src/planets.tex @@ -77,7 +77,7 @@ \chapter{Making Planets for Nigel} But making planets isn't all simple steps and big picture decisions. There are also trifling details for the little people to wrestle with. -\subsection{Step One: Creating the Sea} +\section{Step One: Creating the Sea} Making a sea is very easy. You come up with a character than can be repeated 1024 times to fill the surface of the planet. @@ -238,7 +238,7 @@ \subsection{Step One: Creating the Sea} \subfile{planets/planet1Charset_SeaAgain} -\subsection{Step Two: Creating the Land} +\section{Step Two: Creating the Land} Is that all there is to it? Painting things with blue? No. @@ -422,7 +422,7 @@ \subsection{Step Two: Creating the Land} \end{lstlisting} -\subsection{Step Three: Structures Structures Structures} +\section{Step Three: Structures Structures Structures} The routines for adding structures to the planet are the opportunity to observe some assembly language cleverness. For each structure we draw we have to decide two things: where to drop it on the surface and what type of structure to draw. Apart from the Warp Gates, there are four structure types available. @@ -643,7 +643,7 @@ \subsection{Step Three: Structures Structures Structures} }\caption[]{Planet 3 once \icode{DrawRandomlyChosenStructure} has finished its business.} \end{figure} -\subsection{Step Four: Add the warp gate} +\section{Step Four: Add the warp gate} Our final step is to add the warp gate. \begin{figure}[H] @@ -709,7 +709,7 @@ \subsection{Step Four: Add the warp gate} }\caption[]{The final surfaces for Planets 4 and 5.} \end{figure} -\subsection{Inactive Lower Planet} +\section{Inactive Lower Planet} When the lower planet is inactive a surface with land, sea, and a warp gate is displayed. This doesn't reuse any of the logic described above. Instead it is generated from some customized data in the routine \icode{DrawLowerPlanetWhileInactive}. @@ -773,7 +773,7 @@ \subsection{Inactive Lower Planet} \end{lstlisting} -\subsection{Drawing the Lower Planet} +\section{Drawing the Lower Planet} Drawing the upper planet is all very well. The data is just there and as we have seen it's just a question of 'writing it to the screen'. For the lower planet, which is just an upside down version of the upper one, we could store the data all over again, but inverted. Or we could try something a little more clever, @@ -969,7 +969,7 @@ \subsection{Drawing the Lower Planet} 8 byte character set definition to position 5.} \end{figure} -\subsubsection{1. Flipping the Byte} +\subsection{1. Flipping the Byte} The first of these requirements is the more elaborate of the two. We need to look at each of the four bit-pairs in the byte and move it to its corresponding 'inverted' position in the byte. So in a way we treat one half of they byte as a mirror of the other and move the bit pair there as in the following examples. @@ -1330,7 +1330,7 @@ \subsubsection{1. Flipping the Byte} }\caption{The result of our bit-shifting, \icode{AND}'ing\, and \icode{OR}ing.} \end{figure} -\subsubsection{2. Flipping the Byte's Position} +\subsection{2. Flipping the Byte's Position} The remaining steps for the other two bit-pairs in the byte are similar. In the case of our example they will have no effect as the result will be always be zero for them. We've effectively mirrored our bitpair already. diff --git a/src/preface.tex b/src/preface.tex index 9f02e58a..3b37fb6f 100644 --- a/src/preface.tex +++ b/src/preface.tex @@ -39,7 +39,7 @@ \chapter{Preface} If you are reading the PDF version of this book the \hyperref[sec:appendices]{\textcolor{blue}{Appendices}} contain a data dump of sprite sheets, character sets, maps and tables that should provide hours of rewarding bedtime reading. -\subsection{Note on the Text} +\section{Note on the Text} The version you are reading is little more than a scrapbook still many revisions away from a finished product. If you find the writing hard going or the attempts to explain things difficult to follow, by all means \href{https://github.com/mwenge/iatheory/issues}{\textcolor{blue}{leave me a note}} and @@ -48,3 +48,13 @@ \subsection{Note on the Text} - Rob Hogan 2023 \href{https://mastodon.social/@mwenge}{\textcolor{blue}{@mwenge}} +\clearpage +\vspace*{\fill} +\begin{figure}[H] + \centering + \includegraphics[width=5cm]{src/cover/title_page.png}% +\end{figure} +\vspace*{\fill} +\thispagestyle{empty}% +\clearpage + diff --git a/src/prog_68000.tex b/src/prog_68000.tex index 9d424c84..ddc52c87 100644 --- a/src/prog_68000.tex +++ b/src/prog_68000.tex @@ -64,7 +64,7 @@ \section{Memory Map} \pagebreak -\subsection{Goal} +\section{Goal} To avoid flipping pages, here is the memory map studied on page \pageref{m68k_mm}. \begin{tabularx}{\textwidth}{rrrX} @@ -89,7 +89,7 @@ \subsection{Goal} \toprule \end{tabularx}% -\subsection{Memory Regions} +\section{Memory Regions} \lstinputlisting[]{src/code/68000/cps1.lk} @@ -107,7 +107,7 @@ \subsection{Memory Regions} \end{trivia} -\subsection{Code to segment} +\section{Code to segment} C variables are placed into these sections using the names defined in the linker script. @@ -183,7 +183,7 @@ \section{Ruling them all} \end{trivia} -\subsection{Commanding sound} +\section{Commanding sound} Requesting a sound or music playback is only about writing to a latch and forgetting about it. However special care is necessary if the engine requests multiple sounds during the same frame. If this were to happen the value in the latch could be overwritten before the z80 picked it up. The solution is to implement a queue system where commands are stored and fed one by one every frame. @@ -191,7 +191,7 @@ \subsection{Commanding sound} \lstinputlisting[style=CStyle]{src/code/68000/vsync.c} -\subsection{Main} +\section{Main} \lstinputlisting[style=CStyle]{src/code/68000/main.c} @@ -199,7 +199,7 @@ \subsection{Main} To learn about the kernel and how it is used to run multi-task A.I bytecode and moving fireballs, check out the Street Fighter II Platinum source code\cite{sf2platinium}. -\subsection{Retrieving inputs} +\section{Retrieving inputs} Besides joystick and buttons, the engine must recover inputs such as the dip settings, P1Start, P2Start, and most importantly detect coins being inserted. \begin{trivia} @@ -255,22 +255,22 @@ \subsection{Retrieving inputs} % \caption*{Input bit layouts} % \end{figure} -\subsection{Drawing on screen} +\section{Drawing on screen} Requesting tiles to be drawn consists of first describing the layout in GFXRAM, then setting the palettes, and finally writing to the CPS-A and CPS-B registers to point them to "where is the data". -\subsubsection{Double buffering} +\subsection{Double buffering} When a frame is being drawn, neither the data in the GFXRAM nor the CPS-A/CPS-B register values can be changed. Raster effects are not possible since HSYNC is not forwarded to the m68k. Changes should only occur during the VBLANKing which is signaled via the \icode{VSync} function. The proper way to avoid visual artifacts is to double buffer the SCROLL/OBJ descriptors in the GFXRAM. While one buffer is used for rasterization until the next VSYNC, the next frame is prepared in the other buffer. On \icode{VSync} the CPS-A and CPS-B registers are written to swap the buffer roles. -\subsubsection{CPS-A and CPS-B registers} +\subsection{CPS-A and CPS-B registers} The CPS-A registers are always at the same offset in the m68k memory map and they always use the same layout. Depending on the board being targeted, registers of the CPS-B will move and their internal layout will change. A convenient way to deal with this is to use MACROs and have the build system enable the appropriate ones. Note that all registers are 16-bit to accommodate the 68000 operating on them. As shown in the summary table, a register offset is always located on an even address. -\subsubsection{CPS-A Usage} +\subsection{CPS-A Usage} The CPS-A is controlled via 18 registers. @@ -307,7 +307,7 @@ \subsubsection{CPS-A Usage} The base registers tell the CPS-A where it should expect data in GFXRAM. Registers are 16-bit but addresses must be 24-bit so values are expanded \icode{<< 8} upon reception. The linker script should be configured to make sure data structures are aligned properly. -\subsubsection{Row Scrolling} +\subsection{Row Scrolling} Row scrolling allows for offsetting each visible row on SCROLL2 via a discrete X amount. In Street Fighter II, Honda's dohyō ( the space in which a sumo wrestling bout occurs) perspective is achieved via linear offset differences. The more perspective needed, the more accentuated the offset slope. \begin{figure}[H] @@ -343,7 +343,7 @@ \subsubsection{Row Scrolling} \lstinputlisting[style=CStyle]{src/code/68000/rowscroll.c} -\subsubsection{Real-life example} +\subsection{Real-life example} When a contestant in Street Fighter II jumps, SCROLL2 moves vertically but no rowscroll offsets are re-calculated, only \icode{ROWSCROLL\_OFFSET} is moved. This allows to amortize the generation of perspective correct rowscroll offset. @@ -354,7 +354,7 @@ \subsubsection{Real-life example} \lstinputlisting[style=CStyle]{src/code/68000/videocontrol.c} \label{cpsbreg_programming} -\subsubsection{CPS-B Usage} +\subsection{CPS-B Usage} The CPS-B features only seven registers but their location changes based on the version of the chip. \begin{figure}[H] @@ -417,7 +417,7 @@ \subsubsection{CPS-B Usage} -\subsubsection{Drawing OBJs} +\subsection{Drawing OBJs} To draw sprites and shapes, descriptors must be written to the GFX RAM. Each entry takes four 16-bit WORDS (8 bytes). \lstinputlisting[style=CStyle]{src/code/68000/sprites.c} @@ -434,7 +434,7 @@ \subsubsection{Drawing OBJs} Developers do not have to worry about the \icode{STF29} or GFX partitioning. The tileID is relative to the group it belongs to. -\subsubsection{Drawing SCROLLs} +\subsection{Drawing SCROLLs} Rendering tilemaps is much like rendering OBJs. Descriptors must be written to the GFX RAM but the layout is much simpler. Each entry is two 16-bit WORDs wide (four bytes). @@ -493,7 +493,7 @@ \section{Back in the Days}\index{Back in the days!Programming} In 2018, Akiman confirmed\cite{x68000usage1}\cite{x68000usage2} that Capcom's SDK, named CAT-1, was launched during the making of Street Fighter II and ran on a Sharp X68000. -\subsection{SHARP X68000}\index{Computers!SHARP X68000} +\section{SHARP X68000}\index{Computers!SHARP X68000} Unheard of in the rest of the world, the X68000 is a celebrity in Japan where it was nicknamed "god computer". Released in 1987, the first machine in the series was as beautiful and powerful as it was expensive (¥369,000, roughly \$3000 in 1987, equivalent to \$7,600 in 2022). @@ -571,7 +571,7 @@ \subsection{SHARP X68000}\index{Computers!SHARP X68000} -\subsection{X68000 Tech Specs} +\section{X68000 Tech Specs} Inside its gorgeous "Manhattan" case, the machine packed an unparalleled amount of horse power. Even a machine such as the Amiga 500, released the same year and praised in Europe and USA for its prowess, pales in comparison to the X68000. @@ -604,7 +604,7 @@ \subsection{X68000 Tech Specs} The 1056 KiB of VRAM are divided into three segments feeding four planes. 512 KiB are dedicated to the Text plane, 512 KiB are for the Bitmap plane and the rest, 32 KiB, are for the joined use of the Background plane and Sprite plane. Each plane can be configured to use distinct resolution and layers. -\subsection{Video Prowess} +\section{Video Prowess} The \textbf{Bitmap Plane} is particularly well suited to plot pixels and render images. Its direct 16bpp color mode was ideal for raytracing application (a M68881 math coprocessor could be added to reduce rendering time). Four modes are available. @@ -651,7 +651,7 @@ \subsection{Video Prowess} -\subsection{OS} +\section{OS} Developed by Hudson Soft, the operating system named Human68k is strongly inspired by Microsoft's MS-DOS . All English name commands such as \icode{DIR}, \icode{COPY} and such are available. In fact, Human68k manual is nearly identical to IBM DOS 4.0J manual\cite{human68k_manual}. The system even uses a \icode{CONFIG.SYS} file to boot. @@ -671,12 +671,12 @@ \subsection{OS} -\subsection{A Development Machine?} +\section{A Development Machine?} The similarities between the X68000 and the CPS-1 are many. A quick glance over the specs on page \pageref{x68000-specs} could easily lead one to conclude that a small layer of emulation is all a X68000 needed to run CPS-1 games, making it a perfect development machine. Since developers never detailed to what extent SHARP's machine was involved, we can only make an educated guess. A beginning of an answer comes from the hardware components, while Capcom-produced game ports leave no ambiguity. -\subsubsection{Hardware response} +\subsection{Hardware response} If the Motorola 680000 CPU and the YM2151 present in both machines are identical, the rest diverge from slightly to significantly. The sound chip is an OKI but it is "only" a MSM6258. Although it works alike the MSM6296 with ADPCM, it features only one channel which severely impacts how rich the sound effects and music systems can be. @@ -687,11 +687,11 @@ \subsubsection{Hardware response} -\subsubsection{The 32 KiB VRAM wall} +\subsection{The 32 KiB VRAM wall} The real issue, and perhaps the only real weakness of the "god computer" is the minuscule amount of VRAM dedicated to feed the Sprite and Tilemap layers. Out of 1MiB, only 32KiB is available which results in asset starvation (it can store only 256 16x16 tiles). This limitation knee-capped any potential of using both layers at the same time. A VRAM shared among layers would have been a totally different story. -\subsubsection{Software response} +\subsection{Software response} A definitive answer about the viability of the X68000 as a development station comes from Capcom arcade ports. \begin{figure}[H] @@ -721,7 +721,7 @@ \subsubsection{Software response} \nbimg{gg_manual.jpg} -\subsection{Ports Analysis: Ghouls 'n Ghosts (1994)} +\section{Ports Analysis: Ghouls 'n Ghosts (1994)} Ghouls 'n Ghosts was released in 1994, six years after the arcade version. It is noteworthy for its low RAM requirements of 2MiB RAM and its resolution of 512x512. It is considered a "perfect port" because of its GFX faithfulness to the CPS-1 version. All the enemies, levels, and weapons are there, rendered with the correct rich colors. @@ -772,7 +772,7 @@ \subsection{Ports Analysis: Ghouls 'n Ghosts (1994)} \pagebreak -\subsection{Ports Analysis: Final Fight (1992)} +\section{Ports Analysis: Final Fight (1992)} Final Fight was released in 1992, three years after the arcade version. Like the Ghouls'n Ghosts port, the game managed to ship on two 5.25-inch 1.2 MiB floppies. @@ -826,7 +826,7 @@ \subsection{Ports Analysis: Final Fight (1992)} \pagebreak -\subsection{Per Scene Renderer} +\section{Per Scene Renderer} The color-depth reduction trick is only one among many others. There are many testaments to the hair pulling process an X68000 port appears to be. One of them is the introduction sequence where Damned takes away the mayor's daughter. @@ -884,7 +884,7 @@ \subsection{Per Scene Renderer} \pagebreak -\subsection{Ports Analysis: Street Fighter II Champion Edition (1993)} +\section{Ports Analysis: Street Fighter II Champion Edition (1993)} Street Fighter II Champion Edition was released only a year after the arcade version. The volume of assets forced the game to ship on four 5.25-inch 1.2 MiB floppies. The game manages to run with 2 MiB of RAM but suffers numerous loading delays when traveling between countries. However, on a machine with 4 MiB the game engine loads all floppies to RAM to provide a loading-free experience. @@ -944,7 +944,7 @@ \subsection{Ports Analysis: Street Fighter II Champion Edition (1993)} \item Remain within the m68k software rendering budget \end{enumerate} -\subsection{Per Level Renderer} +\section{Per Level Renderer} Like in Final Fight, where scenes were optimized on a case-per-case basis, Street Fighter II Champion Edition uses a distinct rendering strategy depending on the arena. When fighting occurs in China, the Text layer is not used for Sprite decoration like it is in Thailand. Instead it is dedicated to the sky and its animation. Two rows of clouds, accounting for two "frames" of animation are drawn once. The hardware offsets are leveraged to parallax the clouds and alternate their shapes. This was likely done because of the fillrate required to update this layer. @@ -957,7 +957,7 @@ \subsection{Per Level Renderer} \end{figure} -\subsection{Saving Further 68000 Cycles} +\section{Saving Further 68000 Cycles} If we look closely at Page 1 and 2, we see that the background is split. The alley is on Page 2 while the rest is on Page 1, which is surprising since no parallax effect exists (they are on the same plane). This reduces overdraw when the Page 1 cyclist crosses the screen and goes over the other cyclist in the back alley, saving a few CPU cycles. @@ -994,7 +994,7 @@ \subsection{Saving Further 68000 Cycles} -\subsection{The Rise ...} +\section{The Rise ...} SHARP kept on improving the series with better CPU (68030), more RAM (up to 12MiB) and even bigger HDD (up to 80 MiB). Peripheral manufacturers embraced the computer with extension cards covering anything users and programmers could desire. @@ -1032,7 +1032,7 @@ \subsection{The Rise ...} Often featuring a raytraced cover to boast the graphic capabilities of the SHARP marvels, each publication came loaded with software, originally on one, then two, and later three 5.25" floppy disks \cite{ohXarticle}! \end{trivia} -\subsection{... and Fall} +\section{... and Fall} Ultimately, SHARP updates were too timid to keep up. Even its most recent model sporting a Motorola 68030 CPU failed to remain competitive both in terms of price and performance. After six years without updating the video or audio pipeline, the 2D oriented design of the machine started to look dated. Other machines found themselves better fitted to embrace an era of 3D started by companies such as Silicon Graphics, 3DfX, and Verity. diff --git a/src/prog_z80.tex b/src/prog_z80.tex index a7511141..1fd16adf 100644 --- a/src/prog_z80.tex +++ b/src/prog_z80.tex @@ -31,10 +31,10 @@ \chapter{Sound System} \section{Processing Sound Samples} A wav file is a simple container with a header describing the content followed by a payload. Once the sampling frequency, bits per sample, and number of channels is retrieved, the PCM can be accessed. -\subsection{Constraint} +\section{Constraint} Artists should not produce stereo wavs since the CPS-1 is mono. Moreover, game developers should decide if they wish to use the OKI in high quality (7575Hz) or low quality (6060Hz) and all assets should use that sampling rate. Finally, since ADPCM compressed 12-bit sample to 4-bit samples, artists should provide 16-bit wavs. -\subsection{ADPCM Compression} +\section{ADPCM Compression} \index{ADPCM!Compression} Decompression is done in hardware by the OKI at runtime but the build system still has to compress assets appropriately. @@ -48,22 +48,22 @@ \subsection{ADPCM Compression} \lstinputlisting[style=CStyle]{src/code/pcm-dpcm.c} -\subsubsection{Compressing sample 1} +\subsection{Compressing sample 1} The first 16-bit sample has a value of \icode{960} which becomes \icode{60} in 12-bit. With the current step size at 16, ADPCM can only command a delta of + ( 16 + 16/2 + 16/4) = +28 which it encodes in a nibble \icode{0b0111}. The step size index is updated via the transitionTable[\icode{b111}] = 8. The current step size is \icode{34}. -\subsubsection{Compressing sample 2} +\subsection{Compressing sample 2} The second 16-bit sample also has a value of \icode{960} which becomes \icode{60} in 12-bit. Since the latest sample output was 28, ADPCM must somehow encode a difference of 60-28 = 32. ADPCM commands a delta of + ( 0 + 34/2 + 34/4) = +25 which it encodes in a nibble \icode{0b0011}. The decompressor will output 28 (its last value) + 25 = 53. We can see how the step size has adapted to the delta requested with only two steps. The step size index is updated via 8 (previous value) -1 (transitionTable[\icode{b011}]) = 7. Now the step size is \icode{31}. -\subsubsection{Compressing sample 3} +\subsection{Compressing sample 3} The third 16-bit sample has a value of \icode{950} which becomes \icode{59} in 12-bit. Since the latest sample output was 53, ADPCM encodes a difference of 59-53 = 6. ADPCM commands a delta of + (0 + 0 + 0) = 0 which it encodes in a nibble \icode{0b0000}. The decompressor will output 53 (its last value) + 0 = 53. The step size index is updated via 7 (previous value) - 1 (transitionTable[\icode{b000}]) = 6. Now the step size is \icode{28}. -\subsubsection{Compressing sample 4} +\subsection{Compressing sample 4} The last 16-bit sample has a value of \icode{160} which becomes \icode{10} in 12-bit. Since the latest sample output was 53, ADPCM encodes a difference of 10-53 = -43. ADPCM commands a delta of - (28 + 28/2 + 0) = -42 which it encodes in a nibble \icode{0b1110}. The decompressor will output 53 (its last value) - 42 = 11. The step size index is updated via 6 (previous value) + 6 (transitionTable[\icode{0b110}]) = 12. Now the step size is \icode{50}. @@ -157,7 +157,7 @@ \section{Programming the z80} Debugging a CPS-1 program can be a tedious task. A good starting point when encountering an issue is to read the linker \icode{.map} file which indicates where each symbol was placed. \end{trivia} -\subsection{Bootstrapping} +\section{Bootstrapping} A z80 starts fetching and executing instructions from address \icode{0x0000}. The bootstrap code \icode{crt0.s} (on page \pageref{z80_crt0}) is placed accordingly via directive \icode{.org 0}. The code immediately jumps to \icode{0x100} in order to skip the interrupt handler instructions. The z80 can work in interrupt modes 0, 1, or 2. Modes 0 and 2 are the most powerful and complex but they imply retrieving the ID of the interrupting peripheral by reading a byte on the data bus. This mechanism allows support of multi-device interruption. However in this case, it is overkill. The z80 uses Mode 1 which always makes the CPU jump to \icode{0x38} when interrupted. @@ -178,7 +178,7 @@ \subsection{Bootstrapping} -\subsection{z80 interrupt} +\section{z80 interrupt} \index{Interrupts!Programming z80} In order to interact with the latches properly but also be able to keep track of wall-time, the z80 needs to be interrupted regularly. Zilog's CPU does features a timer RFSH but it is intended for DRAM refresh (which the sound system does not feature anyway). @@ -189,7 +189,7 @@ \subsection{z80 interrupt} \lstinputlisting[style=CStyle]{src/code/z80/interrupts.c} -\subsection{Initializing variables} +\section{Initializing variables} To finish bootstrapping, \icode{crt0} makes sure initialized C variable values are set. The linker placed all values requiring initialization in a \icode{\_GSINIT} segment. By wrapping it with markers \icode{\_INITIALIZER} (src) and \icode{\_INITIALIZED} (dst), they can be copied easily. \lstinputlisting[style=Z80Style]{src/code/z80/initVar.s} @@ -202,7 +202,7 @@ \subsection{Initializing variables} % No initialization of BSS -\subsection{z80 Sound Driver} +\section{z80 Sound Driver} The sound driver is a simple loop which reads bytecode from our mini-vgm format to feed music notes, no-op on pauses, and forwards sample playback. @@ -225,7 +225,7 @@ \section{Back in the Days}\index{Back in the days!SFX/Musics} The Capcom Sound team. L-R: Yoko Shimomura, Yoshihiro Sakaguchi, Manami Matsumae, Masaki Izumiya, Yasuaki Fujita, Mari Yamaguchi, Minae Fujii, Toshio Kajino, and Isao Abe. Identity of table-man is unknown. -\subsection{Recruiting} +\section{Recruiting} Capcom actively recruited by taking advantage of 'careers days' to get graduates to come work for them. Many musicians emerged from music schools located in the Kansai region encompassing Kyoto, Osaka, and Kobe near Capcom headquarters. Several alumni of Osaka College of Music ended up working for Capcom, where they were able to compose music for a living while having the security of working for a large Japanese company. @@ -260,7 +260,7 @@ \subsection{Recruiting} -\subsection{Creative Process} +\section{Creative Process} Even though musicians were part of a "Sound Team", they usually worked alone on a game. They could pick projects based on availability\cite{sf2musics} but they were assigned to the next one immediately after they were done with the previous one. @@ -284,14 +284,14 @@ \subsection{Creative Process} -\subsection{Tools} +\section{Tools} Yoshihiro Sakaguchi, author of Mega Man music, explained what computer the musicians connected to their Yamaha keyboards. \begin{q}{Yoshihiro Sakaguchi\cite{yoko_shimomura_interview} } We worked on both the music and sound effects for Capcom’s games. We’ve got a centralized recording system setup on a PC-98, so that even if we’re writing music for different hardware, we can compose without needing to be able to program. \end{q} -\subsubsection{NEC PC-9800 series}\index{Computers!NEC PC-98} +\subsection{NEC PC-9800 series}\index{Computers!NEC PC-98} NEC entered the personal computer market in 1979 with its 8800 series. These machines, built around 8-bit z80 CPUs would later be known as "PC-88". @@ -311,7 +311,7 @@ \subsubsection{NEC PC-9800 series}\index{Computers!NEC PC-98} -\subsubsection{What Capcom used} +\subsection{What Capcom used} Because so many models were released, it is hard to tell for sure which PC-98 was used for a particular game. What can be done is to list the models released each year in order to get a rough idea. \begin{figure}[H] @@ -322,13 +322,13 @@ \subsubsection{What Capcom used} It is likely musicians working on CPS-1 titles were provided with computers from the Main series. Around that time, it would have been a computer based on a Intel 386 CPU with 50 MiB HDD. -\subsubsection{Proprietary technology} +\subsection{Proprietary technology} Despite their name, NEC's machine had nothing to do with the IBM PC. Due to its operating system, MS-DOS, lacking support for Japanese glyphs, Big Blue’s machines never managed to break into the Japanese market. NEC's PCs were named after what they were, \textbf{P}ersonal \textbf{C}omputers. -\subsubsection{C-Bus} +\subsection{C-Bus} The PC-98 uses a proprietary 16-bit C-bus instead of the IBM's ISA bus. BIOS, I/O port addressing, memory management and graphics output are also different. This architecture was both a moat that protected NEC from clone manufacturers (which plagued IBM in the USA) and a dungeon that prevented its machine from benefiting from the many peripherals built for IBM PCs. @@ -342,14 +342,14 @@ \subsubsection{C-Bus} -\subsubsection{Video chip} +\subsection{Video chip} Besides their proprietary bus, PC-98s were noteworthy for their, at the time, powerful graphic system. The heart of it was the High-Performance Graphics Display Controller 7220, more commonly known as $\upmu$PD7220. The PC-98 used two of them, both running 2.5MHz. One handled the 8 KiB VRAM for text while the other acted as a co-processor managing a 96 KiB VRAM framebuffer. The tandem was one of the first GPUs, presenting primitives to draw lines, circles, arcs, and character graphics. In its highest resolution mode the PC-98 reached an impressive 640×400 with 8 colors. It allowed Latin alphabetic, numeric and most importantly katakana characters. An optional ROM board added 3,000 kanji glyphs to the repertory. -\subsubsection{The end of PC-98} +\subsection{The end of PC-98} Although having specs far inferior to the Fujitsu FM Towns and Sharp X68000, NEC enjoyed tremendous success, selling 18 million units from 1982 to 1999. diff --git a/src/programing.tex b/src/programing.tex index 9175809d..6a100d5a 100644 --- a/src/programing.tex +++ b/src/programing.tex @@ -59,14 +59,14 @@ \section{CPUs Bootstrapping} \caption*{CPU Memory address space, ROM and RAM} \end{figure} -\subsubsection{Read-only} +\subsection{Read-only} Instructions for \icode{f} go in section \icode{.text} at offset 0. Since the linker knows both where the ROM will be mapped and the section offset in the ROM, it can inline calls to \icode{.text + 0}. This means \icode{0x0000} for both the z80 and the m68k. Const values \icode{c} and \icode{d} are read only so they go in ROM as well. These are grouped in section \icode{.rodata} apart from \icode{.text}. Access to these two symbols are respectively inlined with values \icode{.rodata + 0} and \icode{.rodata + 1}. -\subsubsection{Read-Write} +\subsection{Read-Write} Symbol \icode{a} is interesting because it is readable but also writable. The linker will have assigned a RAM address (starting at \icode{0xD000} on z80 and \icode{0xFF0000} on m68k). Since it is uninitialized, it will point to whatever is in the RAM when it started. Like \icode{a}, \icode{b} is readable and writable but it is initialized to value \icode{0}. The linker can make \icode{a} point to RAM and even group zero-initialized variables together in \icode{.bss} but setting the value to 0 cannot be done. This is something the bootstrap will have to resolve. @@ -89,19 +89,19 @@ \section{Systems Communication} That is a total of eight communication lines, but the dotted ones in the drawing are not programmable, lowering the task to understanding five APIs. -\subsection{m68k \begin{CJK}{UTF8}{min}→\end{CJK} CPSA and m68k \begin{CJK}{UTF8}{min}→\end{CJK} CPS-B} Communication occurs over the CPS-A and CPS-B registers. Additional draw commands are written by the 68000 to the GFXRAM where they are read by the CPS-A. All access to GFXRAM is arbitrated by the m68k bus protocol. +\section{m68k \begin{CJK}{UTF8}{min}→\end{CJK} CPSA and m68k \begin{CJK}{UTF8}{min}→\end{CJK} CPS-B} Communication occurs over the CPS-A and CPS-B registers. Additional draw commands are written by the 68000 to the GFXRAM where they are read by the CPS-A. All access to GFXRAM is arbitrated by the m68k bus protocol. -\subsection{z80 \begin{CJK}{UTF8}{min}→\end{CJK} YM2151} Communication occurs over the YM2151 registers which are mapped on the z80 bus. This access is arbitrated by the z80 bus protocol. +\section{z80 \begin{CJK}{UTF8}{min}→\end{CJK} YM2151} Communication occurs over the YM2151 registers which are mapped on the z80 bus. This access is arbitrated by the z80 bus protocol. -\subsection{z80 \begin{CJK}{UTF8}{min}→\end{CJK} MSM6295} Communication occurs over the MSM6295 registers which are mapped on the z80 bus. This access is arbitrated by the z80 bus protocol. +\section{z80 \begin{CJK}{UTF8}{min}→\end{CJK} MSM6295} Communication occurs over the MSM6295 registers which are mapped on the z80 bus. This access is arbitrated by the z80 bus protocol. -\subsection{m68k \begin{CJK}{UTF8}{min}→\end{CJK} z80} Communication between these two CPUs is not trivial. They both have their own bus protocol, run at different speeds, have different address spaces, and data widths. +\section{m68k \begin{CJK}{UTF8}{min}→\end{CJK} z80} Communication between these two CPUs is not trivial. They both have their own bus protocol, run at different speeds, have different address spaces, and data widths. Try to think of a design yourself with the following constraints. There are two 1 byte latches. On one side is a m68k running at 10MHz which can write in them but not read. On the other end is a z80, working at 3.579 MHz which can read but not write them. How can you make these two CPUs talk to each other reliably, making sure the stream of commands features no duplicates and no drops? -\subsection{Interrupts} +\section{Interrupts} \index{Interrupts!z80} \index{Interrupts!68000} Both the z80 and the m68k have interrupt systems. These are used to solve many problems and in particular the issue of communicating over the latches. @@ -129,7 +129,7 @@ \subsection{Interrupts} -\subsection{Back in the days}\index{Back in the days!General} +\section{Back in the days}\index{Back in the days!General} The system and conventions we just described allows for reliable data exchange but it does not give a semantic to the values in the latches. A developer is free to give any meaning to the latches since they control both the writer and the reader. Maybe you can even take a second to think how you would design this interface if you had to before we study how Capcom did it. @@ -151,7 +151,7 @@ \subsection{Back in the days}\index{Back in the days!General} What about the other latch? Street Fighter II only ever uses the first one. The other one is left unused. -\subsubsection{No sound driver can rule them all} +\subsection{No sound driver can rule them all} Given the capabilities of the communication system described above, it would be fair to assume all Capcom games used it. That would be wrong. @@ -164,7 +164,7 @@ \subsubsection{No sound driver can rule them all} If the sound team had to change the OKI layout, all IDS used by the m68k would be invalid. With a translation table, the sound team was able to make any change they wanted and keep their sound and music IDs backward compatible. -\subsection{Our sound driver} +\section{Our sound driver} The sound driver described in the next pages uses the same architecture as Capcom. It relies on interrupts on both sides. Besides being used for the latch communication, the interrupts also maintain a counter to pace the main threads. diff --git a/src/titlescreen.tex b/src/titlescreen.tex index 8e70044a..f0e1568f 100644 --- a/src/titlescreen.tex +++ b/src/titlescreen.tex @@ -69,7 +69,7 @@ \chapter{The First 16 Milliseconds} Before we look at how we fit it all in, let's first appreciate just how much we plan to do each time the screen is painted. -\subsection{Sprites} +\section{Sprites} The C64 makes 8 sprites available to us. A sprite is a special purpose graphical object that can be up to 24 pixels wide by 20 pixels high. We can place them wherever we want on the screen. They are the core of graphics programming and Iridis Alpha has dozens of them. But @@ -234,7 +234,7 @@ \subsection{Sprites} }\caption{The sprite used for painting the starfield. Only a part of the sprite is ever painted!} \end{figure} -\subsection{Waiting for the Beam} +\section{Waiting for the Beam} With our 'Raster Interrupt' handler set up as \icode{TitleScreenInterruptHandler} we're ready to react when the raster reaches line 16 on the screen. Since the screen is made up of 512 lines in total this will be along soon. @@ -287,7 +287,7 @@ \subsection{Waiting for the Beam} will refer to later when it is actually writing dots to the screen. If we write a stripe character to a particulas position in this \icode{SCREEN\_RAM} memory it will know to write it the corresponding position on the screen. -\subsubsection{Drawing the Stripes} +\subsection{Drawing the Stripes} So let's write some stripes to RAM! \begin{lstlisting}[caption=The 'stripe' character.] @@ -386,7 +386,7 @@ \subsubsection{Drawing the Stripes} \input{titlescreen/titlescreen_color_ram_stripes} -\subsubsection{Drawing the Text} +\subsection{Drawing the Text} Next up is to write out the title screen's text to \icode{SCREEN\_RAM}. This we do in \icode{DrawTitleScreenText} using a similar loop to \icode{DrawStripesBehindTitle}. @@ -463,7 +463,7 @@ \subsubsection{Drawing the Text} grid helps compare with our previous figures for \icode{SCREEN\_RAM} and \icode{COLOR\_RAM}.} \end{figure} -\subsection{Racing the Beam} +\section{Racing the Beam} Now we're ready to receive our ifirst beam. You may remember we set this to happen when the raster reached line 16: \begin{lstlisting}[caption=In \icode{InitializeSpritesAndInterruptsForTitleScreen}] @@ -622,7 +622,7 @@ \subsection{Racing the Beam} The next few lines of the routine do quite a bit of convoluted work to handle something called the \icode{spriteMSBXPosOffset} of the star. This is our complication. -\subsubsection{A Complication} +\subsection{A Complication} \begin{lstlisting}[caption= MSBXPos.. some'it.] ; Set the rest of the X position of the star ; if it's greater than 255. @@ -797,7 +797,7 @@ \subsubsection{A Complication} }\caption*{OR'ing \$73 and \$00 gives \$73.} \end{figure} -\subsubsection{Back to the Beam} +\subsection{Back to the Beam} Now that we've fixed the star's co-ordinates there's just two main things left to do before we're done with handling this raster interrupt. One is to set the color of the star. We do this using a look-up array where we get the color for the star per our current index and set it: @@ -841,7 +841,7 @@ \subsubsection{Back to the Beam} the gilby sprites.} \end{figure} -\subsection{Enter The Gilbies} +\section{Enter The Gilbies} \begin{figure}[H] \centering \includegraphics[width=12cm]{titlescreen/title25.png}% @@ -945,7 +945,7 @@ \subsection{Enter The Gilbies} \caption{Behold the gilbies.} \end{figure} -\subsection{Title Text} +\section{Title Text} \begin{figure}[H] \centering \includegraphics[width=12cm]{titlescreen/title57.png}% diff --git a/src/torus.tex b/src/torus.tex index d06b1f24..4d9515b3 100644 --- a/src/torus.tex +++ b/src/torus.tex @@ -24,7 +24,7 @@ \chapter{Another 16\textsuperscript{4} Tunes} \end{figure} -\subsection{Taurus:Torus} +\section{Taurus:Torus} \begin{figure}[H] { \begin{adjustbox}{width=11cm,center} @@ -83,7 +83,7 @@ \subsection{Taurus:Torus} \end{figure} -\subsection{Taurus/Torus Two} +\section{Taurus/Torus Two} \begin{figure}[H] { \begin{adjustbox}{width=11cm,center}