"Another World" Code Review

I spent two weeks reading and reverse engineering further the
source code of Another World ("Out Of This World" in North America). I
based my work on Gregory Montoir's "binary to C++" initial reverse engineering from the DOS executable.

I was amazed to discover an elegant system based on a virtual machine interpreting bytecode in realtime and generating fullscreen vectorial
cinematic in order to produce one of the best game of all time.

All this shipping on a 1.44MB floppy disk and running within 600KB of RAM: Not bad for 1991 ! As usual I cleaned up my notes, it may save a few hours to someone.

But...What source code ?!

The source code of "Another World' was never officially released nor leaked. Some people were so passionate about this groundbreaking game
that they reverse engineered the DOS executable.

This was possible partly because the binary was small (20KB). Why so small ? Because ANOTHER.EXE was not the game itself but just a virtual machine:

Hosting bytecode.

Providing system calls.

The bytecode performs all the game logic with its own opcodes but uses syscalls for "heavy" stuff like drawing, playing music, sound and managing assets.

To implement only the virtual machine for the target OS reduced the effort and the game was broadly ported to more than a dozen platforms:

1991 Amiga, Atari ST

1992 Apple IIGS, DOS, SNES, Mega Drive

1993 3DO

2004 GameBoy Advanced

2005 Windows XP, Symbia OS, Windows Mobile

2011 iOS

Every time only the virtual machine had to be compiled to the target OS: The bytecode remained the same !

Architecture

The executable is 20KB. It can be summarized as:

We can see four modules:

Virtual Machine: Maestro of the entire system.

Resource Manager: Loads resources from the floppy disk when the vm request them.

Sound/Music mixer: Makes noises upon request from the vm.

Renderer: Reads and Renders vertices upon request from the vm. Read vertices from the memory segments.

Upon startup, the executable sets the virtual machine's thread 0 program counter with 0x00 and start interpreting.
Everything is commanded by the bytecode after that.

Rendition explained

In the previous drawing we see three framebuffers. Two because Another World implements
Double Buffering"
in software....and a third one as a clever optimization:

The third framebuffer is used to compose the background of a scene only once and then reuse it frame after frame with a
simple memcpy:

In this video the legendary first level screen of Another World has been slowed down so we can actually see things being drawn.
Everything is drawn with polygons and pixigons. Overdraw is very substantial but since this is only generated once it is not so bad.

Trivia : This famous background is made of 981 polygons.

In order to visualize the big picture I have slowed down and rendered the three framebuffer + what is seen on screen:

We can see very clearly:

The double buffering with rendition occuring alternatively on the two front/back buffers.

The background buffer generated once and stored in the upper left buffer. It is then copied at the beginning of each frame.

If the background changes (as an example when the car stops) the background buffer is updated to save
even more space and time.

Another World Virtual Machine

Eric Chahi's webpage explains a lot about how the machine is structured.

In the code on github you can see how every opcode have been implemented.
All of them are pretty easy to understand except for the renditions ones. The trick is that the polygon segment source where the vertices
should be read is embedded with the opcode id.

Finally a few screenshots from the vm bytecode editor (Called "script editor" by Eric Chahi):

You can see how the label have been lost: setvec 21 nag1 sets the thread 21 instruction counter at "nag1" label offset.
In the bytecode we can only see a hardcoded offset.

Opcode cases

In the following drawings we can see the virtual machine calling an opcode that is actually a system call to
the resource manager in order to load the four memory segments. This happens typically at the beginning of
a game part (The entire game is made of 10 game parts):

In the next drawing the opcode is also a systemcall to the renderer asking to draw and fetch vertices. The rendition
opcode are a bit more complex because they contains where to read the vertices from. To set the target framebuffer is an
independent opcode altogether:

Note: Whether the render should read vertices from the cinematic polygon segment or the animation segment is encoded with the opcodeId.

Resource Management

Resources are identified by an unique integer id. Upon startup the resource manager opens MEMLIST.BIN and
get records as follow:

Memory Management

Like all games from the 90s no memory is allocated during gameplay. Upon startup the game engine grabs 600KB of memory
( anybody remember DOS 640KB conventional memory here ?). Those 600KB are used as a stack allocator:

Free memory: The memory manager has the capability to unallocate one step back OR free the entire memory. In practice the entire memory
is freed at the end of each 10 game parts.

Trivia : Originally the entire 600KB was storing bytecode and vertices. But after two years of generating
the backgrounds with polygons/pixigons the game was still far from being done.
In order to speed up the development speed Eric Chahi decided to integrate a hack in his beautiful architecture (at a performance cost):
The resource manager can load background bitmap from the floppy disk to the background buffer (void copyToBackgroundBuffer(const uint8 *src);).
Hence 32KB (320x200/2) are reserved at the end of the conventional memory.

Trivia : This hack was exploited for the release of Another World for Windows XP in 2005. All background were hand drawn and loaded
directly from hard-drive without using the renderer and its pixigons:

Purist corner

If you are a purist and really want to play the original way, Another World works like a charm in DosBOX:

Or you can run the windows XP version. I recommend to get the Collector's edition since it
feature a lot of additional informations, among them the techical notes from Eric Chahi:

One more thing

I worked on the code a lot, making it simpler to understand. You can see an example of how much clearer it is now.