Software_Porting_Methods


A primary part of the software aspect to this project is porting existing software to use the Vectrex display via the PiTrex hardware and associated vector drawing library. Many open-source games have been identified in the Software_Ports page as being potentially suitable for this, as well as emulators such as MAME that promise an ability to run a number of closed-source games originally written for vector platforms.

Different challenges are presented in porting some of these programs, and here a number of methods for doing this are proposed. Different software may in some cases better suit different methods of porting, though at present only the "Direct Software Modification" method has been attempted.

Also see Software_System_Functions for notes on non-display functions that may be difficult to provide in the Bare-Metal environment.

Direct Software Modification

The software listed in the Software_Ports page all uses some form of internal vector coordinate representation of objects drawn on screen. By replacing the internal routines, or calls to external libraries, that process this vector data, with calls to the vector drawing library, it is possible to direct the display to the Vectrex instead of a software renderer.

Additionally, the methods used by the software to read inputs must be replaced with the functions in the vector drawing library for use with the Vectrex controller. Replacement of any sound effects with sounds generated by the Vectrex Programmable Sound Generator (PSG) would also be desirable.

Problems

  • Some significant time required to modify all affected parts of the original code, in each piece of software to be ported.
  • Software must call the drawing routines frequently enough that the Vectrex display is updated without visible flickering. Software vector renderers will keep drawn lines in video memory indefinitely without repeated refreshes, and some software may take advantage of this to pause execution of the main loop, eg. while waiting on a user input. Such cases may require significant redesign of the program flow.
  • Recalibration of the Vectrex display must be performed frequently using the WaitRecal routine to avoid drift. A suitable place in the program flow must be found for WaitRecal to be called, where it will be performed frequently enough between drawing operations. If such a location is not available, the recal timer may need to be checked prior to every vector drawing operation, with the recalibration routine being performed where required (making sure to reposition from zero even if drawing a joined line).
  • Bitmap graphics must be replaced with vector graphics, unless hidden or somehow drawn using the raster drawing method used for text by the Vectrex.

Implementations

MAME

This method has been used previously by a number of different projects adapting MAME for vector displays or laser projectors.


The source file "src/vidhrdw/vector.c" ("src/emu/video/vector.cpp" in the current version of MAME) is the basis for such modifications, either by directly modifying it to include instructions that send output to the vector control device (Trammell Hudson, Openlase-MAME, LazyMAME), or using the "vector_register_aux_renderer" function to enable passing of the vector list generated by vector.c to the new hardware-specific code, and thereby maintaining the portability of the original code (VectorMAME).

The latter method is preferred by the MAME developers, and should also allow easier integration with any later upstream changes to vector.c.

Conventionally, vector.c creates a bitmap image from the vector data provided by the emulator process, suitable for display on a raster monitor, and this is used as the output to the graphics card or display library. This functionality can optionally be disabled if a "vector_aux_renderer" is used.

Source code is available for these previous adaptations of MAME for vector output:

  • VectorMAME outlink adaptation applying to the MSDOS build of MAME (which has since been discontinued). This vector modification was for a time included in the official MAME sources. Code outlink for processing the vector list from vector.c is in src/msdos/zvgintrf.c. A makefile for only building the code required to emulate vector games is also included outlink.
  • Trammell Hudson outlink adaptation for serial data output from vector.c under Mac OSX. This was used successfully with a DAC board to run MAME on a modified Vectrex outlink, though the method was not approved for integration into MAME, for reasons stated at the Github link.
  • Openlase-MAME outlink adaption for vector output using the OpenLase outlink laser projector library. Similar to Trammell Hudson's approach.
  • LazyMAME outlink is an earlier laser projector mod. It doesn't use the preferred "vector_aux_renderer" method for extracting the vector data either.

For the PiTrex project, Graham Toal has been working on a modification outlink to an alternative version of MAME, called AdvanceMAME, which forked from an old version of the MAME source code. The aim is to output vector data to the Vectrex using the "vector_aux_renderer" method. Difficulties have been encountered in allowing for the repeated recalibration processes required for display with the Vectrex's DAC hardware.

MAME is also difficult to port to the Bare-Metal environment where most initial PiTrex development is currently focused, due to its extensive OS dependencies and general complexity (no existing Bare-Metal port for the Raspberry Pi is known to be available). Focus for emulation has currently shifted to simpler emulators for vector arcade games that share the same manufacturer/architecture. Static binary translations are also preferred for their easier adaptation to the Vectrex hardware (special handling of display features to suit the Vectrex screen, substitution of sounds with ones that can be played via the Vectrex PSG (Programmable Sound Generator)), as well as their faster execution on the Pi.

Rather than adapting it to run in the Bare-Metal environment, further work on MAME may be left until display performance while running Linux is improved (if possible).

External Library Substitution

Most software in Software_Ports uses the vector drawing functions of an external graphics library. Rather than modifying the each piece of software, the functions used from the graphics library could be replaced with functional equivalents using calls to our vector drawing library. The modifications therefore required to the original code may be little more than changing the includes.

Such libraries commonly also handle user inputs, so this can also be used for adapting to the Vectrex controller.

Bitmap graphics might be automatically substituted with vector graphics prepared manually, or even vectorised on-the-fly. The latter method might be used for the whole screen where software sends full pre-rendered bitmap frames to the graphics library instead of specific drawing instructions (looking at you, MAME). See Framebuffer Vectorisation below for more details relevant to this.

Problems

  • Software must call the drawing routines frequently enough that the Vectrex display is updated without visible flickering. Software vector renderers will keep drawn lines in video memory indefinitely without repeated refreshes, and some software may take advantage of this to pause execution of the main loop, eg. while waiting on a user input. Such cases may require significant redesign of the program flow.
  • Recalibration of the Vectrex display must be performed frequently using the WaitRecal routine to avoid drift. A suitable place in the program flow must be found for WaitRecal to be called, where it will be performed frequently enough between drawing operations. If such a location is not available, the recal timer may need to be checked prior to every vector drawing operation, with the recalibration routine being performed where required (making sure to reposition from zero even if drawing a joined line).
  • A buffer of past write operations would have to be kept, because the software will assume that drawn lines will stay visible indefinitely without being redrawn. The library should check whether the previously drawn lines need to be refreshed at every opportunity, such as at the beginning of every new draw operation. If a program does spend long periods of time without calling the graphics library at all, it will still need to be modified to avoid this.
  • As well a erasing the contents of the entire screen (equivalent to clearing the buffer described in the last dot point), the software may use functions for drawing filled shapes, in the same colour as the background, to clear only sections of the screen. Allowing for this will complicate the design of the buffer, as single lines may be split into two, and also require calculations to be performed on every line in the buffer to determine whether, and if so where, each line intersects with the cleared area.
  • The line drawing functions outlink in the SDL library were not added until SDL V.2, which pre-dates most of the games in Software_Ports that use it. Therefore SDL games use their own routines for drawing lines on the raster display, and need to be modified directly to redirect these instructions to the vector drawing library.

Implementations

SVGAlib-Vectrex

A bare-bones translation library outlink has been written to allow SVGAlib outlink games to be ported to the PiTrex using the vectrexInterface library for display output and reading Vectrex controller inputs in place of the keyboard.


The two SVGAlib vector Linux games that have been identified on the Software_Ports page have been ported outlink using this library. These are Zblast and Xhyperoid.

X-Vectrex

X is more complicated than SVGAlib, designed with a client-server architecture to allow for an application to run on a different computer (connected via a network) to the one handling the display and user input. It relies on the concept of buffering for input and output, which is better suited to a multi-process implementation than the single-process result of making a translation library in the style of svgalib-vectrex. The latter will inevitably involve some tricks, probably tailored to the typical usage within vector games.

X Server Driver
Another option is to keep the client software as-is and modify an X server so that it uses the Vectrex display and controller inputs. However X is intended only for drawing to raster displays, even though the server accepts some requests that use vector data to draw lines, so this doesn't seem that it would be as easy as just writing a new graphics driver for the X server. The Wikipedia page outlink also indicates that vector data is converted to raster in the "Device Independent X" (DIX) part of of the X Server code - separate from device drivers in "Device Dependent X" (DDX). X includes support for "extensions", which are used for optimising display - could this system easily intercept the Vector data?

Stop press! Read further down the Wikipedia page and you find out that XFree86 sneeked a layer in between DIX and the DDX, called "XFree86 Acceleration Architecture" (XAA). For improved performance this allows some drawing features to bypass the rasterisation routines in DIX and go straight to the hardware 2D engine outlink in compatible graphics cards. See "/hw/xfree86/xaa/XAA.HOWTO", section 2.3 "Solid Lines", in the X.org Server source for documentation. "void SubsequentSolidTwoPointLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2, int flags)" is the function best suited for redirecting output to the vector drawing library. Dashed lines are also supported (section 2.4) in a way that might well suit the Vectrex method of dashed vector drawing (as a guess: X _might_ use this for displaying bitmaps in some cases).

Glamor outlink is a new system in development for use with OpenGL, odds are that line drawing is part of that, but documentation seems to be very light.

These acceleration systems are enabled by use of a hardware driver that implements one of them, so in contradiction to what was said before it may be possible to write a PiTrex driver for the X.org (or later XFree86) Server. The Pitrex driver would simply send vector commands to the Vector drawing functions (WaitRecal called when the refresh timer has expired, as with svgalib-vectrex), and ignore any bitmap data sent its way (or better yet, optionally vectorise it).

"xorg-input-joystick" is an existing X.org input module for controlling the mouse with a joystick - should be useful for adapting mouse-based games to the Vectrex controller. I haven't been able to find the low-level code for this in the X.org sources. At the other extreme there seem to be lots of keyboard drivers, documentation for one is in "hw/dmx/doc/html/lnx-keyboard_8c.html".

In any case, keeping a Client-Server architecture for X games running with the PiTrex will be incompatible with the bare-metal environment due to the need for two separate processes to be run, unless maybe two CPU cores are available or the client can be run on another computer (these solutions still leave challenges regarding inter-process communication). Perhaps then this approach should be left at least until after a PiTrex driver for Linux capable of reliable vector display is available.

Xlib Translation Library
Xlib "<X11/Xlib.h>" is the primary library used to build an X client program, although various functions are also commonly used from other X11 headers that can be optionally included. As with SVGAlib-vectrex, the aim here is to provide equivalents for all of the functions in Xlib, though for practicality the initial version should be limited to substituting only for those Xlib functions called by the games that will be ported. No server will be used, so plenty of settings can be ignored, and all the I/O will be straight to the Vectrex via the vectrexInterface library.

Hundreds of Xlib library functions are used between all of the known Vector games using X, many of which return structures. Most of these serve no equivalent function in the substitution library. Instead of manually substituting all of these with dummy functions that do nothing except returning a valid value where required, a Bash script has been written to process the output of Exuberant Ctags outlink, in combination with the Xlib source code, in order to automatically generate a complete set of dummy functions for Xlib. After which manual substitution should only be required for the relatively few functions that have equivalents in the vectrexInterface library. Global variables and structures will also have to be manually handled in the translation library where values from them are used in games.

References


Framebuffer Vectorisation

The OpenLase project developed a fast (unlike libraries such as Potrace, used by SpriteTM to pre-compute the vectorised frames for the "Bad Apple" Vectrex video) vectorisation routine outlink in C that was used for real-time vectorisation of raster (though vectory looking) video for display with a laser projector outlink. The Linux framebuffer outlink can be used as an output for raster graphics data by both X and SDL, and provides the raw graphics data for reading by user software. A program could be written that regularly reads a frame from the framebuffer, vectorises it using the fast OpenLase vectoriser, and draws the display on the Vectrex. By running this at the same time as the software that would otherwise need to be ported, the display would be visible on the Vectrex.

The intention of the Linux framebuffer interface is to allow graphics card drivers to be written as kernel modules. Therefore a better approach may be to write a kernel driver module that does the vectorisation and writing to the Vectrex, and this might ensure more accurate timing of the screen refresh rate.

Similarly, it might be possible to write a driver for the graphics library instead of the Linux kernel, so that it runs a little more efficiently. The author's looking through the Xorg sources lead to much confusion, but a general suspicion that this will not be possible with just the addition of driver code, because other parts of the library seem to write to the video RAM directly, not through the specific driver code. Those who actually have a clue about graphics programming might come to a different conclusion though.

The advantage of this approach is that it requires no modification to the software code. Therefore closed-source software available compiled for ARM could also be used. PC software with support for the X windowing system could be run on a PC with the display using the X server running on the Pi over a network. Emulators for raster platforms could also be run, eg. DOSbox.

See fb2png outlink for an example of reading the framebuffer, including all of the settings that make sense of the raw data. In theory just replace the PNG conversion with vector conversion using the OpenLase routine, then send the output to the vector drawing library.

Problems

  • Obviously performance would be a major issue. This would vary in proportion with the resolution of the framebuffer, and the rate at which the Vectrex display is updated. The first question is therefore what are the minimums for these values, while avoiding inaccurate vectorisation and visible flickering.
  • Accuracy and efficiency of the vector data obviously won't be as good as accessing the original vector coordinates used within the software. The OpenLase "Bad Apple" video does look very nice, though it's not clear what video resolution or computing power was used.
  • This method is not applicable to use in the bare-metal environment.