summaryrefslogtreecommitdiff
path: root/doc/porting.htm
diff options
context:
space:
mode:
Diffstat (limited to 'doc/porting.htm')
-rw-r--r--doc/porting.htm1316
1 files changed, 1316 insertions, 0 deletions
diff --git a/doc/porting.htm b/doc/porting.htm
new file mode 100644
index 0000000..1dd3725
--- /dev/null
+++ b/doc/porting.htm
@@ -0,0 +1,1316 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Type"
+content="text/html; charset=iso-8859-1">
+<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
+<title>viDOOM - Free Software DOOM editor</title>
+</head>
+
+<body>
+
+<h1 align="center">Porting viDOOM</h1>
+
+<p>This document is provided in case anyone wishes to port viDOOM
+to a new platform. Below is an indication of what OS dependent
+routines must be provided and what configuration needs to be
+done. It is requested that any ports are also released as Free
+Software.</p>
+
+<ul>
+ <li><a href="#MAKEFILE">Makefile configuration</a></li>
+ <li><a href="#INI">INI File</a></li>
+ <li><a href="#FILES">Files</a></li>
+ <li><a href="#MAIN">Main entry point</a></li>
+ <li><a href="#GFX_H">Graphics and input</a></li>
+ <li><a href="#PLATGUI_H">Platform GUI</a></li>
+ <li><a href="#FILE_H">File interface</a></li>
+ <li><a href="#MEM_H">Memory allocation</a></li>
+ <li><a href="#RUNCMD_H">External command execution</a></li>
+ <li><a href="#VSTRING_H">String functions</a></li>
+ <li><a href="#INSTALLATION">Installation script</a></li>
+ <li><a href="#DOCUMENTATION">Documentation</a></li>
+</ul>
+
+<hr>
+
+<h2><a name="MAKEFILE"></a>Makefile configuration</h2>
+
+<p><strong><u>makefile</u></strong></p>
+
+<p><a name="MAKEPLAT"></a>Set the variable <strong>MAKEPLAT</strong>
+to the name of your platform, eg.</p>
+
+<p><tt>MAKEPLAT=</tt><em><tt>OS</tt></em></p>
+
+<p>You will then need to create a matching file the <strong>make</strong>
+subdirectoy called <em>OS</em>.cfg. Also all the OS dependent C
+source should go into a subdirectory defined in the following
+make config file by the <strong>PLATFORM</strong> variable. See
+the <a href="#FILES">Files</a> section for an overview of these
+files.</p>
+
+<p><a name="MAKE_CONFIG"></a><strong><u>make config file</u></strong></p>
+
+<p>The following values need to be set in the file <strong>make</strong><em><strong>/OS</strong></em><strong>.cfg</strong>:</p>
+
+<table border="1" cellpadding="3">
+ <tr>
+ <td valign="top" nowrap><strong><tt>CC</tt></strong></td>
+ <td valign="top">Set to the name of the C compiler.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>LD</tt></strong></td>
+ <td valign="top">The name of the linker.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><a name="PLATFORMVAR"></a><strong><tt>PLATFORM</tt></strong></td>
+ <td valign="top">The name of the subdirectory containing
+ the OS dependent C sources. The idea of defineing this
+ here, rather than using the MAKEPLAT variable defined in
+ the top level makefile, is so that different
+ configurations can share sources. i.e. An X11 port may
+ use the same code for all the unix platforms, but each
+ machine may require slightly different configuration
+ (library search paths for example).</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>EXE_EXT</tt></strong></td>
+ <td valign="top">An extension to add to the executable
+ name, e.g.<br>
+ <tt>EXE_EXT=.EXE</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>OBJ_EXT</tt></strong></td>
+ <td valign="top">The extension used in this OS to denote
+ object files produced by the C compiler. Generally:<br>
+ <tt>OBJ_EXT=.o</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>LIBS</tt></strong></td>
+ <td valign="top">Any extra libraries to link in with
+ viDOOM for the OS dependent routines.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>EXRACF</tt></strong></td>
+ <td valign="top">Any extra C flags required when
+ compiling the sources. Use it to enable optimisations and
+ to include any extra include paths required by this OS.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>EXTRALF</tt></strong></td>
+ <td valign="top">Any extra flags required when linking
+ viDOOM. Use it to enable include any extra librarypaths
+ required by this OS.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>DIRSEP</tt></strong></td>
+ <td valign="top">The directory seperator character for
+ this OS. The character must be included in quotes, e.g.<font
+ face="Courier New"><tt><br>
+ </tt></font><tt>DIRSEP=&quot;/&quot;</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>MATHLIB</tt></strong></td>
+ <td valign="top">The options required to include the
+ maths library when linking.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>TRACEFORM</tt></strong></td>
+ <td valign="top">This variable is a printf format string
+ and the arguments to the format. This string is used to
+ provide a tracing function used to track bugs in the
+ editor. A simple, portable example is:<br>
+ <tt>TRACEFORM=&quot;%s:%d&quot;,__FILE__,__LINE__</tt><p>It
+ can just be defined to an empty string if you are not
+ compiling the debug version.</p>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>EXEFLAG</tt></strong></td>
+ <td valign="top">The flag to provide to the linker to
+ generate an exectuable. The flag is used in a rule
+ something like this:<br>
+ <tt>$(LD) $(EXTRALF) $(EXEFLAG) vidoom$(EXE_EXT)
+ $(ALL+VIDOOM_OBJECTS)</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>OBJFLAG</tt></strong></td>
+ <td valign="top">The flag to provide to the C compiler to
+ generate an object file from the supplied C source. The
+ flag is used in a rule something like this:<br>
+ <tt>$(CC) $(EXTRACF) $(OBJFLAG) file.c</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>DEFINEFLAG</tt></strong></td>
+ <td valign="top">The flag to provide to the C compiler
+ with pre-processor definition from the command line. The
+ flag is used in a rule something like this (note no space
+ after the DEFINEFLAG - if there is a space between the
+ switch and the argument put it in this variable
+ definition):<br>
+ <tt>$(CC) $(EXTRACF) $(OBJFLAG) $(DEFINEFLAG)MACRO=value
+ file.c</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>INCFLAG</tt></strong></td>
+ <td valign="top">The flag to provide to the C compiler
+ with extra directories in which the pre-processor
+ searches for include files. The flag is used in a rule
+ something like this (note no space after the INCFLAG - if
+ there is a space between the switch and the argument put
+ it in this variable definition):<br>
+ <tt>$(CC) $(EXTRACF) $(OBJFLAG) $(INCFLAG)include_dir
+ file.c</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong><tt>MAKEINSTALL</tt></strong></td>
+ <td valign="top">The command used to execute the <strong>install</strong>
+ makefile as described in the <a href="#INSTALLATION">installation
+ script </a>section. The command must define the
+ INSTALLDIR variable for the makefile and invoke the first
+ rule in the install makefile.<p>For instance, using a
+ normal unix/GCC type make command, this would be:<br>
+ <tt>make INSTALL_DIR='$(INSTALL_DIR)' -f install</tt></p>
+ </td>
+ </tr>
+</table>
+
+<hr>
+
+<h2><a name="INI"></a>INI File</h2>
+
+<p>If your port requires or wants configuration to be set at
+tun-time from the INI file, it is best to place it a
+system-dependent section called the same as the <em>OS</em> value
+you set <a href="#MAKEPLAT">MAKEPLAT</a> to for this platform,
+e.g.</p>
+
+<p><tt>[</tt><em><tt>OS</tt></em><tt>]<br>
+guimode=3D</tt></p>
+
+<hr>
+
+<h2><a name="FILES"></a>Files</h2>
+
+<p>The following files are the minimum that must be provided by
+the platform:</p>
+
+<table border="1" cellpadding="3">
+ <tr>
+ <td valign="top" nowrap><strong>make/</strong><em><strong>OS</strong></em><strong>.cfg</strong></td>
+ <td valign="top">The make config file. Described in the <a
+ href="#MAKE_CONFIG">previous section</a>.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>main.c</strong></td>
+ <td valign="top">This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and provides the <a href="#MAIN">startup
+ code</a> for the operating system.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>gfx.c</strong></td>
+ <td valign="top">This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and provides the <a href="#GFX_H">low level
+ graphics and input</a>.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>platgui.c</strong></td>
+ <td valign="top">This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and provides the <a href="#PLATGUI_H">system
+ dependent GUI</a>.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>file.c</strong></td>
+ <td valign="top">This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and provides the portable part of the <a
+ href="#FILE_H">file system interface</a>.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>mem.c</strong></td>
+ <td valign="top">This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and provides the <a href="#MEM_H">memory
+ handling</a>.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>runcmd.c</strong></td>
+ <td valign="top">This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and provides the method for <a
+ href="#RUNCMD_H">running external commands</a>.</td>
+ </tr>
+ <tr>
+ <td><strong>vstring.c</strong></td>
+ <td>This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and provides functions for <a
+ href="#VSTRING_H">string comparisons</a>.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>install</strong></td>
+ <td valign="top">This goes in the <a href="#PLATFORMVAR">platform
+ directory</a> and is the makefile invoked to <a
+ href="#INSTALLATION">install viDOOM</a>.</td>
+ </tr>
+</table>
+
+<hr>
+
+<h2><a name="MAIN"></a>Main entry point</h2>
+
+<p><strong><u>main.c</u></strong></p>
+
+<p>The OS dependent code must provide it's own main (this is to
+allow for various non-standard environments where main() is not
+the standard entry point). The entry point must do any OS
+dependent initialisations then invoke the following entry point
+to start up viDOOM:</p>
+
+<p><tt>int viDOOM(int argv, char *argv[])</tt></p>
+
+<p>If the OS uses main() as an entry point the following example
+could be enough:</p>
+
+<pre>int main(int argc,char *argv[])
+{
+ return (viDOOM(argc,argv));
+}</pre>
+
+<hr>
+
+<h2><a name="GFX_H"></a>Graphics and input</h2>
+
+<p><strong><u>gfx.c</u></strong></p>
+
+<p>This provides the low-level graphics access and interfaces to
+keyboard and mouse. The GFX object is expected to work on a weak,
+semi-event driven basis for keyboard/mouse access. The following
+are the basic assumptions about the GFX interface:</p>
+
+<ul>
+ <li>A true, or hicolor, display.</li>
+ <li>A Fixed font.</li>
+ <li>Default origin is in the top left of the display, with X
+ positve along and Y positive down.</li>
+ <li>A buffered display. The screen contents should not change
+ until GFX_redraw() is called. If not honoured viDOOM
+ should still work up to a point, but it's use of the XOR
+ mode may not be apparent to the user.</li>
+ <li>Colours are represented using an int, with 8 bits each
+ for the red, green and blue component. The int used to
+ define the colour, when viewed in hex, would look like <tt>0xRRGGBB</tt>.
+ Some examples are:<ul type="disc">
+ <li><tt>0xFF0000</tt> - Red</li>
+ <li><tt>0x00FF00</tt> - Green</li>
+ <li type="disc"><tt>0x0000FF</tt> - Blue</li>
+ <li><tt>0xFFFFFF</tt> - White</li>
+ <li><tt>0x808080</tt> - 50% grey</li>
+ <li><tt>0x000000</tt> - Black</li>
+ </ul>
+ </li>
+</ul>
+
+<p>The following types are defined and used by the GFX object :</p>
+
+<table border="1" cellpadding="3">
+ <tr>
+ <td valign="top" nowrap><pre>typedef void *GFX_IMAGE; </pre>
+ </td>
+ <td valign="top">This is an opaque type provided to allow
+ the GFX object to provide whatever is required to
+ reference a bitmap on the machine.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct
+ {
+ int w;
+ int h;
+ int pal[256];
+ unsigned char *data;
+ } GFX_BITMAP; </pre>
+ </td>
+ <td valign="top">This type represents the bitmap objects
+ that viDOOM defines. These bitmaps are converted into
+ GFX_IMAGE prior to use. The fields are: <table border="0"
+ cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>w</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">width of bitmap</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>h</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">height of bitmap</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>pal[256]</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The pallete used to define the
+ bitmap. Each bitmap pixel is an index into this
+ array of RGB values. Each entry is an integer,
+ that when represented in hex would define the RGB
+ triplet as 0xRRGGBB.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>*data</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">A pointer to the data of the
+ bitmap. This should be accessed using pointer
+ arithmetic as *(data+(x)+(y*w))</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct
+ {
+ int type;
+ int shift;
+ int ctrl;
+ int alt;
+ char ascii;
+ int code;
+ } GFXKey;</pre>
+ </td>
+ <td valign="top">This defines an object for reporting key
+ presses. The fields are:<table border="0" cellpadding="3"
+ cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>type</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The type of event. This field is
+ just used to line up with the event union defined
+ later on. Should just hold GFX_KEY_EVENT.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>shift</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">TRUE if the Shift key is being
+ pressed.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>ctrl</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">TRUE if the Control key is being
+ pressed.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>alt</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">TRUE if the Alt key is being
+ pressed.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>ascii</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The ASCII code of the character
+ read. If the key is not an ASCII key (e.g. a
+ function key) this field should be zero.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>code</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">Holds the code for non-ASCII
+ keys, e.g. GFX_F1. This field should be set to
+ GFX_ASCII for key presses reported through the
+ ascii field.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct GFXMouse
+ {
+ int type;
+ int shift;
+ int ctrl;
+ int alt;
+ int x;
+ int y;
+ int b;
+ } GFXMouse;</pre>
+ </td>
+ <td valign="top">This defines the type for reporting
+ mouse movements and button presses. The fields are:<table
+ border="0" cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>type</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The type of event. This field is
+ just used to line up with the event union defined
+ later on. Should just hold GFX_MOUSE_EVENT.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>shift</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">TRUE if the Shift key is being
+ pressed.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>ctrl</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">TRUE if the Control key is being
+ pressed.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>alt</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">TRUE if the Alt key is being
+ pressed.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>x</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The X co-ordinate of the mouse,
+ relative to the top left of the display.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>y</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The Y co-ordinate of the mouse,
+ relative to the top left of the display.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>b</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The currently pressed buttons.
+ This should be made up of a bit mask composed
+ from GFX_BUTLEFT, GFX_BUTMIDDLE and GFX_BUTRIGHT.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef union GFXEvent
+ {
+ int type;
+ GFXKey key;
+ GFXMouse mouse;
+ } GFXEvent;</pre>
+ </td>
+ <td valign="top">This defines the type for reporting
+ events (a combination of both mouse movements or key
+ presses). The fields are:<table border="0"
+ cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>type</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The type of event. This field is
+ just used to decide which of the other two fields
+ should be accessed to get the event information.
+ This field must be GFX_MOUSE_EVENT or
+ GFX_KEY_EVENT.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>key</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The GFXKey structure defining
+ the event if this is a GFX_KEY_EVENT.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>mouse</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The GFXMouse structure defining
+ the event if this is a GFX_MOUSE_EVENT.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+
+<p>The following interfaces must be supplied by the GFX object:</p>
+
+<p><strong><tt>void GFX_init(void)</tt></strong></p>
+
+<blockquote>
+ <p>Initialises the GFX object. No other GFX interfaces are
+ called prior to this, with the possible (though current not
+ used) exception of <strong><tt>GFX_exit()</tt></strong>.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_close(void)</tt></strong></p>
+
+<blockquote>
+ <p>Called when viDOOM is terminating. Note that other (none
+ system dependent) processing may go on between calling this
+ and then invoking <strong><tt>exit()</tt></strong> or <strong><tt>return()</tt></strong>.</p>
+</blockquote>
+
+<p><strong><tt>GFX_IMAGE GFX_create_image(GFX_BITMAP *bm)</tt></strong></p>
+
+<blockquote>
+ <p>Should create a GFX_IMAGE from the passed bitmap <em>bm</em>.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_destroy_image(GFX_IMAGE img)</tt></strong></p>
+
+<blockquote>
+ <p>Release the bitmap object pointed to by <em>img</em>.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_draw_image(GFX_IMAGE img, int x, int y)</tt></strong></p>
+
+<blockquote>
+ <p>Draws <em>img</em> with it's top-left co-ordinate
+ represented by <em>x,y</em>. This function should implement
+ any necessary clipping when drawing the bitmap.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_fill_screen(GFX_IMAGE img)</tt></strong></p>
+
+<blockquote>
+ <p>Should fill the screen with the image, scaled if
+ necessary. Note that this call is just used for the menu
+ backdrop, so if it cannot be honoured no harm will be done.</p>
+</blockquote>
+
+<p><a name="GFX_OPEN"></a><strong><tt>void GFX_open(int width,
+int height)</tt></strong></p>
+
+<blockquote>
+ <p>Opens the display (or window or whatever) with the
+ specified <em>width</em> and <em>height</em>. Note that
+ failures in here should terminate the program.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_clear(int col)</tt></strong></p>
+
+<blockquote>
+ <p>This clears the display to the passed colour <em>col</em>.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_redraw(void)</tt></strong></p>
+
+<blockquote>
+ <p>This redraws the contents of the screen. All drawing
+ operations should not update the actual screen till this is
+ called (i.e. the display should be buffered).</p>
+</blockquote>
+
+<p><strong><tt>void GFX_line(int x1, int y1, int x2, int y2, int
+col)</tt></strong></p>
+
+<blockquote>
+ <p>Draw a line from <em>x1,y1</em> to <em>x2,y2</em> in
+ colour <em>col</em>.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_plot(int x, int y, int col)</tt></strong></p>
+
+<blockquote>
+ <p>Plot the point <em>x,y</em> in colour <em>col</em>.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_circle(int x, int y, int r, int col)<br>
+void GFX_fcircle(int x, int y, int r, int col)</tt></strong></p>
+
+<blockquote>
+ <p>Draw a circle centred on <em>x,y</em> with a radius <em>r</em>
+ and in colour <em>col</em>. The <strong>fcircle</strong>
+ version should draw a filled circle.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_rect(int x, int y, int w, int h, int col)<br>
+void GFX_frect(int x, int y, int w, int h, int col)</tt></strong></p>
+
+<blockquote>
+ <p>Draw a rectangle with one corner at <em>x,y</em> and the
+ other corner at <em>(x+w),(y+h)</em> in colour <em>col</em>.
+ Note that zero length and negative width and heights must be
+ allowed. The <strong>frect </strong>version should draw a
+ filled rectangle.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_set_XOR_mode(void)<br>
+void GFX_clear_XOR_mode(void)</tt></strong></p>
+
+<blockquote>
+ <p>This should set and clear XOR mode. Normally all GFX
+ operations should set the pixels to the colour specified, but
+ when XOR mode is enabled the pixel values should be XORed
+ into place.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_print(int x, int y, int col, char *fmt,
+...)</tt></strong></p>
+
+<blockquote>
+ <p>Print the printf style arguments (<em>fmt</em> and <em>...</em>)
+ with their top left corner at <em>x,y</em> in colour <em>col</em>.
+ Note that text should rendered transparently.</p>
+</blockquote>
+
+<p><strong><tt>int GFX_fh(void)<br>
+int GFX_fw(void)</tt></strong></p>
+
+<blockquote>
+ <p>Return the height (GFX_fh) and width (GFX_fw) of the fixed
+ width font used for display purposes.</p>
+</blockquote>
+
+<p><strong><tt>int GFX_mouse_buttons(void)</tt></strong></p>
+
+<blockquote>
+ <p>Returns the number of mouse buttons. This is just used as
+ check on initialisation as viDOOM expects at least 2 mouse
+ buttons.</p>
+</blockquote>
+
+<p><strong><tt>int GFX_mouse(int *x, int *y)</tt></strong></p>
+
+<blockquote>
+ <p>Return the current point position in <em>x</em> and <em>y</em>.
+ If any of the passed pointers are NULL that variable should
+ be ignored.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_waitkey(GFXKEy *key)</tt></strong></p>
+
+<blockquote>
+ <p>Waits for a <em>key</em> to be pressed and returns the key
+ press in <em>key</em>. If <em>key</em> is NULL simply wait
+ for a key press.</p>
+</blockquote>
+
+<p><strong><tt>int GFX_key(GFXKey *key)</tt></strong></p>
+
+<blockquote>
+ <p>Returns TRUE if a key has been pressed and returns the
+ keypress in <em>key</em>. Returns FALSE if there is no
+ outstanding keypresses, in which case the contents of <em>key</em>
+ are undefined.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_bounce(void)</tt></strong></p>
+
+<blockquote>
+ <p>Waits for all keys and mouse buttons to be released. On a
+ real event-driven system could be ignored, or flush any
+ outstanding events.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_await_input(GFXEvent *ev)</tt></strong></p>
+
+<blockquote>
+ <p>Waits for either a keypress or a mouse button to be
+ pressed and fills in <em>ev</em> accordingly.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_await_input_full(GFXEvent *ev)</tt></strong></p>
+
+<blockquote>
+ <p>Waits for either a keypress, a mouse button to be pressed
+ or the mouse to be moved and fills in <em>ev</em>
+ accordingly.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_exit(int code, char *fmt, ...)</tt></strong></p>
+
+<blockquote>
+ <p>This call should do any necessary tidying of the display
+ (switching from graphics mode, closing windows, whatever)
+ then display the printf style arguments (<em>fmt</em> and <em>...</em>)
+ and the exit with the passed return <em>code</em>.</p>
+</blockquote>
+
+<p><strong><tt>void GFX_save_screen(char *path)</tt></strong></p>
+
+<blockquote>
+ <p>This call need not be supported. It just allows screen
+ grabs to be captured when viDOOM is compiled with debug
+ information. If supported it should just save a bitmap in the
+ file pointed to by <em>path</em>.</p>
+</blockquote>
+
+<hr>
+
+<h2><a name="PLATGUI_H"></a>Platform GUI</h2>
+
+<p><strong><u>platgui.c</u></strong></p>
+
+<p>This provides access to the platform's GUI routines.</p>
+
+<p>The following types are defined and used by the PLATGUI object
+:</p>
+
+<table border="1" cellpadding="3">
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct
+ {
+ char *text;
+ GFX_IMAGE img;
+ int client_index;
+ } PLAT_IMG_PICKLIST;</pre>
+ </td>
+ <td valign="top">This structure is used to define a
+ picklist that has graphical images and client defined
+ values attached to them. This is used for selection of
+ textures, flats and sprites (things) in viDOOM.<p>The
+ fields in the structure are:</p>
+ <table border="0" cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>text</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This defines the text for a
+ picklist entry. NULL marks the end of the list of
+ picklist entries.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>img</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The GFX_IMAGE to associate with
+ this entry. Can be NULL to indicate show no
+ image.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>client_index</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The value returned if this item
+ is selected.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct
+ {
+ char *text;
+ int client_index;
+ } PLAT_PICKLIST;</pre>
+ </td>
+ <td valign="top">This structure is used to define a
+ picklist that has client defined values attached to the
+ entries.<p>The fields in the structure are:</p>
+ <table border="0" cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>text</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This defines the text for a
+ picklist entry. NULL marks the end of the list of
+ picklist entries.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>client_index</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The value returned if this item
+ is selected.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct
+ {
+ char *text;
+ int client_index;
+ } PLAT_MENU;</pre>
+ </td>
+ <td valign="top">This structure is used to define menu
+ entries that have client defined values attached to them.<p>The
+ fields in the structure are:</p>
+ <table border="0" cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>text</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This defines the text for the
+ menu entry. NULL marks the end of the list of
+ menu entries.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>client_index</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The value returned if this item
+ is selected.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct
+ {
+ char *text;
+ int client_index;
+ } PLAT_RADIO;</pre>
+ </td>
+ <td valign="top">This structure is used to define entries
+ for a radio style picklist (i.e. where only one option
+ can be chosen) that have client defined values attached
+ to them.<p>The fields in the structure are:</p>
+ <table border="0" cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>text</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This defines the text for the
+ radio button. NULL marks the end of the list of
+ radio button entries.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>client_index</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The value returned if this item
+ is selected.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><pre>typedef struct
+ {
+ char *text;
+ int type;
+ union /* Data */
+ {
+ int i;
+ char s[PLAT_DIAL_MAXSTRLEN+1];
+ double d;
+ } data;
+ } PLAT_DIALOG;</pre>
+ </td>
+ <td valign="top">This structure is used to define entries
+ for a simple dialog.<p>The fields in the structure are:</p>
+ <table border="0" cellpadding="3" cellspacing="6">
+ <tr>
+ <td valign="top" nowrap>text</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This defines the text for this
+ field in the dialog. NULL marks the end of the
+ list of dialog entries.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>type</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">The type of field this is.
+ Possible values are PLAT_DIAL_STRING,
+ PLAT_DIAL_INTEGER and PLAT_DIAL_DOUBLE.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>data.i</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This is the field that is
+ displayed and updated on exit if the type is
+ PLAT_DIAL_INTEGER.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>data.s</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This is the field that is
+ displayed and updated on exit if the type is
+ PLAT_DIAL_STRING.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap>data.d</td>
+ <td valign="top" nowrap>-</td>
+ <td valign="top">This is the field that is
+ displayed and updated on exit if the type is
+ PLAT_DIAL_DOUBLE.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+
+<p>Note that along with the types, the following predifined
+values are set (these are read from the INI file). Note that they
+shold be considered to be unset until immediately prior to
+viDOOM's call to <strong><tt>GUI_setscreen()</tt></strong>:</p>
+
+<table border="1" cellpadding="3">
+ <tr>
+ <td valign="top" nowrap><strong>GUI_HI</strong></td>
+ <td valign="top">The brightest colour used to draw the 3D
+ looking interface.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>GUI_MID</strong></td>
+ <td valign="top">The medium colour used to draw the 3D
+ looking interface.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>GUI_LO</strong></td>
+ <td valign="top">The darkest colour used to draw the 3D
+ looking interface.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>GUI_TEXT</strong></td>
+ <td valign="top">The colour of text.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>GUI_TEXTSHADOW</strong></td>
+ <td valign="top">The colour of the shadow behind text.
+ This is only really used by viDOOM's own portable GUI
+ routines.</td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><strong>GUI_BOLD</strong></td>
+ <td valign="top">The colour of bold text (used for
+ titles).</td>
+ </tr>
+</table>
+
+<h3>Functions</h3>
+
+<p>The following interfaces are defined by the PLATGUI object.
+Note that all these calls are assumed to not destory screen
+contents (ie. the screen should be restored after displaying the
+GUI object):</p>
+
+<p><strong><tt>void GUI_setscreen(int width, int height)</tt></strong></p>
+
+<blockquote>
+ <p>Once the display has been opened with <a href="#GFX_OPEN"><strong>GFX_open()</strong></a>
+ then this is called to inform the platform's GUI routines of
+ the display size.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_yesno(char *question)</tt></strong></p>
+
+<blockquote>
+ <p>Display an alert with <em>question</em> in it and <em>Yes</em>
+ and <em>No</em> buttons. Returns TRUE if <em>Yes</em> is
+ pressed and FALSE if <em>No</em> is pressed.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_menu(char *title, int x, int y, PLAT_MENU
+menu[], int defval)</tt></strong></p>
+
+<blockquote>
+ <p>Displays a menu with title <em>title</em> at position <em>x,y</em>.
+ The displayed items are taken from <em>menu</em>. The return
+ is the client_index field from the selected menu item, or <em>defval</em>
+ if the menu is cancelled.</p>
+</blockquote>
+
+<p><strong><tt>char *GUI_fsel(char *title, char *default_path,
+char filter)</tt></strong></p>
+
+<blockquote>
+ <p>Allows a file to be selected. The file selector should
+ have <em>title</em> for it's title and start selecting from
+ the <em>default_path</em>. If <em>filter </em>is NULL then
+ all files should be displayed, otherwise only files ending in
+ <em>filter</em>.</p>
+ <p>The return is NULL if the selector is cancelled. Otherwise
+ a pointer is returned containing the fully qualified path of
+ the selected file. This pointer must be dynamically allocated
+ and will be freed using <a href="#FRELEASE"><strong>FRelease()</strong></a>.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_picklist(char *title, char *opts[])</tt></strong></p>
+
+<blockquote>
+ <p>Displays a picklist with title <em>title</em>. The options
+ are taken from the array of character pointers <em>opts</em>.
+ The return value is the index of the selected item in <em>opts</em>
+ if selected, or -1 if the picklist is cancelled.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_client_picklist(char *title, PLAT_PICKLIST
+opts[], int defval)</tt></strong></p>
+
+<blockquote>
+ <p>Displays a picklist with title <em>title</em>. The text
+ items to display are taken from <em>opts</em>. The return is
+ the client_index field from the selected picklist item, or <em>defval</em>
+ if the picklist is cancelled.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_image_picklist(char *title,
+PLAT_IMG_PICKLIST opts[], int defval)</tt></strong></p>
+
+<blockquote>
+ <p>Displays a picklist with title <em>title</em>. The text
+ items and associated image to display are taken from <em>opts</em>.
+ The return is the client_index field from the selected
+ picklist item, or <em>defval</em> if the picklist is
+ cancelled.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_radio_box(char *title, PLAT_RADIO opts[],
+int current, int defval)</tt></strong></p>
+
+<blockquote>
+ <p>Displays a dialog containing radio buttons with title <em>title</em>.
+ The text to display is taken from <em>opts</em>. The selected
+ object when the the radio box is first displayed is the
+ option who's client_index field matchs <em>current</em> (or
+ the first item if there is no match). The return is the
+ client_index field from the selected radio button, or <em>defval</em>
+ if the radio box is cancelled.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_multi_box(char *title, char *opts[], int
+*val)</tt></strong></p>
+
+<blockquote>
+ <p>Display a mutli-selection radio box. The items are
+ described <em>opts</em>, which terminates with a NULL
+ pointer. <em>Val</em> points to a value which is used to
+ enable/disable the options dependent on the integers bit
+ setting. The integer pointed to by <em>val</em> is updated on
+ exit of the multi-selection box if it is not cancelled.</p>
+ <p>Note that the bit patterns are matched bit number to opt
+ index. ie.</p>
+ <ul>
+ <li>val &amp; 0x0001 corresponds to opts[0]</li>
+ <li>val &amp; 0x0002 corresponds to opts[1] ...</li>
+ <li>val &amp; 0x0010 corresponds to opts[4] ...</li>
+ <li>val &amp; 0x0100 corresponds to opts[8] ...</li>
+ <li>val &amp; 0x8000 corresponds to opts[15]</li>
+ </ul>
+ <p>A maximum of 16 bits should be all that needs supporting
+ currently. The return is TRUE if the dialog is accepted,
+ otherwise FALSE.</p>
+</blockquote>
+
+<p><strong><tt>int GUI_dialog(char *title, int no, PLAT_DIALOG
+dial[])</tt></strong></p>
+
+<blockquote>
+ <p>Displays a dialog with the title <em>title</em>. The
+ fields for the dialog are extracted from <em>dial</em>, for
+ which there is expected to be <em>no</em> elements. The
+ return is TRUE if the dialog is accepted, or FALSE if it is
+ cancelled. On being cancelled the contents of the data union
+ withing the <em>dial</em> elements is undefined.</p>
+</blockquote>
+
+<hr>
+
+<h2><a name="FILE_H"></a>File interface</h2>
+
+<p><strong><u>file.c</u></strong></p>
+
+<p>This provides access to various file system functions and also
+provides some filename manipulation routines. The following
+interfaces should be provided:</p>
+
+<p><strong><tt>char *Pwd(void)</tt></strong></p>
+
+<blockquote>
+ <p>This call should return the current working directory. The
+ return should be static.</p>
+</blockquote>
+
+<p><strong><tt>void Cd(char *path)</tt></strong></p>
+
+<blockquote>
+ <p>This call should change the current working directory to <em>path</em>.</p>
+</blockquote>
+
+<p><strong><tt>char *Dirname(char *path)</tt></strong></p>
+
+<blockquote>
+ <p>This call should return the directory part of <em>path</em>
+ if any. The return should be static.</p>
+</blockquote>
+
+<p><strong><tt>char *Basename(char *path)</tt></strong></p>
+
+<blockquote>
+ <p>This call should return the filname part of <em>path</em>.
+ The return should be static, or a pointer into the <em>path</em>
+ parameter.</p>
+</blockquote>
+
+<p><strong><tt>int FileExists(char *path)</tt></strong></p>
+
+<blockquote>
+ <p>This call should return TRUE if the file pointed to by <em>path</em>
+ exists.</p>
+</blockquote>
+
+<p><strong><tt>int FilenamesEqual(char *path1, char *path2)</tt></strong></p>
+
+<blockquote>
+ <p>This call should return TRUE if the file pointed to by <em>path1</em>
+ and <em>path2</em> are the same file. At it's most basic
+ (e.g. like in the DOS port) it can simply makes sure that
+ directory seperators are in the same form and then does <strong>strcasecmp()</strong>
+ on the paths.</p>
+</blockquote>
+
+<hr>
+
+<h2><a name="MEM_H"></a>Memory allocation</h2>
+
+<p><strong><u>mem.c</u></strong></p>
+
+<p>This provides memory allocation. While memory allocation can
+generally be done portably using <tt>malloc()</tt> providing this
+library just covers for any possible OS dependent twist. Also
+these routines are expected to handle errors internally. In all
+the interfaces <em>file</em> and <em>line</em> parameters are
+included so that errors can be reported more accurately.</p>
+
+<p>The following interfaces should be provided:</p>
+
+<p><strong><tt>void *FGrab (char *file, int line, int len)</tt></strong></p>
+
+<blockquote>
+ <p>This call should allocate <em>len</em> bytes and return a
+ pointer to it. A <em>len</em> of zero is valid. Memory should
+ be initialised to zero. Failure to allocate the memory should
+ terminate the program.</p>
+</blockquote>
+
+<p><strong><tt>void *FReGrab (char *file, int line, void *ptr,
+int len)</tt></strong></p>
+
+<blockquote>
+ <p>This call should re-allocate the memory pointed to by <em>ptr</em>
+ and return a new memory area of <em>len</em> bytes. The
+ original data pointed to by <em>ptr</em> should be copied to
+ the new memory area. Failure to allocate the memory should
+ terminate the program.</p>
+</blockquote>
+
+<p><strong><tt>char *FStrdup (char *file, int line, char *str)</tt></strong></p>
+
+<blockquote>
+ <p>This call should allocate enough bytes to copy the nul
+ terminated <em>str</em> to it. The returned pointer should
+ point to the new copy of <em>str</em>.<em> </em>Failure to
+ allocate the memory should terminate the program.</p>
+</blockquote>
+
+<p><strong><tt>void *FCopy (char *file, int line, void *ptr, int
+len)</tt></strong></p>
+
+<blockquote>
+ <p>This call should allocate <em>len</em> bytes and copy <em>len</em>
+ bytes from <em>ptr</em> into the new area. The newly
+ allocated memory should be returned. Failure to allocate the
+ memory should terminate the program.</p>
+</blockquote>
+
+<p><a name="FRELEASE"></a><strong><tt>void FRelease (char *file,
+int line, void *ptr)</tt></strong></p>
+
+<blockquote>
+ <p>This call should release the memory pointed to by <em>ptr</em>,
+ which will have been allocated by FGrab, FReGrab, FStrdup or
+ FCopy.</p>
+</blockquote>
+
+<hr>
+
+<h2><a name="RUNCMD_H"></a>External command execution</h2>
+
+<p><strong><u>runcmd.c</u></strong></p>
+
+<p>Provides a mechanism to run an external command. The following
+interfaces should be provided:</p>
+
+<p><strong><tt>int RunCommand(char *argv[], char *path)</tt></strong></p>
+
+<blockquote>
+ <p>Run a command. Te output from the command (if there is
+ any) should NOT disturb the screen contents. The call should
+ return TRUE if the call succeeds, FALSE otherwise.</p>
+ <p>The <em>argv</em> list is an array of pointers to various
+ sections of the command and it's arguemnts, terminated with a
+ NULL pointer. Note that arguments may contain more than one
+ argument in each line - the actual command is described
+ simply by concatanating all the pointers together, eg.</p>
+ <p><tt>argv[0]=&quot;bsp&quot;<br>
+ argv[1]=&quot;file.wad&quot;<br>
+ argv[2]=&quot;-o file.wad&quot;<br>
+ argv[3]=NULL</tt></p>
+ <p>The <em>path</em> argument is a place to copy the path to
+ a file where the output from the comand has been stored. If
+ this is not supported then the empty string should be
+ assigned to it. viDOOM will <tt>remove()</tt> the file after
+ it has read it.</p>
+</blockquote>
+
+<hr>
+
+<h2><a name="VSTRING_H"></a>Portable String routines</h2>
+
+<p><strong><u>vstring.c</u></strong></p>
+
+<p>Provides common string functions that are not actually part of
+the ANSI standard:</p>
+
+<p><strong><tt>int StrCaseCmp(char *a, char *b)</tt></strong></p>
+
+<blockquote>
+ <p>Performs in exactly the same way as the ANSI <tt>strcmp()</tt>
+ function, save for the fact that the case of the strings
+ being compared is ignored.</p>
+</blockquote>
+
+<p><strong><tt>int StrNCaseCmp(char *a, char *b)</tt></strong></p>
+
+<blockquote>
+ <p>Performs in exactly the same way as the ANSI <tt>strncmp()</tt>
+ function, save for the fact that the case of the strings
+ being compared is ignored.</p>
+</blockquote>
+
+<hr>
+
+<h2><a name="INSTALLATION"></a>Installation script</h2>
+
+<p>Each platform should provide a makefile called <strong>install</strong>.
+This is invoked from the top level makefile like this:</p>
+
+<blockquote>
+ <p><tt>cd $(PLATFORM) ; $(MAKEINSTALL)</tt></p>
+</blockquote>
+
+<p>Note that the install makefile will be invoked with the <a
+href="#PLATFORMVAR">PLATFORM</a> directory as the current working
+directory.</p>
+
+<p>The following files should be copied (where $SRC represents
+the source build directory and $INSTALLDIR the install
+directory):</p>
+
+<table border="1" cellpadding="3">
+ <tr>
+ <td valign="top" nowrap><tt>$SRC/vidoom</tt></td>
+ <td valign="top"><tt>$INSTALLDIR/vidoom</tt><p>Note that
+ this file may have a system specific extension (e.g. .EXE
+ in DOS)</p>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><tt>$SRC/LICENSE</tt></td>
+ <td valign="top"><tt>$INSTALLDIR/LICENSE</tt><p>The GNU
+ GPL <em><strong>must</strong></em> be copied into the
+ installation directory.</p>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><tt>$SRC/base.ini</tt></td>
+ <td valign="top"><tt>$INSTALLDIR/vidoom.ini</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><tt>$SRC/*.cfg</tt></td>
+ <td valign="top"><tt>$INSTALLDIR/*.cfg</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><tt>$SRC/doc/*.htm</tt></td>
+ <td valign="top"><tt>$INSTALLDIR/doc/*.htm</tt></td>
+ </tr>
+ <tr>
+ <td valign="top" nowrap><tt>$SRC/doc/*.png</tt></td>
+ <td valign="top"><tt>$INSTALLDIR/doc/*.png</tt></td>
+ </tr>
+</table>
+
+<hr>
+
+<h2><a name="DOCUMENTATION"></a>Documentation</h2>
+
+<p>If you release a port of viDOOM to any platform please update <a
+href="bugs.htm#CONTACTS">doc/bugs.htm</a> with a contact address
+for problems on that platform.</p>
+
+<hr>
+
+<p><a href="index.htm">Back to index</a></p>
+
+<p><tt>$Id: porting.htm,v 1.17 2000/08/05 19:58:21 dosuser Exp dosuser $</tt></p>
+</body>
+</html>