At last! I've completed my disassembly of OutRun's slave CPU code. This was by far the most difficult part of the project to date. First, a quick summary of how the road data is stored.
The road data is split into three main components:
1/ The path that the road takes. This is stored as a set of words. Each word ultimately represents the x change of the next road segment, and length of that segment. This data is parsed by a series of functions that interpolate the data and create a nice smooth curve, dependent on the adjacent road segments.
It should be noted that this data does not control the width of the road, the height of the road or how many road layers are enabled.
From what I've seen each stage has a unique path and no data is reused. However, the road split at the end of each segment is reused and the data is mirrored on the x-axis to create the road split.
2/ The height of the road segment. This is divided into a series of segments. Multiple segments are applied to any stage and are reused between stages.
3/ The width of the road segment. This is actually controlled by the Master CPU. I've disassembled the relevant code, but will revisit it at some stage soon.
Finally, the x1, x2 co-ordinates of the road segment are used by the sprite hardware and the scenery positioned on the level.
Interestingly, this means that Outrun's road layer is very dynamic. It's possible to swap the sprites from one stage, with the road data from another. And it's easy to change the height mapping of any point of a level. Very little is hardcoded in terms of screen positioning, and the final world is very much generated in realtime. It's easy to see why an entire 68000 CPU was dedicated to this one task.
As a test of my understanding, I've already converted some of the functions from assembler to a quick java utility. This utility can output the path (point 1 of the list above) of any stage of the game as a CSV file that can be represented by Microsoft Excel. So now it's easy to create an accurate visual map of all the levels, to aid players of the game. Admittedly, once I amend this tool to take the width into account, it will be more useful.
Here is a link to an example from Stage 1 (coconut beach). As mentioned, this map doesn't contain the road split information at the end of the level.
Finally, pleased and amused that people have found the blog interesting - most unexpected. Keep the comments coming.
The road data is split into three main components:
1/ The path that the road takes. This is stored as a set of words. Each word ultimately represents the x change of the next road segment, and length of that segment. This data is parsed by a series of functions that interpolate the data and create a nice smooth curve, dependent on the adjacent road segments.
It should be noted that this data does not control the width of the road, the height of the road or how many road layers are enabled.
From what I've seen each stage has a unique path and no data is reused. However, the road split at the end of each segment is reused and the data is mirrored on the x-axis to create the road split.
2/ The height of the road segment. This is divided into a series of segments. Multiple segments are applied to any stage and are reused between stages.
3/ The width of the road segment. This is actually controlled by the Master CPU. I've disassembled the relevant code, but will revisit it at some stage soon.
Finally, the x1, x2 co-ordinates of the road segment are used by the sprite hardware and the scenery positioned on the level.
Interestingly, this means that Outrun's road layer is very dynamic. It's possible to swap the sprites from one stage, with the road data from another. And it's easy to change the height mapping of any point of a level. Very little is hardcoded in terms of screen positioning, and the final world is very much generated in realtime. It's easy to see why an entire 68000 CPU was dedicated to this one task.
As a test of my understanding, I've already converted some of the functions from assembler to a quick java utility. This utility can output the path (point 1 of the list above) of any stage of the game as a CSV file that can be represented by Microsoft Excel. So now it's easy to create an accurate visual map of all the levels, to aid players of the game. Admittedly, once I amend this tool to take the width into account, it will be more useful.
Here is a link to an example from Stage 1 (coconut beach). As mentioned, this map doesn't contain the road split information at the end of the level.
Finally, pleased and amused that people have found the blog interesting - most unexpected. Keep the comments coming.
2 comments:
I am surprised that there is only one value for the path the road takes. Does the road have a single vanishing point and all lanes point to it? Does it really calculate a curve for every lane in real time?
How are the number of lanes, spacing information and scenary data for the section stored?
e.g. in the picture shown there are 3 lanes, a bit of land with palms on it and 3 lanes on the other side but on other segments there are just 3 maybe even 4 lanes.
I wonder if they had access to the original source code for the Saturn and GBA Versions.
The path is represented in data as four separate values, but ultimately a single point is derived from these.
The number of lanes is stored separately and set by CPU 1. So each chunk of road will be assigned a width, and then the code gradually alters the width as necessary. A width beyond a certain value automatically splits the road into two lanes.
The scenery I will cover in another post at some point :)
The Saturn version is definitely converted straight from the arcade source code. If you load the Saturn binary into a hex editor you can even see strings relating to the physical moving motor hardware (which obviously isn't available on a Saturn conversion!)
The GBA version, even if they had access to it, wasn't used directly.
Post a Comment