wayne piekarski Modifying Microsoft Flight Simulator 4 to run on three immersive monitors

 
Share Blog article posted June 2017

Modifying Microsoft Flight Simulator 4 to run on three immersive monitors

How I modified DOSBox and the original Microsoft Flight Simulator 4 from 1989 to run on my immersive multi-display flight simulator set up.

Update: June 2019 I now have a project page describing the many plugins and apps I have written for X-Plane and home cockpits.

FS4 from 1989

Back in 1989, I was introduced to Microsoft Flight Simulator version 4. I thought it was incredible that I could fly around in a 3D environment, and this was something that got me interested in 3D graphics. However, I always had trouble flying the plane, because I only had a 14 inch CRT monitor, and you had a small field of view out the front of the plane. Since you couldn't see left or right, you were missing important flying cues, and it made flying much more difficult than in a real plane. I've seen some people try to use joystick hats or head trackers, but those always require you to look forwards even if you are virtually looking another direction - it is not intuitive for your brain to understand. So at the time I realized this was a problem, and I'd seen commercial immersive flight simulators in books, but they were too expensive, so I had to wait a few decades for things to become a bit more affordable! However, recently in 2017 I built my own immersive indoor flight simulator, using three large 42" televisions and X-Plane 11. This provides a much more realistic experience, and it is finally the flight simulator I was always looking for.


Microsoft Flight Simulator 4 from 1989, running at 640x350

DOSBox emulation in 2017

I'm a bit of a fan of emulators, so I used DOSBox on Linux to start up Microsoft Flight Simulator version 4 on a big monitor. It is amazing how low-res 640x350 is when displayed on a large 1920x1080 display, although you didn't notice it as much on a 14 inch CRT, which is smaller than many laptops these days. DOSBox supports emulating old analog PC joysticks, so I was able to configure FS4 to use my yoke and throttle. I always wanted to have one of those as a kid as well, and it worked great. While there wasn't much for graphics, it worked with a nice smooth frame rate, and it was pretty cool.

But then I started to think about how even better it would be to run FS4 on all three monitors, just like I'm doing with X-Plane now. In 1989, computers only supported a single small display, and definitely not three of them! The concept of using a cluster of machines was done in expensive commercial simulators even back then, but FS4 didn't support anything like that. FS4 supports the ability to do multiplayer over an RS-232 cable. However, there is no way to set the camera viewpoint to the remote aircraft, so that was not going to be a help in building a cluster. There was nothing else built into FS4 that could support what I wanted, and DOS machines back in 1989 didn't support networking or anything else either. All seemed hopeless with this ancient software.

DOSBox memory dumps

Since I'm running the whole thing within a DOSBox emulator, I now have access to networking and modern tools to try and achieve what I want however. DOS games were very simple in that they didn't use much of an operating system, and wrote everything directly to unprotected memory. I figured that the developer would have written the X Y Z and Heading Pitch Roll values to some kind of struct in a consistent location in memory. If I could work out the memory location of where the aircraft state is stored, I could intercept this with DOSBox, send UDP packets over the network to other DOSBox instances, and write to those same memory locations.

When you dig around in the DOSBox source code, there is a simple 16mb array of 8-bit chars named MemBase in memory.cpp. That is the entire memory space of the DOS machine, and only the first megabyte is actually used. So I started up FS4, paused the game, and attached gdb to the live process and saved out a copy of the MemBase memory array. Then I entered slew mode, which allows you to reposition the aircraft at whatever coordinates and orientation that you want. Then you use gdb to again save the MemBase memory array. I noticed that FS4's coordinate system seemed to have a maximum of 65535 so it was probably using 16-bit integers, and it didn't have support for floating point arithmetic since that was not common in 1989. So I changed the coordinates to values like 0, 1, and 65535, in the hope they would be more obvious in the memory dump as 0x00, 0x01, and 0xFF. I was also able to reload the dump file back into memory, and I could successfully move the viewpoint back to where it was. So in theory, this could work.

I used the Linux cmp command to compare the binary dump files. You would be surprised how little actually changes between the dump files, and so I went through the differences to see if I could spot anything. I didn't find any of the 0x00, 0x01, or 0xFF changes that I was expecting, which seemed strange. After studying lots of diffs, I realized that FS4 must be using a different encoding scheme than just raw integers. I needed a new strategy.

I decided to try just fuzzing over the memory locations that did change to see which one would have an effect. I modified DOSBox to add the ability to receive commands from standard input, and wrote 0x00 over those locations one-by-one with a delay between them. FS4 would crash and go crazy for some values, so I would restart it and keep looking for the desired effect. Eventually I found that the viewpoint would change drastically when I wrote to 0x28D0. Ahah! I had found a memory location that changed the viewpoint, but the encoding was super weird and didn't work the way I expected. Writing zeros moved the aircraft to +16384 instead of +0 or +32767.

North and East encoding

After trying a whole bunch of different values, I worked out how North and East coordinates are represented. The first two bytes are the fractional component, and the second two bytes are the integer component. Intel x86 is little endian, so the least significant byte goes first. Here are some examples of raw memory locations and how they map to coordinates:

0xFFFF = +16383d
0x0000 = +16384d
0x0101 = +16641d
0x1010 = +20496d
0x2020 = +24608d
0x0020 = +24576d
0x2000 = +16416d

0x0030 = +28672d
0x0040 = +32768d
0x0050 = +36864d
0x0060 = +40960d
0x0070 = +45056d
0x0080 = +49152d
0x0090 = +53248d
0x00A0 = +57344d
0x00B0 = +61440d
Here you can see that 0x00C0 is where the origin of the coordinate system is!
0x00C0 = +00000d
0x00D0 = +04096d
0x00E0 = +08192d
0x00F0 = +12288d
0x00FF = +16128d

The fractional part made a bit more sense, you can tell it is just the 16-bit value that is then later divided by 65536. Here are some examples:
0xFFFF = 0.9999
0x8080 = 0.5020
0x00FF = 0.9961
0xFF00 = 0.0039

Angle encoding

Now that I understood what was going on, understanding the angular values was much easier. These are also using an integer representation, where the first byte is a fraction divided by 256 and added to the main angle. The second byte is the most significant part, and there are 256 units in a full circle. Here are some examples of the most significant value:

0x00 = 0 degrees
0xA0 = 180 degrees
0xFF = 358.60 degrees

Memory layout

It turns out that the North, East, Altitude, Heading, Pitch, Roll values are all stored together in a contiguous memory area from 0x28D0 to 0x28E1. Here is a breakdown of every byte and what it does:
OffsetAxisValueOrder
0x28D0EastFractionLSB
0x28D1EastFractionMSB
0x28D2EastIntegerLSB
0x28D3EastIntegerMSB
0x28D4AltitudeIntegerLSB 1
0x28D5AltitudeInteger2
0x28D6AltitudeInteger3
0x28D7AltitudeIntegerMSB 4
0x28D8NorthFractionLSB
0x28D9NorthFractionMSB
0x28DANorthIntegerLSB
0x28DBNorthIntegerMSB
0x28DCPitchFractionLSB
0x28DDPitch256 units to a circleMSB
0x28DERollFractionLSB
0x28DFRoll256 units to a circleMSB
0x28E0HeadingFractionLSB
0x28E1Heading256 units to a circleMSB

Synchronizing over the network

Given that there are exactly 18 bytes of memory from 0x28D0 that contain everything I need, it is pretty easy to send this to another machine. I created my own thread in DOSBox that uses memcpy() at a 10 msec interval to capture the state of this 18 bytes of memory. In theory, this is unsafe without synchronization against the main emulator thread, but it worked well enough for this experiment. I then take the 18 bytes of data, and transmit it as two UDP packets to the localhost network interface with different port numbers. I tried using broadcast packets, but it is not possible to have two processes on the same machine listening on the same port number. After implementing the receiver code in two separate DOSBox instances, I have now managed to do a one-way push of those 18 bytes from one process to two others. Now they are perfectly synchronized, and you see three FS4 instances all showing the same viewpoint!

Configuring the viewpoint

FS4 has keyboard shortcuts that allow you to take a viewpoint and make it look left or right. So you can manually set the left and right DOSBox instance running on each monitor to look in the correct direction. The remaining challenge is configuring the field of view, which can only be varied with keyboard presses, and not as a specific angle. It turns out that FS4 has the ability to do both large and fine changes to the field of view, but we need to work out what that is. The solution is to use slew mode and adjust the orientation of the aircraft so that Heading, Pitch, and Roll all have significant values - you can now see the horizon has large gaps in it across the monitor edges. But if you gradually apply the same zoom in/out controls to each monitor, one step at a time, you will eventually see the horizon become a straight line, and now you have the correct field of view programmed in.

Automatic startup

While it is possible to move the windows to the correct monitor and then use the keyboard to make all the changes to the viewpoint, this is very tedious and it is easy to make mistakes. I wrote a script using wmctrl and xdotool which allows me to automate the placement of the windows and then to send the necessary keystrokes. Now everything starts up as quickly and possible, and it is very reproducible every time I start things up.

Video

This video shows the synchronization taking place across the three monitors, and you can see that as the aircraft flies around, everything works just as well as it works on X-Plane 11 right now. This is the flight simulator I always wanted as a kid, although it is 28 years late! But it is so much fun to see software written 28 years ago that was never intended to be run this way, actually work on an immersive flight simulator like this!

Source code

I made a number of changes to DOSBox to implement my own debugger so I could do the fuzzing more easily, and then to implement the UDP transmitter and receiver. I also added a new stretch mode that will take any DOSBox window and make it fit exactly the desired dimensions, even if it breaks the aspect ratio. While there are many forum postings claiming this should work, it never worked and the source code did not seem to not allow it either. So with my patches, now I can ensure there are no seams between the windows, and I can pick any resolution that I want. However, the default 640x350 used by FS4 most closely matches the aspect ratio of my 1920x1080 monitors, and the round instrument dials are still circular. You can use the 800x600 driver that came out in the early 1990s, but the aspect is not as nice.

You can download my patched version of DOSBox here on github. There is a script apt-get-deps that will download all the necessary dependencies for an Ubuntu 16.04 machine. You will need to provide your own FS4 directory with binaries of the game. I still have my old disks from when I bought FS4 in 1989, but you can also find it on abandonware sites on the Internet as well. There is great web site PlanetMic where there are still fans playing the old FS4 on modern PCs, I hope they enjoy my project!

Photos


Share Blog article posted June 2017


Google Developer Advocate 2014-2023


X-Plane plugins and apps for flight simulation


IoT water meter monitoring


IoT computer vision monitoring


Tiny and cheap offline Wikipedia project 2017


Outdoor augmented reality research
Tinmith 1998-2007


Outdoor augmented reality 3D modelling
Tinmith 1998-2007


Outdoor augmented reality gaming
ARQuake 1999-2007


Scanned physical objects outdoors
Hand of God 3D 2006


Google Developer Advocate 2014-2023


X-Plane plugins and apps for flight simulation


IoT water meter monitoring


IoT computer vision monitoring


Tiny and cheap offline Wikipedia project 2017


Outdoor augmented reality research
Tinmith 1998-2007


Outdoor augmented reality 3D modelling
Tinmith 1998-2007


Outdoor augmented reality gaming
ARQuake 1999-2007


Scanned physical objects outdoors
Hand of God 3D 2006


Contact Wayne Piekarski via email wayne AT tinmith.net for more information

Last Updated 2024